From 3ad4a31620355358316fa08fcfab37b9d6c33347 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 27 Jul 2021 15:51:30 +0300 Subject: [PATCH 01/12] ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init() Last change to device managed APIs cleaned up error path to simple phy_exit() call, which in some cases has been executed with NULL parameter. This per se is not a problem, but rather logical misconception: no need to free resource when it's for sure has not been allocated yet. Fix the driver accordingly. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210727125130.19977-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jens Axboe --- drivers/ata/sata_dwc_460ex.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index f0ef844428bb..338c2e50f759 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1259,24 +1259,20 @@ static int sata_dwc_probe(struct platform_device *ofdev) irq = irq_of_parse_and_map(np, 0); if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); - err = -ENODEV; - goto error_out; + return -ENODEV; } #ifdef CONFIG_SATA_DWC_OLD_DMA if (!of_find_property(np, "dmas", NULL)) { err = sata_dwc_dma_init_old(ofdev, hsdev); if (err) - goto error_out; + return err; } #endif hsdev->phy = devm_phy_optional_get(hsdev->dev, "sata-phy"); - if (IS_ERR(hsdev->phy)) { - err = PTR_ERR(hsdev->phy); - hsdev->phy = NULL; - goto error_out; - } + if (IS_ERR(hsdev->phy)) + return PTR_ERR(hsdev->phy); err = phy_init(hsdev->phy); if (err) From 355a8031dc174450ccad2a61c513ad7222d87a97 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:47 +0900 Subject: [PATCH 02/12] libata: fix ata_host_start() The loop on entry of ata_host_start() may not initialize host->ops to a non NULL value. The test on the host_stop field of host->ops must then be preceded by a check that host->ops is not NULL. Reported-by: kernel test robot Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-3-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 61c762961ca8..44f434acfce0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5573,7 +5573,7 @@ int ata_host_start(struct ata_host *host) have_stop = 1; } - if (host->ops->host_stop) + if (host->ops && host->ops->host_stop) have_stop = 1; if (have_stop) { From 56b4f06c55add95fe508a1746d9173bade6388bf Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:48 +0900 Subject: [PATCH 03/12] libata: simplify ata_scsi_rbuf_fill() Sparse complains about context imbalance in ata_scsi_rbuf_get() and ata_scsi_rbuf_put() due to these functions respectively only taking and releasing the ata_scsi_rbuf_lock spinlock. Since these functions are only called from ata_scsi_rbuf_fill() with ata_scsi_rbuf_get() being called with a copy_in argument always false, the code can be simplified and ata_scsi_rbuf_{get|put} removed. This change both simplifies the code and fixes the sparse warning. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-4-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-scsi.c | 60 ++++++--------------------------------- 1 file changed, 9 insertions(+), 51 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b9588c52815d..0b7b4624e4df 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1765,53 +1765,6 @@ struct ata_scsi_args { struct scsi_cmnd *cmd; }; -/** - * ata_scsi_rbuf_get - Map response buffer. - * @cmd: SCSI command containing buffer to be mapped. - * @flags: unsigned long variable to store irq enable status - * @copy_in: copy in from user buffer - * - * Prepare buffer for simulated SCSI commands. - * - * LOCKING: - * spin_lock_irqsave(ata_scsi_rbuf_lock) on success - * - * RETURNS: - * Pointer to response buffer. - */ -static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in, - unsigned long *flags) -{ - spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags); - - memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); - if (copy_in) - sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); - return ata_scsi_rbuf; -} - -/** - * ata_scsi_rbuf_put - Unmap response buffer. - * @cmd: SCSI command containing buffer to be unmapped. - * @copy_out: copy out result - * @flags: @flags passed to ata_scsi_rbuf_get() - * - * Returns rbuf buffer. The result is copied to @cmd's buffer if - * @copy_back is true. - * - * LOCKING: - * Unlocks ata_scsi_rbuf_lock. - */ -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, - unsigned long *flags) -{ - if (copy_out) - sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); - spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags); -} - /** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators * @args: device IDENTIFY data / SCSI command of interest. @@ -1830,14 +1783,19 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) { - u8 *rbuf; unsigned int rc; struct scsi_cmnd *cmd = args->cmd; unsigned long flags; - rbuf = ata_scsi_rbuf_get(cmd, false, &flags); - rc = actor(args, rbuf); - ata_scsi_rbuf_put(cmd, rc == 0, &flags); + spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); + + memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); + rc = actor(args, ata_scsi_rbuf); + if (rc == 0) + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); if (rc == 0) cmd->result = SAM_STAT_GOOD; From d8d8778c24cc4689250b59c426489a360032d912 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:49 +0900 Subject: [PATCH 04/12] libata: cleanup device sleep capability detection Move the code to retrieve the device sleep capability and timings out of ata_dev_configure() into the helper function ata_dev_config_devslp(). While at it, mark the device as supporting the device sleep capability only if the sata settings page was retrieved successfully to ensure that the timing information is correctly initialized. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-5-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 55 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 44f434acfce0..f96cd2f931bd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2363,6 +2363,37 @@ static void ata_dev_config_trusted(struct ata_device *dev) dev->flags |= ATA_DFLAG_TRUSTED; } +static void ata_dev_config_devslp(struct ata_device *dev) +{ + u8 *sata_setting = dev->link->ap->sector_buf; + unsigned int err_mask; + int i, j; + + /* + * Check device sleep capability. Get DevSlp timing variables + * from SATA Settings page of Identify Device Data Log. + */ + if (!ata_id_has_devslp(dev->id)) + return; + + err_mask = ata_read_log_page(dev, + ATA_LOG_IDENTIFY_DEVICE, + ATA_LOG_SATA_SETTINGS, + sata_setting, 1); + if (err_mask) { + ata_dev_dbg(dev, + "failed to get SATA Settings Log, Emask 0x%x\n", + err_mask); + return; + } + + dev->flags |= ATA_DFLAG_DEVSLP; + for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) { + j = ATA_LOG_DEVSLP_OFFSET + i; + dev->devslp_timing[i] = sata_setting[j]; + } +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -2565,29 +2596,7 @@ int ata_dev_configure(struct ata_device *dev) } } - /* Check and mark DevSlp capability. Get DevSlp timing variables - * from SATA Settings page of Identify Device Data Log. - */ - if (ata_id_has_devslp(dev->id)) { - u8 *sata_setting = ap->sector_buf; - int i, j; - - dev->flags |= ATA_DFLAG_DEVSLP; - err_mask = ata_read_log_page(dev, - ATA_LOG_IDENTIFY_DEVICE, - ATA_LOG_SATA_SETTINGS, - sata_setting, - 1); - if (err_mask) - ata_dev_dbg(dev, - "failed to get Identify Device Data, Emask 0x%x\n", - err_mask); - else - for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) { - j = ATA_LOG_DEVSLP_OFFSET + i; - dev->devslp_timing[i] = sata_setting[j]; - } - } + ata_dev_config_devslp(dev); ata_dev_config_sense_reporting(dev); ata_dev_config_zac(dev); ata_dev_config_trusted(dev); From 891fd7c61952ed3fddb82a3b00ae4b3edfce8733 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:50 +0900 Subject: [PATCH 05/12] libata: cleanup ata_dev_configure() Introduce the helper functions ata_dev_config_lba() and ata_dev_config_chs() to configure the addressing capabilities of a device. To control message printing in these new helpers, as well as in ata_dev_configure() and in ata_hpa_resize(), add the helper function ata_dev_print_info() to avoid open coding for the eh context ATA_EHI_PRINTINFO flag in multiple functions. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-6-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 131 ++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f96cd2f931bd..f600ea16a92c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -159,6 +159,12 @@ MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +static inline bool ata_dev_print_info(struct ata_device *dev) +{ + struct ata_eh_context *ehc = &dev->link->eh_context; + + return ehc->i.flags & ATA_EHI_PRINTINFO; +} static bool ata_sstatus_online(u32 sstatus) { @@ -1266,8 +1272,7 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) */ static int ata_hpa_resize(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->link->eh_context; - int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; + bool print_info = ata_dev_print_info(dev); bool unlock_hpa = ata_ignore_hpa || dev->flags & ATA_DFLAG_UNLOCK_HPA; u64 sectors = ata_id_n_sectors(dev->id); u64 native_sectors; @@ -2363,6 +2368,65 @@ static void ata_dev_config_trusted(struct ata_device *dev) dev->flags |= ATA_DFLAG_TRUSTED; } +static int ata_dev_config_lba(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + const u16 *id = dev->id; + const char *lba_desc; + char ncq_desc[24]; + int ret; + + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(id)) { + lba_desc = "LBA48"; + dev->flags |= ATA_DFLAG_LBA48; + if (dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + dev->flags |= ATA_DFLAG_FLUSH_EXT; + } else { + lba_desc = "LBA"; + } + + /* config NCQ */ + ret = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + + /* print device info to dmesg */ + if (ata_msg_drv(ap) && ata_dev_print_info(dev)) + ata_dev_info(dev, + "%llu sectors, multi %u: %s %s\n", + (unsigned long long)dev->n_sectors, + dev->multi_count, lba_desc, ncq_desc); + + return ret; +} + +static void ata_dev_config_chs(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + const u16 *id = dev->id; + + if (ata_id_current_chs_valid(id)) { + /* Current CHS translation is valid. */ + dev->cylinders = id[54]; + dev->heads = id[55]; + dev->sectors = id[56]; + } else { + /* Default translation */ + dev->cylinders = id[1]; + dev->heads = id[3]; + dev->sectors = id[6]; + } + + /* print device info to dmesg */ + if (ata_msg_drv(ap) && ata_dev_print_info(dev)) + ata_dev_info(dev, + "%llu sectors, multi %u, CHS %u/%u/%u\n", + (unsigned long long)dev->n_sectors, + dev->multi_count, dev->cylinders, + dev->heads, dev->sectors); +} + static void ata_dev_config_devslp(struct ata_device *dev) { u8 *sata_setting = dev->link->ap->sector_buf; @@ -2410,8 +2474,7 @@ static void ata_dev_config_devslp(struct ata_device *dev) int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; - struct ata_eh_context *ehc = &dev->link->eh_context; - int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; + bool print_info = ata_dev_print_info(dev); const u16 *id = dev->id; unsigned long xfer_mask; unsigned int err_mask; @@ -2538,62 +2601,18 @@ int ata_dev_configure(struct ata_device *dev) dev->multi_count = cnt; } + /* print device info to dmesg */ + if (ata_msg_drv(ap) && print_info) + ata_dev_info(dev, "%s: %s, %s, max %s\n", + revbuf, modelbuf, fwrevbuf, + ata_mode_string(xfer_mask)); + if (ata_id_has_lba(id)) { - const char *lba_desc; - char ncq_desc[24]; - - lba_desc = "LBA"; - dev->flags |= ATA_DFLAG_LBA; - if (ata_id_has_lba48(id)) { - dev->flags |= ATA_DFLAG_LBA48; - lba_desc = "LBA48"; - - if (dev->n_sectors >= (1UL << 28) && - ata_id_has_flush_ext(id)) - dev->flags |= ATA_DFLAG_FLUSH_EXT; - } - - /* config NCQ */ - rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + rc = ata_dev_config_lba(dev); if (rc) return rc; - - /* print device info to dmesg */ - if (ata_msg_drv(ap) && print_info) { - ata_dev_info(dev, "%s: %s, %s, max %s\n", - revbuf, modelbuf, fwrevbuf, - ata_mode_string(xfer_mask)); - ata_dev_info(dev, - "%llu sectors, multi %u: %s %s\n", - (unsigned long long)dev->n_sectors, - dev->multi_count, lba_desc, ncq_desc); - } } else { - /* CHS */ - - /* Default translation */ - dev->cylinders = id[1]; - dev->heads = id[3]; - dev->sectors = id[6]; - - if (ata_id_current_chs_valid(id)) { - /* Current CHS translation is valid. */ - dev->cylinders = id[54]; - dev->heads = id[55]; - dev->sectors = id[56]; - } - - /* print device info to dmesg */ - if (ata_msg_drv(ap) && print_info) { - ata_dev_info(dev, "%s: %s, %s, max %s\n", - revbuf, modelbuf, fwrevbuf, - ata_mode_string(xfer_mask)); - ata_dev_info(dev, - "%llu sectors, multi %u, CHS %u/%u/%u\n", - (unsigned long long)dev->n_sectors, - dev->multi_count, dev->cylinders, - dev->heads, dev->sectors); - } + ata_dev_config_chs(dev); } ata_dev_config_devslp(dev); From 2360fa1812cd77e1de13d3cca789fbd23462b651 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:51 +0900 Subject: [PATCH 06/12] libata: cleanup NCQ priority handling The ata device flag ATA_DFLAG_NCQ_PRIO indicates if a device supports the NCQ Priority feature while the ATA_DFLAG_NCQ_PRIO_ENABLE device flag indicates if the feature is enabled. Enabling NCQ priority use is controlled by the user through the device sysfs attribute ncq_prio_enable. As a result, the ATA_DFLAG_NCQ_PRIO flag should not be cleared when ATA_DFLAG_NCQ_PRIO_ENABLE is not set as the device still supports the feature even after the user disables it. This leads to the following cleanups: - In ata_build_rw_tf(), set a command high priority bit based on the ATA_DFLAG_NCQ_PRIO_ENABLE flag, not on the ATA_DFLAG_NCQ flag. That is, set a command high priority only if the user enabled NCQ priority use. - In ata_dev_config_ncq_prio(), ATA_DFLAG_NCQ_PRIO should not be cleared if ATA_DFLAG_NCQ_PRIO_ENABLE is not set. If the device does not support NCQ priority, both ATA_DFLAG_NCQ_PRIO and ATA_DFLAG_NCQ_PRIO_ENABLE must be cleared. With the above ata_dev_config_ncq_prio() change, ATA_DFLAG_NCQ_PRIO flag is set on device scan and revalidation. There is no need to trigger a device revalidation in ata_ncq_prio_enable_store() when the user enables the use of NCQ priority. Remove the revalidation code from that funciton to simplify it. Also change the return value from -EIO to -EINVAL when a user tries to enable NCQ priority for a device that does not support this feature. While at it, also simplify ata_ncq_prio_enable_show(). Overall, there is no functional change introduced by this patch. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-7-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 32 ++++++++++++++------------------ drivers/ata/libata-sata.c | 37 ++++++++++++------------------------- 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f600ea16a92c..f285a2bc8799 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -712,11 +712,9 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, if (tf->flags & ATA_TFLAG_FUA) tf->device |= 1 << 7; - if (dev->flags & ATA_DFLAG_NCQ_PRIO) { - if (class == IOPRIO_CLASS_RT) - tf->hob_nsect |= ATA_PRIO_HIGH << - ATA_SHIFT_PRIO; - } + if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE && + class == IOPRIO_CLASS_RT) + tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO; } else if (dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; @@ -2178,11 +2176,6 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev) struct ata_port *ap = dev->link->ap; unsigned int err_mask; - if (!(dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE)) { - dev->flags &= ~ATA_DFLAG_NCQ_PRIO; - return; - } - err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SATA_SETTINGS, @@ -2190,18 +2183,21 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev) 1); if (err_mask) { ata_dev_dbg(dev, - "failed to get Identify Device data, Emask 0x%x\n", + "failed to get SATA settings log, Emask 0x%x\n", err_mask); - return; + goto not_supported; } - if (ap->sector_buf[ATA_LOG_NCQ_PRIO_OFFSET] & BIT(3)) { - dev->flags |= ATA_DFLAG_NCQ_PRIO; - } else { - dev->flags &= ~ATA_DFLAG_NCQ_PRIO; - ata_dev_dbg(dev, "SATA page does not support priority\n"); - } + if (!(ap->sector_buf[ATA_LOG_NCQ_PRIO_OFFSET] & BIT(3))) + goto not_supported; + dev->flags |= ATA_DFLAG_NCQ_PRIO; + + return; + +not_supported: + dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE; + dev->flags &= ~ATA_DFLAG_NCQ_PRIO; } static int ata_dev_config_ncq(struct ata_device *dev, diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 8adeab76dd38..dc397ebda089 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -839,23 +839,17 @@ static ssize_t ata_ncq_prio_enable_show(struct device *device, char *buf) { struct scsi_device *sdev = to_scsi_device(device); - struct ata_port *ap; + struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev; bool ncq_prio_enable; int rc = 0; - ap = ata_shost_to_port(sdev->host); - spin_lock_irq(ap->lock); dev = ata_scsi_find_dev(ap, sdev); - if (!dev) { + if (!dev) rc = -ENODEV; - goto unlock; - } - - ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE; - -unlock: + else + ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE; spin_unlock_irq(ap->lock); return rc ? rc : snprintf(buf, 20, "%u\n", ncq_prio_enable); @@ -869,7 +863,7 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device, struct ata_port *ap; struct ata_device *dev; long int input; - int rc; + int rc = 0; rc = kstrtol(buf, 10, &input); if (rc) @@ -883,27 +877,20 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device, return -ENODEV; spin_lock_irq(ap->lock); + + if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) { + rc = -EINVAL; + goto unlock; + } + if (input) dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLE; else dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE; - dev->link->eh_info.action |= ATA_EH_REVALIDATE; - dev->link->eh_info.flags |= ATA_EHI_QUIET; - ata_port_schedule_eh(ap); +unlock: spin_unlock_irq(ap->lock); - ata_port_wait_eh(ap); - - if (input) { - spin_lock_irq(ap->lock); - if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) { - dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE; - rc = -EIO; - } - spin_unlock_irq(ap->lock); - } - return rc ? rc : len; } From fc5c8aa7bc4977205e0ceb93425075f8a8f49501 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:52 +0900 Subject: [PATCH 07/12] libata: fix ata_read_log_page() warning Support for the READ LOG PAGE DMA EXT command is indicated by words 119 and 120 of a device identify data. This is tested in ata_read_log_page() with ata_id_has_read_log_dma_ext() and the READ LOG PAGE DMA command used if the device reports supports for it. However, some devices lie about this support and using the DMA version of the command fails, generating the warning message "READ LOG DMA EXT failed, trying PIO". Since READ LOG PAGE DMA EXT is an optional command, this warning is not at all important but may be scary for the user. Change ata_read_log_page() to suppres this warning and to print an error message if both DMA and PIO attempts failed. With this change, there is no need to print again an error message when ata_read_log_page() returns an error. So simplify the users of this function. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-8-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 47 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f285a2bc8799..5befe6ce6039 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2026,13 +2026,15 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, buf, sectors * ATA_SECT_SIZE, 0); - if (err_mask && dma) { - dev->horkage |= ATA_HORKAGE_NO_DMA_LOG; - ata_dev_warn(dev, "READ LOG DMA EXT failed, trying PIO\n"); - goto retry; + if (err_mask) { + if (dma) { + dev->horkage |= ATA_HORKAGE_NO_DMA_LOG; + goto retry; + } + ata_dev_err(dev, "Read log page 0x%02x failed, Emask 0x%x\n", + (unsigned int)page, err_mask); } - DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; } @@ -2061,12 +2063,8 @@ static bool ata_identify_page_supported(struct ata_device *dev, u8 page) */ err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0, ap->sector_buf, 1); - if (err) { - ata_dev_info(dev, - "failed to get Device Identify Log Emask 0x%x\n", - err); + if (err) return false; - } for (i = 0; i < ap->sector_buf[8]; i++) { if (ap->sector_buf[9 + i] == page) @@ -2130,11 +2128,7 @@ static void ata_dev_config_ncq_send_recv(struct ata_device *dev) } err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV, 0, ap->sector_buf, 1); - if (err_mask) { - ata_dev_dbg(dev, - "failed to get NCQ Send/Recv Log Emask 0x%x\n", - err_mask); - } else { + if (!err_mask) { u8 *cmds = dev->ncq_send_recv_cmds; dev->flags |= ATA_DFLAG_NCQ_SEND_RECV; @@ -2160,11 +2154,7 @@ static void ata_dev_config_ncq_non_data(struct ata_device *dev) } err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_NON_DATA, 0, ap->sector_buf, 1); - if (err_mask) { - ata_dev_dbg(dev, - "failed to get NCQ Non-Data Log Emask 0x%x\n", - err_mask); - } else { + if (!err_mask) { u8 *cmds = dev->ncq_non_data_cmds; memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_NON_DATA_SIZE); @@ -2181,12 +2171,8 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev) ATA_LOG_SATA_SETTINGS, ap->sector_buf, 1); - if (err_mask) { - ata_dev_dbg(dev, - "failed to get SATA settings log, Emask 0x%x\n", - err_mask); + if (err_mask) goto not_supported; - } if (!(ap->sector_buf[ATA_LOG_NCQ_PRIO_OFFSET] & BIT(3))) goto not_supported; @@ -2347,11 +2333,8 @@ static void ata_dev_config_trusted(struct ata_device *dev) err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SECURITY, ap->sector_buf, 1); - if (err) { - ata_dev_dbg(dev, - "failed to read Security Log, Emask 0x%x\n", err); + if (err) return; - } trusted_cap = get_unaligned_le64(&ap->sector_buf[40]); if (!(trusted_cap & (1ULL << 63))) { @@ -2440,12 +2423,8 @@ static void ata_dev_config_devslp(struct ata_device *dev) ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SATA_SETTINGS, sata_setting, 1); - if (err_mask) { - ata_dev_dbg(dev, - "failed to get SATA Settings Log, Emask 0x%x\n", - err_mask); + if (err_mask) return; - } dev->flags |= ATA_DFLAG_DEVSLP; for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) { From d633b8a702ab2eb4ef9263f1ab1610bb8cdf71a5 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:53 +0900 Subject: [PATCH 08/12] libata: print feature list on device scan Print a list of features supported by a drive when it is configured in ata_dev_configure() using the new function ata_dev_print_features(). The features printed are not already advertized and are: trusted send-recev support, device attention support, device sleep support, NCQ send-recv support and NCQ priority support. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-9-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libata-core.c | 17 +++++++++++++++++ include/linux/libata.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5befe6ce6039..b8459c54f739 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2433,6 +2433,20 @@ static void ata_dev_config_devslp(struct ata_device *dev) } } +static void ata_dev_print_features(struct ata_device *dev) +{ + if (!(dev->flags & ATA_DFLAG_FEATURES_MASK)) + return; + + ata_dev_info(dev, + "Features:%s%s%s%s%s\n", + dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "", + dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "", + dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "", + dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "", + dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : ""); +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -2595,6 +2609,9 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_config_zac(dev); ata_dev_config_trusted(dev); dev->cdb_len = 32; + + if (ata_msg_drv(ap) && print_info) + ata_dev_print_features(dev); } /* ATAPI-specific feature tests */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 3fcd24236793..b23f28cfc8e0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -161,6 +161,10 @@ enum { ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */ ATA_DFLAG_ZAC = (1 << 30), /* ZAC device */ + ATA_DFLAG_FEATURES_MASK = ATA_DFLAG_TRUSTED | ATA_DFLAG_DA | \ + ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \ + ATA_DFLAG_NCQ_PRIO, + ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */ From 5f91b8f54874300a8e3c6c89f39ce5a74a449f2c Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:54 +0900 Subject: [PATCH 09/12] libata: Introduce ncq_prio_supported sysfs sttribute Currently, the only way a user can determine if a SATA device supports NCQ priority is to try to enable the use of this feature using the ncq_prio_enable sysfs device attribute. If enabling the feature fails, it is because the device does not support NCQ priority. Otherwise, the feature is enabled and success indicates that the device supports NCQ priority. Improve this odd interface by introducing the read-only ncq_prio_supported sysfs device attribute to indicate if a SATA device supports NCQ priority. The value of this attribute reflects the status of device flag ATA_DFLAG_NCQ_PRIO, which is set only for devices supporting NCQ priority. Add this new sysfs attribute to the device attributes group of libahci and libata-sata. Signed-off-by: Damien Le Moal Link: https://lore.kernel.org/r/20210816014456.2191776-10-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- drivers/ata/libahci.c | 1 + drivers/ata/libata-sata.c | 25 +++++++++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index fec2e9754aed..5b3fa2cbe722 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -125,6 +125,7 @@ EXPORT_SYMBOL_GPL(ahci_shost_attrs); struct device_attribute *ahci_sdev_attrs[] = { &dev_attr_sw_activity, &dev_attr_unload_heads, + &dev_attr_ncq_prio_supported, &dev_attr_ncq_prio_enable, NULL }; diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index dc397ebda089..8f3ff830ab0c 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -834,6 +834,30 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_store); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); +static ssize_t ata_ncq_prio_supported_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(device); + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + bool ncq_prio_supported; + int rc = 0; + + spin_lock_irq(ap->lock); + dev = ata_scsi_find_dev(ap, sdev); + if (!dev) + rc = -ENODEV; + else + ncq_prio_supported = dev->flags & ATA_DFLAG_NCQ_PRIO; + spin_unlock_irq(ap->lock); + + return rc ? rc : sysfs_emit(buf, "%u\n", ncq_prio_supported); +} + +DEVICE_ATTR(ncq_prio_supported, S_IRUGO, ata_ncq_prio_supported_show, NULL); +EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_supported); + static ssize_t ata_ncq_prio_enable_show(struct device *device, struct device_attribute *attr, char *buf) @@ -901,6 +925,7 @@ EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_enable); struct device_attribute *ata_ncq_sdev_attrs[] = { &dev_attr_unload_heads, &dev_attr_ncq_prio_enable, + &dev_attr_ncq_prio_supported, NULL }; EXPORT_SYMBOL_GPL(ata_ncq_sdev_attrs); diff --git a/include/linux/libata.h b/include/linux/libata.h index b23f28cfc8e0..a2d1bae7900b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -539,6 +539,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_policy; +extern struct device_attribute dev_attr_ncq_prio_supported; extern struct device_attribute dev_attr_ncq_prio_enable; extern struct device_attribute dev_attr_em_message_type; extern struct device_attribute dev_attr_em_message; From 5b8a2345e64b7c9ad00d1bd2d5081d14c574d989 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 16 Aug 2021 10:44:55 +0900 Subject: [PATCH 10/12] docs: sysfs-block-device: improve ncq_prio_enable documentation NCQ priority is an optional feature of the NCQ feature set and should not be confused with the NCQ feature set itself. Clarify the description of the ncq_prio_enable attribute to avoid this confusion. Also add the missing documentation for the equivalent sas_ncq_prio_enable attribute. Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-11-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block-device | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device index aa0fb500e3c9..cf1013df4b92 100644 --- a/Documentation/ABI/testing/sysfs-block-device +++ b/Documentation/ABI/testing/sysfs-block-device @@ -55,6 +55,20 @@ Date: Oct, 2016 KernelVersion: v4.10 Contact: linux-ide@vger.kernel.org Description: - (RW) Write to the file to turn on or off the SATA ncq (native - command queueing) support. By default this feature is turned - off. + (RW) Write to the file to turn on or off the SATA NCQ (native + command queueing) priority support. By default this feature is + turned off. If the device does not support the SATA NCQ + priority feature, writing "1" to this file results in an error. + + +What: /sys/block/*/device/sas_ncq_prio_enable +Date: Oct, 2016 +KernelVersion: v4.10 +Contact: linux-ide@vger.kernel.org +Description: + (RW) This is the equivalent of the ncq_prio_enable attribute + file for SATA devices connected to a SAS host-bus-adapter + (HBA) implementing support for the SATA NCQ priority feature. + This file does not exist if the HBA driver does not implement + support for the SATA NCQ priority feature, regardless of the + device support for this feature. From f5975d18d46ae8485bb08161086e59360844840b Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Mon, 16 Aug 2021 10:44:56 +0900 Subject: [PATCH 11/12] docs: sysfs-block-device: document ncq_prio_supported Add documentation for the new device attribute file ncq_prio_supported, and its SAS HBA equivalent sas_ncq_prio_supported. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Link: https://lore.kernel.org/r/20210816014456.2191776-12-damien.lemoal@wdc.com Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block-device | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device index cf1013df4b92..7ac7b19b2f72 100644 --- a/Documentation/ABI/testing/sysfs-block-device +++ b/Documentation/ABI/testing/sysfs-block-device @@ -58,7 +58,8 @@ Description: (RW) Write to the file to turn on or off the SATA NCQ (native command queueing) priority support. By default this feature is turned off. If the device does not support the SATA NCQ - priority feature, writing "1" to this file results in an error. + priority feature, writing "1" to this file results in an error + (see ncq_prio_supported). What: /sys/block/*/device/sas_ncq_prio_enable @@ -71,4 +72,26 @@ Description: (HBA) implementing support for the SATA NCQ priority feature. This file does not exist if the HBA driver does not implement support for the SATA NCQ priority feature, regardless of the + device support for this feature (see sas_ncq_prio_supported). + + +What: /sys/block/*/device/ncq_prio_supported +Date: Aug, 2021 +KernelVersion: v5.15 +Contact: linux-ide@vger.kernel.org +Description: + (RO) Indicates if the device supports the SATA NCQ (native + command queueing) priority feature. + + +What: /sys/block/*/device/sas_ncq_prio_supported +Date: Aug, 2021 +KernelVersion: v5.15 +Contact: linux-ide@vger.kernel.org +Description: + (RO) This is the equivalent of the ncq_prio_supported attribute + file for SATA devices connected to a SAS host-bus-adapter + (HBA) implementing support for the SATA NCQ priority feature. + This file does not exist if the HBA driver does not implement + support for the SATA NCQ priority feature, regardless of the device support for this feature. From 62283c6c9d4c1018badcd0b9c5b6ca66d978fa0d Mon Sep 17 00:00:00 2001 From: Jing Yangyang Date: Mon, 23 Aug 2021 23:07:02 -0700 Subject: [PATCH 12/12] include:libata: fix boolreturn.cocci warnings ./include/linux/libata.h:1462:8-9:WARNING: return of 0/1 in function 'ata_is_host_link' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Reported-by: Zeal Robot Signed-off-by: Jing Yangyang Link: https://lore.kernel.org/r/20210824060702.59006-1-deng.changcheng@zte.com.cn Signed-off-by: Jens Axboe --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index a2d1bae7900b..860e63f5667b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1459,7 +1459,7 @@ static inline bool sata_pmp_attached(struct ata_port *ap) static inline bool ata_is_host_link(const struct ata_link *link) { - return 1; + return true; } #endif /* CONFIG_SATA_PMP */