3ware 9000 driver update for scsi-misc-2.6
adam radford
maintainerPATCH 1/1 3ware 9000 driver update for scsi-misc-2.6
The attached patch updates the driver for the 3ware 9000 series to do the following:
- Add support for 9550SX controllers.
James, Please apply
Thanks!
Note: The patch is attached as an attachment, and also included
in-line below. The below may have line-wrap issues since I'm pasting
into gmail.
diff -Naur scsi-misc-2.6.old/drivers/scsi/3w-9xxx.c scsi-misc-2.6.new/drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.c +12 -6
@@ -60,6 +60,7 @@Remove un-needed eh_abort handler. Add support for embedded firmware error strings. 2.26.02.003 - Correctly handle single sgl's with use_sg=1. +2.26.02.004 - Add support for 9550SX controllers. */ #include <linux/module.h>
@@ -82,7 +83,7 @@#include "3w-9xxx.h" /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.003" +#define TW_DRIVER_VERSION "2.26.02.004"static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT ];static unsigned int twa_device_extension_count;static int twa_major =-1 ;
@@ -892,11 +893,6 @@writel (TW_CONTROL_CLEAR_QUEUE_ERROR ,TW_CONTROL_REG_ADDR (tw_dev)); } -if (status_reg_value &TW_STATUS_SBUF_WRITE_ERROR ) { -TW_PRINTK (tw_dev->host,TW_DRIVER ,0xf ,"SBUF Write Error: clearing" ); -writel (TW_CONTROL_CLEAR_SBUF_WRITE_ERROR ,TW_CONTROL_REG_ADDR (tw_dev)); - } -if (status_reg_value &TW_STATUS_MICROCONTROLLER_ERROR ) {if (tw_dev->reset_print ==0 ) {TW_PRINTK (tw_dev->host,TW_DRIVER ,0x10 ,"Microcontroller Error: clearing" );
@@ -930,6 +926,36 @@return retval; }/* End twa_empty_response_queue() */ +/* This function will clear the pchip/response queue on 9550SX */ +static int twa_empty_response_queue_large (TW_Device_Extension *tw_dev) +{ +u32 status_reg_value, response_que_value; +int count =0 , retval =1 ; + +if (tw_dev->tw_pci_dev->device ==PCI_DEVICE_ID_3WARE_9550SX ) { + status_reg_value =readl (TW_STATUS_REG_ADDR (tw_dev)); + + while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0)
&& (count < TW_MAX_RESPONSE_DRAIN)) {
+ response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
+ if ((response_que_value & TW_9550SX_DRAIN_COMPLETED) ==TW_9550SX_DRAIN_COMPLETED) {
+ /* P-chip settle time */
+ msleep(500);
+ retval = 0;
+ goto out;
+ }
+ status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+ count++;
+ }
+ if (count == TW_MAX_RESPONSE_DRAIN)
+ goto out;
+
+ retval = 0;
+ } else
+ retval = 0;
+out:
+ return retval;
+} /* End twa_empty_response_queue_large() */
+
/* This function passes sense keys from firmware to scsi layer */ static int twa_fill_sense(TW_Device_Extension *tw_dev, intrequest_id, int copy_sense, int print_host)
{
@@ -1613,8 +1639,16 @@
int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
while (tries < TW_MAX_RESET_TRIES) {
- if (do_soft_reset)
+ if (do_soft_reset) {
TW_SOFT_RESET(tw_dev);
+ /* Clear pchip/response queue on 9550SX */
+ if (twa_empty_response_queue_large(tw_dev)) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large)
empty failed during reset sequence");
+ do_soft_reset = 1;
+ tries++;
+ continue;
+ }
+ }
/* Make sure controller is in a good state */
if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY |
(do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) { @@ -2034,7 +2068,10 @@
goto out_free_device_extension;
}
- mem_addr = pci_resource_start(pdev, 1);
+ if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
+ mem_addr = pci_resource_start(pdev, 1);
+ else
+ mem_addr = pci_resource_start(pdev, 2);
/* Save base address */
tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
@@ -2148,6 +2185,8 @@
static struct pci_device_id twa_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff -Naur scsi-misc-2.6.old/drivers/scsi/3w-9xxx.h scsi-misc-2.6.new/drivers/scsi/3w-9xxx.h
drivers/scsi/3w-9xxx.h +9 -7
@@ -267,7 +267,6 @@#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 -#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008/* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000
@@ -285,9 +284,8 @@#define TW_STATUS_MICROCONTROLLER_READY 0x00002000#define TW_STATUS_COMMAND_QUEUE_EMPTY 0x00001000#define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 -#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 -#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 +#define TW_STATUS_UNEXPECTED_BITS 0x00F00000 +#define TW_STATUS_VALID_INTERRUPT 0x00DF0000/* RESPONSE QUEUE BIT DEFINITIONS */ #define TW_RESPONSE_ID_MASK 0x00000FF0
@@ -324,9 +322,9 @@/* Compatibility defines */ #define TW_9000_ARCH_ID 0x5 -#define TW_CURRENT_DRIVER_SRL 28 -#define TW_CURRENT_DRIVER_BUILD 9 -#define TW_CURRENT_DRIVER_BRANCH 4 +#define TW_CURRENT_DRIVER_SRL 30 +#define TW_CURRENT_DRIVER_BUILD 80 +#define TW_CURRENT_DRIVER_BRANCH 0/* Phase defines */ #define TW_PHASE_INITIAL 0
@@ -334,6 +332,7 @@#define TW_PHASE_SGLIST 2/* Misc defines */ +#define TW_9550SX_DRAIN_COMPLETED 0xFFFF#define TW_SECTOR_SIZE 512#define TW_ALIGNMENT_9000 4/* 4 bytes */ #define TW_ALIGNMENT_9000_SGL 0x3
@@ -417,6 +416,9 @@#ifndef PCI_DEVICE_ID_3WARE_9000 #define PCI_DEVICE_ID_3WARE_9000 0x1002#endif +#ifndef PCI_DEVICE_ID_3WARE_9550SX +#define PCI_DEVICE_ID_3WARE_9550SX 0x1003 +#endif /* Bitmask macros to eliminate bitfields */
@@ -443,6 +445,7 @@#define TW_STATUS_REG_ADDR (x) ((unsigned char __iomem *)x->base_addr + 0x4)#define TW_COMMAND_QUEUE_REG_ADDR (x) (sizeof(dma_addr_t) > 4 ?
((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem
*)x->base_addr + 0xC)
+#define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30)
#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT,TW_CONTROL_REG_ADDR(x)))
#define TW_CLEAR_ATTENTION_INTERRUPT(x)
(writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
#define TW_CLEAR_HOST_INTERRUPT(x)
(writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
drivers/scsi/3w-9xxx.c +47 -8
98 lines not on this page · raw message
drivers/scsi/3w-9xxx.h +10 -7
@@ -267,7 +267,6 @@#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 -#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008/* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000
@@ -285,9 +284,8 @@#define TW_STATUS_MICROCONTROLLER_READY 0x00002000#define TW_STATUS_COMMAND_QUEUE_EMPTY 0x00001000#define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 -#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 -#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 +#define TW_STATUS_UNEXPECTED_BITS 0x00F00000 +#define TW_STATUS_VALID_INTERRUPT 0x00DF0000/* RESPONSE QUEUE BIT DEFINITIONS */ #define TW_RESPONSE_ID_MASK 0x00000FF0
@@ -324,9 +322,9 @@/* Compatibility defines */ #define TW_9000_ARCH_ID 0x5 -#define TW_CURRENT_DRIVER_SRL 28 -#define TW_CURRENT_DRIVER_BUILD 9 -#define TW_CURRENT_DRIVER_BRANCH 4 +#define TW_CURRENT_DRIVER_SRL 30 +#define TW_CURRENT_DRIVER_BUILD 80 +#define TW_CURRENT_DRIVER_BRANCH 0/* Phase defines */ #define TW_PHASE_INITIAL 0
@@ -334,6 +332,7 @@#define TW_PHASE_SGLIST 2/* Misc defines */ +#define TW_9550SX_DRAIN_COMPLETED 0xFFFF#define TW_SECTOR_SIZE 512#define TW_ALIGNMENT_9000 4/* 4 bytes */ #define TW_ALIGNMENT_9000_SGL 0x3
@@ -417,6 +416,9 @@#ifndef PCI_DEVICE_ID_3WARE_9000 #define PCI_DEVICE_ID_3WARE_9000 0x1002#endif +#ifndef PCI_DEVICE_ID_3WARE_9550SX +#define PCI_DEVICE_ID_3WARE_9550SX 0x1003 +#endif /* Bitmask macros to eliminate bitfields */
@@ -443,6 +445,7 @@#define TW_STATUS_REG_ADDR (x) ((unsigned char __iomem *)x->base_addr + 0x4)#define TW_COMMAND_QUEUE_REG_ADDR (x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))#define TW_RESPONSE_QUEUE_REG_ADDR (x) ((unsigned char __iomem *)x->base_addr + 0xC) +#define TW_RESPONSE_QUEUE_REG_ADDR_LARGE (x) ((unsigned char __iomem *)x->base_addr + 0x30)#define TW_CLEAR_ALL_INTERRUPTS (x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))#define TW_CLEAR_ATTENTION_INTERRUPT (x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))#define TW_CLEAR_HOST_INTERRUPT (x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))