scsi: mpt3sas: Use firmware recommended queue depth

Currently, the mpt3sas driver sets the default queue depth based on the
physical interface of the attached device:

 - SAS : 254
 - SATA:  32
 - NVMe: 128

The IOC firmware provides a recommended queue depth for each device through
SAS IO Unit Page1 for SAS/SATA and PCIe IO Unit Page 1 for NVMe devices.

If the host sets the queue depth greater than the firmware recommended
value, then the IOC places the I/Os above the recommended queue depth in an
internal pending queue. This consumes outstanding host-credit/resources,
thereby leading to potential starvation of other devices.

To avoid this, use the device depth recommended by the IOC firmware.

Link: https://lore.kernel.org/r/20210809072639.21228-2-suganath-prabu.subramani@broadcom.com
Signed-off-by: Suganath Prabu S <suganath-prabu.subramani@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Suganath Prabu S 2021-08-09 12:56:38 +05:30 committed by Martin K. Petersen
parent 44f88ef3c9
commit 787f2448c2
5 changed files with 165 additions and 6 deletions

View file

@ -5365,6 +5365,73 @@ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
&ioc->diag_trigger_mpi, 1);
}
/**
* _base_assign_fw_reported_qd - Get FW reported QD for SAS/SATA devices.
* - On failure set default QD values.
* @ioc : per adapter object
*
* Returns 0 for success, non-zero for failure.
*
*/
static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1;
int sz;
int rc = 0;
ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH;
ioc->max_narrowport_qd = MPT3SAS_SAS_QUEUE_DEPTH;
ioc->max_sata_qd = MPT3SAS_SATA_QUEUE_DEPTH;
ioc->max_nvme_qd = MPT3SAS_NVME_QUEUE_DEPTH;
if (!ioc->is_gen35_ioc)
goto out;
/* sas iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData);
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
if (!sas_iounit_pg1) {
pr_err("%s: failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return rc;
}
rc = mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
sas_iounit_pg1, sz);
if (rc) {
pr_err("%s: failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
ioc->max_wideport_qd =
(le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth)) ?
le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth) :
MPT3SAS_SAS_QUEUE_DEPTH;
ioc->max_narrowport_qd =
(le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth)) ?
le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth) :
MPT3SAS_SAS_QUEUE_DEPTH;
ioc->max_sata_qd = (sas_iounit_pg1->SATAMaxQDepth) ?
sas_iounit_pg1->SATAMaxQDepth : MPT3SAS_SATA_QUEUE_DEPTH;
/* pcie iounit page 1 */
rc = mpt3sas_config_get_pcie_iounit_pg1(ioc, &mpi_reply,
&pcie_iounit_pg1, sizeof(Mpi26PCIeIOUnitPage1_t));
if (rc) {
pr_err("%s: failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
ioc->max_nvme_qd = (le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) ?
(le16_to_cpu(pcie_iounit_pg1.NVMeMaxQueueDepth)) :
MPT3SAS_NVME_QUEUE_DEPTH;
out:
dinitprintk(ioc, pr_err(
"MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n",
ioc->max_wideport_qd, ioc->max_narrowport_qd,
ioc->max_sata_qd, ioc->max_nvme_qd));
kfree(sas_iounit_pg1);
return rc;
}
/**
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
@ -5434,6 +5501,9 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
ioc_warn(ioc,
"TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n");
}
rc = _base_assign_fw_reported_qd(ioc);
if (rc)
return rc;
rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
if (rc)
return rc;

View file

@ -576,6 +576,7 @@ struct _sas_device {
u8 is_chassis_slot_valid;
u8 connector_name[5];
struct kref refcount;
u8 port_type;
struct hba_port *port;
struct sas_rphy *rphy;
};
@ -1443,6 +1444,10 @@ struct MPT3SAS_ADAPTER {
u8 tm_custom_handling;
u8 nvme_abort_timeout;
u16 max_shutdown_latency;
u16 max_wideport_qd;
u16 max_narrowport_qd;
u16 max_nvme_qd;
u8 max_sata_qd;
/* static config pages */
struct mpt3sas_facts facts;
@ -1848,6 +1853,9 @@ int mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc,
int mpt3sas_config_get_pcie_device_pg2(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeDevicePage2_t *config_page,
u32 form, u32 handle);
int mpt3sas_config_get_pcie_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeIOUnitPage1_t *config_page,
u16 sz);
int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page,
u16 sz);

View file

@ -1168,6 +1168,43 @@ mpt3sas_config_get_pcie_device_pg0(struct MPT3SAS_ADAPTER *ioc,
return r;
}
/**
* mpt3sas_config_get_pcie_iounit_pg1 - obtain pcie iounit page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @sz: size of buffer passed in config_page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt3sas_config_get_pcie_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi26PCIeIOUnitPage1_t *config_page,
u16 sz)
{
Mpi2ConfigRequest_t mpi_request;
int r;
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
mpi_request.Function = MPI2_FUNCTION_CONFIG;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_IO_UNIT;
mpi_request.Header.PageVersion = MPI26_PCIEIOUNITPAGE1_PAGEVERSION;
mpi_request.Header.PageNumber = 1;
ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
out:
return r;
}
/**
* mpt3sas_config_get_pcie_device_pg2 - obtain pcie device page 2
* @ioc: per adapter object

View file

@ -3820,9 +3820,10 @@ enable_sdev_max_qd_store(struct device *cdev,
}
} else if (sas_target_priv_data->flags &
MPT_TARGET_FLAGS_PCIE_DEVICE)
qdepth = MPT3SAS_NVME_QUEUE_DEPTH;
qdepth = ioc->max_nvme_qd;
else
qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
qdepth = (sas_target_priv_data->sas_dev->port_type > 1) ?
ioc->max_wideport_qd : ioc->max_narrowport_qd;
mpt3sas_scsih_change_queue_depth(sdev, qdepth);
}

View file

@ -1803,7 +1803,7 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
* limit max device queue for SATA to 32 if enable_sdev_max_qd
* is disabled.
*/
if (ioc->enable_sdev_max_qd)
if (ioc->enable_sdev_max_qd || ioc->is_gen35_ioc)
goto not_sata;
sas_device_priv_data = sdev->hostdata;
@ -2657,7 +2657,7 @@ scsih_slave_configure(struct scsi_device *sdev)
return 1;
}
qdepth = MPT3SAS_NVME_QUEUE_DEPTH;
qdepth = ioc->max_nvme_qd;
ds = "NVMe";
sdev_printk(KERN_INFO, sdev,
"%s: handle(0x%04x), wwid(0x%016llx), port(%d)\n",
@ -2709,7 +2709,8 @@ scsih_slave_configure(struct scsi_device *sdev)
sas_device->volume_handle = volume_handle;
sas_device->volume_wwid = volume_wwid;
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
qdepth = (sas_device->port_type > 1) ?
ioc->max_wideport_qd : ioc->max_narrowport_qd;
ssp_target = 1;
if (sas_device->device_info &
MPI2_SAS_DEVICE_INFO_SEP) {
@ -2721,7 +2722,7 @@ scsih_slave_configure(struct scsi_device *sdev)
} else
ds = "SSP";
} else {
qdepth = MPT3SAS_SATA_QUEUE_DEPTH;
qdepth = ioc->max_sata_qd;
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
ds = "STP";
else if (sas_device->device_info &
@ -7371,6 +7372,10 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
/* get device name */
sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
sas_device->port_type = sas_device_pg0.MaxPortConnections;
ioc_info(ioc,
"handle(0x%0x) sas_address(0x%016llx) port_type(0x%0x)\n",
handle, sas_device->sas_address, sas_device->port_type);
if (ioc->wait_for_discovery_to_complete)
_scsih_sas_device_init_add(ioc, sas_device);
@ -9603,6 +9608,42 @@ _scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc)
}
}
/**
* _scsih_update_device_qdepth - Update QD during Reset.
* @ioc: per adapter object
*
*/
static void
_scsih_update_device_qdepth(struct MPT3SAS_ADAPTER *ioc)
{
struct MPT3SAS_DEVICE *sas_device_priv_data;
struct MPT3SAS_TARGET *sas_target_priv_data;
struct _sas_device *sas_device;
struct scsi_device *sdev;
u16 qdepth;
ioc_info(ioc, "Update devices with firmware reported queue depth\n");
shost_for_each_device(sdev, ioc->shost) {
sas_device_priv_data = sdev->hostdata;
if (sas_device_priv_data && sas_device_priv_data->sas_target) {
sas_target_priv_data = sas_device_priv_data->sas_target;
sas_device = sas_device_priv_data->sas_target->sas_dev;
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_PCIE_DEVICE)
qdepth = ioc->max_nvme_qd;
else if (sas_device &&
sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
qdepth = (sas_device->port_type > 1) ?
ioc->max_wideport_qd : ioc->max_narrowport_qd;
else if (sas_device &&
sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
qdepth = ioc->max_sata_qd;
else
continue;
mpt3sas_scsih_change_queue_depth(sdev, qdepth);
}
}
}
/**
* _scsih_mark_responding_sas_device - mark a sas_devices as responding
* @ioc: per adapter object
@ -10654,6 +10695,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
_scsih_remove_unresponding_devices(ioc);
_scsih_del_dirty_vphy(ioc);
_scsih_del_dirty_port_entries(ioc);
if (ioc->is_gen35_ioc)
_scsih_update_device_qdepth(ioc);
_scsih_scan_for_devices_after_reset(ioc);
/*
* If diag reset has occurred during the driver load