diff options
author | Salyzyn, Mark <mark_salyzyn@adaptec.com> | 2007-06-12 09:33:54 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 16:00:47 -0400 |
commit | 29c976844d0bef07d97babc8db60fa6c46788133 (patch) | |
tree | 9543cef49748d0fe7ac08a5a1780c213e0fc37bd /drivers | |
parent | 1a655040c24ebf3954ad5cf8848391cb420b1ffb (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')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 18 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 25 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 210 | ||||
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 46 | ||||
-rw-r--r-- | drivers/scsi/aacraid/rx.c | 33 |
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; | |||
169 | module_param(acbsize, int, S_IRUGO|S_IWUSR); | 169 | module_param(acbsize, int, S_IRUGO|S_IWUSR); |
170 | MODULE_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."); | 170 | MODULE_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 | ||
172 | int update_interval = 30 * 60; | ||
173 | module_param(update_interval, int, S_IRUGO|S_IWUSR); | ||
174 | MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter."); | ||
175 | |||
176 | int check_interval = 24 * 60 * 60; | ||
177 | module_param(check_interval, int, S_IRUGO|S_IWUSR); | ||
178 | MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks."); | ||
179 | |||
180 | int check_reset = 1; | ||
181 | module_param(check_reset, int, S_IRUGO|S_IWUSR); | ||
182 | MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter."); | ||
183 | |||
172 | int expose_physicals = -1; | 184 | int expose_physicals = -1; |
173 | module_param(expose_physicals, int, S_IRUGO|S_IWUSR); | 185 | module_param(expose_physicals, int, S_IRUGO|S_IWUSR); |
174 | MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); | 186 | MODULE_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 | ||
1267 | struct 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 | |||
1263 | struct aac_srb | 1278 | struct 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 | |||
1816 | unsigned int aac_response_normal(struct aac_queue * q); | 1831 | unsigned int aac_response_normal(struct aac_queue * q); |
1817 | unsigned int aac_command_normal(struct aac_queue * q); | 1832 | unsigned int aac_command_normal(struct aac_queue * q); |
1818 | unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); | 1833 | unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); |
1834 | int aac_reset_adapter(struct aac_dev * dev, int forced); | ||
1819 | int aac_check_health(struct aac_dev * dev); | 1835 | int aac_check_health(struct aac_dev * dev); |
1820 | int aac_command_thread(void *data); | 1836 | int aac_command_thread(void *data); |
1821 | int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); | 1837 | int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); |
@@ -1835,3 +1851,6 @@ extern int aif_timeout; | |||
1835 | extern int expose_physicals; | 1851 | extern int expose_physicals; |
1836 | extern int aac_reset_devices; | 1852 | extern int aac_reset_devices; |
1837 | extern int aac_commit; | 1853 | extern int aac_commit; |
1854 | extern int update_interval; | ||
1855 | extern int check_interval; | ||
1856 | extern 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 | ||
1024 | static int _aac_reset_adapter(struct aac_dev *aac) | 1024 | static 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) | |||
1150 | out: | 1159 | out: |
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 | |||
1168 | int 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 | ||
1279 | out: | 1384 | out: |
@@ -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 | ||
797 | static 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 | |||
810 | static 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 | ||
792 | static struct class_device_attribute aac_model = { | 823 | static 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 | }; |
879 | static 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 | ||
849 | static struct class_device_attribute *aac_attrs[] = { | 888 | static 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. |