aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aacraid/linit.c
diff options
context:
space:
mode:
authorMark Haverkamp <markh@linux-foundation.org>2007-03-15 13:27:45 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-03-20 11:56:03 -0400
commit03d4433721880bf1972c924b168e4e1dd3c59d53 (patch)
tree820ad2f8aea551d03e7ff8751aba7dfe1f674bcd /drivers/scsi/aacraid/linit.c
parentf2b1a06ad46209c6e631e3099138d1fa3f14d3a8 (diff)
[SCSI] aacraid: Improved error handling
Received from Mark Salyzyn, This set of fixes improve error handling stability of the driver. A popular manifestation of the problems is an NULL pointer reference in the interrupt handler when referencing portions of the scsi command context, or in the scsi_done handling when an offlined device is referenced. The aacraid driver currently does not get notification of orphaned command completions due to devices going offline. The driver also fails to handle the commands that are finished by the error handler, and thus can complete again later at the hands of the adapter causing situations of completion of an invalid scsi command context. Test Unit Ready calls abort assuming that the abort was successful, but are not, and thus when the interrupt from the adapter occurs, they reference invalid command contexts. We add in a TIMED_OUT flag to inform the aacraid FIB context that the interrupt service should merely release the driver resources and not complete the command up. We take advantage of this with the abort handler as well for select abortable commands. And we detect and react if a command that can not be aborted is currently still outstanding to the controller when reissued by the retry mechanism. Signed-off-by: Mark Haverkamp <markh@linux-foundation.org> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/linit.c')
-rw-r--r--drivers/scsi/aacraid/linit.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 0f948c2fb609..3cf3f6472e94 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -5,7 +5,7 @@
5 * based on the old aacraid driver that is.. 5 * based on the old aacraid driver that is..
6 * Adaptec aacraid device driver for Linux. 6 * Adaptec aacraid device driver for Linux.
7 * 7 *
8 * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) 8 * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
@@ -247,6 +247,19 @@ static struct aac_driver_ident aac_drivers[] = {
247 247
248static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) 248static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
249{ 249{
250 struct Scsi_Host *host = cmd->device->host;
251 struct aac_dev *dev = (struct aac_dev *)host->hostdata;
252 u32 count = 0;
253 cmd->scsi_done = done;
254 for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
255 struct fib * fib = &dev->fibs[count];
256 struct scsi_cmnd * command;
257 if (fib->hw_fib_va->header.XferState &&
258 ((command = fib->callback_data)) &&
259 (command == cmd) &&
260 (cmd->SCp.phase == AAC_OWNER_FIRMWARE))
261 return 0; /* Already owned by Adapter */
262 }
250 cmd->scsi_done = done; 263 cmd->scsi_done = done;
251 cmd->SCp.phase = AAC_OWNER_LOWLEVEL; 264 cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
252 return (aac_scsi_cmd(cmd) ? FAILED : 0); 265 return (aac_scsi_cmd(cmd) ? FAILED : 0);
@@ -446,6 +459,40 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
446 return aac_do_ioctl(dev, cmd, arg); 459 return aac_do_ioctl(dev, cmd, arg);
447} 460}
448 461
462static int aac_eh_abort(struct scsi_cmnd* cmd)
463{
464 struct Scsi_Host * host = cmd->device->host;
465 struct aac_dev * aac = (struct aac_dev *)host->hostdata;
466 int count;
467 int ret = FAILED;
468
469 printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n",
470 AAC_DRIVERNAME,
471 cmd->device->host->host_no, sdev_channel(cmd->device),
472 sdev_id(cmd->device), cmd->device->lun);
473 switch (cmd->cmnd[0]) {
474 case SERVICE_ACTION_IN:
475 if (!(aac->raw_io_interface) ||
476 !(aac->raw_io_64) ||
477 ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
478 break;
479 case INQUIRY:
480 case READ_CAPACITY:
481 case TEST_UNIT_READY:
482 /* Mark associated FIB to not complete, eh handler does this */
483 for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
484 struct fib * fib = &aac->fibs[count];
485 if (fib->hw_fib_va->header.XferState &&
486 (fib->callback_data == cmd)) {
487 fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
488 cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
489 ret = SUCCESS;
490 }
491 }
492 }
493 return ret;
494}
495
449/* 496/*
450 * aac_eh_reset - Reset command handling 497 * aac_eh_reset - Reset command handling
451 * @scsi_cmd: SCSI command block causing the reset 498 * @scsi_cmd: SCSI command block causing the reset
@@ -457,12 +504,20 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
457 struct Scsi_Host * host = dev->host; 504 struct Scsi_Host * host = dev->host;
458 struct scsi_cmnd * command; 505 struct scsi_cmnd * command;
459 int count; 506 int count;
460 struct aac_dev * aac; 507 struct aac_dev * aac = (struct aac_dev *)host->hostdata;
461 unsigned long flags; 508 unsigned long flags;
462 509
510 /* Mark the associated FIB to not complete, eh handler does this */
511 for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
512 struct fib * fib = &aac->fibs[count];
513 if (fib->hw_fib_va->header.XferState &&
514 (fib->callback_data == cmd)) {
515 fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
516 cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
517 }
518 }
463 printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 519 printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
464 AAC_DRIVERNAME); 520 AAC_DRIVERNAME);
465 aac = (struct aac_dev *)host->hostdata;
466 521
467 if ((count = aac_check_health(aac))) 522 if ((count = aac_check_health(aac)))
468 return count; 523 return count;
@@ -496,7 +551,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
496 ssleep(1); 551 ssleep(1);
497 } 552 }
498 printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); 553 printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
499 return -ETIMEDOUT; 554 return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
500} 555}
501 556
502/** 557/**
@@ -796,6 +851,7 @@ static struct scsi_host_template aac_driver_template = {
796 .bios_param = aac_biosparm, 851 .bios_param = aac_biosparm,
797 .shost_attrs = aac_attrs, 852 .shost_attrs = aac_attrs,
798 .slave_configure = aac_slave_configure, 853 .slave_configure = aac_slave_configure,
854 .eh_abort_handler = aac_eh_abort,
799 .eh_host_reset_handler = aac_eh_reset, 855 .eh_host_reset_handler = aac_eh_reset,
800 .can_queue = AAC_NUM_IO_FIB, 856 .can_queue = AAC_NUM_IO_FIB,
801 .this_id = MAXIMUM_NUM_CONTAINERS, 857 .this_id = MAXIMUM_NUM_CONTAINERS,