aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aacraid/commsup.c
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/aacraid/commsup.c
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/aacraid/commsup.c')
-rw-r--r--drivers/scsi/aacraid/commsup.c210
1 files changed, 193 insertions, 17 deletions
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);