ata fixes for 6.17-rc1

- Cleanup whitespace in messages in libata-core and the pata_pdc2027x,
    pata_macio drivers (Colin).
 
  - Fix ata_to_sense_error() to avoid seeing nonsensical sense data for
    rare cases where we fail to get sense data from the drive. The
    complementary fix to this is to ensure that we always return the
    generic "ABORTED COMMAND" sense data for a failed command for which
    we have no status or error fields.
 
  - The recent changes to link power management (LPM) which now prevent
    the user from attempting to set an LPM policy through the
    link_power_management_policy caused some regressions in test
    environments because of the error that is now returned when writing
    to that attribute when LPM is not supported. To allow users to not
    trip on this, introduce the new link_power_management_supported
    attribute to allow simple testing of a port/device LPM support (me).
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCaJLfKAAKCRDdoc3SxdoY
 djDMAQDiz6WkgTKrJpRLkYYjsePRBRq4xFFJkD0U/82+UW653wEA3JLO3eoy6u8O
 2/0DEisPnzfMj42NIMlNFbDRd3FHwg8=
 =h28h
 -----END PGP SIGNATURE-----

Merge tag 'ata-6.17-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux

Pull ata fixes from Damien Le Moal:

 - Cleanup whitespace in messages in libata-core and the pata_pdc2027x,
   pata_macio drivers (Colin)

 - Fix ata_to_sense_error() to avoid seeing nonsensical sense data for
   rare cases where we fail to get sense data from the drive. The
   complementary fix to this is to ensure that we always return the
   generic "ABORTED COMMAND" sense data for a failed command for which
   we have no status or error fields

 - The recent changes to link power management (LPM) which now prevent
   the user from attempting to set an LPM policy through the
   link_power_management_policy caused some regressions in test
   environments because of the error that is now returned when writing
   to that attribute when LPM is not supported. To allow users to not
   trip on this, introduce the new link_power_management_supported
   attribute to allow simple testing of a port/device LPM support (me)

* tag 'ata-6.17-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux:
  ata: pata_pdc2027x: Remove space before newline and abbreviations
  ata: pata_macio: Remove space before newline
  ata: libata-core: Remove space before newline
  ata: libata-sata: Add link_power_management_supported sysfs attribute
  ata: libata-scsi: Return aborted command when missing sense and result TF
  ata: libata-scsi: Fix ata_to_sense_error() status handling
This commit is contained in:
Linus Torvalds 2025-08-06 08:52:59 +03:00
commit 479058002c
8 changed files with 71 additions and 39 deletions

View file

@ -1089,6 +1089,7 @@ static struct ata_port_operations ich_pata_ops = {
};
static struct attribute *piix_sidpr_shost_attrs[] = {
&dev_attr_link_power_management_supported.attr,
&dev_attr_link_power_management_policy.attr,
NULL
};

View file

@ -111,6 +111,7 @@ static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
static struct attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_supported.attr,
&dev_attr_link_power_management_policy.attr,
&dev_attr_em_message_type.attr,
&dev_attr_em_message.attr,

View file

@ -4602,7 +4602,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
return AC_ERR_INVALID;
/* set up init dev params taskfile */
ata_dev_dbg(dev, "init dev params \n");
ata_dev_dbg(dev, "init dev params\n");
ata_tf_init(dev, &tf);
tf.command = ATA_CMD_INIT_DEV_PARAMS;

View file

@ -900,14 +900,52 @@ static const char *ata_lpm_policy_names[] = {
[ATA_LPM_MIN_POWER] = "min_power",
};
/*
* Check if a port supports link power management.
* Must be called with the port locked.
*/
static bool ata_scsi_lpm_supported(struct ata_port *ap)
{
struct ata_link *link;
struct ata_device *dev;
if (ap->flags & ATA_FLAG_NO_LPM)
return false;
ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, &ap->link, ENABLED) {
if (dev->quirks & ATA_QUIRK_NOLPM)
return false;
}
}
return true;
}
static ssize_t ata_scsi_lpm_supported_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
unsigned long flags;
bool supported;
spin_lock_irqsave(ap->lock, flags);
supported = ata_scsi_lpm_supported(ap);
spin_unlock_irqrestore(ap->lock, flags);
return sysfs_emit(buf, "%d\n", supported);
}
DEVICE_ATTR(link_power_management_supported, S_IRUGO,
ata_scsi_lpm_supported_show, NULL);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_supported);
static ssize_t ata_scsi_lpm_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(device);
struct ata_port *ap = ata_shost_to_port(shost);
struct ata_link *link;
struct ata_device *dev;
enum ata_lpm_policy policy;
unsigned long flags;
@ -924,20 +962,11 @@ static ssize_t ata_scsi_lpm_store(struct device *device,
spin_lock_irqsave(ap->lock, flags);
if (ap->flags & ATA_FLAG_NO_LPM) {
if (!ata_scsi_lpm_supported(ap)) {
count = -EOPNOTSUPP;
goto out_unlock;
}
ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, &ap->link, ENABLED) {
if (dev->quirks & ATA_QUIRK_NOLPM) {
count = -EOPNOTSUPP;
goto out_unlock;
}
}
}
ap->target_lpm_policy = policy;
ata_port_schedule_eh(ap);
out_unlock:

View file

@ -859,18 +859,14 @@ static void ata_to_sense_error(u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
};
static const unsigned char stat_table[][4] = {
/* Must be first because BUSY means no other bits valid */
{0x80, ABORTED_COMMAND, 0x47, 0x00},
// Busy, fake parity for now
{0x40, ILLEGAL_REQUEST, 0x21, 0x04},
// Device ready, unaligned write command
{0x20, HARDWARE_ERROR, 0x44, 0x00},
// Device fault, internal target failure
{0x08, ABORTED_COMMAND, 0x47, 0x00},
// Timed out in xfer, fake parity for now
{0x04, RECOVERED_ERROR, 0x11, 0x00},
// Recovered ECC error Medium error, recovered
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
/* Busy: must be first because BUSY means no other bits valid */
{ ATA_BUSY, ABORTED_COMMAND, 0x00, 0x00 },
/* Device fault: INTERNAL TARGET FAILURE */
{ ATA_DF, HARDWARE_ERROR, 0x44, 0x00 },
/* Corrected data error */
{ ATA_CORR, RECOVERED_ERROR, 0x00, 0x00 },
{ 0xFF, 0xFF, 0xFF, 0xFF }, /* END mark */
};
/*
@ -942,6 +938,8 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) {
ata_dev_dbg(dev,
"missing result TF: can't generate ATA PT sense data\n");
if (qc->err_mask)
ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0);
return;
}
@ -996,8 +994,8 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) {
ata_dev_dbg(dev,
"missing result TF: can't generate sense data\n");
return;
"Missing result TF: reporting aborted command\n");
goto aborted;
}
/* Use ata_to_sense_error() to map status register bits
@ -1008,13 +1006,15 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
ata_to_sense_error(tf->status, tf->error,
&sense_key, &asc, &ascq);
ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq);
} else {
/* Could not decode error */
ata_dev_warn(dev, "could not decode error status 0x%x err_mask 0x%x\n",
tf->status, qc->err_mask);
ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0);
return;
}
/* Could not decode error */
ata_dev_warn(dev,
"Could not decode error 0x%x, status 0x%x (err_mask=0x%x)\n",
tf->error, tf->status, qc->err_mask);
aborted:
ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0);
}
void ata_scsi_sdev_config(struct scsi_device *sdev)

View file

@ -758,7 +758,7 @@ static void pata_macio_irq_clear(struct ata_port *ap)
static void pata_macio_reset_hw(struct pata_macio_priv *priv, int resume)
{
dev_dbg(priv->dev, "Enabling & resetting... \n");
dev_dbg(priv->dev, "Enabling & resetting...\n");
if (priv->mediabay)
return;

View file

@ -295,7 +295,7 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
/* Set the PIO timing registers using value table for 133MHz */
ata_port_dbg(ap, "Set pio regs... \n");
ata_port_dbg(ap, "Set PIO regs...\n");
ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0xffff0000;
@ -308,7 +308,7 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
ata_port_dbg(ap, "Set to pio mode[%u] \n", pio);
ata_port_dbg(ap, "Set to PIO mode[%u]\n", pio);
}
/**
@ -341,7 +341,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
}
ata_port_dbg(ap, "Set udma regs... \n");
ata_port_dbg(ap, "Set UDMA regs...\n");
ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0xff000000;
@ -350,14 +350,14 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
(pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
ata_port_dbg(ap, "Set to udma mode[%u] \n", udma_mode);
ata_port_dbg(ap, "Set to UDMA mode[%u]\n", udma_mode);
} else if ((dma_mode >= XFER_MW_DMA_0) &&
(dma_mode <= XFER_MW_DMA_2)) {
/* Set the MDMA timing registers with value table for 133MHz */
unsigned int mdma_mode = dma_mode & 0x07;
ata_port_dbg(ap, "Set mdma regs... \n");
ata_port_dbg(ap, "Set MDMA regs...\n");
ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0x0000ffff;
@ -366,7 +366,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
ata_port_dbg(ap, "Set to mdma mode[%u] \n", mdma_mode);
ata_port_dbg(ap, "Set to MDMA mode[%u]\n", mdma_mode);
} else {
ata_port_err(ap, "Unknown dma mode [%u] ignored\n", dma_mode);
}

View file

@ -545,6 +545,7 @@ typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes)
extern struct device_attribute dev_attr_unload_heads;
#ifdef CONFIG_SATA_HOST
extern struct device_attribute dev_attr_link_power_management_supported;
extern struct device_attribute dev_attr_link_power_management_policy;
extern struct device_attribute dev_attr_ncq_prio_supported;
extern struct device_attribute dev_attr_ncq_prio_enable;