diff options
author | Tejun Heo <htejun@gmail.com> | 2007-05-14 11:26:18 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-05-16 01:18:31 -0400 |
commit | da071b42f73dabbd0daf7ea4c3ff157d53b00648 (patch) | |
tree | 6b8aa61169f6c18263821d9c5fe298b3b2eb6b21 /drivers/ata | |
parent | 3cadbcc09891b8544203f211dac13f9cc4e6832a (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.c | 35 |
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 */ | ||
897 | static 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 */ | ||
905 | static 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 | ||
1489 | early_finish: | 1508 | early_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 | ||
1495 | err_did: | 1514 | err_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); |
1499 | err_mem: | 1518 | err_mem: |
1500 | DPRINTK("EXIT - internal\n"); | 1519 | DPRINTK("EXIT - internal\n"); |
1501 | return 0; | 1520 | return 0; |