Skip to content

Commit

Permalink
libata: fix shutdown warning message printing
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed May 16, 2007
1 parent 3cadbcc commit da071b4
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,23 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
return 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
Expand Down Expand Up @@ -952,19 +969,21 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
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;
Expand Down Expand Up @@ -1488,14 +1507,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,

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;
Expand Down

0 comments on commit da071b4

Please sign in to comment.