Line 0
Link Here
|
|
|
1 |
/* |
2 |
3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. |
3 |
|
4 |
Written By: Adam Radford <linuxraid@amcc.com> |
5 |
|
6 |
Copyright (C) 2004 Applied Micro Circuits Corporation. |
7 |
|
8 |
This program is free software; you can redistribute it and/or modify |
9 |
it under the terms of the GNU General Public License as published by |
10 |
the Free Software Foundation; version 2 of the License. |
11 |
|
12 |
This program is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
16 |
|
17 |
NO WARRANTY |
18 |
THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR |
19 |
CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT |
20 |
LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, |
21 |
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is |
22 |
solely responsible for determining the appropriateness of using and |
23 |
distributing the Program and assumes all risks associated with its |
24 |
exercise of rights under this Agreement, including but not limited to |
25 |
the risks and costs of program errors, damage to or loss of data, |
26 |
programs or equipment, and unavailability or interruption of operations. |
27 |
|
28 |
DISCLAIMER OF LIABILITY |
29 |
NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY |
30 |
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
31 |
DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND |
32 |
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
33 |
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
34 |
USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED |
35 |
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES |
36 |
|
37 |
You should have received a copy of the GNU General Public License |
38 |
along with this program; if not, write to the Free Software |
39 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
40 |
|
41 |
Bugs/Comments/Suggestions should be mailed to: |
42 |
linuxraid@amcc.com |
43 |
|
44 |
For more information, goto: |
45 |
http://www.amcc.com |
46 |
|
47 |
Note: This version of the driver does not contain a bundled firmware |
48 |
image. |
49 |
|
50 |
History |
51 |
------- |
52 |
2.26.00.005 - Initial release. |
53 |
2.26.00.006 - Remove TW_WRITEL macro, replace with writeq(). |
54 |
2.26.00.007 - Skip lun and channel probes. |
55 |
*/ |
56 |
|
57 |
#include <linux/module.h> |
58 |
|
59 |
MODULE_AUTHOR ("AMCC"); |
60 |
#ifdef CONFIG_SMP |
61 |
MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver (SMP)"); |
62 |
#else |
63 |
MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver"); |
64 |
#endif |
65 |
MODULE_LICENSE("GPL"); |
66 |
|
67 |
#include <linux/kernel.h> |
68 |
#include <linux/pci.h> |
69 |
#include <linux/time.h> |
70 |
#include <linux/proc_fs.h> |
71 |
#include <linux/sched.h> |
72 |
#include <linux/ioport.h> |
73 |
#include <linux/blkdev.h> |
74 |
#include <linux/hdreg.h> |
75 |
#include <linux/string.h> |
76 |
#include <linux/delay.h> |
77 |
#include <linux/smp.h> |
78 |
#include <linux/reboot.h> |
79 |
#include <linux/spinlock.h> |
80 |
#include <linux/interrupt.h> |
81 |
#include <linux/moduleparam.h> |
82 |
|
83 |
#include <asm/errno.h> |
84 |
#include <asm/io.h> |
85 |
#include <asm/irq.h> |
86 |
#include <asm/uaccess.h> |
87 |
|
88 |
#include "scsi.h" |
89 |
#include "hosts.h" |
90 |
|
91 |
#include "3w-9xxx.h" |
92 |
|
93 |
/* Notifier block to get a notify on system shutdown/halt/reboot */ |
94 |
static struct notifier_block twa_notifier = { |
95 |
.notifier_call = twa_halt, |
96 |
.next = NULL, |
97 |
.priority = 0 |
98 |
}; |
99 |
|
100 |
/* File operations struct for character device */ |
101 |
static struct file_operations twa_fops = { |
102 |
.owner = THIS_MODULE, |
103 |
.ioctl = twa_chrdev_ioctl, |
104 |
.open = twa_chrdev_open, |
105 |
.release = twa_chrdev_release |
106 |
}; |
107 |
|
108 |
/* Globals */ |
109 |
char *twa_driver_version="2.26.00.007"; |
110 |
TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; |
111 |
unsigned int twa_device_extension_count = 0; |
112 |
static int twa_major = -1; |
113 |
extern struct timezone sys_tz; |
114 |
static int cmds_per_lun; |
115 |
|
116 |
/* Module parameters */ |
117 |
module_param(cmds_per_lun, int, 0); |
118 |
MODULE_PARM_DESC(cmds_per_lun, "Maximum commands per LUN"); |
119 |
|
120 |
/* Functions */ |
121 |
|
122 |
/* This function will complete an aen request from the isr */ |
123 |
static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) |
124 |
{ |
125 |
TW_Command_Full *full_command_packet; |
126 |
TW_Command *command_packet; |
127 |
TW_Command_Apache_Header *header; |
128 |
unsigned short aen; |
129 |
int retval = 1; |
130 |
|
131 |
header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; |
132 |
tw_dev->posted_request_count--; |
133 |
aen = header->status_block.error; |
134 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
135 |
command_packet = &full_command_packet->command.oldcommand; |
136 |
|
137 |
/* First check for internal completion of set param for time sync */ |
138 |
if (command_packet->byte0_offset.opcode == TW_OP_SET_PARAM) { |
139 |
/* Keep reading the queue in case there are more aen's */ |
140 |
if (twa_aen_read_queue(tw_dev, request_id)) |
141 |
goto out2; |
142 |
else { |
143 |
retval = 0; |
144 |
goto out; |
145 |
} |
146 |
} |
147 |
|
148 |
switch (aen) { |
149 |
case TW_AEN_QUEUE_EMPTY: |
150 |
/* Quit reading the queue if this is the last one */ |
151 |
break; |
152 |
case TW_AEN_SYNC_TIME_WITH_HOST: |
153 |
twa_aen_sync_time(tw_dev, request_id); |
154 |
retval = 0; |
155 |
goto out; |
156 |
default: |
157 |
twa_aen_queue_event(tw_dev, header); |
158 |
|
159 |
/* If there are more aen's, keep reading the queue */ |
160 |
if (twa_aen_read_queue(tw_dev, request_id)) |
161 |
goto out2; |
162 |
else { |
163 |
retval = 0; |
164 |
goto out; |
165 |
} |
166 |
} |
167 |
retval = 0; |
168 |
out2: |
169 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
170 |
twa_free_request_id(tw_dev, request_id); |
171 |
TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); |
172 |
clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); |
173 |
out: |
174 |
return retval; |
175 |
} /* End twa_aen_complete() */ |
176 |
|
177 |
/* This function will drain aen queue */ |
178 |
static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) |
179 |
{ |
180 |
int request_id = 0; |
181 |
char cdb[TW_MAX_CDB_LEN]; |
182 |
TW_SG_Apache sglist[1]; |
183 |
int finished = 0, count = 0; |
184 |
TW_Command_Full *full_command_packet; |
185 |
TW_Command_Apache_Header *header; |
186 |
unsigned short aen; |
187 |
int first_reset = 0, queue = 0, retval = 1; |
188 |
|
189 |
if (no_check_reset) |
190 |
first_reset = 0; |
191 |
else |
192 |
first_reset = 1; |
193 |
|
194 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
195 |
memset(full_command_packet, 0, sizeof(TW_Command_Full)); |
196 |
|
197 |
/* Initialize cdb */ |
198 |
memset(&cdb, 0, TW_MAX_CDB_LEN); |
199 |
cdb[0] = REQUEST_SENSE; /* opcode */ |
200 |
cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ |
201 |
|
202 |
/* Initialize sglist */ |
203 |
memset(&sglist, 0, sizeof(TW_SG_Apache)); |
204 |
sglist[0].length = TW_SECTOR_SIZE; |
205 |
sglist[0].address = tw_dev->generic_buffer_phys[request_id]; |
206 |
|
207 |
if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { |
208 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); |
209 |
goto out; |
210 |
} |
211 |
|
212 |
/* Mark internal command */ |
213 |
tw_dev->srb[request_id] = NULL; |
214 |
|
215 |
do { |
216 |
/* Send command to the board */ |
217 |
if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { |
218 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense"); |
219 |
goto out; |
220 |
} |
221 |
|
222 |
/* Now poll for completion */ |
223 |
if (twa_poll_response(tw_dev, request_id, 30)) { |
224 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue"); |
225 |
tw_dev->posted_request_count--; |
226 |
goto out; |
227 |
} |
228 |
|
229 |
tw_dev->posted_request_count--; |
230 |
header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; |
231 |
aen = header->status_block.error; |
232 |
queue = 0; |
233 |
count++; |
234 |
|
235 |
switch (aen) { |
236 |
case TW_AEN_QUEUE_EMPTY: |
237 |
if (first_reset != 1) |
238 |
goto out; |
239 |
else |
240 |
finished = 1; |
241 |
break; |
242 |
case TW_AEN_SOFT_RESET: |
243 |
if (first_reset == 0) |
244 |
first_reset = 1; |
245 |
else |
246 |
queue = 1; |
247 |
break; |
248 |
case TW_AEN_SYNC_TIME_WITH_HOST: |
249 |
break; |
250 |
default: |
251 |
queue = 1; |
252 |
} |
253 |
|
254 |
/* Now queue an event info */ |
255 |
if (queue) |
256 |
twa_aen_queue_event(tw_dev, header); |
257 |
} while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); |
258 |
|
259 |
if (count == TW_MAX_AEN_DRAIN) |
260 |
goto out; |
261 |
|
262 |
retval = 0; |
263 |
out: |
264 |
tw_dev->state[request_id] = TW_S_INITIAL; |
265 |
return retval; |
266 |
} /* End twa_aen_drain_queue() */ |
267 |
|
268 |
/* This function will queue an event */ |
269 |
static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) |
270 |
{ |
271 |
u32 local_time; |
272 |
struct timeval time; |
273 |
TW_Event *event; |
274 |
unsigned short aen; |
275 |
char host[16]; |
276 |
|
277 |
tw_dev->aen_count++; |
278 |
|
279 |
/* Fill out event info */ |
280 |
event = tw_dev->event_queue[tw_dev->error_index]; |
281 |
|
282 |
/* Check for clobber */ |
283 |
host[0] = '\0'; |
284 |
if (tw_dev->host) { |
285 |
sprintf(host, " scsi%d:", tw_dev->host->host_no); |
286 |
if (event->retrieved == TW_AEN_NOT_RETRIEVED) |
287 |
tw_dev->aen_clobber = 1; |
288 |
} |
289 |
|
290 |
aen = header->status_block.error; |
291 |
memset(event, 0, sizeof(TW_Event)); |
292 |
|
293 |
event->severity = header->status_block.substatus_block.severity; |
294 |
do_gettimeofday(&time); |
295 |
local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); |
296 |
event->time_stamp_sec = local_time; |
297 |
event->aen_code = aen; |
298 |
event->retrieved = TW_AEN_NOT_RETRIEVED; |
299 |
event->sequence_id = tw_dev->error_sequence_id; |
300 |
tw_dev->error_sequence_id++; |
301 |
|
302 |
header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; |
303 |
event->parameter_len = strlen(header->err_specific_desc); |
304 |
memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len); |
305 |
if (event->severity != TW_AEN_SEVERITY_DEBUG) |
306 |
printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", host, twa_aen_severity_lookup(header->status_block.substatus_block.severity), TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, twa_string_lookup(twa_aen_table, aen), header->err_specific_desc); |
307 |
else |
308 |
tw_dev->aen_count--; |
309 |
|
310 |
if ((tw_dev->error_index + 1) == TW_Q_LENGTH) |
311 |
tw_dev->event_queue_wrapped = 1; |
312 |
tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; |
313 |
} /* End twa_aen_queue_event() */ |
314 |
|
315 |
/* This function will read the aen queue from the isr */ |
316 |
static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) |
317 |
{ |
318 |
char cdb[TW_MAX_CDB_LEN]; |
319 |
TW_SG_Apache sglist[1]; |
320 |
TW_Command_Full *full_command_packet; |
321 |
int retval = 1; |
322 |
|
323 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
324 |
memset(full_command_packet, 0, sizeof(TW_Command_Full)); |
325 |
|
326 |
/* Initialize cdb */ |
327 |
memset(&cdb, 0, TW_MAX_CDB_LEN); |
328 |
cdb[0] = REQUEST_SENSE; /* opcode */ |
329 |
cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ |
330 |
|
331 |
/* Initialize sglist */ |
332 |
memset(&sglist, 0, sizeof(TW_SG_Apache)); |
333 |
sglist[0].length = TW_SECTOR_SIZE; |
334 |
sglist[0].address = tw_dev->generic_buffer_phys[request_id]; |
335 |
|
336 |
/* Mark internal command */ |
337 |
tw_dev->srb[request_id] = NULL; |
338 |
|
339 |
/* Now post the command packet */ |
340 |
if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { |
341 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue"); |
342 |
goto out; |
343 |
} |
344 |
retval = 0; |
345 |
out: |
346 |
return retval; |
347 |
} /* End twa_aen_read_queue() */ |
348 |
|
349 |
/* This function will look up an AEN severity string */ |
350 |
static char *twa_aen_severity_lookup(unsigned char severity_code) |
351 |
{ |
352 |
char *retval = NULL; |
353 |
|
354 |
if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || |
355 |
(severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) |
356 |
goto out; |
357 |
|
358 |
retval = twa_aen_severity_table[severity_code]; |
359 |
out: |
360 |
return retval; |
361 |
} /* End twa_aen_severity_lookup() */ |
362 |
|
363 |
/* This function will sync firmware time with the host time */ |
364 |
static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) |
365 |
{ |
366 |
u32 schedulertime; |
367 |
struct timeval utc; |
368 |
TW_Command_Full *full_command_packet; |
369 |
TW_Command *command_packet; |
370 |
TW_Param_Apache *param; |
371 |
u32 local_time; |
372 |
|
373 |
/* Fill out the command packet */ |
374 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
375 |
memset(full_command_packet, 0, sizeof(TW_Command_Full)); |
376 |
command_packet = &full_command_packet->command.oldcommand; |
377 |
command_packet->byte0_offset.opcode = TW_OP_SET_PARAM; |
378 |
command_packet->byte0_offset.sgl_offset = 2; |
379 |
command_packet->request_id = request_id; |
380 |
command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id]; |
381 |
command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; |
382 |
command_packet->size = TW_COMMAND_SIZE; |
383 |
command_packet->byte6_offset.parameter_count = 1; |
384 |
|
385 |
/* Setup the param */ |
386 |
param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; |
387 |
memset(param, 0, TW_SECTOR_SIZE); |
388 |
param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */ |
389 |
param->parameter_id = 0x3; /* SchedulerTime */ |
390 |
param->parameter_size_bytes = 4; |
391 |
|
392 |
/* Convert system time in UTC to local time seconds since last |
393 |
Sunday 12:00AM */ |
394 |
do_gettimeofday(&utc); |
395 |
local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); |
396 |
schedulertime = local_time - (3 * 86400); |
397 |
schedulertime = schedulertime % 604800; |
398 |
|
399 |
memcpy(param->data, &schedulertime, sizeof(u32)); |
400 |
|
401 |
/* Mark internal command */ |
402 |
tw_dev->srb[request_id] = NULL; |
403 |
|
404 |
/* Now post the command */ |
405 |
twa_post_command_packet(tw_dev, request_id); |
406 |
} /* End twa_aen_sync_time() */ |
407 |
|
408 |
/* This function will allocate memory and check if it is correctly aligned */ |
409 |
static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) |
410 |
{ |
411 |
int i; |
412 |
dma_addr_t dma_handle; |
413 |
unsigned long *cpu_addr; |
414 |
int retval = 1; |
415 |
|
416 |
cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); |
417 |
if (!cpu_addr) { |
418 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); |
419 |
goto out; |
420 |
} |
421 |
|
422 |
if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { |
423 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); |
424 |
pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); |
425 |
goto out; |
426 |
} |
427 |
|
428 |
memset(cpu_addr, 0, size*TW_Q_LENGTH); |
429 |
|
430 |
for (i = 0; i < TW_Q_LENGTH; i++) { |
431 |
switch(which) { |
432 |
case 0: |
433 |
tw_dev->command_packet_phys[i] = dma_handle+(i*size); |
434 |
tw_dev->command_packet_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); |
435 |
break; |
436 |
case 1: |
437 |
tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); |
438 |
tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); |
439 |
break; |
440 |
} |
441 |
} |
442 |
retval = 0; |
443 |
out: |
444 |
return retval; |
445 |
} /* End twa_allocate_memory() */ |
446 |
|
447 |
/* This function will check the status register for unexpected bits */ |
448 |
static int twa_check_bits(u32 status_reg_value) |
449 |
{ |
450 |
int retval = 1; |
451 |
|
452 |
if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) |
453 |
goto out; |
454 |
if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) |
455 |
goto out; |
456 |
|
457 |
retval = 0; |
458 |
out: |
459 |
return retval; |
460 |
} /* End twa_check_bits() */ |
461 |
|
462 |
/* This function will check the srl and decide if we are compatible */ |
463 |
static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) |
464 |
{ |
465 |
int retval = 1; |
466 |
unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; |
467 |
unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; |
468 |
u32 init_connect_result = 0; |
469 |
|
470 |
if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL, TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH, TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) { |
471 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL"); |
472 |
goto out; |
473 |
} |
474 |
|
475 |
tw_dev->working_srl = TW_CURRENT_FW_SRL; |
476 |
tw_dev->working_branch = TW_CURRENT_FW_BRANCH; |
477 |
tw_dev->working_build = TW_CURRENT_FW_BUILD; |
478 |
|
479 |
/* Try base mode compatibility */ |
480 |
if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { |
481 |
if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, TW_EXTENDED_INIT_CONNECT, TW_BASE_FW_SRL, TW_9000_ARCH_ID, TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD, &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, &fw_on_ctlr_build, &init_connect_result)) { |
482 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL"); |
483 |
goto out; |
484 |
} |
485 |
if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { |
486 |
if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) { |
487 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware"); |
488 |
} else { |
489 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver"); |
490 |
} |
491 |
goto out; |
492 |
} |
493 |
tw_dev->working_srl = TW_BASE_FW_SRL; |
494 |
tw_dev->working_branch = TW_BASE_FW_BRANCH; |
495 |
tw_dev->working_build = TW_BASE_FW_BUILD; |
496 |
} |
497 |
retval = 0; |
498 |
out: |
499 |
return retval; |
500 |
} /* End twa_check_srl() */ |
501 |
|
502 |
/* This function handles ioctl for the character device */ |
503 |
static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) |
504 |
{ |
505 |
long timeout; |
506 |
unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; |
507 |
dma_addr_t dma_handle; |
508 |
int request_id = 0; |
509 |
unsigned int sequence_id = 0; |
510 |
unsigned char event_index, start_index; |
511 |
TW_Ioctl_Driver_Command driver_command; |
512 |
TW_Ioctl_Buf_Apache *tw_ioctl; |
513 |
TW_Lock *tw_lock; |
514 |
TW_Command_Full *full_command_packet; |
515 |
TW_Compatibility_Info *tw_compat_info; |
516 |
TW_Event *event; |
517 |
struct timeval current_time; |
518 |
u32 current_time_ms; |
519 |
TW_Device_Extension *tw_dev = twa_device_extension_list[MINOR(inode->i_rdev)]; |
520 |
int retval = TW_IOCTL_ERROR_OS_EFAULT; |
521 |
|
522 |
/* Only let one of these through at a time */ |
523 |
if (down_interruptible(&tw_dev->ioctl_sem)) { |
524 |
retval = TW_IOCTL_ERROR_OS_EINTR; |
525 |
goto out; |
526 |
} |
527 |
|
528 |
/* First copy down the driver command */ |
529 |
if (copy_from_user(&driver_command, (void *)arg, sizeof(TW_Ioctl_Driver_Command))) |
530 |
goto out2; |
531 |
|
532 |
/* Check data buffer size */ |
533 |
if (driver_command.buffer_length > TW_MAX_SECTORS * 512) { |
534 |
retval = TW_IOCTL_ERROR_OS_EINVAL; |
535 |
goto out2; |
536 |
} |
537 |
|
538 |
/* Hardware can only do multiple of 512 byte transfers */ |
539 |
data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; |
540 |
|
541 |
/* Now allocate ioctl buf memory */ |
542 |
cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle); |
543 |
if (!cpu_addr) { |
544 |
retval = TW_IOCTL_ERROR_OS_ENOMEM; |
545 |
goto out2; |
546 |
} |
547 |
|
548 |
tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; |
549 |
|
550 |
/* Now copy down the entire ioctl */ |
551 |
if (copy_from_user(tw_ioctl, (void *)arg, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) |
552 |
goto out3; |
553 |
|
554 |
/* See which ioctl we are doing */ |
555 |
switch (cmd) { |
556 |
case TW_IOCTL_FIRMWARE_PASS_THROUGH: |
557 |
spin_lock_irqsave(tw_dev->host->host_lock, flags); |
558 |
twa_get_request_id(tw_dev, &request_id); |
559 |
|
560 |
/* Flag internal command */ |
561 |
tw_dev->srb[request_id] = 0; |
562 |
|
563 |
/* Flag chrdev ioctl */ |
564 |
tw_dev->chrdev_request_id = request_id; |
565 |
|
566 |
full_command_packet = &tw_ioctl->firmware_command; |
567 |
|
568 |
/* Load request id and sglist for both command types */ |
569 |
twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); |
570 |
|
571 |
memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); |
572 |
|
573 |
/* Now post the command packet to the controller */ |
574 |
twa_post_command_packet(tw_dev, request_id); |
575 |
spin_unlock_irqrestore(tw_dev->host->host_lock, flags); |
576 |
|
577 |
timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; |
578 |
|
579 |
/* Now wait for command to complete */ |
580 |
timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); |
581 |
|
582 |
/* Check if we timed out, got a signal, or didn't get |
583 |
an interrupt */ |
584 |
if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) { |
585 |
/* Now we need to reset the board */ |
586 |
if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) { |
587 |
retval = timeout; |
588 |
} else { |
589 |
printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0xc, cmd); |
590 |
retval = TW_IOCTL_ERROR_OS_EIO; |
591 |
} |
592 |
spin_lock_irqsave(tw_dev->host->host_lock, flags); |
593 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
594 |
twa_free_request_id(tw_dev, request_id); |
595 |
tw_dev->posted_request_count--; |
596 |
twa_reset_device_extension(tw_dev); |
597 |
spin_unlock_irqrestore(tw_dev->host->host_lock, flags); |
598 |
goto out3; |
599 |
} |
600 |
|
601 |
/* Now copy in the command packet response */ |
602 |
memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); |
603 |
|
604 |
/* Now complete the io */ |
605 |
spin_lock_irqsave(tw_dev->host->host_lock, flags); |
606 |
tw_dev->posted_request_count--; |
607 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
608 |
twa_free_request_id(tw_dev, request_id); |
609 |
spin_unlock_irqrestore(tw_dev->host->host_lock, flags); |
610 |
break; |
611 |
case TW_IOCTL_GET_COMPATIBILITY_INFO: |
612 |
tw_ioctl->driver_command.status = 0; |
613 |
/* Copy compatiblity struct into ioctl data buffer */ |
614 |
tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; |
615 |
strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version)); |
616 |
tw_compat_info->working_srl = tw_dev->working_srl; |
617 |
tw_compat_info->working_branch = tw_dev->working_branch; |
618 |
tw_compat_info->working_build = tw_dev->working_build; |
619 |
break; |
620 |
case TW_IOCTL_GET_LAST_EVENT: |
621 |
if (tw_dev->event_queue_wrapped) { |
622 |
if (tw_dev->aen_clobber) { |
623 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; |
624 |
tw_dev->aen_clobber = 0; |
625 |
} else |
626 |
tw_ioctl->driver_command.status = 0; |
627 |
} else { |
628 |
if (!tw_dev->error_index) { |
629 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
630 |
break; |
631 |
} |
632 |
tw_ioctl->driver_command.status = 0; |
633 |
} |
634 |
event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH; |
635 |
memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); |
636 |
tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; |
637 |
break; |
638 |
case TW_IOCTL_GET_FIRST_EVENT: |
639 |
if (tw_dev->event_queue_wrapped) { |
640 |
if (tw_dev->aen_clobber) { |
641 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; |
642 |
tw_dev->aen_clobber = 0; |
643 |
} else |
644 |
tw_ioctl->driver_command.status = 0; |
645 |
event_index = tw_dev->error_index; |
646 |
} else { |
647 |
if (!tw_dev->error_index) { |
648 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
649 |
break; |
650 |
} |
651 |
tw_ioctl->driver_command.status = 0; |
652 |
event_index = 0; |
653 |
} |
654 |
memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); |
655 |
tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; |
656 |
break; |
657 |
case TW_IOCTL_GET_NEXT_EVENT: |
658 |
event = (TW_Event *)tw_ioctl->data_buffer; |
659 |
sequence_id = event->sequence_id; |
660 |
tw_ioctl->driver_command.status = 0; |
661 |
|
662 |
if (tw_dev->event_queue_wrapped) { |
663 |
if (tw_dev->aen_clobber) { |
664 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; |
665 |
tw_dev->aen_clobber = 0; |
666 |
} |
667 |
start_index = tw_dev->error_index; |
668 |
} else { |
669 |
if (!tw_dev->error_index) { |
670 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
671 |
break; |
672 |
} |
673 |
start_index = 0; |
674 |
} |
675 |
event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH; |
676 |
|
677 |
if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) { |
678 |
if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) |
679 |
tw_dev->aen_clobber = 1; |
680 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
681 |
break; |
682 |
} |
683 |
memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); |
684 |
tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; |
685 |
break; |
686 |
case TW_IOCTL_GET_PREVIOUS_EVENT: |
687 |
event = (TW_Event *)tw_ioctl->data_buffer; |
688 |
sequence_id = event->sequence_id; |
689 |
tw_ioctl->driver_command.status = 0; |
690 |
|
691 |
if (tw_dev->event_queue_wrapped) { |
692 |
if (tw_dev->aen_clobber) { |
693 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; |
694 |
tw_dev->aen_clobber = 0; |
695 |
} |
696 |
start_index = tw_dev->error_index; |
697 |
} else { |
698 |
if (!tw_dev->error_index) { |
699 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
700 |
break; |
701 |
} |
702 |
start_index = 0; |
703 |
} |
704 |
event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH; |
705 |
|
706 |
if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) { |
707 |
if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) |
708 |
tw_dev->aen_clobber = 1; |
709 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; |
710 |
break; |
711 |
} |
712 |
memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); |
713 |
tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; |
714 |
break; |
715 |
case TW_IOCTL_GET_LOCK: |
716 |
tw_lock = (TW_Lock *)tw_ioctl->data_buffer; |
717 |
do_gettimeofday(¤t_time); |
718 |
current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); |
719 |
|
720 |
if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) { |
721 |
tw_dev->ioctl_sem_lock = 1; |
722 |
tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec; |
723 |
tw_ioctl->driver_command.status = 0; |
724 |
tw_lock->time_remaining_msec = tw_lock->timeout_msec; |
725 |
} else { |
726 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED; |
727 |
tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms; |
728 |
} |
729 |
break; |
730 |
case TW_IOCTL_RELEASE_LOCK: |
731 |
if (tw_dev->ioctl_sem_lock == 1) { |
732 |
tw_dev->ioctl_sem_lock = 0; |
733 |
tw_ioctl->driver_command.status = 0; |
734 |
} else { |
735 |
tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED; |
736 |
} |
737 |
break; |
738 |
default: |
739 |
retval = TW_IOCTL_ERROR_OS_ENOTTY; |
740 |
goto out3; |
741 |
} |
742 |
|
743 |
/* Now copy the entire response to userspace */ |
744 |
if (copy_to_user((void *)arg, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) |
745 |
retval = 0; |
746 |
out3: |
747 |
/* Now free ioctl buf memory */ |
748 |
pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); |
749 |
out2: |
750 |
up(&tw_dev->ioctl_sem); |
751 |
out: |
752 |
return retval; |
753 |
} /* End twa_chrdev_ioctl() */ |
754 |
|
755 |
/* This function handles open for the character device */ |
756 |
static int twa_chrdev_open(struct inode *inode, struct file *file) |
757 |
{ |
758 |
unsigned int minor_number; |
759 |
int retval = TW_IOCTL_ERROR_OS_ENODEV; |
760 |
|
761 |
minor_number = MINOR(inode->i_rdev); |
762 |
if (minor_number >= twa_device_extension_count) |
763 |
goto out; |
764 |
retval = 0; |
765 |
out: |
766 |
return retval; |
767 |
} /* End twa_chrdev_open() */ |
768 |
|
769 |
/* This function handles close for the character device */ |
770 |
static int twa_chrdev_release(struct inode *inode, struct file *file) |
771 |
{ |
772 |
return 0; |
773 |
} /* End twa_chrdev_release() */ |
774 |
|
775 |
/* This function is called by twa_scsi_proc_info */ |
776 |
static int twa_copy_info(TW_Info *info, char *fmt, ...) |
777 |
{ |
778 |
va_list args; |
779 |
char buf[81]; |
780 |
int len; |
781 |
|
782 |
va_start(args, fmt); |
783 |
len = vsprintf(buf, fmt, args); |
784 |
va_end(args); |
785 |
twa_copy_mem_info(info, buf, len); |
786 |
|
787 |
return len; |
788 |
} /* End twa_copy_info() */ |
789 |
|
790 |
/* This function is called by twa_scsi_proc_info */ |
791 |
static void twa_copy_mem_info(TW_Info *info, char *data, int len) |
792 |
{ |
793 |
if (info->position + len > info->length) |
794 |
len = info->length - info->position; |
795 |
|
796 |
if (info->position + len < info->offset) { |
797 |
info->position += len; |
798 |
return; |
799 |
} |
800 |
if (info->position < info->offset) { |
801 |
data += (info->offset - info->position); |
802 |
len -= (info->offset - info->position); |
803 |
} |
804 |
if (len > 0) { |
805 |
memcpy(info->buffer + info->position, data, len); |
806 |
info->position += len; |
807 |
} |
808 |
} /* End twa_copy_mem_info() */ |
809 |
|
810 |
/* This function will print readable messages from status register errors */ |
811 |
static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) |
812 |
{ |
813 |
int retval = 1; |
814 |
|
815 |
/* Check for various error conditions and handle them appropriately */ |
816 |
if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { |
817 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing"); |
818 |
writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); |
819 |
} |
820 |
|
821 |
if (status_reg_value & TW_STATUS_PCI_ABORT) { |
822 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing"); |
823 |
writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev)); |
824 |
pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); |
825 |
} |
826 |
|
827 |
if (status_reg_value & TW_STATUS_QUEUE_ERROR) { |
828 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); |
829 |
writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); |
830 |
} |
831 |
|
832 |
if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) { |
833 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing"); |
834 |
writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); |
835 |
} |
836 |
|
837 |
if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { |
838 |
if (tw_dev->reset_print == 0) { |
839 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing"); |
840 |
tw_dev->reset_print = 1; |
841 |
} |
842 |
goto out; |
843 |
} |
844 |
retval = 0; |
845 |
out: |
846 |
return retval; |
847 |
} /* End twa_decode_bits() */ |
848 |
|
849 |
/* This function will empty the response queue */ |
850 |
static int twa_empty_response_queue(TW_Device_Extension *tw_dev) |
851 |
{ |
852 |
u32 status_reg_value, response_que_value; |
853 |
int count = 0, retval = 1; |
854 |
|
855 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
856 |
|
857 |
while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { |
858 |
response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); |
859 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
860 |
count++; |
861 |
} |
862 |
if (count == TW_MAX_RESPONSE_DRAIN) |
863 |
goto out; |
864 |
|
865 |
retval = 0; |
866 |
out: |
867 |
return retval; |
868 |
} /* End twa_empty_response_queue() */ |
869 |
|
870 |
/* This function passes sense keys from firmware to scsi layer */ |
871 |
static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host) |
872 |
{ |
873 |
TW_Command_Full *full_command_packet; |
874 |
unsigned short error; |
875 |
int retval = 1; |
876 |
|
877 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
878 |
/* Don't print error for Logical unit not supported during rollcall */ |
879 |
error = full_command_packet->header.status_block.error; |
880 |
if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) { |
881 |
if (print_host) |
882 |
printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", tw_dev->host->host_no, TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc); |
883 |
else |
884 |
printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", TW_MESSAGE_SOURCE_CONTROLLER_ERROR, full_command_packet->header.status_block.error, twa_string_lookup(twa_error_table, full_command_packet->header.status_block.error), full_command_packet->header.err_specific_desc); |
885 |
} |
886 |
|
887 |
if (copy_sense) { |
888 |
memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH); |
889 |
tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); |
890 |
retval = TW_ISR_DONT_RESULT; |
891 |
goto out; |
892 |
} |
893 |
retval = 0; |
894 |
out: |
895 |
return retval; |
896 |
} /* End twa_fill_sense() */ |
897 |
|
898 |
/* This function will free up device extension resources */ |
899 |
static void twa_free_device_extension(TW_Device_Extension *tw_dev) |
900 |
{ |
901 |
if (tw_dev->command_packet_virt[0]) |
902 |
pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command_Full)*TW_Q_LENGTH, tw_dev->command_packet_virt[0], tw_dev->command_packet_phys[0]); |
903 |
|
904 |
if (tw_dev->generic_buffer_virt[0]) |
905 |
pci_free_consistent(tw_dev->tw_pci_dev, TW_SECTOR_SIZE*TW_Q_LENGTH, tw_dev->generic_buffer_virt[0], tw_dev->generic_buffer_phys[0]); |
906 |
|
907 |
if (tw_dev->event_queue[0]) |
908 |
kfree(tw_dev->event_queue[0]); |
909 |
} /* End twa_free_device_extension() */ |
910 |
|
911 |
/* This function will free a request id */ |
912 |
static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id) |
913 |
{ |
914 |
tw_dev->free_queue[tw_dev->free_tail] = request_id; |
915 |
tw_dev->state[request_id] = TW_S_FINISHED; |
916 |
tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; |
917 |
} /* End twa_free_request_id() */ |
918 |
|
919 |
/* This function will get parameter table entires from the firmware */ |
920 |
static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) |
921 |
{ |
922 |
TW_Command_Full *full_command_packet; |
923 |
TW_Command *command_packet; |
924 |
TW_Param_Apache *param; |
925 |
unsigned long param_value; |
926 |
void *retval = NULL; |
927 |
|
928 |
/* Setup the command packet */ |
929 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
930 |
memset(full_command_packet, 0, sizeof(TW_Command_Full)); |
931 |
command_packet = &full_command_packet->command.oldcommand; |
932 |
|
933 |
command_packet->byte0_offset.opcode = TW_OP_GET_PARAM; |
934 |
command_packet->byte0_offset.sgl_offset = 2; |
935 |
command_packet->size = TW_COMMAND_SIZE; |
936 |
command_packet->request_id = request_id; |
937 |
command_packet->byte6_offset.block_count = 1; |
938 |
|
939 |
/* Now setup the param */ |
940 |
param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; |
941 |
memset(param, 0, TW_SECTOR_SIZE); |
942 |
param->table_id = table_id | 0x8000; |
943 |
param->parameter_id = parameter_id; |
944 |
param->parameter_size_bytes = parameter_size_bytes; |
945 |
param_value = tw_dev->generic_buffer_phys[request_id]; |
946 |
|
947 |
command_packet->byte8_offset.param.sgl[0].address = param_value; |
948 |
command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE; |
949 |
|
950 |
/* Post the command packet to the board */ |
951 |
twa_post_command_packet(tw_dev, request_id); |
952 |
|
953 |
/* Poll for completion */ |
954 |
if (twa_poll_response(tw_dev, request_id, 30)) |
955 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param") |
956 |
else |
957 |
retval = (void *)&(param->data[0]); |
958 |
|
959 |
tw_dev->posted_request_count--; |
960 |
tw_dev->state[request_id] = TW_S_INITIAL; |
961 |
|
962 |
return retval; |
963 |
} /* End twa_get_param() */ |
964 |
|
965 |
/* This function will assign an available request id */ |
966 |
static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id) |
967 |
{ |
968 |
*request_id = tw_dev->free_queue[tw_dev->free_head]; |
969 |
tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; |
970 |
tw_dev->state[*request_id] = TW_S_STARTED; |
971 |
} /* End twa_get_request_id() */ |
972 |
|
973 |
/* Clean shutdown routine */ |
974 |
static int twa_halt(struct notifier_block *nb, ulong event, void *buf) |
975 |
{ |
976 |
unsigned int i; |
977 |
|
978 |
for (i = 0; i < twa_device_extension_count; i++) { |
979 |
if (twa_device_extension_list[i]->online == 1) { |
980 |
printk(KERN_WARNING "3w-9xxx: Shutting down card %d.\n", i); |
981 |
twa_shutdown_device(twa_device_extension_list[i]); |
982 |
twa_device_extension_list[i]->online = 0; |
983 |
} |
984 |
} |
985 |
unregister_reboot_notifier(&twa_notifier); |
986 |
|
987 |
return NOTIFY_OK; |
988 |
} /* End twa_halt() */ |
989 |
|
990 |
/* This function will send an initconnection command to controller */ |
991 |
static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, |
992 |
u32 set_features, unsigned short current_fw_srl, |
993 |
unsigned short current_fw_arch_id, |
994 |
unsigned short current_fw_branch, |
995 |
unsigned short current_fw_build, |
996 |
unsigned short *fw_on_ctlr_srl, |
997 |
unsigned short *fw_on_ctlr_arch_id, |
998 |
unsigned short *fw_on_ctlr_branch, |
999 |
unsigned short *fw_on_ctlr_build, |
1000 |
u32 *init_connect_result) |
1001 |
{ |
1002 |
TW_Command_Full *full_command_packet; |
1003 |
TW_Initconnect *tw_initconnect; |
1004 |
int request_id = 0, retval = 1; |
1005 |
|
1006 |
/* Initialize InitConnection command packet */ |
1007 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
1008 |
memset(full_command_packet, 0, sizeof(TW_Command_Full)); |
1009 |
full_command_packet->header.header_desc.size_header = 128; |
1010 |
|
1011 |
tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; |
1012 |
tw_initconnect->opcode = TW_OP_INIT_CONNECTION; |
1013 |
|
1014 |
tw_initconnect->request_id = request_id; |
1015 |
tw_initconnect->message_credits = message_credits; |
1016 |
tw_initconnect->features = set_features; |
1017 |
#if BITS_PER_LONG > 32 |
1018 |
/* Turn on 64-bit sgl support */ |
1019 |
tw_initconnect->features |= 1; |
1020 |
#endif |
1021 |
|
1022 |
if (set_features & TW_EXTENDED_INIT_CONNECT) |
1023 |
{ |
1024 |
tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; |
1025 |
tw_initconnect->fw_srl = current_fw_srl; |
1026 |
tw_initconnect->fw_arch_id = current_fw_arch_id; |
1027 |
tw_initconnect->fw_branch = current_fw_branch; |
1028 |
tw_initconnect->fw_build = current_fw_build; |
1029 |
} else |
1030 |
tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; |
1031 |
|
1032 |
/* Send command packet to the board */ |
1033 |
twa_post_command_packet(tw_dev, request_id); |
1034 |
|
1035 |
/* Poll for completion */ |
1036 |
if (twa_poll_response(tw_dev, request_id, 30)) { |
1037 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection"); |
1038 |
} else { |
1039 |
if (set_features & TW_EXTENDED_INIT_CONNECT) { |
1040 |
*fw_on_ctlr_srl = tw_initconnect->fw_srl; |
1041 |
*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id; |
1042 |
*fw_on_ctlr_branch = tw_initconnect->fw_branch; |
1043 |
*fw_on_ctlr_build = tw_initconnect->fw_build; |
1044 |
*init_connect_result = tw_initconnect->result; |
1045 |
} |
1046 |
retval = 0; |
1047 |
} |
1048 |
|
1049 |
tw_dev->posted_request_count--; |
1050 |
tw_dev->state[request_id] = TW_S_INITIAL; |
1051 |
|
1052 |
return retval; |
1053 |
} /* End twa_initconnection() */ |
1054 |
|
1055 |
/* This function will initialize the fields of a device extension */ |
1056 |
static int twa_initialize_device_extension(TW_Device_Extension *tw_dev) |
1057 |
{ |
1058 |
int i, retval = 1; |
1059 |
|
1060 |
/* Initialize command packet buffers */ |
1061 |
if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { |
1062 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed"); |
1063 |
goto out; |
1064 |
} |
1065 |
|
1066 |
/* Initialize generic buffer */ |
1067 |
if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { |
1068 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed"); |
1069 |
goto out; |
1070 |
} |
1071 |
|
1072 |
/* Allocate event info space */ |
1073 |
tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_ATOMIC); |
1074 |
if (!tw_dev->event_queue[0]) { |
1075 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); |
1076 |
goto out; |
1077 |
} |
1078 |
|
1079 |
memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH); |
1080 |
|
1081 |
for (i = 0; i < TW_Q_LENGTH; i++) { |
1082 |
tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); |
1083 |
tw_dev->free_queue[i] = i; |
1084 |
tw_dev->state[i] = TW_S_INITIAL; |
1085 |
} |
1086 |
|
1087 |
tw_dev->pending_head = TW_Q_START; |
1088 |
tw_dev->pending_tail = TW_Q_START; |
1089 |
tw_dev->free_head = TW_Q_START; |
1090 |
tw_dev->free_tail = TW_Q_START; |
1091 |
tw_dev->error_sequence_id = 1; |
1092 |
tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; |
1093 |
retval = 0; |
1094 |
out: |
1095 |
return retval; |
1096 |
} /* End twa_initialize_device_extension() */ |
1097 |
|
1098 |
/* This function is the interrupt service routine */ |
1099 |
static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs) |
1100 |
{ |
1101 |
int request_id, error = 0; |
1102 |
u32 status_reg_value; |
1103 |
TW_Response_Queue response_que; |
1104 |
unsigned long flags = 0; |
1105 |
TW_Command_Full *full_command_packet; |
1106 |
TW_Command *command_packet; |
1107 |
TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; |
1108 |
int handled = 0; |
1109 |
|
1110 |
/* See if we are already running on another processor */ |
1111 |
if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags)) |
1112 |
return IRQ_NONE; |
1113 |
|
1114 |
/* Get the per adapter lock */ |
1115 |
spin_lock_irqsave(tw_dev->host->host_lock, flags); |
1116 |
|
1117 |
/* See if the interrupt matches this instance */ |
1118 |
if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) { |
1119 |
|
1120 |
handled = 1; |
1121 |
|
1122 |
/* Read the registers */ |
1123 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1124 |
|
1125 |
/* Check if this is our interrupt, otherwise bail */ |
1126 |
if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) |
1127 |
goto twa_interrupt_bail; |
1128 |
|
1129 |
/* Check controller for errors */ |
1130 |
if (twa_check_bits(status_reg_value)) { |
1131 |
if (twa_decode_bits(tw_dev, status_reg_value)) { |
1132 |
TW_CLEAR_ALL_INTERRUPTS(tw_dev); |
1133 |
goto twa_interrupt_bail; |
1134 |
} |
1135 |
} |
1136 |
|
1137 |
/* Handle host interrupt */ |
1138 |
if (status_reg_value & TW_STATUS_HOST_INTERRUPT) |
1139 |
TW_CLEAR_HOST_INTERRUPT(tw_dev); |
1140 |
|
1141 |
/* Handle attention interrupt */ |
1142 |
if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { |
1143 |
if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { |
1144 |
twa_get_request_id(tw_dev, &request_id); |
1145 |
|
1146 |
error = twa_aen_read_queue(tw_dev, request_id); |
1147 |
if (error) { |
1148 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
1149 |
twa_free_request_id(tw_dev, request_id); |
1150 |
TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); |
1151 |
clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); |
1152 |
} |
1153 |
} |
1154 |
} |
1155 |
|
1156 |
/* Handle command interrupt */ |
1157 |
if ((status_reg_value & TW_STATUS_COMMAND_INTERRUPT) || !(status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) { |
1158 |
/* Drain as many pending commands as we can */ |
1159 |
while (tw_dev->pending_request_count > 0) { |
1160 |
request_id = tw_dev->pending_queue[tw_dev->pending_head]; |
1161 |
if (tw_dev->state[request_id] != TW_S_PENDING) { |
1162 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending"); |
1163 |
TW_CLEAR_ALL_INTERRUPTS(tw_dev); |
1164 |
goto twa_interrupt_bail; |
1165 |
} |
1166 |
if (twa_post_command_packet(tw_dev, request_id)==0) { |
1167 |
tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH; |
1168 |
tw_dev->pending_request_count--; |
1169 |
} else { |
1170 |
/* If we get here, we will continue re-posting on the next command interrupt */ |
1171 |
break; |
1172 |
} |
1173 |
} |
1174 |
/* If there are no more pending requests, we mask command interrupt */ |
1175 |
if (tw_dev->pending_request_count == 0) |
1176 |
TW_MASK_COMMAND_INTERRUPT(tw_dev); |
1177 |
} |
1178 |
|
1179 |
/* Handle response interrupt */ |
1180 |
if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { |
1181 |
|
1182 |
/* Drain the response queue from the board */ |
1183 |
while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { |
1184 |
/* Complete the response */ |
1185 |
response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); |
1186 |
request_id = response_que.u.response_id; |
1187 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
1188 |
error = 0; |
1189 |
command_packet = &full_command_packet->command.oldcommand; |
1190 |
/* Check for command packet errors */ |
1191 |
if (full_command_packet->command.newcommand.status != 0) { |
1192 |
if (tw_dev->srb[request_id] != 0) { |
1193 |
error = twa_fill_sense(tw_dev, request_id, 1, 1); |
1194 |
} else { |
1195 |
/* Skip ioctl error prints */ |
1196 |
if (request_id != tw_dev->chrdev_request_id) { |
1197 |
error = twa_fill_sense(tw_dev, request_id, 0, 1); |
1198 |
} |
1199 |
} |
1200 |
} |
1201 |
|
1202 |
/* Check for correct state */ |
1203 |
if (tw_dev->state[request_id] != TW_S_POSTED) { |
1204 |
if (tw_dev->srb[request_id] != 0) { |
1205 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted"); |
1206 |
TW_CLEAR_ALL_INTERRUPTS(tw_dev); |
1207 |
goto twa_interrupt_bail; |
1208 |
} |
1209 |
} |
1210 |
|
1211 |
/* Check for internal command completion */ |
1212 |
if (tw_dev->srb[request_id] == 0) { |
1213 |
if (request_id != tw_dev->chrdev_request_id) { |
1214 |
if (twa_aen_complete(tw_dev, request_id)) |
1215 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt"); |
1216 |
} else { |
1217 |
tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; |
1218 |
wake_up(&tw_dev->ioctl_wqueue); |
1219 |
} |
1220 |
} else { |
1221 |
twa_scsiop_execute_scsi_complete(tw_dev, request_id); |
1222 |
/* If no error command was a success */ |
1223 |
if (error == 0) { |
1224 |
tw_dev->srb[request_id]->result = (DID_OK << 16); |
1225 |
} |
1226 |
|
1227 |
/* If error, command failed */ |
1228 |
if (error == 1) { |
1229 |
/* Ask for a host reset */ |
1230 |
tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); |
1231 |
} |
1232 |
|
1233 |
/* Now complete the io */ |
1234 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
1235 |
twa_free_request_id(tw_dev, request_id); |
1236 |
tw_dev->posted_request_count--; |
1237 |
tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); |
1238 |
twa_unmap_scsi_data(tw_dev, request_id); |
1239 |
} |
1240 |
|
1241 |
/* Check for valid status after each drain */ |
1242 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1243 |
if (twa_check_bits(status_reg_value)) { |
1244 |
if (twa_decode_bits(tw_dev, status_reg_value)) { |
1245 |
TW_CLEAR_ALL_INTERRUPTS(tw_dev); |
1246 |
goto twa_interrupt_bail; |
1247 |
} |
1248 |
} |
1249 |
} |
1250 |
} |
1251 |
} |
1252 |
twa_interrupt_bail: |
1253 |
spin_unlock_irqrestore(tw_dev->host->host_lock, flags); |
1254 |
clear_bit(TW_IN_INTR, &tw_dev->flags); |
1255 |
return IRQ_RETVAL(handled); |
1256 |
} /* End twa_interrupt() */ |
1257 |
|
1258 |
/* This function will load the request id and various sgls for ioctls */ |
1259 |
static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) |
1260 |
{ |
1261 |
TW_Command *oldcommand; |
1262 |
TW_Command_Apache *newcommand; |
1263 |
TW_SG_Entry *sgl; |
1264 |
|
1265 |
if (full_command_packet->command.newcommand.command.opcode == TW_OP_EXECUTE_SCSI) { |
1266 |
newcommand = &full_command_packet->command.newcommand; |
1267 |
newcommand->request_id = request_id; |
1268 |
newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; |
1269 |
newcommand->sg_list[0].length = length; |
1270 |
} else { |
1271 |
oldcommand = &full_command_packet->command.oldcommand; |
1272 |
oldcommand->request_id = request_id; |
1273 |
|
1274 |
if (oldcommand->byte0_offset.sgl_offset) { |
1275 |
/* Load the sg list */ |
1276 |
sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->byte0_offset.sgl_offset); |
1277 |
sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1; |
1278 |
sgl->length = length; |
1279 |
} |
1280 |
} |
1281 |
} /* End twa_load_sgl() */ |
1282 |
|
1283 |
/* This function will perform a pci-dma mapping for a scatter gather list */ |
1284 |
static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) |
1285 |
{ |
1286 |
int use_sg; |
1287 |
Scsi_Cmnd *cmd = tw_dev->srb[request_id]; |
1288 |
int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); |
1289 |
struct pci_dev *pdev = tw_dev->tw_pci_dev; |
1290 |
int retval = 0; |
1291 |
|
1292 |
if (cmd->use_sg == 0) |
1293 |
goto out; |
1294 |
|
1295 |
use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); |
1296 |
|
1297 |
if (use_sg == 0) { |
1298 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); |
1299 |
goto out; |
1300 |
} |
1301 |
|
1302 |
cmd->SCp.phase = 2; |
1303 |
cmd->SCp.have_data_in = use_sg; |
1304 |
retval = use_sg; |
1305 |
out: |
1306 |
return retval; |
1307 |
} /* End twa_map_scsi_sg_data() */ |
1308 |
|
1309 |
/* This function will perform a pci-dma map for a single buffer */ |
1310 |
static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id) |
1311 |
{ |
1312 |
dma_addr_t mapping; |
1313 |
Scsi_Cmnd *cmd = tw_dev->srb[request_id]; |
1314 |
int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); |
1315 |
struct pci_dev *pdev = tw_dev->tw_pci_dev; |
1316 |
int retval = 0; |
1317 |
|
1318 |
if (cmd->request_bufflen == 0) { |
1319 |
retval = 0; |
1320 |
goto out; |
1321 |
} |
1322 |
|
1323 |
mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir); |
1324 |
|
1325 |
if (mapping == 0) { |
1326 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page"); |
1327 |
goto out; |
1328 |
} |
1329 |
|
1330 |
cmd->SCp.phase = 1; |
1331 |
cmd->SCp.have_data_in = mapping; |
1332 |
retval = mapping; |
1333 |
out: |
1334 |
return retval; |
1335 |
} /* End twa_map_scsi_single_data() */ |
1336 |
|
1337 |
/* This function will poll for a response interrupt of a request */ |
1338 |
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) |
1339 |
{ |
1340 |
int retval = 1, found = 0, response_request_id; |
1341 |
TW_Response_Queue response_queue; |
1342 |
TW_Command_Full *full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
1343 |
|
1344 |
if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) { |
1345 |
response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); |
1346 |
response_request_id = (unsigned char)response_queue.u.response_id; |
1347 |
if (request_id != response_request_id) { |
1348 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response"); |
1349 |
goto out; |
1350 |
} |
1351 |
if (full_command_packet->command.newcommand.command.opcode == TW_OP_EXECUTE_SCSI) { |
1352 |
if (full_command_packet->command.newcommand.status != 0) { |
1353 |
/* bad response */ |
1354 |
twa_fill_sense(tw_dev, request_id, 0, 0); |
1355 |
goto out; |
1356 |
} |
1357 |
found = 1; |
1358 |
} else { |
1359 |
if (full_command_packet->command.oldcommand.status != 0) { |
1360 |
/* bad response */ |
1361 |
twa_fill_sense(tw_dev, request_id, 0, 0); |
1362 |
goto out; |
1363 |
} |
1364 |
found = 1; |
1365 |
} |
1366 |
} |
1367 |
|
1368 |
if (found) |
1369 |
retval = 0; |
1370 |
out: |
1371 |
return retval; |
1372 |
} /* End twa_poll_response() */ |
1373 |
|
1374 |
/* This function will poll the status register for a flag */ |
1375 |
static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) |
1376 |
{ |
1377 |
u32 status_reg_value; |
1378 |
unsigned long before; |
1379 |
int retval = 1; |
1380 |
|
1381 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1382 |
before = jiffies; |
1383 |
|
1384 |
if (twa_check_bits(status_reg_value)) |
1385 |
twa_decode_bits(tw_dev, status_reg_value); |
1386 |
|
1387 |
while ((status_reg_value & flag) != flag) { |
1388 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1389 |
|
1390 |
if (twa_check_bits(status_reg_value)) |
1391 |
twa_decode_bits(tw_dev, status_reg_value); |
1392 |
|
1393 |
if (time_after(jiffies, before + HZ * seconds)) |
1394 |
goto out; |
1395 |
|
1396 |
mdelay(5); |
1397 |
} |
1398 |
retval = 0; |
1399 |
out: |
1400 |
return retval; |
1401 |
} /* End twa_poll_status() */ |
1402 |
|
1403 |
/* This function will poll the status register for disappearance of a flag */ |
1404 |
static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds) |
1405 |
{ |
1406 |
u32 status_reg_value; |
1407 |
unsigned long before; |
1408 |
int retval = 1; |
1409 |
|
1410 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1411 |
before = jiffies; |
1412 |
|
1413 |
if (twa_check_bits(status_reg_value)) |
1414 |
twa_decode_bits(tw_dev, status_reg_value); |
1415 |
|
1416 |
while ((status_reg_value & flag) != 0) { |
1417 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1418 |
if (twa_check_bits(status_reg_value)) |
1419 |
twa_decode_bits(tw_dev, status_reg_value); |
1420 |
|
1421 |
if (time_after(jiffies, before + HZ * seconds)) |
1422 |
goto out; |
1423 |
|
1424 |
mdelay(5); |
1425 |
} |
1426 |
retval = 0; |
1427 |
out: |
1428 |
return retval; |
1429 |
} /* End twa_poll_status_gone() */ |
1430 |
|
1431 |
/* This function will attempt to post a command packet to the board */ |
1432 |
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id) |
1433 |
{ |
1434 |
u32 status_reg_value; |
1435 |
unsigned long command_que_value; |
1436 |
int retval = 1; |
1437 |
|
1438 |
command_que_value = tw_dev->command_packet_phys[request_id]; |
1439 |
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); |
1440 |
|
1441 |
if (twa_check_bits(status_reg_value)) |
1442 |
twa_decode_bits(tw_dev, status_reg_value); |
1443 |
|
1444 |
if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) { |
1445 |
/* Couldn't post the command packet, so we do it later */ |
1446 |
if (tw_dev->state[request_id] != TW_S_PENDING) { |
1447 |
tw_dev->state[request_id] = TW_S_PENDING; |
1448 |
tw_dev->pending_request_count++; |
1449 |
if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { |
1450 |
tw_dev->max_pending_request_count = tw_dev->pending_request_count; |
1451 |
} |
1452 |
tw_dev->pending_queue[tw_dev->pending_tail] = request_id; |
1453 |
tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH; |
1454 |
} |
1455 |
TW_UNMASK_COMMAND_INTERRUPT(tw_dev); |
1456 |
goto out; |
1457 |
} else { |
1458 |
/* We successfully posted the command packet */ |
1459 |
#if BITS_PER_LONG > 32 |
1460 |
writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); |
1461 |
#else |
1462 |
writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); |
1463 |
#endif |
1464 |
tw_dev->state[request_id] = TW_S_POSTED; |
1465 |
tw_dev->posted_request_count++; |
1466 |
if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { |
1467 |
tw_dev->max_posted_request_count = tw_dev->posted_request_count; |
1468 |
} |
1469 |
} |
1470 |
retval = 0; |
1471 |
out: |
1472 |
return retval; |
1473 |
} /* End twa_post_command_packet() */ |
1474 |
|
1475 |
/* This function will reset a device extension */ |
1476 |
static int twa_reset_device_extension(TW_Device_Extension *tw_dev) |
1477 |
{ |
1478 |
int i = 0; |
1479 |
int retval = 1; |
1480 |
|
1481 |
/* Abort all requests that are in progress */ |
1482 |
for (i = 0; i < TW_Q_LENGTH; i++) { |
1483 |
if ((tw_dev->state[i] != TW_S_FINISHED) && |
1484 |
(tw_dev->state[i] != TW_S_INITIAL) && |
1485 |
(tw_dev->state[i] != TW_S_COMPLETED)) { |
1486 |
if (tw_dev->srb[i]) { |
1487 |
tw_dev->srb[i]->result = (DID_RESET << 16); |
1488 |
tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); |
1489 |
twa_unmap_scsi_data(tw_dev, i); |
1490 |
} |
1491 |
} |
1492 |
} |
1493 |
|
1494 |
/* Reset queues and counts */ |
1495 |
for (i = 0; i < TW_Q_LENGTH; i++) { |
1496 |
tw_dev->free_queue[i] = i; |
1497 |
tw_dev->state[i] = TW_S_INITIAL; |
1498 |
} |
1499 |
tw_dev->free_head = TW_Q_START; |
1500 |
tw_dev->free_tail = TW_Q_START; |
1501 |
tw_dev->posted_request_count = 0; |
1502 |
tw_dev->pending_request_count = 0; |
1503 |
tw_dev->pending_head = TW_Q_START; |
1504 |
tw_dev->pending_tail = TW_Q_START; |
1505 |
tw_dev->reset_print = 0; |
1506 |
tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; |
1507 |
tw_dev->flags = 0; |
1508 |
|
1509 |
TW_DISABLE_INTERRUPTS(tw_dev); |
1510 |
|
1511 |
if (twa_reset_sequence(tw_dev, 1)) |
1512 |
goto out; |
1513 |
|
1514 |
TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); |
1515 |
|
1516 |
retval = 0; |
1517 |
out: |
1518 |
return retval; |
1519 |
} /* End twa_reset_device_extension() */ |
1520 |
|
1521 |
/* This function will reset a controller */ |
1522 |
static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) |
1523 |
{ |
1524 |
int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset; |
1525 |
|
1526 |
while (tries < TW_MAX_RESET_TRIES) { |
1527 |
if (do_soft_reset) |
1528 |
TW_SOFT_RESET(tw_dev); |
1529 |
|
1530 |
/* Make sure controller is in a good state */ |
1531 |
if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) { |
1532 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence"); |
1533 |
do_soft_reset = 1; |
1534 |
tries++; |
1535 |
continue; |
1536 |
} |
1537 |
|
1538 |
/* Empty response queue */ |
1539 |
if (twa_empty_response_queue(tw_dev)) { |
1540 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence"); |
1541 |
do_soft_reset = 1; |
1542 |
tries++; |
1543 |
continue; |
1544 |
} |
1545 |
|
1546 |
flashed = 0; |
1547 |
|
1548 |
/* Check for compatibility/flash */ |
1549 |
if (twa_check_srl(tw_dev, &flashed)) { |
1550 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence"); |
1551 |
do_soft_reset = 1; |
1552 |
tries++; |
1553 |
continue; |
1554 |
} else { |
1555 |
if (flashed) { |
1556 |
tries++; |
1557 |
continue; |
1558 |
} |
1559 |
} |
1560 |
|
1561 |
/* Drain the AEN queue */ |
1562 |
if (twa_aen_drain_queue(tw_dev, soft_reset)) { |
1563 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence"); |
1564 |
do_soft_reset = 1; |
1565 |
tries++; |
1566 |
continue; |
1567 |
} |
1568 |
|
1569 |
/* If we got here, controller is in a good state */ |
1570 |
retval = 0; |
1571 |
goto out; |
1572 |
} |
1573 |
out: |
1574 |
return retval; |
1575 |
} /* End twa_reset_sequence() */ |
1576 |
|
1577 |
/* This funciton returns unit geometry in cylinders/heads/sectors */ |
1578 |
static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) |
1579 |
{ |
1580 |
int heads, sectors, cylinders; |
1581 |
TW_Device_Extension *tw_dev; |
1582 |
|
1583 |
tw_dev = (TW_Device_Extension *)sdev->host->hostdata; |
1584 |
|
1585 |
heads = 64; |
1586 |
sectors = 32; |
1587 |
cylinders = (unsigned long)capacity / (heads * sectors); |
1588 |
|
1589 |
if (capacity >= 0x200000) { |
1590 |
heads = 255; |
1591 |
sectors = 63; |
1592 |
cylinders = (unsigned long)capacity / (heads * sectors); |
1593 |
} |
1594 |
|
1595 |
geom[0] = heads; |
1596 |
geom[1] = sectors; |
1597 |
geom[2] = cylinders; |
1598 |
|
1599 |
return 0; |
1600 |
} /* End twa_scsi_biosparam() */ |
1601 |
|
1602 |
/* This function will find and initialize all cards */ |
1603 |
static int twa_scsi_detect(Scsi_Host_Template *tw_host) |
1604 |
{ |
1605 |
int numcards = 0, i; |
1606 |
struct Scsi_Host *host = NULL; |
1607 |
TW_Device_Extension *tw_dev, *tw_dev2; |
1608 |
struct pci_dev *tw_pci_dev=NULL; |
1609 |
u32 mem_addr, mem_len; |
1610 |
u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID_9000 }; |
1611 |
|
1612 |
printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version); |
1613 |
|
1614 |
for (i = 0; i < TW_NUMDEVICES; i++) { |
1615 |
while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) { |
1616 |
if (pci_enable_device(tw_pci_dev)) |
1617 |
continue; |
1618 |
|
1619 |
if (pci_set_dma_mask(tw_pci_dev, TW_DMA_MASK)) { |
1620 |
TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); |
1621 |
continue; |
1622 |
} |
1623 |
|
1624 |
/* Prepare temporary device extension */ |
1625 |
tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC); |
1626 |
if (!tw_dev) { |
1627 |
TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension"); |
1628 |
continue; |
1629 |
} |
1630 |
memset(tw_dev, 0, sizeof(TW_Device_Extension)); |
1631 |
|
1632 |
/* Save pci_dev struct to device extension */ |
1633 |
tw_dev->tw_pci_dev = tw_pci_dev; |
1634 |
|
1635 |
if (twa_initialize_device_extension(tw_dev)) { |
1636 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); |
1637 |
twa_free_device_extension(tw_dev); |
1638 |
kfree(tw_dev); |
1639 |
continue; |
1640 |
} |
1641 |
|
1642 |
mem_addr = pci_resource_start(tw_pci_dev, 1); |
1643 |
mem_len = pci_resource_len(tw_pci_dev, 1); |
1644 |
|
1645 |
/* Make sure that mem region isn't already taken */ |
1646 |
if (check_mem_region(mem_addr, mem_len)) { |
1647 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region"); |
1648 |
twa_free_device_extension(tw_dev); |
1649 |
kfree(tw_dev); |
1650 |
continue; |
1651 |
} |
1652 |
|
1653 |
/* Reserve the mem address space */ |
1654 |
request_mem_region(mem_addr, mem_len, TW_DEVICE_NAME); |
1655 |
|
1656 |
/* Save base address */ |
1657 |
tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE); |
1658 |
|
1659 |
/* Disable interrupts on the card */ |
1660 |
TW_DISABLE_INTERRUPTS(tw_dev); |
1661 |
|
1662 |
/* Initialize the card */ |
1663 |
if (twa_reset_sequence(tw_dev, 0)) { |
1664 |
release_mem_region(mem_addr, mem_len); |
1665 |
twa_free_device_extension(tw_dev); |
1666 |
kfree(tw_dev); |
1667 |
continue; |
1668 |
} |
1669 |
|
1670 |
/* Set card status as online */ |
1671 |
tw_dev->online = 1; |
1672 |
|
1673 |
/* Register the card with the kernel SCSI layer */ |
1674 |
host = scsi_register(tw_host, sizeof(TW_Device_Extension)); |
1675 |
if (!host) { |
1676 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi register failed"); |
1677 |
release_mem_region(mem_addr, mem_len); |
1678 |
twa_free_device_extension(tw_dev); |
1679 |
kfree(tw_dev); |
1680 |
continue; |
1681 |
} |
1682 |
|
1683 |
/* Set max target id's */ |
1684 |
host->max_id = TW_MAX_UNITS; |
1685 |
|
1686 |
/* Set max cdb size in bytes */ |
1687 |
host->max_cmd_len = TW_MAX_CDB_LEN; |
1688 |
|
1689 |
scsi_set_device(host, &tw_pci_dev->dev); |
1690 |
|
1691 |
printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, mem_addr, tw_pci_dev->irq); |
1692 |
printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", host->host_no, (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE, TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)); |
1693 |
if (host->hostdata) { |
1694 |
tw_dev2 = (TW_Device_Extension *)host->hostdata; |
1695 |
memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); |
1696 |
/* Need to init the sem/wqueue after the copy */ |
1697 |
init_MUTEX(&tw_dev2->ioctl_sem); |
1698 |
init_waitqueue_head(&tw_dev2->ioctl_wqueue); |
1699 |
|
1700 |
twa_device_extension_list[twa_device_extension_count] = tw_dev2; |
1701 |
numcards++; |
1702 |
twa_device_extension_count = numcards; |
1703 |
tw_dev2->host = host; |
1704 |
} else { |
1705 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x28, "Bad scsi host data"); |
1706 |
scsi_unregister(host); |
1707 |
release_mem_region(mem_addr, mem_len); |
1708 |
twa_free_device_extension(tw_dev); |
1709 |
kfree(tw_dev); |
1710 |
continue; |
1711 |
} |
1712 |
|
1713 |
/* Now setup the interrupt handler */ |
1714 |
if (twa_setup_irq(tw_dev2)) { |
1715 |
scsi_unregister(host); |
1716 |
release_mem_region(mem_addr, mem_len); |
1717 |
twa_free_device_extension(tw_dev); |
1718 |
kfree(tw_dev); |
1719 |
numcards--; |
1720 |
continue; |
1721 |
} |
1722 |
|
1723 |
/* Re-enable interrupts on the card */ |
1724 |
TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev2); |
1725 |
|
1726 |
/* Free the temporary device extension */ |
1727 |
if (tw_dev) |
1728 |
kfree(tw_dev); |
1729 |
} |
1730 |
} |
1731 |
|
1732 |
if (numcards == 0) { |
1733 |
printk(KERN_WARNING "3w-9xxx: No cards successfully initialized.\n"); |
1734 |
} else { |
1735 |
register_reboot_notifier(&twa_notifier); |
1736 |
if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0) |
1737 |
TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device"); |
1738 |
} |
1739 |
return numcards; |
1740 |
} /* End twa_scsi_detect() */ |
1741 |
|
1742 |
/* This is the new scsi eh abort function */ |
1743 |
static int twa_scsi_eh_abort(Scsi_Cmnd *SCpnt) |
1744 |
{ |
1745 |
int i; |
1746 |
TW_Device_Extension *tw_dev = NULL; |
1747 |
int retval = FAILED; |
1748 |
|
1749 |
tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; |
1750 |
|
1751 |
tw_dev->num_aborts++; |
1752 |
|
1753 |
/* If we find any IO's in process, we have to reset the card */ |
1754 |
for (i = 0; i < TW_Q_LENGTH; i++) { |
1755 |
if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) { |
1756 |
printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]); |
1757 |
if (twa_reset_device_extension(tw_dev)) { |
1758 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort"); |
1759 |
goto out; |
1760 |
} |
1761 |
break; |
1762 |
} |
1763 |
} |
1764 |
retval = SUCCESS; |
1765 |
out: |
1766 |
return retval; |
1767 |
} /* End twa_scsi_eh_abort() */ |
1768 |
|
1769 |
/* This is the new scsi eh reset function */ |
1770 |
static int twa_scsi_eh_reset(Scsi_Cmnd *SCpnt) |
1771 |
{ |
1772 |
TW_Device_Extension *tw_dev = NULL; |
1773 |
int retval = FAILED; |
1774 |
|
1775 |
tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; |
1776 |
|
1777 |
tw_dev->num_resets++; |
1778 |
|
1779 |
printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no); |
1780 |
|
1781 |
/* Now reset the card and some of the device extension data */ |
1782 |
if (twa_reset_device_extension(tw_dev)) { |
1783 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); |
1784 |
goto out; |
1785 |
} |
1786 |
printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no); |
1787 |
retval = SUCCESS; |
1788 |
out: |
1789 |
return retval; |
1790 |
} /* End twa_scsi_eh_reset() */ |
1791 |
|
1792 |
/* This function handles input and output from /proc/scsi/3w-9xxx/x */ |
1793 |
static int twa_scsi_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) |
1794 |
{ |
1795 |
TW_Device_Extension *tw_dev = NULL; |
1796 |
TW_Info info; |
1797 |
unsigned int i; |
1798 |
int retval = -EINVAL; |
1799 |
|
1800 |
/* Find the correct device extension */ |
1801 |
for (i = 0; i < twa_device_extension_count; i++) |
1802 |
if (twa_device_extension_list[i]->host->host_no == shost->host_no) |
1803 |
tw_dev = twa_device_extension_list[i]; |
1804 |
if (!tw_dev) { |
1805 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2c, "No device extension for proc operation"); |
1806 |
goto out; |
1807 |
} |
1808 |
|
1809 |
info.buffer = buffer; |
1810 |
info.length = length; |
1811 |
info.offset = offset; |
1812 |
info.position = 0; |
1813 |
|
1814 |
if (!inout) { |
1815 |
/* Read */ |
1816 |
if (start) { |
1817 |
*start = buffer; |
1818 |
} |
1819 |
twa_copy_info(&info, "scsi%d: 3ware 9000 Storage Controller\n", shost->host_no); |
1820 |
twa_copy_info(&info, "Driver version: %s\n", twa_driver_version); |
1821 |
twa_copy_info(&info, "Current commands posted: %4d\n", tw_dev->posted_request_count); |
1822 |
twa_copy_info(&info, "Max commands posted: %4d\n", tw_dev->max_posted_request_count); |
1823 |
twa_copy_info(&info, "Current pending commands: %4d\n", tw_dev->pending_request_count); |
1824 |
twa_copy_info(&info, "Max pending commands: %4d\n", tw_dev->max_pending_request_count); |
1825 |
twa_copy_info(&info, "Last sgl length: %4d\n", tw_dev->sgl_entries); |
1826 |
twa_copy_info(&info, "Max sgl length: %4d\n", tw_dev->max_sgl_entries); |
1827 |
twa_copy_info(&info, "Last sector count: %4d\n", tw_dev->sector_count); |
1828 |
twa_copy_info(&info, "Max sector count: %4d\n", tw_dev->max_sector_count); |
1829 |
twa_copy_info(&info, "SCSI Host Resets: %4d\n", tw_dev->num_resets); |
1830 |
twa_copy_info(&info, "SCSI Aborts/Timeouts: %4d\n", tw_dev->num_aborts); |
1831 |
twa_copy_info(&info, "AEN's: %4d\n", tw_dev->aen_count); |
1832 |
} |
1833 |
if (info.position > info.offset) { |
1834 |
retval = info.position - info.offset; |
1835 |
} else { |
1836 |
retval = 0; |
1837 |
} |
1838 |
out: |
1839 |
return retval; |
1840 |
} /* End twa_scsi_proc_info() */ |
1841 |
|
1842 |
/* This is the main scsi queue function to handle scsi opcodes */ |
1843 |
static int twa_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) |
1844 |
{ |
1845 |
int request_id; |
1846 |
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; |
1847 |
|
1848 |
/* Skip lun and channel probes */ |
1849 |
if ((SCpnt->device->lun != 0) || (SCpnt->device->channel != 0)) { |
1850 |
SCpnt->result = (DID_BAD_TARGET << 16); |
1851 |
done(SCpnt); |
1852 |
goto out; |
1853 |
} |
1854 |
|
1855 |
/* Save done function into Scsi_Cmnd struct */ |
1856 |
SCpnt->scsi_done = done; |
1857 |
|
1858 |
/* Get a free request id */ |
1859 |
twa_get_request_id(tw_dev, &request_id); |
1860 |
|
1861 |
/* Save the scsi command for use by the ISR */ |
1862 |
tw_dev->srb[request_id] = SCpnt; |
1863 |
|
1864 |
/* Initialize phase to zero */ |
1865 |
SCpnt->SCp.phase = 0; |
1866 |
|
1867 |
if (twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL)) { |
1868 |
tw_dev->state[request_id] = TW_S_COMPLETED; |
1869 |
twa_free_request_id(tw_dev, request_id); |
1870 |
SCpnt->result = (DID_ERROR << 16); |
1871 |
done(SCpnt); |
1872 |
} |
1873 |
out: |
1874 |
return 0; |
1875 |
} /* End twa_scsi_queue() */ |
1876 |
|
1877 |
/* This function will release the resources on an rmmod call */ |
1878 |
static int twa_scsi_release(struct Scsi_Host *tw_host) |
1879 |
{ |
1880 |
TW_Device_Extension *tw_dev = (TW_Device_Extension *)tw_host->hostdata; |
1881 |
|
1882 |
twa_halt(0, 0, 0); |
1883 |
|
1884 |
/* Free up the mem region */ |
1885 |
release_mem_region(pci_resource_start(tw_dev->tw_pci_dev, 1), pci_resource_len(tw_dev->tw_pci_dev, 1)); |
1886 |
|
1887 |
/* Free up the IRQ */ |
1888 |
free_irq(tw_dev->tw_pci_dev->irq, tw_dev); |
1889 |
|
1890 |
/* Unregister character device */ |
1891 |
if (twa_major >= 0) { |
1892 |
unregister_chrdev(twa_major, "twa"); |
1893 |
twa_major = -1; |
1894 |
} |
1895 |
|
1896 |
/* Free up device extension resources */ |
1897 |
twa_free_device_extension(tw_dev); |
1898 |
|
1899 |
/* Tell kernel scsi-layer we are gone */ |
1900 |
scsi_unregister(tw_host); |
1901 |
|
1902 |
return 0; |
1903 |
} /* End twa_scsi_release() */ |
1904 |
|
1905 |
/* This function hands scsi cdb's to the firmware */ |
1906 |
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg) |
1907 |
{ |
1908 |
TW_Command_Full *full_command_packet; |
1909 |
TW_Command_Apache *command_packet; |
1910 |
u32 num_sectors = 0x0; |
1911 |
int i, sg_count; |
1912 |
Scsi_Cmnd *srb = NULL; |
1913 |
struct scatterlist *sglist = NULL; |
1914 |
u32 buffaddr = 0x0; |
1915 |
int retval = 1; |
1916 |
|
1917 |
if (tw_dev->srb[request_id]) { |
1918 |
if (tw_dev->srb[request_id]->request_buffer) { |
1919 |
sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; |
1920 |
} |
1921 |
srb = tw_dev->srb[request_id]; |
1922 |
} |
1923 |
|
1924 |
/* Initialize command packet */ |
1925 |
full_command_packet = (TW_Command_Full *)tw_dev->command_packet_virt[request_id]; |
1926 |
full_command_packet->header.header_desc.size_header = 128; |
1927 |
full_command_packet->header.status_block.error = 0; |
1928 |
full_command_packet->header.status_block.substatus_block.severity = 0; |
1929 |
|
1930 |
command_packet = &full_command_packet->command.newcommand; |
1931 |
command_packet->status = 0; |
1932 |
command_packet->command.opcode = TW_OP_EXECUTE_SCSI; |
1933 |
|
1934 |
/* We forced 16 byte cdb use earlier */ |
1935 |
if (!cdb) |
1936 |
memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); |
1937 |
else |
1938 |
memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); |
1939 |
|
1940 |
if (srb) |
1941 |
command_packet->unit = srb->device->id; |
1942 |
else |
1943 |
command_packet->unit = 0; |
1944 |
|
1945 |
command_packet->request_id = request_id; |
1946 |
command_packet->sgl_offset = 16; |
1947 |
|
1948 |
if (!sglistarg) { |
1949 |
/* Map sglist from scsi layer to cmd packet */ |
1950 |
if (tw_dev->srb[request_id]->use_sg == 0) { |
1951 |
if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) { |
1952 |
command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id]; |
1953 |
command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH; |
1954 |
} else { |
1955 |
buffaddr = twa_map_scsi_single_data(tw_dev, request_id); |
1956 |
if (buffaddr == 0) |
1957 |
goto out; |
1958 |
|
1959 |
command_packet->sg_list[0].address = buffaddr; |
1960 |
command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen; |
1961 |
} |
1962 |
command_packet->sgl_entries = 1; |
1963 |
|
1964 |
if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) { |
1965 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi"); |
1966 |
goto out; |
1967 |
} |
1968 |
} |
1969 |
|
1970 |
if (tw_dev->srb[request_id]->use_sg > 0) { |
1971 |
sg_count = twa_map_scsi_sg_data(tw_dev, request_id); |
1972 |
if (sg_count == 0) |
1973 |
goto out; |
1974 |
|
1975 |
for (i = 0; i < sg_count; i++) { |
1976 |
command_packet->sg_list[i].address = sg_dma_address(&sglist[i]); |
1977 |
command_packet->sg_list[i].length = sg_dma_len(&sglist[i]); |
1978 |
if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { |
1979 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi"); |
1980 |
goto out; |
1981 |
} |
1982 |
} |
1983 |
command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg; |
1984 |
} |
1985 |
} else { |
1986 |
/* Internal cdb post */ |
1987 |
for (i = 0; i < use_sg; i++) { |
1988 |
command_packet->sg_list[i].address = sglistarg[i].address; |
1989 |
command_packet->sg_list[i].length = sglistarg[i].length; |
1990 |
if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) { |
1991 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); |
1992 |
goto out; |
1993 |
} |
1994 |
} |
1995 |
command_packet->sgl_entries = use_sg; |
1996 |
} |
1997 |
|
1998 |
if (srb) { |
1999 |
if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) |
2000 |
num_sectors = (u32)srb->cmnd[4]; |
2001 |
|
2002 |
if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) |
2003 |
num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); |
2004 |
} |
2005 |
|
2006 |
/* Update sector statistic */ |
2007 |
tw_dev->sector_count = num_sectors; |
2008 |
if (tw_dev->sector_count > tw_dev->max_sector_count) |
2009 |
tw_dev->max_sector_count = tw_dev->sector_count; |
2010 |
|
2011 |
/* Update SG statistics */ |
2012 |
if (srb) { |
2013 |
tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg; |
2014 |
if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) |
2015 |
tw_dev->max_sgl_entries = tw_dev->sgl_entries; |
2016 |
} |
2017 |
|
2018 |
/* Now post the command to the board */ |
2019 |
twa_post_command_packet(tw_dev, request_id); |
2020 |
retval = 0; |
2021 |
out: |
2022 |
return retval; |
2023 |
} /* End twa_scsiop_execute_scsi() */ |
2024 |
|
2025 |
/* This function completes an execute scsi operation */ |
2026 |
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) |
2027 |
{ |
2028 |
/* Copy the response if too small */ |
2029 |
if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) { |
2030 |
memcpy(tw_dev->srb[request_id]->request_buffer, tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_bufflen); |
2031 |
} |
2032 |
} /* End twa_scsiop_execute_scsi_complete() */ |
2033 |
|
2034 |
/* This function will setup the interrupt handler */ |
2035 |
static int twa_setup_irq(TW_Device_Extension *tw_dev) |
2036 |
{ |
2037 |
char *device = TW_DEVICE_NAME; |
2038 |
int retval = 1; |
2039 |
|
2040 |
if (request_irq(tw_dev->tw_pci_dev->irq, twa_interrupt, SA_SHIRQ, device, tw_dev) < 0) { |
2041 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ"); |
2042 |
goto out; |
2043 |
} |
2044 |
retval = 0; |
2045 |
out: |
2046 |
return retval; |
2047 |
} /* End twa_setup_irq() */ |
2048 |
|
2049 |
/* This function tells the controller to shut down */ |
2050 |
static void twa_shutdown_device(TW_Device_Extension *tw_dev) |
2051 |
{ |
2052 |
/* Disable interrupts */ |
2053 |
TW_DISABLE_INTERRUPTS(tw_dev); |
2054 |
|
2055 |
/* Tell the card we are shutting down */ |
2056 |
if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { |
2057 |
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed"); |
2058 |
} else { |
2059 |
printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n"); |
2060 |
} |
2061 |
|
2062 |
/* Clear all interrupts just before exit */ |
2063 |
TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); |
2064 |
} /* End twa_shutdown_device() */ |
2065 |
|
2066 |
/* This function will configure individual target parameters */ |
2067 |
static int twa_slave_configure(Scsi_Device *SDptr) |
2068 |
{ |
2069 |
int max_cmds; |
2070 |
|
2071 |
if (cmds_per_lun) { |
2072 |
max_cmds = cmds_per_lun; |
2073 |
if (max_cmds > TW_MAX_CMDS_PER_LUN) |
2074 |
max_cmds = TW_MAX_CMDS_PER_LUN; |
2075 |
} else { |
2076 |
max_cmds = TW_MAX_CMDS_PER_LUN; |
2077 |
} |
2078 |
scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, max_cmds); |
2079 |
|
2080 |
return 0; |
2081 |
} /* End twa_slave_configure */ |
2082 |
|
2083 |
/* This function will look up a string */ |
2084 |
static char *twa_string_lookup(twa_message_type *table, unsigned int code) |
2085 |
{ |
2086 |
int index; |
2087 |
|
2088 |
for (index = 0; ((code != table[index].code) && |
2089 |
(table[index].text != (char *)0)); index++); |
2090 |
return(table[index].text); |
2091 |
} /* End twa_string_lookup() */ |
2092 |
|
2093 |
/* This function will perform a pci-dma unmap */ |
2094 |
static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) |
2095 |
{ |
2096 |
Scsi_Cmnd *cmd = tw_dev->srb[request_id]; |
2097 |
int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); |
2098 |
struct pci_dev *pdev = tw_dev->tw_pci_dev; |
2099 |
|
2100 |
switch(cmd->SCp.phase) { |
2101 |
case 1: |
2102 |
pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir); |
2103 |
break; |
2104 |
case 2: |
2105 |
pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir); |
2106 |
break; |
2107 |
} |
2108 |
} /* End twa_unmap_scsi_data() */ |
2109 |
|
2110 |
/* Now get things going */ |
2111 |
static Scsi_Host_Template driver_template = { |
2112 |
.proc_name = "3w-9xxx", |
2113 |
.proc_info = twa_scsi_proc_info, |
2114 |
.name = "3ware 9000 Storage Controller", |
2115 |
.detect = twa_scsi_detect, |
2116 |
.release = twa_scsi_release, |
2117 |
.queuecommand = twa_scsi_queue, |
2118 |
.eh_abort_handler = twa_scsi_eh_abort, |
2119 |
.eh_host_reset_handler = twa_scsi_eh_reset, |
2120 |
.bios_param = twa_scsi_biosparam, |
2121 |
.slave_configure = twa_slave_configure, |
2122 |
.can_queue = TW_Q_LENGTH-2, |
2123 |
.this_id = -1, |
2124 |
.sg_tablesize = TW_APACHE_MAX_SGL_LENGTH, |
2125 |
.max_sectors = TW_MAX_SECTORS, |
2126 |
.cmd_per_lun = TW_MAX_CMDS_PER_LUN, |
2127 |
.use_clustering = ENABLE_CLUSTERING, |
2128 |
.emulated = 1 |
2129 |
}; |
2130 |
#include "scsi_module.c" |
2131 |
|