libata: fix shutdown warning message printing
PATCH 1/1 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.
drivers/ata/libata-scsi.c +27 -8
@@ -893,6 +893,23 @@ int ata_scsi_change_queue_depth(struct sreturn queue_depth; } +/* XXX: for ata_spindown_compat */ +static void ata_delayed_done_timerfn (unsigned long arg) +{ +struct scsi_cmnd *scmd = (void *)arg; + + scmd->scsi_done (scmd); +} + +/* XXX: for ata_spindown_compat */ +static void ata_delayed_done (struct scsi_cmnd *scmd) +{ +static struct timer_list timer; + +setup_timer (&timer, ata_delayed_done_timerfn, (unsigned long )scmd); +mod_timer (&timer, jiffies +5 *HZ ); +} +/** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile
@@ -952,19 +969,21 @@ static unsigned int ata_scsi_start_stop_if (ata_spindown_compat && (system_state ==SYSTEM_HALT || system_state ==SYSTEM_POWER_OFF )) { -static int warned =0 ; +static unsigned long warned =0 ; -if (!warned) { -spin_unlock_irq (qc->ap->lock); +if (!test_and_set_bit (0 , &warned)) {ata_dev_printk (qc->dev,KERN_WARNING ,"DISK MIGHT NOT BE SPUN DOWN PROPERLY. " "UPDATE SHUTDOWN UTILITY\n" );ata_dev_printk (qc->dev,KERN_WARNING ,"For more info, visit " "http://linux-ata.org/shutdown.html\n" ); - warned =1 ; -ssleep (5 ); -spin_lock_irq (qc->ap->lock); + +/* ->scsi_done is not used, use it for +* delayed completion. +*/ + scmd->scsi_done = qc->scsidone; + qc->scsidone = ata_delayed_done; } scmd->result =SAM_STAT_GOOD ;return 1 ;
@@ -1488,14 +1507,14 @@ static int ata_scsi_translate(struct ata early_finish:ata_qc_free (qc); -done (cmd); + qc->scsidone (cmd);DPRINTK ("EXIT - early finish (good or error)\n" );return 0 ; err_did:ata_qc_free (qc); cmd->result = (DID_ERROR <<16 ); -done (cmd); + qc->scsidone (cmd); err_mem:DPRINTK ("EXIT - internal\n" );return 0 ;
Quoted 7 lines · Tejun Heo
Unlocking
ap->lockand ssleeping don't work because SCSI commands can be issued from completion path without context. Reimplement delayed completion by allowing translation functions to overrideqc->scsidone(), storing the original completion function toscmd->scsi_done()and overridingqc->scsidone()with a function which schedules delayed invocation ofscmd->scsi_done().
Quoted 5 lines
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 <[email protected]>
Heh, very clever, but a bit of a hack (however, no better way I can see to do it given the layering constraints).
James
Jeff Garzik
AppliedQuoted 7 lines · Tejun Heo
Unlocking
ap->lockand ssleeping don't work because SCSI commands can be issued from completion path without context. Reimplement delayed completion by allowing translation functions to overrideqc->scsidone(), storing the original completion function toscmd->scsi_done()and overridingqc->scsidone()with a function which schedules delayed invocation ofscmd->scsi_done().
Quoted 5 lines
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 <[email protected]>
applied to #upstream-fixes