aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aacraid
diff options
context:
space:
mode:
authorSalyzyn, Mark <mark_salyzyn@adaptec.com>2007-12-13 19:14:18 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:28:07 -0500
commit94cf6ba11b068b8a8f68a1e88bffb6827e92124b (patch)
treec5ec05bb60248471ba9992c56dfeb1b44980d24b /drivers/scsi/aacraid
parent00f5970193e22c48f399a2430635d6416b51befe (diff)
[SCSI] aacraid: fix driver failure with Dell PowerEdge Expandable RAID Controller 3/Di
As reported in http://bugzilla.kernel.org/show_bug.cgi?id=3D9133 it was discovered that the PERC line of controllers lacked a key 64 bit ScatterGather capable SCSI pass-through function. The adapters are still capable of 64 bit ScatterGather I/O commands, but these two can not be mixed. This problem was exacerbated by the introduction of the SCSI Generic access to the DASD physical devices. The fix for users before this patch is applied is aacraid.dacmode=3D0 on the kernel command line to disable 64 bit I/O. The enclosed patch introduces a new adapter quirk and tries to limp along by enabling pass-through in situations where memory is 32 bit addressable on 64 bit machines, or disable the pass-through functions altogether. I expect that the check for 32 bit addressable memory to be controversial in that it can be incorrect in non-Dell non-Intel systems that PERC would never be installed under, the alternative is to disable pass-through in all cases which could be reported as another regression. Pass-through is used for SCSI Generic access to the physical devices, or for the management applications to properly function. In systems where this patch has disabled pass-through because it is unsupportable in combination with I/O performance, the user can choose to enable pass-through by turning off dacmode (aacraid.dacmode=3D0) or limiting the discovered kernel memory (mem=3D4G) with an associated loss in runtime performance. If we chose instead to turn off 64 bit dacmode for the adapters with this quirk, then this would be reported as another regression. Signed-off-by: Mark Salyzyn <aacraid@adaptec.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r--drivers/scsi/aacraid/aachba.c15
-rw-r--r--drivers/scsi/aacraid/aacraid.h6
-rw-r--r--drivers/scsi/aacraid/commsup.c6
-rw-r--r--drivers/scsi/aacraid/linit.c42
4 files changed, 47 insertions, 22 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 641c303d28ef..cef764eba307 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1190,6 +1190,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
1190 (fib_callback) aac_srb_callback, (void *) cmd); 1190 (fib_callback) aac_srb_callback, (void *) cmd);
1191} 1191}
1192 1192
1193static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
1194{
1195 if ((sizeof(dma_addr_t) > 4) &&
1196 (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
1197 (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
1198 return FAILED;
1199 return aac_scsi_32(fib, cmd);
1200}
1201
1193int aac_get_adapter_info(struct aac_dev* dev) 1202int aac_get_adapter_info(struct aac_dev* dev)
1194{ 1203{
1195 struct fib* fibptr; 1204 struct fib* fibptr;
@@ -1267,6 +1276,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
1267 1, 1, 1276 1, 1,
1268 NULL, NULL); 1277 NULL, NULL);
1269 1278
1279 /* reasoned default */
1280 dev->maximum_num_physicals = 16;
1270 if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) { 1281 if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
1271 dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus); 1282 dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
1272 dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); 1283 dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
@@ -1377,7 +1388,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
1377 * interface. 1388 * interface.
1378 */ 1389 */
1379 dev->a_ops.adapter_scsi = (dev->dac_support) 1390 dev->a_ops.adapter_scsi = (dev->dac_support)
1380 ? aac_scsi_64 1391 ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
1392 ? aac_scsi_32_64
1393 : aac_scsi_64)
1381 : aac_scsi_32; 1394 : aac_scsi_32;
1382 if (dev->raw_io_interface) { 1395 if (dev->raw_io_interface) {
1383 dev->a_ops.adapter_bounds = (dev->raw_io_64) 1396 dev->a_ops.adapter_bounds = (dev->raw_io_64)
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 9abba8b90f70..734623af9c45 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -521,6 +521,12 @@ struct aac_driver_ident
521#define AAC_QUIRK_17SG 0x0010 521#define AAC_QUIRK_17SG 0x0010
522 522
523/* 523/*
524 * Some adapter firmware does not support 64 bit scsi passthrough
525 * commands.
526 */
527#define AAC_QUIRK_SCSI_32 0x0020
528
529/*
524 * The adapter interface specs all queues to be located in the same 530 * The adapter interface specs all queues to be located in the same
525 * physically contigous block. The host structure that defines the 531 * physically contigous block. The host structure that defines the
526 * commuication queues will assume they are each a separate physically 532 * commuication queues will assume they are each a separate physically
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 310fd80b8c06..53d415e812ee 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1099,7 +1099,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
1099 free_irq(aac->pdev->irq, aac); 1099 free_irq(aac->pdev->irq, aac);
1100 kfree(aac->fsa_dev); 1100 kfree(aac->fsa_dev);
1101 aac->fsa_dev = NULL; 1101 aac->fsa_dev = NULL;
1102 if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) { 1102 quirks = aac_get_driver_ident(index)->quirks;
1103 if (quirks & AAC_QUIRK_31BIT) {
1103 if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) || 1104 if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
1104 ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK)))) 1105 ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
1105 goto out; 1106 goto out;
@@ -1110,7 +1111,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
1110 } 1111 }
1111 if ((retval = (*(aac_get_driver_ident(index)->init))(aac))) 1112 if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
1112 goto out; 1113 goto out;
1113 if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) 1114 if (quirks & AAC_QUIRK_31BIT)
1114 if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) 1115 if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
1115 goto out; 1116 goto out;
1116 if (jafo) { 1117 if (jafo) {
@@ -1121,7 +1122,6 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
1121 } 1122 }
1122 } 1123 }
1123 (void)aac_get_adapter_info(aac); 1124 (void)aac_get_adapter_info(aac);
1124 quirks = aac_get_driver_ident(index)->quirks;
1125 if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) { 1125 if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
1126 host->sg_tablesize = 34; 1126 host->sg_tablesize = 34;
1127 host->max_sectors = (host->sg_tablesize * 8) + 112; 1127 host->max_sectors = (host->sg_tablesize * 8) + 112;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 782fae83ab48..b4ad9effcf50 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -164,22 +164,22 @@ MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
164 * for the card. At that time we can remove the channels from here 164 * for the card. At that time we can remove the channels from here
165 */ 165 */
166static struct aac_driver_ident aac_drivers[] = { 166static struct aac_driver_ident aac_drivers[] = {
167 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */ 167 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */
168 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */ 168 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */
169 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */ 169 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */
170 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ 170 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
171 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */ 171 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */
172 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */ 172 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */
173 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ 173 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
174 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */ 174 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */
175 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */ 175 { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */
176 { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */ 176 { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */
177 { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */ 177 { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */
178 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */ 178 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */
179 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */ 179 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */
180 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */ 180 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */
181 { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */ 181 { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */
182 { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */ 182 { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */
183 183
184 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ 184 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */
185 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ 185 { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */
@@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = {
224 { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */ 224 { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
225 { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ 225 { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
226 226
227 { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ 227 { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */
228 { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ 228 { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
229 { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ 229 { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */
230 { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ 230 { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */
231 { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ 231 { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */
@@ -420,6 +420,12 @@ static int aac_slave_configure(struct scsi_device *sdev)
420 unsigned num_one = 0; 420 unsigned num_one = 0;
421 unsigned depth; 421 unsigned depth;
422 422
423 /*
424 * Firmware has an individual device recovery time typically
425 * of 35 seconds, give us a margin.
426 */
427 if (sdev->timeout < (45 * HZ))
428 sdev->timeout = 45 * HZ;
423 __shost_for_each_device(dev, host) { 429 __shost_for_each_device(dev, host) {
424 if (dev->tagged_supported && (dev->type == TYPE_DISK) && 430 if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
425 (sdev_channel(dev) == CONTAINER_CHANNEL)) 431 (sdev_channel(dev) == CONTAINER_CHANNEL))