diff options
| author | Dave Jones <davej@suse.de> | 2002-06-19 22:15:50 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-06-19 22:15:50 -0700 |
| commit | 518a6e8714d310f406a02714a67134be7bbda09d (patch) | |
| tree | d7d495afdbbb23381d926b36d9aec72cd6a421ce | |
| parent | 6eb57548cf00b1b96cc7e200cbde338484eee452 (diff) | |
[PATCH] udpated 3ware driver from vendor.
| -rw-r--r-- | drivers/scsi/3w-xxxx.c | 83 | ||||
| -rw-r--r-- | drivers/scsi/3w-xxxx.h | 67 |
2 files changed, 94 insertions, 56 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index c7ccb6c0ad21..87b883e6107f 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -141,12 +141,23 @@ 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() */ diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 37ae5521d0d9..4dce8ea588e0 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -60,43 +60,44 @@ /* 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) \ |
