Skip to content

Commit 4c47efc

Browse files
jsmart-ghmartinkpetersen
authored andcommitted
scsi: lpfc: Move SCSI and NVME Stats to hardware queue structures
Many io statistics were being sampled and saved using adapter-based data structures. This was creating a lot of contention and cache thrashing in the I/O path. Move the statistics to the hardware queue data structures. Given the per-queue data structures, use of atomic types is lessened. Add new sysfs and debugfs stat routines to collate the per hardware queue values and report at an adapter level. Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <jsmart2021@gmail.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 63df6d6 commit 4c47efc

File tree

10 files changed

+304
-103
lines changed

10 files changed

+304
-103
lines changed

drivers/scsi/lpfc/lpfc.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ struct lpfc_vport {
479479
struct dentry *debug_disc_trc;
480480
struct dentry *debug_nodelist;
481481
struct dentry *debug_nvmestat;
482+
struct dentry *debug_scsistat;
482483
struct dentry *debug_nvmektime;
483484
struct dentry *debug_cpucheck;
484485
struct dentry *vport_debugfs_root;
@@ -946,14 +947,6 @@ struct lpfc_hba {
946947
struct timer_list eratt_poll;
947948
uint32_t eratt_poll_interval;
948949

949-
/*
950-
* stat counters
951-
*/
952-
atomic_t fc4ScsiInputRequests;
953-
atomic_t fc4ScsiOutputRequests;
954-
atomic_t fc4ScsiControlRequests;
955-
atomic_t fc4ScsiIoCmpls;
956-
957950
uint64_t bg_guard_err_cnt;
958951
uint64_t bg_apptag_err_cnt;
959952
uint64_t bg_reftag_err_cnt;

drivers/scsi/lpfc/lpfc_attr.c

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@
6464
#define LPFC_MIN_MRQ_POST 512
6565
#define LPFC_MAX_MRQ_POST 2048
6666

67-
#define LPFC_MAX_NVME_INFO_TMP_LEN 100
68-
#define LPFC_NVME_INFO_MORE_STR "\nCould be more info...\n"
69-
7067
/*
7168
* Write key size should be multiple of 4. If write key is changed
7269
* make sure that library write key is also changed.
@@ -155,7 +152,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
155152
struct lpfc_nvme_rport *rport;
156153
struct lpfc_nodelist *ndlp;
157154
struct nvme_fc_remote_port *nrport;
158-
struct lpfc_nvme_ctrl_stat *cstat;
155+
struct lpfc_fc4_ctrl_stat *cstat;
159156
uint64_t data1, data2, data3;
160157
uint64_t totin, totout, tot;
161158
char *statep;
@@ -457,12 +454,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
457454
totin = 0;
458455
totout = 0;
459456
for (i = 0; i < phba->cfg_hdw_queue; i++) {
460-
cstat = &lport->cstat[i];
461-
tot = atomic_read(&cstat->fc4NvmeIoCmpls);
457+
cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
458+
tot = cstat->io_cmpls;
462459
totin += tot;
463-
data1 = atomic_read(&cstat->fc4NvmeInputRequests);
464-
data2 = atomic_read(&cstat->fc4NvmeOutputRequests);
465-
data3 = atomic_read(&cstat->fc4NvmeControlRequests);
460+
data1 = cstat->input_requests;
461+
data2 = cstat->output_requests;
462+
data3 = cstat->control_requests;
466463
totout += (data1 + data2 + data3);
467464
}
468465
scnprintf(tmp, sizeof(tmp),
@@ -508,6 +505,57 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
508505
return len;
509506
}
510507

508+
static ssize_t
509+
lpfc_scsi_stat_show(struct device *dev, struct device_attribute *attr,
510+
char *buf)
511+
{
512+
struct Scsi_Host *shost = class_to_shost(dev);
513+
struct lpfc_vport *vport = shost_priv(shost);
514+
struct lpfc_hba *phba = vport->phba;
515+
int len;
516+
struct lpfc_fc4_ctrl_stat *cstat;
517+
u64 data1, data2, data3;
518+
u64 tot, totin, totout;
519+
int i;
520+
char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
521+
522+
if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
523+
(phba->sli_rev != LPFC_SLI_REV4))
524+
return 0;
525+
526+
scnprintf(buf, PAGE_SIZE, "SCSI HDWQ Statistics\n");
527+
528+
totin = 0;
529+
totout = 0;
530+
for (i = 0; i < phba->cfg_hdw_queue; i++) {
531+
cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
532+
tot = cstat->io_cmpls;
533+
totin += tot;
534+
data1 = cstat->input_requests;
535+
data2 = cstat->output_requests;
536+
data3 = cstat->control_requests;
537+
totout += (data1 + data2 + data3);
538+
539+
scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx "
540+
"IO %016llx ", i, data1, data2, data3);
541+
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
542+
goto buffer_done;
543+
544+
scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n",
545+
tot, ((data1 + data2 + data3) - tot));
546+
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
547+
goto buffer_done;
548+
}
549+
scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx "
550+
"OutIO %016llx\n", totin, totout, totout - totin);
551+
strlcat(buf, tmp, PAGE_SIZE);
552+
553+
buffer_done:
554+
len = strnlen(buf, PAGE_SIZE);
555+
556+
return len;
557+
}
558+
511559
static ssize_t
512560
lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
513561
char *buf)
@@ -2573,6 +2621,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
25732621

25742622

25752623
static DEVICE_ATTR(nvme_info, 0444, lpfc_nvme_info_show, NULL);
2624+
static DEVICE_ATTR(scsi_stat, 0444, lpfc_scsi_stat_show, NULL);
25762625
static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL);
25772626
static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL);
25782627
static DEVICE_ATTR(bg_apptag_err, S_IRUGO, lpfc_bg_apptag_err_show, NULL);
@@ -5642,6 +5691,7 @@ LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push");
56425691

56435692
struct device_attribute *lpfc_hba_attrs[] = {
56445693
&dev_attr_nvme_info,
5694+
&dev_attr_scsi_stat,
56455695
&dev_attr_bg_info,
56465696
&dev_attr_bg_guard_err,
56475697
&dev_attr_bg_apptag_err,

drivers/scsi/lpfc/lpfc_debugfs.c

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
840840
struct lpfc_nvmet_tgtport *tgtp;
841841
struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
842842
struct nvme_fc_local_port *localport;
843-
struct lpfc_nvme_ctrl_stat *cstat;
843+
struct lpfc_fc4_ctrl_stat *cstat;
844844
struct lpfc_nvme_lport *lport;
845845
uint64_t data1, data2, data3;
846846
uint64_t tot, totin, totout;
@@ -979,7 +979,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
979979
return len;
980980

981981
len += snprintf(buf + len, size - len,
982-
"\nNVME Lport Statistics\n");
982+
"\nNVME HDWQ Statistics\n");
983983

984984
len += snprintf(buf + len, size - len,
985985
"LS: Xmt %016x Cmpl %016x\n",
@@ -993,20 +993,20 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
993993
totin = 0;
994994
totout = 0;
995995
for (i = 0; i < phba->cfg_hdw_queue; i++) {
996-
cstat = &lport->cstat[i];
997-
tot = atomic_read(&cstat->fc4NvmeIoCmpls);
996+
cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
997+
tot = cstat->io_cmpls;
998998
totin += tot;
999-
data1 = atomic_read(&cstat->fc4NvmeInputRequests);
1000-
data2 = atomic_read(&cstat->fc4NvmeOutputRequests);
1001-
data3 = atomic_read(&cstat->fc4NvmeControlRequests);
999+
data1 = cstat->input_requests;
1000+
data2 = cstat->output_requests;
1001+
data3 = cstat->control_requests;
10021002
totout += (data1 + data2 + data3);
10031003

10041004
/* Limit to 32, debugfs display buffer limitation */
10051005
if (i >= 32)
10061006
continue;
10071007

10081008
len += snprintf(buf + len, PAGE_SIZE - len,
1009-
"FCP (%d): Rd %016llx Wr %016llx "
1009+
"HDWQ (%d): Rd %016llx Wr %016llx "
10101010
"IO %016llx ",
10111011
i, data1, data2, data3);
10121012
len += snprintf(buf + len, PAGE_SIZE - len,
@@ -1046,6 +1046,66 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
10461046
return len;
10471047
}
10481048

1049+
/**
1050+
* lpfc_debugfs_scsistat_data - Dump target node list to a buffer
1051+
* @vport: The vport to gather target node info from.
1052+
* @buf: The buffer to dump log into.
1053+
* @size: The maximum amount of data to process.
1054+
*
1055+
* Description:
1056+
* This routine dumps the SCSI statistics associated with @vport
1057+
*
1058+
* Return Value:
1059+
* This routine returns the amount of bytes that were dumped into @buf and will
1060+
* not exceed @size.
1061+
**/
1062+
static int
1063+
lpfc_debugfs_scsistat_data(struct lpfc_vport *vport, char *buf, int size)
1064+
{
1065+
int len;
1066+
struct lpfc_hba *phba = vport->phba;
1067+
struct lpfc_fc4_ctrl_stat *cstat;
1068+
u64 data1, data2, data3;
1069+
u64 tot, totin, totout;
1070+
int i;
1071+
char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
1072+
1073+
if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
1074+
(phba->sli_rev != LPFC_SLI_REV4))
1075+
return 0;
1076+
1077+
scnprintf(buf, size, "SCSI HDWQ Statistics\n");
1078+
1079+
totin = 0;
1080+
totout = 0;
1081+
for (i = 0; i < phba->cfg_hdw_queue; i++) {
1082+
cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
1083+
tot = cstat->io_cmpls;
1084+
totin += tot;
1085+
data1 = cstat->input_requests;
1086+
data2 = cstat->output_requests;
1087+
data3 = cstat->control_requests;
1088+
totout += (data1 + data2 + data3);
1089+
1090+
scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx "
1091+
"IO %016llx ", i, data1, data2, data3);
1092+
if (strlcat(buf, tmp, size) >= size)
1093+
goto buffer_done;
1094+
1095+
scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n",
1096+
tot, ((data1 + data2 + data3) - tot));
1097+
if (strlcat(buf, tmp, size) >= size)
1098+
goto buffer_done;
1099+
}
1100+
scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx "
1101+
"OutIO %016llx\n", totin, totout, totout - totin);
1102+
strlcat(buf, tmp, size);
1103+
1104+
buffer_done:
1105+
len = strnlen(buf, size);
1106+
1107+
return len;
1108+
}
10491109

10501110
/**
10511111
* lpfc_debugfs_nvmektime_data - Dump target node list to a buffer
@@ -2211,6 +2271,64 @@ lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf,
22112271
return nbytes;
22122272
}
22132273

2274+
static int
2275+
lpfc_debugfs_scsistat_open(struct inode *inode, struct file *file)
2276+
{
2277+
struct lpfc_vport *vport = inode->i_private;
2278+
struct lpfc_debug *debug;
2279+
int rc = -ENOMEM;
2280+
2281+
debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2282+
if (!debug)
2283+
goto out;
2284+
2285+
/* Round to page boundary */
2286+
debug->buffer = kzalloc(LPFC_SCSISTAT_SIZE, GFP_KERNEL);
2287+
if (!debug->buffer) {
2288+
kfree(debug);
2289+
goto out;
2290+
}
2291+
2292+
debug->len = lpfc_debugfs_scsistat_data(vport, debug->buffer,
2293+
LPFC_SCSISTAT_SIZE);
2294+
2295+
debug->i_private = inode->i_private;
2296+
file->private_data = debug;
2297+
2298+
rc = 0;
2299+
out:
2300+
return rc;
2301+
}
2302+
2303+
static ssize_t
2304+
lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
2305+
size_t nbytes, loff_t *ppos)
2306+
{
2307+
struct lpfc_debug *debug = file->private_data;
2308+
struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
2309+
struct lpfc_hba *phba = vport->phba;
2310+
char mybuf[6] = {0};
2311+
int i;
2312+
2313+
/* Protect copy from user */
2314+
if (!access_ok(buf, nbytes))
2315+
return -EFAULT;
2316+
2317+
if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ?
2318+
(sizeof(mybuf) - 1) : nbytes))
2319+
return -EFAULT;
2320+
2321+
if ((strncmp(&mybuf[0], "reset", strlen("reset")) == 0) ||
2322+
(strncmp(&mybuf[0], "zero", strlen("zero")) == 0)) {
2323+
for (i = 0; i < phba->cfg_hdw_queue; i++) {
2324+
memset(&phba->sli4_hba.hdwq[i].scsi_cstat, 0,
2325+
sizeof(phba->sli4_hba.hdwq[i].scsi_cstat));
2326+
}
2327+
}
2328+
2329+
return nbytes;
2330+
}
2331+
22142332
static int
22152333
lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file)
22162334
{
@@ -4972,6 +5090,16 @@ static const struct file_operations lpfc_debugfs_op_nvmestat = {
49725090
.release = lpfc_debugfs_release,
49735091
};
49745092

5093+
#undef lpfc_debugfs_op_scsistat
5094+
static const struct file_operations lpfc_debugfs_op_scsistat = {
5095+
.owner = THIS_MODULE,
5096+
.open = lpfc_debugfs_scsistat_open,
5097+
.llseek = lpfc_debugfs_lseek,
5098+
.read = lpfc_debugfs_read,
5099+
.write = lpfc_debugfs_scsistat_write,
5100+
.release = lpfc_debugfs_release,
5101+
};
5102+
49755103
#undef lpfc_debugfs_op_nvmektime
49765104
static const struct file_operations lpfc_debugfs_op_nvmektime = {
49775105
.owner = THIS_MODULE,
@@ -5612,6 +5740,17 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
56125740
vport->vport_debugfs_root,
56135741
vport, &lpfc_debugfs_op_nvmestat);
56145742

5743+
snprintf(name, sizeof(name), "scsistat");
5744+
vport->debug_scsistat =
5745+
debugfs_create_file(name, 0644,
5746+
vport->vport_debugfs_root,
5747+
vport, &lpfc_debugfs_op_scsistat);
5748+
if (!vport->debug_scsistat) {
5749+
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
5750+
"0811 Cannot create debugfs scsistat\n");
5751+
goto debug_failed;
5752+
}
5753+
56155754
snprintf(name, sizeof(name), "nvmektime");
56165755
vport->debug_nvmektime =
56175756
debugfs_create_file(name, 0644,
@@ -5750,6 +5889,9 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
57505889
debugfs_remove(vport->debug_nvmestat); /* nvmestat */
57515890
vport->debug_nvmestat = NULL;
57525891

5892+
debugfs_remove(vport->debug_scsistat); /* scsistat */
5893+
vport->debug_scsistat = NULL;
5894+
57535895
debugfs_remove(vport->debug_nvmektime); /* nvmektime */
57545896
vport->debug_nvmektime = NULL;
57555897

drivers/scsi/lpfc/lpfc_debugfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
#define LPFC_CPUCHECK_SIZE 8192
5151
#define LPFC_NVMEIO_TRC_SIZE 8192
5252

53+
/* scsistat output buffer size */
54+
#define LPFC_SCSISTAT_SIZE 8192
55+
5356
#define LPFC_DEBUG_OUT_LINE_SZ 80
5457

5558
/*

0 commit comments

Comments
 (0)