diff options
author | adam radford <aradford@gmail.com> | 2007-07-20 18:28:28 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-07-21 09:57:40 -0400 |
commit | 0e78d158b67fba3977f577f293c323359d80dd0e (patch) | |
tree | 539065fd92feb757e548891dbe29c481df091075 /drivers/scsi/3w-9xxx.c | |
parent | 6826ee4fdbe24c7aab56ce833ef94be81d190587 (diff) |
[SCSI] 3w-9xxx: add support for 9690SA
The attached patch updates the 3ware 9000 driver:
- Fix dma mask setting to fallback to 32-bit if 64-bit fails.
- Add support for 9690SA controllers.
Signed-off-by: Adam Radford <linuxraid@amcc.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/3w-9xxx.c')
-rw-r--r-- | drivers/scsi/3w-9xxx.c | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 76c09097175f..fcad9fd73971 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c | |||
@@ -4,7 +4,7 @@ | |||
4 | Written By: Adam Radford <linuxraid@amcc.com> | 4 | Written By: Adam Radford <linuxraid@amcc.com> |
5 | Modifications By: Tom Couch <linuxraid@amcc.com> | 5 | Modifications By: Tom Couch <linuxraid@amcc.com> |
6 | 6 | ||
7 | Copyright (C) 2004-2006 Applied Micro Circuits Corporation. | 7 | Copyright (C) 2004-2007 Applied Micro Circuits Corporation. |
8 | 8 | ||
9 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
10 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
@@ -69,6 +69,8 @@ | |||
69 | 2.26.02.008 - Free irq handler in __twa_shutdown(). | 69 | 2.26.02.008 - Free irq handler in __twa_shutdown(). |
70 | Serialize reset code. | 70 | Serialize reset code. |
71 | Add support for 9650SE controllers. | 71 | Add support for 9650SE controllers. |
72 | 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails. | ||
73 | 2.26.02.010 - Add support for 9690SA controllers. | ||
72 | */ | 74 | */ |
73 | 75 | ||
74 | #include <linux/module.h> | 76 | #include <linux/module.h> |
@@ -92,7 +94,7 @@ | |||
92 | #include "3w-9xxx.h" | 94 | #include "3w-9xxx.h" |
93 | 95 | ||
94 | /* Globals */ | 96 | /* Globals */ |
95 | #define TW_DRIVER_VERSION "2.26.02.008" | 97 | #define TW_DRIVER_VERSION "2.26.02.010" |
96 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; | 98 | static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; |
97 | static unsigned int twa_device_extension_count; | 99 | static unsigned int twa_device_extension_count; |
98 | static int twa_major = -1; | 100 | static int twa_major = -1; |
@@ -124,11 +126,11 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, | |||
124 | unsigned short *fw_on_ctlr_branch, | 126 | unsigned short *fw_on_ctlr_branch, |
125 | unsigned short *fw_on_ctlr_build, | 127 | unsigned short *fw_on_ctlr_build, |
126 | u32 *init_connect_result); | 128 | u32 *init_connect_result); |
127 | static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length); | 129 | static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length); |
128 | static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds); | 130 | static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds); |
129 | static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds); | 131 | static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds); |
130 | static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal); | 132 | static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal); |
131 | static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); | 133 | static int twa_reset_device_extension(TW_Device_Extension *tw_dev); |
132 | static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); | 134 | static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); |
133 | static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); | 135 | static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); |
134 | static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); | 136 | static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); |
@@ -683,7 +685,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int | |||
683 | full_command_packet = &tw_ioctl->firmware_command; | 685 | full_command_packet = &tw_ioctl->firmware_command; |
684 | 686 | ||
685 | /* Load request id and sglist for both command types */ | 687 | /* Load request id and sglist for both command types */ |
686 | twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); | 688 | twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); |
687 | 689 | ||
688 | memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); | 690 | memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); |
689 | 691 | ||
@@ -700,10 +702,10 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int | |||
700 | if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { | 702 | if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { |
701 | /* Now we need to reset the board */ | 703 | /* Now we need to reset the board */ |
702 | printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", | 704 | printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", |
703 | tw_dev->host->host_no, TW_DRIVER, 0xc, | 705 | tw_dev->host->host_no, TW_DRIVER, 0x37, |
704 | cmd); | 706 | cmd); |
705 | retval = TW_IOCTL_ERROR_OS_EIO; | 707 | retval = TW_IOCTL_ERROR_OS_EIO; |
706 | twa_reset_device_extension(tw_dev, 1); | 708 | twa_reset_device_extension(tw_dev); |
707 | goto out3; | 709 | goto out3; |
708 | } | 710 | } |
709 | 711 | ||
@@ -890,7 +892,9 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) | |||
890 | } | 892 | } |
891 | 893 | ||
892 | if (status_reg_value & TW_STATUS_QUEUE_ERROR) { | 894 | if (status_reg_value & TW_STATUS_QUEUE_ERROR) { |
893 | if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags))) | 895 | if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) && |
896 | (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) || | ||
897 | (!test_bit(TW_IN_RESET, &tw_dev->flags))) | ||
894 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); | 898 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); |
895 | writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); | 899 | writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); |
896 | } | 900 | } |
@@ -935,8 +939,7 @@ static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev) | |||
935 | unsigned long before; | 939 | unsigned long before; |
936 | int retval = 1; | 940 | int retval = 1; |
937 | 941 | ||
938 | if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) || | 942 | if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) { |
939 | (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) { | ||
940 | before = jiffies; | 943 | before = jiffies; |
941 | while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) { | 944 | while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) { |
942 | response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev)); | 945 | response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev)); |
@@ -1196,7 +1199,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) | |||
1196 | u32 status_reg_value; | 1199 | u32 status_reg_value; |
1197 | TW_Response_Queue response_que; | 1200 | TW_Response_Queue response_que; |
1198 | TW_Command_Full *full_command_packet; | 1201 | TW_Command_Full *full_command_packet; |
1199 | TW_Command *command_packet; | ||
1200 | TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; | 1202 | TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; |
1201 | int handled = 0; | 1203 | int handled = 0; |
1202 | 1204 | ||
@@ -1274,7 +1276,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) | |||
1274 | request_id = TW_RESID_OUT(response_que.response_id); | 1276 | request_id = TW_RESID_OUT(response_que.response_id); |
1275 | full_command_packet = tw_dev->command_packet_virt[request_id]; | 1277 | full_command_packet = tw_dev->command_packet_virt[request_id]; |
1276 | error = 0; | 1278 | error = 0; |
1277 | command_packet = &full_command_packet->command.oldcommand; | ||
1278 | /* Check for command packet errors */ | 1279 | /* Check for command packet errors */ |
1279 | if (full_command_packet->command.newcommand.status != 0) { | 1280 | if (full_command_packet->command.newcommand.status != 0) { |
1280 | if (tw_dev->srb[request_id] != 0) { | 1281 | if (tw_dev->srb[request_id] != 0) { |
@@ -1353,11 +1354,15 @@ twa_interrupt_bail: | |||
1353 | } /* End twa_interrupt() */ | 1354 | } /* End twa_interrupt() */ |
1354 | 1355 | ||
1355 | /* This function will load the request id and various sgls for ioctls */ | 1356 | /* This function will load the request id and various sgls for ioctls */ |
1356 | static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) | 1357 | static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) |
1357 | { | 1358 | { |
1358 | TW_Command *oldcommand; | 1359 | TW_Command *oldcommand; |
1359 | TW_Command_Apache *newcommand; | 1360 | TW_Command_Apache *newcommand; |
1360 | TW_SG_Entry *sgl; | 1361 | TW_SG_Entry *sgl; |
1362 | unsigned int pae = 0; | ||
1363 | |||
1364 | if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) | ||
1365 | pae = 1; | ||
1361 | 1366 | ||
1362 | if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { | 1367 | if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { |
1363 | newcommand = &full_command_packet->command.newcommand; | 1368 | newcommand = &full_command_packet->command.newcommand; |
@@ -1373,12 +1378,14 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d | |||
1373 | 1378 | ||
1374 | if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { | 1379 | if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { |
1375 | /* Load the sg list */ | 1380 | /* Load the sg list */ |
1376 | sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); | 1381 | if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA) |
1382 | sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae); | ||
1383 | else | ||
1384 | sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); | ||
1377 | sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); | 1385 | sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); |
1378 | sgl->length = cpu_to_le32(length); | 1386 | sgl->length = cpu_to_le32(length); |
1379 | 1387 | ||
1380 | if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) | 1388 | oldcommand->size += pae; |
1381 | oldcommand->size += 1; | ||
1382 | } | 1389 | } |
1383 | } | 1390 | } |
1384 | } /* End twa_load_sgl() */ | 1391 | } /* End twa_load_sgl() */ |
@@ -1507,7 +1514,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, | |||
1507 | command_que_value = tw_dev->command_packet_phys[request_id]; | 1514 | command_que_value = tw_dev->command_packet_phys[request_id]; |
1508 | 1515 | ||
1509 | /* For 9650SE write low 4 bytes first */ | 1516 | /* For 9650SE write low 4 bytes first */ |
1510 | if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { | 1517 | if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) || |
1518 | (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) { | ||
1511 | command_que_value += TW_COMMAND_OFFSET; | 1519 | command_que_value += TW_COMMAND_OFFSET; |
1512 | writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev)); | 1520 | writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev)); |
1513 | } | 1521 | } |
@@ -1538,7 +1546,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, | |||
1538 | TW_UNMASK_COMMAND_INTERRUPT(tw_dev); | 1546 | TW_UNMASK_COMMAND_INTERRUPT(tw_dev); |
1539 | goto out; | 1547 | goto out; |
1540 | } else { | 1548 | } else { |
1541 | if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) { | 1549 | if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) || |
1550 | (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) { | ||
1542 | /* Now write upper 4 bytes */ | 1551 | /* Now write upper 4 bytes */ |
1543 | writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4); | 1552 | writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4); |
1544 | } else { | 1553 | } else { |
@@ -1562,7 +1571,7 @@ out: | |||
1562 | } /* End twa_post_command_packet() */ | 1571 | } /* End twa_post_command_packet() */ |
1563 | 1572 | ||
1564 | /* This function will reset a device extension */ | 1573 | /* This function will reset a device extension */ |
1565 | static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) | 1574 | static int twa_reset_device_extension(TW_Device_Extension *tw_dev) |
1566 | { | 1575 | { |
1567 | int i = 0; | 1576 | int i = 0; |
1568 | int retval = 1; | 1577 | int retval = 1; |
@@ -1720,7 +1729,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) | |||
1720 | mutex_lock(&tw_dev->ioctl_lock); | 1729 | mutex_lock(&tw_dev->ioctl_lock); |
1721 | 1730 | ||
1722 | /* Now reset the card and some of the device extension data */ | 1731 | /* Now reset the card and some of the device extension data */ |
1723 | if (twa_reset_device_extension(tw_dev, 0)) { | 1732 | if (twa_reset_device_extension(tw_dev)) { |
1724 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); | 1733 | TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); |
1725 | goto out; | 1734 | goto out; |
1726 | } | 1735 | } |
@@ -2002,11 +2011,14 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
2002 | 2011 | ||
2003 | pci_set_master(pdev); | 2012 | pci_set_master(pdev); |
2004 | 2013 | ||
2005 | retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK); | 2014 | if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) |
2006 | if (retval) { | 2015 | || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) |
2007 | TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); | 2016 | if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) |
2008 | goto out_disable_device; | 2017 | || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { |
2009 | } | 2018 | TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); |
2019 | retval = -ENODEV; | ||
2020 | goto out_disable_device; | ||
2021 | } | ||
2010 | 2022 | ||
2011 | host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); | 2023 | host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); |
2012 | if (!host) { | 2024 | if (!host) { |
@@ -2054,7 +2066,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id | |||
2054 | goto out_iounmap; | 2066 | goto out_iounmap; |
2055 | 2067 | ||
2056 | /* Set host specific parameters */ | 2068 | /* Set host specific parameters */ |
2057 | if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE) | 2069 | if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || |
2070 | (pdev->device == PCI_DEVICE_ID_3WARE_9690SA)) | ||
2058 | host->max_id = TW_MAX_UNITS_9650SE; | 2071 | host->max_id = TW_MAX_UNITS_9650SE; |
2059 | else | 2072 | else |
2060 | host->max_id = TW_MAX_UNITS; | 2073 | host->max_id = TW_MAX_UNITS; |
@@ -2161,6 +2174,8 @@ static struct pci_device_id twa_pci_tbl[] __devinitdata = { | |||
2161 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 2174 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
2162 | { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE, | 2175 | { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE, |
2163 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 2176 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
2177 | { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA, | ||
2178 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
2164 | { } | 2179 | { } |
2165 | }; | 2180 | }; |
2166 | MODULE_DEVICE_TABLE(pci, twa_pci_tbl); | 2181 | MODULE_DEVICE_TABLE(pci, twa_pci_tbl); |