blob: 17dbd4ac86929d557f3feeb0e03be3551e4c0c2d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
3
4 Written By: Adam Radford <linuxraid@amcc.com>
5 Modifications By: Joel Jacobson <linux@3ware.com>
6 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7 Brad Strand <linux@3ware.com>
8
9 Copyright (C) 1999-2005 3ware Inc.
10
11 Kernel compatiblity By: Andre Hedrick <andre@suse.com>
12 Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
13
14 Further tiny build fixes and trivial hoovering Alan Cox
15
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; version 2 of the License.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 NO WARRANTY
26 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
27 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
28 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
29 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
30 solely responsible for determining the appropriateness of using and
31 distributing the Program and assumes all risks associated with its
32 exercise of rights under this Agreement, including but not limited to
33 the risks and costs of program errors, damage to or loss of data,
34 programs or equipment, and unavailability or interruption of operations.
35
36 DISCLAIMER OF LIABILITY
37 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
38 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
40 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
41 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
42 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
43 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
44
45 You should have received a copy of the GNU General Public License
46 along with this program; if not, write to the Free Software
47 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
48
49 Bugs/Comments/Suggestions should be mailed to:
50 linuxraid@amcc.com
51
52 For more information, goto:
53 http://www.amcc.com
54
55 History
56 -------
57 0.1.000 - Initial release.
58 0.4.000 - Added support for Asynchronous Event Notification through
59 ioctls for 3DM.
60 1.0.000 - Added DPO & FUA bit support for WRITE_10 & WRITE_6 cdb
61 to disable drive write-cache before writes.
62 1.1.000 - Fixed performance bug with DPO & FUA not existing for WRITE_6.
63 1.2.000 - Added support for clean shutdown notification/feature table.
64 1.02.00.001 - Added support for full command packet posts through ioctls
65 for 3DM.
66 Bug fix so hot spare drives don't show up.
67 1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some
68 systems.
69 08/21/00 - release previously allocated resources on failure at
70 tw_allocate_memory (acme)
71 1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
72 controller status is non-zero.
73 Added handling of request_sense opcode.
74 Fix possible null pointer dereference in
75 tw_reset_device_extension()
76 1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
77 Make tw_setfeature() call with interrupts disabled.
78 Register interrupt handler before enabling interrupts.
79 Clear attention interrupt before draining aen queue.
80 1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for
81 6000 and 5000 series controllers.
82 Reduce polling mdelays causing problems on some systems.
83 Fix use_sg = 1 calculation bug.
84 Check for scsi_register returning NULL.
85 Add aen count to /proc/scsi/3w-xxxx.
86 Remove aen code unit masking in tw_aen_complete().
87 1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing
88 possible oops.
89 Fix possible null pointer dereference in tw_scsi_queue()
90 if done function pointer was invalid.
91 1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl().
92 Remove check for invalid done function pointer from
93 tw_scsi_queue().
94 1.02.00.008 - Set max sectors per io to TW_MAX_SECTORS in tw_findcards().
95 Add tw_decode_error() for printing readable error messages.
96 Print some useful information on certain aen codes.
97 Add tw_decode_bits() for interpreting status register output.
98 Make scsi_set_pci_device() for kernels >= 2.4.4
99 Fix bug where aen's could be lost before a reset.
100 Re-add spinlocks in tw_scsi_detect().
101 Fix possible null pointer dereference in tw_aen_drain_queue()
102 during initialization.
103 Clear pci parity errors during initialization and during io.
104 1.02.00.009 - Remove redundant increment in tw_state_request_start().
105 Add ioctl support for direct ATA command passthru.
106 Add entire aen code string list.
107 1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
108 Fix get_param for specific units.
109 1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
110 Fix tw_aen_drain_queue() to display useful info at init.
111 Set tw_host->max_id for 12 port cards.
112 Add ioctl support for raw command packet post from userspace
113 with sglist fragments (parameter and io).
114 1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
115 last sector ioctl.
116 1.02.00.013 - Fix bug where more AEN codes weren't coming out during
117 driver initialization.
118 Improved handling of PCI aborts.
119 1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
120 Increase timeout in tw_aen_drain_queue() to 30 seconds.
121 1.02.00.015 - Re-write raw command post with data ioctl method.
122 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
123 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
124 Replace io_request_lock with host_lock for kernel 2.5
125 Set max_cmd_len to 16 for 3dm for kernel 2.5
126 1.02.00.016 - Set host->max_sectors back up to 256.
127 1.02.00.017 - Modified pci parity error handling/clearing from config space
128 during initialization.
129 1.02.00.018 - Better handling of request sense opcode and sense information
130 for failed commands. Add tw_decode_sense().
131 Replace all mdelay()'s with scsi_sleep().
132 1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
133 some SMP systems.
134 1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
135 pci_alloc/free_consistent().
136 Better alignment checking in tw_allocate_memory().
137 Cleanup tw_initialize_device_extension().
138 1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
139 Improve handling of errors in tw_interrupt().
140 Add handling/clearing of controller queue error.
141 Empty stale responses before draining aen queue.
142 Fix tw_scsi_eh_abort() to not reset on every io abort.
143 Set can_queue in SHT to 255 to prevent hang from AEN.
144 1.02.00.022 - Fix possible null pointer dereference in tw_scsi_release().
145 1.02.00.023 - Fix bug in tw_aen_drain_queue() where unit # was always zero.
146 1.02.00.024 - Add severity levels to AEN strings.
147 1.02.00.025 - Fix command interrupt spurious error messages.
148 Fix bug in raw command post with data ioctl method.
149 Fix bug where rollcall sometimes failed with cable errors.
150 Print unit # on all command timeouts.
151 1.02.00.026 - Fix possible infinite retry bug with power glitch induced
152 drive timeouts.
153 Cleanup some AEN severity levels.
154 1.02.00.027 - Add drive not supported AEN code for SATA controllers.
155 Remove spurious unknown ioctl error message.
156 1.02.00.028 - Fix bug where multiple controllers with no units were the
157 same card number.
158 Fix bug where cards were being shut down more than once.
159 1.02.00.029 - Add missing pci_free_consistent() in tw_allocate_memory().
160 Replace pci_map_single() with pci_map_page() for highmem.
161 Check for tw_setfeature() failure.
162 1.02.00.030 - Make driver 64-bit clean.
163 1.02.00.031 - Cleanup polling timeouts/routines in several places.
164 Add support for mode sense opcode.
165 Add support for cache mode page.
166 Add support for synchronize cache opcode.
167 1.02.00.032 - Fix small multicard rollcall bug.
168 Make driver stay loaded with no units for hot add/swap.
169 Add support for "twe" character device for ioctls.
170 Clean up request_id queueing code.
171 Fix tw_scsi_queue() spinlocks.
172 1.02.00.033 - Fix tw_aen_complete() to not queue 'queue empty' AEN's.
173 Initialize queues correctly when loading with no valid units.
174 1.02.00.034 - Fix tw_decode_bits() to handle multiple errors.
175 Add support for user configurable cmd_per_lun.
176 Add support for sht->slave_configure().
177 1.02.00.035 - Improve tw_allocate_memory() memory allocation.
178 Fix tw_chrdev_ioctl() to sleep correctly.
179 1.02.00.036 - Increase character ioctl timeout to 60 seconds.
180 1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds
181 for 'smartmontools' support.
182 1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6.
183 Add support for cmds_per_lun module parameter.
184 1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code.
185 Fix data_buffer_length usage in tw_chrdev_ioctl().
186 Update contact information.
187 1.26.02.000 - Convert driver to pci_driver format.
188 1.26.02.001 - Increase max ioctl buffer size to 512 sectors.
189 Make tw_scsi_queue() return 0 for 'Unknown scsi opcode'.
190 Fix tw_remove() to free irq handler/unregister_chrdev()
191 before shutting down card.
192 Change to new 'change_queue_depth' api.
193 Fix 'handled=1' ISR usage, remove bogus IRQ check.
194*/
195
196#include <linux/module.h>
197#include <linux/reboot.h>
198#include <linux/spinlock.h>
199#include <linux/interrupt.h>
200#include <linux/moduleparam.h>
201#include <linux/errno.h>
202#include <linux/types.h>
203#include <linux/delay.h>
204#include <linux/pci.h>
205#include <linux/time.h>
Jes Sorensena12e25b2006-01-11 08:39:45 -0500206#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207#include <asm/io.h>
208#include <asm/irq.h>
209#include <asm/uaccess.h>
210#include <scsi/scsi.h>
211#include <scsi/scsi_host.h>
212#include <scsi/scsi_tcq.h>
213#include <scsi/scsi_cmnd.h>
214#include "3w-xxxx.h"
215
216/* Globals */
217#define TW_DRIVER_VERSION "1.26.02.001"
218static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
219static int tw_device_extension_count = 0;
220static int twe_major = -1;
221
222/* Module parameters */
223MODULE_AUTHOR("AMCC");
224MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
225MODULE_LICENSE("GPL");
226MODULE_VERSION(TW_DRIVER_VERSION);
227
228/* Function prototypes */
229static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
230
231/* Functions */
232
233/* This function will check the status register for unexpected bits */
234static int tw_check_bits(u32 status_reg_value)
235{
236 if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) {
237 dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value);
238 return 1;
239 }
240 if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) {
241 dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value);
242 return 1;
243 }
244
245 return 0;
246} /* End tw_check_bits() */
247
248/* This function will print readable messages from status register errors */
249static int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
250{
251 char host[16];
252
253 dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
254
255 if (print_host)
256 sprintf(host, " scsi%d:", tw_dev->host->host_no);
257 else
258 host[0] = '\0';
259
260 if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
261 printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
262 outl(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
263 }
264
265 if (status_reg_value & TW_STATUS_PCI_ABORT) {
266 printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
267 outl(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
268 pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
269 }
270
271 if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
272 printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
273 outl(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
274 }
275
276 if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
277 printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
278 outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
279 }
280
281 if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
282 if (tw_dev->reset_print == 0) {
283 printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
284 tw_dev->reset_print = 1;
285 }
286 return 1;
287 }
288
289 return 0;
290} /* End tw_decode_bits() */
291
292/* This function will poll the status register for a flag */
293static int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
294{
295 u32 status_reg_value;
296 unsigned long before;
297 int retval = 1;
298
299 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
300 before = jiffies;
301
302 if (tw_check_bits(status_reg_value))
303 tw_decode_bits(tw_dev, status_reg_value, 0);
304
305 while ((status_reg_value & flag) != flag) {
306 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
307
308 if (tw_check_bits(status_reg_value))
309 tw_decode_bits(tw_dev, status_reg_value, 0);
310
311 if (time_after(jiffies, before + HZ * seconds))
312 goto out;
313
314 msleep(50);
315 }
316 retval = 0;
317out:
318 return retval;
319} /* End tw_poll_status() */
320
321/* This function will poll the status register for disappearance of a flag */
322static int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
323{
324 u32 status_reg_value;
325 unsigned long before;
326 int retval = 1;
327
328 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
329 before = jiffies;
330
331 if (tw_check_bits(status_reg_value))
332 tw_decode_bits(tw_dev, status_reg_value, 0);
333
334 while ((status_reg_value & flag) != 0) {
335 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
336
337 if (tw_check_bits(status_reg_value))
338 tw_decode_bits(tw_dev, status_reg_value, 0);
339
340 if (time_after(jiffies, before + HZ * seconds))
341 goto out;
342
343 msleep(50);
344 }
345 retval = 0;
346out:
347 return retval;
348} /* End tw_poll_status_gone() */
349
350/* This function will attempt to post a command packet to the board */
351static int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
352{
353 u32 status_reg_value;
354 unsigned long command_que_value;
355
356 dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
357 command_que_value = tw_dev->command_packet_physical_address[request_id];
358 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
359
360 if (tw_check_bits(status_reg_value)) {
361 dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
362 tw_decode_bits(tw_dev, status_reg_value, 1);
363 }
364
365 if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
366 /* We successfully posted the command packet */
367 outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
368 tw_dev->state[request_id] = TW_S_POSTED;
369 tw_dev->posted_request_count++;
370 if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
371 tw_dev->max_posted_request_count = tw_dev->posted_request_count;
372 }
373 } else {
374 /* Couldn't post the command packet, so we do it in the isr */
375 if (tw_dev->state[request_id] != TW_S_PENDING) {
376 tw_dev->state[request_id] = TW_S_PENDING;
377 tw_dev->pending_request_count++;
378 if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
379 tw_dev->max_pending_request_count = tw_dev->pending_request_count;
380 }
381 tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
382 if (tw_dev->pending_tail == TW_Q_LENGTH-1) {
383 tw_dev->pending_tail = TW_Q_START;
384 } else {
385 tw_dev->pending_tail = tw_dev->pending_tail + 1;
386 }
387 }
388 TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
389 return 1;
390 }
391 return 0;
392} /* End tw_post_command_packet() */
393
394/* This function will return valid sense buffer information for failed cmds */
395static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
396{
397 int i;
398 TW_Command *command;
399
400 dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
401 command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
402
403 printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, TW_UNIT_OUT(command->unit__hostid));
404
405 /* Attempt to return intelligent sense information */
406 if (fill_sense) {
407 if ((command->status == 0xc7) || (command->status == 0xcb)) {
Tobias Klauser6391a112006-06-08 22:23:48 -0700408 for (i = 0; i < ARRAY_SIZE(tw_sense_table); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 if (command->flags == tw_sense_table[i][0]) {
410
411 /* Valid bit and 'current errors' */
412 tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
413
414 /* Sense key */
415 tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
416
417 /* Additional sense length */
418 tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
419
420 /* Additional sense code */
421 tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
422
423 /* Additional sense code qualifier */
424 tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
425
426 tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
427 return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
428 }
429 }
430 }
431
432 /* If no table match, error so we get a reset */
433 return 1;
434 }
435
436 return 0;
437} /* End tw_decode_sense() */
438
439/* This function will report controller error status */
440static int tw_check_errors(TW_Device_Extension *tw_dev)
441{
442 u32 status_reg_value;
443
444 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
445
446 if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
447 tw_decode_bits(tw_dev, status_reg_value, 0);
448 return 1;
449 }
450
451 return 0;
452} /* End tw_check_errors() */
453
454/* This function will empty the response que */
455static void tw_empty_response_que(TW_Device_Extension *tw_dev)
456{
457 u32 status_reg_value, response_que_value;
458
459 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
460
461 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
462 response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
463 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
464 }
465} /* End tw_empty_response_que() */
466
467/* This function will free a request_id */
468static void tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id)
469{
470 tw_dev->free_queue[tw_dev->free_tail] = request_id;
471 tw_dev->state[request_id] = TW_S_FINISHED;
472 tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
473} /* End tw_state_request_finish() */
474
475/* This function will assign an available request_id */
476static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
477{
478 *request_id = tw_dev->free_queue[tw_dev->free_head];
479 tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
480 tw_dev->state[*request_id] = TW_S_STARTED;
481} /* End tw_state_request_start() */
482
483/* Show some statistics about the card */
484static ssize_t tw_show_stats(struct class_device *class_dev, char *buf)
485{
486 struct Scsi_Host *host = class_to_shost(class_dev);
487 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
488 unsigned long flags = 0;
489 ssize_t len;
490
491 spin_lock_irqsave(tw_dev->host->host_lock, flags);
492 len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n"
493 "Current commands posted: %4d\n"
494 "Max commands posted: %4d\n"
495 "Current pending commands: %4d\n"
496 "Max pending commands: %4d\n"
497 "Last sgl length: %4d\n"
498 "Max sgl length: %4d\n"
499 "Last sector count: %4d\n"
500 "Max sector count: %4d\n"
501 "SCSI Host Resets: %4d\n"
502 "AEN's: %4d\n",
503 TW_DRIVER_VERSION,
504 tw_dev->posted_request_count,
505 tw_dev->max_posted_request_count,
506 tw_dev->pending_request_count,
507 tw_dev->max_pending_request_count,
508 tw_dev->sgl_entries,
509 tw_dev->max_sgl_entries,
510 tw_dev->sector_count,
511 tw_dev->max_sector_count,
512 tw_dev->num_resets,
513 tw_dev->aen_count);
514 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
515 return len;
516} /* End tw_show_stats() */
517
518/* This function will set a devices queue depth */
519static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
520{
521 if (queue_depth > TW_Q_LENGTH-2)
522 queue_depth = TW_Q_LENGTH-2;
523 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
524 return queue_depth;
525} /* End tw_change_queue_depth() */
526
527/* Create sysfs 'stats' entry */
528static struct class_device_attribute tw_host_stats_attr = {
529 .attr = {
530 .name = "stats",
531 .mode = S_IRUGO,
532 },
533 .show = tw_show_stats
534};
535
536/* Host attributes initializer */
537static struct class_device_attribute *tw_host_attrs[] = {
538 &tw_host_stats_attr,
539 NULL,
540};
541
542/* This function will read the aen queue from the isr */
543static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
544{
545 TW_Command *command_packet;
546 TW_Param *param;
547 unsigned long command_que_value;
548 u32 status_reg_value;
549 unsigned long param_value = 0;
550
551 dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
552
553 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
554 if (tw_check_bits(status_reg_value)) {
555 dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
556 tw_decode_bits(tw_dev, status_reg_value, 1);
557 return 1;
558 }
559 if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
560 printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet virtual address.\n");
561 return 1;
562 }
563 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
564 memset(command_packet, 0, sizeof(TW_Sector));
565 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
566 command_packet->size = 4;
567 command_packet->request_id = request_id;
568 command_packet->status = 0;
569 command_packet->flags = 0;
570 command_packet->byte6.parameter_count = 1;
571 command_que_value = tw_dev->command_packet_physical_address[request_id];
572 if (command_que_value == 0) {
573 printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet physical address.\n");
574 return 1;
575 }
576 /* Now setup the param */
577 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
578 printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment virtual address.\n");
579 return 1;
580 }
581 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
582 memset(param, 0, sizeof(TW_Sector));
583 param->table_id = 0x401; /* AEN table */
584 param->parameter_id = 2; /* Unit code */
585 param->parameter_size_bytes = 2;
586 param_value = tw_dev->alignment_physical_address[request_id];
587 if (param_value == 0) {
588 printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment physical address.\n");
589 return 1;
590 }
591 command_packet->byte8.param.sgl[0].address = param_value;
592 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
593
594 /* Now post the command packet */
595 if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
596 dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n");
597 tw_dev->srb[request_id] = NULL; /* Flag internal command */
598 tw_dev->state[request_id] = TW_S_POSTED;
599 outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
600 } else {
601 printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n");
602 return 1;
603 }
604
605 return 0;
606} /* End tw_aen_read_queue() */
607
608/* This function will complete an aen request from the isr */
609static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id)
610{
611 TW_Param *param;
612 unsigned short aen;
613 int error = 0, table_max = 0;
614
615 dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
616 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
617 printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
618 return 1;
619 }
620 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
621 aen = *(unsigned short *)(param->data);
622 dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
623
624 /* Print some useful info when certain aen codes come out */
625 if (aen == 0x0ff) {
626 printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
627 } else {
Tobias Klauser6391a112006-06-08 22:23:48 -0700628 table_max = ARRAY_SIZE(tw_aen_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if ((aen & 0x0ff) < table_max) {
630 if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
631 printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
632 } else {
633 if (aen != 0x0)
634 printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
635 }
636 } else {
637 printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
638 }
639 }
640 if (aen != TW_AEN_QUEUE_EMPTY) {
641 tw_dev->aen_count++;
642
643 /* Now queue the code */
644 tw_dev->aen_queue[tw_dev->aen_tail] = aen;
645 if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
646 tw_dev->aen_tail = TW_Q_START;
647 } else {
648 tw_dev->aen_tail = tw_dev->aen_tail + 1;
649 }
650 if (tw_dev->aen_head == tw_dev->aen_tail) {
651 if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
652 tw_dev->aen_head = TW_Q_START;
653 } else {
654 tw_dev->aen_head = tw_dev->aen_head + 1;
655 }
656 }
657
658 error = tw_aen_read_queue(tw_dev, request_id);
659 if (error) {
660 printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
661 tw_dev->state[request_id] = TW_S_COMPLETED;
662 tw_state_request_finish(tw_dev, request_id);
663 }
664 } else {
665 tw_dev->state[request_id] = TW_S_COMPLETED;
666 tw_state_request_finish(tw_dev, request_id);
667 }
668
669 return 0;
670} /* End tw_aen_complete() */
671
672/* This function will drain the aen queue after a soft reset */
673static int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
674{
675 TW_Command *command_packet;
676 TW_Param *param;
677 int request_id = 0;
678 unsigned long command_que_value;
679 unsigned long param_value;
680 TW_Response_Queue response_queue;
681 unsigned short aen;
682 unsigned short aen_code;
683 int finished = 0;
684 int first_reset = 0;
685 int queue = 0;
686 int found = 0, table_max = 0;
687
688 dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
689
690 if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
691 dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
692 return 1;
693 }
694 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
695
696 /* Empty response queue */
697 tw_empty_response_que(tw_dev);
698
699 /* Initialize command packet */
700 if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
701 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
702 return 1;
703 }
704 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
705 memset(command_packet, 0, sizeof(TW_Sector));
706 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
707 command_packet->size = 4;
708 command_packet->request_id = request_id;
709 command_packet->status = 0;
710 command_packet->flags = 0;
711 command_packet->byte6.parameter_count = 1;
712 command_que_value = tw_dev->command_packet_physical_address[request_id];
713 if (command_que_value == 0) {
714 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n");
715 return 1;
716 }
717
718 /* Now setup the param */
719 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
720 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n");
721 return 1;
722 }
723 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
724 memset(param, 0, sizeof(TW_Sector));
725 param->table_id = 0x401; /* AEN table */
726 param->parameter_id = 2; /* Unit code */
727 param->parameter_size_bytes = 2;
728 param_value = tw_dev->alignment_physical_address[request_id];
729 if (param_value == 0) {
730 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment physical address.\n");
731 return 1;
732 }
733 command_packet->byte8.param.sgl[0].address = param_value;
734 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
735
736 /* Now drain the controller's aen queue */
737 do {
738 /* Post command packet */
739 outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
740
741 /* Now poll for completion */
742 if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
743 response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
744 request_id = TW_RESID_OUT(response_queue.response_id);
745
746 if (request_id != 0) {
747 /* Unexpected request id */
748 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
749 return 1;
750 }
751
752 if (command_packet->status != 0) {
753 if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
754 /* Bad response */
755 tw_decode_sense(tw_dev, request_id, 0);
756 return 1;
757 } else {
758 /* We know this is a 3w-1x00, and doesn't support aen's */
759 return 0;
760 }
761 }
762
763 /* Now check the aen */
764 aen = *(unsigned short *)(param->data);
765 aen_code = (aen & 0x0ff);
766 queue = 0;
767 switch (aen_code) {
768 case TW_AEN_QUEUE_EMPTY:
769 dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
770 if (first_reset != 1) {
771 return 1;
772 } else {
773 finished = 1;
774 }
775 break;
776 case TW_AEN_SOFT_RESET:
777 if (first_reset == 0) {
778 first_reset = 1;
779 } else {
780 printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
781 tw_dev->aen_count++;
782 queue = 1;
783 }
784 break;
785 default:
786 if (aen == 0x0ff) {
787 printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
788 } else {
Tobias Klauser6391a112006-06-08 22:23:48 -0700789 table_max = ARRAY_SIZE(tw_aen_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if ((aen & 0x0ff) < table_max) {
791 if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
792 printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
793 } else {
794 printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
795 }
796 } else
797 printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
798 }
799 tw_dev->aen_count++;
800 queue = 1;
801 }
802
803 /* Now put the aen on the aen_queue */
804 if (queue == 1) {
805 tw_dev->aen_queue[tw_dev->aen_tail] = aen;
806 if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
807 tw_dev->aen_tail = TW_Q_START;
808 } else {
809 tw_dev->aen_tail = tw_dev->aen_tail + 1;
810 }
811 if (tw_dev->aen_head == tw_dev->aen_tail) {
812 if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
813 tw_dev->aen_head = TW_Q_START;
814 } else {
815 tw_dev->aen_head = tw_dev->aen_head + 1;
816 }
817 }
818 }
819 found = 1;
820 }
821 if (found == 0) {
822 printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
823 return 1;
824 }
825 } while (finished == 0);
826
827 return 0;
828} /* End tw_aen_drain_queue() */
829
830/* This function will allocate memory */
831static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
832{
833 int i;
834 dma_addr_t dma_handle;
835 unsigned long *cpu_addr = NULL;
836
837 dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
838
839 cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
840 if (cpu_addr == NULL) {
841 printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
842 return 1;
843 }
844
845 if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
846 printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
847 pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
848 return 1;
849 }
850
851 memset(cpu_addr, 0, size*TW_Q_LENGTH);
852
853 for (i=0;i<TW_Q_LENGTH;i++) {
854 switch(which) {
855 case 0:
856 tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
857 tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
858 break;
859 case 1:
860 tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
861 tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
862 break;
863 default:
864 printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
865 return 1;
866 }
867 }
868
869 return 0;
870} /* End tw_allocate_memory() */
871
872/* This function handles ioctl for the character device */
873static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
874{
875 int request_id;
876 dma_addr_t dma_handle;
877 unsigned short tw_aen_code;
878 unsigned long flags;
879 unsigned int data_buffer_length = 0;
880 unsigned long data_buffer_length_adjusted = 0;
881 unsigned long *cpu_addr;
882 long timeout;
883 TW_New_Ioctl *tw_ioctl;
884 TW_Passthru *passthru;
885 TW_Device_Extension *tw_dev = tw_device_extension_list[iminor(inode)];
886 int retval = -EFAULT;
887 void __user *argp = (void __user *)arg;
888
889 dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
890
891 /* Only let one of these through at a time */
Jes Sorensena12e25b2006-01-11 08:39:45 -0500892 if (mutex_lock_interruptible(&tw_dev->ioctl_lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return -EINTR;
894
895 /* First copy down the buffer length */
896 if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int)))
897 goto out;
898
899 /* Check size */
900 if (data_buffer_length > TW_MAX_IOCTL_SECTORS * 512) {
901 retval = -EINVAL;
902 goto out;
903 }
904
905 /* Hardware can only do multiple of 512 byte transfers */
906 data_buffer_length_adjusted = (data_buffer_length + 511) & ~511;
907
908 /* Now allocate ioctl buf memory */
909 cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle, GFP_KERNEL);
910 if (cpu_addr == NULL) {
911 retval = -ENOMEM;
912 goto out;
913 }
914
915 tw_ioctl = (TW_New_Ioctl *)cpu_addr;
916
917 /* Now copy down the entire ioctl */
918 if (copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1))
919 goto out2;
920
921 passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
922
923 /* See which ioctl we are doing */
924 switch (cmd) {
925 case TW_OP_NOP:
926 dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");
927 break;
928 case TW_OP_AEN_LISTEN:
929 dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");
930 memset(tw_ioctl->data_buffer, 0, data_buffer_length);
931
932 spin_lock_irqsave(tw_dev->host->host_lock, flags);
933 if (tw_dev->aen_head == tw_dev->aen_tail) {
934 tw_aen_code = TW_AEN_QUEUE_EMPTY;
935 } else {
936 tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
937 if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
938 tw_dev->aen_head = TW_Q_START;
939 } else {
940 tw_dev->aen_head = tw_dev->aen_head + 1;
941 }
942 }
943 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
944 memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));
945 break;
946 case TW_CMD_PACKET_WITH_DATA:
947 dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
948 spin_lock_irqsave(tw_dev->host->host_lock, flags);
949
950 tw_state_request_start(tw_dev, &request_id);
951
952 /* Flag internal command */
953 tw_dev->srb[request_id] = NULL;
954
955 /* Flag chrdev ioctl */
956 tw_dev->chrdev_request_id = request_id;
957
958 tw_ioctl->firmware_command.request_id = request_id;
959
960 /* Load the sg list */
961 switch (TW_SGL_OUT(tw_ioctl->firmware_command.opcode__sgloffset)) {
962 case 2:
963 tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
964 tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
965 break;
966 case 3:
967 tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
968 tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;
969 break;
970 case 5:
971 passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
972 passthru->sg_list[0].length = data_buffer_length_adjusted;
973 break;
974 }
975
976 memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));
977
978 /* Now post the command packet to the controller */
979 tw_post_command_packet(tw_dev, request_id);
980 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
981
982 timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
983
984 /* Now wait for the command to complete */
985 timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
986
987 /* See if we reset while waiting for the ioctl to complete */
988 if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
989 clear_bit(TW_IN_RESET, &tw_dev->flags);
990 retval = -ERESTARTSYS;
991 goto out2;
992 }
993
994 /* We timed out, and didn't get an interrupt */
995 if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
996 /* Now we need to reset the board */
997 printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
998 retval = -EIO;
999 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1000 tw_dev->state[request_id] = TW_S_COMPLETED;
1001 tw_state_request_finish(tw_dev, request_id);
1002 tw_dev->posted_request_count--;
1003 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1004 if (tw_reset_device_extension(tw_dev, 1)) {
1005 printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
1006 }
1007 goto out2;
1008 }
1009
1010 /* Now copy in the command packet response */
1011 memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
1012
1013 /* Now complete the io */
1014 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1015 tw_dev->posted_request_count--;
1016 tw_dev->state[request_id] = TW_S_COMPLETED;
1017 tw_state_request_finish(tw_dev, request_id);
1018 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1019 break;
1020 default:
1021 retval = -ENOTTY;
1022 goto out2;
1023 }
1024
1025 /* Now copy the response to userspace */
1026 if (copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1))
1027 goto out2;
1028 retval = 0;
1029out2:
1030 /* Now free ioctl buf memory */
1031 dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
1032out:
Jes Sorensena12e25b2006-01-11 08:39:45 -05001033 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return retval;
1035} /* End tw_chrdev_ioctl() */
1036
1037/* This function handles open for the character device */
1038static int tw_chrdev_open(struct inode *inode, struct file *file)
1039{
1040 unsigned int minor_number;
1041
1042 dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
1043
1044 minor_number = iminor(inode);
1045 if (minor_number >= tw_device_extension_count)
1046 return -ENODEV;
1047
1048 return 0;
1049} /* End tw_chrdev_open() */
1050
1051/* File operations struct for character device */
1052static struct file_operations tw_fops = {
1053 .owner = THIS_MODULE,
1054 .ioctl = tw_chrdev_ioctl,
1055 .open = tw_chrdev_open,
1056 .release = NULL
1057};
1058
1059/* This function will free up device extension resources */
1060static void tw_free_device_extension(TW_Device_Extension *tw_dev)
1061{
1062 dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
1063
1064 /* Free command packet and generic buffer memory */
1065 if (tw_dev->command_packet_virtual_address[0])
1066 pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
1067
1068 if (tw_dev->alignment_virtual_address[0])
1069 pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
1070} /* End tw_free_device_extension() */
1071
1072/* This function will send an initconnection command to controller */
1073static int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits)
1074{
1075 unsigned long command_que_value;
1076 TW_Command *command_packet;
1077 TW_Response_Queue response_queue;
1078 int request_id = 0;
1079
1080 dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
1081
1082 /* Initialize InitConnection command packet */
1083 if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
1084 printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n");
1085 return 1;
1086 }
1087
1088 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1089 memset(command_packet, 0, sizeof(TW_Sector));
1090 command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_INIT_CONNECTION);
1091 command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;
1092 command_packet->request_id = request_id;
1093 command_packet->status = 0x0;
1094 command_packet->flags = 0x0;
1095 command_packet->byte6.message_credits = message_credits;
1096 command_packet->byte8.init_connection.response_queue_pointer = 0x0;
1097 command_que_value = tw_dev->command_packet_physical_address[request_id];
1098
1099 if (command_que_value == 0) {
1100 printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n");
1101 return 1;
1102 }
1103
1104 /* Send command packet to the board */
1105 outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1106
1107 /* Poll for completion */
1108 if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
1109 response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1110 request_id = TW_RESID_OUT(response_queue.response_id);
1111
1112 if (request_id != 0) {
1113 /* unexpected request id */
1114 printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
1115 return 1;
1116 }
1117 if (command_packet->status != 0) {
1118 /* bad response */
1119 tw_decode_sense(tw_dev, request_id, 0);
1120 return 1;
1121 }
1122 }
1123 return 0;
1124} /* End tw_initconnection() */
1125
1126/* Set a value in the features table */
1127static int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
1128 unsigned char *val)
1129{
1130 TW_Param *param;
1131 TW_Command *command_packet;
1132 TW_Response_Queue response_queue;
1133 int request_id = 0;
1134 unsigned long command_que_value;
1135 unsigned long param_value;
1136
1137 /* Initialize SetParam command packet */
1138 if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
1139 printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n");
1140 return 1;
1141 }
1142 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1143 memset(command_packet, 0, sizeof(TW_Sector));
1144 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1145
1146 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
1147 param->table_id = 0x404; /* Features table */
1148 param->parameter_id = parm;
1149 param->parameter_size_bytes = param_size;
1150 memcpy(param->data, val, param_size);
1151
1152 param_value = tw_dev->alignment_physical_address[request_id];
1153 if (param_value == 0) {
1154 printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad alignment physical address.\n");
1155 tw_dev->state[request_id] = TW_S_COMPLETED;
1156 tw_state_request_finish(tw_dev, request_id);
1157 tw_dev->srb[request_id]->result = (DID_OK << 16);
1158 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1159 }
1160 command_packet->byte8.param.sgl[0].address = param_value;
1161 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
1162
1163 command_packet->size = 4;
1164 command_packet->request_id = request_id;
1165 command_packet->byte6.parameter_count = 1;
1166
1167 command_que_value = tw_dev->command_packet_physical_address[request_id];
1168 if (command_que_value == 0) {
1169 printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n");
1170 return 1;
1171 }
1172
1173 /* Send command packet to the board */
1174 outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1175
1176 /* Poll for completion */
1177 if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
1178 response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1179 request_id = TW_RESID_OUT(response_queue.response_id);
1180
1181 if (request_id != 0) {
1182 /* unexpected request id */
1183 printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
1184 return 1;
1185 }
1186 if (command_packet->status != 0) {
1187 /* bad response */
1188 tw_decode_sense(tw_dev, request_id, 0);
1189 return 1;
1190 }
1191 }
1192
1193 return 0;
1194} /* End tw_setfeature() */
1195
1196/* This function will reset a controller */
1197static int tw_reset_sequence(TW_Device_Extension *tw_dev)
1198{
1199 int error = 0;
1200 int tries = 0;
1201 unsigned char c = 1;
1202
1203 /* Reset the board */
1204 while (tries < TW_MAX_RESET_TRIES) {
1205 TW_SOFT_RESET(tw_dev);
1206
1207 error = tw_aen_drain_queue(tw_dev);
1208 if (error) {
1209 printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
1210 tries++;
1211 continue;
1212 }
1213
1214 /* Check for controller errors */
1215 if (tw_check_errors(tw_dev)) {
1216 printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no);
1217 tries++;
1218 continue;
1219 }
1220
1221 /* Now the controller is in a good state */
1222 break;
1223 }
1224
1225 if (tries >= TW_MAX_RESET_TRIES) {
1226 printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no);
1227 return 1;
1228 }
1229
1230 error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
1231 if (error) {
1232 printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no);
1233 return 1;
1234 }
1235
1236 error = tw_setfeature(tw_dev, 2, 1, &c);
1237 if (error) {
1238 printk(KERN_WARNING "3w-xxxx: Unable to set features for card, probable old firmware or card.\n");
1239 }
1240
1241 return 0;
1242} /* End tw_reset_sequence() */
1243
1244/* This function will initialize the fields of a device extension */
1245static int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
1246{
1247 int i, error=0;
1248
1249 dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
1250
1251 /* Initialize command packet buffers */
1252 error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
1253 if (error) {
1254 printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
1255 return 1;
1256 }
1257
1258 /* Initialize generic buffer */
1259 error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
1260 if (error) {
1261 printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
1262 return 1;
1263 }
1264
1265 for (i=0;i<TW_Q_LENGTH;i++) {
1266 tw_dev->free_queue[i] = i;
1267 tw_dev->state[i] = TW_S_INITIAL;
1268 }
1269
1270 tw_dev->pending_head = TW_Q_START;
1271 tw_dev->pending_tail = TW_Q_START;
1272 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1273
Jes Sorensena12e25b2006-01-11 08:39:45 -05001274 mutex_init(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 init_waitqueue_head(&tw_dev->ioctl_wqueue);
1276
1277 return 0;
1278} /* End tw_initialize_device_extension() */
1279
1280static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
1281{
1282 int use_sg;
1283
1284 dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
1285
1286 if (cmd->use_sg == 0)
1287 return 0;
1288
Christoph Hellwig5d5ff442006-06-03 13:21:13 +02001289 use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 if (use_sg == 0) {
1292 printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
1293 return 0;
1294 }
1295
1296 cmd->SCp.phase = TW_PHASE_SGLIST;
1297 cmd->SCp.have_data_in = use_sg;
1298
1299 return use_sg;
1300} /* End tw_map_scsi_sg_data() */
1301
1302static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
1303{
1304 dma_addr_t mapping;
1305
1306 dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
1307
1308 if (cmd->request_bufflen == 0)
1309 return 0;
1310
1311 mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
1312
1313 if (mapping == 0) {
1314 printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
1315 return 0;
1316 }
1317
1318 cmd->SCp.phase = TW_PHASE_SINGLE;
1319 cmd->SCp.have_data_in = mapping;
1320
1321 return mapping;
1322} /* End tw_map_scsi_single_data() */
1323
1324static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
1325{
1326 dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
1327
1328 switch(cmd->SCp.phase) {
1329 case TW_PHASE_SINGLE:
1330 pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
1331 break;
1332 case TW_PHASE_SGLIST:
1333 pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
1334 break;
1335 }
1336} /* End tw_unmap_scsi_data() */
1337
1338/* This function will reset a device extension */
1339static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
1340{
1341 int i = 0;
1342 struct scsi_cmnd *srb;
1343 unsigned long flags = 0;
1344
1345 dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
1346
1347 set_bit(TW_IN_RESET, &tw_dev->flags);
1348 TW_DISABLE_INTERRUPTS(tw_dev);
1349 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1350 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1351
1352 /* Abort all requests that are in progress */
1353 for (i=0;i<TW_Q_LENGTH;i++) {
1354 if ((tw_dev->state[i] != TW_S_FINISHED) &&
1355 (tw_dev->state[i] != TW_S_INITIAL) &&
1356 (tw_dev->state[i] != TW_S_COMPLETED)) {
1357 srb = tw_dev->srb[i];
1358 if (srb != NULL) {
1359 srb->result = (DID_RESET << 16);
1360 tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
1361 tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
1362 }
1363 }
1364 }
1365
1366 /* Reset queues and counts */
1367 for (i=0;i<TW_Q_LENGTH;i++) {
1368 tw_dev->free_queue[i] = i;
1369 tw_dev->state[i] = TW_S_INITIAL;
1370 }
1371 tw_dev->free_head = TW_Q_START;
1372 tw_dev->free_tail = TW_Q_START;
1373 tw_dev->posted_request_count = 0;
1374 tw_dev->pending_request_count = 0;
1375 tw_dev->pending_head = TW_Q_START;
1376 tw_dev->pending_tail = TW_Q_START;
1377 tw_dev->reset_print = 0;
1378
1379 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1380
1381 if (tw_reset_sequence(tw_dev)) {
1382 printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
1383 return 1;
1384 }
1385 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
1386
1387 /* Wake up any ioctl that was pending before the reset */
1388 if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
1389 clear_bit(TW_IN_RESET, &tw_dev->flags);
1390 } else {
1391 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1392 wake_up(&tw_dev->ioctl_wqueue);
1393 }
1394
1395 return 0;
1396} /* End tw_reset_device_extension() */
1397
1398/* This funciton returns unit geometry in cylinders/heads/sectors */
1399static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
1400 sector_t capacity, int geom[])
1401{
1402 int heads, sectors, cylinders;
1403 TW_Device_Extension *tw_dev;
1404
1405 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
1406 tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
1407
1408 heads = 64;
1409 sectors = 32;
1410 cylinders = sector_div(capacity, heads * sectors);
1411
1412 if (capacity >= 0x200000) {
1413 heads = 255;
1414 sectors = 63;
1415 cylinders = sector_div(capacity, heads * sectors);
1416 }
1417
1418 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
1419 geom[0] = heads;
1420 geom[1] = sectors;
1421 geom[2] = cylinders;
1422
1423 return 0;
1424} /* End tw_scsi_biosparam() */
1425
1426/* This is the new scsi eh reset function */
1427static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt)
1428{
1429 TW_Device_Extension *tw_dev=NULL;
1430 int retval = FAILED;
1431
1432 tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1433
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 tw_dev->num_resets++;
1435
Jeff Garzik017560f2005-10-24 18:04:36 -04001436 sdev_printk(KERN_WARNING, SCpnt->device,
1437 "WARNING: Command (0x%x) timed out, resetting card.\n",
1438 SCpnt->cmnd[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 /* Now reset the card and some of the device extension data */
1441 if (tw_reset_device_extension(tw_dev, 0)) {
1442 printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
1443 goto out;
1444 }
1445
1446 retval = SUCCESS;
1447out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 return retval;
1449} /* End tw_scsi_eh_reset() */
1450
1451/* This function handles scsi inquiry commands */
1452static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
1453{
1454 TW_Param *param;
1455 TW_Command *command_packet;
1456 unsigned long command_que_value;
1457 unsigned long param_value;
1458
1459 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
1460
1461 /* Initialize command packet */
1462 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1463 if (command_packet == NULL) {
1464 printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet virtual address.\n");
1465 return 1;
1466 }
1467 memset(command_packet, 0, sizeof(TW_Sector));
1468 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1469 command_packet->size = 4;
1470 command_packet->request_id = request_id;
1471 command_packet->status = 0;
1472 command_packet->flags = 0;
1473 command_packet->byte6.parameter_count = 1;
1474
1475 /* Now setup the param */
1476 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
1477 printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment virtual address.\n");
1478 return 1;
1479 }
1480 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1481 memset(param, 0, sizeof(TW_Sector));
1482 param->table_id = 3; /* unit summary table */
1483 param->parameter_id = 3; /* unitsstatus parameter */
1484 param->parameter_size_bytes = TW_MAX_UNITS;
1485 param_value = tw_dev->alignment_physical_address[request_id];
1486 if (param_value == 0) {
1487 printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n");
1488 return 1;
1489 }
1490
1491 command_packet->byte8.param.sgl[0].address = param_value;
1492 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
1493 command_que_value = tw_dev->command_packet_physical_address[request_id];
1494 if (command_que_value == 0) {
1495 printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n");
1496 return 1;
1497 }
1498
1499 /* Now try to post the command packet */
1500 tw_post_command_packet(tw_dev, request_id);
1501
1502 return 0;
1503} /* End tw_scsiop_inquiry() */
1504
James Bottomleyc9d297c2005-06-28 09:18:21 -05001505static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
1506 void *data, unsigned int len)
1507{
1508 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
1509 void *buf;
1510 unsigned int transfer_len;
Andrew Morton7551d9a2006-04-10 22:54:34 -07001511 unsigned long flags = 0;
James Bottomleyc9d297c2005-06-28 09:18:21 -05001512
1513 if (cmd->use_sg) {
1514 struct scatterlist *sg =
1515 (struct scatterlist *)cmd->request_buffer;
Andrew Morton7551d9a2006-04-10 22:54:34 -07001516 local_irq_save(flags);
James Bottomleyc9d297c2005-06-28 09:18:21 -05001517 buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
1518 transfer_len = min(sg->length, len);
1519 } else {
1520 buf = cmd->request_buffer;
1521 transfer_len = min(cmd->request_bufflen, len);
1522 }
1523
1524 memcpy(buf, data, transfer_len);
1525
1526 if (cmd->use_sg) {
1527 struct scatterlist *sg;
1528
1529 sg = (struct scatterlist *)cmd->request_buffer;
1530 kunmap_atomic(buf - sg->offset, KM_IRQ0);
Andrew Morton7551d9a2006-04-10 22:54:34 -07001531 local_irq_restore(flags);
James Bottomleyc9d297c2005-06-28 09:18:21 -05001532 }
1533}
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535/* This function is called by the isr to complete an inquiry command */
1536static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
1537{
1538 unsigned char *is_unit_present;
James Bottomleyc9d297c2005-06-28 09:18:21 -05001539 unsigned char request_buffer[36];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 TW_Param *param;
1541
1542 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
1543
James Bottomleyc9d297c2005-06-28 09:18:21 -05001544 memset(request_buffer, 0, sizeof(request_buffer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 request_buffer[0] = TYPE_DISK; /* Peripheral device type */
1546 request_buffer[1] = 0; /* Device type modifier */
1547 request_buffer[2] = 0; /* No ansi/iso compliance */
1548 request_buffer[4] = 31; /* Additional length */
1549 memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */
1550 sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
1551 memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3);
James Bottomleyc9d297c2005-06-28 09:18:21 -05001552 tw_transfer_internal(tw_dev, request_id, request_buffer,
1553 sizeof(request_buffer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
1555 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1556 if (param == NULL) {
1557 printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n");
1558 return 1;
1559 }
1560 is_unit_present = &(param->data[0]);
1561
1562 if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
1563 tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
1564 } else {
1565 tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
1566 tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
1567 return TW_ISR_DONT_RESULT;
1568 }
1569
1570 return 0;
1571} /* End tw_scsiop_inquiry_complete() */
1572
1573/* This function handles scsi mode_sense commands */
1574static int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
1575{
1576 TW_Param *param;
1577 TW_Command *command_packet;
1578 unsigned long command_que_value;
1579 unsigned long param_value;
1580
1581 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
1582
1583 /* Only page control = 0, page code = 0x8 (cache page) supported */
1584 if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
1585 tw_dev->state[request_id] = TW_S_COMPLETED;
1586 tw_state_request_finish(tw_dev, request_id);
1587 tw_dev->srb[request_id]->result = (DID_OK << 16);
1588 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1589 return 0;
1590 }
1591
1592 /* Now read firmware cache setting for this unit */
1593 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1594 if (command_packet == NULL) {
1595 printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
1596 return 1;
1597 }
1598
1599 /* Setup the command packet */
1600 memset(command_packet, 0, sizeof(TW_Sector));
1601 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1602 command_packet->size = 4;
1603 command_packet->request_id = request_id;
1604 command_packet->status = 0;
1605 command_packet->flags = 0;
1606 command_packet->byte6.parameter_count = 1;
1607
1608 /* Setup the param */
1609 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
1610 printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
1611 return 1;
1612 }
1613
1614 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1615 memset(param, 0, sizeof(TW_Sector));
1616 param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id;
1617 param->parameter_id = 7; /* unit flags */
1618 param->parameter_size_bytes = 1;
1619 param_value = tw_dev->alignment_physical_address[request_id];
1620 if (param_value == 0) {
1621 printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
1622 return 1;
1623 }
1624
1625 command_packet->byte8.param.sgl[0].address = param_value;
1626 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
1627 command_que_value = tw_dev->command_packet_physical_address[request_id];
1628 if (command_que_value == 0) {
1629 printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
1630 return 1;
1631 }
1632
1633 /* Now try to post the command packet */
1634 tw_post_command_packet(tw_dev, request_id);
1635
1636 return 0;
1637} /* End tw_scsiop_mode_sense() */
1638
1639/* This function is called by the isr to complete a mode sense command */
1640static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
1641{
1642 TW_Param *param;
1643 unsigned char *flags;
James Bottomleyc9d297c2005-06-28 09:18:21 -05001644 unsigned char request_buffer[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
1647
1648 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1649 if (param == NULL) {
1650 printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
1651 return 1;
1652 }
1653 flags = (char *)&(param->data[0]);
James Bottomleyc9d297c2005-06-28 09:18:21 -05001654 memset(request_buffer, 0, sizeof(request_buffer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 request_buffer[0] = 0xf; /* mode data length */
1657 request_buffer[1] = 0; /* default medium type */
1658 request_buffer[2] = 0x10; /* dpo/fua support on */
1659 request_buffer[3] = 0; /* no block descriptors */
1660 request_buffer[4] = 0x8; /* caching page */
1661 request_buffer[5] = 0xa; /* page length */
1662 if (*flags & 0x1)
1663 request_buffer[6] = 0x4; /* WCE on */
1664 else
1665 request_buffer[6] = 0x0; /* WCE off */
James Bottomleyc9d297c2005-06-28 09:18:21 -05001666 tw_transfer_internal(tw_dev, request_id, request_buffer,
1667 sizeof(request_buffer));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
1669 return 0;
1670} /* End tw_scsiop_mode_sense_complete() */
1671
1672/* This function handles scsi read_capacity commands */
1673static int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id)
1674{
1675 TW_Param *param;
1676 TW_Command *command_packet;
1677 unsigned long command_que_value;
1678 unsigned long param_value;
1679
1680 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
1681
1682 /* Initialize command packet */
1683 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1684
1685 if (command_packet == NULL) {
1686 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet virtual address.\n");
1687 return 1;
1688 }
1689 memset(command_packet, 0, sizeof(TW_Sector));
1690 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1691 command_packet->size = 4;
1692 command_packet->request_id = request_id;
1693 command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
1694 command_packet->status = 0;
1695 command_packet->flags = 0;
1696 command_packet->byte6.block_count = 1;
1697
1698 /* Now setup the param */
1699 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
1700 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n");
1701 return 1;
1702 }
1703 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1704 memset(param, 0, sizeof(TW_Sector));
1705 param->table_id = TW_UNIT_INFORMATION_TABLE_BASE +
1706 tw_dev->srb[request_id]->device->id;
1707 param->parameter_id = 4; /* unitcapacity parameter */
1708 param->parameter_size_bytes = 4;
1709 param_value = tw_dev->alignment_physical_address[request_id];
1710 if (param_value == 0) {
1711 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment physical address.\n");
1712 return 1;
1713 }
1714
1715 command_packet->byte8.param.sgl[0].address = param_value;
1716 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
1717 command_que_value = tw_dev->command_packet_physical_address[request_id];
1718 if (command_que_value == 0) {
1719 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n");
1720 return 1;
1721 }
1722
1723 /* Now try to post the command to the board */
1724 tw_post_command_packet(tw_dev, request_id);
1725
1726 return 0;
1727} /* End tw_scsiop_read_capacity() */
1728
1729/* This function is called by the isr to complete a readcapacity command */
1730static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id)
1731{
1732 unsigned char *param_data;
1733 u32 capacity;
James Bottomleyc9d297c2005-06-28 09:18:21 -05001734 char buff[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 TW_Param *param;
1736
1737 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
1738
James Bottomleyc9d297c2005-06-28 09:18:21 -05001739 memset(buff, 0, sizeof(buff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1741 if (param == NULL) {
1742 printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
1743 return 1;
1744 }
1745 param_data = &(param->data[0]);
1746
1747 capacity = (param_data[3] << 24) | (param_data[2] << 16) |
1748 (param_data[1] << 8) | param_data[0];
1749
1750 /* Subtract one sector to fix get last sector ioctl */
1751 capacity -= 1;
1752
1753 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
1754
1755 /* Number of LBA's */
1756 buff[0] = (capacity >> 24);
1757 buff[1] = (capacity >> 16) & 0xff;
1758 buff[2] = (capacity >> 8) & 0xff;
1759 buff[3] = capacity & 0xff;
1760
1761 /* Block size in bytes (512) */
1762 buff[4] = (TW_BLOCK_SIZE >> 24);
1763 buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
1764 buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
1765 buff[7] = TW_BLOCK_SIZE & 0xff;
1766
James Bottomleyc9d297c2005-06-28 09:18:21 -05001767 tw_transfer_internal(tw_dev, request_id, buff, sizeof(buff));
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 return 0;
1770} /* End tw_scsiop_read_capacity_complete() */
1771
1772/* This function handles scsi read or write commands */
1773static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
1774{
1775 TW_Command *command_packet;
1776 unsigned long command_que_value;
1777 u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
1778 int i, use_sg;
1779 struct scsi_cmnd *srb;
1780 struct scatterlist *sglist;
1781
1782 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
1783
1784 if (tw_dev->srb[request_id]->request_buffer == NULL) {
1785 printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
1786 return 1;
1787 }
1788 sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
1789 srb = tw_dev->srb[request_id];
1790
1791 /* Initialize command packet */
1792 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1793 if (command_packet == NULL) {
1794 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n");
1795 return 1;
1796 }
1797
1798 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) {
1799 command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_READ);
1800 } else {
1801 command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_WRITE);
1802 }
1803
1804 command_packet->size = 3;
1805 command_packet->request_id = request_id;
1806 command_packet->unit__hostid = TW_UNITHOST_IN(0, srb->device->id);
1807 command_packet->status = 0;
1808 command_packet->flags = 0;
1809
1810 if (srb->cmnd[0] == WRITE_10) {
1811 if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
1812 command_packet->flags = 1;
1813 }
1814
1815 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
1816 lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
1817 num_sectors = (u32)srb->cmnd[4];
1818 } else {
1819 lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
1820 num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
1821 }
1822
1823 /* Update sector statistic */
1824 tw_dev->sector_count = num_sectors;
1825 if (tw_dev->sector_count > tw_dev->max_sector_count)
1826 tw_dev->max_sector_count = tw_dev->sector_count;
1827
1828 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors);
1829 command_packet->byte8.io.lba = lba;
1830 command_packet->byte6.block_count = num_sectors;
1831
1832 /* Do this if there are no sg list entries */
1833 if (tw_dev->srb[request_id]->use_sg == 0) {
1834 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
1835 buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
1836 if (buffaddr == 0)
1837 return 1;
1838
1839 command_packet->byte8.io.sgl[0].address = buffaddr;
1840 command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
1841 command_packet->size+=2;
1842 }
1843
1844 /* Do this if we have multiple sg list entries */
1845 if (tw_dev->srb[request_id]->use_sg > 0) {
1846 use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
1847 if (use_sg == 0)
1848 return 1;
1849
1850 for (i=0;i<use_sg; i++) {
1851 command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
1852 command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
1853 command_packet->size+=2;
1854 }
1855 }
1856
1857 /* Update SG statistics */
1858 tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
1859 if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
1860 tw_dev->max_sgl_entries = tw_dev->sgl_entries;
1861
1862 command_que_value = tw_dev->command_packet_physical_address[request_id];
1863 if (command_que_value == 0) {
1864 dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n");
1865 return 1;
1866 }
1867
1868 /* Now try to post the command to the board */
1869 tw_post_command_packet(tw_dev, request_id);
1870
1871 return 0;
1872} /* End tw_scsiop_read_write() */
1873
1874/* This function will handle the request sense scsi command */
1875static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
1876{
1877 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
1878
1879 /* For now we just zero the request buffer */
1880 memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
1881 tw_dev->state[request_id] = TW_S_COMPLETED;
1882 tw_state_request_finish(tw_dev, request_id);
1883
1884 /* If we got a request_sense, we probably want a reset, return error */
1885 tw_dev->srb[request_id]->result = (DID_ERROR << 16);
1886 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1887
1888 return 0;
1889} /* End tw_scsiop_request_sense() */
1890
1891/* This function will handle synchronize cache scsi command */
1892static int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
1893{
1894 TW_Command *command_packet;
1895 unsigned long command_que_value;
1896
1897 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
1898
1899 /* Send firmware flush command for this unit */
1900 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1901 if (command_packet == NULL) {
1902 printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
1903 return 1;
1904 }
1905
1906 /* Setup the command packet */
1907 memset(command_packet, 0, sizeof(TW_Sector));
1908 command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_FLUSH_CACHE);
1909 command_packet->size = 2;
1910 command_packet->request_id = request_id;
1911 command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
1912 command_packet->status = 0;
1913 command_packet->flags = 0;
1914 command_packet->byte6.parameter_count = 1;
1915 command_que_value = tw_dev->command_packet_physical_address[request_id];
1916 if (command_que_value == 0) {
1917 printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
1918 return 1;
1919 }
1920
1921 /* Now try to post the command packet */
1922 tw_post_command_packet(tw_dev, request_id);
1923
1924 return 0;
1925} /* End tw_scsiop_synchronize_cache() */
1926
1927/* This function will handle test unit ready scsi command */
1928static int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
1929{
1930 TW_Param *param;
1931 TW_Command *command_packet;
1932 unsigned long command_que_value;
1933 unsigned long param_value;
1934
1935 dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
1936
1937 /* Initialize command packet */
1938 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
1939 if (command_packet == NULL) {
1940 printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
1941 return 1;
1942 }
1943 memset(command_packet, 0, sizeof(TW_Sector));
1944 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1945 command_packet->size = 4;
1946 command_packet->request_id = request_id;
1947 command_packet->status = 0;
1948 command_packet->flags = 0;
1949 command_packet->byte6.parameter_count = 1;
1950
1951 /* Now setup the param */
1952 if (tw_dev->alignment_virtual_address[request_id] == NULL) {
1953 printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
1954 return 1;
1955 }
1956 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1957 memset(param, 0, sizeof(TW_Sector));
1958 param->table_id = 3; /* unit summary table */
1959 param->parameter_id = 3; /* unitsstatus parameter */
1960 param->parameter_size_bytes = TW_MAX_UNITS;
1961 param_value = tw_dev->alignment_physical_address[request_id];
1962 if (param_value == 0) {
1963 printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
1964 return 1;
1965 }
1966
1967 command_packet->byte8.param.sgl[0].address = param_value;
1968 command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
1969 command_que_value = tw_dev->command_packet_physical_address[request_id];
1970 if (command_que_value == 0) {
1971 printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
1972 return 1;
1973 }
1974
1975 /* Now try to post the command packet */
1976 tw_post_command_packet(tw_dev, request_id);
1977
1978 return 0;
1979} /* End tw_scsiop_test_unit_ready() */
1980
1981/* This function is called by the isr to complete a testunitready command */
1982static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
1983{
1984 unsigned char *is_unit_present;
1985 TW_Param *param;
1986
1987 dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
1988
1989 param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
1990 if (param == NULL) {
1991 printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
1992 return 1;
1993 }
1994 is_unit_present = &(param->data[0]);
1995
1996 if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
1997 tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
1998 } else {
1999 tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
2000 tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
2001 return TW_ISR_DONT_RESULT;
2002 }
2003
2004 return 0;
2005} /* End tw_scsiop_test_unit_ready_complete() */
2006
2007/* This is the main scsi queue function to handle scsi opcodes */
2008static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
2009{
2010 unsigned char *command = SCpnt->cmnd;
2011 int request_id = 0;
2012 int retval = 1;
2013 TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
2014
2015 /* Save done function into Scsi_Cmnd struct */
2016 SCpnt->scsi_done = done;
2017
2018 /* Queue the command and get a request id */
2019 tw_state_request_start(tw_dev, &request_id);
2020
2021 /* Save the scsi command for use by the ISR */
2022 tw_dev->srb[request_id] = SCpnt;
2023
2024 /* Initialize phase to zero */
2025 SCpnt->SCp.phase = TW_PHASE_INITIAL;
2026
2027 switch (*command) {
2028 case READ_10:
2029 case READ_6:
2030 case WRITE_10:
2031 case WRITE_6:
2032 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n");
2033 retval = tw_scsiop_read_write(tw_dev, request_id);
2034 break;
2035 case TEST_UNIT_READY:
2036 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n");
2037 retval = tw_scsiop_test_unit_ready(tw_dev, request_id);
2038 break;
2039 case INQUIRY:
2040 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n");
2041 retval = tw_scsiop_inquiry(tw_dev, request_id);
2042 break;
2043 case READ_CAPACITY:
2044 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
2045 retval = tw_scsiop_read_capacity(tw_dev, request_id);
2046 break;
2047 case REQUEST_SENSE:
2048 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
2049 retval = tw_scsiop_request_sense(tw_dev, request_id);
2050 break;
2051 case MODE_SENSE:
2052 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n");
2053 retval = tw_scsiop_mode_sense(tw_dev, request_id);
2054 break;
2055 case SYNCHRONIZE_CACHE:
2056 dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n");
2057 retval = tw_scsiop_synchronize_cache(tw_dev, request_id);
2058 break;
2059 case TW_IOCTL:
2060 printk(KERN_WARNING "3w-xxxx: SCSI_IOCTL_SEND_COMMAND deprecated, please update your 3ware tools.\n");
2061 break;
2062 default:
2063 printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command);
2064 tw_dev->state[request_id] = TW_S_COMPLETED;
2065 tw_state_request_finish(tw_dev, request_id);
2066 SCpnt->result = (DID_BAD_TARGET << 16);
2067 done(SCpnt);
2068 retval = 0;
2069 }
2070 if (retval) {
2071 tw_dev->state[request_id] = TW_S_COMPLETED;
2072 tw_state_request_finish(tw_dev, request_id);
2073 SCpnt->result = (DID_ERROR << 16);
2074 done(SCpnt);
2075 retval = 0;
2076 }
2077 return retval;
2078} /* End tw_scsi_queue() */
2079
2080/* This function is the interrupt service routine */
2081static irqreturn_t tw_interrupt(int irq, void *dev_instance,
2082 struct pt_regs *regs)
2083{
2084 int request_id;
2085 u32 status_reg_value;
2086 TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
2087 TW_Response_Queue response_que;
2088 int error = 0, retval = 0;
2089 TW_Command *command_packet;
2090 int handled = 0;
2091
2092 /* Get the host lock for io completions */
2093 spin_lock(tw_dev->host->host_lock);
2094
2095 /* Read the registers */
2096 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
2097
2098 /* Check if this is our interrupt, otherwise bail */
2099 if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
2100 goto tw_interrupt_bail;
2101
2102 handled = 1;
2103
2104 /* Check controller for errors */
2105 if (tw_check_bits(status_reg_value)) {
2106 dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
2107 if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
2108 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2109 goto tw_interrupt_bail;
2110 }
2111 }
2112
2113 /* Handle host interrupt */
2114 if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
2115 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
2116 TW_CLEAR_HOST_INTERRUPT(tw_dev);
2117 }
2118
2119 /* Handle attention interrupt */
2120 if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
2121 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
2122 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
2123 tw_state_request_start(tw_dev, &request_id);
2124 error = tw_aen_read_queue(tw_dev, request_id);
2125 if (error) {
2126 printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
2127 tw_dev->state[request_id] = TW_S_COMPLETED;
2128 tw_state_request_finish(tw_dev, request_id);
2129 }
2130 }
2131
2132 /* Handle command interrupt */
2133 if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
2134 /* Drain as many pending commands as we can */
2135 while (tw_dev->pending_request_count > 0) {
2136 request_id = tw_dev->pending_queue[tw_dev->pending_head];
2137 if (tw_dev->state[request_id] != TW_S_PENDING) {
2138 printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
2139 break;
2140 }
2141 if (tw_post_command_packet(tw_dev, request_id)==0) {
2142 if (tw_dev->pending_head == TW_Q_LENGTH-1) {
2143 tw_dev->pending_head = TW_Q_START;
2144 } else {
2145 tw_dev->pending_head = tw_dev->pending_head + 1;
2146 }
2147 tw_dev->pending_request_count--;
2148 } else {
2149 /* If we get here, we will continue re-posting on the next command interrupt */
2150 break;
2151 }
2152 }
2153 /* If there are no more pending requests, we mask command interrupt */
2154 if (tw_dev->pending_request_count == 0)
2155 TW_MASK_COMMAND_INTERRUPT(tw_dev);
2156 }
2157
2158 /* Handle response interrupt */
2159 if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
2160 /* Drain the response queue from the board */
2161 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
2162 /* Read response queue register */
2163 response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
2164 request_id = TW_RESID_OUT(response_que.response_id);
2165 command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
2166 error = 0;
2167
2168 /* Check for bad response */
2169 if (command_packet->status != 0) {
2170 /* If internal command, don't error, don't fill sense */
2171 if (tw_dev->srb[request_id] == NULL) {
2172 tw_decode_sense(tw_dev, request_id, 0);
2173 } else {
2174 error = tw_decode_sense(tw_dev, request_id, 1);
2175 }
2176 }
2177
2178 /* Check for correct state */
2179 if (tw_dev->state[request_id] != TW_S_POSTED) {
2180 if (tw_dev->srb[request_id] != NULL) {
2181 printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no);
2182 error = 1;
2183 }
2184 }
2185
2186 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
2187
2188 /* Check for internal command completion */
2189 if (tw_dev->srb[request_id] == NULL) {
2190 dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
2191 /* Check for chrdev ioctl completion */
2192 if (request_id != tw_dev->chrdev_request_id) {
2193 retval = tw_aen_complete(tw_dev, request_id);
2194 if (retval) {
2195 printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
2196 }
2197 } else {
2198 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
2199 wake_up(&tw_dev->ioctl_wqueue);
2200 }
2201 } else {
2202 switch (tw_dev->srb[request_id]->cmnd[0]) {
2203 case READ_10:
2204 case READ_6:
2205 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
2206 break;
2207 case WRITE_10:
2208 case WRITE_6:
2209 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
2210 break;
2211 case TEST_UNIT_READY:
2212 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
2213 error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
2214 break;
2215 case INQUIRY:
2216 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
2217 error = tw_scsiop_inquiry_complete(tw_dev, request_id);
2218 break;
2219 case READ_CAPACITY:
2220 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
2221 error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
2222 break;
2223 case MODE_SENSE:
2224 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
2225 error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
2226 break;
2227 case SYNCHRONIZE_CACHE:
2228 dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
2229 break;
2230 default:
2231 printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
2232 error = 1;
2233 }
2234
2235 /* If no error command was a success */
2236 if (error == 0) {
2237 tw_dev->srb[request_id]->result = (DID_OK << 16);
2238 }
2239
2240 /* If error, command failed */
2241 if (error == 1) {
2242 /* Ask for a host reset */
2243 tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
2244 }
2245
2246 /* Now complete the io */
2247 if ((error != TW_ISR_DONT_COMPLETE)) {
2248 tw_dev->state[request_id] = TW_S_COMPLETED;
2249 tw_state_request_finish(tw_dev, request_id);
2250 tw_dev->posted_request_count--;
2251 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
2252
2253 tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
2254 }
2255 }
2256
2257 /* Check for valid status after each drain */
2258 status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
2259 if (tw_check_bits(status_reg_value)) {
2260 dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
2261 if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
2262 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2263 goto tw_interrupt_bail;
2264 }
2265 }
2266 }
2267 }
2268
2269tw_interrupt_bail:
2270 spin_unlock(tw_dev->host->host_lock);
2271 return IRQ_RETVAL(handled);
2272} /* End tw_interrupt() */
2273
2274/* This function tells the controller to shut down */
2275static void __tw_shutdown(TW_Device_Extension *tw_dev)
2276{
2277 /* Disable interrupts */
2278 TW_DISABLE_INTERRUPTS(tw_dev);
2279
2280 printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no);
2281
2282 /* Tell the card we are shutting down */
2283 if (tw_initconnection(tw_dev, 1)) {
2284 printk(KERN_WARNING "3w-xxxx: Connection shutdown failed.\n");
2285 } else {
2286 printk(KERN_WARNING "3w-xxxx: Shutdown complete.\n");
2287 }
2288
2289 /* Clear all interrupts just before exit */
2290 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2291} /* End __tw_shutdown() */
2292
2293/* Wrapper for __tw_shutdown */
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002294static void tw_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002296 struct Scsi_Host *host = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2298
2299 __tw_shutdown(tw_dev);
2300} /* End tw_shutdown() */
2301
2302static struct scsi_host_template driver_template = {
2303 .module = THIS_MODULE,
2304 .name = "3ware Storage Controller",
2305 .queuecommand = tw_scsi_queue,
2306 .eh_host_reset_handler = tw_scsi_eh_reset,
2307 .bios_param = tw_scsi_biosparam,
2308 .change_queue_depth = tw_change_queue_depth,
2309 .can_queue = TW_Q_LENGTH-2,
2310 .this_id = -1,
2311 .sg_tablesize = TW_MAX_SGL_LENGTH,
2312 .max_sectors = TW_MAX_SECTORS,
2313 .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
2314 .use_clustering = ENABLE_CLUSTERING,
2315 .shost_attrs = tw_host_attrs,
2316 .emulated = 1
2317};
2318
2319/* This function will probe and initialize a card */
2320static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
2321{
2322 struct Scsi_Host *host = NULL;
2323 TW_Device_Extension *tw_dev;
2324 int retval = -ENODEV;
2325
2326 retval = pci_enable_device(pdev);
2327 if (retval) {
2328 printk(KERN_WARNING "3w-xxxx: Failed to enable pci device.");
2329 goto out_disable_device;
2330 }
2331
2332 pci_set_master(pdev);
2333
2334 retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
2335 if (retval) {
2336 printk(KERN_WARNING "3w-xxxx: Failed to set dma mask.");
2337 goto out_disable_device;
2338 }
2339
2340 host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
2341 if (!host) {
2342 printk(KERN_WARNING "3w-xxxx: Failed to allocate memory for device extension.");
2343 retval = -ENOMEM;
2344 goto out_disable_device;
2345 }
2346 tw_dev = (TW_Device_Extension *)host->hostdata;
2347
2348 memset(tw_dev, 0, sizeof(TW_Device_Extension));
2349
2350 /* Save values to device extension */
2351 tw_dev->host = host;
2352 tw_dev->tw_pci_dev = pdev;
2353
2354 if (tw_initialize_device_extension(tw_dev)) {
2355 printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension.");
2356 goto out_free_device_extension;
2357 }
2358
2359 /* Request IO regions */
2360 retval = pci_request_regions(pdev, "3w-xxxx");
2361 if (retval) {
2362 printk(KERN_WARNING "3w-xxxx: Failed to get mem region.");
2363 goto out_free_device_extension;
2364 }
2365
2366 /* Save base address */
2367 tw_dev->base_addr = pci_resource_start(pdev, 0);
2368 if (!tw_dev->base_addr) {
2369 printk(KERN_WARNING "3w-xxxx: Failed to get io address.");
2370 goto out_release_mem_region;
2371 }
2372
2373 /* Disable interrupts on the card */
2374 TW_DISABLE_INTERRUPTS(tw_dev);
2375
2376 /* Initialize the card */
2377 if (tw_reset_sequence(tw_dev))
2378 goto out_release_mem_region;
2379
2380 /* Set host specific parameters */
2381 host->max_id = TW_MAX_UNITS;
2382 host->max_cmd_len = TW_MAX_CDB_LEN;
2383
2384 /* Luns and channels aren't supported by adapter */
2385 host->max_lun = 0;
2386 host->max_channel = 0;
2387
2388 /* Register the card with the kernel SCSI layer */
2389 retval = scsi_add_host(host, &pdev->dev);
2390 if (retval) {
2391 printk(KERN_WARNING "3w-xxxx: scsi add host failed");
2392 goto out_release_mem_region;
2393 }
2394
2395 pci_set_drvdata(pdev, host);
2396
2397 printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq);
2398
2399 /* Now setup the interrupt handler */
2400 retval = request_irq(pdev->irq, tw_interrupt, SA_SHIRQ, "3w-xxxx", tw_dev);
2401 if (retval) {
2402 printk(KERN_WARNING "3w-xxxx: Error requesting IRQ.");
2403 goto out_remove_host;
2404 }
2405
2406 tw_device_extension_list[tw_device_extension_count] = tw_dev;
2407 tw_device_extension_count++;
2408
2409 /* Re-enable interrupts on the card */
2410 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2411
2412 /* Finally, scan the host */
2413 scsi_scan_host(host);
2414
2415 if (twe_major == -1) {
2416 if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0)
2417 printk(KERN_WARNING "3w-xxxx: Failed to register character device.");
2418 }
2419 return 0;
2420
2421out_remove_host:
2422 scsi_remove_host(host);
2423out_release_mem_region:
2424 pci_release_regions(pdev);
2425out_free_device_extension:
2426 tw_free_device_extension(tw_dev);
2427 scsi_host_put(host);
2428out_disable_device:
2429 pci_disable_device(pdev);
2430
2431 return retval;
2432} /* End tw_probe() */
2433
2434/* This function is called to remove a device */
2435static void tw_remove(struct pci_dev *pdev)
2436{
2437 struct Scsi_Host *host = pci_get_drvdata(pdev);
2438 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2439
2440 scsi_remove_host(tw_dev->host);
2441
2442 /* Unregister character device */
2443 if (twe_major >= 0) {
2444 unregister_chrdev(twe_major, "twe");
2445 twe_major = -1;
2446 }
2447
2448 /* Free up the IRQ */
2449 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
2450
2451 /* Shutdown the card */
2452 __tw_shutdown(tw_dev);
2453
2454 /* Free up the mem region */
2455 pci_release_regions(pdev);
2456
2457 /* Free up device extension resources */
2458 tw_free_device_extension(tw_dev);
2459
2460 scsi_host_put(tw_dev->host);
2461 pci_disable_device(pdev);
2462 tw_device_extension_count--;
2463} /* End tw_remove() */
2464
2465/* PCI Devices supported by this driver */
2466static struct pci_device_id tw_pci_tbl[] __devinitdata = {
2467 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000,
2468 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2469 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000,
2470 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
2471 { }
2472};
2473MODULE_DEVICE_TABLE(pci, tw_pci_tbl);
2474
2475/* pci_driver initializer */
2476static struct pci_driver tw_driver = {
2477 .name = "3w-xxxx",
2478 .id_table = tw_pci_tbl,
2479 .probe = tw_probe,
2480 .remove = tw_remove,
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002481 .shutdown = tw_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482};
2483
2484/* This function is called on driver initialization */
2485static int __init tw_init(void)
2486{
2487 printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
2488
2489 return pci_module_init(&tw_driver);
2490} /* End tw_init() */
2491
2492/* This function is called on driver exit */
2493static void __exit tw_exit(void)
2494{
2495 pci_unregister_driver(&tw_driver);
2496} /* End tw_exit() */
2497
2498module_init(tw_init);
2499module_exit(tw_exit);
2500