Commit abeded46 authored by Igor Pylypiv's avatar Igor Pylypiv Committed by Martin K. Petersen

scsi: ata: libata-sata: Factor out NCQ Priority configuration helpers

Export libata NCQ Priority configuration helpers to be reused for libsas
managed SATA devices.

Switched locking from spin_lock_irq() to spin_lock_irqsave().  In the
future someone might call these helper functions when interrupts are
disabled. spin_unlock_irq() could lead to a premature re-enabling of
interrupts, whereas spin_unlock_irqrestore() restores the interrupt state
to its condition prior to the spin_lock_irqsave() call.
Acked-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarIgor Pylypiv <ipylypiv@google.com>
Link: https://lore.kernel.org/r/20240307214418.3812290-2-ipylypiv@google.comReviewed-by: default avatarNiklas Cassel <cassel@kernel.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 4cece764
...@@ -848,80 +848,143 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ...@@ -848,80 +848,143 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_store); ata_scsi_lpm_show, ata_scsi_lpm_store);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
static ssize_t ata_ncq_prio_supported_show(struct device *device, /**
struct device_attribute *attr, * ata_ncq_prio_supported - Check if device supports NCQ Priority
char *buf) * @ap: ATA port of the target device
* @sdev: SCSI device
* @supported: Address of a boolean to store the result
*
* Helper to check if device supports NCQ Priority feature.
*
* Context: Any context. Takes and releases @ap->lock.
*
* Return:
* * %0 - OK. Status is stored into @supported
* * %-ENODEV - Failed to find the ATA device
*/
int ata_ncq_prio_supported(struct ata_port *ap, struct scsi_device *sdev,
bool *supported)
{ {
struct scsi_device *sdev = to_scsi_device(device);
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev; struct ata_device *dev;
bool ncq_prio_supported; unsigned long flags;
int rc = 0; int rc = 0;
spin_lock_irq(ap->lock); spin_lock_irqsave(ap->lock, flags);
dev = ata_scsi_find_dev(ap, sdev); dev = ata_scsi_find_dev(ap, sdev);
if (!dev) if (!dev)
rc = -ENODEV; rc = -ENODEV;
else else
ncq_prio_supported = dev->flags & ATA_DFLAG_NCQ_PRIO; *supported = dev->flags & ATA_DFLAG_NCQ_PRIO;
spin_unlock_irq(ap->lock); spin_unlock_irqrestore(ap->lock, flags);
return rc;
}
EXPORT_SYMBOL_GPL(ata_ncq_prio_supported);
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);
bool supported;
int rc;
rc = ata_ncq_prio_supported(ap, sdev, &supported);
if (rc)
return rc;
return rc ? rc : sysfs_emit(buf, "%u\n", ncq_prio_supported); return sysfs_emit(buf, "%d\n", supported);
} }
DEVICE_ATTR(ncq_prio_supported, S_IRUGO, ata_ncq_prio_supported_show, NULL); DEVICE_ATTR(ncq_prio_supported, S_IRUGO, ata_ncq_prio_supported_show, NULL);
EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_supported); EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_supported);
static ssize_t ata_ncq_prio_enable_show(struct device *device, /**
struct device_attribute *attr, * ata_ncq_prio_enabled - Check if NCQ Priority is enabled
char *buf) * @ap: ATA port of the target device
* @sdev: SCSI device
* @enabled: Address of a boolean to store the result
*
* Helper to check if NCQ Priority feature is enabled.
*
* Context: Any context. Takes and releases @ap->lock.
*
* Return:
* * %0 - OK. Status is stored into @enabled
* * %-ENODEV - Failed to find the ATA device
*/
int ata_ncq_prio_enabled(struct ata_port *ap, struct scsi_device *sdev,
bool *enabled)
{ {
struct scsi_device *sdev = to_scsi_device(device);
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev; struct ata_device *dev;
bool ncq_prio_enable; unsigned long flags;
int rc = 0; int rc = 0;
spin_lock_irq(ap->lock); spin_lock_irqsave(ap->lock, flags);
dev = ata_scsi_find_dev(ap, sdev); dev = ata_scsi_find_dev(ap, sdev);
if (!dev) if (!dev)
rc = -ENODEV; rc = -ENODEV;
else else
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED; *enabled = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
spin_unlock_irq(ap->lock); spin_unlock_irqrestore(ap->lock, flags);
return rc ? rc : sysfs_emit(buf, "%u\n", ncq_prio_enable); return rc;
} }
EXPORT_SYMBOL_GPL(ata_ncq_prio_enabled);
static ssize_t ata_ncq_prio_enable_store(struct device *device, static ssize_t ata_ncq_prio_enable_show(struct device *device,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t len) char *buf)
{ {
struct scsi_device *sdev = to_scsi_device(device); 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 enabled;
long int input; int rc;
int rc = 0;
rc = kstrtol(buf, 10, &input); rc = ata_ncq_prio_enabled(ap, sdev, &enabled);
if (rc) if (rc)
return rc; return rc;
if ((input < 0) || (input > 1))
return -EINVAL;
ap = ata_shost_to_port(sdev->host); return sysfs_emit(buf, "%d\n", enabled);
dev = ata_scsi_find_dev(ap, sdev); }
if (unlikely(!dev))
return -ENODEV; /**
* ata_ncq_prio_enable - Enable/disable NCQ Priority
* @ap: ATA port of the target device
* @sdev: SCSI device
* @enable: true - enable NCQ Priority, false - disable NCQ Priority
*
* Helper to enable/disable NCQ Priority feature.
*
* Context: Any context. Takes and releases @ap->lock.
*
* Return:
* * %0 - OK. Status is stored into @enabled
* * %-ENODEV - Failed to find the ATA device
* * %-EINVAL - NCQ Priority is not supported or CDL is enabled
*/
int ata_ncq_prio_enable(struct ata_port *ap, struct scsi_device *sdev,
bool enable)
{
struct ata_device *dev;
unsigned long flags;
int rc = 0;
spin_lock_irqsave(ap->lock, flags);
spin_lock_irq(ap->lock); dev = ata_scsi_find_dev(ap, sdev);
if (!dev) {
rc = -ENODEV;
goto unlock;
}
if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) { if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) {
rc = -EINVAL; rc = -EINVAL;
goto unlock; goto unlock;
} }
if (input) { if (enable) {
if (dev->flags & ATA_DFLAG_CDL_ENABLED) { if (dev->flags & ATA_DFLAG_CDL_ENABLED) {
ata_dev_err(dev, ata_dev_err(dev,
"CDL must be disabled to enable NCQ priority\n"); "CDL must be disabled to enable NCQ priority\n");
...@@ -934,9 +997,30 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device, ...@@ -934,9 +997,30 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
} }
unlock: unlock:
spin_unlock_irq(ap->lock); spin_unlock_irqrestore(ap->lock, flags);
return rc;
}
EXPORT_SYMBOL_GPL(ata_ncq_prio_enable);
static ssize_t ata_ncq_prio_enable_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct scsi_device *sdev = to_scsi_device(device);
struct ata_port *ap = ata_shost_to_port(sdev->host);
bool enable;
int rc;
rc = kstrtobool(buf, &enable);
if (rc)
return rc;
rc = ata_ncq_prio_enable(ap, sdev, enable);
if (rc)
return rc;
return rc ? rc : len; return len;
} }
DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR, DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
......
...@@ -1157,6 +1157,12 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, ...@@ -1157,6 +1157,12 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
int queue_depth); int queue_depth);
extern int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev, extern int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
int queue_depth); int queue_depth);
extern int ata_ncq_prio_supported(struct ata_port *ap, struct scsi_device *sdev,
bool *supported);
extern int ata_ncq_prio_enabled(struct ata_port *ap, struct scsi_device *sdev,
bool *enabled);
extern int ata_ncq_prio_enable(struct ata_port *ap, struct scsi_device *sdev,
bool enable);
extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern struct ata_device *ata_dev_pair(struct ata_device *adev);
extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment