Skip to content

Commit 1dd0c0e

Browse files
Matthew R. Ochsmartinkpetersen
authored andcommitted
scsi: cxlflash: Introduce hardware queue steering
As an enhancement to distribute requests to multiple hardware queues, add the infrastructure to hash a SCSI command into a particular hardware queue. Support the following scenarios when deriving which queue to use: single queue, tagging when SCSI-MQ enabled, and simple hash via CPU ID when SCSI-MQ is disabled. Rather than altering the existing send API, the derived hardware queue is stored in the AFU command where it can be used for sending a command to the chosen hardware queue. Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Signed-off-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 3065267 commit 1dd0c0e

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

drivers/scsi/cxlflash/common.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ enum cxlflash_state {
9696
STATE_FAILTERM /* Failed/terminating state, error out users/threads */
9797
};
9898

99+
enum cxlflash_hwq_mode {
100+
HWQ_MODE_RR, /* Roundrobin (default) */
101+
HWQ_MODE_TAG, /* Distribute based on block MQ tag */
102+
HWQ_MODE_CPU, /* CPU affinity */
103+
MAX_HWQ_MODE
104+
};
105+
99106
/*
100107
* Each context has its own set of resource handles that is visible
101108
* only from that context.
@@ -146,9 +153,9 @@ struct afu_cmd {
146153
struct scsi_cmnd *scp;
147154
struct completion cevent;
148155
struct list_head queue;
156+
u32 hwq_index;
149157

150158
u8 cmd_tmf:1;
151-
u32 hwq_index;
152159

153160
/* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned.
154161
* However for performance reasons the IOARCB/IOASA should be
@@ -213,8 +220,11 @@ struct afu {
213220
atomic_t cmds_active; /* Number of currently active AFU commands */
214221
u64 hb;
215222
u32 internal_lun; /* User-desired LUN mode for this AFU */
223+
216224
u32 num_hwqs; /* Number of hardware queues */
217225
u32 desired_hwqs; /* Desired h/w queues, effective on AFU reset */
226+
enum cxlflash_hwq_mode hwq_mode; /* Steering mode for h/w queues */
227+
u32 hwq_rr_count; /* Count to distribute traffic for roundrobin */
218228

219229
char version[16];
220230
u64 interface_version;

drivers/scsi/cxlflash/main.c

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,43 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
357357
return rc;
358358
}
359359

360+
/**
361+
* cmd_to_target_hwq() - selects a target hardware queue for a SCSI command
362+
* @host: SCSI host associated with device.
363+
* @scp: SCSI command to send.
364+
* @afu: SCSI command to send.
365+
*
366+
* Hashes a command based upon the hardware queue mode.
367+
*
368+
* Return: Trusted index of target hardware queue
369+
*/
370+
static u32 cmd_to_target_hwq(struct Scsi_Host *host, struct scsi_cmnd *scp,
371+
struct afu *afu)
372+
{
373+
u32 tag;
374+
u32 hwq = 0;
375+
376+
if (afu->num_hwqs == 1)
377+
return 0;
378+
379+
switch (afu->hwq_mode) {
380+
case HWQ_MODE_RR:
381+
hwq = afu->hwq_rr_count++ % afu->num_hwqs;
382+
break;
383+
case HWQ_MODE_TAG:
384+
tag = blk_mq_unique_tag(scp->request);
385+
hwq = blk_mq_unique_tag_to_hwq(tag);
386+
break;
387+
case HWQ_MODE_CPU:
388+
hwq = smp_processor_id() % afu->num_hwqs;
389+
break;
390+
default:
391+
WARN_ON_ONCE(1);
392+
}
393+
394+
return hwq;
395+
}
396+
360397
/**
361398
* send_tmf() - sends a Task Management Function (TMF)
362399
* @afu: AFU to checkout from.
@@ -368,10 +405,12 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
368405
*/
369406
static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
370407
{
371-
struct cxlflash_cfg *cfg = shost_priv(scp->device->host);
408+
struct Scsi_Host *host = scp->device->host;
409+
struct cxlflash_cfg *cfg = shost_priv(host);
372410
struct afu_cmd *cmd = sc_to_afucz(scp);
373411
struct device *dev = &cfg->dev->dev;
374-
struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ);
412+
int hwq_index = cmd_to_target_hwq(host, scp, afu);
413+
struct hwq *hwq = get_hwq(afu, hwq_index);
375414
ulong lock_flags;
376415
int rc = 0;
377416
ulong to;
@@ -388,7 +427,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
388427
cmd->scp = scp;
389428
cmd->parent = afu;
390429
cmd->cmd_tmf = true;
391-
cmd->hwq_index = hwq->index;
430+
cmd->hwq_index = hwq_index;
392431

393432
cmd->rcb.ctx_id = hwq->ctx_hndl;
394433
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
@@ -448,7 +487,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
448487
struct device *dev = &cfg->dev->dev;
449488
struct afu_cmd *cmd = sc_to_afucz(scp);
450489
struct scatterlist *sg = scsi_sglist(scp);
451-
struct hwq *hwq = get_hwq(afu, PRIMARY_HWQ);
490+
int hwq_index = cmd_to_target_hwq(host, scp, afu);
491+
struct hwq *hwq = get_hwq(afu, hwq_index);
452492
u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN;
453493
ulong lock_flags;
454494
int rc = 0;
@@ -498,7 +538,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
498538

499539
cmd->scp = scp;
500540
cmd->parent = afu;
501-
cmd->hwq_index = hwq->index;
541+
cmd->hwq_index = hwq_index;
502542

503543
cmd->rcb.ctx_id = hwq->ctx_hndl;
504544
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
@@ -2654,6 +2694,74 @@ static ssize_t num_hwqs_store(struct device *dev,
26542694
return count;
26552695
}
26562696

2697+
static const char *hwq_mode_name[MAX_HWQ_MODE] = { "rr", "tag", "cpu" };
2698+
2699+
/**
2700+
* hwq_mode_show() - presents the HWQ steering mode for the host
2701+
* @dev: Generic device associated with the host.
2702+
* @attr: Device attribute representing the HWQ steering mode.
2703+
* @buf: Buffer of length PAGE_SIZE to report back the HWQ steering mode
2704+
* as a character string.
2705+
*
2706+
* Return: The size of the ASCII string returned in @buf.
2707+
*/
2708+
static ssize_t hwq_mode_show(struct device *dev,
2709+
struct device_attribute *attr, char *buf)
2710+
{
2711+
struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
2712+
struct afu *afu = cfg->afu;
2713+
2714+
return scnprintf(buf, PAGE_SIZE, "%s\n", hwq_mode_name[afu->hwq_mode]);
2715+
}
2716+
2717+
/**
2718+
* hwq_mode_store() - sets the HWQ steering mode for the host
2719+
* @dev: Generic device associated with the host.
2720+
* @attr: Device attribute representing the HWQ steering mode.
2721+
* @buf: Buffer of length PAGE_SIZE containing the HWQ steering mode
2722+
* as a character string.
2723+
* @count: Length of data resizing in @buf.
2724+
*
2725+
* rr = Round-Robin
2726+
* tag = Block MQ Tagging
2727+
* cpu = CPU Affinity
2728+
*
2729+
* Return: The size of the ASCII string returned in @buf.
2730+
*/
2731+
static ssize_t hwq_mode_store(struct device *dev,
2732+
struct device_attribute *attr,
2733+
const char *buf, size_t count)
2734+
{
2735+
struct Scsi_Host *shost = class_to_shost(dev);
2736+
struct cxlflash_cfg *cfg = shost_priv(shost);
2737+
struct device *cfgdev = &cfg->dev->dev;
2738+
struct afu *afu = cfg->afu;
2739+
int i;
2740+
u32 mode = MAX_HWQ_MODE;
2741+
2742+
for (i = 0; i < MAX_HWQ_MODE; i++) {
2743+
if (!strncmp(hwq_mode_name[i], buf, strlen(hwq_mode_name[i]))) {
2744+
mode = i;
2745+
break;
2746+
}
2747+
}
2748+
2749+
if (mode >= MAX_HWQ_MODE) {
2750+
dev_info(cfgdev, "Invalid HWQ steering mode.\n");
2751+
return -EINVAL;
2752+
}
2753+
2754+
if ((mode == HWQ_MODE_TAG) && !shost_use_blk_mq(shost)) {
2755+
dev_info(cfgdev, "SCSI-MQ is not enabled, use a different "
2756+
"HWQ steering mode.\n");
2757+
return -EINVAL;
2758+
}
2759+
2760+
afu->hwq_mode = mode;
2761+
2762+
return count;
2763+
}
2764+
26572765
/**
26582766
* mode_show() - presents the current mode of the device
26592767
* @dev: Generic device associated with the device.
@@ -2686,6 +2794,7 @@ static DEVICE_ATTR_RO(port2_lun_table);
26862794
static DEVICE_ATTR_RO(port3_lun_table);
26872795
static DEVICE_ATTR_RW(irqpoll_weight);
26882796
static DEVICE_ATTR_RW(num_hwqs);
2797+
static DEVICE_ATTR_RW(hwq_mode);
26892798

26902799
static struct device_attribute *cxlflash_host_attrs[] = {
26912800
&dev_attr_port0,
@@ -2700,6 +2809,7 @@ static struct device_attribute *cxlflash_host_attrs[] = {
27002809
&dev_attr_port3_lun_table,
27012810
&dev_attr_irqpoll_weight,
27022811
&dev_attr_num_hwqs,
2812+
&dev_attr_hwq_mode,
27032813
NULL
27042814
};
27052815

0 commit comments

Comments
 (0)