Skip to content

Commit

Permalink
scsi: mpt3sas: Add support for shared host tagset for CPU hotplug
Browse files Browse the repository at this point in the history
MPT Fusion adapters can steer completions to individual queues and we now
have support for shared host-wide tags in the I/O stack. The addition of
the host-wide tags allows us to enable multiqueue support for MPT Fusion
adapters. Once host-wise tags are enabled, the CPU hotplug feature is also
supported.

Allow use of host-wide tags to be disabled through the "host_tagset_enable"
module parameter. Once we do not have any major performance regressions
using host-wide tags, we will drop the hand-crafted interrupt affinity
settings.

Performance is meeting expectations. About 3.1M IOPS using 24 Drive SSD on
Aero controllers.

Link: https://lore.kernel.org/r/20210202095832.23072-1-sreekanth.reddy@broadcom.com
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
sreekanthbrcm authored and martinkpetersen committed Feb 9, 2021
1 parent d309ae0 commit 664f0dc
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 18 deletions.
50 changes: 33 additions & 17 deletions drivers/scsi/mpt3sas/mpt3sas_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -3648,25 +3648,16 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
base_mod64(atomic64_add_return(1,
&ioc->total_io_cnt), ioc->reply_queue_count) : 0;

return ioc->cpu_msix_table[raw_smp_processor_id()];
}
if (scmd && ioc->shost->nr_hw_queues > 1) {
u32 tag = blk_mq_unique_tag(scmd->request);

/**
* _base_sdev_nr_inflight_request -get number of inflight requests
* of a request queue.
* @q: request_queue object
*
* returns number of inflight request of a request queue.
*/
inline unsigned long
_base_sdev_nr_inflight_request(struct request_queue *q)
{
struct blk_mq_hw_ctx *hctx = q->queue_hw_ctx[0];
return blk_mq_unique_tag_to_hwq(tag) +
ioc->high_iops_queues;
}

return atomic_read(&hctx->nr_active);
return ioc->cpu_msix_table[raw_smp_processor_id()];
}


/**
* _base_get_high_iops_msix_index - get the msix index of
* high iops queues
Expand All @@ -3686,7 +3677,8 @@ _base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
* reply queues in terms of batch count 16 when outstanding
* IOs on the target device is >=8.
*/
if (_base_sdev_nr_inflight_request(scmd->device->request_queue) >

if (atomic_read(&scmd->device->device_busy) >
MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
return base_mod64((
atomic64_add_return(1, &ioc->high_iops_outstanding) /
Expand Down Expand Up @@ -3739,8 +3731,23 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
struct scsi_cmnd *scmd)
{
struct scsiio_tracker *request = scsi_cmd_priv(scmd);
unsigned int tag = scmd->request->tag;
u16 smid;
u32 tag, unique_tag;

unique_tag = blk_mq_unique_tag(scmd->request);
tag = blk_mq_unique_tag_to_tag(unique_tag);

/*
* Store hw queue number corresponding to the tag.
* This hw queue number is used later to determine
* the unique_tag using the logic below. This unique_tag
* is used to retrieve the scmd pointer corresponding
* to tag using scsi_host_find_tag() API.
*
* tag = smid - 1;
* unique_tag = ioc->io_queue_num[tag] << BLK_MQ_UNIQUE_TAG_BITS | tag;
*/
ioc->io_queue_num[tag] = blk_mq_unique_tag_to_hwq(unique_tag);

smid = tag + 1;
request->cb_idx = cb_idx;
Expand Down Expand Up @@ -3831,6 +3838,7 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)

mpt3sas_base_clear_st(ioc, st);
_base_recovery_check(ioc);
ioc->io_queue_num[smid - 1] = 0;
return;
}

Expand Down Expand Up @@ -5362,6 +5370,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
kfree(ioc->chain_lookup);
ioc->chain_lookup = NULL;
}

kfree(ioc->io_queue_num);
ioc->io_queue_num = NULL;
}

/**
Expand Down Expand Up @@ -5773,6 +5784,11 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
ioc_info(ioc, "internal(0x%p): depth(%d), start smid(%d)\n",
ioc->internal,
ioc->internal_depth, ioc->internal_smid));

ioc->io_queue_num = kcalloc(ioc->scsiio_depth,
sizeof(u16), GFP_KERNEL);
if (!ioc->io_queue_num)
goto out;
/*
* The number of NVMe page sized blocks needed is:
* (((sg_tablesize * 8) - 1) / (page_size - 8)) + 1
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/mpt3sas/mpt3sas_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,7 @@ struct MPT3SAS_ADAPTER {
spinlock_t scsi_lookup_lock;
int pending_io_count;
wait_queue_head_t reset_wq;
u16 *io_queue_num;

/* PCIe SGL */
struct dma_pool *pcie_sgl_dma_pool;
Expand Down
42 changes: 41 additions & 1 deletion drivers/scsi/mpt3sas/mpt3sas_scsih.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include <linux/interrupt.h>
#include <linux/aer.h>
#include <linux/raid_class.h>
#include <linux/blk-mq-pci.h>
#include <asm/unaligned.h>

#include "mpt3sas_base.h"
Expand Down Expand Up @@ -168,6 +169,11 @@ MODULE_PARM_DESC(multipath_on_hba,
"\t SAS 2.0 & SAS 3.0 HBA - This will be disabled,\n\t\t"
"\t SAS 3.5 HBA - This will be enabled)");

static int host_tagset_enable = 1;
module_param(host_tagset_enable, int, 0444);
MODULE_PARM_DESC(host_tagset_enable,
"Shared host tagset enable/disable Default: enable(1)");

/* raid transport support */
static struct raid_template *mpt3sas_raid_template;
static struct raid_template *mpt2sas_raid_template;
Expand Down Expand Up @@ -1743,10 +1749,12 @@ mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
struct scsi_cmnd *scmd = NULL;
struct scsiio_tracker *st;
Mpi25SCSIIORequest_t *mpi_request;
u16 tag = smid - 1;

if (smid > 0 &&
smid <= ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT) {
u32 unique_tag = smid - 1;
u32 unique_tag =
ioc->io_queue_num[tag] << BLK_MQ_UNIQUE_TAG_BITS | tag;

mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);

Expand Down Expand Up @@ -11599,6 +11607,22 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
return 1;
}

/**
* scsih_map_queues - map reply queues with request queues
* @shost: SCSI host pointer
*/
static int scsih_map_queues(struct Scsi_Host *shost)
{
struct MPT3SAS_ADAPTER *ioc =
(struct MPT3SAS_ADAPTER *)shost->hostdata;

if (ioc->shost->nr_hw_queues == 1)
return 0;

return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
ioc->pdev, ioc->high_iops_queues);
}

/* shost template for SAS 2.0 HBA devices */
static struct scsi_host_template mpt2sas_driver_template = {
.module = THIS_MODULE,
Expand Down Expand Up @@ -11666,6 +11690,7 @@ static struct scsi_host_template mpt3sas_driver_template = {
.sdev_attrs = mpt3sas_dev_attrs,
.track_queue_depth = 1,
.cmd_size = sizeof(struct scsiio_tracker),
.map_queues = scsih_map_queues,
};

/* raid transport support for SAS 3.0 HBA devices */
Expand Down Expand Up @@ -12028,6 +12053,21 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
} else
ioc->hide_drives = 0;

shost->host_tagset = 0;
shost->nr_hw_queues = 1;

if (ioc->is_gen35_ioc && ioc->reply_queue_count > 1 &&
host_tagset_enable && ioc->smp_affinity_enable) {

shost->host_tagset = 1;
shost->nr_hw_queues =
ioc->reply_queue_count - ioc->high_iops_queues;

dev_info(&ioc->pdev->dev,
"Max SCSIIO MPT commands: %d shared with nr_hw_queues = %d\n",
shost->can_queue, shost->nr_hw_queues);
}

rv = scsi_add_host(shost, &pdev->dev);
if (rv) {
ioc_err(ioc, "failure at %s:%d/%s()!\n",
Expand Down

0 comments on commit 664f0dc

Please sign in to comment.