Commit 787f2448 authored by Suganath Prabu S's avatar Suganath Prabu S Committed by Martin K. Petersen
Browse files

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: default avatarSuganath Prabu S <suganath-prabu.subramani@broadcom.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 44f88ef3
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -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;
+8 −0
Original line number Diff line number Diff line
@@ -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);
+37 −0
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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);
		}
+47 −4
Original line number Diff line number Diff line
@@ -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