mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
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: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Jason Yan <yanaijie@huawei.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Igor Pylypiv <ipylypiv@google.com> Link: https://lore.kernel.org/r/20240307214418.3812290-2-ipylypiv@google.com Reviewed-by: Niklas Cassel <cassel@kernel.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
4cece76496
commit
abeded46bc
@ -848,80 +848,143 @@ 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);
|
||||
|
||||
/**
|
||||
* ata_ncq_prio_supported - Check if device supports NCQ Priority
|
||||
* @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 ata_device *dev;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
dev = ata_scsi_find_dev(ap, sdev);
|
||||
if (!dev)
|
||||
rc = -ENODEV;
|
||||
else
|
||||
*supported = dev->flags & ATA_DFLAG_NCQ_PRIO;
|
||||
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);
|
||||
struct ata_device *dev;
|
||||
bool ncq_prio_supported;
|
||||
int rc = 0;
|
||||
bool supported;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
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);
|
||||
EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_supported);
|
||||
|
||||
/**
|
||||
* ata_ncq_prio_enabled - Check if NCQ Priority is enabled
|
||||
* @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 ata_device *dev;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
dev = ata_scsi_find_dev(ap, sdev);
|
||||
if (!dev)
|
||||
rc = -ENODEV;
|
||||
else
|
||||
*enabled = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_ncq_prio_enabled);
|
||||
|
||||
static ssize_t ata_ncq_prio_enable_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_enable;
|
||||
int rc = 0;
|
||||
bool enabled;
|
||||
int rc;
|
||||
|
||||
spin_lock_irq(ap->lock);
|
||||
dev = ata_scsi_find_dev(ap, sdev);
|
||||
if (!dev)
|
||||
rc = -ENODEV;
|
||||
else
|
||||
ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
spin_unlock_irq(ap->lock);
|
||||
|
||||
return rc ? rc : sysfs_emit(buf, "%u\n", 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;
|
||||
struct ata_device *dev;
|
||||
long int input;
|
||||
int rc = 0;
|
||||
|
||||
rc = kstrtol(buf, 10, &input);
|
||||
rc = ata_ncq_prio_enabled(ap, sdev, &enabled);
|
||||
if (rc)
|
||||
return rc;
|
||||
if ((input < 0) || (input > 1))
|
||||
return -EINVAL;
|
||||
|
||||
ap = ata_shost_to_port(sdev->host);
|
||||
return sysfs_emit(buf, "%d\n", enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
dev = ata_scsi_find_dev(ap, sdev);
|
||||
if (unlikely(!dev))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_irq(ap->lock);
|
||||
if (!dev) {
|
||||
rc = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) {
|
||||
rc = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (input) {
|
||||
if (enable) {
|
||||
if (dev->flags & ATA_DFLAG_CDL_ENABLED) {
|
||||
ata_dev_err(dev,
|
||||
"CDL must be disabled to enable NCQ priority\n");
|
||||
@ -934,9 +997,30 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(ap->lock);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
return rc ? rc : len;
|
||||
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 len;
|
||||
}
|
||||
|
||||
DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
|
||||
|
@ -1157,6 +1157,12 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
|
||||
int queue_depth);
|
||||
extern int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
|
||||
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 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);
|
||||
|
Loading…
Reference in New Issue
Block a user