aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-05-14 11:26:18 -0400
committerJeff Garzik <jeff@garzik.org>2007-05-16 01:18:31 -0400
commitda071b42f73dabbd0daf7ea4c3ff157d53b00648 (patch)
tree6b8aa61169f6c18263821d9c5fe298b3b2eb6b21 /drivers/ata
parent3cadbcc09891b8544203f211dac13f9cc4e6832a (diff)
libata: fix shutdown warning message printing
Unlocking ap->lock and ssleeping don't work because SCSI commands can be issued from completion path without context. Reimplement delayed completion by allowing translation functions to override qc->scsidone(), storing the original completion function to scmd->scsi_done() and overriding qc->scsidone() with a function which schedules delayed invocation of scmd->scsi_done(). This isn't pretty at all but all the ugly parts are thankfully contained in the stop translation path where the compat feature is implemented. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-scsi.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index dd81fa78cdcf..07b5a3d4ed21 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -893,6 +893,23 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
893 return queue_depth; 893 return queue_depth;
894} 894}
895 895
896/* XXX: for ata_spindown_compat */
897static void ata_delayed_done_timerfn(unsigned long arg)
898{
899 struct scsi_cmnd *scmd = (void *)arg;
900
901 scmd->scsi_done(scmd);
902}
903
904/* XXX: for ata_spindown_compat */
905static void ata_delayed_done(struct scsi_cmnd *scmd)
906{
907 static struct timer_list timer;
908
909 setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd);
910 mod_timer(&timer, jiffies + 5 * HZ);
911}
912
896/** 913/**
897 * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command 914 * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
898 * @qc: Storage for translated ATA taskfile 915 * @qc: Storage for translated ATA taskfile
@@ -952,19 +969,21 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
952 if (ata_spindown_compat && 969 if (ata_spindown_compat &&
953 (system_state == SYSTEM_HALT || 970 (system_state == SYSTEM_HALT ||
954 system_state == SYSTEM_POWER_OFF)) { 971 system_state == SYSTEM_POWER_OFF)) {
955 static int warned = 0; 972 static unsigned long warned = 0;
956 973
957 if (!warned) { 974 if (!test_and_set_bit(0, &warned)) {
958 spin_unlock_irq(qc->ap->lock);
959 ata_dev_printk(qc->dev, KERN_WARNING, 975 ata_dev_printk(qc->dev, KERN_WARNING,
960 "DISK MIGHT NOT BE SPUN DOWN PROPERLY. " 976 "DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
961 "UPDATE SHUTDOWN UTILITY\n"); 977 "UPDATE SHUTDOWN UTILITY\n");
962 ata_dev_printk(qc->dev, KERN_WARNING, 978 ata_dev_printk(qc->dev, KERN_WARNING,
963 "For more info, visit " 979 "For more info, visit "
964 "http://linux-ata.org/shutdown.html\n"); 980 "http://linux-ata.org/shutdown.html\n");
965 warned = 1; 981
966 ssleep(5); 982 /* ->scsi_done is not used, use it for
967 spin_lock_irq(qc->ap->lock); 983 * delayed completion.
984 */
985 scmd->scsi_done = qc->scsidone;
986 qc->scsidone = ata_delayed_done;
968 } 987 }
969 scmd->result = SAM_STAT_GOOD; 988 scmd->result = SAM_STAT_GOOD;
970 return 1; 989 return 1;
@@ -1488,14 +1507,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
1488 1507
1489early_finish: 1508early_finish:
1490 ata_qc_free(qc); 1509 ata_qc_free(qc);
1491 done(cmd); 1510 qc->scsidone(cmd);
1492 DPRINTK("EXIT - early finish (good or error)\n"); 1511 DPRINTK("EXIT - early finish (good or error)\n");
1493 return 0; 1512 return 0;
1494 1513
1495err_did: 1514err_did:
1496 ata_qc_free(qc); 1515 ata_qc_free(qc);
1497 cmd->result = (DID_ERROR << 16); 1516 cmd->result = (DID_ERROR << 16);
1498 done(cmd); 1517 qc->scsidone(cmd);
1499err_mem: 1518err_mem:
1500 DPRINTK("EXIT - internal\n"); 1519 DPRINTK("EXIT - internal\n");
1501 return 0; 1520 return 0;