Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da071b42 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

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: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 3cadbcc0
Loading
Loading
Loading
Loading
+27 −8
Original line number Original line Diff line number Diff line
@@ -893,6 +893,23 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
	return 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
 *	ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
 *	@qc: Storage for translated ATA taskfile
 *	@qc: Storage for translated ATA taskfile
@@ -952,19 +969,21 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
		if (ata_spindown_compat &&
		if (ata_spindown_compat &&
		    (system_state == SYSTEM_HALT ||
		    (system_state == SYSTEM_HALT ||
		     system_state == SYSTEM_POWER_OFF)) {
		     system_state == SYSTEM_POWER_OFF)) {
			static int warned = 0;
			static unsigned long warned = 0;


			if (!warned) {
			if (!test_and_set_bit(0, &warned)) {
				spin_unlock_irq(qc->ap->lock);
				ata_dev_printk(qc->dev, KERN_WARNING,
				ata_dev_printk(qc->dev, KERN_WARNING,
					"DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
					"DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
					"UPDATE SHUTDOWN UTILITY\n");
					"UPDATE SHUTDOWN UTILITY\n");
				ata_dev_printk(qc->dev, KERN_WARNING,
				ata_dev_printk(qc->dev, KERN_WARNING,
					"For more info, visit "
					"For more info, visit "
					"http://linux-ata.org/shutdown.html\n");
					"http://linux-ata.org/shutdown.html\n");
				warned = 1;

				ssleep(5);
				/* ->scsi_done is not used, use it for
				spin_lock_irq(qc->ap->lock);
				 * delayed completion.
				 */
				scmd->scsi_done = qc->scsidone;
				qc->scsidone = ata_delayed_done;
			}
			}
			scmd->result = SAM_STAT_GOOD;
			scmd->result = SAM_STAT_GOOD;
			return 1;
			return 1;
@@ -1488,14 +1507,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,


early_finish:
early_finish:
        ata_qc_free(qc);
        ata_qc_free(qc);
	done(cmd);
	qc->scsidone(cmd);
	DPRINTK("EXIT - early finish (good or error)\n");
	DPRINTK("EXIT - early finish (good or error)\n");
	return 0;
	return 0;


err_did:
err_did:
	ata_qc_free(qc);
	ata_qc_free(qc);
	cmd->result = (DID_ERROR << 16);
	cmd->result = (DID_ERROR << 16);
	done(cmd);
	qc->scsidone(cmd);
err_mem:
err_mem:
	DPRINTK("EXIT - internal\n");
	DPRINTK("EXIT - internal\n");
	return 0;
	return 0;