Skip to content

Commit

Permalink
scsi: mpi3mr: Fix ATA NCQ priority support
Browse files Browse the repository at this point in the history
commit 90e6f08 upstream.

The function mpi3mr_qcmd() of the mpi3mr driver is able to indicate to
the HBA if a read or write command directed at an ATA device should be
translated to an NCQ read/write command with the high prioiryt bit set
when the request uses the RT priority class and the user has enabled NCQ
priority through sysfs.

However, unlike the mpt3sas driver, the mpi3mr driver does not define
the sas_ncq_prio_supported and sas_ncq_prio_enable sysfs attributes, so
the ncq_prio_enable field of struct mpi3mr_sdev_priv_data is never
actually set and NCQ Priority cannot ever be used.

Fix this by defining these missing atributes to allow a user to check if
an ATA device supports NCQ priority and to enable/disable the use of NCQ
priority. To do this, lift the function scsih_ncq_prio_supp() out of the
mpt3sas driver and make it the generic SCSI SAS transport function
sas_ata_ncq_prio_supported(). Nothing in that function is hardware
specific, so this function can be used in both the mpt3sas driver and
the mpi3mr driver.

Reported-by: Scott McCoy <scott.mccoy@wdc.com>
Fixes: 023ab2a ("scsi: mpi3mr: Add support for queue command processing")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://lore.kernel.org/r/20240611083435.92961-1-dlemoal@kernel.org
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
damien-lemoal authored and gregkh committed Jul 5, 2024
1 parent ecb7ab3 commit 3e5a49e
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 30 deletions.
1 change: 1 addition & 0 deletions drivers/scsi/mpi3mr/mpi3mr.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_sas.h>

#include "mpi/mpi30_transport.h"
#include "mpi/mpi30_cnfg.h"
Expand Down
67 changes: 67 additions & 0 deletions drivers/scsi/mpi3mr/mpi3mr_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -3549,6 +3549,72 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
return retval;
}

/**
* sas_ncq_prio_supported_show - Indicate if device supports NCQ priority
* @dev: pointer to embedded device
* @attr: sas_ncq_prio_supported attribute descriptor
* @buf: the buffer returned
*
* A sysfs 'read-only' sdev attribute, only works with SATA devices
*/
static ssize_t
sas_ncq_prio_supported_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);

return sysfs_emit(buf, "%d\n", sas_ata_ncq_prio_supported(sdev));
}
static DEVICE_ATTR_RO(sas_ncq_prio_supported);

/**
* sas_ncq_prio_enable_show - send prioritized io commands to device
* @dev: pointer to embedded device
* @attr: sas_ncq_prio_enable attribute descriptor
* @buf: the buffer returned
*
* A sysfs 'read/write' sdev attribute, only works with SATA devices
*/
static ssize_t
sas_ncq_prio_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;

if (!sdev_priv_data)
return 0;

return sysfs_emit(buf, "%d\n", sdev_priv_data->ncq_prio_enable);
}

static ssize_t
sas_ncq_prio_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata;
bool ncq_prio_enable = 0;

if (kstrtobool(buf, &ncq_prio_enable))
return -EINVAL;

if (!sas_ata_ncq_prio_supported(sdev))
return -EINVAL;

sdev_priv_data->ncq_prio_enable = ncq_prio_enable;

return strlen(buf);
}
static DEVICE_ATTR_RW(sas_ncq_prio_enable);

static struct device_attribute *mpi3mr_dev_attrs[] = {
&dev_attr_sas_ncq_prio_supported,
&dev_attr_sas_ncq_prio_enable,
NULL,
};

static struct scsi_host_template mpi3mr_driver_template = {
.module = THIS_MODULE,
.name = "MPI3 Storage Controller",
Expand Down Expand Up @@ -3577,6 +3643,7 @@ static struct scsi_host_template mpi3mr_driver_template = {
.cmd_per_lun = MPI3MR_MAX_CMDS_LUN,
.track_queue_depth = 1,
.cmd_size = sizeof(struct scmd_priv),
.sdev_attrs = mpi3mr_dev_attrs,
};

/**
Expand Down
3 changes: 0 additions & 3 deletions drivers/scsi/mpt3sas/mpt3sas_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -2010,9 +2010,6 @@ void
mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
struct _raid_device *raid_device, Mpi25SCSIIORequest_t *mpi_request);

/* NCQ Prio Handling Check */
bool scsih_ncq_prio_supp(struct scsi_device *sdev);

void mpt3sas_setup_debugfs(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_destroy_debugfs(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_init_debugfs(void);
Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/mpt3sas/mpt3sas_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3933,7 +3933,7 @@ sas_ncq_prio_supported_show(struct device *dev,
{
struct scsi_device *sdev = to_scsi_device(dev);

return sysfs_emit(buf, "%d\n", scsih_ncq_prio_supp(sdev));
return sysfs_emit(buf, "%d\n", sas_ata_ncq_prio_supported(sdev));
}
static DEVICE_ATTR_RO(sas_ncq_prio_supported);

Expand Down Expand Up @@ -3968,7 +3968,7 @@ sas_ncq_prio_enable_store(struct device *dev,
if (kstrtobool(buf, &ncq_prio_enable))
return -EINVAL;

if (!scsih_ncq_prio_supp(sdev))
if (!sas_ata_ncq_prio_supported(sdev))
return -EINVAL;

sas_device_priv_data->ncq_prio_enable = ncq_prio_enable;
Expand Down
25 changes: 0 additions & 25 deletions drivers/scsi/mpt3sas/mpt3sas_scsih.c
Original file line number Diff line number Diff line change
Expand Up @@ -12580,31 +12580,6 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
return PCI_ERS_RESULT_RECOVERED;
}

/**
* scsih_ncq_prio_supp - Check for NCQ command priority support
* @sdev: scsi device struct
*
* This is called when a user indicates they would like to enable
* ncq command priorities. This works only on SATA devices.
*/
bool scsih_ncq_prio_supp(struct scsi_device *sdev)
{
unsigned char *buf;
bool ncq_prio_supp = false;

if (!scsi_device_supports_vpd(sdev))
return ncq_prio_supp;

buf = kmalloc(SCSI_VPD_PG_LEN, GFP_KERNEL);
if (!buf)
return ncq_prio_supp;

if (!scsi_get_vpd_page(sdev, 0x89, buf, SCSI_VPD_PG_LEN))
ncq_prio_supp = (buf[213] >> 4) & 1;

kfree(buf);
return ncq_prio_supp;
}
/*
* The pci device ids are defined in mpi/mpi2_cnfg.h.
*/
Expand Down
29 changes: 29 additions & 0 deletions drivers/scsi/scsi_transport_sas.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,35 @@ unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
}
EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);

/**
* sas_ata_ncq_prio_supported - Check for ATA NCQ command priority support
* @sdev: SCSI device
*
* Check if an ATA device supports NCQ priority using VPD page 89h (ATA
* Information). Since this VPD page is implemented only for ATA devices,
* this function always returns false for SCSI devices.
*/
bool sas_ata_ncq_prio_supported(struct scsi_device *sdev)
{
unsigned char *buf;
bool ncq_prio_supported = false;

if (!scsi_device_supports_vpd(sdev))
return false;

buf = kmalloc(SCSI_VPD_PG_LEN, GFP_KERNEL);
if (!buf)
return false;

if (!scsi_get_vpd_page(sdev, 0x89, buf, SCSI_VPD_PG_LEN))
ncq_prio_supported = (buf[213] >> 4) & 1;

kfree(buf);

return ncq_prio_supported;
}
EXPORT_SYMBOL_GPL(sas_ata_ncq_prio_supported);

/*
* SAS Phy attributes
*/
Expand Down
2 changes: 2 additions & 0 deletions include/scsi/scsi_transport_sas.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ unsigned int sas_is_tlr_enabled(struct scsi_device *);
void sas_disable_tlr(struct scsi_device *);
void sas_enable_tlr(struct scsi_device *);

bool sas_ata_ncq_prio_supported(struct scsi_device *sdev);

extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
void sas_rphy_free(struct sas_rphy *);
Expand Down

0 comments on commit 3e5a49e

Please sign in to comment.