diff options
Diffstat (limited to 'drivers/scsi/aacraid/linit.c')
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 0f948c2fb609..350ea7feb61d 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 |
@@ -82,8 +82,6 @@ static LIST_HEAD(aac_devices); | |||
82 | static int aac_cfg_major = -1; | 82 | static int aac_cfg_major = -1; |
83 | char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; | 83 | char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; |
84 | 84 | ||
85 | extern int expose_physicals; | ||
86 | |||
87 | /* | 85 | /* |
88 | * Because of the way Linux names scsi devices, the order in this table has | 86 | * Because of the way Linux names scsi devices, the order in this table has |
89 | * become important. Check for on-board Raid first, add-in cards second. | 87 | * become important. Check for on-board Raid first, add-in cards second. |
@@ -247,7 +245,19 @@ static struct aac_driver_ident aac_drivers[] = { | |||
247 | 245 | ||
248 | static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | 246 | static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) |
249 | { | 247 | { |
248 | struct Scsi_Host *host = cmd->device->host; | ||
249 | struct aac_dev *dev = (struct aac_dev *)host->hostdata; | ||
250 | u32 count = 0; | ||
250 | cmd->scsi_done = done; | 251 | cmd->scsi_done = done; |
252 | for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { | ||
253 | struct fib * fib = &dev->fibs[count]; | ||
254 | struct scsi_cmnd * command; | ||
255 | if (fib->hw_fib_va->header.XferState && | ||
256 | ((command = fib->callback_data)) && | ||
257 | (command == cmd) && | ||
258 | (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) | ||
259 | return 0; /* Already owned by Adapter */ | ||
260 | } | ||
251 | cmd->SCp.phase = AAC_OWNER_LOWLEVEL; | 261 | cmd->SCp.phase = AAC_OWNER_LOWLEVEL; |
252 | return (aac_scsi_cmd(cmd) ? FAILED : 0); | 262 | return (aac_scsi_cmd(cmd) ? FAILED : 0); |
253 | } | 263 | } |
@@ -446,6 +456,40 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) | |||
446 | return aac_do_ioctl(dev, cmd, arg); | 456 | return aac_do_ioctl(dev, cmd, arg); |
447 | } | 457 | } |
448 | 458 | ||
459 | static int aac_eh_abort(struct scsi_cmnd* cmd) | ||
460 | { | ||
461 | struct scsi_device * dev = cmd->device; | ||
462 | struct Scsi_Host * host = dev->host; | ||
463 | struct aac_dev * aac = (struct aac_dev *)host->hostdata; | ||
464 | int count; | ||
465 | int ret = FAILED; | ||
466 | |||
467 | printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n", | ||
468 | AAC_DRIVERNAME, | ||
469 | host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun); | ||
470 | switch (cmd->cmnd[0]) { | ||
471 | case SERVICE_ACTION_IN: | ||
472 | if (!(aac->raw_io_interface) || | ||
473 | !(aac->raw_io_64) || | ||
474 | ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) | ||
475 | break; | ||
476 | case INQUIRY: | ||
477 | case READ_CAPACITY: | ||
478 | case TEST_UNIT_READY: | ||
479 | /* Mark associated FIB to not complete, eh handler does this */ | ||
480 | for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { | ||
481 | struct fib * fib = &aac->fibs[count]; | ||
482 | if (fib->hw_fib_va->header.XferState && | ||
483 | (fib->callback_data == cmd)) { | ||
484 | fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; | ||
485 | cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; | ||
486 | ret = SUCCESS; | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | return ret; | ||
491 | } | ||
492 | |||
449 | /* | 493 | /* |
450 | * aac_eh_reset - Reset command handling | 494 | * aac_eh_reset - Reset command handling |
451 | * @scsi_cmd: SCSI command block causing the reset | 495 | * @scsi_cmd: SCSI command block causing the reset |
@@ -457,12 +501,20 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) | |||
457 | struct Scsi_Host * host = dev->host; | 501 | struct Scsi_Host * host = dev->host; |
458 | struct scsi_cmnd * command; | 502 | struct scsi_cmnd * command; |
459 | int count; | 503 | int count; |
460 | struct aac_dev * aac; | 504 | struct aac_dev * aac = (struct aac_dev *)host->hostdata; |
461 | unsigned long flags; | 505 | unsigned long flags; |
462 | 506 | ||
507 | /* Mark the associated FIB to not complete, eh handler does this */ | ||
508 | for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { | ||
509 | struct fib * fib = &aac->fibs[count]; | ||
510 | if (fib->hw_fib_va->header.XferState && | ||
511 | (fib->callback_data == cmd)) { | ||
512 | fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; | ||
513 | cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; | ||
514 | } | ||
515 | } | ||
463 | printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", | 516 | printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", |
464 | AAC_DRIVERNAME); | 517 | AAC_DRIVERNAME); |
465 | aac = (struct aac_dev *)host->hostdata; | ||
466 | 518 | ||
467 | if ((count = aac_check_health(aac))) | 519 | if ((count = aac_check_health(aac))) |
468 | return count; | 520 | return count; |
@@ -496,7 +548,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) | |||
496 | ssleep(1); | 548 | ssleep(1); |
497 | } | 549 | } |
498 | printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); | 550 | printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); |
499 | return -ETIMEDOUT; | 551 | return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ |
500 | } | 552 | } |
501 | 553 | ||
502 | /** | 554 | /** |
@@ -796,6 +848,7 @@ static struct scsi_host_template aac_driver_template = { | |||
796 | .bios_param = aac_biosparm, | 848 | .bios_param = aac_biosparm, |
797 | .shost_attrs = aac_attrs, | 849 | .shost_attrs = aac_attrs, |
798 | .slave_configure = aac_slave_configure, | 850 | .slave_configure = aac_slave_configure, |
851 | .eh_abort_handler = aac_eh_abort, | ||
799 | .eh_host_reset_handler = aac_eh_reset, | 852 | .eh_host_reset_handler = aac_eh_reset, |
800 | .can_queue = AAC_NUM_IO_FIB, | 853 | .can_queue = AAC_NUM_IO_FIB, |
801 | .this_id = MAXIMUM_NUM_CONTAINERS, | 854 | .this_id = MAXIMUM_NUM_CONTAINERS, |