]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: mpt3sas: Use firmware recommended queue depth
authorSuganath Prabu S <suganath-prabu.subramani@broadcom.com>
Mon, 9 Aug 2021 07:26:38 +0000 (12:56 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 10 Aug 2021 03:07:04 +0000 (23:07 -0400)
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>
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_config.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c

index 90dd18a315b93b199061bc2ffb46201a0e732b65..54fd9aef21ac844bd234e3d09426bb7541ecc1bd 100644 (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;
index bfea345e6ea24920be2aa9a2416b6d5542f0811f..740b6de23be55742b9ce61102d9bc2b956052637 100644 (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);
index 83a5c2172ad4b14d26243f6fa7845e6e30862135..0563078227de6c1265c72289e45b84d99424025c 100644 (file)
@@ -1168,6 +1168,43 @@ out:
        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
index b66140e4c370a01e338df8aea3b57bd5555b6f01..db95cda1fad44d66060d33933c6ffd2271709907 100644 (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);
                }
index f15c809e22c1da0200ca0409da2458d26c6eaf19..b30f271888f74caf1f8f79675e40bd2aef8a727a 100644 (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