aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorSalyzyn, Mark <mark_salyzyn@adaptec.com>2007-06-12 09:33:54 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-06-17 16:00:47 -0400
commit29c976844d0bef07d97babc8db60fa6c46788133 (patch)
tree9543cef49748d0fe7ac08a5a1780c213e0fc37bd /drivers/scsi
parent1a655040c24ebf3954ad5cf8848391cb420b1ffb (diff)
[SCSI] aacraid: add user initiated reset
Add the ability for an application to issue a hardware reset to the adapter via sysfs. Typical uses include restarting the adapter after it has been flashed. Bumped revision number for the driver and added a feature to periodically check the adapter's health (check_interval), update the adapter's concept of time (update_interval) and block checking/resetting of the adapter (check_reset). Signed-off-by: Mark Salyzyn <aacraid@adaptec.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/aacraid/aachba.c18
-rw-r--r--drivers/scsi/aacraid/aacraid.h25
-rw-r--r--drivers/scsi/aacraid/commsup.c210
-rw-r--r--drivers/scsi/aacraid/linit.c46
-rw-r--r--drivers/scsi/aacraid/rx.c33
5 files changed, 294 insertions, 38 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index ef11c18d9ba4..b3081b10d0a3 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -169,6 +169,18 @@ int acbsize = -1;
169module_param(acbsize, int, S_IRUGO|S_IWUSR); 169module_param(acbsize, int, S_IRUGO|S_IWUSR);
170MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware."); 170MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
171 171
172int update_interval = 30 * 60;
173module_param(update_interval, int, S_IRUGO|S_IWUSR);
174MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter.");
175
176int check_interval = 24 * 60 * 60;
177module_param(check_interval, int, S_IRUGO|S_IWUSR);
178MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
179
180int check_reset = 1;
181module_param(check_reset, int, S_IRUGO|S_IWUSR);
182MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
183
172int expose_physicals = -1; 184int expose_physicals = -1;
173module_param(expose_physicals, int, S_IRUGO|S_IWUSR); 185module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
174MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); 186MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
@@ -1197,6 +1209,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
1197 (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), 1209 (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
1198 dev->supplement_adapter_info.VpdInfo.Tsid); 1210 dev->supplement_adapter_info.VpdInfo.Tsid);
1199 } 1211 }
1212 if (!check_reset ||
1213 (dev->supplement_adapter_info.SupportedOptions2 &
1214 le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
1215 printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
1216 dev->name, dev->id);
1217 }
1200 } 1218 }
1201 1219
1202 dev->nondasd_support = 0; 1220 dev->nondasd_support = 0;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index fdbedb17d03b..8abe4f97b0af 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@
12 *----------------------------------------------------------------------------*/ 12 *----------------------------------------------------------------------------*/
13 13
14#ifndef AAC_DRIVER_BUILD 14#ifndef AAC_DRIVER_BUILD
15# define AAC_DRIVER_BUILD 2437 15# define AAC_DRIVER_BUILD 2447
16# define AAC_DRIVER_BRANCH "-mh4" 16# define AAC_DRIVER_BRANCH "-ms"
17#endif 17#endif
18#define MAXIMUM_NUM_CONTAINERS 32 18#define MAXIMUM_NUM_CONTAINERS 32
19 19
@@ -860,10 +860,12 @@ struct aac_supplement_adapter_info
860 __le32 FlashFirmwareBootBuild; 860 __le32 FlashFirmwareBootBuild;
861 u8 MfgPcbaSerialNo[12]; 861 u8 MfgPcbaSerialNo[12];
862 u8 MfgWWNName[8]; 862 u8 MfgWWNName[8];
863 __le32 MoreFeatureBits; 863 __le32 SupportedOptions2;
864 __le32 ReservedGrowth[1]; 864 __le32 ReservedGrowth[1];
865}; 865};
866#define AAC_FEATURE_FALCON 0x00000010 866#define AAC_FEATURE_FALCON 0x00000010
867#define AAC_OPTION_MU_RESET 0x00000001
868#define AAC_OPTION_IGNORE_RESET 0x00000002
867#define AAC_SIS_VERSION_V3 3 869#define AAC_SIS_VERSION_V3 3
868#define AAC_SIS_SLOT_UNKNOWN 0xFF 870#define AAC_SIS_SLOT_UNKNOWN 0xFF
869 871
@@ -1260,6 +1262,19 @@ struct aac_synchronize_reply {
1260 u8 data[16]; 1262 u8 data[16];
1261}; 1263};
1262 1264
1265#define CT_PAUSE_IO 65
1266#define CT_RELEASE_IO 66
1267struct aac_pause {
1268 __le32 command; /* VM_ContainerConfig */
1269 __le32 type; /* CT_PAUSE_IO */
1270 __le32 timeout; /* 10ms ticks */
1271 __le32 min;
1272 __le32 noRescan;
1273 __le32 parm3;
1274 __le32 parm4;
1275 __le32 count; /* sizeof(((struct aac_pause_reply *)NULL)->data) */
1276};
1277
1263struct aac_srb 1278struct aac_srb
1264{ 1279{
1265 __le32 function; 1280 __le32 function;
@@ -1816,6 +1831,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
1816unsigned int aac_response_normal(struct aac_queue * q); 1831unsigned int aac_response_normal(struct aac_queue * q);
1817unsigned int aac_command_normal(struct aac_queue * q); 1832unsigned int aac_command_normal(struct aac_queue * q);
1818unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); 1833unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
1834int aac_reset_adapter(struct aac_dev * dev, int forced);
1819int aac_check_health(struct aac_dev * dev); 1835int aac_check_health(struct aac_dev * dev);
1820int aac_command_thread(void *data); 1836int aac_command_thread(void *data);
1821int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); 1837int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
@@ -1835,3 +1851,6 @@ extern int aif_timeout;
1835extern int expose_physicals; 1851extern int expose_physicals;
1836extern int aac_reset_devices; 1852extern int aac_reset_devices;
1837extern int aac_commit; 1853extern int aac_commit;
1854extern int update_interval;
1855extern int check_interval;
1856extern int check_reset;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 9aca57eda943..d510839c0bb2 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1021,7 +1021,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
1021 1021
1022} 1022}
1023 1023
1024static int _aac_reset_adapter(struct aac_dev *aac) 1024static int _aac_reset_adapter(struct aac_dev *aac, int forced)
1025{ 1025{
1026 int index, quirks; 1026 int index, quirks;
1027 int retval; 1027 int retval;
@@ -1029,25 +1029,32 @@ static int _aac_reset_adapter(struct aac_dev *aac)
1029 struct scsi_device *dev; 1029 struct scsi_device *dev;
1030 struct scsi_cmnd *command; 1030 struct scsi_cmnd *command;
1031 struct scsi_cmnd *command_list; 1031 struct scsi_cmnd *command_list;
1032 int jafo = 0;
1032 1033
1033 /* 1034 /*
1034 * Assumptions: 1035 * Assumptions:
1035 * - host is locked. 1036 * - host is locked, unless called by the aacraid thread.
1037 * (a matter of convenience, due to legacy issues surrounding
1038 * eh_host_adapter_reset).
1036 * - in_reset is asserted, so no new i/o is getting to the 1039 * - in_reset is asserted, so no new i/o is getting to the
1037 * card. 1040 * card.
1038 * - The card is dead. 1041 * - The card is dead, or will be very shortly ;-/ so no new
1042 * commands are completing in the interrupt service.
1039 */ 1043 */
1040 host = aac->scsi_host_ptr; 1044 host = aac->scsi_host_ptr;
1041 scsi_block_requests(host); 1045 scsi_block_requests(host);
1042 aac_adapter_disable_int(aac); 1046 aac_adapter_disable_int(aac);
1043 spin_unlock_irq(host->host_lock); 1047 if (aac->thread->pid != current->pid) {
1044 kthread_stop(aac->thread); 1048 spin_unlock_irq(host->host_lock);
1049 kthread_stop(aac->thread);
1050 jafo = 1;
1051 }
1045 1052
1046 /* 1053 /*
1047 * If a positive health, means in a known DEAD PANIC 1054 * If a positive health, means in a known DEAD PANIC
1048 * state and the adapter could be reset to `try again'. 1055 * state and the adapter could be reset to `try again'.
1049 */ 1056 */
1050 retval = aac_adapter_restart(aac, aac_adapter_check_health(aac)); 1057 retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac));
1051 1058
1052 if (retval) 1059 if (retval)
1053 goto out; 1060 goto out;
@@ -1104,10 +1111,12 @@ static int _aac_reset_adapter(struct aac_dev *aac)
1104 if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) 1111 if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
1105 if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) 1112 if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
1106 goto out; 1113 goto out;
1107 aac->thread = kthread_run(aac_command_thread, aac, aac->name); 1114 if (jafo) {
1108 if (IS_ERR(aac->thread)) { 1115 aac->thread = kthread_run(aac_command_thread, aac, aac->name);
1109 retval = PTR_ERR(aac->thread); 1116 if (IS_ERR(aac->thread)) {
1110 goto out; 1117 retval = PTR_ERR(aac->thread);
1118 goto out;
1119 }
1111 } 1120 }
1112 (void)aac_get_adapter_info(aac); 1121 (void)aac_get_adapter_info(aac);
1113 quirks = aac_get_driver_ident(index)->quirks; 1122 quirks = aac_get_driver_ident(index)->quirks;
@@ -1150,7 +1159,98 @@ static int _aac_reset_adapter(struct aac_dev *aac)
1150out: 1159out:
1151 aac->in_reset = 0; 1160 aac->in_reset = 0;
1152 scsi_unblock_requests(host); 1161 scsi_unblock_requests(host);
1153 spin_lock_irq(host->host_lock); 1162 if (jafo) {
1163 spin_lock_irq(host->host_lock);
1164 }
1165 return retval;
1166}
1167
1168int aac_reset_adapter(struct aac_dev * aac, int forced)
1169{
1170 unsigned long flagv = 0;
1171 int retval;
1172 struct Scsi_Host * host;
1173
1174 if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
1175 return -EBUSY;
1176
1177 if (aac->in_reset) {
1178 spin_unlock_irqrestore(&aac->fib_lock, flagv);
1179 return -EBUSY;
1180 }
1181 aac->in_reset = 1;
1182 spin_unlock_irqrestore(&aac->fib_lock, flagv);
1183
1184 /*
1185 * Wait for all commands to complete to this specific
1186 * target (block maximum 60 seconds). Although not necessary,
1187 * it does make us a good storage citizen.
1188 */
1189 host = aac->scsi_host_ptr;
1190 scsi_block_requests(host);
1191 if (forced < 2) for (retval = 60; retval; --retval) {
1192 struct scsi_device * dev;
1193 struct scsi_cmnd * command;
1194 int active = 0;
1195
1196 __shost_for_each_device(dev, host) {
1197 spin_lock_irqsave(&dev->list_lock, flagv);
1198 list_for_each_entry(command, &dev->cmd_list, list) {
1199 if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
1200 active++;
1201 break;
1202 }
1203 }
1204 spin_unlock_irqrestore(&dev->list_lock, flagv);
1205 if (active)
1206 break;
1207
1208 }
1209 /*
1210 * We can exit If all the commands are complete
1211 */
1212 if (active == 0)
1213 break;
1214 ssleep(1);
1215 }
1216
1217 /* Quiesce build, flush cache, write through mode */
1218 aac_send_shutdown(aac);
1219 spin_lock_irqsave(host->host_lock, flagv);
1220 retval = _aac_reset_adapter(aac, forced);
1221 spin_unlock_irqrestore(host->host_lock, flagv);
1222
1223 if (retval == -ENODEV) {
1224 /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
1225 struct fib * fibctx = aac_fib_alloc(aac);
1226 if (fibctx) {
1227 struct aac_pause *cmd;
1228 int status;
1229
1230 aac_fib_init(fibctx);
1231
1232 cmd = (struct aac_pause *) fib_data(fibctx);
1233
1234 cmd->command = cpu_to_le32(VM_ContainerConfig);
1235 cmd->type = cpu_to_le32(CT_PAUSE_IO);
1236 cmd->timeout = cpu_to_le32(1);
1237 cmd->min = cpu_to_le32(1);
1238 cmd->noRescan = cpu_to_le32(1);
1239 cmd->count = cpu_to_le32(0);
1240
1241 status = aac_fib_send(ContainerCommand,
1242 fibctx,
1243 sizeof(struct aac_pause),
1244 FsaNormal,
1245 -2 /* Timeout silently */, 1,
1246 NULL, NULL);
1247
1248 if (status >= 0)
1249 aac_fib_complete(fibctx);
1250 aac_fib_free(fibctx);
1251 }
1252 }
1253
1154 return retval; 1254 return retval;
1155} 1255}
1156 1256
@@ -1270,10 +1370,15 @@ int aac_check_health(struct aac_dev * aac)
1270 1370
1271 printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); 1371 printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
1272 1372
1373 if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
1374 le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
1375 goto out;
1273 host = aac->scsi_host_ptr; 1376 host = aac->scsi_host_ptr;
1274 spin_lock_irqsave(host->host_lock, flagv); 1377 if (aac->thread->pid != current->pid)
1275 BlinkLED = _aac_reset_adapter(aac); 1378 spin_lock_irqsave(host->host_lock, flagv);
1276 spin_unlock_irqrestore(host->host_lock, flagv); 1379 BlinkLED = _aac_reset_adapter(aac, 0);
1380 if (aac->thread->pid != current->pid)
1381 spin_unlock_irqrestore(host->host_lock, flagv);
1277 return BlinkLED; 1382 return BlinkLED;
1278 1383
1279out: 1384out:
@@ -1300,6 +1405,9 @@ int aac_command_thread(void *data)
1300 struct aac_fib_context *fibctx; 1405 struct aac_fib_context *fibctx;
1301 unsigned long flags; 1406 unsigned long flags;
1302 DECLARE_WAITQUEUE(wait, current); 1407 DECLARE_WAITQUEUE(wait, current);
1408 unsigned long next_jiffies = jiffies + HZ;
1409 unsigned long next_check_jiffies = next_jiffies;
1410 long difference = HZ;
1303 1411
1304 /* 1412 /*
1305 * We can only have one thread per adapter for AIF's. 1413 * We can only have one thread per adapter for AIF's.
@@ -1368,7 +1476,7 @@ int aac_command_thread(void *data)
1368 cpu_to_le32(AifCmdJobProgress))) { 1476 cpu_to_le32(AifCmdJobProgress))) {
1369 aac_handle_aif(dev, fib); 1477 aac_handle_aif(dev, fib);
1370 } 1478 }
1371 1479
1372 time_now = jiffies/HZ; 1480 time_now = jiffies/HZ;
1373 1481
1374 /* 1482 /*
@@ -1507,11 +1615,79 @@ int aac_command_thread(void *data)
1507 * There are no more AIF's 1615 * There are no more AIF's
1508 */ 1616 */
1509 spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); 1617 spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
1510 schedule(); 1618
1619 /*
1620 * Background activity
1621 */
1622 if ((time_before(next_check_jiffies,next_jiffies))
1623 && ((difference = next_check_jiffies - jiffies) <= 0)) {
1624 next_check_jiffies = next_jiffies;
1625 if (aac_check_health(dev) == 0) {
1626 difference = ((long)(unsigned)check_interval)
1627 * HZ;
1628 next_check_jiffies = jiffies + difference;
1629 } else if (!dev->queues)
1630 break;
1631 }
1632 if (!time_before(next_check_jiffies,next_jiffies)
1633 && ((difference = next_jiffies - jiffies) <= 0)) {
1634 struct timeval now;
1635 int ret;
1636
1637 /* Don't even try to talk to adapter if its sick */
1638 ret = aac_check_health(dev);
1639 if (!ret && !dev->queues)
1640 break;
1641 next_check_jiffies = jiffies
1642 + ((long)(unsigned)check_interval)
1643 * HZ;
1644 do_gettimeofday(&now);
1645
1646 /* Synchronize our watches */
1647 if (((1000000 - (1000000 / HZ)) > now.tv_usec)
1648 && (now.tv_usec > (1000000 / HZ)))
1649 difference = (((1000000 - now.tv_usec) * HZ)
1650 + 500000) / 1000000;
1651 else if (ret == 0) {
1652 struct fib *fibptr;
1653
1654 if ((fibptr = aac_fib_alloc(dev))) {
1655 u32 * info;
1656
1657 aac_fib_init(fibptr);
1658
1659 info = (u32 *) fib_data(fibptr);
1660 if (now.tv_usec > 500000)
1661 ++now.tv_sec;
1662
1663 *info = cpu_to_le32(now.tv_sec);
1664
1665 (void)aac_fib_send(SendHostTime,
1666 fibptr,
1667 sizeof(*info),
1668 FsaNormal,
1669 1, 1,
1670 NULL,
1671 NULL);
1672 aac_fib_complete(fibptr);
1673 aac_fib_free(fibptr);
1674 }
1675 difference = (long)(unsigned)update_interval*HZ;
1676 } else {
1677 /* retry shortly */
1678 difference = 10 * HZ;
1679 }
1680 next_jiffies = jiffies + difference;
1681 if (time_before(next_check_jiffies,next_jiffies))
1682 difference = next_check_jiffies - jiffies;
1683 }
1684 if (difference <= 0)
1685 difference = 1;
1686 set_current_state(TASK_INTERRUPTIBLE);
1687 schedule_timeout(difference);
1511 1688
1512 if (kthread_should_stop()) 1689 if (kthread_should_stop())
1513 break; 1690 break;
1514 set_current_state(TASK_INTERRUPTIBLE);
1515 } 1691 }
1516 if (dev->queues) 1692 if (dev->queues)
1517 remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); 1693 remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 6f92d077679f..f8c2aaf72aff 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -39,10 +39,8 @@
39#include <linux/pci.h> 39#include <linux/pci.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41#include <linux/spinlock.h> 41#include <linux/spinlock.h>
42#include <linux/dma-mapping.h>
43#include <linux/syscalls.h> 42#include <linux/syscalls.h>
44#include <linux/delay.h> 43#include <linux/delay.h>
45#include <linux/smp_lock.h>
46#include <linux/kthread.h> 44#include <linux/kthread.h>
47#include <asm/semaphore.h> 45#include <asm/semaphore.h>
48 46
@@ -581,6 +579,14 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
581 ssleep(1); 579 ssleep(1);
582 } 580 }
583 printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); 581 printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
582 /*
583 * This adapter needs a blind reset, only do so for Adapters that
584 * support a register, instead of a commanded, reset.
585 */
586 if ((aac->supplement_adapter_info.SupportedOptions2 &
587 le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
588 le32_to_cpu(AAC_OPTION_MU_RESET))
589 aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
584 return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ 590 return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
585} 591}
586 592
@@ -788,6 +794,31 @@ static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf)
788 class_to_shost(class_dev)->max_id); 794 class_to_shost(class_dev)->max_id);
789} 795}
790 796
797static ssize_t aac_store_reset_adapter(struct class_device *class_dev,
798 const char *buf, size_t count)
799{
800 int retval = -EACCES;
801
802 if (!capable(CAP_SYS_ADMIN))
803 return retval;
804 retval = aac_reset_adapter((struct aac_dev*)class_to_shost(class_dev)->hostdata, buf[0] == '!');
805 if (retval >= 0)
806 retval = count;
807 return retval;
808}
809
810static ssize_t aac_show_reset_adapter(struct class_device *class_dev,
811 char *buf)
812{
813 struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
814 int len, tmp;
815
816 tmp = aac_adapter_check_health(dev);
817 if ((tmp == 0) && dev->in_reset)
818 tmp = -EBUSY;
819 len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
820 return len;
821}
791 822
792static struct class_device_attribute aac_model = { 823static struct class_device_attribute aac_model = {
793 .attr = { 824 .attr = {
@@ -845,6 +876,14 @@ static struct class_device_attribute aac_max_id = {
845 }, 876 },
846 .show = aac_show_max_id, 877 .show = aac_show_max_id,
847}; 878};
879static struct class_device_attribute aac_reset = {
880 .attr = {
881 .name = "reset_host",
882 .mode = S_IWUSR|S_IRUGO,
883 },
884 .store = aac_store_reset_adapter,
885 .show = aac_show_reset_adapter,
886};
848 887
849static struct class_device_attribute *aac_attrs[] = { 888static struct class_device_attribute *aac_attrs[] = {
850 &aac_model, 889 &aac_model,
@@ -855,6 +894,7 @@ static struct class_device_attribute *aac_attrs[] = {
855 &aac_serial_number, 894 &aac_serial_number,
856 &aac_max_channel, 895 &aac_max_channel,
857 &aac_max_id, 896 &aac_max_id,
897 &aac_reset,
858 NULL 898 NULL
859}; 899};
860 900
@@ -1118,7 +1158,7 @@ static int __init aac_init(void)
1118{ 1158{
1119 int error; 1159 int error;
1120 1160
1121 printk(KERN_INFO "Adaptec %s driver (%s)\n", 1161 printk(KERN_INFO "Adaptec %s driver %s\n",
1122 AAC_DRIVERNAME, aac_driver_version); 1162 AAC_DRIVERNAME, aac_driver_version);
1123 1163
1124 error = pci_register_driver(&aac_pci_driver); 1164 error = pci_register_driver(&aac_pci_driver);
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ae978a373c56..ebc65b9fea92 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -464,21 +464,24 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
464{ 464{
465 u32 var; 465 u32 var;
466 466
467 if (bled) 467 if (!(dev->supplement_adapter_info.SupportedOptions2 &
468 printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", 468 le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
469 dev->name, dev->id, bled); 469 if (bled)
470 else { 470 printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
471 bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 471 dev->name, dev->id, bled);
472 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 472 else {
473 if (!bled && (var != 0x00000001)) 473 bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
474 bled = -EINVAL; 474 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
475 } 475 if (!bled && (var != 0x00000001))
476 if (bled && (bled != -ETIMEDOUT)) 476 bled = -EINVAL;
477 bled = aac_adapter_sync_cmd(dev, IOP_RESET, 477 }
478 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 478 if (bled && (bled != -ETIMEDOUT))
479 bled = aac_adapter_sync_cmd(dev, IOP_RESET,
480 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
479 481
480 if (bled && (bled != -ETIMEDOUT)) 482 if (bled && (bled != -ETIMEDOUT))
481 return -EINVAL; 483 return -EINVAL;
484 }
482 if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */ 485 if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
483 rx_writel(dev, MUnit.reserved2, 3); 486 rx_writel(dev, MUnit.reserved2, 3);
484 msleep(5000); /* Delay 5 seconds */ 487 msleep(5000); /* Delay 5 seconds */
@@ -596,7 +599,7 @@ int _aac_rx_init(struct aac_dev *dev)
596 } 599 }
597 msleep(1); 600 msleep(1);
598 } 601 }
599 if (restart) 602 if (restart && aac_commit)
600 aac_commit = 1; 603 aac_commit = 1;
601 /* 604 /*
602 * Fill in the common function dispatch table. 605 * Fill in the common function dispatch table.