ata: libata-core: Do not call ata_dev_power_set_standby() twice
authorDamien Le Moal <dlemoal@kernel.org>
Mon, 19 Feb 2024 15:44:30 +0000 (16:44 +0100)
committerNiklas Cassel <cassel@kernel.org>
Wed, 21 Feb 2024 18:09:17 +0000 (19:09 +0100)
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: 2da4c5e24e86 ("ata: libata-core: Improve ata_dev_power_set_active()")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
drivers/ata/libata-core.c

index d9f80f4f70f5b29ae15693fc5ae5e14a8ffcdfb4..be3412cdb22e78a1d663337698f07b07c66727e4 100644 (file)
@@ -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