]> git.hungrycats.org Git - linux/commitdiff
[PATCH] udpated 3ware driver from vendor.
authorDave Jones <davej@suse.de>
Thu, 20 Jun 2002 05:15:50 +0000 (22:15 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Thu, 20 Jun 2002 05:15:50 +0000 (22:15 -0700)
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h

index c7ccb6c0ad21b30dc1d8b3e6cf27d437cc3242f6..87b883e6107f0094f0fff06ceb64fe3bd5c27398 100644 (file)
                  Empty stale responses before draining aen queue.
                  Fix tw_scsi_eh_abort() to not reset on every io abort.
                  Set can_queue in SHT to 255 to prevent hang from AEN.
+   1.02.00.022 - Fix possible null pointer dereference in tw_scsi_release().
+   1.02.00.023 - Fix bug in tw_aen_drain_queue() where unit # was always zero.
+   1.02.00.024 - Add severity levels to AEN strings.
+   1.02.00.025 - Fix command interrupt spurious error messages.
+                 Fix bug in raw command post with data ioctl method.
+                 Fix bug where rollcall sometimes failed with cable errors.
+                 Print unit # on all command timeouts.
 */
 
 #include <linux/module.h>
 
 MODULE_AUTHOR ("3ware Inc.");
+#ifdef __SMP__
+MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver (SMP)");
+#else
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
+#endif
 MODULE_LICENSE("GPL");
 
 #include <linux/kernel.h>
@@ -190,7 +201,7 @@ static struct notifier_block tw_notifier = {
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.021";
+char *tw_driver_version="1.02.00.025";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -214,7 +225,7 @@ int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id)
 
        /* Print some useful info when certain aen codes come out */
        if (aen == 0x0ff) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: AEN queue overflow.\n", tw_dev->host->host_no);
+               printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
        } else {
                if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
                        if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
@@ -286,7 +297,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
        status_reg_addr = tw_dev->registers.status_reg_addr;
        response_que_addr = tw_dev->registers.response_que_addr;
 
-       if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
+       if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
                dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
                return 1;
        }
@@ -396,7 +407,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
                                                break;
                                        default:
                                                if (aen == 0x0ff) {
-                                                       printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
+                                                       printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
                                                } else {
                                                        if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
                                                                if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
@@ -413,7 +424,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
 
                                /* Now put the aen on the aen_queue */
                                if (queue == 1) {
-                                       tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+                                       tw_dev->aen_queue[tw_dev->aen_tail] = aen;
                                        if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
                                                tw_dev->aen_tail = TW_Q_START;
                                        } else {
@@ -1348,7 +1359,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        }
                                        tw_dev->pending_request_count--;
                                } else {
-                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no);
+                                       /* If we get here, we will continue re-posting on the next command interrupt */
                                        break;
                                }
                        }
@@ -1379,8 +1390,13 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
                                /* Check for correct state */
                                if (tw_dev->state[request_id] != TW_S_POSTED) {
-                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
-                                       error = 1;
+                                       /* Handle timed out ioctl's */
+                                       if (tw_dev->srb[request_id] != 0) {
+                                               if (tw_dev->srb[request_id]->cmnd[0] != TW_IOCTL) {
+                                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
+                                                       error = 1;
+                                               }
+                                       }
                                }
 
                                dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
@@ -1472,8 +1488,9 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
        TW_Passthru *passthru = NULL;
        int tw_aen_code, i, use_sg;
        char *data_ptr;
-       int total_bytes = 0;
+       int total_bytes = 0, posted = 0;
        dma_addr_t dma_handle;
+       struct timeval before, timeout;
 
        ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
        if (ioctl == NULL) {
@@ -1625,7 +1642,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                                if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
                                                        error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
                                                        if (error) {
-                                                               printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
+                                                               dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
                                                                goto tw_ioctl_bail;
                                                        }
                                                } else {
@@ -1656,7 +1673,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                                        if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
                                                                error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
                                                                if (error) {
-                                                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
+                                                                       dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
                                                                        goto tw_ioctl_bail;
                                                                }
                                                        } else {
@@ -1672,15 +1689,31 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                        command_packet->byte8.io.sgl[0].length = total_bytes;
                                }
 
+                               spin_unlock(&tw_dev->tw_lock);
                                spin_unlock_irq(tw_dev->host->host_lock);
-                               spin_unlock_irq(&tw_dev->tw_lock);
+
+                               set_bit(TW_IN_IOCTL, &tw_dev->flags);
 
                                /* Finally post the command packet */
                                tw_post_command_packet(tw_dev, request_id);
+                               posted = 1;
+                               do_gettimeofday(&before);
 
+                       tw_ioctl_retry:
                                mdelay(TW_IOCTL_WAIT_TIME);
-                               spin_lock_irq(&tw_dev->tw_lock);
+                               if (test_bit(TW_IN_IOCTL, &tw_dev->flags)) {
+                                       do_gettimeofday(&timeout);
+                                       if (before.tv_sec + TW_IOCTL_TIMEOUT < timeout.tv_sec) {
+                                               spin_lock_irq(tw_dev->host->host_lock);
+                                               spin_lock(&tw_dev->tw_lock);
+                                               goto tw_ioctl_bail;
+                                       } else {
+                                               goto tw_ioctl_retry;
+                                       }
+                               }
+
                                spin_lock_irq(tw_dev->host->host_lock);
+                               spin_lock(&tw_dev->tw_lock);
 
                                if (signal_pending(current)) {
                                        dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
@@ -1697,7 +1730,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                                if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
                                                        error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
                                                        if (error) {
-                                                               printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
+                                                               dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
                                                                goto tw_ioctl_bail;
                                                        }
                                                        dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
@@ -1717,7 +1750,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                                        if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
                                                                error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
                                                                if (error) {
-                                                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
+                                                                       dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
                                                                        goto tw_ioctl_bail;
                                                                }
                                                                dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
@@ -1742,7 +1775,8 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
                                /* Now complete the io */
                                tw_dev->state[request_id] = TW_S_COMPLETED;
                                tw_state_request_finish(tw_dev, request_id);
-                               tw_dev->posted_request_count--;
+                               if (posted)
+                                       tw_dev->posted_request_count--;
                                tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
                                return 0;
                        } else {
@@ -1818,6 +1852,7 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
                        break;
                case TW_CMD_PACKET_WITH_DATA:
                        dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
+                       clear_bit(TW_IN_IOCTL, &tw_dev->flags);
                        return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
                default:
                        memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
@@ -2121,14 +2156,14 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
        for (i=0;i<TW_Q_LENGTH;i++) {
                if (tw_dev->srb[i] == SCpnt) {
                        if (tw_dev->state[i] == TW_S_STARTED) {
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt);
+                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
                                tw_dev->state[i] = TW_S_COMPLETED;
                                tw_state_request_finish(tw_dev, i);
                                spin_unlock(&tw_dev->tw_lock);
                                return (SUCCESS);
                        }
                        if (tw_dev->state[i] == TW_S_PENDING) {
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt);
+                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
                                if (tw_dev->pending_head == TW_Q_LENGTH-1) {
                                        tw_dev->pending_head = TW_Q_START;
                                } else {
@@ -2142,7 +2177,7 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
                        }
                        if (tw_dev->state[i] == TW_S_POSTED) {
                                /* If the command has already been posted, we have to reset the card */
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
+                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
                                /* We have to let AEN requests through before the reset */
                                spin_unlock(&tw_dev->tw_lock);
                                spin_unlock_irq(tw_dev->host->host_lock);
@@ -2360,6 +2395,11 @@ int tw_scsi_release(struct Scsi_Host *tw_host)
 
        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_release()\n");
 
+       /* Fake like we just shut down, so notify the card that
+        * we "shut down cleanly".
+        */
+       tw_halt(0, 0, 0);  // parameters aren't actually used
+
        /* Free up the IO region */
        release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 
@@ -2371,11 +2411,6 @@ int tw_scsi_release(struct Scsi_Host *tw_host)
 
        /* Tell kernel scsi-layer we are gone */
        scsi_unregister(tw_host);
-       
-       /* Fake like we just shut down, so notify the card that
-        * we "shut down cleanly".
-        */
-       tw_halt(0, 0, 0);  // parameters aren't actually used
 
        return 0;
 } /* End tw_scsi_release() */
index 37ae5521d0d9e223fd8c5f2f4e6ed2b6fc907b88..4dce8ea588e04a7011f1fbd1289eb9e69f8086c4 100644 (file)
 
 /* AEN strings */
 static char *tw_aen_string[] = {
-       "AEN queue empty",                      // 0x000
-       "Soft reset occurred",                  // 0x001
-       "Unit degraded: Unit #",                // 0x002
-       "Controller error",                     // 0x003 
-       "Rebuild failed: Unit #",               // 0x004
-       "Rebuild complete: Unit #",             // 0x005
-       "Incomplete unit detected: Unit #",     // 0x006
-       "Initialization complete: Unit #",      // 0x007
-       "Unclean shutdown detected: Unit #",    // 0x008
-       "ATA port timeout: Port #",             // 0x009
-       "Drive error: Port #",                  // 0x00A
-       "Rebuild started: Unit #",              // 0x00B 
-       "Initialization started: Unit #",       // 0x00C
-       "Logical unit deleted: Unit #",         // 0x00D
-       NULL,                                   // 0x00E unused
-       "SMART threshold exceeded: Port #",     // 0x00F
+       "INFO: AEN queue empty",                       // 0x000
+       "INFO: Soft reset occurred",                   // 0x001
+       "ERROR: Unit degraded: Unit #",                // 0x002
+       "ERROR: Controller error",                     // 0x003 
+       "ERROR: Rebuild failed: Unit #",               // 0x004
+       "INFO: Rebuild complete: Unit #",              // 0x005
+       "ERROR: Incomplete unit detected: Unit #",     // 0x006
+       "INFO: Initialization complete: Unit #",       // 0x007
+       "WARNING: Unclean shutdown detected: Unit #",  // 0x008
+       "WARNING: ATA port timeout: Port #",           // 0x009
+       "ERROR: Drive error: Port #",                  // 0x00A
+       "INFO: Rebuild started: Unit #",               // 0x00B 
+       "INFO: Initialization started: Unit #",        // 0x00C
+       "ERROR: Logical unit deleted: Unit #",         // 0x00D
+       NULL,                                          // 0x00E unused
+       "WARNING: SMART threshold exceeded: Port #",   // 0x00F
        NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL, NULL,
-       NULL, NULL,                             // 0x010-0x020 unused
-       "ATA UDMA downgrade: Port #",           // 0x021
-       "ATA UDMA upgrade: Port #",             // 0x022
-       "Sector repair occurred: Port #",       // 0x023
-       "SBUF integrity check failure",         // 0x024
-       "Lost cached write: Port #",            // 0x025
-       "Drive ECC error detected: Port #",     // 0x026
-       "DCB checksum error: Port #",           // 0x027
-       "DCB unsupported version: Port #",      // 0x028
-       "Verify started: Unit #",               // 0x029
-       "Verify failed: Port #",                // 0x02A
-       "Verify complete: Unit #",              // 0x02B
-       "Overwrote bad sector during rebuild: Port #",  //0x2C
-       "Encountered bad sector during rebuild: Port #", //0x2D
-       "Replacement drive is too small: Port #" //0x2E
+       NULL, NULL,                                    // 0x010-0x020 unused
+       "WARNING: ATA UDMA downgrade: Port #",         // 0x021
+       "WARNING: ATA UDMA upgrade: Port #",           // 0x022
+       "WARNING: Sector repair occurred: Port #",     // 0x023
+       "ERROR: SBUF integrity check failure",         // 0x024
+       "ERROR: Lost cached write: Port #",            // 0x025
+       "ERROR: Drive ECC error detected: Port #",     // 0x026
+       "ERROR: DCB checksum error: Port #",           // 0x027
+       "ERROR: DCB unsupported version: Port #",      // 0x028
+       "INFO: Verify started: Unit #",                // 0x029
+       "ERROR: Verify failed: Port #",                // 0x02A
+       "INFO: Verify complete: Unit #",               // 0x02B
+       "ERROR: Overwrote bad sector during rebuild: Port #",   //0x02C
+       "ERROR: Encountered bad sector during rebuild: Port #", //0x02D
+       "INFO: Replacement drive is too small: Port #",         //0x02E
+       "WARNING: Verify error: Unit not previously initialized: Unit #" //0x02F
 };
 
-#define TW_AEN_STRING_MAX                      0x02F
+#define TW_AEN_STRING_MAX                      0x030
 
 /*
    Sense key lookup table
@@ -225,11 +226,13 @@ static unsigned char tw_sense_table[][4] =
 #define TW_MAX_AEN_TRIES                      100
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
+#define TW_IN_IOCTL                           2
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
 #define TW_ISR_DONT_COMPLETE                  2
 #define TW_ISR_DONT_RESULT                    3
+#define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \