]>
Commit | Line | Data |
---|---|---|
7383e370 | 1 | diff -uNr linux-2.6.16.orig/drivers/scsi/3w-9xxx.c linux-2.6.16/drivers/scsi/3w-9xxx.c |
2 | --- linux-2.6.16.orig/drivers/scsi/3w-9xxx.c 2007-05-31 23:13:02.123552000 +0200 | |
3 | +++ linux-2.6.16/drivers/scsi/3w-9xxx.c 2006-10-20 22:22:02.000000000 +0200 | |
4 | @@ -2,8 +2,9 @@ | |
5 | 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. | |
6 | ||
7 | Written By: Adam Radford <linuxraid@amcc.com> | |
8 | + Modifications By: Tom Couch <linuxraid@amcc.com> | |
9 | ||
10 | - Copyright (C) 2004-2005 Applied Micro Circuits Corporation. | |
11 | + Copyright (C) 2004-2006 Applied Micro Circuits Corporation. | |
12 | ||
13 | This program is free software; you can redistribute it and/or modify | |
14 | it under the terms of the GNU General Public License as published by | |
15 | @@ -62,6 +63,12 @@ | |
16 | 2.26.02.003 - Correctly handle single sgl's with use_sg=1. | |
17 | 2.26.02.004 - Add support for 9550SX controllers. | |
18 | 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher. | |
19 | + 2.26.02.006 - Fix 9550SX pchip reset timeout. | |
20 | + Add big endian support. | |
21 | + 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic(). | |
22 | + 2.26.02.008 - Free irq handler in __twa_shutdown(). | |
23 | + Serialize reset code. | |
24 | + Add support for 9650SE controllers. | |
25 | */ | |
26 | ||
27 | #include <linux/module.h> | |
28 | @@ -85,7 +92,7 @@ | |
29 | #include "3w-9xxx.h" | |
30 | ||
31 | /* Globals */ | |
32 | -#define TW_DRIVER_VERSION "2.26.02.007" | |
33 | +#define TW_DRIVER_VERSION "2.26.02.008" | |
34 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; | |
35 | static unsigned int twa_device_extension_count; | |
36 | static int twa_major = -1; | |
37 | @@ -208,7 +215,7 @@ | |
38 | ||
39 | header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; | |
40 | tw_dev->posted_request_count--; | |
41 | - aen = header->status_block.error; | |
42 | + aen = le16_to_cpu(header->status_block.error); | |
43 | full_command_packet = tw_dev->command_packet_virt[request_id]; | |
44 | command_packet = &full_command_packet->command.oldcommand; | |
45 | ||
46 | @@ -305,7 +312,7 @@ | |
47 | ||
48 | tw_dev->posted_request_count--; | |
49 | header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; | |
50 | - aen = header->status_block.error; | |
51 | + aen = le16_to_cpu(header->status_block.error); | |
52 | queue = 0; | |
53 | count++; | |
54 | ||
55 | @@ -365,7 +372,7 @@ | |
56 | tw_dev->aen_clobber = 1; | |
57 | } | |
58 | ||
59 | - aen = header->status_block.error; | |
60 | + aen = le16_to_cpu(header->status_block.error); | |
61 | memset(event, 0, sizeof(TW_Event)); | |
62 | ||
63 | event->severity = TW_SEV_OUT(header->status_block.severity__reserved); | |
64 | @@ -382,7 +389,7 @@ | |
65 | ||
66 | header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; | |
67 | event->parameter_len = strlen(header->err_specific_desc); | |
68 | - memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len); | |
69 | + memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + (error_str[0] == '\0' ? 0 : (1 + strlen(error_str)))); | |
70 | if (event->severity != TW_AEN_SEVERITY_DEBUG) | |
71 | printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", | |
72 | host, | |
73 | @@ -462,24 +469,24 @@ | |
74 | command_packet = &full_command_packet->command.oldcommand; | |
75 | command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); | |
76 | command_packet->request_id = request_id; | |
77 | - command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id]; | |
78 | - command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; | |
79 | + command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); | |
80 | + command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); | |
81 | command_packet->size = TW_COMMAND_SIZE; | |
82 | - command_packet->byte6_offset.parameter_count = 1; | |
83 | + command_packet->byte6_offset.parameter_count = cpu_to_le16(1); | |
84 | ||
85 | /* Setup the param */ | |
86 | param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; | |
87 | memset(param, 0, TW_SECTOR_SIZE); | |
88 | - param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */ | |
89 | - param->parameter_id = 0x3; /* SchedulerTime */ | |
90 | - param->parameter_size_bytes = 4; | |
91 | + param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ | |
92 | + param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ | |
93 | + param->parameter_size_bytes = cpu_to_le16(4); | |
94 | ||
95 | /* Convert system time in UTC to local time seconds since last | |
96 | Sunday 12:00AM */ | |
97 | do_gettimeofday(&utc); | |
98 | local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); | |
99 | schedulertime = local_time - (3 * 86400); | |
100 | - schedulertime = schedulertime % 604800; | |
101 | + schedulertime = cpu_to_le32(schedulertime % 604800); | |
102 | ||
103 | memcpy(param->data, &schedulertime, sizeof(u32)); | |
104 | ||
105 | @@ -562,9 +569,9 @@ | |
106 | goto out; | |
107 | } | |
108 | ||
109 | - tw_dev->working_srl = fw_on_ctlr_srl; | |
110 | - tw_dev->working_branch = fw_on_ctlr_branch; | |
111 | - tw_dev->working_build = fw_on_ctlr_build; | |
112 | + tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl; | |
113 | + tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch; | |
114 | + tw_dev->tw_compat_info.working_build = fw_on_ctlr_build; | |
115 | ||
116 | /* Try base mode compatibility */ | |
117 | if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { | |
118 | @@ -586,10 +593,23 @@ | |
119 | } | |
120 | goto out; | |
121 | } | |
122 | - tw_dev->working_srl = TW_BASE_FW_SRL; | |
123 | - tw_dev->working_branch = TW_BASE_FW_BRANCH; | |
124 | - tw_dev->working_build = TW_BASE_FW_BUILD; | |
125 | - } | |
126 | + tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL; | |
127 | + tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH; | |
128 | + tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD; | |
129 | + } | |
130 | + | |
131 | + /* Load rest of compatibility struct */ | |
132 | + strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); | |
133 | + tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; | |
134 | + tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; | |
135 | + tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; | |
136 | + tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; | |
137 | + tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; | |
138 | + tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; | |
139 | + tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; | |
140 | + tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; | |
141 | + tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; | |
142 | + | |
143 | retval = 0; | |
144 | out: | |
145 | return retval; | |
146 | @@ -627,7 +647,7 @@ | |
147 | goto out2; | |
148 | ||
149 | /* Check data buffer size */ | |
150 | - if (driver_command.buffer_length > TW_MAX_SECTORS * 512) { | |
151 | + if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { | |
152 | retval = TW_IOCTL_ERROR_OS_EINVAL; | |
153 | goto out2; | |
154 | } | |
155 | @@ -676,13 +696,6 @@ | |
156 | /* Now wait for command to complete */ | |
157 | timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); | |
158 | ||
159 | - /* See if we reset while waiting for the ioctl to complete */ | |
160 | - if (test_bit(TW_IN_RESET, &tw_dev->flags)) { | |
161 | - clear_bit(TW_IN_RESET, &tw_dev->flags); | |
162 | - retval = TW_IOCTL_ERROR_OS_ERESTARTSYS; | |
163 | - goto out3; | |
164 | - } | |
165 | - | |
166 | /* We timed out, and didn't get an interrupt */ | |
167 | if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { | |
168 | /* Now we need to reset the board */ | |
169 | @@ -690,11 +703,6 @@ | |
170 | tw_dev->host->host_no, TW_DRIVER, 0xc, | |
171 | cmd); | |
172 | retval = TW_IOCTL_ERROR_OS_EIO; | |
173 | - spin_lock_irqsave(tw_dev->host->host_lock, flags); | |
174 | - tw_dev->state[request_id] = TW_S_COMPLETED; | |
175 | - twa_free_request_id(tw_dev, request_id); | |
176 | - tw_dev->posted_request_count--; | |
177 | - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); | |
178 | twa_reset_device_extension(tw_dev, 1); | |
179 | goto out3; | |
180 | } | |
181 | @@ -713,16 +721,7 @@ | |
182 | tw_ioctl->driver_command.status = 0; | |
183 | /* Copy compatiblity struct into ioctl data buffer */ | |
184 | tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; | |
185 | - strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); | |
186 | - tw_compat_info->working_srl = tw_dev->working_srl; | |
187 | - tw_compat_info->working_branch = tw_dev->working_branch; | |
188 | - tw_compat_info->working_build = tw_dev->working_build; | |
189 | - tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL; | |
190 | - tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH; | |
191 | - tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD; | |
192 | - tw_compat_info->driver_srl_low = TW_BASE_FW_SRL; | |
193 | - tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH; | |
194 | - tw_compat_info->driver_build_low = TW_BASE_FW_BUILD; | |
195 | + memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); | |
196 | break; | |
197 | case TW_IOCTL_GET_LAST_EVENT: | |
198 | if (tw_dev->event_queue_wrapped) { | |
199 | @@ -891,7 +890,8 @@ | |
200 | } | |
201 | ||
202 | if (status_reg_value & TW_STATUS_QUEUE_ERROR) { | |
203 | - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); | |
204 | + if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags))) | |
205 | + TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); | |
206 | writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); | |
207 | } | |
208 | ||
209 | @@ -931,26 +931,21 @@ | |
210 | /* This function will clear the pchip/response queue on 9550SX */ | |
211 | static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev) | |
212 | { | |
213 | - u32 status_reg_value, response_que_value; | |
214 | - int count = 0, retval = 1; | |
215 | - | |
216 | - if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) { | |
217 | - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); | |
218 | + u32 response_que_value = 0; | |
219 | + unsigned long before; | |
220 | + int retval = 1; | |
221 | ||
222 | - while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { | |
223 | + if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) || | |
224 | + (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) { | |
225 | + before = jiffies; | |
226 | + while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) { | |
227 | response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev)); | |
228 | - if ((response_que_value & TW_9550SX_DRAIN_COMPLETED) == TW_9550SX_DRAIN_COMPLETED) { | |
229 | - /* P-chip settle time */ | |
230 | - msleep(500); | |
231 | - retval = 0; | |
232 | + msleep(1); | |
233 | + if (time_after(jiffies, before + HZ * 30)) | |
234 | goto out; | |
235 | - } | |
236 | - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); | |
237 | - count++; | |
238 | } | |
239 | - if (count == TW_MAX_RESPONSE_DRAIN) | |
240 | - goto out; | |
241 | - | |
242 | + /* P-chip settle time */ | |
243 | + msleep(500); | |
244 | retval = 0; | |
245 | } else | |
246 | retval = 0; | |
247 | @@ -972,7 +967,7 @@ | |
248 | error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]); | |
249 | ||
250 | /* Don't print error for Logical unit not supported during rollcall */ | |
251 | - error = full_command_packet->header.status_block.error; | |
252 | + error = le16_to_cpu(full_command_packet->header.status_block.error); | |
253 | if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) { | |
254 | if (print_host) | |
255 | printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", | |
256 | @@ -1030,7 +1025,7 @@ | |
257 | tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; | |
258 | } /* End twa_free_request_id() */ | |
259 | ||
260 | -/* This function will get parameter table entires from the firmware */ | |
261 | +/* This function will get parameter table entries from the firmware */ | |
262 | static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) | |
263 | { | |
264 | TW_Command_Full *full_command_packet; | |
265 | @@ -1047,18 +1042,18 @@ | |
266 | command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); | |
267 | command_packet->size = TW_COMMAND_SIZE; | |
268 | command_packet->request_id = request_id; | |
269 | - command_packet->byte6_offset.block_count = 1; | |
270 | + command_packet->byte6_offset.block_count = cpu_to_le16(1); | |
271 | ||
272 | /* Now setup the param */ | |
273 | param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; | |
274 | memset(param, 0, TW_SECTOR_SIZE); | |
275 | - param->table_id = table_id | 0x8000; | |
276 | - param->parameter_id = parameter_id; | |
277 | - param->parameter_size_bytes = parameter_size_bytes; | |
278 | + param->table_id = cpu_to_le16(table_id | 0x8000); | |
279 | + param->parameter_id = cpu_to_le16(parameter_id); | |
280 | + param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); | |
281 | param_value = tw_dev->generic_buffer_phys[request_id]; | |
282 | ||
283 | - command_packet->byte8_offset.param.sgl[0].address = param_value; | |
284 | - command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; | |
285 | + command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(param_value); | |
286 | + command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); | |
287 | ||
288 | /* Post the command packet to the board */ | |
289 | twa_post_command_packet(tw_dev, request_id, 1); | |
290 | @@ -1107,18 +1102,20 @@ | |
291 | tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; | |
292 | tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); | |
293 | tw_initconnect->request_id = request_id; | |
294 | - tw_initconnect->message_credits = message_credits; | |
295 | + tw_initconnect->message_credits = cpu_to_le16(message_credits); | |
296 | tw_initconnect->features = set_features; | |
297 | ||
298 | /* Turn on 64-bit sgl support if we need to */ | |
299 | tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; | |
300 | ||
301 | + tw_initconnect->features = cpu_to_le32(tw_initconnect->features); | |
302 | + | |
303 | if (set_features & TW_EXTENDED_INIT_CONNECT) { | |
304 | tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; | |
305 | - tw_initconnect->fw_srl = current_fw_srl; | |
306 | - tw_initconnect->fw_arch_id = current_fw_arch_id; | |
307 | - tw_initconnect->fw_branch = current_fw_branch; | |
308 | - tw_initconnect->fw_build = current_fw_build; | |
309 | + tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl); | |
310 | + tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); | |
311 | + tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); | |
312 | + tw_initconnect->fw_build = cpu_to_le16(current_fw_build); | |
313 | } else | |
314 | tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; | |
315 | ||
316 | @@ -1130,11 +1127,11 @@ | |
317 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection"); | |
318 | } else { | |
319 | if (set_features & TW_EXTENDED_INIT_CONNECT) { | |
320 | - *fw_on_ctlr_srl = tw_initconnect->fw_srl; | |
321 | - *fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id; | |
322 | - *fw_on_ctlr_branch = tw_initconnect->fw_branch; | |
323 | - *fw_on_ctlr_build = tw_initconnect->fw_build; | |
324 | - *init_connect_result = tw_initconnect->result; | |
325 | + *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl); | |
326 | + *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id); | |
327 | + *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch); | |
328 | + *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build); | |
329 | + *init_connect_result = le32_to_cpu(tw_initconnect->result); | |
330 | } | |
331 | retval = 0; | |
332 | } | |
333 | @@ -1193,7 +1190,7 @@ | |
334 | } /* End twa_initialize_device_extension() */ | |
335 | ||
336 | /* This function is the interrupt service routine */ | |
337 | -static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs) | |
338 | +static irqreturn_t twa_interrupt(int irq, void *dev_instance) | |
339 | { | |
340 | int request_id, error = 0; | |
341 | u32 status_reg_value; | |
342 | @@ -1215,6 +1212,10 @@ | |
343 | ||
344 | handled = 1; | |
345 | ||
346 | + /* If we are resetting, bail */ | |
347 | + if (test_bit(TW_IN_RESET, &tw_dev->flags)) | |
348 | + goto twa_interrupt_bail; | |
349 | + | |
350 | /* Check controller for errors */ | |
351 | if (twa_check_bits(status_reg_value)) { | |
352 | if (twa_decode_bits(tw_dev, status_reg_value)) { | |
353 | @@ -1356,12 +1357,12 @@ | |
354 | ||
355 | if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { | |
356 | newcommand = &full_command_packet->command.newcommand; | |
357 | - newcommand->request_id__lunl = | |
358 | - TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id); | |
359 | - newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; | |
360 | - newcommand->sg_list[0].length = length; | |
361 | + newcommand->request_id__lunl = | |
362 | + cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); | |
363 | + newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); | |
364 | + newcommand->sg_list[0].length = cpu_to_le32(length); | |
365 | newcommand->sgl_entries__lunh = | |
366 | - TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1); | |
367 | + cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1)); | |
368 | } else { | |
369 | oldcommand = &full_command_packet->command.oldcommand; | |
370 | oldcommand->request_id = request_id; | |
371 | @@ -1369,8 +1370,8 @@ | |
372 | if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { | |
373 | /* Load the sg list */ | |
374 | sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); | |
375 | - sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; | |
376 | - sgl->length = length; | |
377 | + sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); | |
378 | + sgl->length = cpu_to_le32(length); | |
379 | ||
380 | if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) | |
381 | oldcommand->size += 1; | |
382 | @@ -1389,7 +1390,7 @@ | |
383 | if (cmd->use_sg == 0) | |
384 | goto out; | |
385 | ||
386 | - use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL); | |
387 | + use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL); | |
388 | ||
389 | if (use_sg == 0) { | |
390 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); | |
391 | @@ -1532,6 +1533,13 @@ | |
392 | int retval = 1; | |
393 | ||
394 | command_que_value = tw_dev->command_packet_phys[request_id]; | |
395 | + | |
396 | + /* For 9650SE write low 4 bytes first */ | |
397 | + if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { | |
398 | + command_que_value += TW_COMMAND_OFFSET; | |
399 | + writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev)); | |
400 | + } | |
401 | + | |
402 | status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); | |
403 | ||
404 | if (twa_check_bits(status_reg_value)) | |
405 | @@ -1558,13 +1566,17 @@ | |
406 | TW_UNMASK_COMMAND_INTERRUPT(tw_dev); | |
407 | goto out; | |
408 | } else { | |
409 | - /* We successfully posted the command packet */ | |
410 | - if (sizeof(dma_addr_t) > 4) { | |
411 | - command_que_value += TW_COMMAND_OFFSET; | |
412 | - writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); | |
413 | - writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4); | |
414 | + if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { | |
415 | + /* Now write upper 4 bytes */ | |
416 | + writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4); | |
417 | } else { | |
418 | - writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); | |
419 | + if (sizeof(dma_addr_t) > 4) { | |
420 | + command_que_value += TW_COMMAND_OFFSET; | |
421 | + writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); | |
422 | + writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4); | |
423 | + } else { | |
424 | + writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); | |
425 | + } | |
426 | } | |
427 | tw_dev->state[request_id] = TW_S_POSTED; | |
428 | tw_dev->posted_request_count++; | |
429 | @@ -1621,14 +1633,9 @@ | |
430 | goto out; | |
431 | ||
432 | TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); | |
433 | + clear_bit(TW_IN_RESET, &tw_dev->flags); | |
434 | + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; | |
435 | ||
436 | - /* Wake up any ioctl that was pending before the reset */ | |
437 | - if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) { | |
438 | - clear_bit(TW_IN_RESET, &tw_dev->flags); | |
439 | - } else { | |
440 | - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; | |
441 | - wake_up(&tw_dev->ioctl_wqueue); | |
442 | - } | |
443 | retval = 0; | |
444 | out: | |
445 | return retval; | |
446 | @@ -1737,6 +1744,9 @@ | |
447 | "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", | |
448 | TW_DRIVER, 0x2c, SCpnt->cmnd[0]); | |
449 | ||
450 | + /* Make sure we are not issuing an ioctl or resetting from ioctl */ | |
451 | + mutex_lock(&tw_dev->ioctl_lock); | |
452 | + | |
453 | /* Now reset the card and some of the device extension data */ | |
454 | if (twa_reset_device_extension(tw_dev, 0)) { | |
455 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); | |
456 | @@ -1745,6 +1755,7 @@ | |
457 | ||
458 | retval = SUCCESS; | |
459 | out: | |
460 | + mutex_unlock(&tw_dev->ioctl_lock); | |
461 | return retval; | |
462 | } /* End twa_scsi_eh_reset() */ | |
463 | ||
464 | @@ -1754,8 +1765,14 @@ | |
465 | int request_id, retval; | |
466 | TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; | |
467 | ||
468 | + /* If we are resetting due to timed out ioctl, report as busy */ | |
469 | + if (test_bit(TW_IN_RESET, &tw_dev->flags)) { | |
470 | + retval = SCSI_MLQUEUE_HOST_BUSY; | |
471 | + goto out; | |
472 | + } | |
473 | + | |
474 | /* Check if this FW supports luns */ | |
475 | - if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) { | |
476 | + if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) { | |
477 | SCpnt->result = (DID_BAD_TARGET << 16); | |
478 | done(SCpnt); | |
479 | retval = 0; | |
480 | @@ -1828,10 +1845,10 @@ | |
481 | if (srb) { | |
482 | command_packet->unit = srb->device->id; | |
483 | command_packet->request_id__lunl = | |
484 | - TW_REQ_LUN_IN(srb->device->lun, request_id); | |
485 | + cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); | |
486 | } else { | |
487 | command_packet->request_id__lunl = | |
488 | - TW_REQ_LUN_IN(0, request_id); | |
489 | + cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); | |
490 | command_packet->unit = 0; | |
491 | } | |
492 | ||
493 | @@ -1841,8 +1858,8 @@ | |
494 | /* Map sglist from scsi layer to cmd packet */ | |
495 | if (tw_dev->srb[request_id]->use_sg == 0) { | |
496 | if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { | |
497 | - command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; | |
498 | - command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; | |
499 | + command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); | |
500 | + command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); | |
501 | if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) | |
502 | memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); | |
503 | } else { | |
504 | @@ -1850,12 +1867,12 @@ | |
505 | if (buffaddr == 0) | |
506 | goto out; | |
507 | ||
508 | - command_packet->sg_list[0].address = buffaddr; | |
509 | - command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen; | |
510 | + command_packet->sg_list[0].address = TW_CPU_TO_SGL(buffaddr); | |
511 | + command_packet->sg_list[0].length = cpu_to_le32(tw_dev->srb[request_id]->request_bufflen); | |
512 | } | |
513 | - command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), 1); | |
514 | + command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), 1)); | |
515 | ||
516 | - if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) { | |
517 | + if (command_packet->sg_list[0].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { | |
518 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi"); | |
519 | goto out; | |
520 | } | |
521 | @@ -1869,35 +1886,35 @@ | |
522 | memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length); | |
523 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | |
524 | } | |
525 | - command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; | |
526 | - command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; | |
527 | + command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); | |
528 | + command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); | |
529 | } else { | |
530 | sg_count = twa_map_scsi_sg_data(tw_dev, request_id); | |
531 | if (sg_count == 0) | |
532 | goto out; | |
533 | ||
534 | for (i = 0; i < sg_count; i++) { | |
535 | - command_packet->sg_list[i].address = sg_dma_address(&sglist[i]); | |
536 | - command_packet->sg_list[i].length = sg_dma_len(&sglist[i]); | |
537 | - if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { | |
538 | + command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(&sglist[i])); | |
539 | + command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(&sglist[i])); | |
540 | + if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { | |
541 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi"); | |
542 | goto out; | |
543 | } | |
544 | } | |
545 | } | |
546 | - command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg); | |
547 | + command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg)); | |
548 | } | |
549 | } else { | |
550 | /* Internal cdb post */ | |
551 | for (i = 0; i < use_sg; i++) { | |
552 | - command_packet->sg_list[i].address = sglistarg[i].address; | |
553 | - command_packet->sg_list[i].length = sglistarg[i].length; | |
554 | - if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { | |
555 | + command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); | |
556 | + command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length); | |
557 | + if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { | |
558 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); | |
559 | goto out; | |
560 | } | |
561 | } | |
562 | - command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg); | |
563 | + command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); | |
564 | } | |
565 | ||
566 | if (srb) { | |
567 | @@ -1961,6 +1978,9 @@ | |
568 | /* Disable interrupts */ | |
569 | TW_DISABLE_INTERRUPTS(tw_dev); | |
570 | ||
571 | + /* Free up the IRQ */ | |
572 | + free_irq(tw_dev->tw_pci_dev->irq, tw_dev); | |
573 | + | |
574 | printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no); | |
575 | ||
576 | /* Tell the card we are shutting down */ | |
577 | @@ -2092,21 +2112,25 @@ | |
578 | ||
579 | /* Initialize the card */ | |
580 | if (twa_reset_sequence(tw_dev, 0)) | |
581 | - goto out_release_mem_region; | |
582 | + goto out_iounmap; | |
583 | ||
584 | /* Set host specific parameters */ | |
585 | - host->max_id = TW_MAX_UNITS; | |
586 | + if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE) | |
587 | + host->max_id = TW_MAX_UNITS_9650SE; | |
588 | + else | |
589 | + host->max_id = TW_MAX_UNITS; | |
590 | + | |
591 | host->max_cmd_len = TW_MAX_CDB_LEN; | |
592 | ||
593 | /* Channels aren't supported by adapter */ | |
594 | - host->max_lun = TW_MAX_LUNS(tw_dev->working_srl); | |
595 | + host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl); | |
596 | host->max_channel = 0; | |
597 | ||
598 | /* Register the card with the kernel SCSI layer */ | |
599 | retval = scsi_add_host(host, &pdev->dev); | |
600 | if (retval) { | |
601 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed"); | |
602 | - goto out_release_mem_region; | |
603 | + goto out_iounmap; | |
604 | } | |
605 | ||
606 | pci_set_drvdata(pdev, host); | |
607 | @@ -2119,8 +2143,8 @@ | |
608 | TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), | |
609 | (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, | |
610 | TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), | |
611 | - *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, | |
612 | - TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)); | |
613 | + le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, | |
614 | + TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); | |
615 | ||
616 | /* Now setup the interrupt handler */ | |
617 | retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev); | |
618 | @@ -2146,6 +2170,8 @@ | |
619 | ||
620 | out_remove_host: | |
621 | scsi_remove_host(host); | |
622 | +out_iounmap: | |
623 | + iounmap(tw_dev->base_addr); | |
624 | out_release_mem_region: | |
625 | pci_release_regions(pdev); | |
626 | out_free_device_extension: | |
627 | @@ -2171,12 +2197,12 @@ | |
628 | twa_major = -1; | |
629 | } | |
630 | ||
631 | - /* Free up the IRQ */ | |
632 | - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); | |
633 | - | |
634 | /* Shutdown the card */ | |
635 | __twa_shutdown(tw_dev); | |
636 | ||
637 | + /* Free IO remapping */ | |
638 | + iounmap(tw_dev->base_addr); | |
639 | + | |
640 | /* Free up the mem region */ | |
641 | pci_release_regions(pdev); | |
642 | ||
643 | @@ -2194,6 +2220,8 @@ | |
644 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
645 | { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX, | |
646 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
647 | + { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE, | |
648 | + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | |
649 | { } | |
650 | }; | |
651 | MODULE_DEVICE_TABLE(pci, twa_pci_tbl); | |
652 | @@ -2212,7 +2240,7 @@ | |
653 | { | |
654 | printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); | |
655 | ||
656 | - return pci_module_init(&twa_driver); | |
657 | + return pci_register_driver(&twa_driver); | |
658 | } /* End twa_init() */ | |
659 | ||
660 | /* This function is called on driver exit */ | |
661 | diff -uNr linux-2.6.16.orig/drivers/scsi/3w-9xxx.h linux-2.6.16/drivers/scsi/3w-9xxx.h | |
662 | --- linux-2.6.16.orig/drivers/scsi/3w-9xxx.h 2006-03-20 06:53:29.000000000 +0100 | |
663 | +++ linux-2.6.16/drivers/scsi/3w-9xxx.h 2006-10-20 22:22:02.000000000 +0200 | |
664 | @@ -2,8 +2,9 @@ | |
665 | 3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux. | |
666 | ||
667 | Written By: Adam Radford <linuxraid@amcc.com> | |
668 | + Modifications By: Tom Couch <linuxraid@amcc.com> | |
669 | ||
670 | - Copyright (C) 2004-2005 Applied Micro Circuits Corporation. | |
671 | + Copyright (C) 2004-2006 Applied Micro Circuits Corporation. | |
672 | ||
673 | This program is free software; you can redistribute it and/or modify | |
674 | it under the terms of the GNU General Public License as published by | |
675 | @@ -287,11 +288,7 @@ | |
676 | #define TW_STATUS_UNEXPECTED_BITS 0x00F00000 | |
677 | #define TW_STATUS_VALID_INTERRUPT 0x00DF0000 | |
678 | ||
679 | -/* RESPONSE QUEUE BIT DEFINITIONS */ | |
680 | -#define TW_RESPONSE_ID_MASK 0x00000FF0 | |
681 | - | |
682 | /* PCI related defines */ | |
683 | -#define TW_NUMDEVICES 1 | |
684 | #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 | |
685 | #define TW_PCI_CLEAR_PCI_ABORT 0x2000 | |
686 | ||
687 | @@ -337,6 +334,7 @@ | |
688 | #define TW_ALIGNMENT_9000 4 /* 4 bytes */ | |
689 | #define TW_ALIGNMENT_9000_SGL 0x3 | |
690 | #define TW_MAX_UNITS 16 | |
691 | +#define TW_MAX_UNITS_9650SE 32 | |
692 | #define TW_INIT_MESSAGE_CREDITS 0x100 | |
693 | #define TW_INIT_COMMAND_PACKET_SIZE 0x3 | |
694 | #define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 | |
695 | @@ -356,7 +354,6 @@ | |
696 | #define TW_MAX_RESPONSE_DRAIN 256 | |
697 | #define TW_MAX_AEN_DRAIN 40 | |
698 | #define TW_IN_RESET 2 | |
699 | -#define TW_IN_CHRDEV_IOCTL 3 | |
700 | #define TW_IN_ATTENTION_LOOP 4 | |
701 | #define TW_MAX_SECTORS 256 | |
702 | #define TW_AEN_WAIT_TIME 1000 | |
703 | @@ -419,6 +416,9 @@ | |
704 | #ifndef PCI_DEVICE_ID_3WARE_9550SX | |
705 | #define PCI_DEVICE_ID_3WARE_9550SX 0x1003 | |
706 | #endif | |
707 | +#ifndef PCI_DEVICE_ID_3WARE_9650SE | |
708 | +#define PCI_DEVICE_ID_3WARE_9650SE 0x1004 | |
709 | +#endif | |
710 | ||
711 | /* Bitmask macros to eliminate bitfields */ | |
712 | ||
713 | @@ -444,6 +444,7 @@ | |
714 | #define TW_CONTROL_REG_ADDR(x) (x->base_addr) | |
715 | #define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4) | |
716 | #define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8)) | |
717 | +#define TW_COMMAND_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x20) | |
718 | #define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC) | |
719 | #define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30) | |
720 | #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x))) | |
721 | @@ -471,6 +472,7 @@ | |
722 | #define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109) | |
723 | #define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62) | |
724 | #define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0) | |
725 | +#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) | |
726 | ||
727 | #pragma pack(1) | |
728 | ||
729 | @@ -614,13 +616,6 @@ | |
730 | u32 value; | |
731 | } TW_Response_Queue; | |
732 | ||
733 | -typedef struct TAG_TW_Info { | |
734 | - char *buffer; | |
735 | - int length; | |
736 | - int offset; | |
737 | - int position; | |
738 | -} TW_Info; | |
739 | - | |
740 | /* Compatibility information structure */ | |
741 | typedef struct TAG_TW_Compatibility_Info | |
742 | { | |
743 | @@ -634,8 +629,13 @@ | |
744 | unsigned short driver_srl_low; | |
745 | unsigned short driver_branch_low; | |
746 | unsigned short driver_build_low; | |
747 | + unsigned short fw_on_ctlr_srl; | |
748 | + unsigned short fw_on_ctlr_branch; | |
749 | + unsigned short fw_on_ctlr_build; | |
750 | } TW_Compatibility_Info; | |
751 | ||
752 | +#pragma pack() | |
753 | + | |
754 | typedef struct TAG_TW_Device_Extension { | |
755 | u32 __iomem *base_addr; | |
756 | unsigned long *generic_buffer_virt[TW_Q_LENGTH]; | |
757 | @@ -674,12 +674,8 @@ | |
758 | wait_queue_head_t ioctl_wqueue; | |
759 | struct mutex ioctl_lock; | |
760 | char aen_clobber; | |
761 | - unsigned short working_srl; | |
762 | - unsigned short working_branch; | |
763 | - unsigned short working_build; | |
764 | + TW_Compatibility_Info tw_compat_info; | |
765 | } TW_Device_Extension; | |
766 | ||
767 | -#pragma pack() | |
768 | - | |
769 | #endif /* _3W_9XXX_H */ | |
770 |