Skip to content

Commit

Permalink
Merge patch series "NCQ Priority sysfs sttributes for libsas"
Browse files Browse the repository at this point in the history
Igor Pylypiv <[email protected]> says:

This patch series adds ncq_prio_supported and ncq_prio_enable sysfs
attributes for libsas managed SATA devices. Existing libata sysfs
attributes cannot be used directly because the ata_port location is
different for libsas.

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Martin K. Petersen <[email protected]>
  • Loading branch information
martinkpetersen committed Mar 25, 2024
2 parents 5fcc60d + c65c436 commit e595ae7
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 38 deletions.
160 changes: 122 additions & 38 deletions drivers/ata/libata-sata.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

static ssize_t ata_ncq_prio_supported_show(struct device *device,
struct device_attribute *attr,
char *buf)
/**
* 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 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;
unsigned long flags;
int rc = 0;

spin_lock_irq(ap->lock);
spin_lock_irqsave(ap->lock, flags);
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);
*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);
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);
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)
/**
* 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 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;
unsigned long flags;
int rc = 0;

spin_lock_irq(ap->lock);
spin_lock_irqsave(ap->lock, flags);
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);
*enabled = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED;
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,
struct device_attribute *attr,
const char *buf, size_t len)
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;
struct ata_device *dev;
long int input;
int rc = 0;
struct ata_port *ap = ata_shost_to_port(sdev->host);
bool enabled;
int rc;

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);
dev = ata_scsi_find_dev(ap, sdev);
if (unlikely(!dev))
return -ENODEV;
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);

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)) {
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");
Expand All @@ -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;
}
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,
Expand Down
8 changes: 8 additions & 0 deletions drivers/scsi/aic94xx/aic94xx_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/firmware.h>
#include <linux/slab.h>

#include <scsi/sas_ata.h>
#include <scsi/scsi_host.h>

#include "aic94xx.h"
Expand All @@ -34,6 +35,7 @@ MODULE_PARM_DESC(use_msi, "\n"
static struct scsi_transport_template *aic94xx_transport_template;
static int asd_scan_finished(struct Scsi_Host *, unsigned long);
static void asd_scan_start(struct Scsi_Host *);
static const struct attribute_group *asd_sdev_groups[];

static const struct scsi_host_template aic94xx_sht = {
.module = THIS_MODULE,
Expand All @@ -60,6 +62,7 @@ static const struct scsi_host_template aic94xx_sht = {
.compat_ioctl = sas_ioctl,
#endif
.track_queue_depth = 1,
.sdev_groups = asd_sdev_groups,
};

static int asd_map_memio(struct asd_ha_struct *asd_ha)
Expand Down Expand Up @@ -951,6 +954,11 @@ static void asd_remove_driver_attrs(struct device_driver *driver)
driver_remove_file(driver, &driver_attr_version);
}

static const struct attribute_group *asd_sdev_groups[] = {
&sas_ata_sdev_attr_group,
NULL
};

static struct sas_domain_function_template aic94xx_transport_functions = {
.lldd_dev_found = asd_dev_found,
.lldd_dev_gone = asd_dev_gone,
Expand Down
6 changes: 6 additions & 0 deletions drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -3544,6 +3544,11 @@ static struct attribute *host_v2_hw_attrs[] = {

ATTRIBUTE_GROUPS(host_v2_hw);

static const struct attribute_group *sdev_groups_v2_hw[] = {
&sas_ata_sdev_attr_group,
NULL
};

static void map_queues_v2_hw(struct Scsi_Host *shost)
{
struct hisi_hba *hisi_hba = shost_priv(shost);
Expand Down Expand Up @@ -3585,6 +3590,7 @@ static const struct scsi_host_template sht_v2_hw = {
.compat_ioctl = sas_ioctl,
#endif
.shost_groups = host_v2_hw_groups,
.sdev_groups = sdev_groups_v2_hw,
.host_reset = hisi_sas_host_reset,
.map_queues = map_queues_v2_hw,
.host_tagset = 1,
Expand Down
6 changes: 6 additions & 0 deletions drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2929,6 +2929,11 @@ static struct attribute *host_v3_hw_attrs[] = {

ATTRIBUTE_GROUPS(host_v3_hw);

static const struct attribute_group *sdev_groups_v3_hw[] = {
&sas_ata_sdev_attr_group,
NULL
};

#define HISI_SAS_DEBUGFS_REG(x) {#x, x}

struct hisi_sas_debugfs_reg_lu {
Expand Down Expand Up @@ -3340,6 +3345,7 @@ static const struct scsi_host_template sht_v3_hw = {
.compat_ioctl = sas_ioctl,
#endif
.shost_groups = host_v3_hw_groups,
.sdev_groups = sdev_groups_v3_hw,
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
.host_reset = hisi_sas_host_reset,
.host_tagset = 1,
Expand Down
6 changes: 6 additions & 0 deletions drivers/scsi/isci/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ static struct attribute *isci_host_attrs[] = {

ATTRIBUTE_GROUPS(isci_host);

static const struct attribute_group *isci_sdev_groups[] = {
&sas_ata_sdev_attr_group,
NULL
};

static const struct scsi_host_template isci_sht = {

.module = THIS_MODULE,
Expand Down Expand Up @@ -176,6 +181,7 @@ static const struct scsi_host_template isci_sht = {
.compat_ioctl = sas_ioctl,
#endif
.shost_groups = isci_host_groups,
.sdev_groups = isci_sdev_groups,
.track_queue_depth = 1,
};

Expand Down
82 changes: 82 additions & 0 deletions drivers/scsi/libsas/sas_ata.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,3 +964,85 @@ int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id)
force_phy_id, &tmf_task);
}
EXPORT_SYMBOL_GPL(sas_execute_ata_cmd);

static ssize_t sas_ncq_prio_supported_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(device);
struct domain_device *ddev = sdev_to_domain_dev(sdev);
bool supported;
int rc;

rc = ata_ncq_prio_supported(ddev->sata_dev.ap, sdev, &supported);
if (rc)
return rc;

return sysfs_emit(buf, "%d\n", supported);
}

DEVICE_ATTR(ncq_prio_supported, S_IRUGO, sas_ncq_prio_supported_show, NULL);

static ssize_t sas_ncq_prio_enable_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(device);
struct domain_device *ddev = sdev_to_domain_dev(sdev);
bool enabled;
int rc;

rc = ata_ncq_prio_enabled(ddev->sata_dev.ap, sdev, &enabled);
if (rc)
return rc;

return sysfs_emit(buf, "%d\n", enabled);
}

static ssize_t sas_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 domain_device *ddev = sdev_to_domain_dev(sdev);
bool enable;
int rc;

rc = kstrtobool(buf, &enable);
if (rc)
return rc;

rc = ata_ncq_prio_enable(ddev->sata_dev.ap, sdev, enable);
if (rc)
return rc;

return len;
}

DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
sas_ncq_prio_enable_show, sas_ncq_prio_enable_store);

static struct attribute *sas_ata_sdev_attrs[] = {
&dev_attr_ncq_prio_supported.attr,
&dev_attr_ncq_prio_enable.attr,
NULL
};

static umode_t sas_ata_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int i)
{
struct device *dev = kobj_to_dev(kobj);
struct scsi_device *sdev = to_scsi_device(dev);
struct domain_device *ddev = sdev_to_domain_dev(sdev);

if (!dev_is_sata(ddev))
return 0;

return attr->mode;
}

const struct attribute_group sas_ata_sdev_attr_group = {
.attrs = sas_ata_sdev_attrs,
.is_visible = sas_ata_attr_is_visible,
};
EXPORT_SYMBOL_GPL(sas_ata_sdev_attr_group);
Loading

0 comments on commit e595ae7

Please sign in to comment.