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>

authored by Tejun Heo and committed by Jeff Garzik da071b42 3cadbcc0

+27 -8
+27 -8
drivers/ata/libata-scsi.c
··· 893 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 914 * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command 898 915 * @qc: Storage for translated ATA taskfile ··· 969 952 if (ata_spindown_compat && 970 953 (system_state == SYSTEM_HALT || 971 954 system_state == SYSTEM_POWER_OFF)) { 972 - static int warned = 0; 955 + static unsigned long warned = 0; 973 956 974 - if (!warned) { 975 - spin_unlock_irq(qc->ap->lock); 957 + if (!test_and_set_bit(0, &warned)) { 976 958 ata_dev_printk(qc->dev, KERN_WARNING, 977 959 "DISK MIGHT NOT BE SPUN DOWN PROPERLY. " 978 960 "UPDATE SHUTDOWN UTILITY\n"); 979 961 ata_dev_printk(qc->dev, KERN_WARNING, 980 962 "For more info, visit " 981 963 "http://linux-ata.org/shutdown.html\n"); 982 - warned = 1; 983 - ssleep(5); 984 - spin_lock_irq(qc->ap->lock); 964 + 965 + /* ->scsi_done is not used, use it for 966 + * delayed completion. 967 + */ 968 + scmd->scsi_done = qc->scsidone; 969 + qc->scsidone = ata_delayed_done; 985 970 } 986 971 scmd->result = SAM_STAT_GOOD; 987 972 return 1; ··· 1507 1488 1508 1489 early_finish: 1509 1490 ata_qc_free(qc); 1510 - done(cmd); 1491 + qc->scsidone(cmd); 1511 1492 DPRINTK("EXIT - early finish (good or error)\n"); 1512 1493 return 0; 1513 1494 1514 1495 err_did: 1515 1496 ata_qc_free(qc); 1516 1497 cmd->result = (DID_ERROR << 16); 1517 - done(cmd); 1498 + qc->scsidone(cmd); 1518 1499 err_mem: 1519 1500 DPRINTK("EXIT - internal\n"); 1520 1501 return 0;