Commit 9cec467d authored by Damien Le Moal's avatar Damien Le Moal Committed by Niklas Cassel
Browse files

ata: libata-core: Do not call ata_dev_power_set_standby() twice



For regular system shutdown, ata_dev_power_set_standby() will be
executed twice: once the scsi device is removed and another when
ata_pci_shutdown_one() executes and EH completes unloading the devices.

Make the second call to ata_dev_power_set_standby() do nothing by using
ata_dev_power_is_active() and return if the device is already in
standby.

Fixes: 2da4c5e2 ("ata: libata-core: Improve ata_dev_power_set_active()")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Signed-off-by: default avatarNiklas Cassel <cassel@kernel.org>
parent 26c8404e
Loading
Loading
Loading
Loading
+30 −29
Original line number Diff line number Diff line
@@ -2001,6 +2001,33 @@ bool ata_dev_power_init_tf(struct ata_device *dev, struct ata_taskfile *tf,
	return true;
}

static bool ata_dev_power_is_active(struct ata_device *dev)
{
	struct ata_taskfile tf;
	unsigned int err_mask;

	ata_tf_init(dev, &tf);
	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
	tf.protocol = ATA_PROT_NODATA;
	tf.command = ATA_CMD_CHK_POWER;

	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
	if (err_mask) {
		ata_dev_err(dev, "Check power mode failed (err_mask=0x%x)\n",
			    err_mask);
		/*
		 * Assume we are in standby mode so that we always force a
		 * spinup in ata_dev_power_set_active().
		 */
		return false;
	}

	ata_dev_dbg(dev, "Power mode: 0x%02x\n", tf.nsect);

	/* Active or idle */
	return tf.nsect == 0xff;
}

/**
 *	ata_dev_power_set_standby - Set a device power mode to standby
 *	@dev: target device
@@ -2017,8 +2044,9 @@ void ata_dev_power_set_standby(struct ata_device *dev)
	struct ata_taskfile tf;
	unsigned int err_mask;

	/* If the device is already sleeping, do nothing. */
	if (dev->flags & ATA_DFLAG_SLEEPING)
	/* If the device is already sleeping or in standby, do nothing. */
	if ((dev->flags & ATA_DFLAG_SLEEPING) ||
	    !ata_dev_power_is_active(dev))
		return;

	/*
@@ -2046,33 +2074,6 @@ void ata_dev_power_set_standby(struct ata_device *dev)
			    err_mask);
}

static bool ata_dev_power_is_active(struct ata_device *dev)
{
	struct ata_taskfile tf;
	unsigned int err_mask;

	ata_tf_init(dev, &tf);
	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
	tf.protocol = ATA_PROT_NODATA;
	tf.command = ATA_CMD_CHK_POWER;

	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
	if (err_mask) {
		ata_dev_err(dev, "Check power mode failed (err_mask=0x%x)\n",
			    err_mask);
		/*
		 * Assume we are in standby mode so that we always force a
		 * spinup in ata_dev_power_set_active().
		 */
		return false;
	}

	ata_dev_dbg(dev, "Power mode: 0x%02x\n", tf.nsect);

	/* Active or idle */
	return tf.nsect == 0xff;
}

/**
 *	ata_dev_power_set_active -  Set a device power mode to active
 *	@dev: target device