1*4882a593Smuzhiyun /*******************************************************************
2*4882a593Smuzhiyun * This file is part of the Emulex Linux Device Driver for *
3*4882a593Smuzhiyun * Fibre Channel Host Bus Adapters. *
4*4882a593Smuzhiyun * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term *
5*4882a593Smuzhiyun * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
6*4882a593Smuzhiyun * Copyright (C) 2007-2015 Emulex. All rights reserved. *
7*4882a593Smuzhiyun * EMULEX and SLI are trademarks of Emulex. *
8*4882a593Smuzhiyun * www.broadcom.com *
9*4882a593Smuzhiyun * *
10*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or *
11*4882a593Smuzhiyun * modify it under the terms of version 2 of the GNU General *
12*4882a593Smuzhiyun * Public License as published by the Free Software Foundation. *
13*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful. *
14*4882a593Smuzhiyun * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
15*4882a593Smuzhiyun * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
16*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
17*4882a593Smuzhiyun * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
18*4882a593Smuzhiyun * TO BE LEGALLY INVALID. See the GNU General Public License for *
19*4882a593Smuzhiyun * more details, a copy of which can be found in the file COPYING *
20*4882a593Smuzhiyun * included with this package. *
21*4882a593Smuzhiyun *******************************************************************/
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/blkdev.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/module.h>
26*4882a593Smuzhiyun #include <linux/dma-mapping.h>
27*4882a593Smuzhiyun #include <linux/idr.h>
28*4882a593Smuzhiyun #include <linux/interrupt.h>
29*4882a593Smuzhiyun #include <linux/kthread.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun #include <linux/pci.h>
32*4882a593Smuzhiyun #include <linux/spinlock.h>
33*4882a593Smuzhiyun #include <linux/ctype.h>
34*4882a593Smuzhiyun #include <linux/vmalloc.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #include <scsi/scsi.h>
37*4882a593Smuzhiyun #include <scsi/scsi_device.h>
38*4882a593Smuzhiyun #include <scsi/scsi_host.h>
39*4882a593Smuzhiyun #include <scsi/scsi_transport_fc.h>
40*4882a593Smuzhiyun #include <scsi/fc/fc_fs.h>
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #include "lpfc_hw4.h"
43*4882a593Smuzhiyun #include "lpfc_hw.h"
44*4882a593Smuzhiyun #include "lpfc_sli.h"
45*4882a593Smuzhiyun #include "lpfc_sli4.h"
46*4882a593Smuzhiyun #include "lpfc_nl.h"
47*4882a593Smuzhiyun #include "lpfc_disc.h"
48*4882a593Smuzhiyun #include "lpfc.h"
49*4882a593Smuzhiyun #include "lpfc_scsi.h"
50*4882a593Smuzhiyun #include "lpfc_nvme.h"
51*4882a593Smuzhiyun #include "lpfc_logmsg.h"
52*4882a593Smuzhiyun #include "lpfc_crtn.h"
53*4882a593Smuzhiyun #include "lpfc_vport.h"
54*4882a593Smuzhiyun #include "lpfc_version.h"
55*4882a593Smuzhiyun #include "lpfc_compat.h"
56*4882a593Smuzhiyun #include "lpfc_debugfs.h"
57*4882a593Smuzhiyun #include "lpfc_bsg.h"
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
60*4882a593Smuzhiyun /*
61*4882a593Smuzhiyun * debugfs interface
62*4882a593Smuzhiyun *
63*4882a593Smuzhiyun * To access this interface the user should:
64*4882a593Smuzhiyun * # mount -t debugfs none /sys/kernel/debug
65*4882a593Smuzhiyun *
66*4882a593Smuzhiyun * The lpfc debugfs directory hierarchy is:
67*4882a593Smuzhiyun * /sys/kernel/debug/lpfc/fnX/vportY
68*4882a593Smuzhiyun * where X is the lpfc hba function unique_id
69*4882a593Smuzhiyun * where Y is the vport VPI on that hba
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun * Debugging services available per vport:
72*4882a593Smuzhiyun * discovery_trace
73*4882a593Smuzhiyun * This is an ACSII readable file that contains a trace of the last
74*4882a593Smuzhiyun * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
75*4882a593Smuzhiyun * See lpfc_debugfs.h for different categories of discovery events.
76*4882a593Smuzhiyun * To enable the discovery trace, the following module parameters must be set:
77*4882a593Smuzhiyun * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
78*4882a593Smuzhiyun * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for
79*4882a593Smuzhiyun * EACH vport. X MUST also be a power of 2.
80*4882a593Smuzhiyun * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in
81*4882a593Smuzhiyun * lpfc_debugfs.h .
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * slow_ring_trace
84*4882a593Smuzhiyun * This is an ACSII readable file that contains a trace of the last
85*4882a593Smuzhiyun * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA.
86*4882a593Smuzhiyun * To enable the slow ring trace, the following module parameters must be set:
87*4882a593Smuzhiyun * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
88*4882a593Smuzhiyun * lpfc_debugfs_max_slow_ring_trc=X Where X is the event trace depth for
89*4882a593Smuzhiyun * the HBA. X MUST also be a power of 2.
90*4882a593Smuzhiyun */
91*4882a593Smuzhiyun static int lpfc_debugfs_enable = 1;
92*4882a593Smuzhiyun module_param(lpfc_debugfs_enable, int, S_IRUGO);
93*4882a593Smuzhiyun MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* This MUST be a power of 2 */
96*4882a593Smuzhiyun static int lpfc_debugfs_max_disc_trc;
97*4882a593Smuzhiyun module_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO);
98*4882a593Smuzhiyun MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
99*4882a593Smuzhiyun "Set debugfs discovery trace depth");
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* This MUST be a power of 2 */
102*4882a593Smuzhiyun static int lpfc_debugfs_max_slow_ring_trc;
103*4882a593Smuzhiyun module_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO);
104*4882a593Smuzhiyun MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
105*4882a593Smuzhiyun "Set debugfs slow ring trace depth");
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* This MUST be a power of 2 */
108*4882a593Smuzhiyun static int lpfc_debugfs_max_nvmeio_trc;
109*4882a593Smuzhiyun module_param(lpfc_debugfs_max_nvmeio_trc, int, 0444);
110*4882a593Smuzhiyun MODULE_PARM_DESC(lpfc_debugfs_max_nvmeio_trc,
111*4882a593Smuzhiyun "Set debugfs NVME IO trace depth");
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun static int lpfc_debugfs_mask_disc_trc;
114*4882a593Smuzhiyun module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO);
115*4882a593Smuzhiyun MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
116*4882a593Smuzhiyun "Set debugfs discovery trace mask");
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #include <linux/debugfs.h>
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
121*4882a593Smuzhiyun static unsigned long lpfc_debugfs_start_time = 0L;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* iDiag */
124*4882a593Smuzhiyun static struct lpfc_idiag idiag;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /**
127*4882a593Smuzhiyun * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer
128*4882a593Smuzhiyun * @vport: The vport to gather the log info from.
129*4882a593Smuzhiyun * @buf: The buffer to dump log into.
130*4882a593Smuzhiyun * @size: The maximum amount of data to process.
131*4882a593Smuzhiyun *
132*4882a593Smuzhiyun * Description:
133*4882a593Smuzhiyun * This routine gathers the lpfc discovery debugfs data from the @vport and
134*4882a593Smuzhiyun * dumps it to @buf up to @size number of bytes. It will start at the next entry
135*4882a593Smuzhiyun * in the log and process the log until the end of the buffer. Then it will
136*4882a593Smuzhiyun * gather from the beginning of the log and process until the current entry.
137*4882a593Smuzhiyun *
138*4882a593Smuzhiyun * Notes:
139*4882a593Smuzhiyun * Discovery logging will be disabled while while this routine dumps the log.
140*4882a593Smuzhiyun *
141*4882a593Smuzhiyun * Return Value:
142*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
143*4882a593Smuzhiyun * not exceed @size.
144*4882a593Smuzhiyun **/
145*4882a593Smuzhiyun static int
lpfc_debugfs_disc_trc_data(struct lpfc_vport * vport,char * buf,int size)146*4882a593Smuzhiyun lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun int i, index, len, enable;
149*4882a593Smuzhiyun uint32_t ms;
150*4882a593Smuzhiyun struct lpfc_debugfs_trc *dtp;
151*4882a593Smuzhiyun char *buffer;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
154*4882a593Smuzhiyun if (!buffer)
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun enable = lpfc_debugfs_enable;
158*4882a593Smuzhiyun lpfc_debugfs_enable = 0;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun len = 0;
161*4882a593Smuzhiyun index = (atomic_read(&vport->disc_trc_cnt) + 1) &
162*4882a593Smuzhiyun (lpfc_debugfs_max_disc_trc - 1);
163*4882a593Smuzhiyun for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
164*4882a593Smuzhiyun dtp = vport->disc_trc + i;
165*4882a593Smuzhiyun if (!dtp->fmt)
166*4882a593Smuzhiyun continue;
167*4882a593Smuzhiyun ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
168*4882a593Smuzhiyun snprintf(buffer,
169*4882a593Smuzhiyun LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
170*4882a593Smuzhiyun dtp->seq_cnt, ms, dtp->fmt);
171*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, buffer,
172*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun for (i = 0; i < index; i++) {
175*4882a593Smuzhiyun dtp = vport->disc_trc + i;
176*4882a593Smuzhiyun if (!dtp->fmt)
177*4882a593Smuzhiyun continue;
178*4882a593Smuzhiyun ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
179*4882a593Smuzhiyun snprintf(buffer,
180*4882a593Smuzhiyun LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
181*4882a593Smuzhiyun dtp->seq_cnt, ms, dtp->fmt);
182*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, buffer,
183*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun lpfc_debugfs_enable = enable;
187*4882a593Smuzhiyun kfree(buffer);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return len;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /**
193*4882a593Smuzhiyun * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer
194*4882a593Smuzhiyun * @phba: The HBA to gather the log info from.
195*4882a593Smuzhiyun * @buf: The buffer to dump log into.
196*4882a593Smuzhiyun * @size: The maximum amount of data to process.
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * Description:
199*4882a593Smuzhiyun * This routine gathers the lpfc slow ring debugfs data from the @phba and
200*4882a593Smuzhiyun * dumps it to @buf up to @size number of bytes. It will start at the next entry
201*4882a593Smuzhiyun * in the log and process the log until the end of the buffer. Then it will
202*4882a593Smuzhiyun * gather from the beginning of the log and process until the current entry.
203*4882a593Smuzhiyun *
204*4882a593Smuzhiyun * Notes:
205*4882a593Smuzhiyun * Slow ring logging will be disabled while while this routine dumps the log.
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * Return Value:
208*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
209*4882a593Smuzhiyun * not exceed @size.
210*4882a593Smuzhiyun **/
211*4882a593Smuzhiyun static int
lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba * phba,char * buf,int size)212*4882a593Smuzhiyun lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun int i, index, len, enable;
215*4882a593Smuzhiyun uint32_t ms;
216*4882a593Smuzhiyun struct lpfc_debugfs_trc *dtp;
217*4882a593Smuzhiyun char *buffer;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
220*4882a593Smuzhiyun if (!buffer)
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun enable = lpfc_debugfs_enable;
224*4882a593Smuzhiyun lpfc_debugfs_enable = 0;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun len = 0;
227*4882a593Smuzhiyun index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) &
228*4882a593Smuzhiyun (lpfc_debugfs_max_slow_ring_trc - 1);
229*4882a593Smuzhiyun for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) {
230*4882a593Smuzhiyun dtp = phba->slow_ring_trc + i;
231*4882a593Smuzhiyun if (!dtp->fmt)
232*4882a593Smuzhiyun continue;
233*4882a593Smuzhiyun ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
234*4882a593Smuzhiyun snprintf(buffer,
235*4882a593Smuzhiyun LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
236*4882a593Smuzhiyun dtp->seq_cnt, ms, dtp->fmt);
237*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, buffer,
238*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun for (i = 0; i < index; i++) {
241*4882a593Smuzhiyun dtp = phba->slow_ring_trc + i;
242*4882a593Smuzhiyun if (!dtp->fmt)
243*4882a593Smuzhiyun continue;
244*4882a593Smuzhiyun ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
245*4882a593Smuzhiyun snprintf(buffer,
246*4882a593Smuzhiyun LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
247*4882a593Smuzhiyun dtp->seq_cnt, ms, dtp->fmt);
248*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, buffer,
249*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun lpfc_debugfs_enable = enable;
253*4882a593Smuzhiyun kfree(buffer);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun return len;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun static int lpfc_debugfs_last_hbq = -1;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /**
261*4882a593Smuzhiyun * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer
262*4882a593Smuzhiyun * @phba: The HBA to gather host buffer info from.
263*4882a593Smuzhiyun * @buf: The buffer to dump log into.
264*4882a593Smuzhiyun * @size: The maximum amount of data to process.
265*4882a593Smuzhiyun *
266*4882a593Smuzhiyun * Description:
267*4882a593Smuzhiyun * This routine dumps the host buffer queue info from the @phba to @buf up to
268*4882a593Smuzhiyun * @size number of bytes. A header that describes the current hbq state will be
269*4882a593Smuzhiyun * dumped to @buf first and then info on each hbq entry will be dumped to @buf
270*4882a593Smuzhiyun * until @size bytes have been dumped or all the hbq info has been dumped.
271*4882a593Smuzhiyun *
272*4882a593Smuzhiyun * Notes:
273*4882a593Smuzhiyun * This routine will rotate through each configured HBQ each time called.
274*4882a593Smuzhiyun *
275*4882a593Smuzhiyun * Return Value:
276*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
277*4882a593Smuzhiyun * not exceed @size.
278*4882a593Smuzhiyun **/
279*4882a593Smuzhiyun static int
lpfc_debugfs_hbqinfo_data(struct lpfc_hba * phba,char * buf,int size)280*4882a593Smuzhiyun lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun int len = 0;
283*4882a593Smuzhiyun int i, j, found, posted, low;
284*4882a593Smuzhiyun uint32_t phys, raw_index, getidx;
285*4882a593Smuzhiyun struct lpfc_hbq_init *hip;
286*4882a593Smuzhiyun struct hbq_s *hbqs;
287*4882a593Smuzhiyun struct lpfc_hbq_entry *hbqe;
288*4882a593Smuzhiyun struct lpfc_dmabuf *d_buf;
289*4882a593Smuzhiyun struct hbq_dmabuf *hbq_buf;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (phba->sli_rev != 3)
292*4882a593Smuzhiyun return 0;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* toggle between multiple hbqs, if any */
297*4882a593Smuzhiyun i = lpfc_sli_hbq_count();
298*4882a593Smuzhiyun if (i > 1) {
299*4882a593Smuzhiyun lpfc_debugfs_last_hbq++;
300*4882a593Smuzhiyun if (lpfc_debugfs_last_hbq >= i)
301*4882a593Smuzhiyun lpfc_debugfs_last_hbq = 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun else
304*4882a593Smuzhiyun lpfc_debugfs_last_hbq = 0;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun i = lpfc_debugfs_last_hbq;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun hbqs = &phba->hbqs[i];
311*4882a593Smuzhiyun posted = 0;
312*4882a593Smuzhiyun list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list)
313*4882a593Smuzhiyun posted++;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun hip = lpfc_hbq_defs[i];
316*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
317*4882a593Smuzhiyun "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
318*4882a593Smuzhiyun hip->hbq_index, hip->profile, hip->rn,
319*4882a593Smuzhiyun hip->buffer_count, hip->init_count, hip->add_count, posted);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun raw_index = phba->hbq_get[i];
322*4882a593Smuzhiyun getidx = le32_to_cpu(raw_index);
323*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
324*4882a593Smuzhiyun "entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
325*4882a593Smuzhiyun hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
326*4882a593Smuzhiyun hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
329*4882a593Smuzhiyun for (j=0; j<hbqs->entry_count; j++) {
330*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
331*4882a593Smuzhiyun "%03d: %08x %04x %05x ", j,
332*4882a593Smuzhiyun le32_to_cpu(hbqe->bde.addrLow),
333*4882a593Smuzhiyun le32_to_cpu(hbqe->bde.tus.w),
334*4882a593Smuzhiyun le32_to_cpu(hbqe->buffer_tag));
335*4882a593Smuzhiyun i = 0;
336*4882a593Smuzhiyun found = 0;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* First calculate if slot has an associated posted buffer */
339*4882a593Smuzhiyun low = hbqs->hbqPutIdx - posted;
340*4882a593Smuzhiyun if (low >= 0) {
341*4882a593Smuzhiyun if ((j >= hbqs->hbqPutIdx) || (j < low)) {
342*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
343*4882a593Smuzhiyun "Unused\n");
344*4882a593Smuzhiyun goto skipit;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun else {
348*4882a593Smuzhiyun if ((j >= hbqs->hbqPutIdx) &&
349*4882a593Smuzhiyun (j < (hbqs->entry_count+low))) {
350*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
351*4882a593Smuzhiyun "Unused\n");
352*4882a593Smuzhiyun goto skipit;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* Get the Buffer info for the posted buffer */
357*4882a593Smuzhiyun list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
358*4882a593Smuzhiyun hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
359*4882a593Smuzhiyun phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
360*4882a593Smuzhiyun if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
361*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
362*4882a593Smuzhiyun "Buf%d: x%px %06x\n", i,
363*4882a593Smuzhiyun hbq_buf->dbuf.virt, hbq_buf->tag);
364*4882a593Smuzhiyun found = 1;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun i++;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun if (!found) {
370*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "No DMAinfo?\n");
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun skipit:
373*4882a593Smuzhiyun hbqe++;
374*4882a593Smuzhiyun if (len > LPFC_HBQINFO_SIZE - 54)
375*4882a593Smuzhiyun break;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
378*4882a593Smuzhiyun return len;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun static int lpfc_debugfs_last_xripool;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /**
384*4882a593Smuzhiyun * lpfc_debugfs_common_xri_data - Dump Hardware Queue info to a buffer
385*4882a593Smuzhiyun * @phba: The HBA to gather host buffer info from.
386*4882a593Smuzhiyun * @buf: The buffer to dump log into.
387*4882a593Smuzhiyun * @size: The maximum amount of data to process.
388*4882a593Smuzhiyun *
389*4882a593Smuzhiyun * Description:
390*4882a593Smuzhiyun * This routine dumps the Hardware Queue info from the @phba to @buf up to
391*4882a593Smuzhiyun * @size number of bytes. A header that describes the current hdwq state will be
392*4882a593Smuzhiyun * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
393*4882a593Smuzhiyun * until @size bytes have been dumped or all the hdwq info has been dumped.
394*4882a593Smuzhiyun *
395*4882a593Smuzhiyun * Notes:
396*4882a593Smuzhiyun * This routine will rotate through each configured Hardware Queue each
397*4882a593Smuzhiyun * time called.
398*4882a593Smuzhiyun *
399*4882a593Smuzhiyun * Return Value:
400*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
401*4882a593Smuzhiyun * not exceed @size.
402*4882a593Smuzhiyun **/
403*4882a593Smuzhiyun static int
lpfc_debugfs_commonxripools_data(struct lpfc_hba * phba,char * buf,int size)404*4882a593Smuzhiyun lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct lpfc_sli4_hdw_queue *qp;
407*4882a593Smuzhiyun int len = 0;
408*4882a593Smuzhiyun int i, out;
409*4882a593Smuzhiyun unsigned long iflag;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
412*4882a593Smuzhiyun if (len > (LPFC_DUMP_MULTIXRIPOOL_SIZE - 80))
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool];
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i);
417*4882a593Smuzhiyun spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
418*4882a593Smuzhiyun spin_lock(&qp->io_buf_list_get_lock);
419*4882a593Smuzhiyun spin_lock(&qp->io_buf_list_put_lock);
420*4882a593Smuzhiyun out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs +
421*4882a593Smuzhiyun qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs);
422*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
423*4882a593Smuzhiyun "tot:%d get:%d put:%d mt:%d "
424*4882a593Smuzhiyun "ABTS scsi:%d nvme:%d Out:%d\n",
425*4882a593Smuzhiyun qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs,
426*4882a593Smuzhiyun qp->empty_io_bufs, qp->abts_scsi_io_bufs,
427*4882a593Smuzhiyun qp->abts_nvme_io_bufs, out);
428*4882a593Smuzhiyun spin_unlock(&qp->io_buf_list_put_lock);
429*4882a593Smuzhiyun spin_unlock(&qp->io_buf_list_get_lock);
430*4882a593Smuzhiyun spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun lpfc_debugfs_last_xripool++;
433*4882a593Smuzhiyun if (lpfc_debugfs_last_xripool >= phba->cfg_hdw_queue)
434*4882a593Smuzhiyun lpfc_debugfs_last_xripool = 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun return len;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun /**
441*4882a593Smuzhiyun * lpfc_debugfs_multixripools_data - Display multi-XRI pools information
442*4882a593Smuzhiyun * @phba: The HBA to gather host buffer info from.
443*4882a593Smuzhiyun * @buf: The buffer to dump log into.
444*4882a593Smuzhiyun * @size: The maximum amount of data to process.
445*4882a593Smuzhiyun *
446*4882a593Smuzhiyun * Description:
447*4882a593Smuzhiyun * This routine displays current multi-XRI pools information including XRI
448*4882a593Smuzhiyun * count in public, private and txcmplq. It also displays current high and
449*4882a593Smuzhiyun * low watermark.
450*4882a593Smuzhiyun *
451*4882a593Smuzhiyun * Return Value:
452*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
453*4882a593Smuzhiyun * not exceed @size.
454*4882a593Smuzhiyun **/
455*4882a593Smuzhiyun static int
lpfc_debugfs_multixripools_data(struct lpfc_hba * phba,char * buf,int size)456*4882a593Smuzhiyun lpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun u32 i;
459*4882a593Smuzhiyun u32 hwq_count;
460*4882a593Smuzhiyun struct lpfc_sli4_hdw_queue *qp;
461*4882a593Smuzhiyun struct lpfc_multixri_pool *multixri_pool;
462*4882a593Smuzhiyun struct lpfc_pvt_pool *pvt_pool;
463*4882a593Smuzhiyun struct lpfc_pbl_pool *pbl_pool;
464*4882a593Smuzhiyun u32 txcmplq_cnt;
465*4882a593Smuzhiyun char tmp[LPFC_DEBUG_OUT_LINE_SZ] = {0};
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (phba->sli_rev != LPFC_SLI_REV4)
468*4882a593Smuzhiyun return 0;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (!phba->sli4_hba.hdwq)
471*4882a593Smuzhiyun return 0;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (!phba->cfg_xri_rebalancing) {
474*4882a593Smuzhiyun i = lpfc_debugfs_commonxripools_data(phba, buf, size);
475*4882a593Smuzhiyun return i;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * Pbl: Current number of free XRIs in public pool
480*4882a593Smuzhiyun * Pvt: Current number of free XRIs in private pool
481*4882a593Smuzhiyun * Busy: Current number of outstanding XRIs
482*4882a593Smuzhiyun * HWM: Current high watermark
483*4882a593Smuzhiyun * pvt_empty: Incremented by 1 when IO submission fails (no xri)
484*4882a593Smuzhiyun * pbl_empty: Incremented by 1 when all pbl_pool are empty during
485*4882a593Smuzhiyun * IO submission
486*4882a593Smuzhiyun */
487*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
488*4882a593Smuzhiyun "HWQ: Pbl Pvt Busy HWM | pvt_empty pbl_empty ");
489*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
490*4882a593Smuzhiyun return strnlen(buf, size);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun #ifdef LPFC_MXP_STAT
493*4882a593Smuzhiyun /*
494*4882a593Smuzhiyun * MAXH: Max high watermark seen so far
495*4882a593Smuzhiyun * above_lmt: Incremented by 1 if xri_owned > xri_limit during
496*4882a593Smuzhiyun * IO submission
497*4882a593Smuzhiyun * below_lmt: Incremented by 1 if xri_owned <= xri_limit during
498*4882a593Smuzhiyun * IO submission
499*4882a593Smuzhiyun * locPbl_hit: Incremented by 1 if successfully get a batch of XRI from
500*4882a593Smuzhiyun * local pbl_pool
501*4882a593Smuzhiyun * othPbl_hit: Incremented by 1 if successfully get a batch of XRI from
502*4882a593Smuzhiyun * other pbl_pool
503*4882a593Smuzhiyun */
504*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
505*4882a593Smuzhiyun "MAXH above_lmt below_lmt locPbl_hit othPbl_hit");
506*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
507*4882a593Smuzhiyun return strnlen(buf, size);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /*
510*4882a593Smuzhiyun * sPbl: snapshot of Pbl 15 sec after stat gets cleared
511*4882a593Smuzhiyun * sPvt: snapshot of Pvt 15 sec after stat gets cleared
512*4882a593Smuzhiyun * sBusy: snapshot of Busy 15 sec after stat gets cleared
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
515*4882a593Smuzhiyun " | sPbl sPvt sBusy");
516*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
517*4882a593Smuzhiyun return strnlen(buf, size);
518*4882a593Smuzhiyun #endif
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "\n");
521*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
522*4882a593Smuzhiyun return strnlen(buf, size);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun hwq_count = phba->cfg_hdw_queue;
525*4882a593Smuzhiyun for (i = 0; i < hwq_count; i++) {
526*4882a593Smuzhiyun qp = &phba->sli4_hba.hdwq[i];
527*4882a593Smuzhiyun multixri_pool = qp->p_multixri_pool;
528*4882a593Smuzhiyun if (!multixri_pool)
529*4882a593Smuzhiyun continue;
530*4882a593Smuzhiyun pbl_pool = &multixri_pool->pbl_pool;
531*4882a593Smuzhiyun pvt_pool = &multixri_pool->pvt_pool;
532*4882a593Smuzhiyun txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
535*4882a593Smuzhiyun "%03d: %4d %4d %4d %4d | %10d %10d ",
536*4882a593Smuzhiyun i, pbl_pool->count, pvt_pool->count,
537*4882a593Smuzhiyun txcmplq_cnt, pvt_pool->high_watermark,
538*4882a593Smuzhiyun qp->empty_io_bufs, multixri_pool->pbl_empty_count);
539*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
540*4882a593Smuzhiyun break;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun #ifdef LPFC_MXP_STAT
543*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
544*4882a593Smuzhiyun "%4d %10d %10d %10d %10d",
545*4882a593Smuzhiyun multixri_pool->stat_max_hwm,
546*4882a593Smuzhiyun multixri_pool->above_limit_count,
547*4882a593Smuzhiyun multixri_pool->below_limit_count,
548*4882a593Smuzhiyun multixri_pool->local_pbl_hit_count,
549*4882a593Smuzhiyun multixri_pool->other_pbl_hit_count);
550*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
551*4882a593Smuzhiyun break;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
554*4882a593Smuzhiyun " | %4d %4d %5d",
555*4882a593Smuzhiyun multixri_pool->stat_pbl_count,
556*4882a593Smuzhiyun multixri_pool->stat_pvt_count,
557*4882a593Smuzhiyun multixri_pool->stat_busy_count);
558*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
559*4882a593Smuzhiyun break;
560*4882a593Smuzhiyun #endif
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "\n");
563*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
564*4882a593Smuzhiyun break;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun return strnlen(buf, size);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun #ifdef LPFC_HDWQ_LOCK_STAT
571*4882a593Smuzhiyun static int lpfc_debugfs_last_lock;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /**
574*4882a593Smuzhiyun * lpfc_debugfs_lockstat_data - Dump Hardware Queue info to a buffer
575*4882a593Smuzhiyun * @phba: The HBA to gather host buffer info from.
576*4882a593Smuzhiyun * @buf: The buffer to dump log into.
577*4882a593Smuzhiyun * @size: The maximum amount of data to process.
578*4882a593Smuzhiyun *
579*4882a593Smuzhiyun * Description:
580*4882a593Smuzhiyun * This routine dumps the Hardware Queue info from the @phba to @buf up to
581*4882a593Smuzhiyun * @size number of bytes. A header that describes the current hdwq state will be
582*4882a593Smuzhiyun * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
583*4882a593Smuzhiyun * until @size bytes have been dumped or all the hdwq info has been dumped.
584*4882a593Smuzhiyun *
585*4882a593Smuzhiyun * Notes:
586*4882a593Smuzhiyun * This routine will rotate through each configured Hardware Queue each
587*4882a593Smuzhiyun * time called.
588*4882a593Smuzhiyun *
589*4882a593Smuzhiyun * Return Value:
590*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
591*4882a593Smuzhiyun * not exceed @size.
592*4882a593Smuzhiyun **/
593*4882a593Smuzhiyun static int
lpfc_debugfs_lockstat_data(struct lpfc_hba * phba,char * buf,int size)594*4882a593Smuzhiyun lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun struct lpfc_sli4_hdw_queue *qp;
597*4882a593Smuzhiyun int len = 0;
598*4882a593Smuzhiyun int i;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun if (phba->sli_rev != LPFC_SLI_REV4)
601*4882a593Smuzhiyun return 0;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun if (!phba->sli4_hba.hdwq)
604*4882a593Smuzhiyun return 0;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
607*4882a593Smuzhiyun if (len > (LPFC_HDWQINFO_SIZE - 100))
608*4882a593Smuzhiyun break;
609*4882a593Smuzhiyun qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock];
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i);
612*4882a593Smuzhiyun if (phba->cfg_xri_rebalancing) {
613*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
614*4882a593Smuzhiyun "get_pvt:%d mv_pvt:%d "
615*4882a593Smuzhiyun "mv2pub:%d mv2pvt:%d "
616*4882a593Smuzhiyun "put_pvt:%d put_pub:%d wq:%d\n",
617*4882a593Smuzhiyun qp->lock_conflict.alloc_pvt_pool,
618*4882a593Smuzhiyun qp->lock_conflict.mv_from_pvt_pool,
619*4882a593Smuzhiyun qp->lock_conflict.mv_to_pub_pool,
620*4882a593Smuzhiyun qp->lock_conflict.mv_to_pvt_pool,
621*4882a593Smuzhiyun qp->lock_conflict.free_pvt_pool,
622*4882a593Smuzhiyun qp->lock_conflict.free_pub_pool,
623*4882a593Smuzhiyun qp->lock_conflict.wq_access);
624*4882a593Smuzhiyun } else {
625*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
626*4882a593Smuzhiyun "get:%d put:%d free:%d wq:%d\n",
627*4882a593Smuzhiyun qp->lock_conflict.alloc_xri_get,
628*4882a593Smuzhiyun qp->lock_conflict.alloc_xri_put,
629*4882a593Smuzhiyun qp->lock_conflict.free_xri,
630*4882a593Smuzhiyun qp->lock_conflict.wq_access);
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun lpfc_debugfs_last_lock++;
634*4882a593Smuzhiyun if (lpfc_debugfs_last_lock >= phba->cfg_hdw_queue)
635*4882a593Smuzhiyun lpfc_debugfs_last_lock = 0;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun return len;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun #endif
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun static int lpfc_debugfs_last_hba_slim_off;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /**
645*4882a593Smuzhiyun * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer
646*4882a593Smuzhiyun * @phba: The HBA to gather SLIM info from.
647*4882a593Smuzhiyun * @buf: The buffer to dump log into.
648*4882a593Smuzhiyun * @size: The maximum amount of data to process.
649*4882a593Smuzhiyun *
650*4882a593Smuzhiyun * Description:
651*4882a593Smuzhiyun * This routine dumps the current contents of HBA SLIM for the HBA associated
652*4882a593Smuzhiyun * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data.
653*4882a593Smuzhiyun *
654*4882a593Smuzhiyun * Notes:
655*4882a593Smuzhiyun * This routine will only dump up to 1024 bytes of data each time called and
656*4882a593Smuzhiyun * should be called multiple times to dump the entire HBA SLIM.
657*4882a593Smuzhiyun *
658*4882a593Smuzhiyun * Return Value:
659*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
660*4882a593Smuzhiyun * not exceed @size.
661*4882a593Smuzhiyun **/
662*4882a593Smuzhiyun static int
lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba * phba,char * buf,int size)663*4882a593Smuzhiyun lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun int len = 0;
666*4882a593Smuzhiyun int i, off;
667*4882a593Smuzhiyun uint32_t *ptr;
668*4882a593Smuzhiyun char *buffer;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun buffer = kmalloc(1024, GFP_KERNEL);
671*4882a593Smuzhiyun if (!buffer)
672*4882a593Smuzhiyun return 0;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun off = 0;
675*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "HBA SLIM\n");
678*4882a593Smuzhiyun lpfc_memcpy_from_slim(buffer,
679*4882a593Smuzhiyun phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun ptr = (uint32_t *)&buffer[0];
682*4882a593Smuzhiyun off = lpfc_debugfs_last_hba_slim_off;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun /* Set it up for the next time */
685*4882a593Smuzhiyun lpfc_debugfs_last_hba_slim_off += 1024;
686*4882a593Smuzhiyun if (lpfc_debugfs_last_hba_slim_off >= 4096)
687*4882a593Smuzhiyun lpfc_debugfs_last_hba_slim_off = 0;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun i = 1024;
690*4882a593Smuzhiyun while (i > 0) {
691*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
692*4882a593Smuzhiyun "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
693*4882a593Smuzhiyun off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
694*4882a593Smuzhiyun *(ptr+5), *(ptr+6), *(ptr+7));
695*4882a593Smuzhiyun ptr += 8;
696*4882a593Smuzhiyun i -= (8 * sizeof(uint32_t));
697*4882a593Smuzhiyun off += (8 * sizeof(uint32_t));
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
701*4882a593Smuzhiyun kfree(buffer);
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun return len;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun /**
707*4882a593Smuzhiyun * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer
708*4882a593Smuzhiyun * @phba: The HBA to gather Host SLIM info from.
709*4882a593Smuzhiyun * @buf: The buffer to dump log into.
710*4882a593Smuzhiyun * @size: The maximum amount of data to process.
711*4882a593Smuzhiyun *
712*4882a593Smuzhiyun * Description:
713*4882a593Smuzhiyun * This routine dumps the current contents of host SLIM for the host associated
714*4882a593Smuzhiyun * with @phba to @buf up to @size bytes of data. The dump will contain the
715*4882a593Smuzhiyun * Mailbox, PCB, Rings, and Registers that are located in host memory.
716*4882a593Smuzhiyun *
717*4882a593Smuzhiyun * Return Value:
718*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
719*4882a593Smuzhiyun * not exceed @size.
720*4882a593Smuzhiyun **/
721*4882a593Smuzhiyun static int
lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba * phba,char * buf,int size)722*4882a593Smuzhiyun lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun int len = 0;
725*4882a593Smuzhiyun int i, off;
726*4882a593Smuzhiyun uint32_t word0, word1, word2, word3;
727*4882a593Smuzhiyun uint32_t *ptr;
728*4882a593Smuzhiyun struct lpfc_pgp *pgpp;
729*4882a593Smuzhiyun struct lpfc_sli *psli = &phba->sli;
730*4882a593Smuzhiyun struct lpfc_sli_ring *pring;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun off = 0;
733*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "SLIM Mailbox\n");
736*4882a593Smuzhiyun ptr = (uint32_t *)phba->slim2p.virt;
737*4882a593Smuzhiyun i = sizeof(MAILBOX_t);
738*4882a593Smuzhiyun while (i > 0) {
739*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
740*4882a593Smuzhiyun "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
741*4882a593Smuzhiyun off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
742*4882a593Smuzhiyun *(ptr+5), *(ptr+6), *(ptr+7));
743*4882a593Smuzhiyun ptr += 8;
744*4882a593Smuzhiyun i -= (8 * sizeof(uint32_t));
745*4882a593Smuzhiyun off += (8 * sizeof(uint32_t));
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "SLIM PCB\n");
749*4882a593Smuzhiyun ptr = (uint32_t *)phba->pcb;
750*4882a593Smuzhiyun i = sizeof(PCB_t);
751*4882a593Smuzhiyun while (i > 0) {
752*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
753*4882a593Smuzhiyun "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
754*4882a593Smuzhiyun off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
755*4882a593Smuzhiyun *(ptr+5), *(ptr+6), *(ptr+7));
756*4882a593Smuzhiyun ptr += 8;
757*4882a593Smuzhiyun i -= (8 * sizeof(uint32_t));
758*4882a593Smuzhiyun off += (8 * sizeof(uint32_t));
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun if (phba->sli_rev <= LPFC_SLI_REV3) {
762*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
763*4882a593Smuzhiyun pgpp = &phba->port_gp[i];
764*4882a593Smuzhiyun pring = &psli->sli3_ring[i];
765*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
766*4882a593Smuzhiyun "Ring %d: CMD GetInx:%d "
767*4882a593Smuzhiyun "(Max:%d Next:%d "
768*4882a593Smuzhiyun "Local:%d flg:x%x) "
769*4882a593Smuzhiyun "RSP PutInx:%d Max:%d\n",
770*4882a593Smuzhiyun i, pgpp->cmdGetInx,
771*4882a593Smuzhiyun pring->sli.sli3.numCiocb,
772*4882a593Smuzhiyun pring->sli.sli3.next_cmdidx,
773*4882a593Smuzhiyun pring->sli.sli3.local_getidx,
774*4882a593Smuzhiyun pring->flag, pgpp->rspPutInx,
775*4882a593Smuzhiyun pring->sli.sli3.numRiocb);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun word0 = readl(phba->HAregaddr);
779*4882a593Smuzhiyun word1 = readl(phba->CAregaddr);
780*4882a593Smuzhiyun word2 = readl(phba->HSregaddr);
781*4882a593Smuzhiyun word3 = readl(phba->HCregaddr);
782*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
783*4882a593Smuzhiyun "HC:%08x\n", word0, word1, word2, word3);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
786*4882a593Smuzhiyun return len;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun /**
790*4882a593Smuzhiyun * lpfc_debugfs_nodelist_data - Dump target node list to a buffer
791*4882a593Smuzhiyun * @vport: The vport to gather target node info from.
792*4882a593Smuzhiyun * @buf: The buffer to dump log into.
793*4882a593Smuzhiyun * @size: The maximum amount of data to process.
794*4882a593Smuzhiyun *
795*4882a593Smuzhiyun * Description:
796*4882a593Smuzhiyun * This routine dumps the current target node list associated with @vport to
797*4882a593Smuzhiyun * @buf up to @size bytes of data. Each node entry in the dump will contain a
798*4882a593Smuzhiyun * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields.
799*4882a593Smuzhiyun *
800*4882a593Smuzhiyun * Return Value:
801*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
802*4882a593Smuzhiyun * not exceed @size.
803*4882a593Smuzhiyun **/
804*4882a593Smuzhiyun static int
lpfc_debugfs_nodelist_data(struct lpfc_vport * vport,char * buf,int size)805*4882a593Smuzhiyun lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun int len = 0;
808*4882a593Smuzhiyun int i, iocnt, outio, cnt;
809*4882a593Smuzhiyun struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
810*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
811*4882a593Smuzhiyun struct lpfc_nodelist *ndlp;
812*4882a593Smuzhiyun unsigned char *statep;
813*4882a593Smuzhiyun struct nvme_fc_local_port *localport;
814*4882a593Smuzhiyun struct nvme_fc_remote_port *nrport = NULL;
815*4882a593Smuzhiyun struct lpfc_nvme_rport *rport;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
818*4882a593Smuzhiyun outio = 0;
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
821*4882a593Smuzhiyun spin_lock_irq(shost->host_lock);
822*4882a593Smuzhiyun list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
823*4882a593Smuzhiyun iocnt = 0;
824*4882a593Smuzhiyun if (!cnt) {
825*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
826*4882a593Smuzhiyun "Missing Nodelist Entries\n");
827*4882a593Smuzhiyun break;
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun cnt--;
830*4882a593Smuzhiyun switch (ndlp->nlp_state) {
831*4882a593Smuzhiyun case NLP_STE_UNUSED_NODE:
832*4882a593Smuzhiyun statep = "UNUSED";
833*4882a593Smuzhiyun break;
834*4882a593Smuzhiyun case NLP_STE_PLOGI_ISSUE:
835*4882a593Smuzhiyun statep = "PLOGI ";
836*4882a593Smuzhiyun break;
837*4882a593Smuzhiyun case NLP_STE_ADISC_ISSUE:
838*4882a593Smuzhiyun statep = "ADISC ";
839*4882a593Smuzhiyun break;
840*4882a593Smuzhiyun case NLP_STE_REG_LOGIN_ISSUE:
841*4882a593Smuzhiyun statep = "REGLOG";
842*4882a593Smuzhiyun break;
843*4882a593Smuzhiyun case NLP_STE_PRLI_ISSUE:
844*4882a593Smuzhiyun statep = "PRLI ";
845*4882a593Smuzhiyun break;
846*4882a593Smuzhiyun case NLP_STE_LOGO_ISSUE:
847*4882a593Smuzhiyun statep = "LOGO ";
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun case NLP_STE_UNMAPPED_NODE:
850*4882a593Smuzhiyun statep = "UNMAP ";
851*4882a593Smuzhiyun iocnt = 1;
852*4882a593Smuzhiyun break;
853*4882a593Smuzhiyun case NLP_STE_MAPPED_NODE:
854*4882a593Smuzhiyun statep = "MAPPED";
855*4882a593Smuzhiyun iocnt = 1;
856*4882a593Smuzhiyun break;
857*4882a593Smuzhiyun case NLP_STE_NPR_NODE:
858*4882a593Smuzhiyun statep = "NPR ";
859*4882a593Smuzhiyun break;
860*4882a593Smuzhiyun default:
861*4882a593Smuzhiyun statep = "UNKNOWN";
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
864*4882a593Smuzhiyun statep, ndlp->nlp_DID);
865*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
866*4882a593Smuzhiyun "WWPN x%llx ",
867*4882a593Smuzhiyun wwn_to_u64(ndlp->nlp_portname.u.wwn));
868*4882a593Smuzhiyun len += scnprintf(buf+len, size-len,
869*4882a593Smuzhiyun "WWNN x%llx ",
870*4882a593Smuzhiyun wwn_to_u64(ndlp->nlp_nodename.u.wwn));
871*4882a593Smuzhiyun if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
872*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "RPI:%03d ",
873*4882a593Smuzhiyun ndlp->nlp_rpi);
874*4882a593Smuzhiyun else
875*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "RPI:none ");
876*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "flag:x%08x ",
877*4882a593Smuzhiyun ndlp->nlp_flag);
878*4882a593Smuzhiyun if (!ndlp->nlp_type)
879*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE ");
880*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_FC_NODE)
881*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "FC_NODE ");
882*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_FABRIC) {
883*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "FABRIC ");
884*4882a593Smuzhiyun iocnt = 0;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_FCP_TARGET)
887*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ",
888*4882a593Smuzhiyun ndlp->nlp_sid);
889*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_FCP_INITIATOR)
890*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "FCP_INITIATOR ");
891*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_NVME_TARGET)
892*4882a593Smuzhiyun len += scnprintf(buf + len,
893*4882a593Smuzhiyun size - len, "NVME_TGT sid:%d ",
894*4882a593Smuzhiyun NLP_NO_SID);
895*4882a593Smuzhiyun if (ndlp->nlp_type & NLP_NVME_INITIATOR)
896*4882a593Smuzhiyun len += scnprintf(buf + len,
897*4882a593Smuzhiyun size - len, "NVME_INITIATOR ");
898*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "usgmap:%x ",
899*4882a593Smuzhiyun ndlp->nlp_usg_map);
900*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "refcnt:%x",
901*4882a593Smuzhiyun kref_read(&ndlp->kref));
902*4882a593Smuzhiyun if (iocnt) {
903*4882a593Smuzhiyun i = atomic_read(&ndlp->cmd_pending);
904*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
905*4882a593Smuzhiyun " OutIO:x%x Qdepth x%x",
906*4882a593Smuzhiyun i, ndlp->cmd_qdepth);
907*4882a593Smuzhiyun outio += i;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "defer:%x ",
910*4882a593Smuzhiyun ndlp->nlp_defer_did);
911*4882a593Smuzhiyun len += scnprintf(buf+len, size-len, "\n");
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun spin_unlock_irq(shost->host_lock);
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
916*4882a593Smuzhiyun "\nOutstanding IO x%x\n", outio);
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) {
919*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
920*4882a593Smuzhiyun "\nNVME Targetport Entry ...\n");
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun /* Port state is only one of two values for now. */
923*4882a593Smuzhiyun if (phba->targetport->port_id)
924*4882a593Smuzhiyun statep = "REGISTERED";
925*4882a593Smuzhiyun else
926*4882a593Smuzhiyun statep = "INIT";
927*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
928*4882a593Smuzhiyun "TGT WWNN x%llx WWPN x%llx State %s\n",
929*4882a593Smuzhiyun wwn_to_u64(vport->fc_nodename.u.wwn),
930*4882a593Smuzhiyun wwn_to_u64(vport->fc_portname.u.wwn),
931*4882a593Smuzhiyun statep);
932*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
933*4882a593Smuzhiyun " Targetport DID x%06x\n",
934*4882a593Smuzhiyun phba->targetport->port_id);
935*4882a593Smuzhiyun goto out_exit;
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
939*4882a593Smuzhiyun "\nNVME Lport/Rport Entries ...\n");
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun localport = vport->localport;
942*4882a593Smuzhiyun if (!localport)
943*4882a593Smuzhiyun goto out_exit;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun spin_lock_irq(shost->host_lock);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun /* Port state is only one of two values for now. */
948*4882a593Smuzhiyun if (localport->port_id)
949*4882a593Smuzhiyun statep = "ONLINE";
950*4882a593Smuzhiyun else
951*4882a593Smuzhiyun statep = "UNKNOWN ";
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
954*4882a593Smuzhiyun "Lport DID x%06x PortState %s\n",
955*4882a593Smuzhiyun localport->port_id, statep);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\tRport List:\n");
958*4882a593Smuzhiyun list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
959*4882a593Smuzhiyun /* local short-hand pointer. */
960*4882a593Smuzhiyun spin_lock(&phba->hbalock);
961*4882a593Smuzhiyun rport = lpfc_ndlp_get_nrport(ndlp);
962*4882a593Smuzhiyun if (rport)
963*4882a593Smuzhiyun nrport = rport->remoteport;
964*4882a593Smuzhiyun else
965*4882a593Smuzhiyun nrport = NULL;
966*4882a593Smuzhiyun spin_unlock(&phba->hbalock);
967*4882a593Smuzhiyun if (!nrport)
968*4882a593Smuzhiyun continue;
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun /* Port state is only one of two values for now. */
971*4882a593Smuzhiyun switch (nrport->port_state) {
972*4882a593Smuzhiyun case FC_OBJSTATE_ONLINE:
973*4882a593Smuzhiyun statep = "ONLINE";
974*4882a593Smuzhiyun break;
975*4882a593Smuzhiyun case FC_OBJSTATE_UNKNOWN:
976*4882a593Smuzhiyun statep = "UNKNOWN ";
977*4882a593Smuzhiyun break;
978*4882a593Smuzhiyun default:
979*4882a593Smuzhiyun statep = "UNSUPPORTED";
980*4882a593Smuzhiyun break;
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun /* Tab in to show lport ownership. */
984*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
985*4882a593Smuzhiyun "\t%s Port ID:x%06x ",
986*4882a593Smuzhiyun statep, nrport->port_id);
987*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "WWPN x%llx ",
988*4882a593Smuzhiyun nrport->port_name);
989*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "WWNN x%llx ",
990*4882a593Smuzhiyun nrport->node_name);
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun /* An NVME rport can have multiple roles. */
993*4882a593Smuzhiyun if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR)
994*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
995*4882a593Smuzhiyun "INITIATOR ");
996*4882a593Smuzhiyun if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET)
997*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
998*4882a593Smuzhiyun "TARGET ");
999*4882a593Smuzhiyun if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY)
1000*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1001*4882a593Smuzhiyun "DISCSRVC ");
1002*4882a593Smuzhiyun if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
1003*4882a593Smuzhiyun FC_PORT_ROLE_NVME_TARGET |
1004*4882a593Smuzhiyun FC_PORT_ROLE_NVME_DISCOVERY))
1005*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1006*4882a593Smuzhiyun "UNKNOWN ROLE x%x",
1007*4882a593Smuzhiyun nrport->port_role);
1008*4882a593Smuzhiyun /* Terminate the string. */
1009*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun spin_unlock_irq(shost->host_lock);
1013*4882a593Smuzhiyun out_exit:
1014*4882a593Smuzhiyun return len;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun /**
1018*4882a593Smuzhiyun * lpfc_debugfs_nvmestat_data - Dump target node list to a buffer
1019*4882a593Smuzhiyun * @vport: The vport to gather target node info from.
1020*4882a593Smuzhiyun * @buf: The buffer to dump log into.
1021*4882a593Smuzhiyun * @size: The maximum amount of data to process.
1022*4882a593Smuzhiyun *
1023*4882a593Smuzhiyun * Description:
1024*4882a593Smuzhiyun * This routine dumps the NVME statistics associated with @vport
1025*4882a593Smuzhiyun *
1026*4882a593Smuzhiyun * Return Value:
1027*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
1028*4882a593Smuzhiyun * not exceed @size.
1029*4882a593Smuzhiyun **/
1030*4882a593Smuzhiyun static int
lpfc_debugfs_nvmestat_data(struct lpfc_vport * vport,char * buf,int size)1031*4882a593Smuzhiyun lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
1032*4882a593Smuzhiyun {
1033*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
1034*4882a593Smuzhiyun struct lpfc_nvmet_tgtport *tgtp;
1035*4882a593Smuzhiyun struct lpfc_async_xchg_ctx *ctxp, *next_ctxp;
1036*4882a593Smuzhiyun struct nvme_fc_local_port *localport;
1037*4882a593Smuzhiyun struct lpfc_fc4_ctrl_stat *cstat;
1038*4882a593Smuzhiyun struct lpfc_nvme_lport *lport;
1039*4882a593Smuzhiyun uint64_t data1, data2, data3;
1040*4882a593Smuzhiyun uint64_t tot, totin, totout;
1041*4882a593Smuzhiyun int cnt, i;
1042*4882a593Smuzhiyun int len = 0;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun if (phba->nvmet_support) {
1045*4882a593Smuzhiyun if (!phba->targetport)
1046*4882a593Smuzhiyun return len;
1047*4882a593Smuzhiyun tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
1048*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1049*4882a593Smuzhiyun "\nNVME Targetport Statistics\n");
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1052*4882a593Smuzhiyun "LS: Rcv %08x Drop %08x Abort %08x\n",
1053*4882a593Smuzhiyun atomic_read(&tgtp->rcv_ls_req_in),
1054*4882a593Smuzhiyun atomic_read(&tgtp->rcv_ls_req_drop),
1055*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_abort));
1056*4882a593Smuzhiyun if (atomic_read(&tgtp->rcv_ls_req_in) !=
1057*4882a593Smuzhiyun atomic_read(&tgtp->rcv_ls_req_out)) {
1058*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1059*4882a593Smuzhiyun "Rcv LS: in %08x != out %08x\n",
1060*4882a593Smuzhiyun atomic_read(&tgtp->rcv_ls_req_in),
1061*4882a593Smuzhiyun atomic_read(&tgtp->rcv_ls_req_out));
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun
1064*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1065*4882a593Smuzhiyun "LS: Xmt %08x Drop %08x Cmpl %08x\n",
1066*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_rsp),
1067*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_drop),
1068*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_rsp_cmpl));
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1071*4882a593Smuzhiyun "LS: RSP Abort %08x xb %08x Err %08x\n",
1072*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_rsp_aborted),
1073*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_rsp_xb_set),
1074*4882a593Smuzhiyun atomic_read(&tgtp->xmt_ls_rsp_error));
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1077*4882a593Smuzhiyun "FCP: Rcv %08x Defer %08x Release %08x "
1078*4882a593Smuzhiyun "Drop %08x\n",
1079*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_in),
1080*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_defer),
1081*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_release),
1082*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_drop));
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun if (atomic_read(&tgtp->rcv_fcp_cmd_in) !=
1085*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_out)) {
1086*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1087*4882a593Smuzhiyun "Rcv FCP: in %08x != out %08x\n",
1088*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_in),
1089*4882a593Smuzhiyun atomic_read(&tgtp->rcv_fcp_cmd_out));
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1093*4882a593Smuzhiyun "FCP Rsp: read %08x readrsp %08x "
1094*4882a593Smuzhiyun "write %08x rsp %08x\n",
1095*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_read),
1096*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_read_rsp),
1097*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_write),
1098*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp));
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1101*4882a593Smuzhiyun "FCP Rsp Cmpl: %08x err %08x drop %08x\n",
1102*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp_cmpl),
1103*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp_error),
1104*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp_drop));
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1107*4882a593Smuzhiyun "FCP Rsp Abort: %08x xb %08x xricqe %08x\n",
1108*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp_aborted),
1109*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_rsp_xb_set),
1110*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_xri_abort_cqe));
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1113*4882a593Smuzhiyun "ABORT: Xmt %08x Cmpl %08x\n",
1114*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_abort),
1115*4882a593Smuzhiyun atomic_read(&tgtp->xmt_fcp_abort_cmpl));
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1118*4882a593Smuzhiyun "ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x",
1119*4882a593Smuzhiyun atomic_read(&tgtp->xmt_abort_sol),
1120*4882a593Smuzhiyun atomic_read(&tgtp->xmt_abort_unsol),
1121*4882a593Smuzhiyun atomic_read(&tgtp->xmt_abort_rsp),
1122*4882a593Smuzhiyun atomic_read(&tgtp->xmt_abort_rsp_error));
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, "\n");
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun cnt = 0;
1127*4882a593Smuzhiyun spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
1128*4882a593Smuzhiyun list_for_each_entry_safe(ctxp, next_ctxp,
1129*4882a593Smuzhiyun &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
1130*4882a593Smuzhiyun list) {
1131*4882a593Smuzhiyun cnt++;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
1134*4882a593Smuzhiyun if (cnt) {
1135*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1136*4882a593Smuzhiyun "ABORT: %d ctx entries\n", cnt);
1137*4882a593Smuzhiyun spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
1138*4882a593Smuzhiyun list_for_each_entry_safe(ctxp, next_ctxp,
1139*4882a593Smuzhiyun &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
1140*4882a593Smuzhiyun list) {
1141*4882a593Smuzhiyun if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ))
1142*4882a593Smuzhiyun break;
1143*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1144*4882a593Smuzhiyun "Entry: oxid %x state %x "
1145*4882a593Smuzhiyun "flag %x\n",
1146*4882a593Smuzhiyun ctxp->oxid, ctxp->state,
1147*4882a593Smuzhiyun ctxp->flag);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun /* Calculate outstanding IOs */
1153*4882a593Smuzhiyun tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
1154*4882a593Smuzhiyun tot += atomic_read(&tgtp->xmt_fcp_release);
1155*4882a593Smuzhiyun tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot;
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1158*4882a593Smuzhiyun "IO_CTX: %08x WAIT: cur %08x tot %08x\n"
1159*4882a593Smuzhiyun "CTX Outstanding %08llx\n",
1160*4882a593Smuzhiyun phba->sli4_hba.nvmet_xri_cnt,
1161*4882a593Smuzhiyun phba->sli4_hba.nvmet_io_wait_cnt,
1162*4882a593Smuzhiyun phba->sli4_hba.nvmet_io_wait_total,
1163*4882a593Smuzhiyun tot);
1164*4882a593Smuzhiyun } else {
1165*4882a593Smuzhiyun if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME))
1166*4882a593Smuzhiyun return len;
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun localport = vport->localport;
1169*4882a593Smuzhiyun if (!localport)
1170*4882a593Smuzhiyun return len;
1171*4882a593Smuzhiyun lport = (struct lpfc_nvme_lport *)localport->private;
1172*4882a593Smuzhiyun if (!lport)
1173*4882a593Smuzhiyun return len;
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1176*4882a593Smuzhiyun "\nNVME HDWQ Statistics\n");
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1179*4882a593Smuzhiyun "LS: Xmt %016x Cmpl %016x\n",
1180*4882a593Smuzhiyun atomic_read(&lport->fc4NvmeLsRequests),
1181*4882a593Smuzhiyun atomic_read(&lport->fc4NvmeLsCmpls));
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun totin = 0;
1184*4882a593Smuzhiyun totout = 0;
1185*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
1186*4882a593Smuzhiyun cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
1187*4882a593Smuzhiyun tot = cstat->io_cmpls;
1188*4882a593Smuzhiyun totin += tot;
1189*4882a593Smuzhiyun data1 = cstat->input_requests;
1190*4882a593Smuzhiyun data2 = cstat->output_requests;
1191*4882a593Smuzhiyun data3 = cstat->control_requests;
1192*4882a593Smuzhiyun totout += (data1 + data2 + data3);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun /* Limit to 32, debugfs display buffer limitation */
1195*4882a593Smuzhiyun if (i >= 32)
1196*4882a593Smuzhiyun continue;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
1199*4882a593Smuzhiyun "HDWQ (%d): Rd %016llx Wr %016llx "
1200*4882a593Smuzhiyun "IO %016llx ",
1201*4882a593Smuzhiyun i, data1, data2, data3);
1202*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
1203*4882a593Smuzhiyun "Cmpl %016llx OutIO %016llx\n",
1204*4882a593Smuzhiyun tot, ((data1 + data2 + data3) - tot));
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
1207*4882a593Smuzhiyun "Total FCP Cmpl %016llx Issue %016llx "
1208*4882a593Smuzhiyun "OutIO %016llx\n",
1209*4882a593Smuzhiyun totin, totout, totout - totin);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1212*4882a593Smuzhiyun "LS Xmt Err: Abrt %08x Err %08x "
1213*4882a593Smuzhiyun "Cmpl Err: xb %08x Err %08x\n",
1214*4882a593Smuzhiyun atomic_read(&lport->xmt_ls_abort),
1215*4882a593Smuzhiyun atomic_read(&lport->xmt_ls_err),
1216*4882a593Smuzhiyun atomic_read(&lport->cmpl_ls_xb),
1217*4882a593Smuzhiyun atomic_read(&lport->cmpl_ls_err));
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1220*4882a593Smuzhiyun "FCP Xmt Err: noxri %06x nondlp %06x "
1221*4882a593Smuzhiyun "qdepth %06x wqerr %06x err %06x Abrt %06x\n",
1222*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_noxri),
1223*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_bad_ndlp),
1224*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_qdepth),
1225*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_wqerr),
1226*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_err),
1227*4882a593Smuzhiyun atomic_read(&lport->xmt_fcp_abort));
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1230*4882a593Smuzhiyun "FCP Cmpl Err: xb %08x Err %08x\n",
1231*4882a593Smuzhiyun atomic_read(&lport->cmpl_fcp_xb),
1232*4882a593Smuzhiyun atomic_read(&lport->cmpl_fcp_err));
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun return len;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun /**
1240*4882a593Smuzhiyun * lpfc_debugfs_scsistat_data - Dump target node list to a buffer
1241*4882a593Smuzhiyun * @vport: The vport to gather target node info from.
1242*4882a593Smuzhiyun * @buf: The buffer to dump log into.
1243*4882a593Smuzhiyun * @size: The maximum amount of data to process.
1244*4882a593Smuzhiyun *
1245*4882a593Smuzhiyun * Description:
1246*4882a593Smuzhiyun * This routine dumps the SCSI statistics associated with @vport
1247*4882a593Smuzhiyun *
1248*4882a593Smuzhiyun * Return Value:
1249*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
1250*4882a593Smuzhiyun * not exceed @size.
1251*4882a593Smuzhiyun **/
1252*4882a593Smuzhiyun static int
lpfc_debugfs_scsistat_data(struct lpfc_vport * vport,char * buf,int size)1253*4882a593Smuzhiyun lpfc_debugfs_scsistat_data(struct lpfc_vport *vport, char *buf, int size)
1254*4882a593Smuzhiyun {
1255*4882a593Smuzhiyun int len;
1256*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
1257*4882a593Smuzhiyun struct lpfc_fc4_ctrl_stat *cstat;
1258*4882a593Smuzhiyun u64 data1, data2, data3;
1259*4882a593Smuzhiyun u64 tot, totin, totout;
1260*4882a593Smuzhiyun int i;
1261*4882a593Smuzhiyun char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
1264*4882a593Smuzhiyun (phba->sli_rev != LPFC_SLI_REV4))
1265*4882a593Smuzhiyun return 0;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun scnprintf(buf, size, "SCSI HDWQ Statistics\n");
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun totin = 0;
1270*4882a593Smuzhiyun totout = 0;
1271*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
1272*4882a593Smuzhiyun cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
1273*4882a593Smuzhiyun tot = cstat->io_cmpls;
1274*4882a593Smuzhiyun totin += tot;
1275*4882a593Smuzhiyun data1 = cstat->input_requests;
1276*4882a593Smuzhiyun data2 = cstat->output_requests;
1277*4882a593Smuzhiyun data3 = cstat->control_requests;
1278*4882a593Smuzhiyun totout += (data1 + data2 + data3);
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx "
1281*4882a593Smuzhiyun "IO %016llx ", i, data1, data2, data3);
1282*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1283*4882a593Smuzhiyun goto buffer_done;
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n",
1286*4882a593Smuzhiyun tot, ((data1 + data2 + data3) - tot));
1287*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1288*4882a593Smuzhiyun goto buffer_done;
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx "
1291*4882a593Smuzhiyun "OutIO %016llx\n", totin, totout, totout - totin);
1292*4882a593Smuzhiyun strlcat(buf, tmp, size);
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun buffer_done:
1295*4882a593Smuzhiyun len = strnlen(buf, size);
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun return len;
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun void
lpfc_io_ktime(struct lpfc_hba * phba,struct lpfc_io_buf * lpfc_cmd)1301*4882a593Smuzhiyun lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
1302*4882a593Smuzhiyun {
1303*4882a593Smuzhiyun uint64_t seg1, seg2, seg3, seg4;
1304*4882a593Smuzhiyun uint64_t segsum;
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun if (!lpfc_cmd->ts_last_cmd ||
1307*4882a593Smuzhiyun !lpfc_cmd->ts_cmd_start ||
1308*4882a593Smuzhiyun !lpfc_cmd->ts_cmd_wqput ||
1309*4882a593Smuzhiyun !lpfc_cmd->ts_isr_cmpl ||
1310*4882a593Smuzhiyun !lpfc_cmd->ts_data_io)
1311*4882a593Smuzhiyun return;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start)
1314*4882a593Smuzhiyun return;
1315*4882a593Smuzhiyun if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd)
1316*4882a593Smuzhiyun return;
1317*4882a593Smuzhiyun if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start)
1318*4882a593Smuzhiyun return;
1319*4882a593Smuzhiyun if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput)
1320*4882a593Smuzhiyun return;
1321*4882a593Smuzhiyun if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl)
1322*4882a593Smuzhiyun return;
1323*4882a593Smuzhiyun /*
1324*4882a593Smuzhiyun * Segment 1 - Time from Last FCP command cmpl is handed
1325*4882a593Smuzhiyun * off to NVME Layer to start of next command.
1326*4882a593Smuzhiyun * Segment 2 - Time from Driver receives a IO cmd start
1327*4882a593Smuzhiyun * from NVME Layer to WQ put is done on IO cmd.
1328*4882a593Smuzhiyun * Segment 3 - Time from Driver WQ put is done on IO cmd
1329*4882a593Smuzhiyun * to MSI-X ISR for IO cmpl.
1330*4882a593Smuzhiyun * Segment 4 - Time from MSI-X ISR for IO cmpl to when
1331*4882a593Smuzhiyun * cmpl is handled off to the NVME Layer.
1332*4882a593Smuzhiyun */
1333*4882a593Smuzhiyun seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd;
1334*4882a593Smuzhiyun if (seg1 > 5000000) /* 5 ms - for sequential IOs only */
1335*4882a593Smuzhiyun seg1 = 0;
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun /* Calculate times relative to start of IO */
1338*4882a593Smuzhiyun seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start);
1339*4882a593Smuzhiyun segsum = seg2;
1340*4882a593Smuzhiyun seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start;
1341*4882a593Smuzhiyun if (segsum > seg3)
1342*4882a593Smuzhiyun return;
1343*4882a593Smuzhiyun seg3 -= segsum;
1344*4882a593Smuzhiyun segsum += seg3;
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start;
1347*4882a593Smuzhiyun if (segsum > seg4)
1348*4882a593Smuzhiyun return;
1349*4882a593Smuzhiyun seg4 -= segsum;
1350*4882a593Smuzhiyun
1351*4882a593Smuzhiyun phba->ktime_data_samples++;
1352*4882a593Smuzhiyun phba->ktime_seg1_total += seg1;
1353*4882a593Smuzhiyun if (seg1 < phba->ktime_seg1_min)
1354*4882a593Smuzhiyun phba->ktime_seg1_min = seg1;
1355*4882a593Smuzhiyun else if (seg1 > phba->ktime_seg1_max)
1356*4882a593Smuzhiyun phba->ktime_seg1_max = seg1;
1357*4882a593Smuzhiyun phba->ktime_seg2_total += seg2;
1358*4882a593Smuzhiyun if (seg2 < phba->ktime_seg2_min)
1359*4882a593Smuzhiyun phba->ktime_seg2_min = seg2;
1360*4882a593Smuzhiyun else if (seg2 > phba->ktime_seg2_max)
1361*4882a593Smuzhiyun phba->ktime_seg2_max = seg2;
1362*4882a593Smuzhiyun phba->ktime_seg3_total += seg3;
1363*4882a593Smuzhiyun if (seg3 < phba->ktime_seg3_min)
1364*4882a593Smuzhiyun phba->ktime_seg3_min = seg3;
1365*4882a593Smuzhiyun else if (seg3 > phba->ktime_seg3_max)
1366*4882a593Smuzhiyun phba->ktime_seg3_max = seg3;
1367*4882a593Smuzhiyun phba->ktime_seg4_total += seg4;
1368*4882a593Smuzhiyun if (seg4 < phba->ktime_seg4_min)
1369*4882a593Smuzhiyun phba->ktime_seg4_min = seg4;
1370*4882a593Smuzhiyun else if (seg4 > phba->ktime_seg4_max)
1371*4882a593Smuzhiyun phba->ktime_seg4_max = seg4;
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun lpfc_cmd->ts_last_cmd = 0;
1374*4882a593Smuzhiyun lpfc_cmd->ts_cmd_start = 0;
1375*4882a593Smuzhiyun lpfc_cmd->ts_cmd_wqput = 0;
1376*4882a593Smuzhiyun lpfc_cmd->ts_isr_cmpl = 0;
1377*4882a593Smuzhiyun lpfc_cmd->ts_data_io = 0;
1378*4882a593Smuzhiyun }
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun /**
1381*4882a593Smuzhiyun * lpfc_debugfs_ioktime_data - Dump target node list to a buffer
1382*4882a593Smuzhiyun * @vport: The vport to gather target node info from.
1383*4882a593Smuzhiyun * @buf: The buffer to dump log into.
1384*4882a593Smuzhiyun * @size: The maximum amount of data to process.
1385*4882a593Smuzhiyun *
1386*4882a593Smuzhiyun * Description:
1387*4882a593Smuzhiyun * This routine dumps the NVME statistics associated with @vport
1388*4882a593Smuzhiyun *
1389*4882a593Smuzhiyun * Return Value:
1390*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
1391*4882a593Smuzhiyun * not exceed @size.
1392*4882a593Smuzhiyun **/
1393*4882a593Smuzhiyun static int
lpfc_debugfs_ioktime_data(struct lpfc_vport * vport,char * buf,int size)1394*4882a593Smuzhiyun lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size)
1395*4882a593Smuzhiyun {
1396*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
1397*4882a593Smuzhiyun int len = 0;
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun if (phba->nvmet_support == 0) {
1400*4882a593Smuzhiyun /* Initiator */
1401*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
1402*4882a593Smuzhiyun "ktime %s: Total Samples: %lld\n",
1403*4882a593Smuzhiyun (phba->ktime_on ? "Enabled" : "Disabled"),
1404*4882a593Smuzhiyun phba->ktime_data_samples);
1405*4882a593Smuzhiyun if (phba->ktime_data_samples == 0)
1406*4882a593Smuzhiyun return len;
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun len += scnprintf(
1409*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1410*4882a593Smuzhiyun "Segment 1: Last Cmd cmpl "
1411*4882a593Smuzhiyun "done -to- Start of next Cmd (in driver)\n");
1412*4882a593Smuzhiyun len += scnprintf(
1413*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1414*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1415*4882a593Smuzhiyun div_u64(phba->ktime_seg1_total,
1416*4882a593Smuzhiyun phba->ktime_data_samples),
1417*4882a593Smuzhiyun phba->ktime_seg1_min,
1418*4882a593Smuzhiyun phba->ktime_seg1_max);
1419*4882a593Smuzhiyun len += scnprintf(
1420*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1421*4882a593Smuzhiyun "Segment 2: Driver start of Cmd "
1422*4882a593Smuzhiyun "-to- Firmware WQ doorbell\n");
1423*4882a593Smuzhiyun len += scnprintf(
1424*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1425*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1426*4882a593Smuzhiyun div_u64(phba->ktime_seg2_total,
1427*4882a593Smuzhiyun phba->ktime_data_samples),
1428*4882a593Smuzhiyun phba->ktime_seg2_min,
1429*4882a593Smuzhiyun phba->ktime_seg2_max);
1430*4882a593Smuzhiyun len += scnprintf(
1431*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1432*4882a593Smuzhiyun "Segment 3: Firmware WQ doorbell -to- "
1433*4882a593Smuzhiyun "MSI-X ISR cmpl\n");
1434*4882a593Smuzhiyun len += scnprintf(
1435*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1436*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1437*4882a593Smuzhiyun div_u64(phba->ktime_seg3_total,
1438*4882a593Smuzhiyun phba->ktime_data_samples),
1439*4882a593Smuzhiyun phba->ktime_seg3_min,
1440*4882a593Smuzhiyun phba->ktime_seg3_max);
1441*4882a593Smuzhiyun len += scnprintf(
1442*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1443*4882a593Smuzhiyun "Segment 4: MSI-X ISR cmpl -to- "
1444*4882a593Smuzhiyun "Cmd cmpl done\n");
1445*4882a593Smuzhiyun len += scnprintf(
1446*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1447*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1448*4882a593Smuzhiyun div_u64(phba->ktime_seg4_total,
1449*4882a593Smuzhiyun phba->ktime_data_samples),
1450*4882a593Smuzhiyun phba->ktime_seg4_min,
1451*4882a593Smuzhiyun phba->ktime_seg4_max);
1452*4882a593Smuzhiyun len += scnprintf(
1453*4882a593Smuzhiyun buf + len, PAGE_SIZE - len,
1454*4882a593Smuzhiyun "Total IO avg time: %08lld\n",
1455*4882a593Smuzhiyun div_u64(phba->ktime_seg1_total +
1456*4882a593Smuzhiyun phba->ktime_seg2_total +
1457*4882a593Smuzhiyun phba->ktime_seg3_total +
1458*4882a593Smuzhiyun phba->ktime_seg4_total,
1459*4882a593Smuzhiyun phba->ktime_data_samples));
1460*4882a593Smuzhiyun return len;
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun /* NVME Target */
1464*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1465*4882a593Smuzhiyun "ktime %s: Total Samples: %lld %lld\n",
1466*4882a593Smuzhiyun (phba->ktime_on ? "Enabled" : "Disabled"),
1467*4882a593Smuzhiyun phba->ktime_data_samples,
1468*4882a593Smuzhiyun phba->ktime_status_samples);
1469*4882a593Smuzhiyun if (phba->ktime_data_samples == 0)
1470*4882a593Smuzhiyun return len;
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1473*4882a593Smuzhiyun "Segment 1: MSI-X ISR Rcv cmd -to- "
1474*4882a593Smuzhiyun "cmd pass to NVME Layer\n");
1475*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1476*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1477*4882a593Smuzhiyun div_u64(phba->ktime_seg1_total,
1478*4882a593Smuzhiyun phba->ktime_data_samples),
1479*4882a593Smuzhiyun phba->ktime_seg1_min,
1480*4882a593Smuzhiyun phba->ktime_seg1_max);
1481*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1482*4882a593Smuzhiyun "Segment 2: cmd pass to NVME Layer- "
1483*4882a593Smuzhiyun "-to- Driver rcv cmd OP (action)\n");
1484*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1485*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1486*4882a593Smuzhiyun div_u64(phba->ktime_seg2_total,
1487*4882a593Smuzhiyun phba->ktime_data_samples),
1488*4882a593Smuzhiyun phba->ktime_seg2_min,
1489*4882a593Smuzhiyun phba->ktime_seg2_max);
1490*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1491*4882a593Smuzhiyun "Segment 3: Driver rcv cmd OP -to- "
1492*4882a593Smuzhiyun "Firmware WQ doorbell: cmd\n");
1493*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1494*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1495*4882a593Smuzhiyun div_u64(phba->ktime_seg3_total,
1496*4882a593Smuzhiyun phba->ktime_data_samples),
1497*4882a593Smuzhiyun phba->ktime_seg3_min,
1498*4882a593Smuzhiyun phba->ktime_seg3_max);
1499*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1500*4882a593Smuzhiyun "Segment 4: Firmware WQ doorbell: cmd "
1501*4882a593Smuzhiyun "-to- MSI-X ISR for cmd cmpl\n");
1502*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1503*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1504*4882a593Smuzhiyun div_u64(phba->ktime_seg4_total,
1505*4882a593Smuzhiyun phba->ktime_data_samples),
1506*4882a593Smuzhiyun phba->ktime_seg4_min,
1507*4882a593Smuzhiyun phba->ktime_seg4_max);
1508*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1509*4882a593Smuzhiyun "Segment 5: MSI-X ISR for cmd cmpl "
1510*4882a593Smuzhiyun "-to- NVME layer passed cmd done\n");
1511*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1512*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1513*4882a593Smuzhiyun div_u64(phba->ktime_seg5_total,
1514*4882a593Smuzhiyun phba->ktime_data_samples),
1515*4882a593Smuzhiyun phba->ktime_seg5_min,
1516*4882a593Smuzhiyun phba->ktime_seg5_max);
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun if (phba->ktime_status_samples == 0) {
1519*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1520*4882a593Smuzhiyun "Total: cmd received by MSI-X ISR "
1521*4882a593Smuzhiyun "-to- cmd completed on wire\n");
1522*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1523*4882a593Smuzhiyun "avg:%08lld min:%08lld "
1524*4882a593Smuzhiyun "max %08lld\n",
1525*4882a593Smuzhiyun div_u64(phba->ktime_seg10_total,
1526*4882a593Smuzhiyun phba->ktime_data_samples),
1527*4882a593Smuzhiyun phba->ktime_seg10_min,
1528*4882a593Smuzhiyun phba->ktime_seg10_max);
1529*4882a593Smuzhiyun return len;
1530*4882a593Smuzhiyun }
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1533*4882a593Smuzhiyun "Segment 6: NVME layer passed cmd done "
1534*4882a593Smuzhiyun "-to- Driver rcv rsp status OP\n");
1535*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1536*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1537*4882a593Smuzhiyun div_u64(phba->ktime_seg6_total,
1538*4882a593Smuzhiyun phba->ktime_status_samples),
1539*4882a593Smuzhiyun phba->ktime_seg6_min,
1540*4882a593Smuzhiyun phba->ktime_seg6_max);
1541*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1542*4882a593Smuzhiyun "Segment 7: Driver rcv rsp status OP "
1543*4882a593Smuzhiyun "-to- Firmware WQ doorbell: status\n");
1544*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1545*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1546*4882a593Smuzhiyun div_u64(phba->ktime_seg7_total,
1547*4882a593Smuzhiyun phba->ktime_status_samples),
1548*4882a593Smuzhiyun phba->ktime_seg7_min,
1549*4882a593Smuzhiyun phba->ktime_seg7_max);
1550*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1551*4882a593Smuzhiyun "Segment 8: Firmware WQ doorbell: status"
1552*4882a593Smuzhiyun " -to- MSI-X ISR for status cmpl\n");
1553*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1554*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1555*4882a593Smuzhiyun div_u64(phba->ktime_seg8_total,
1556*4882a593Smuzhiyun phba->ktime_status_samples),
1557*4882a593Smuzhiyun phba->ktime_seg8_min,
1558*4882a593Smuzhiyun phba->ktime_seg8_max);
1559*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1560*4882a593Smuzhiyun "Segment 9: MSI-X ISR for status cmpl "
1561*4882a593Smuzhiyun "-to- NVME layer passed status done\n");
1562*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1563*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1564*4882a593Smuzhiyun div_u64(phba->ktime_seg9_total,
1565*4882a593Smuzhiyun phba->ktime_status_samples),
1566*4882a593Smuzhiyun phba->ktime_seg9_min,
1567*4882a593Smuzhiyun phba->ktime_seg9_max);
1568*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1569*4882a593Smuzhiyun "Total: cmd received by MSI-X ISR -to- "
1570*4882a593Smuzhiyun "cmd completed on wire\n");
1571*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE-len,
1572*4882a593Smuzhiyun "avg:%08lld min:%08lld max %08lld\n",
1573*4882a593Smuzhiyun div_u64(phba->ktime_seg10_total,
1574*4882a593Smuzhiyun phba->ktime_status_samples),
1575*4882a593Smuzhiyun phba->ktime_seg10_min,
1576*4882a593Smuzhiyun phba->ktime_seg10_max);
1577*4882a593Smuzhiyun return len;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
1580*4882a593Smuzhiyun /**
1581*4882a593Smuzhiyun * lpfc_debugfs_nvmeio_trc_data - Dump NVME IO trace list to a buffer
1582*4882a593Smuzhiyun * @phba: The phba to gather target node info from.
1583*4882a593Smuzhiyun * @buf: The buffer to dump log into.
1584*4882a593Smuzhiyun * @size: The maximum amount of data to process.
1585*4882a593Smuzhiyun *
1586*4882a593Smuzhiyun * Description:
1587*4882a593Smuzhiyun * This routine dumps the NVME IO trace associated with @phba
1588*4882a593Smuzhiyun *
1589*4882a593Smuzhiyun * Return Value:
1590*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
1591*4882a593Smuzhiyun * not exceed @size.
1592*4882a593Smuzhiyun **/
1593*4882a593Smuzhiyun static int
lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba * phba,char * buf,int size)1594*4882a593Smuzhiyun lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
1595*4882a593Smuzhiyun {
1596*4882a593Smuzhiyun struct lpfc_debugfs_nvmeio_trc *dtp;
1597*4882a593Smuzhiyun int i, state, index, skip;
1598*4882a593Smuzhiyun int len = 0;
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun state = phba->nvmeio_trc_on;
1601*4882a593Smuzhiyun
1602*4882a593Smuzhiyun index = (atomic_read(&phba->nvmeio_trc_cnt) + 1) &
1603*4882a593Smuzhiyun (phba->nvmeio_trc_size - 1);
1604*4882a593Smuzhiyun skip = phba->nvmeio_trc_output_idx;
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1607*4882a593Smuzhiyun "%s IO Trace %s: next_idx %d skip %d size %d\n",
1608*4882a593Smuzhiyun (phba->nvmet_support ? "NVME" : "NVMET"),
1609*4882a593Smuzhiyun (state ? "Enabled" : "Disabled"),
1610*4882a593Smuzhiyun index, skip, phba->nvmeio_trc_size);
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun if (!phba->nvmeio_trc || state)
1613*4882a593Smuzhiyun return len;
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun /* trace MUST bhe off to continue */
1616*4882a593Smuzhiyun
1617*4882a593Smuzhiyun for (i = index; i < phba->nvmeio_trc_size; i++) {
1618*4882a593Smuzhiyun if (skip) {
1619*4882a593Smuzhiyun skip--;
1620*4882a593Smuzhiyun continue;
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun dtp = phba->nvmeio_trc + i;
1623*4882a593Smuzhiyun phba->nvmeio_trc_output_idx++;
1624*4882a593Smuzhiyun
1625*4882a593Smuzhiyun if (!dtp->fmt)
1626*4882a593Smuzhiyun continue;
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, dtp->fmt,
1629*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
1632*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
1633*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1634*4882a593Smuzhiyun "Trace Complete\n");
1635*4882a593Smuzhiyun goto out;
1636*4882a593Smuzhiyun }
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
1639*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1640*4882a593Smuzhiyun "Trace Continue (%d of %d)\n",
1641*4882a593Smuzhiyun phba->nvmeio_trc_output_idx,
1642*4882a593Smuzhiyun phba->nvmeio_trc_size);
1643*4882a593Smuzhiyun goto out;
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun for (i = 0; i < index; i++) {
1647*4882a593Smuzhiyun if (skip) {
1648*4882a593Smuzhiyun skip--;
1649*4882a593Smuzhiyun continue;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun dtp = phba->nvmeio_trc + i;
1652*4882a593Smuzhiyun phba->nvmeio_trc_output_idx++;
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun if (!dtp->fmt)
1655*4882a593Smuzhiyun continue;
1656*4882a593Smuzhiyun
1657*4882a593Smuzhiyun len += scnprintf(buf + len, size - len, dtp->fmt,
1658*4882a593Smuzhiyun dtp->data1, dtp->data2, dtp->data3);
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
1661*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
1662*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1663*4882a593Smuzhiyun "Trace Complete\n");
1664*4882a593Smuzhiyun goto out;
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
1668*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1669*4882a593Smuzhiyun "Trace Continue (%d of %d)\n",
1670*4882a593Smuzhiyun phba->nvmeio_trc_output_idx,
1671*4882a593Smuzhiyun phba->nvmeio_trc_size);
1672*4882a593Smuzhiyun goto out;
1673*4882a593Smuzhiyun }
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun
1676*4882a593Smuzhiyun len += scnprintf(buf + len, size - len,
1677*4882a593Smuzhiyun "Trace Done\n");
1678*4882a593Smuzhiyun out:
1679*4882a593Smuzhiyun return len;
1680*4882a593Smuzhiyun }
1681*4882a593Smuzhiyun
1682*4882a593Smuzhiyun /**
1683*4882a593Smuzhiyun * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer
1684*4882a593Smuzhiyun * @vport: The vport to gather target node info from.
1685*4882a593Smuzhiyun * @buf: The buffer to dump log into.
1686*4882a593Smuzhiyun * @size: The maximum amount of data to process.
1687*4882a593Smuzhiyun *
1688*4882a593Smuzhiyun * Description:
1689*4882a593Smuzhiyun * This routine dumps the NVME + SCSI statistics associated with @vport
1690*4882a593Smuzhiyun *
1691*4882a593Smuzhiyun * Return Value:
1692*4882a593Smuzhiyun * This routine returns the amount of bytes that were dumped into @buf and will
1693*4882a593Smuzhiyun * not exceed @size.
1694*4882a593Smuzhiyun **/
1695*4882a593Smuzhiyun static int
lpfc_debugfs_hdwqstat_data(struct lpfc_vport * vport,char * buf,int size)1696*4882a593Smuzhiyun lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size)
1697*4882a593Smuzhiyun {
1698*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
1699*4882a593Smuzhiyun struct lpfc_hdwq_stat *c_stat;
1700*4882a593Smuzhiyun int i, j, len;
1701*4882a593Smuzhiyun uint32_t tot_xmt;
1702*4882a593Smuzhiyun uint32_t tot_rcv;
1703*4882a593Smuzhiyun uint32_t tot_cmpl;
1704*4882a593Smuzhiyun char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
1705*4882a593Smuzhiyun
1706*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n");
1707*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1708*4882a593Smuzhiyun goto buffer_done;
1709*4882a593Smuzhiyun
1710*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ",
1711*4882a593Smuzhiyun (phba->hdwqstat_on &
1712*4882a593Smuzhiyun (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ?
1713*4882a593Smuzhiyun "Enabled" : "Disabled"));
1714*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1715*4882a593Smuzhiyun goto buffer_done;
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ",
1718*4882a593Smuzhiyun (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ?
1719*4882a593Smuzhiyun "Enabled" : "Disabled"));
1720*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1721*4882a593Smuzhiyun goto buffer_done;
1722*4882a593Smuzhiyun
1723*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "\n\n");
1724*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1725*4882a593Smuzhiyun goto buffer_done;
1726*4882a593Smuzhiyun
1727*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
1728*4882a593Smuzhiyun tot_rcv = 0;
1729*4882a593Smuzhiyun tot_xmt = 0;
1730*4882a593Smuzhiyun tot_cmpl = 0;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun for_each_present_cpu(j) {
1733*4882a593Smuzhiyun c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j);
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun /* Only display for this HDWQ */
1736*4882a593Smuzhiyun if (i != c_stat->hdwq_no)
1737*4882a593Smuzhiyun continue;
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun /* Only display non-zero counters */
1740*4882a593Smuzhiyun if (!c_stat->xmt_io && !c_stat->cmpl_io &&
1741*4882a593Smuzhiyun !c_stat->rcv_io)
1742*4882a593Smuzhiyun continue;
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun if (!tot_xmt && !tot_cmpl && !tot_rcv) {
1745*4882a593Smuzhiyun /* Print HDWQ string only the first time */
1746*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i);
1747*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1748*4882a593Smuzhiyun goto buffer_done;
1749*4882a593Smuzhiyun }
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun tot_xmt += c_stat->xmt_io;
1752*4882a593Smuzhiyun tot_cmpl += c_stat->cmpl_io;
1753*4882a593Smuzhiyun if (phba->nvmet_support)
1754*4882a593Smuzhiyun tot_rcv += c_stat->rcv_io;
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j);
1757*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1758*4882a593Smuzhiyun goto buffer_done;
1759*4882a593Smuzhiyun
1760*4882a593Smuzhiyun if (phba->nvmet_support) {
1761*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
1762*4882a593Smuzhiyun "XMT 0x%x CMPL 0x%x RCV 0x%x |",
1763*4882a593Smuzhiyun c_stat->xmt_io, c_stat->cmpl_io,
1764*4882a593Smuzhiyun c_stat->rcv_io);
1765*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1766*4882a593Smuzhiyun goto buffer_done;
1767*4882a593Smuzhiyun } else {
1768*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
1769*4882a593Smuzhiyun "XMT 0x%x CMPL 0x%x |",
1770*4882a593Smuzhiyun c_stat->xmt_io, c_stat->cmpl_io);
1771*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1772*4882a593Smuzhiyun goto buffer_done;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun }
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun /* Check if nothing to display */
1777*4882a593Smuzhiyun if (!tot_xmt && !tot_cmpl && !tot_rcv)
1778*4882a593Smuzhiyun continue;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: ");
1781*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1782*4882a593Smuzhiyun goto buffer_done;
1783*4882a593Smuzhiyun
1784*4882a593Smuzhiyun if (phba->nvmet_support) {
1785*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
1786*4882a593Smuzhiyun "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n",
1787*4882a593Smuzhiyun tot_xmt, tot_cmpl, tot_rcv);
1788*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1789*4882a593Smuzhiyun goto buffer_done;
1790*4882a593Smuzhiyun } else {
1791*4882a593Smuzhiyun scnprintf(tmp, sizeof(tmp),
1792*4882a593Smuzhiyun "XMT 0x%x CMPL 0x%x]\n\n",
1793*4882a593Smuzhiyun tot_xmt, tot_cmpl);
1794*4882a593Smuzhiyun if (strlcat(buf, tmp, size) >= size)
1795*4882a593Smuzhiyun goto buffer_done;
1796*4882a593Smuzhiyun }
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun
1799*4882a593Smuzhiyun buffer_done:
1800*4882a593Smuzhiyun len = strnlen(buf, size);
1801*4882a593Smuzhiyun return len;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun
1804*4882a593Smuzhiyun #endif
1805*4882a593Smuzhiyun
1806*4882a593Smuzhiyun /**
1807*4882a593Smuzhiyun * lpfc_debugfs_disc_trc - Store discovery trace log
1808*4882a593Smuzhiyun * @vport: The vport to associate this trace string with for retrieval.
1809*4882a593Smuzhiyun * @mask: Log entry classification.
1810*4882a593Smuzhiyun * @fmt: Format string to be displayed when dumping the log.
1811*4882a593Smuzhiyun * @data1: 1st data parameter to be applied to @fmt.
1812*4882a593Smuzhiyun * @data2: 2nd data parameter to be applied to @fmt.
1813*4882a593Smuzhiyun * @data3: 3rd data parameter to be applied to @fmt.
1814*4882a593Smuzhiyun *
1815*4882a593Smuzhiyun * Description:
1816*4882a593Smuzhiyun * This routine is used by the driver code to add a debugfs log entry to the
1817*4882a593Smuzhiyun * discovery trace buffer associated with @vport. Only entries with a @mask that
1818*4882a593Smuzhiyun * match the current debugfs discovery mask will be saved. Entries that do not
1819*4882a593Smuzhiyun * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like
1820*4882a593Smuzhiyun * printf when displaying the log.
1821*4882a593Smuzhiyun **/
1822*4882a593Smuzhiyun inline void
lpfc_debugfs_disc_trc(struct lpfc_vport * vport,int mask,char * fmt,uint32_t data1,uint32_t data2,uint32_t data3)1823*4882a593Smuzhiyun lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
1824*4882a593Smuzhiyun uint32_t data1, uint32_t data2, uint32_t data3)
1825*4882a593Smuzhiyun {
1826*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1827*4882a593Smuzhiyun struct lpfc_debugfs_trc *dtp;
1828*4882a593Smuzhiyun int index;
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun if (!(lpfc_debugfs_mask_disc_trc & mask))
1831*4882a593Smuzhiyun return;
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
1834*4882a593Smuzhiyun !vport || !vport->disc_trc)
1835*4882a593Smuzhiyun return;
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun index = atomic_inc_return(&vport->disc_trc_cnt) &
1838*4882a593Smuzhiyun (lpfc_debugfs_max_disc_trc - 1);
1839*4882a593Smuzhiyun dtp = vport->disc_trc + index;
1840*4882a593Smuzhiyun dtp->fmt = fmt;
1841*4882a593Smuzhiyun dtp->data1 = data1;
1842*4882a593Smuzhiyun dtp->data2 = data2;
1843*4882a593Smuzhiyun dtp->data3 = data3;
1844*4882a593Smuzhiyun dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
1845*4882a593Smuzhiyun dtp->jif = jiffies;
1846*4882a593Smuzhiyun #endif
1847*4882a593Smuzhiyun return;
1848*4882a593Smuzhiyun }
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun /**
1851*4882a593Smuzhiyun * lpfc_debugfs_slow_ring_trc - Store slow ring trace log
1852*4882a593Smuzhiyun * @phba: The phba to associate this trace string with for retrieval.
1853*4882a593Smuzhiyun * @fmt: Format string to be displayed when dumping the log.
1854*4882a593Smuzhiyun * @data1: 1st data parameter to be applied to @fmt.
1855*4882a593Smuzhiyun * @data2: 2nd data parameter to be applied to @fmt.
1856*4882a593Smuzhiyun * @data3: 3rd data parameter to be applied to @fmt.
1857*4882a593Smuzhiyun *
1858*4882a593Smuzhiyun * Description:
1859*4882a593Smuzhiyun * This routine is used by the driver code to add a debugfs log entry to the
1860*4882a593Smuzhiyun * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and
1861*4882a593Smuzhiyun * @data3 are used like printf when displaying the log.
1862*4882a593Smuzhiyun **/
1863*4882a593Smuzhiyun inline void
lpfc_debugfs_slow_ring_trc(struct lpfc_hba * phba,char * fmt,uint32_t data1,uint32_t data2,uint32_t data3)1864*4882a593Smuzhiyun lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt,
1865*4882a593Smuzhiyun uint32_t data1, uint32_t data2, uint32_t data3)
1866*4882a593Smuzhiyun {
1867*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1868*4882a593Smuzhiyun struct lpfc_debugfs_trc *dtp;
1869*4882a593Smuzhiyun int index;
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc ||
1872*4882a593Smuzhiyun !phba || !phba->slow_ring_trc)
1873*4882a593Smuzhiyun return;
1874*4882a593Smuzhiyun
1875*4882a593Smuzhiyun index = atomic_inc_return(&phba->slow_ring_trc_cnt) &
1876*4882a593Smuzhiyun (lpfc_debugfs_max_slow_ring_trc - 1);
1877*4882a593Smuzhiyun dtp = phba->slow_ring_trc + index;
1878*4882a593Smuzhiyun dtp->fmt = fmt;
1879*4882a593Smuzhiyun dtp->data1 = data1;
1880*4882a593Smuzhiyun dtp->data2 = data2;
1881*4882a593Smuzhiyun dtp->data3 = data3;
1882*4882a593Smuzhiyun dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
1883*4882a593Smuzhiyun dtp->jif = jiffies;
1884*4882a593Smuzhiyun #endif
1885*4882a593Smuzhiyun return;
1886*4882a593Smuzhiyun }
1887*4882a593Smuzhiyun
1888*4882a593Smuzhiyun /**
1889*4882a593Smuzhiyun * lpfc_debugfs_nvme_trc - Store NVME/NVMET trace log
1890*4882a593Smuzhiyun * @phba: The phba to associate this trace string with for retrieval.
1891*4882a593Smuzhiyun * @fmt: Format string to be displayed when dumping the log.
1892*4882a593Smuzhiyun * @data1: 1st data parameter to be applied to @fmt.
1893*4882a593Smuzhiyun * @data2: 2nd data parameter to be applied to @fmt.
1894*4882a593Smuzhiyun * @data3: 3rd data parameter to be applied to @fmt.
1895*4882a593Smuzhiyun *
1896*4882a593Smuzhiyun * Description:
1897*4882a593Smuzhiyun * This routine is used by the driver code to add a debugfs log entry to the
1898*4882a593Smuzhiyun * nvme trace buffer associated with @phba. @fmt, @data1, @data2, and
1899*4882a593Smuzhiyun * @data3 are used like printf when displaying the log.
1900*4882a593Smuzhiyun **/
1901*4882a593Smuzhiyun inline void
lpfc_debugfs_nvme_trc(struct lpfc_hba * phba,char * fmt,uint16_t data1,uint16_t data2,uint32_t data3)1902*4882a593Smuzhiyun lpfc_debugfs_nvme_trc(struct lpfc_hba *phba, char *fmt,
1903*4882a593Smuzhiyun uint16_t data1, uint16_t data2, uint32_t data3)
1904*4882a593Smuzhiyun {
1905*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1906*4882a593Smuzhiyun struct lpfc_debugfs_nvmeio_trc *dtp;
1907*4882a593Smuzhiyun int index;
1908*4882a593Smuzhiyun
1909*4882a593Smuzhiyun if (!phba->nvmeio_trc_on || !phba->nvmeio_trc)
1910*4882a593Smuzhiyun return;
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun index = atomic_inc_return(&phba->nvmeio_trc_cnt) &
1913*4882a593Smuzhiyun (phba->nvmeio_trc_size - 1);
1914*4882a593Smuzhiyun dtp = phba->nvmeio_trc + index;
1915*4882a593Smuzhiyun dtp->fmt = fmt;
1916*4882a593Smuzhiyun dtp->data1 = data1;
1917*4882a593Smuzhiyun dtp->data2 = data2;
1918*4882a593Smuzhiyun dtp->data3 = data3;
1919*4882a593Smuzhiyun #endif
1920*4882a593Smuzhiyun }
1921*4882a593Smuzhiyun
1922*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1923*4882a593Smuzhiyun /**
1924*4882a593Smuzhiyun * lpfc_debugfs_disc_trc_open - Open the discovery trace log
1925*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
1926*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
1927*4882a593Smuzhiyun *
1928*4882a593Smuzhiyun * Description:
1929*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
1930*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
1931*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
1932*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
1933*4882a593Smuzhiyun *
1934*4882a593Smuzhiyun * Returns:
1935*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
1936*4882a593Smuzhiyun * error value.
1937*4882a593Smuzhiyun **/
1938*4882a593Smuzhiyun static int
lpfc_debugfs_disc_trc_open(struct inode * inode,struct file * file)1939*4882a593Smuzhiyun lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
1940*4882a593Smuzhiyun {
1941*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
1942*4882a593Smuzhiyun struct lpfc_debug *debug;
1943*4882a593Smuzhiyun int size;
1944*4882a593Smuzhiyun int rc = -ENOMEM;
1945*4882a593Smuzhiyun
1946*4882a593Smuzhiyun if (!lpfc_debugfs_max_disc_trc) {
1947*4882a593Smuzhiyun rc = -ENOSPC;
1948*4882a593Smuzhiyun goto out;
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun
1951*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
1952*4882a593Smuzhiyun if (!debug)
1953*4882a593Smuzhiyun goto out;
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun /* Round to page boundary */
1956*4882a593Smuzhiyun size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
1957*4882a593Smuzhiyun size = PAGE_ALIGN(size);
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun debug->buffer = kmalloc(size, GFP_KERNEL);
1960*4882a593Smuzhiyun if (!debug->buffer) {
1961*4882a593Smuzhiyun kfree(debug);
1962*4882a593Smuzhiyun goto out;
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun
1965*4882a593Smuzhiyun debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
1966*4882a593Smuzhiyun file->private_data = debug;
1967*4882a593Smuzhiyun
1968*4882a593Smuzhiyun rc = 0;
1969*4882a593Smuzhiyun out:
1970*4882a593Smuzhiyun return rc;
1971*4882a593Smuzhiyun }
1972*4882a593Smuzhiyun
1973*4882a593Smuzhiyun /**
1974*4882a593Smuzhiyun * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log
1975*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
1976*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
1977*4882a593Smuzhiyun *
1978*4882a593Smuzhiyun * Description:
1979*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
1980*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
1981*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
1982*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
1983*4882a593Smuzhiyun *
1984*4882a593Smuzhiyun * Returns:
1985*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
1986*4882a593Smuzhiyun * error value.
1987*4882a593Smuzhiyun **/
1988*4882a593Smuzhiyun static int
lpfc_debugfs_slow_ring_trc_open(struct inode * inode,struct file * file)1989*4882a593Smuzhiyun lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file)
1990*4882a593Smuzhiyun {
1991*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
1992*4882a593Smuzhiyun struct lpfc_debug *debug;
1993*4882a593Smuzhiyun int size;
1994*4882a593Smuzhiyun int rc = -ENOMEM;
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun if (!lpfc_debugfs_max_slow_ring_trc) {
1997*4882a593Smuzhiyun rc = -ENOSPC;
1998*4882a593Smuzhiyun goto out;
1999*4882a593Smuzhiyun }
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2002*4882a593Smuzhiyun if (!debug)
2003*4882a593Smuzhiyun goto out;
2004*4882a593Smuzhiyun
2005*4882a593Smuzhiyun /* Round to page boundary */
2006*4882a593Smuzhiyun size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
2007*4882a593Smuzhiyun size = PAGE_ALIGN(size);
2008*4882a593Smuzhiyun
2009*4882a593Smuzhiyun debug->buffer = kmalloc(size, GFP_KERNEL);
2010*4882a593Smuzhiyun if (!debug->buffer) {
2011*4882a593Smuzhiyun kfree(debug);
2012*4882a593Smuzhiyun goto out;
2013*4882a593Smuzhiyun }
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size);
2016*4882a593Smuzhiyun file->private_data = debug;
2017*4882a593Smuzhiyun
2018*4882a593Smuzhiyun rc = 0;
2019*4882a593Smuzhiyun out:
2020*4882a593Smuzhiyun return rc;
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun /**
2024*4882a593Smuzhiyun * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer
2025*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2026*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2027*4882a593Smuzhiyun *
2028*4882a593Smuzhiyun * Description:
2029*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2030*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2031*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2032*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2033*4882a593Smuzhiyun *
2034*4882a593Smuzhiyun * Returns:
2035*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2036*4882a593Smuzhiyun * error value.
2037*4882a593Smuzhiyun **/
2038*4882a593Smuzhiyun static int
lpfc_debugfs_hbqinfo_open(struct inode * inode,struct file * file)2039*4882a593Smuzhiyun lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file)
2040*4882a593Smuzhiyun {
2041*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2042*4882a593Smuzhiyun struct lpfc_debug *debug;
2043*4882a593Smuzhiyun int rc = -ENOMEM;
2044*4882a593Smuzhiyun
2045*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2046*4882a593Smuzhiyun if (!debug)
2047*4882a593Smuzhiyun goto out;
2048*4882a593Smuzhiyun
2049*4882a593Smuzhiyun /* Round to page boundary */
2050*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL);
2051*4882a593Smuzhiyun if (!debug->buffer) {
2052*4882a593Smuzhiyun kfree(debug);
2053*4882a593Smuzhiyun goto out;
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun
2056*4882a593Smuzhiyun debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer,
2057*4882a593Smuzhiyun LPFC_HBQINFO_SIZE);
2058*4882a593Smuzhiyun file->private_data = debug;
2059*4882a593Smuzhiyun
2060*4882a593Smuzhiyun rc = 0;
2061*4882a593Smuzhiyun out:
2062*4882a593Smuzhiyun return rc;
2063*4882a593Smuzhiyun }
2064*4882a593Smuzhiyun
2065*4882a593Smuzhiyun /**
2066*4882a593Smuzhiyun * lpfc_debugfs_multixripools_open - Open the multixripool debugfs buffer
2067*4882a593Smuzhiyun * @inode: The inode pointer that contains a hba pointer.
2068*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2069*4882a593Smuzhiyun *
2070*4882a593Smuzhiyun * Description:
2071*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2072*4882a593Smuzhiyun * the hba from the i_private field in @inode, allocates the necessary buffer
2073*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this hba, and then
2074*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2075*4882a593Smuzhiyun *
2076*4882a593Smuzhiyun * Returns:
2077*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2078*4882a593Smuzhiyun * error value.
2079*4882a593Smuzhiyun **/
2080*4882a593Smuzhiyun static int
lpfc_debugfs_multixripools_open(struct inode * inode,struct file * file)2081*4882a593Smuzhiyun lpfc_debugfs_multixripools_open(struct inode *inode, struct file *file)
2082*4882a593Smuzhiyun {
2083*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2084*4882a593Smuzhiyun struct lpfc_debug *debug;
2085*4882a593Smuzhiyun int rc = -ENOMEM;
2086*4882a593Smuzhiyun
2087*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2088*4882a593Smuzhiyun if (!debug)
2089*4882a593Smuzhiyun goto out;
2090*4882a593Smuzhiyun
2091*4882a593Smuzhiyun /* Round to page boundary */
2092*4882a593Smuzhiyun debug->buffer = kzalloc(LPFC_DUMP_MULTIXRIPOOL_SIZE, GFP_KERNEL);
2093*4882a593Smuzhiyun if (!debug->buffer) {
2094*4882a593Smuzhiyun kfree(debug);
2095*4882a593Smuzhiyun goto out;
2096*4882a593Smuzhiyun }
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun debug->len = lpfc_debugfs_multixripools_data(
2099*4882a593Smuzhiyun phba, debug->buffer, LPFC_DUMP_MULTIXRIPOOL_SIZE);
2100*4882a593Smuzhiyun
2101*4882a593Smuzhiyun debug->i_private = inode->i_private;
2102*4882a593Smuzhiyun file->private_data = debug;
2103*4882a593Smuzhiyun
2104*4882a593Smuzhiyun rc = 0;
2105*4882a593Smuzhiyun out:
2106*4882a593Smuzhiyun return rc;
2107*4882a593Smuzhiyun }
2108*4882a593Smuzhiyun
2109*4882a593Smuzhiyun #ifdef LPFC_HDWQ_LOCK_STAT
2110*4882a593Smuzhiyun /**
2111*4882a593Smuzhiyun * lpfc_debugfs_lockstat_open - Open the lockstat debugfs buffer
2112*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2113*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2114*4882a593Smuzhiyun *
2115*4882a593Smuzhiyun * Description:
2116*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2117*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2118*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2119*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2120*4882a593Smuzhiyun *
2121*4882a593Smuzhiyun * Returns:
2122*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2123*4882a593Smuzhiyun * error value.
2124*4882a593Smuzhiyun **/
2125*4882a593Smuzhiyun static int
lpfc_debugfs_lockstat_open(struct inode * inode,struct file * file)2126*4882a593Smuzhiyun lpfc_debugfs_lockstat_open(struct inode *inode, struct file *file)
2127*4882a593Smuzhiyun {
2128*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2129*4882a593Smuzhiyun struct lpfc_debug *debug;
2130*4882a593Smuzhiyun int rc = -ENOMEM;
2131*4882a593Smuzhiyun
2132*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2133*4882a593Smuzhiyun if (!debug)
2134*4882a593Smuzhiyun goto out;
2135*4882a593Smuzhiyun
2136*4882a593Smuzhiyun /* Round to page boundary */
2137*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_HDWQINFO_SIZE, GFP_KERNEL);
2138*4882a593Smuzhiyun if (!debug->buffer) {
2139*4882a593Smuzhiyun kfree(debug);
2140*4882a593Smuzhiyun goto out;
2141*4882a593Smuzhiyun }
2142*4882a593Smuzhiyun
2143*4882a593Smuzhiyun debug->len = lpfc_debugfs_lockstat_data(phba, debug->buffer,
2144*4882a593Smuzhiyun LPFC_HBQINFO_SIZE);
2145*4882a593Smuzhiyun file->private_data = debug;
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun rc = 0;
2148*4882a593Smuzhiyun out:
2149*4882a593Smuzhiyun return rc;
2150*4882a593Smuzhiyun }
2151*4882a593Smuzhiyun
2152*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_lockstat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2153*4882a593Smuzhiyun lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf,
2154*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2155*4882a593Smuzhiyun {
2156*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2157*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
2158*4882a593Smuzhiyun struct lpfc_sli4_hdw_queue *qp;
2159*4882a593Smuzhiyun char mybuf[64];
2160*4882a593Smuzhiyun char *pbuf;
2161*4882a593Smuzhiyun int i;
2162*4882a593Smuzhiyun
2163*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
2164*4882a593Smuzhiyun
2165*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
2166*4882a593Smuzhiyun return -EFAULT;
2167*4882a593Smuzhiyun pbuf = &mybuf[0];
2168*4882a593Smuzhiyun
2169*4882a593Smuzhiyun if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
2170*4882a593Smuzhiyun (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
2171*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
2172*4882a593Smuzhiyun qp = &phba->sli4_hba.hdwq[i];
2173*4882a593Smuzhiyun qp->lock_conflict.alloc_xri_get = 0;
2174*4882a593Smuzhiyun qp->lock_conflict.alloc_xri_put = 0;
2175*4882a593Smuzhiyun qp->lock_conflict.free_xri = 0;
2176*4882a593Smuzhiyun qp->lock_conflict.wq_access = 0;
2177*4882a593Smuzhiyun qp->lock_conflict.alloc_pvt_pool = 0;
2178*4882a593Smuzhiyun qp->lock_conflict.mv_from_pvt_pool = 0;
2179*4882a593Smuzhiyun qp->lock_conflict.mv_to_pub_pool = 0;
2180*4882a593Smuzhiyun qp->lock_conflict.mv_to_pvt_pool = 0;
2181*4882a593Smuzhiyun qp->lock_conflict.free_pvt_pool = 0;
2182*4882a593Smuzhiyun qp->lock_conflict.free_pub_pool = 0;
2183*4882a593Smuzhiyun qp->lock_conflict.wq_access = 0;
2184*4882a593Smuzhiyun }
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun return nbytes;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun #endif
2189*4882a593Smuzhiyun
lpfc_debugfs_ras_log_data(struct lpfc_hba * phba,char * buffer,int size)2190*4882a593Smuzhiyun static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
2191*4882a593Smuzhiyun char *buffer, int size)
2192*4882a593Smuzhiyun {
2193*4882a593Smuzhiyun int copied = 0;
2194*4882a593Smuzhiyun struct lpfc_dmabuf *dmabuf, *next;
2195*4882a593Smuzhiyun
2196*4882a593Smuzhiyun memset(buffer, 0, size);
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
2199*4882a593Smuzhiyun if (phba->ras_fwlog.state != ACTIVE) {
2200*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
2201*4882a593Smuzhiyun return -EINVAL;
2202*4882a593Smuzhiyun }
2203*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun list_for_each_entry_safe(dmabuf, next,
2206*4882a593Smuzhiyun &phba->ras_fwlog.fwlog_buff_list, list) {
2207*4882a593Smuzhiyun /* Check if copying will go over size and a '\0' char */
2208*4882a593Smuzhiyun if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) {
2209*4882a593Smuzhiyun memcpy(buffer + copied, dmabuf->virt,
2210*4882a593Smuzhiyun size - copied - 1);
2211*4882a593Smuzhiyun copied += size - copied - 1;
2212*4882a593Smuzhiyun break;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
2215*4882a593Smuzhiyun copied += LPFC_RAS_MAX_ENTRY_SIZE;
2216*4882a593Smuzhiyun }
2217*4882a593Smuzhiyun return copied;
2218*4882a593Smuzhiyun }
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun static int
lpfc_debugfs_ras_log_release(struct inode * inode,struct file * file)2221*4882a593Smuzhiyun lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file)
2222*4882a593Smuzhiyun {
2223*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun vfree(debug->buffer);
2226*4882a593Smuzhiyun kfree(debug);
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun return 0;
2229*4882a593Smuzhiyun }
2230*4882a593Smuzhiyun
2231*4882a593Smuzhiyun /**
2232*4882a593Smuzhiyun * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer
2233*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2234*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2235*4882a593Smuzhiyun *
2236*4882a593Smuzhiyun * Description:
2237*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2238*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2239*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2240*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2241*4882a593Smuzhiyun *
2242*4882a593Smuzhiyun * Returns:
2243*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2244*4882a593Smuzhiyun * error value.
2245*4882a593Smuzhiyun **/
2246*4882a593Smuzhiyun static int
lpfc_debugfs_ras_log_open(struct inode * inode,struct file * file)2247*4882a593Smuzhiyun lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
2248*4882a593Smuzhiyun {
2249*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2250*4882a593Smuzhiyun struct lpfc_debug *debug;
2251*4882a593Smuzhiyun int size;
2252*4882a593Smuzhiyun int rc = -ENOMEM;
2253*4882a593Smuzhiyun
2254*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
2255*4882a593Smuzhiyun if (phba->ras_fwlog.state != ACTIVE) {
2256*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
2257*4882a593Smuzhiyun rc = -EINVAL;
2258*4882a593Smuzhiyun goto out;
2259*4882a593Smuzhiyun }
2260*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
2261*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2262*4882a593Smuzhiyun if (!debug)
2263*4882a593Smuzhiyun goto out;
2264*4882a593Smuzhiyun
2265*4882a593Smuzhiyun size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize;
2266*4882a593Smuzhiyun debug->buffer = vmalloc(size);
2267*4882a593Smuzhiyun if (!debug->buffer)
2268*4882a593Smuzhiyun goto free_debug;
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size);
2271*4882a593Smuzhiyun if (debug->len < 0) {
2272*4882a593Smuzhiyun rc = -EINVAL;
2273*4882a593Smuzhiyun goto free_buffer;
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun file->private_data = debug;
2276*4882a593Smuzhiyun
2277*4882a593Smuzhiyun return 0;
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun free_buffer:
2280*4882a593Smuzhiyun vfree(debug->buffer);
2281*4882a593Smuzhiyun free_debug:
2282*4882a593Smuzhiyun kfree(debug);
2283*4882a593Smuzhiyun out:
2284*4882a593Smuzhiyun return rc;
2285*4882a593Smuzhiyun }
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun /**
2288*4882a593Smuzhiyun * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer
2289*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2290*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2291*4882a593Smuzhiyun *
2292*4882a593Smuzhiyun * Description:
2293*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2294*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2295*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2296*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2297*4882a593Smuzhiyun *
2298*4882a593Smuzhiyun * Returns:
2299*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2300*4882a593Smuzhiyun * error value.
2301*4882a593Smuzhiyun **/
2302*4882a593Smuzhiyun static int
lpfc_debugfs_dumpHBASlim_open(struct inode * inode,struct file * file)2303*4882a593Smuzhiyun lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
2304*4882a593Smuzhiyun {
2305*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2306*4882a593Smuzhiyun struct lpfc_debug *debug;
2307*4882a593Smuzhiyun int rc = -ENOMEM;
2308*4882a593Smuzhiyun
2309*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2310*4882a593Smuzhiyun if (!debug)
2311*4882a593Smuzhiyun goto out;
2312*4882a593Smuzhiyun
2313*4882a593Smuzhiyun /* Round to page boundary */
2314*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
2315*4882a593Smuzhiyun if (!debug->buffer) {
2316*4882a593Smuzhiyun kfree(debug);
2317*4882a593Smuzhiyun goto out;
2318*4882a593Smuzhiyun }
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
2321*4882a593Smuzhiyun LPFC_DUMPHBASLIM_SIZE);
2322*4882a593Smuzhiyun file->private_data = debug;
2323*4882a593Smuzhiyun
2324*4882a593Smuzhiyun rc = 0;
2325*4882a593Smuzhiyun out:
2326*4882a593Smuzhiyun return rc;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun /**
2330*4882a593Smuzhiyun * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer
2331*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2332*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2333*4882a593Smuzhiyun *
2334*4882a593Smuzhiyun * Description:
2335*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2336*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2337*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2338*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2339*4882a593Smuzhiyun *
2340*4882a593Smuzhiyun * Returns:
2341*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2342*4882a593Smuzhiyun * error value.
2343*4882a593Smuzhiyun **/
2344*4882a593Smuzhiyun static int
lpfc_debugfs_dumpHostSlim_open(struct inode * inode,struct file * file)2345*4882a593Smuzhiyun lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
2346*4882a593Smuzhiyun {
2347*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2348*4882a593Smuzhiyun struct lpfc_debug *debug;
2349*4882a593Smuzhiyun int rc = -ENOMEM;
2350*4882a593Smuzhiyun
2351*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2352*4882a593Smuzhiyun if (!debug)
2353*4882a593Smuzhiyun goto out;
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun /* Round to page boundary */
2356*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
2357*4882a593Smuzhiyun if (!debug->buffer) {
2358*4882a593Smuzhiyun kfree(debug);
2359*4882a593Smuzhiyun goto out;
2360*4882a593Smuzhiyun }
2361*4882a593Smuzhiyun
2362*4882a593Smuzhiyun debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
2363*4882a593Smuzhiyun LPFC_DUMPHOSTSLIM_SIZE);
2364*4882a593Smuzhiyun file->private_data = debug;
2365*4882a593Smuzhiyun
2366*4882a593Smuzhiyun rc = 0;
2367*4882a593Smuzhiyun out:
2368*4882a593Smuzhiyun return rc;
2369*4882a593Smuzhiyun }
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_dif_err_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)2372*4882a593Smuzhiyun lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
2373*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2374*4882a593Smuzhiyun {
2375*4882a593Smuzhiyun struct dentry *dent = file->f_path.dentry;
2376*4882a593Smuzhiyun struct lpfc_hba *phba = file->private_data;
2377*4882a593Smuzhiyun char cbuf[32];
2378*4882a593Smuzhiyun uint64_t tmp = 0;
2379*4882a593Smuzhiyun int cnt = 0;
2380*4882a593Smuzhiyun
2381*4882a593Smuzhiyun if (dent == phba->debug_writeGuard)
2382*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
2383*4882a593Smuzhiyun else if (dent == phba->debug_writeApp)
2384*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
2385*4882a593Smuzhiyun else if (dent == phba->debug_writeRef)
2386*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
2387*4882a593Smuzhiyun else if (dent == phba->debug_readGuard)
2388*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
2389*4882a593Smuzhiyun else if (dent == phba->debug_readApp)
2390*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
2391*4882a593Smuzhiyun else if (dent == phba->debug_readRef)
2392*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
2393*4882a593Smuzhiyun else if (dent == phba->debug_InjErrNPortID)
2394*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "0x%06x\n",
2395*4882a593Smuzhiyun phba->lpfc_injerr_nportid);
2396*4882a593Smuzhiyun else if (dent == phba->debug_InjErrWWPN) {
2397*4882a593Smuzhiyun memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name));
2398*4882a593Smuzhiyun tmp = cpu_to_be64(tmp);
2399*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp);
2400*4882a593Smuzhiyun } else if (dent == phba->debug_InjErrLBA) {
2401*4882a593Smuzhiyun if (phba->lpfc_injerr_lba == (sector_t)(-1))
2402*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "off\n");
2403*4882a593Smuzhiyun else
2404*4882a593Smuzhiyun cnt = scnprintf(cbuf, 32, "0x%llx\n",
2405*4882a593Smuzhiyun (uint64_t) phba->lpfc_injerr_lba);
2406*4882a593Smuzhiyun } else
2407*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2408*4882a593Smuzhiyun "0547 Unknown debugfs error injection entry\n");
2409*4882a593Smuzhiyun
2410*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt);
2411*4882a593Smuzhiyun }
2412*4882a593Smuzhiyun
2413*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_dif_err_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2414*4882a593Smuzhiyun lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
2415*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2416*4882a593Smuzhiyun {
2417*4882a593Smuzhiyun struct dentry *dent = file->f_path.dentry;
2418*4882a593Smuzhiyun struct lpfc_hba *phba = file->private_data;
2419*4882a593Smuzhiyun char dstbuf[33];
2420*4882a593Smuzhiyun uint64_t tmp = 0;
2421*4882a593Smuzhiyun int size;
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun memset(dstbuf, 0, 33);
2424*4882a593Smuzhiyun size = (nbytes < 32) ? nbytes : 32;
2425*4882a593Smuzhiyun if (copy_from_user(dstbuf, buf, size))
2426*4882a593Smuzhiyun return -EFAULT;
2427*4882a593Smuzhiyun
2428*4882a593Smuzhiyun if (dent == phba->debug_InjErrLBA) {
2429*4882a593Smuzhiyun if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') &&
2430*4882a593Smuzhiyun (dstbuf[2] == 'f'))
2431*4882a593Smuzhiyun tmp = (uint64_t)(-1);
2432*4882a593Smuzhiyun }
2433*4882a593Smuzhiyun
2434*4882a593Smuzhiyun if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp)))
2435*4882a593Smuzhiyun return -EINVAL;
2436*4882a593Smuzhiyun
2437*4882a593Smuzhiyun if (dent == phba->debug_writeGuard)
2438*4882a593Smuzhiyun phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp;
2439*4882a593Smuzhiyun else if (dent == phba->debug_writeApp)
2440*4882a593Smuzhiyun phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
2441*4882a593Smuzhiyun else if (dent == phba->debug_writeRef)
2442*4882a593Smuzhiyun phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
2443*4882a593Smuzhiyun else if (dent == phba->debug_readGuard)
2444*4882a593Smuzhiyun phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
2445*4882a593Smuzhiyun else if (dent == phba->debug_readApp)
2446*4882a593Smuzhiyun phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
2447*4882a593Smuzhiyun else if (dent == phba->debug_readRef)
2448*4882a593Smuzhiyun phba->lpfc_injerr_rref_cnt = (uint32_t)tmp;
2449*4882a593Smuzhiyun else if (dent == phba->debug_InjErrLBA)
2450*4882a593Smuzhiyun phba->lpfc_injerr_lba = (sector_t)tmp;
2451*4882a593Smuzhiyun else if (dent == phba->debug_InjErrNPortID)
2452*4882a593Smuzhiyun phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID);
2453*4882a593Smuzhiyun else if (dent == phba->debug_InjErrWWPN) {
2454*4882a593Smuzhiyun tmp = cpu_to_be64(tmp);
2455*4882a593Smuzhiyun memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name));
2456*4882a593Smuzhiyun } else
2457*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2458*4882a593Smuzhiyun "0548 Unknown debugfs error injection entry\n");
2459*4882a593Smuzhiyun
2460*4882a593Smuzhiyun return nbytes;
2461*4882a593Smuzhiyun }
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun static int
lpfc_debugfs_dif_err_release(struct inode * inode,struct file * file)2464*4882a593Smuzhiyun lpfc_debugfs_dif_err_release(struct inode *inode, struct file *file)
2465*4882a593Smuzhiyun {
2466*4882a593Smuzhiyun return 0;
2467*4882a593Smuzhiyun }
2468*4882a593Smuzhiyun
2469*4882a593Smuzhiyun /**
2470*4882a593Smuzhiyun * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file
2471*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer.
2472*4882a593Smuzhiyun * @file: The file pointer to attach the log output.
2473*4882a593Smuzhiyun *
2474*4882a593Smuzhiyun * Description:
2475*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It gets
2476*4882a593Smuzhiyun * the vport from the i_private field in @inode, allocates the necessary buffer
2477*4882a593Smuzhiyun * for the log, fills the buffer from the in-memory log for this vport, and then
2478*4882a593Smuzhiyun * returns a pointer to that log in the private_data field in @file.
2479*4882a593Smuzhiyun *
2480*4882a593Smuzhiyun * Returns:
2481*4882a593Smuzhiyun * This function returns zero if successful. On error it will return a negative
2482*4882a593Smuzhiyun * error value.
2483*4882a593Smuzhiyun **/
2484*4882a593Smuzhiyun static int
lpfc_debugfs_nodelist_open(struct inode * inode,struct file * file)2485*4882a593Smuzhiyun lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
2486*4882a593Smuzhiyun {
2487*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
2488*4882a593Smuzhiyun struct lpfc_debug *debug;
2489*4882a593Smuzhiyun int rc = -ENOMEM;
2490*4882a593Smuzhiyun
2491*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2492*4882a593Smuzhiyun if (!debug)
2493*4882a593Smuzhiyun goto out;
2494*4882a593Smuzhiyun
2495*4882a593Smuzhiyun /* Round to page boundary */
2496*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
2497*4882a593Smuzhiyun if (!debug->buffer) {
2498*4882a593Smuzhiyun kfree(debug);
2499*4882a593Smuzhiyun goto out;
2500*4882a593Smuzhiyun }
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
2503*4882a593Smuzhiyun LPFC_NODELIST_SIZE);
2504*4882a593Smuzhiyun file->private_data = debug;
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun rc = 0;
2507*4882a593Smuzhiyun out:
2508*4882a593Smuzhiyun return rc;
2509*4882a593Smuzhiyun }
2510*4882a593Smuzhiyun
2511*4882a593Smuzhiyun /**
2512*4882a593Smuzhiyun * lpfc_debugfs_lseek - Seek through a debugfs file
2513*4882a593Smuzhiyun * @file: The file pointer to seek through.
2514*4882a593Smuzhiyun * @off: The offset to seek to or the amount to seek by.
2515*4882a593Smuzhiyun * @whence: Indicates how to seek.
2516*4882a593Smuzhiyun *
2517*4882a593Smuzhiyun * Description:
2518*4882a593Smuzhiyun * This routine is the entry point for the debugfs lseek file operation. The
2519*4882a593Smuzhiyun * @whence parameter indicates whether @off is the offset to directly seek to,
2520*4882a593Smuzhiyun * or if it is a value to seek forward or reverse by. This function figures out
2521*4882a593Smuzhiyun * what the new offset of the debugfs file will be and assigns that value to the
2522*4882a593Smuzhiyun * f_pos field of @file.
2523*4882a593Smuzhiyun *
2524*4882a593Smuzhiyun * Returns:
2525*4882a593Smuzhiyun * This function returns the new offset if successful and returns a negative
2526*4882a593Smuzhiyun * error if unable to process the seek.
2527*4882a593Smuzhiyun **/
2528*4882a593Smuzhiyun static loff_t
lpfc_debugfs_lseek(struct file * file,loff_t off,int whence)2529*4882a593Smuzhiyun lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2532*4882a593Smuzhiyun return fixed_size_llseek(file, off, whence, debug->len);
2533*4882a593Smuzhiyun }
2534*4882a593Smuzhiyun
2535*4882a593Smuzhiyun /**
2536*4882a593Smuzhiyun * lpfc_debugfs_read - Read a debugfs file
2537*4882a593Smuzhiyun * @file: The file pointer to read from.
2538*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
2539*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
2540*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
2541*4882a593Smuzhiyun *
2542*4882a593Smuzhiyun * Description:
2543*4882a593Smuzhiyun * This routine reads data from from the buffer indicated in the private_data
2544*4882a593Smuzhiyun * field of @file. It will start reading at @ppos and copy up to @nbytes of
2545*4882a593Smuzhiyun * data to @buf.
2546*4882a593Smuzhiyun *
2547*4882a593Smuzhiyun * Returns:
2548*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
2549*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
2550*4882a593Smuzhiyun **/
2551*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)2552*4882a593Smuzhiyun lpfc_debugfs_read(struct file *file, char __user *buf,
2553*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2554*4882a593Smuzhiyun {
2555*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2556*4882a593Smuzhiyun
2557*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
2558*4882a593Smuzhiyun debug->len);
2559*4882a593Smuzhiyun }
2560*4882a593Smuzhiyun
2561*4882a593Smuzhiyun /**
2562*4882a593Smuzhiyun * lpfc_debugfs_release - Release the buffer used to store debugfs file data
2563*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer. (unused)
2564*4882a593Smuzhiyun * @file: The file pointer that contains the buffer to release.
2565*4882a593Smuzhiyun *
2566*4882a593Smuzhiyun * Description:
2567*4882a593Smuzhiyun * This routine frees the buffer that was allocated when the debugfs file was
2568*4882a593Smuzhiyun * opened.
2569*4882a593Smuzhiyun *
2570*4882a593Smuzhiyun * Returns:
2571*4882a593Smuzhiyun * This function returns zero.
2572*4882a593Smuzhiyun **/
2573*4882a593Smuzhiyun static int
lpfc_debugfs_release(struct inode * inode,struct file * file)2574*4882a593Smuzhiyun lpfc_debugfs_release(struct inode *inode, struct file *file)
2575*4882a593Smuzhiyun {
2576*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun kfree(debug->buffer);
2579*4882a593Smuzhiyun kfree(debug);
2580*4882a593Smuzhiyun
2581*4882a593Smuzhiyun return 0;
2582*4882a593Smuzhiyun }
2583*4882a593Smuzhiyun
2584*4882a593Smuzhiyun /**
2585*4882a593Smuzhiyun * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics
2586*4882a593Smuzhiyun * @file: The file pointer to read from.
2587*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
2588*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
2589*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
2590*4882a593Smuzhiyun *
2591*4882a593Smuzhiyun * Description:
2592*4882a593Smuzhiyun * This routine clears multi-XRI pools statistics when buf contains "clear".
2593*4882a593Smuzhiyun *
2594*4882a593Smuzhiyun * Return Value:
2595*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
2596*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
2597*4882a593Smuzhiyun * space.
2598*4882a593Smuzhiyun **/
2599*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_multixripools_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2600*4882a593Smuzhiyun lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf,
2601*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2602*4882a593Smuzhiyun {
2603*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2604*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
2605*4882a593Smuzhiyun char mybuf[64];
2606*4882a593Smuzhiyun char *pbuf;
2607*4882a593Smuzhiyun u32 i;
2608*4882a593Smuzhiyun u32 hwq_count;
2609*4882a593Smuzhiyun struct lpfc_sli4_hdw_queue *qp;
2610*4882a593Smuzhiyun struct lpfc_multixri_pool *multixri_pool;
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun if (nbytes > sizeof(mybuf) - 1)
2613*4882a593Smuzhiyun nbytes = sizeof(mybuf) - 1;
2614*4882a593Smuzhiyun
2615*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
2616*4882a593Smuzhiyun
2617*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
2618*4882a593Smuzhiyun return -EFAULT;
2619*4882a593Smuzhiyun pbuf = &mybuf[0];
2620*4882a593Smuzhiyun
2621*4882a593Smuzhiyun if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) {
2622*4882a593Smuzhiyun hwq_count = phba->cfg_hdw_queue;
2623*4882a593Smuzhiyun for (i = 0; i < hwq_count; i++) {
2624*4882a593Smuzhiyun qp = &phba->sli4_hba.hdwq[i];
2625*4882a593Smuzhiyun multixri_pool = qp->p_multixri_pool;
2626*4882a593Smuzhiyun if (!multixri_pool)
2627*4882a593Smuzhiyun continue;
2628*4882a593Smuzhiyun
2629*4882a593Smuzhiyun qp->empty_io_bufs = 0;
2630*4882a593Smuzhiyun multixri_pool->pbl_empty_count = 0;
2631*4882a593Smuzhiyun #ifdef LPFC_MXP_STAT
2632*4882a593Smuzhiyun multixri_pool->above_limit_count = 0;
2633*4882a593Smuzhiyun multixri_pool->below_limit_count = 0;
2634*4882a593Smuzhiyun multixri_pool->stat_max_hwm = 0;
2635*4882a593Smuzhiyun multixri_pool->local_pbl_hit_count = 0;
2636*4882a593Smuzhiyun multixri_pool->other_pbl_hit_count = 0;
2637*4882a593Smuzhiyun
2638*4882a593Smuzhiyun multixri_pool->stat_pbl_count = 0;
2639*4882a593Smuzhiyun multixri_pool->stat_pvt_count = 0;
2640*4882a593Smuzhiyun multixri_pool->stat_busy_count = 0;
2641*4882a593Smuzhiyun multixri_pool->stat_snapshot_taken = 0;
2642*4882a593Smuzhiyun #endif
2643*4882a593Smuzhiyun }
2644*4882a593Smuzhiyun return strlen(pbuf);
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun
2647*4882a593Smuzhiyun return -EINVAL;
2648*4882a593Smuzhiyun }
2649*4882a593Smuzhiyun
2650*4882a593Smuzhiyun static int
lpfc_debugfs_nvmestat_open(struct inode * inode,struct file * file)2651*4882a593Smuzhiyun lpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file)
2652*4882a593Smuzhiyun {
2653*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
2654*4882a593Smuzhiyun struct lpfc_debug *debug;
2655*4882a593Smuzhiyun int rc = -ENOMEM;
2656*4882a593Smuzhiyun
2657*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2658*4882a593Smuzhiyun if (!debug)
2659*4882a593Smuzhiyun goto out;
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun /* Round to page boundary */
2662*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_NVMESTAT_SIZE, GFP_KERNEL);
2663*4882a593Smuzhiyun if (!debug->buffer) {
2664*4882a593Smuzhiyun kfree(debug);
2665*4882a593Smuzhiyun goto out;
2666*4882a593Smuzhiyun }
2667*4882a593Smuzhiyun
2668*4882a593Smuzhiyun debug->len = lpfc_debugfs_nvmestat_data(vport, debug->buffer,
2669*4882a593Smuzhiyun LPFC_NVMESTAT_SIZE);
2670*4882a593Smuzhiyun
2671*4882a593Smuzhiyun debug->i_private = inode->i_private;
2672*4882a593Smuzhiyun file->private_data = debug;
2673*4882a593Smuzhiyun
2674*4882a593Smuzhiyun rc = 0;
2675*4882a593Smuzhiyun out:
2676*4882a593Smuzhiyun return rc;
2677*4882a593Smuzhiyun }
2678*4882a593Smuzhiyun
2679*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_nvmestat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2680*4882a593Smuzhiyun lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf,
2681*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2682*4882a593Smuzhiyun {
2683*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2684*4882a593Smuzhiyun struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
2685*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
2686*4882a593Smuzhiyun struct lpfc_nvmet_tgtport *tgtp;
2687*4882a593Smuzhiyun char mybuf[64];
2688*4882a593Smuzhiyun char *pbuf;
2689*4882a593Smuzhiyun
2690*4882a593Smuzhiyun if (!phba->targetport)
2691*4882a593Smuzhiyun return -ENXIO;
2692*4882a593Smuzhiyun
2693*4882a593Smuzhiyun if (nbytes > sizeof(mybuf) - 1)
2694*4882a593Smuzhiyun nbytes = sizeof(mybuf) - 1;
2695*4882a593Smuzhiyun
2696*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
2699*4882a593Smuzhiyun return -EFAULT;
2700*4882a593Smuzhiyun pbuf = &mybuf[0];
2701*4882a593Smuzhiyun
2702*4882a593Smuzhiyun tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
2703*4882a593Smuzhiyun if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
2704*4882a593Smuzhiyun (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
2705*4882a593Smuzhiyun atomic_set(&tgtp->rcv_ls_req_in, 0);
2706*4882a593Smuzhiyun atomic_set(&tgtp->rcv_ls_req_out, 0);
2707*4882a593Smuzhiyun atomic_set(&tgtp->rcv_ls_req_drop, 0);
2708*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_abort, 0);
2709*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_abort_cmpl, 0);
2710*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_rsp, 0);
2711*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_drop, 0);
2712*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_rsp_error, 0);
2713*4882a593Smuzhiyun atomic_set(&tgtp->xmt_ls_rsp_cmpl, 0);
2714*4882a593Smuzhiyun
2715*4882a593Smuzhiyun atomic_set(&tgtp->rcv_fcp_cmd_in, 0);
2716*4882a593Smuzhiyun atomic_set(&tgtp->rcv_fcp_cmd_out, 0);
2717*4882a593Smuzhiyun atomic_set(&tgtp->rcv_fcp_cmd_drop, 0);
2718*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_drop, 0);
2719*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_read_rsp, 0);
2720*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_read, 0);
2721*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_write, 0);
2722*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_rsp, 0);
2723*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_release, 0);
2724*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_rsp_cmpl, 0);
2725*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_rsp_error, 0);
2726*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_rsp_drop, 0);
2727*4882a593Smuzhiyun
2728*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_abort, 0);
2729*4882a593Smuzhiyun atomic_set(&tgtp->xmt_fcp_abort_cmpl, 0);
2730*4882a593Smuzhiyun atomic_set(&tgtp->xmt_abort_sol, 0);
2731*4882a593Smuzhiyun atomic_set(&tgtp->xmt_abort_unsol, 0);
2732*4882a593Smuzhiyun atomic_set(&tgtp->xmt_abort_rsp, 0);
2733*4882a593Smuzhiyun atomic_set(&tgtp->xmt_abort_rsp_error, 0);
2734*4882a593Smuzhiyun }
2735*4882a593Smuzhiyun return nbytes;
2736*4882a593Smuzhiyun }
2737*4882a593Smuzhiyun
2738*4882a593Smuzhiyun static int
lpfc_debugfs_scsistat_open(struct inode * inode,struct file * file)2739*4882a593Smuzhiyun lpfc_debugfs_scsistat_open(struct inode *inode, struct file *file)
2740*4882a593Smuzhiyun {
2741*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
2742*4882a593Smuzhiyun struct lpfc_debug *debug;
2743*4882a593Smuzhiyun int rc = -ENOMEM;
2744*4882a593Smuzhiyun
2745*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2746*4882a593Smuzhiyun if (!debug)
2747*4882a593Smuzhiyun goto out;
2748*4882a593Smuzhiyun
2749*4882a593Smuzhiyun /* Round to page boundary */
2750*4882a593Smuzhiyun debug->buffer = kzalloc(LPFC_SCSISTAT_SIZE, GFP_KERNEL);
2751*4882a593Smuzhiyun if (!debug->buffer) {
2752*4882a593Smuzhiyun kfree(debug);
2753*4882a593Smuzhiyun goto out;
2754*4882a593Smuzhiyun }
2755*4882a593Smuzhiyun
2756*4882a593Smuzhiyun debug->len = lpfc_debugfs_scsistat_data(vport, debug->buffer,
2757*4882a593Smuzhiyun LPFC_SCSISTAT_SIZE);
2758*4882a593Smuzhiyun
2759*4882a593Smuzhiyun debug->i_private = inode->i_private;
2760*4882a593Smuzhiyun file->private_data = debug;
2761*4882a593Smuzhiyun
2762*4882a593Smuzhiyun rc = 0;
2763*4882a593Smuzhiyun out:
2764*4882a593Smuzhiyun return rc;
2765*4882a593Smuzhiyun }
2766*4882a593Smuzhiyun
2767*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_scsistat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2768*4882a593Smuzhiyun lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
2769*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2770*4882a593Smuzhiyun {
2771*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2772*4882a593Smuzhiyun struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
2773*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
2774*4882a593Smuzhiyun char mybuf[6] = {0};
2775*4882a593Smuzhiyun int i;
2776*4882a593Smuzhiyun
2777*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ?
2778*4882a593Smuzhiyun (sizeof(mybuf) - 1) : nbytes))
2779*4882a593Smuzhiyun return -EFAULT;
2780*4882a593Smuzhiyun
2781*4882a593Smuzhiyun if ((strncmp(&mybuf[0], "reset", strlen("reset")) == 0) ||
2782*4882a593Smuzhiyun (strncmp(&mybuf[0], "zero", strlen("zero")) == 0)) {
2783*4882a593Smuzhiyun for (i = 0; i < phba->cfg_hdw_queue; i++) {
2784*4882a593Smuzhiyun memset(&phba->sli4_hba.hdwq[i].scsi_cstat, 0,
2785*4882a593Smuzhiyun sizeof(phba->sli4_hba.hdwq[i].scsi_cstat));
2786*4882a593Smuzhiyun }
2787*4882a593Smuzhiyun }
2788*4882a593Smuzhiyun
2789*4882a593Smuzhiyun return nbytes;
2790*4882a593Smuzhiyun }
2791*4882a593Smuzhiyun
2792*4882a593Smuzhiyun static int
lpfc_debugfs_ioktime_open(struct inode * inode,struct file * file)2793*4882a593Smuzhiyun lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file)
2794*4882a593Smuzhiyun {
2795*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
2796*4882a593Smuzhiyun struct lpfc_debug *debug;
2797*4882a593Smuzhiyun int rc = -ENOMEM;
2798*4882a593Smuzhiyun
2799*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2800*4882a593Smuzhiyun if (!debug)
2801*4882a593Smuzhiyun goto out;
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun /* Round to page boundary */
2804*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL);
2805*4882a593Smuzhiyun if (!debug->buffer) {
2806*4882a593Smuzhiyun kfree(debug);
2807*4882a593Smuzhiyun goto out;
2808*4882a593Smuzhiyun }
2809*4882a593Smuzhiyun
2810*4882a593Smuzhiyun debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer,
2811*4882a593Smuzhiyun LPFC_IOKTIME_SIZE);
2812*4882a593Smuzhiyun
2813*4882a593Smuzhiyun debug->i_private = inode->i_private;
2814*4882a593Smuzhiyun file->private_data = debug;
2815*4882a593Smuzhiyun
2816*4882a593Smuzhiyun rc = 0;
2817*4882a593Smuzhiyun out:
2818*4882a593Smuzhiyun return rc;
2819*4882a593Smuzhiyun }
2820*4882a593Smuzhiyun
2821*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_ioktime_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2822*4882a593Smuzhiyun lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf,
2823*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2824*4882a593Smuzhiyun {
2825*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2826*4882a593Smuzhiyun struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
2827*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
2828*4882a593Smuzhiyun char mybuf[64];
2829*4882a593Smuzhiyun char *pbuf;
2830*4882a593Smuzhiyun
2831*4882a593Smuzhiyun if (nbytes > sizeof(mybuf) - 1)
2832*4882a593Smuzhiyun nbytes = sizeof(mybuf) - 1;
2833*4882a593Smuzhiyun
2834*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
2835*4882a593Smuzhiyun
2836*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
2837*4882a593Smuzhiyun return -EFAULT;
2838*4882a593Smuzhiyun pbuf = &mybuf[0];
2839*4882a593Smuzhiyun
2840*4882a593Smuzhiyun if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
2841*4882a593Smuzhiyun phba->ktime_data_samples = 0;
2842*4882a593Smuzhiyun phba->ktime_status_samples = 0;
2843*4882a593Smuzhiyun phba->ktime_seg1_total = 0;
2844*4882a593Smuzhiyun phba->ktime_seg1_max = 0;
2845*4882a593Smuzhiyun phba->ktime_seg1_min = 0xffffffff;
2846*4882a593Smuzhiyun phba->ktime_seg2_total = 0;
2847*4882a593Smuzhiyun phba->ktime_seg2_max = 0;
2848*4882a593Smuzhiyun phba->ktime_seg2_min = 0xffffffff;
2849*4882a593Smuzhiyun phba->ktime_seg3_total = 0;
2850*4882a593Smuzhiyun phba->ktime_seg3_max = 0;
2851*4882a593Smuzhiyun phba->ktime_seg3_min = 0xffffffff;
2852*4882a593Smuzhiyun phba->ktime_seg4_total = 0;
2853*4882a593Smuzhiyun phba->ktime_seg4_max = 0;
2854*4882a593Smuzhiyun phba->ktime_seg4_min = 0xffffffff;
2855*4882a593Smuzhiyun phba->ktime_seg5_total = 0;
2856*4882a593Smuzhiyun phba->ktime_seg5_max = 0;
2857*4882a593Smuzhiyun phba->ktime_seg5_min = 0xffffffff;
2858*4882a593Smuzhiyun phba->ktime_seg6_total = 0;
2859*4882a593Smuzhiyun phba->ktime_seg6_max = 0;
2860*4882a593Smuzhiyun phba->ktime_seg6_min = 0xffffffff;
2861*4882a593Smuzhiyun phba->ktime_seg7_total = 0;
2862*4882a593Smuzhiyun phba->ktime_seg7_max = 0;
2863*4882a593Smuzhiyun phba->ktime_seg7_min = 0xffffffff;
2864*4882a593Smuzhiyun phba->ktime_seg8_total = 0;
2865*4882a593Smuzhiyun phba->ktime_seg8_max = 0;
2866*4882a593Smuzhiyun phba->ktime_seg8_min = 0xffffffff;
2867*4882a593Smuzhiyun phba->ktime_seg9_total = 0;
2868*4882a593Smuzhiyun phba->ktime_seg9_max = 0;
2869*4882a593Smuzhiyun phba->ktime_seg9_min = 0xffffffff;
2870*4882a593Smuzhiyun phba->ktime_seg10_total = 0;
2871*4882a593Smuzhiyun phba->ktime_seg10_max = 0;
2872*4882a593Smuzhiyun phba->ktime_seg10_min = 0xffffffff;
2873*4882a593Smuzhiyun
2874*4882a593Smuzhiyun phba->ktime_on = 1;
2875*4882a593Smuzhiyun return strlen(pbuf);
2876*4882a593Smuzhiyun } else if ((strncmp(pbuf, "off",
2877*4882a593Smuzhiyun sizeof("off") - 1) == 0)) {
2878*4882a593Smuzhiyun phba->ktime_on = 0;
2879*4882a593Smuzhiyun return strlen(pbuf);
2880*4882a593Smuzhiyun } else if ((strncmp(pbuf, "zero",
2881*4882a593Smuzhiyun sizeof("zero") - 1) == 0)) {
2882*4882a593Smuzhiyun phba->ktime_data_samples = 0;
2883*4882a593Smuzhiyun phba->ktime_status_samples = 0;
2884*4882a593Smuzhiyun phba->ktime_seg1_total = 0;
2885*4882a593Smuzhiyun phba->ktime_seg1_max = 0;
2886*4882a593Smuzhiyun phba->ktime_seg1_min = 0xffffffff;
2887*4882a593Smuzhiyun phba->ktime_seg2_total = 0;
2888*4882a593Smuzhiyun phba->ktime_seg2_max = 0;
2889*4882a593Smuzhiyun phba->ktime_seg2_min = 0xffffffff;
2890*4882a593Smuzhiyun phba->ktime_seg3_total = 0;
2891*4882a593Smuzhiyun phba->ktime_seg3_max = 0;
2892*4882a593Smuzhiyun phba->ktime_seg3_min = 0xffffffff;
2893*4882a593Smuzhiyun phba->ktime_seg4_total = 0;
2894*4882a593Smuzhiyun phba->ktime_seg4_max = 0;
2895*4882a593Smuzhiyun phba->ktime_seg4_min = 0xffffffff;
2896*4882a593Smuzhiyun phba->ktime_seg5_total = 0;
2897*4882a593Smuzhiyun phba->ktime_seg5_max = 0;
2898*4882a593Smuzhiyun phba->ktime_seg5_min = 0xffffffff;
2899*4882a593Smuzhiyun phba->ktime_seg6_total = 0;
2900*4882a593Smuzhiyun phba->ktime_seg6_max = 0;
2901*4882a593Smuzhiyun phba->ktime_seg6_min = 0xffffffff;
2902*4882a593Smuzhiyun phba->ktime_seg7_total = 0;
2903*4882a593Smuzhiyun phba->ktime_seg7_max = 0;
2904*4882a593Smuzhiyun phba->ktime_seg7_min = 0xffffffff;
2905*4882a593Smuzhiyun phba->ktime_seg8_total = 0;
2906*4882a593Smuzhiyun phba->ktime_seg8_max = 0;
2907*4882a593Smuzhiyun phba->ktime_seg8_min = 0xffffffff;
2908*4882a593Smuzhiyun phba->ktime_seg9_total = 0;
2909*4882a593Smuzhiyun phba->ktime_seg9_max = 0;
2910*4882a593Smuzhiyun phba->ktime_seg9_min = 0xffffffff;
2911*4882a593Smuzhiyun phba->ktime_seg10_total = 0;
2912*4882a593Smuzhiyun phba->ktime_seg10_max = 0;
2913*4882a593Smuzhiyun phba->ktime_seg10_min = 0xffffffff;
2914*4882a593Smuzhiyun return strlen(pbuf);
2915*4882a593Smuzhiyun }
2916*4882a593Smuzhiyun return -EINVAL;
2917*4882a593Smuzhiyun }
2918*4882a593Smuzhiyun
2919*4882a593Smuzhiyun static int
lpfc_debugfs_nvmeio_trc_open(struct inode * inode,struct file * file)2920*4882a593Smuzhiyun lpfc_debugfs_nvmeio_trc_open(struct inode *inode, struct file *file)
2921*4882a593Smuzhiyun {
2922*4882a593Smuzhiyun struct lpfc_hba *phba = inode->i_private;
2923*4882a593Smuzhiyun struct lpfc_debug *debug;
2924*4882a593Smuzhiyun int rc = -ENOMEM;
2925*4882a593Smuzhiyun
2926*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2927*4882a593Smuzhiyun if (!debug)
2928*4882a593Smuzhiyun goto out;
2929*4882a593Smuzhiyun
2930*4882a593Smuzhiyun /* Round to page boundary */
2931*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_NVMEIO_TRC_SIZE, GFP_KERNEL);
2932*4882a593Smuzhiyun if (!debug->buffer) {
2933*4882a593Smuzhiyun kfree(debug);
2934*4882a593Smuzhiyun goto out;
2935*4882a593Smuzhiyun }
2936*4882a593Smuzhiyun
2937*4882a593Smuzhiyun debug->len = lpfc_debugfs_nvmeio_trc_data(phba, debug->buffer,
2938*4882a593Smuzhiyun LPFC_NVMEIO_TRC_SIZE);
2939*4882a593Smuzhiyun
2940*4882a593Smuzhiyun debug->i_private = inode->i_private;
2941*4882a593Smuzhiyun file->private_data = debug;
2942*4882a593Smuzhiyun
2943*4882a593Smuzhiyun rc = 0;
2944*4882a593Smuzhiyun out:
2945*4882a593Smuzhiyun return rc;
2946*4882a593Smuzhiyun }
2947*4882a593Smuzhiyun
2948*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_nvmeio_trc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2949*4882a593Smuzhiyun lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
2950*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
2951*4882a593Smuzhiyun {
2952*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
2953*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
2954*4882a593Smuzhiyun int i;
2955*4882a593Smuzhiyun unsigned long sz;
2956*4882a593Smuzhiyun char mybuf[64];
2957*4882a593Smuzhiyun char *pbuf;
2958*4882a593Smuzhiyun
2959*4882a593Smuzhiyun if (nbytes > sizeof(mybuf) - 1)
2960*4882a593Smuzhiyun nbytes = sizeof(mybuf) - 1;
2961*4882a593Smuzhiyun
2962*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
2963*4882a593Smuzhiyun
2964*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
2965*4882a593Smuzhiyun return -EFAULT;
2966*4882a593Smuzhiyun pbuf = &mybuf[0];
2967*4882a593Smuzhiyun
2968*4882a593Smuzhiyun if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) {
2969*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2970*4882a593Smuzhiyun "0570 nvmeio_trc_off\n");
2971*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
2972*4882a593Smuzhiyun phba->nvmeio_trc_on = 0;
2973*4882a593Smuzhiyun return strlen(pbuf);
2974*4882a593Smuzhiyun } else if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
2975*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2976*4882a593Smuzhiyun "0571 nvmeio_trc_on\n");
2977*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
2978*4882a593Smuzhiyun phba->nvmeio_trc_on = 1;
2979*4882a593Smuzhiyun return strlen(pbuf);
2980*4882a593Smuzhiyun }
2981*4882a593Smuzhiyun
2982*4882a593Smuzhiyun /* We must be off to allocate the trace buffer */
2983*4882a593Smuzhiyun if (phba->nvmeio_trc_on != 0)
2984*4882a593Smuzhiyun return -EINVAL;
2985*4882a593Smuzhiyun
2986*4882a593Smuzhiyun /* If not on or off, the parameter is the trace buffer size */
2987*4882a593Smuzhiyun i = kstrtoul(pbuf, 0, &sz);
2988*4882a593Smuzhiyun if (i)
2989*4882a593Smuzhiyun return -EINVAL;
2990*4882a593Smuzhiyun phba->nvmeio_trc_size = (uint32_t)sz;
2991*4882a593Smuzhiyun
2992*4882a593Smuzhiyun /* It must be a power of 2 - round down */
2993*4882a593Smuzhiyun i = 0;
2994*4882a593Smuzhiyun while (sz > 1) {
2995*4882a593Smuzhiyun sz = sz >> 1;
2996*4882a593Smuzhiyun i++;
2997*4882a593Smuzhiyun }
2998*4882a593Smuzhiyun sz = (1 << i);
2999*4882a593Smuzhiyun if (phba->nvmeio_trc_size != sz)
3000*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3001*4882a593Smuzhiyun "0572 nvmeio_trc_size changed to %ld\n",
3002*4882a593Smuzhiyun sz);
3003*4882a593Smuzhiyun phba->nvmeio_trc_size = (uint32_t)sz;
3004*4882a593Smuzhiyun
3005*4882a593Smuzhiyun /* If one previously exists, free it */
3006*4882a593Smuzhiyun kfree(phba->nvmeio_trc);
3007*4882a593Smuzhiyun
3008*4882a593Smuzhiyun /* Allocate new trace buffer and initialize */
3009*4882a593Smuzhiyun phba->nvmeio_trc = kzalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) *
3010*4882a593Smuzhiyun sz), GFP_KERNEL);
3011*4882a593Smuzhiyun if (!phba->nvmeio_trc) {
3012*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3013*4882a593Smuzhiyun "0573 Cannot create debugfs "
3014*4882a593Smuzhiyun "nvmeio_trc buffer\n");
3015*4882a593Smuzhiyun return -ENOMEM;
3016*4882a593Smuzhiyun }
3017*4882a593Smuzhiyun atomic_set(&phba->nvmeio_trc_cnt, 0);
3018*4882a593Smuzhiyun phba->nvmeio_trc_on = 0;
3019*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
3020*4882a593Smuzhiyun
3021*4882a593Smuzhiyun return strlen(pbuf);
3022*4882a593Smuzhiyun }
3023*4882a593Smuzhiyun
3024*4882a593Smuzhiyun static int
lpfc_debugfs_hdwqstat_open(struct inode * inode,struct file * file)3025*4882a593Smuzhiyun lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file)
3026*4882a593Smuzhiyun {
3027*4882a593Smuzhiyun struct lpfc_vport *vport = inode->i_private;
3028*4882a593Smuzhiyun struct lpfc_debug *debug;
3029*4882a593Smuzhiyun int rc = -ENOMEM;
3030*4882a593Smuzhiyun
3031*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
3032*4882a593Smuzhiyun if (!debug)
3033*4882a593Smuzhiyun goto out;
3034*4882a593Smuzhiyun
3035*4882a593Smuzhiyun /* Round to page boundary */
3036*4882a593Smuzhiyun debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL);
3037*4882a593Smuzhiyun if (!debug->buffer) {
3038*4882a593Smuzhiyun kfree(debug);
3039*4882a593Smuzhiyun goto out;
3040*4882a593Smuzhiyun }
3041*4882a593Smuzhiyun
3042*4882a593Smuzhiyun debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer,
3043*4882a593Smuzhiyun LPFC_SCSISTAT_SIZE);
3044*4882a593Smuzhiyun
3045*4882a593Smuzhiyun debug->i_private = inode->i_private;
3046*4882a593Smuzhiyun file->private_data = debug;
3047*4882a593Smuzhiyun
3048*4882a593Smuzhiyun rc = 0;
3049*4882a593Smuzhiyun out:
3050*4882a593Smuzhiyun return rc;
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun
3053*4882a593Smuzhiyun static ssize_t
lpfc_debugfs_hdwqstat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)3054*4882a593Smuzhiyun lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf,
3055*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
3056*4882a593Smuzhiyun {
3057*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3058*4882a593Smuzhiyun struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
3059*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
3060*4882a593Smuzhiyun struct lpfc_hdwq_stat *c_stat;
3061*4882a593Smuzhiyun char mybuf[64];
3062*4882a593Smuzhiyun char *pbuf;
3063*4882a593Smuzhiyun int i;
3064*4882a593Smuzhiyun
3065*4882a593Smuzhiyun if (nbytes > sizeof(mybuf) - 1)
3066*4882a593Smuzhiyun nbytes = sizeof(mybuf) - 1;
3067*4882a593Smuzhiyun
3068*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
3069*4882a593Smuzhiyun
3070*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, nbytes))
3071*4882a593Smuzhiyun return -EFAULT;
3072*4882a593Smuzhiyun pbuf = &mybuf[0];
3073*4882a593Smuzhiyun
3074*4882a593Smuzhiyun if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
3075*4882a593Smuzhiyun if (phba->nvmet_support)
3076*4882a593Smuzhiyun phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
3077*4882a593Smuzhiyun else
3078*4882a593Smuzhiyun phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO |
3079*4882a593Smuzhiyun LPFC_CHECK_SCSI_IO);
3080*4882a593Smuzhiyun return strlen(pbuf);
3081*4882a593Smuzhiyun } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) {
3082*4882a593Smuzhiyun if (phba->nvmet_support)
3083*4882a593Smuzhiyun phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
3084*4882a593Smuzhiyun else
3085*4882a593Smuzhiyun phba->hdwqstat_on |= LPFC_CHECK_NVME_IO;
3086*4882a593Smuzhiyun return strlen(pbuf);
3087*4882a593Smuzhiyun } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) {
3088*4882a593Smuzhiyun if (!phba->nvmet_support)
3089*4882a593Smuzhiyun phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO;
3090*4882a593Smuzhiyun return strlen(pbuf);
3091*4882a593Smuzhiyun } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) {
3092*4882a593Smuzhiyun phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO |
3093*4882a593Smuzhiyun LPFC_CHECK_NVMET_IO);
3094*4882a593Smuzhiyun return strlen(pbuf);
3095*4882a593Smuzhiyun } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) {
3096*4882a593Smuzhiyun phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO;
3097*4882a593Smuzhiyun return strlen(pbuf);
3098*4882a593Smuzhiyun } else if ((strncmp(pbuf, "off",
3099*4882a593Smuzhiyun sizeof("off") - 1) == 0)) {
3100*4882a593Smuzhiyun phba->hdwqstat_on = LPFC_CHECK_OFF;
3101*4882a593Smuzhiyun return strlen(pbuf);
3102*4882a593Smuzhiyun } else if ((strncmp(pbuf, "zero",
3103*4882a593Smuzhiyun sizeof("zero") - 1) == 0)) {
3104*4882a593Smuzhiyun for_each_present_cpu(i) {
3105*4882a593Smuzhiyun c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i);
3106*4882a593Smuzhiyun c_stat->xmt_io = 0;
3107*4882a593Smuzhiyun c_stat->cmpl_io = 0;
3108*4882a593Smuzhiyun c_stat->rcv_io = 0;
3109*4882a593Smuzhiyun }
3110*4882a593Smuzhiyun return strlen(pbuf);
3111*4882a593Smuzhiyun }
3112*4882a593Smuzhiyun return -EINVAL;
3113*4882a593Smuzhiyun }
3114*4882a593Smuzhiyun
3115*4882a593Smuzhiyun /*
3116*4882a593Smuzhiyun * ---------------------------------
3117*4882a593Smuzhiyun * iDiag debugfs file access methods
3118*4882a593Smuzhiyun * ---------------------------------
3119*4882a593Smuzhiyun *
3120*4882a593Smuzhiyun * All access methods are through the proper SLI4 PCI function's debugfs
3121*4882a593Smuzhiyun * iDiag directory:
3122*4882a593Smuzhiyun *
3123*4882a593Smuzhiyun * /sys/kernel/debug/lpfc/fn<#>/iDiag
3124*4882a593Smuzhiyun */
3125*4882a593Smuzhiyun
3126*4882a593Smuzhiyun /**
3127*4882a593Smuzhiyun * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space
3128*4882a593Smuzhiyun * @buf: The pointer to the user space buffer.
3129*4882a593Smuzhiyun * @nbytes: The number of bytes in the user space buffer.
3130*4882a593Smuzhiyun * @idiag_cmd: pointer to the idiag command struct.
3131*4882a593Smuzhiyun *
3132*4882a593Smuzhiyun * This routine reads data from debugfs user space buffer and parses the
3133*4882a593Smuzhiyun * buffer for getting the idiag command and arguments. The while space in
3134*4882a593Smuzhiyun * between the set of data is used as the parsing separator.
3135*4882a593Smuzhiyun *
3136*4882a593Smuzhiyun * This routine returns 0 when successful, it returns proper error code
3137*4882a593Smuzhiyun * back to the user space in error conditions.
3138*4882a593Smuzhiyun */
lpfc_idiag_cmd_get(const char __user * buf,size_t nbytes,struct lpfc_idiag_cmd * idiag_cmd)3139*4882a593Smuzhiyun static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes,
3140*4882a593Smuzhiyun struct lpfc_idiag_cmd *idiag_cmd)
3141*4882a593Smuzhiyun {
3142*4882a593Smuzhiyun char mybuf[64];
3143*4882a593Smuzhiyun char *pbuf, *step_str;
3144*4882a593Smuzhiyun int i;
3145*4882a593Smuzhiyun size_t bsize;
3146*4882a593Smuzhiyun
3147*4882a593Smuzhiyun memset(mybuf, 0, sizeof(mybuf));
3148*4882a593Smuzhiyun memset(idiag_cmd, 0, sizeof(*idiag_cmd));
3149*4882a593Smuzhiyun bsize = min(nbytes, (sizeof(mybuf)-1));
3150*4882a593Smuzhiyun
3151*4882a593Smuzhiyun if (copy_from_user(mybuf, buf, bsize))
3152*4882a593Smuzhiyun return -EFAULT;
3153*4882a593Smuzhiyun pbuf = &mybuf[0];
3154*4882a593Smuzhiyun step_str = strsep(&pbuf, "\t ");
3155*4882a593Smuzhiyun
3156*4882a593Smuzhiyun /* The opcode must present */
3157*4882a593Smuzhiyun if (!step_str)
3158*4882a593Smuzhiyun return -EINVAL;
3159*4882a593Smuzhiyun
3160*4882a593Smuzhiyun idiag_cmd->opcode = simple_strtol(step_str, NULL, 0);
3161*4882a593Smuzhiyun if (idiag_cmd->opcode == 0)
3162*4882a593Smuzhiyun return -EINVAL;
3163*4882a593Smuzhiyun
3164*4882a593Smuzhiyun for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) {
3165*4882a593Smuzhiyun step_str = strsep(&pbuf, "\t ");
3166*4882a593Smuzhiyun if (!step_str)
3167*4882a593Smuzhiyun return i;
3168*4882a593Smuzhiyun idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0);
3169*4882a593Smuzhiyun }
3170*4882a593Smuzhiyun return i;
3171*4882a593Smuzhiyun }
3172*4882a593Smuzhiyun
3173*4882a593Smuzhiyun /**
3174*4882a593Smuzhiyun * lpfc_idiag_open - idiag open debugfs
3175*4882a593Smuzhiyun * @inode: The inode pointer that contains a pointer to phba.
3176*4882a593Smuzhiyun * @file: The file pointer to attach the file operation.
3177*4882a593Smuzhiyun *
3178*4882a593Smuzhiyun * Description:
3179*4882a593Smuzhiyun * This routine is the entry point for the debugfs open file operation. It
3180*4882a593Smuzhiyun * gets the reference to phba from the i_private field in @inode, it then
3181*4882a593Smuzhiyun * allocates buffer for the file operation, performs the necessary PCI config
3182*4882a593Smuzhiyun * space read into the allocated buffer according to the idiag user command
3183*4882a593Smuzhiyun * setup, and then returns a pointer to buffer in the private_data field in
3184*4882a593Smuzhiyun * @file.
3185*4882a593Smuzhiyun *
3186*4882a593Smuzhiyun * Returns:
3187*4882a593Smuzhiyun * This function returns zero if successful. On error it will return an
3188*4882a593Smuzhiyun * negative error value.
3189*4882a593Smuzhiyun **/
3190*4882a593Smuzhiyun static int
lpfc_idiag_open(struct inode * inode,struct file * file)3191*4882a593Smuzhiyun lpfc_idiag_open(struct inode *inode, struct file *file)
3192*4882a593Smuzhiyun {
3193*4882a593Smuzhiyun struct lpfc_debug *debug;
3194*4882a593Smuzhiyun
3195*4882a593Smuzhiyun debug = kmalloc(sizeof(*debug), GFP_KERNEL);
3196*4882a593Smuzhiyun if (!debug)
3197*4882a593Smuzhiyun return -ENOMEM;
3198*4882a593Smuzhiyun
3199*4882a593Smuzhiyun debug->i_private = inode->i_private;
3200*4882a593Smuzhiyun debug->buffer = NULL;
3201*4882a593Smuzhiyun file->private_data = debug;
3202*4882a593Smuzhiyun
3203*4882a593Smuzhiyun return 0;
3204*4882a593Smuzhiyun }
3205*4882a593Smuzhiyun
3206*4882a593Smuzhiyun /**
3207*4882a593Smuzhiyun * lpfc_idiag_release - Release idiag access file operation
3208*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer. (unused)
3209*4882a593Smuzhiyun * @file: The file pointer that contains the buffer to release.
3210*4882a593Smuzhiyun *
3211*4882a593Smuzhiyun * Description:
3212*4882a593Smuzhiyun * This routine is the generic release routine for the idiag access file
3213*4882a593Smuzhiyun * operation, it frees the buffer that was allocated when the debugfs file
3214*4882a593Smuzhiyun * was opened.
3215*4882a593Smuzhiyun *
3216*4882a593Smuzhiyun * Returns:
3217*4882a593Smuzhiyun * This function returns zero.
3218*4882a593Smuzhiyun **/
3219*4882a593Smuzhiyun static int
lpfc_idiag_release(struct inode * inode,struct file * file)3220*4882a593Smuzhiyun lpfc_idiag_release(struct inode *inode, struct file *file)
3221*4882a593Smuzhiyun {
3222*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3223*4882a593Smuzhiyun
3224*4882a593Smuzhiyun /* Free the buffers to the file operation */
3225*4882a593Smuzhiyun kfree(debug->buffer);
3226*4882a593Smuzhiyun kfree(debug);
3227*4882a593Smuzhiyun
3228*4882a593Smuzhiyun return 0;
3229*4882a593Smuzhiyun }
3230*4882a593Smuzhiyun
3231*4882a593Smuzhiyun /**
3232*4882a593Smuzhiyun * lpfc_idiag_cmd_release - Release idiag cmd access file operation
3233*4882a593Smuzhiyun * @inode: The inode pointer that contains a vport pointer. (unused)
3234*4882a593Smuzhiyun * @file: The file pointer that contains the buffer to release.
3235*4882a593Smuzhiyun *
3236*4882a593Smuzhiyun * Description:
3237*4882a593Smuzhiyun * This routine frees the buffer that was allocated when the debugfs file
3238*4882a593Smuzhiyun * was opened. It also reset the fields in the idiag command struct in the
3239*4882a593Smuzhiyun * case of command for write operation.
3240*4882a593Smuzhiyun *
3241*4882a593Smuzhiyun * Returns:
3242*4882a593Smuzhiyun * This function returns zero.
3243*4882a593Smuzhiyun **/
3244*4882a593Smuzhiyun static int
lpfc_idiag_cmd_release(struct inode * inode,struct file * file)3245*4882a593Smuzhiyun lpfc_idiag_cmd_release(struct inode *inode, struct file *file)
3246*4882a593Smuzhiyun {
3247*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3248*4882a593Smuzhiyun
3249*4882a593Smuzhiyun if (debug->op == LPFC_IDIAG_OP_WR) {
3250*4882a593Smuzhiyun switch (idiag.cmd.opcode) {
3251*4882a593Smuzhiyun case LPFC_IDIAG_CMD_PCICFG_WR:
3252*4882a593Smuzhiyun case LPFC_IDIAG_CMD_PCICFG_ST:
3253*4882a593Smuzhiyun case LPFC_IDIAG_CMD_PCICFG_CL:
3254*4882a593Smuzhiyun case LPFC_IDIAG_CMD_QUEACC_WR:
3255*4882a593Smuzhiyun case LPFC_IDIAG_CMD_QUEACC_ST:
3256*4882a593Smuzhiyun case LPFC_IDIAG_CMD_QUEACC_CL:
3257*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
3258*4882a593Smuzhiyun break;
3259*4882a593Smuzhiyun default:
3260*4882a593Smuzhiyun break;
3261*4882a593Smuzhiyun }
3262*4882a593Smuzhiyun }
3263*4882a593Smuzhiyun
3264*4882a593Smuzhiyun /* Free the buffers to the file operation */
3265*4882a593Smuzhiyun kfree(debug->buffer);
3266*4882a593Smuzhiyun kfree(debug);
3267*4882a593Smuzhiyun
3268*4882a593Smuzhiyun return 0;
3269*4882a593Smuzhiyun }
3270*4882a593Smuzhiyun
3271*4882a593Smuzhiyun /**
3272*4882a593Smuzhiyun * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg
3273*4882a593Smuzhiyun * @file: The file pointer to read from.
3274*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
3275*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
3276*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
3277*4882a593Smuzhiyun *
3278*4882a593Smuzhiyun * Description:
3279*4882a593Smuzhiyun * This routine reads data from the @phba pci config space according to the
3280*4882a593Smuzhiyun * idiag command, and copies to user @buf. Depending on the PCI config space
3281*4882a593Smuzhiyun * read command setup, it does either a single register read of a byte
3282*4882a593Smuzhiyun * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all
3283*4882a593Smuzhiyun * registers from the 4K extended PCI config space.
3284*4882a593Smuzhiyun *
3285*4882a593Smuzhiyun * Returns:
3286*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
3287*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
3288*4882a593Smuzhiyun **/
3289*4882a593Smuzhiyun static ssize_t
lpfc_idiag_pcicfg_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)3290*4882a593Smuzhiyun lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
3291*4882a593Smuzhiyun loff_t *ppos)
3292*4882a593Smuzhiyun {
3293*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3294*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3295*4882a593Smuzhiyun int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE;
3296*4882a593Smuzhiyun int where, count;
3297*4882a593Smuzhiyun char *pbuffer;
3298*4882a593Smuzhiyun struct pci_dev *pdev;
3299*4882a593Smuzhiyun uint32_t u32val;
3300*4882a593Smuzhiyun uint16_t u16val;
3301*4882a593Smuzhiyun uint8_t u8val;
3302*4882a593Smuzhiyun
3303*4882a593Smuzhiyun pdev = phba->pcidev;
3304*4882a593Smuzhiyun if (!pdev)
3305*4882a593Smuzhiyun return 0;
3306*4882a593Smuzhiyun
3307*4882a593Smuzhiyun /* This is a user read operation */
3308*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
3309*4882a593Smuzhiyun
3310*4882a593Smuzhiyun if (!debug->buffer)
3311*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL);
3312*4882a593Smuzhiyun if (!debug->buffer)
3313*4882a593Smuzhiyun return 0;
3314*4882a593Smuzhiyun pbuffer = debug->buffer;
3315*4882a593Smuzhiyun
3316*4882a593Smuzhiyun if (*ppos)
3317*4882a593Smuzhiyun return 0;
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
3320*4882a593Smuzhiyun where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3321*4882a593Smuzhiyun count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
3322*4882a593Smuzhiyun } else
3323*4882a593Smuzhiyun return 0;
3324*4882a593Smuzhiyun
3325*4882a593Smuzhiyun /* Read single PCI config space register */
3326*4882a593Smuzhiyun switch (count) {
3327*4882a593Smuzhiyun case SIZE_U8: /* byte (8 bits) */
3328*4882a593Smuzhiyun pci_read_config_byte(pdev, where, &u8val);
3329*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3330*4882a593Smuzhiyun "%03x: %02x\n", where, u8val);
3331*4882a593Smuzhiyun break;
3332*4882a593Smuzhiyun case SIZE_U16: /* word (16 bits) */
3333*4882a593Smuzhiyun pci_read_config_word(pdev, where, &u16val);
3334*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3335*4882a593Smuzhiyun "%03x: %04x\n", where, u16val);
3336*4882a593Smuzhiyun break;
3337*4882a593Smuzhiyun case SIZE_U32: /* double word (32 bits) */
3338*4882a593Smuzhiyun pci_read_config_dword(pdev, where, &u32val);
3339*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3340*4882a593Smuzhiyun "%03x: %08x\n", where, u32val);
3341*4882a593Smuzhiyun break;
3342*4882a593Smuzhiyun case LPFC_PCI_CFG_BROWSE: /* browse all */
3343*4882a593Smuzhiyun goto pcicfg_browse;
3344*4882a593Smuzhiyun break;
3345*4882a593Smuzhiyun default:
3346*4882a593Smuzhiyun /* illegal count */
3347*4882a593Smuzhiyun len = 0;
3348*4882a593Smuzhiyun break;
3349*4882a593Smuzhiyun }
3350*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3351*4882a593Smuzhiyun
3352*4882a593Smuzhiyun pcicfg_browse:
3353*4882a593Smuzhiyun
3354*4882a593Smuzhiyun /* Browse all PCI config space registers */
3355*4882a593Smuzhiyun offset_label = idiag.offset.last_rd;
3356*4882a593Smuzhiyun offset = offset_label;
3357*4882a593Smuzhiyun
3358*4882a593Smuzhiyun /* Read PCI config space */
3359*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3360*4882a593Smuzhiyun "%03x: ", offset_label);
3361*4882a593Smuzhiyun while (index > 0) {
3362*4882a593Smuzhiyun pci_read_config_dword(pdev, offset, &u32val);
3363*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3364*4882a593Smuzhiyun "%08x ", u32val);
3365*4882a593Smuzhiyun offset += sizeof(uint32_t);
3366*4882a593Smuzhiyun if (offset >= LPFC_PCI_CFG_SIZE) {
3367*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
3368*4882a593Smuzhiyun LPFC_PCI_CFG_SIZE-len, "\n");
3369*4882a593Smuzhiyun break;
3370*4882a593Smuzhiyun }
3371*4882a593Smuzhiyun index -= sizeof(uint32_t);
3372*4882a593Smuzhiyun if (!index)
3373*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3374*4882a593Smuzhiyun "\n");
3375*4882a593Smuzhiyun else if (!(index % (8 * sizeof(uint32_t)))) {
3376*4882a593Smuzhiyun offset_label += (8 * sizeof(uint32_t));
3377*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
3378*4882a593Smuzhiyun "\n%03x: ", offset_label);
3379*4882a593Smuzhiyun }
3380*4882a593Smuzhiyun }
3381*4882a593Smuzhiyun
3382*4882a593Smuzhiyun /* Set up the offset for next portion of pci cfg read */
3383*4882a593Smuzhiyun if (index == 0) {
3384*4882a593Smuzhiyun idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
3385*4882a593Smuzhiyun if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
3386*4882a593Smuzhiyun idiag.offset.last_rd = 0;
3387*4882a593Smuzhiyun } else
3388*4882a593Smuzhiyun idiag.offset.last_rd = 0;
3389*4882a593Smuzhiyun
3390*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3391*4882a593Smuzhiyun }
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun /**
3394*4882a593Smuzhiyun * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands
3395*4882a593Smuzhiyun * @file: The file pointer to read from.
3396*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
3397*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
3398*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
3399*4882a593Smuzhiyun *
3400*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and
3401*4882a593Smuzhiyun * then perform the syntax check for PCI config space read or write command
3402*4882a593Smuzhiyun * accordingly. In the case of PCI config space read command, it sets up
3403*4882a593Smuzhiyun * the command in the idiag command struct for the debugfs read operation.
3404*4882a593Smuzhiyun * In the case of PCI config space write operation, it executes the write
3405*4882a593Smuzhiyun * operation into the PCI config space accordingly.
3406*4882a593Smuzhiyun *
3407*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
3408*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
3409*4882a593Smuzhiyun * space.
3410*4882a593Smuzhiyun */
3411*4882a593Smuzhiyun static ssize_t
lpfc_idiag_pcicfg_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)3412*4882a593Smuzhiyun lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
3413*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
3414*4882a593Smuzhiyun {
3415*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3416*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3417*4882a593Smuzhiyun uint32_t where, value, count;
3418*4882a593Smuzhiyun uint32_t u32val;
3419*4882a593Smuzhiyun uint16_t u16val;
3420*4882a593Smuzhiyun uint8_t u8val;
3421*4882a593Smuzhiyun struct pci_dev *pdev;
3422*4882a593Smuzhiyun int rc;
3423*4882a593Smuzhiyun
3424*4882a593Smuzhiyun pdev = phba->pcidev;
3425*4882a593Smuzhiyun if (!pdev)
3426*4882a593Smuzhiyun return -EFAULT;
3427*4882a593Smuzhiyun
3428*4882a593Smuzhiyun /* This is a user write operation */
3429*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
3430*4882a593Smuzhiyun
3431*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
3432*4882a593Smuzhiyun if (rc < 0)
3433*4882a593Smuzhiyun return rc;
3434*4882a593Smuzhiyun
3435*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
3436*4882a593Smuzhiyun /* Sanity check on PCI config read command line arguments */
3437*4882a593Smuzhiyun if (rc != LPFC_PCI_CFG_RD_CMD_ARG)
3438*4882a593Smuzhiyun goto error_out;
3439*4882a593Smuzhiyun /* Read command from PCI config space, set up command fields */
3440*4882a593Smuzhiyun where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3441*4882a593Smuzhiyun count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
3442*4882a593Smuzhiyun if (count == LPFC_PCI_CFG_BROWSE) {
3443*4882a593Smuzhiyun if (where % sizeof(uint32_t))
3444*4882a593Smuzhiyun goto error_out;
3445*4882a593Smuzhiyun /* Starting offset to browse */
3446*4882a593Smuzhiyun idiag.offset.last_rd = where;
3447*4882a593Smuzhiyun } else if ((count != sizeof(uint8_t)) &&
3448*4882a593Smuzhiyun (count != sizeof(uint16_t)) &&
3449*4882a593Smuzhiyun (count != sizeof(uint32_t)))
3450*4882a593Smuzhiyun goto error_out;
3451*4882a593Smuzhiyun if (count == sizeof(uint8_t)) {
3452*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
3453*4882a593Smuzhiyun goto error_out;
3454*4882a593Smuzhiyun if (where % sizeof(uint8_t))
3455*4882a593Smuzhiyun goto error_out;
3456*4882a593Smuzhiyun }
3457*4882a593Smuzhiyun if (count == sizeof(uint16_t)) {
3458*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
3459*4882a593Smuzhiyun goto error_out;
3460*4882a593Smuzhiyun if (where % sizeof(uint16_t))
3461*4882a593Smuzhiyun goto error_out;
3462*4882a593Smuzhiyun }
3463*4882a593Smuzhiyun if (count == sizeof(uint32_t)) {
3464*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
3465*4882a593Smuzhiyun goto error_out;
3466*4882a593Smuzhiyun if (where % sizeof(uint32_t))
3467*4882a593Smuzhiyun goto error_out;
3468*4882a593Smuzhiyun }
3469*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR ||
3470*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST ||
3471*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
3472*4882a593Smuzhiyun /* Sanity check on PCI config write command line arguments */
3473*4882a593Smuzhiyun if (rc != LPFC_PCI_CFG_WR_CMD_ARG)
3474*4882a593Smuzhiyun goto error_out;
3475*4882a593Smuzhiyun /* Write command to PCI config space, read-modify-write */
3476*4882a593Smuzhiyun where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3477*4882a593Smuzhiyun count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
3478*4882a593Smuzhiyun value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];
3479*4882a593Smuzhiyun /* Sanity checks */
3480*4882a593Smuzhiyun if ((count != sizeof(uint8_t)) &&
3481*4882a593Smuzhiyun (count != sizeof(uint16_t)) &&
3482*4882a593Smuzhiyun (count != sizeof(uint32_t)))
3483*4882a593Smuzhiyun goto error_out;
3484*4882a593Smuzhiyun if (count == sizeof(uint8_t)) {
3485*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
3486*4882a593Smuzhiyun goto error_out;
3487*4882a593Smuzhiyun if (where % sizeof(uint8_t))
3488*4882a593Smuzhiyun goto error_out;
3489*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
3490*4882a593Smuzhiyun pci_write_config_byte(pdev, where,
3491*4882a593Smuzhiyun (uint8_t)value);
3492*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
3493*4882a593Smuzhiyun rc = pci_read_config_byte(pdev, where, &u8val);
3494*4882a593Smuzhiyun if (!rc) {
3495*4882a593Smuzhiyun u8val |= (uint8_t)value;
3496*4882a593Smuzhiyun pci_write_config_byte(pdev, where,
3497*4882a593Smuzhiyun u8val);
3498*4882a593Smuzhiyun }
3499*4882a593Smuzhiyun }
3500*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
3501*4882a593Smuzhiyun rc = pci_read_config_byte(pdev, where, &u8val);
3502*4882a593Smuzhiyun if (!rc) {
3503*4882a593Smuzhiyun u8val &= (uint8_t)(~value);
3504*4882a593Smuzhiyun pci_write_config_byte(pdev, where,
3505*4882a593Smuzhiyun u8val);
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun }
3508*4882a593Smuzhiyun }
3509*4882a593Smuzhiyun if (count == sizeof(uint16_t)) {
3510*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
3511*4882a593Smuzhiyun goto error_out;
3512*4882a593Smuzhiyun if (where % sizeof(uint16_t))
3513*4882a593Smuzhiyun goto error_out;
3514*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
3515*4882a593Smuzhiyun pci_write_config_word(pdev, where,
3516*4882a593Smuzhiyun (uint16_t)value);
3517*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
3518*4882a593Smuzhiyun rc = pci_read_config_word(pdev, where, &u16val);
3519*4882a593Smuzhiyun if (!rc) {
3520*4882a593Smuzhiyun u16val |= (uint16_t)value;
3521*4882a593Smuzhiyun pci_write_config_word(pdev, where,
3522*4882a593Smuzhiyun u16val);
3523*4882a593Smuzhiyun }
3524*4882a593Smuzhiyun }
3525*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
3526*4882a593Smuzhiyun rc = pci_read_config_word(pdev, where, &u16val);
3527*4882a593Smuzhiyun if (!rc) {
3528*4882a593Smuzhiyun u16val &= (uint16_t)(~value);
3529*4882a593Smuzhiyun pci_write_config_word(pdev, where,
3530*4882a593Smuzhiyun u16val);
3531*4882a593Smuzhiyun }
3532*4882a593Smuzhiyun }
3533*4882a593Smuzhiyun }
3534*4882a593Smuzhiyun if (count == sizeof(uint32_t)) {
3535*4882a593Smuzhiyun if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
3536*4882a593Smuzhiyun goto error_out;
3537*4882a593Smuzhiyun if (where % sizeof(uint32_t))
3538*4882a593Smuzhiyun goto error_out;
3539*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
3540*4882a593Smuzhiyun pci_write_config_dword(pdev, where, value);
3541*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
3542*4882a593Smuzhiyun rc = pci_read_config_dword(pdev, where,
3543*4882a593Smuzhiyun &u32val);
3544*4882a593Smuzhiyun if (!rc) {
3545*4882a593Smuzhiyun u32val |= value;
3546*4882a593Smuzhiyun pci_write_config_dword(pdev, where,
3547*4882a593Smuzhiyun u32val);
3548*4882a593Smuzhiyun }
3549*4882a593Smuzhiyun }
3550*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
3551*4882a593Smuzhiyun rc = pci_read_config_dword(pdev, where,
3552*4882a593Smuzhiyun &u32val);
3553*4882a593Smuzhiyun if (!rc) {
3554*4882a593Smuzhiyun u32val &= ~value;
3555*4882a593Smuzhiyun pci_write_config_dword(pdev, where,
3556*4882a593Smuzhiyun u32val);
3557*4882a593Smuzhiyun }
3558*4882a593Smuzhiyun }
3559*4882a593Smuzhiyun }
3560*4882a593Smuzhiyun } else
3561*4882a593Smuzhiyun /* All other opecodes are illegal for now */
3562*4882a593Smuzhiyun goto error_out;
3563*4882a593Smuzhiyun
3564*4882a593Smuzhiyun return nbytes;
3565*4882a593Smuzhiyun error_out:
3566*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
3567*4882a593Smuzhiyun return -EINVAL;
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun
3570*4882a593Smuzhiyun /**
3571*4882a593Smuzhiyun * lpfc_idiag_baracc_read - idiag debugfs pci bar access read
3572*4882a593Smuzhiyun * @file: The file pointer to read from.
3573*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
3574*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
3575*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
3576*4882a593Smuzhiyun *
3577*4882a593Smuzhiyun * Description:
3578*4882a593Smuzhiyun * This routine reads data from the @phba pci bar memory mapped space
3579*4882a593Smuzhiyun * according to the idiag command, and copies to user @buf.
3580*4882a593Smuzhiyun *
3581*4882a593Smuzhiyun * Returns:
3582*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
3583*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
3584*4882a593Smuzhiyun **/
3585*4882a593Smuzhiyun static ssize_t
lpfc_idiag_baracc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)3586*4882a593Smuzhiyun lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
3587*4882a593Smuzhiyun loff_t *ppos)
3588*4882a593Smuzhiyun {
3589*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3590*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3591*4882a593Smuzhiyun int offset_label, offset, offset_run, len = 0, index;
3592*4882a593Smuzhiyun int bar_num, acc_range, bar_size;
3593*4882a593Smuzhiyun char *pbuffer;
3594*4882a593Smuzhiyun void __iomem *mem_mapped_bar;
3595*4882a593Smuzhiyun uint32_t if_type;
3596*4882a593Smuzhiyun struct pci_dev *pdev;
3597*4882a593Smuzhiyun uint32_t u32val;
3598*4882a593Smuzhiyun
3599*4882a593Smuzhiyun pdev = phba->pcidev;
3600*4882a593Smuzhiyun if (!pdev)
3601*4882a593Smuzhiyun return 0;
3602*4882a593Smuzhiyun
3603*4882a593Smuzhiyun /* This is a user read operation */
3604*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
3605*4882a593Smuzhiyun
3606*4882a593Smuzhiyun if (!debug->buffer)
3607*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL);
3608*4882a593Smuzhiyun if (!debug->buffer)
3609*4882a593Smuzhiyun return 0;
3610*4882a593Smuzhiyun pbuffer = debug->buffer;
3611*4882a593Smuzhiyun
3612*4882a593Smuzhiyun if (*ppos)
3613*4882a593Smuzhiyun return 0;
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
3616*4882a593Smuzhiyun bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
3617*4882a593Smuzhiyun offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
3618*4882a593Smuzhiyun acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
3619*4882a593Smuzhiyun bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
3620*4882a593Smuzhiyun } else
3621*4882a593Smuzhiyun return 0;
3622*4882a593Smuzhiyun
3623*4882a593Smuzhiyun if (acc_range == 0)
3624*4882a593Smuzhiyun return 0;
3625*4882a593Smuzhiyun
3626*4882a593Smuzhiyun if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
3627*4882a593Smuzhiyun if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3628*4882a593Smuzhiyun if (bar_num == IDIAG_BARACC_BAR_0)
3629*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3630*4882a593Smuzhiyun else if (bar_num == IDIAG_BARACC_BAR_1)
3631*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
3632*4882a593Smuzhiyun else if (bar_num == IDIAG_BARACC_BAR_2)
3633*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
3634*4882a593Smuzhiyun else
3635*4882a593Smuzhiyun return 0;
3636*4882a593Smuzhiyun } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3637*4882a593Smuzhiyun if (bar_num == IDIAG_BARACC_BAR_0)
3638*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3639*4882a593Smuzhiyun else
3640*4882a593Smuzhiyun return 0;
3641*4882a593Smuzhiyun } else
3642*4882a593Smuzhiyun return 0;
3643*4882a593Smuzhiyun
3644*4882a593Smuzhiyun /* Read single PCI bar space register */
3645*4882a593Smuzhiyun if (acc_range == SINGLE_WORD) {
3646*4882a593Smuzhiyun offset_run = offset;
3647*4882a593Smuzhiyun u32val = readl(mem_mapped_bar + offset_run);
3648*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3649*4882a593Smuzhiyun "%05x: %08x\n", offset_run, u32val);
3650*4882a593Smuzhiyun } else
3651*4882a593Smuzhiyun goto baracc_browse;
3652*4882a593Smuzhiyun
3653*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3654*4882a593Smuzhiyun
3655*4882a593Smuzhiyun baracc_browse:
3656*4882a593Smuzhiyun
3657*4882a593Smuzhiyun /* Browse all PCI bar space registers */
3658*4882a593Smuzhiyun offset_label = idiag.offset.last_rd;
3659*4882a593Smuzhiyun offset_run = offset_label;
3660*4882a593Smuzhiyun
3661*4882a593Smuzhiyun /* Read PCI bar memory mapped space */
3662*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3663*4882a593Smuzhiyun "%05x: ", offset_label);
3664*4882a593Smuzhiyun index = LPFC_PCI_BAR_RD_SIZE;
3665*4882a593Smuzhiyun while (index > 0) {
3666*4882a593Smuzhiyun u32val = readl(mem_mapped_bar + offset_run);
3667*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3668*4882a593Smuzhiyun "%08x ", u32val);
3669*4882a593Smuzhiyun offset_run += sizeof(uint32_t);
3670*4882a593Smuzhiyun if (acc_range == LPFC_PCI_BAR_BROWSE) {
3671*4882a593Smuzhiyun if (offset_run >= bar_size) {
3672*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
3673*4882a593Smuzhiyun LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3674*4882a593Smuzhiyun break;
3675*4882a593Smuzhiyun }
3676*4882a593Smuzhiyun } else {
3677*4882a593Smuzhiyun if (offset_run >= offset +
3678*4882a593Smuzhiyun (acc_range * sizeof(uint32_t))) {
3679*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
3680*4882a593Smuzhiyun LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3681*4882a593Smuzhiyun break;
3682*4882a593Smuzhiyun }
3683*4882a593Smuzhiyun }
3684*4882a593Smuzhiyun index -= sizeof(uint32_t);
3685*4882a593Smuzhiyun if (!index)
3686*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
3687*4882a593Smuzhiyun LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3688*4882a593Smuzhiyun else if (!(index % (8 * sizeof(uint32_t)))) {
3689*4882a593Smuzhiyun offset_label += (8 * sizeof(uint32_t));
3690*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
3691*4882a593Smuzhiyun LPFC_PCI_BAR_RD_BUF_SIZE-len,
3692*4882a593Smuzhiyun "\n%05x: ", offset_label);
3693*4882a593Smuzhiyun }
3694*4882a593Smuzhiyun }
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun /* Set up the offset for next portion of pci bar read */
3697*4882a593Smuzhiyun if (index == 0) {
3698*4882a593Smuzhiyun idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE;
3699*4882a593Smuzhiyun if (acc_range == LPFC_PCI_BAR_BROWSE) {
3700*4882a593Smuzhiyun if (idiag.offset.last_rd >= bar_size)
3701*4882a593Smuzhiyun idiag.offset.last_rd = 0;
3702*4882a593Smuzhiyun } else {
3703*4882a593Smuzhiyun if (offset_run >= offset +
3704*4882a593Smuzhiyun (acc_range * sizeof(uint32_t)))
3705*4882a593Smuzhiyun idiag.offset.last_rd = offset;
3706*4882a593Smuzhiyun }
3707*4882a593Smuzhiyun } else {
3708*4882a593Smuzhiyun if (acc_range == LPFC_PCI_BAR_BROWSE)
3709*4882a593Smuzhiyun idiag.offset.last_rd = 0;
3710*4882a593Smuzhiyun else
3711*4882a593Smuzhiyun idiag.offset.last_rd = offset;
3712*4882a593Smuzhiyun }
3713*4882a593Smuzhiyun
3714*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3715*4882a593Smuzhiyun }
3716*4882a593Smuzhiyun
3717*4882a593Smuzhiyun /**
3718*4882a593Smuzhiyun * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands
3719*4882a593Smuzhiyun * @file: The file pointer to read from.
3720*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
3721*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
3722*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
3723*4882a593Smuzhiyun *
3724*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and
3725*4882a593Smuzhiyun * then perform the syntax check for PCI bar memory mapped space read or
3726*4882a593Smuzhiyun * write command accordingly. In the case of PCI bar memory mapped space
3727*4882a593Smuzhiyun * read command, it sets up the command in the idiag command struct for
3728*4882a593Smuzhiyun * the debugfs read operation. In the case of PCI bar memorpy mapped space
3729*4882a593Smuzhiyun * write operation, it executes the write operation into the PCI bar memory
3730*4882a593Smuzhiyun * mapped space accordingly.
3731*4882a593Smuzhiyun *
3732*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
3733*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
3734*4882a593Smuzhiyun * space.
3735*4882a593Smuzhiyun */
3736*4882a593Smuzhiyun static ssize_t
lpfc_idiag_baracc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)3737*4882a593Smuzhiyun lpfc_idiag_baracc_write(struct file *file, const char __user *buf,
3738*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
3739*4882a593Smuzhiyun {
3740*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
3741*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3742*4882a593Smuzhiyun uint32_t bar_num, bar_size, offset, value, acc_range;
3743*4882a593Smuzhiyun struct pci_dev *pdev;
3744*4882a593Smuzhiyun void __iomem *mem_mapped_bar;
3745*4882a593Smuzhiyun uint32_t if_type;
3746*4882a593Smuzhiyun uint32_t u32val;
3747*4882a593Smuzhiyun int rc;
3748*4882a593Smuzhiyun
3749*4882a593Smuzhiyun pdev = phba->pcidev;
3750*4882a593Smuzhiyun if (!pdev)
3751*4882a593Smuzhiyun return -EFAULT;
3752*4882a593Smuzhiyun
3753*4882a593Smuzhiyun /* This is a user write operation */
3754*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
3755*4882a593Smuzhiyun
3756*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
3757*4882a593Smuzhiyun if (rc < 0)
3758*4882a593Smuzhiyun return rc;
3759*4882a593Smuzhiyun
3760*4882a593Smuzhiyun if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
3761*4882a593Smuzhiyun bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
3762*4882a593Smuzhiyun
3763*4882a593Smuzhiyun if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3764*4882a593Smuzhiyun if ((bar_num != IDIAG_BARACC_BAR_0) &&
3765*4882a593Smuzhiyun (bar_num != IDIAG_BARACC_BAR_1) &&
3766*4882a593Smuzhiyun (bar_num != IDIAG_BARACC_BAR_2))
3767*4882a593Smuzhiyun goto error_out;
3768*4882a593Smuzhiyun } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3769*4882a593Smuzhiyun if (bar_num != IDIAG_BARACC_BAR_0)
3770*4882a593Smuzhiyun goto error_out;
3771*4882a593Smuzhiyun } else
3772*4882a593Smuzhiyun goto error_out;
3773*4882a593Smuzhiyun
3774*4882a593Smuzhiyun if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3775*4882a593Smuzhiyun if (bar_num == IDIAG_BARACC_BAR_0) {
3776*4882a593Smuzhiyun idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3777*4882a593Smuzhiyun LPFC_PCI_IF0_BAR0_SIZE;
3778*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3779*4882a593Smuzhiyun } else if (bar_num == IDIAG_BARACC_BAR_1) {
3780*4882a593Smuzhiyun idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3781*4882a593Smuzhiyun LPFC_PCI_IF0_BAR1_SIZE;
3782*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
3783*4882a593Smuzhiyun } else if (bar_num == IDIAG_BARACC_BAR_2) {
3784*4882a593Smuzhiyun idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3785*4882a593Smuzhiyun LPFC_PCI_IF0_BAR2_SIZE;
3786*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
3787*4882a593Smuzhiyun } else
3788*4882a593Smuzhiyun goto error_out;
3789*4882a593Smuzhiyun } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3790*4882a593Smuzhiyun if (bar_num == IDIAG_BARACC_BAR_0) {
3791*4882a593Smuzhiyun idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3792*4882a593Smuzhiyun LPFC_PCI_IF2_BAR0_SIZE;
3793*4882a593Smuzhiyun mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3794*4882a593Smuzhiyun } else
3795*4882a593Smuzhiyun goto error_out;
3796*4882a593Smuzhiyun } else
3797*4882a593Smuzhiyun goto error_out;
3798*4882a593Smuzhiyun
3799*4882a593Smuzhiyun offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
3800*4882a593Smuzhiyun if (offset % sizeof(uint32_t))
3801*4882a593Smuzhiyun goto error_out;
3802*4882a593Smuzhiyun
3803*4882a593Smuzhiyun bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
3804*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
3805*4882a593Smuzhiyun /* Sanity check on PCI config read command line arguments */
3806*4882a593Smuzhiyun if (rc != LPFC_PCI_BAR_RD_CMD_ARG)
3807*4882a593Smuzhiyun goto error_out;
3808*4882a593Smuzhiyun acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
3809*4882a593Smuzhiyun if (acc_range == LPFC_PCI_BAR_BROWSE) {
3810*4882a593Smuzhiyun if (offset > bar_size - sizeof(uint32_t))
3811*4882a593Smuzhiyun goto error_out;
3812*4882a593Smuzhiyun /* Starting offset to browse */
3813*4882a593Smuzhiyun idiag.offset.last_rd = offset;
3814*4882a593Smuzhiyun } else if (acc_range > SINGLE_WORD) {
3815*4882a593Smuzhiyun if (offset + acc_range * sizeof(uint32_t) > bar_size)
3816*4882a593Smuzhiyun goto error_out;
3817*4882a593Smuzhiyun /* Starting offset to browse */
3818*4882a593Smuzhiyun idiag.offset.last_rd = offset;
3819*4882a593Smuzhiyun } else if (acc_range != SINGLE_WORD)
3820*4882a593Smuzhiyun goto error_out;
3821*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR ||
3822*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST ||
3823*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
3824*4882a593Smuzhiyun /* Sanity check on PCI bar write command line arguments */
3825*4882a593Smuzhiyun if (rc != LPFC_PCI_BAR_WR_CMD_ARG)
3826*4882a593Smuzhiyun goto error_out;
3827*4882a593Smuzhiyun /* Write command to PCI bar space, read-modify-write */
3828*4882a593Smuzhiyun acc_range = SINGLE_WORD;
3829*4882a593Smuzhiyun value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX];
3830*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) {
3831*4882a593Smuzhiyun writel(value, mem_mapped_bar + offset);
3832*4882a593Smuzhiyun readl(mem_mapped_bar + offset);
3833*4882a593Smuzhiyun }
3834*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) {
3835*4882a593Smuzhiyun u32val = readl(mem_mapped_bar + offset);
3836*4882a593Smuzhiyun u32val |= value;
3837*4882a593Smuzhiyun writel(u32val, mem_mapped_bar + offset);
3838*4882a593Smuzhiyun readl(mem_mapped_bar + offset);
3839*4882a593Smuzhiyun }
3840*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
3841*4882a593Smuzhiyun u32val = readl(mem_mapped_bar + offset);
3842*4882a593Smuzhiyun u32val &= ~value;
3843*4882a593Smuzhiyun writel(u32val, mem_mapped_bar + offset);
3844*4882a593Smuzhiyun readl(mem_mapped_bar + offset);
3845*4882a593Smuzhiyun }
3846*4882a593Smuzhiyun } else
3847*4882a593Smuzhiyun /* All other opecodes are illegal for now */
3848*4882a593Smuzhiyun goto error_out;
3849*4882a593Smuzhiyun
3850*4882a593Smuzhiyun return nbytes;
3851*4882a593Smuzhiyun error_out:
3852*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
3853*4882a593Smuzhiyun return -EINVAL;
3854*4882a593Smuzhiyun }
3855*4882a593Smuzhiyun
3856*4882a593Smuzhiyun static int
__lpfc_idiag_print_wq(struct lpfc_queue * qp,char * wqtype,char * pbuffer,int len)3857*4882a593Smuzhiyun __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype,
3858*4882a593Smuzhiyun char *pbuffer, int len)
3859*4882a593Smuzhiyun {
3860*4882a593Smuzhiyun if (!qp)
3861*4882a593Smuzhiyun return len;
3862*4882a593Smuzhiyun
3863*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3864*4882a593Smuzhiyun "\t\t%s WQ info: ", wqtype);
3865*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3866*4882a593Smuzhiyun "AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n",
3867*4882a593Smuzhiyun qp->assoc_qid, qp->q_cnt_1,
3868*4882a593Smuzhiyun (unsigned long long)qp->q_cnt_4);
3869*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3870*4882a593Smuzhiyun "\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
3871*4882a593Smuzhiyun "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]",
3872*4882a593Smuzhiyun qp->queue_id, qp->entry_count,
3873*4882a593Smuzhiyun qp->entry_size, qp->host_index,
3874*4882a593Smuzhiyun qp->hba_index, qp->notify_interval);
3875*4882a593Smuzhiyun len += scnprintf(pbuffer + len,
3876*4882a593Smuzhiyun LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
3877*4882a593Smuzhiyun return len;
3878*4882a593Smuzhiyun }
3879*4882a593Smuzhiyun
3880*4882a593Smuzhiyun static int
lpfc_idiag_wqs_for_cq(struct lpfc_hba * phba,char * wqtype,char * pbuffer,int * len,int max_cnt,int cq_id)3881*4882a593Smuzhiyun lpfc_idiag_wqs_for_cq(struct lpfc_hba *phba, char *wqtype, char *pbuffer,
3882*4882a593Smuzhiyun int *len, int max_cnt, int cq_id)
3883*4882a593Smuzhiyun {
3884*4882a593Smuzhiyun struct lpfc_queue *qp;
3885*4882a593Smuzhiyun int qidx;
3886*4882a593Smuzhiyun
3887*4882a593Smuzhiyun for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
3888*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[qidx].io_wq;
3889*4882a593Smuzhiyun if (qp->assoc_qid != cq_id)
3890*4882a593Smuzhiyun continue;
3891*4882a593Smuzhiyun *len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len);
3892*4882a593Smuzhiyun if (*len >= max_cnt)
3893*4882a593Smuzhiyun return 1;
3894*4882a593Smuzhiyun }
3895*4882a593Smuzhiyun return 0;
3896*4882a593Smuzhiyun }
3897*4882a593Smuzhiyun
3898*4882a593Smuzhiyun static int
__lpfc_idiag_print_cq(struct lpfc_queue * qp,char * cqtype,char * pbuffer,int len)3899*4882a593Smuzhiyun __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype,
3900*4882a593Smuzhiyun char *pbuffer, int len)
3901*4882a593Smuzhiyun {
3902*4882a593Smuzhiyun if (!qp)
3903*4882a593Smuzhiyun return len;
3904*4882a593Smuzhiyun
3905*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3906*4882a593Smuzhiyun "\t%s CQ info: ", cqtype);
3907*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3908*4882a593Smuzhiyun "AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x "
3909*4882a593Smuzhiyun "xabt:x%x wq:x%llx]\n",
3910*4882a593Smuzhiyun qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
3911*4882a593Smuzhiyun qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
3912*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3913*4882a593Smuzhiyun "\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
3914*4882a593Smuzhiyun "HST-IDX[%04d], NTFI[%03d], PLMT[%03d]",
3915*4882a593Smuzhiyun qp->queue_id, qp->entry_count,
3916*4882a593Smuzhiyun qp->entry_size, qp->host_index,
3917*4882a593Smuzhiyun qp->notify_interval, qp->max_proc_limit);
3918*4882a593Smuzhiyun
3919*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3920*4882a593Smuzhiyun "\n");
3921*4882a593Smuzhiyun
3922*4882a593Smuzhiyun return len;
3923*4882a593Smuzhiyun }
3924*4882a593Smuzhiyun
3925*4882a593Smuzhiyun static int
__lpfc_idiag_print_rqpair(struct lpfc_queue * qp,struct lpfc_queue * datqp,char * rqtype,char * pbuffer,int len)3926*4882a593Smuzhiyun __lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp,
3927*4882a593Smuzhiyun char *rqtype, char *pbuffer, int len)
3928*4882a593Smuzhiyun {
3929*4882a593Smuzhiyun if (!qp || !datqp)
3930*4882a593Smuzhiyun return len;
3931*4882a593Smuzhiyun
3932*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3933*4882a593Smuzhiyun "\t\t%s RQ info: ", rqtype);
3934*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3935*4882a593Smuzhiyun "AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x "
3936*4882a593Smuzhiyun "posted:x%x rcv:x%llx]\n",
3937*4882a593Smuzhiyun qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
3938*4882a593Smuzhiyun qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
3939*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3940*4882a593Smuzhiyun "\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
3941*4882a593Smuzhiyun "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
3942*4882a593Smuzhiyun qp->queue_id, qp->entry_count, qp->entry_size,
3943*4882a593Smuzhiyun qp->host_index, qp->hba_index, qp->notify_interval);
3944*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3945*4882a593Smuzhiyun "\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
3946*4882a593Smuzhiyun "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
3947*4882a593Smuzhiyun datqp->queue_id, datqp->entry_count,
3948*4882a593Smuzhiyun datqp->entry_size, datqp->host_index,
3949*4882a593Smuzhiyun datqp->hba_index, datqp->notify_interval);
3950*4882a593Smuzhiyun return len;
3951*4882a593Smuzhiyun }
3952*4882a593Smuzhiyun
3953*4882a593Smuzhiyun static int
lpfc_idiag_cqs_for_eq(struct lpfc_hba * phba,char * pbuffer,int * len,int max_cnt,int eqidx,int eq_id)3954*4882a593Smuzhiyun lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer,
3955*4882a593Smuzhiyun int *len, int max_cnt, int eqidx, int eq_id)
3956*4882a593Smuzhiyun {
3957*4882a593Smuzhiyun struct lpfc_queue *qp;
3958*4882a593Smuzhiyun int rc;
3959*4882a593Smuzhiyun
3960*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[eqidx].io_cq;
3961*4882a593Smuzhiyun
3962*4882a593Smuzhiyun *len = __lpfc_idiag_print_cq(qp, "IO", pbuffer, *len);
3963*4882a593Smuzhiyun
3964*4882a593Smuzhiyun /* Reset max counter */
3965*4882a593Smuzhiyun qp->CQ_max_cqe = 0;
3966*4882a593Smuzhiyun
3967*4882a593Smuzhiyun if (*len >= max_cnt)
3968*4882a593Smuzhiyun return 1;
3969*4882a593Smuzhiyun
3970*4882a593Smuzhiyun rc = lpfc_idiag_wqs_for_cq(phba, "IO", pbuffer, len,
3971*4882a593Smuzhiyun max_cnt, qp->queue_id);
3972*4882a593Smuzhiyun if (rc)
3973*4882a593Smuzhiyun return 1;
3974*4882a593Smuzhiyun
3975*4882a593Smuzhiyun if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) {
3976*4882a593Smuzhiyun /* NVMET CQset */
3977*4882a593Smuzhiyun qp = phba->sli4_hba.nvmet_cqset[eqidx];
3978*4882a593Smuzhiyun *len = __lpfc_idiag_print_cq(qp, "NVMET CQset", pbuffer, *len);
3979*4882a593Smuzhiyun
3980*4882a593Smuzhiyun /* Reset max counter */
3981*4882a593Smuzhiyun qp->CQ_max_cqe = 0;
3982*4882a593Smuzhiyun
3983*4882a593Smuzhiyun if (*len >= max_cnt)
3984*4882a593Smuzhiyun return 1;
3985*4882a593Smuzhiyun
3986*4882a593Smuzhiyun /* RQ header */
3987*4882a593Smuzhiyun qp = phba->sli4_hba.nvmet_mrq_hdr[eqidx];
3988*4882a593Smuzhiyun *len = __lpfc_idiag_print_rqpair(qp,
3989*4882a593Smuzhiyun phba->sli4_hba.nvmet_mrq_data[eqidx],
3990*4882a593Smuzhiyun "NVMET MRQ", pbuffer, *len);
3991*4882a593Smuzhiyun
3992*4882a593Smuzhiyun if (*len >= max_cnt)
3993*4882a593Smuzhiyun return 1;
3994*4882a593Smuzhiyun }
3995*4882a593Smuzhiyun
3996*4882a593Smuzhiyun return 0;
3997*4882a593Smuzhiyun }
3998*4882a593Smuzhiyun
3999*4882a593Smuzhiyun static int
__lpfc_idiag_print_eq(struct lpfc_queue * qp,char * eqtype,char * pbuffer,int len)4000*4882a593Smuzhiyun __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype,
4001*4882a593Smuzhiyun char *pbuffer, int len)
4002*4882a593Smuzhiyun {
4003*4882a593Smuzhiyun if (!qp)
4004*4882a593Smuzhiyun return len;
4005*4882a593Smuzhiyun
4006*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
4007*4882a593Smuzhiyun "\n%s EQ info: EQ-STAT[max:x%x noE:x%x "
4008*4882a593Smuzhiyun "cqe_proc:x%x eqe_proc:x%llx eqd %d]\n",
4009*4882a593Smuzhiyun eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3,
4010*4882a593Smuzhiyun (unsigned long long)qp->q_cnt_4, qp->q_mode);
4011*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
4012*4882a593Smuzhiyun "EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
4013*4882a593Smuzhiyun "HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]",
4014*4882a593Smuzhiyun qp->queue_id, qp->entry_count, qp->entry_size,
4015*4882a593Smuzhiyun qp->host_index, qp->notify_interval,
4016*4882a593Smuzhiyun qp->max_proc_limit, qp->chann);
4017*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
4018*4882a593Smuzhiyun "\n");
4019*4882a593Smuzhiyun
4020*4882a593Smuzhiyun return len;
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun
4023*4882a593Smuzhiyun /**
4024*4882a593Smuzhiyun * lpfc_idiag_queinfo_read - idiag debugfs read queue information
4025*4882a593Smuzhiyun * @file: The file pointer to read from.
4026*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
4027*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
4028*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4029*4882a593Smuzhiyun *
4030*4882a593Smuzhiyun * Description:
4031*4882a593Smuzhiyun * This routine reads data from the @phba SLI4 PCI function queue information,
4032*4882a593Smuzhiyun * and copies to user @buf.
4033*4882a593Smuzhiyun * This routine only returns 1 EQs worth of information. It remembers the last
4034*4882a593Smuzhiyun * EQ read and jumps to the next EQ. Thus subsequent calls to queInfo will
4035*4882a593Smuzhiyun * retrieve all EQs allocated for the phba.
4036*4882a593Smuzhiyun *
4037*4882a593Smuzhiyun * Returns:
4038*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
4039*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
4040*4882a593Smuzhiyun **/
4041*4882a593Smuzhiyun static ssize_t
lpfc_idiag_queinfo_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4042*4882a593Smuzhiyun lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
4043*4882a593Smuzhiyun loff_t *ppos)
4044*4882a593Smuzhiyun {
4045*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4046*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4047*4882a593Smuzhiyun char *pbuffer;
4048*4882a593Smuzhiyun int max_cnt, rc, x, len = 0;
4049*4882a593Smuzhiyun struct lpfc_queue *qp = NULL;
4050*4882a593Smuzhiyun
4051*4882a593Smuzhiyun if (!debug->buffer)
4052*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL);
4053*4882a593Smuzhiyun if (!debug->buffer)
4054*4882a593Smuzhiyun return 0;
4055*4882a593Smuzhiyun pbuffer = debug->buffer;
4056*4882a593Smuzhiyun max_cnt = LPFC_QUE_INFO_GET_BUF_SIZE - 256;
4057*4882a593Smuzhiyun
4058*4882a593Smuzhiyun if (*ppos)
4059*4882a593Smuzhiyun return 0;
4060*4882a593Smuzhiyun
4061*4882a593Smuzhiyun spin_lock_irq(&phba->hbalock);
4062*4882a593Smuzhiyun
4063*4882a593Smuzhiyun /* Fast-path event queue */
4064*4882a593Smuzhiyun if (phba->sli4_hba.hdwq && phba->cfg_hdw_queue) {
4065*4882a593Smuzhiyun
4066*4882a593Smuzhiyun x = phba->lpfc_idiag_last_eq;
4067*4882a593Smuzhiyun phba->lpfc_idiag_last_eq++;
4068*4882a593Smuzhiyun if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue)
4069*4882a593Smuzhiyun phba->lpfc_idiag_last_eq = 0;
4070*4882a593Smuzhiyun
4071*4882a593Smuzhiyun len += scnprintf(pbuffer + len,
4072*4882a593Smuzhiyun LPFC_QUE_INFO_GET_BUF_SIZE - len,
4073*4882a593Smuzhiyun "HDWQ %d out of %d HBA HDWQs\n",
4074*4882a593Smuzhiyun x, phba->cfg_hdw_queue);
4075*4882a593Smuzhiyun
4076*4882a593Smuzhiyun /* Fast-path EQ */
4077*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[x].hba_eq;
4078*4882a593Smuzhiyun if (!qp)
4079*4882a593Smuzhiyun goto out;
4080*4882a593Smuzhiyun
4081*4882a593Smuzhiyun len = __lpfc_idiag_print_eq(qp, "HBA", pbuffer, len);
4082*4882a593Smuzhiyun
4083*4882a593Smuzhiyun /* Reset max counter */
4084*4882a593Smuzhiyun qp->EQ_max_eqe = 0;
4085*4882a593Smuzhiyun
4086*4882a593Smuzhiyun if (len >= max_cnt)
4087*4882a593Smuzhiyun goto too_big;
4088*4882a593Smuzhiyun
4089*4882a593Smuzhiyun /* will dump both fcp and nvme cqs/wqs for the eq */
4090*4882a593Smuzhiyun rc = lpfc_idiag_cqs_for_eq(phba, pbuffer, &len,
4091*4882a593Smuzhiyun max_cnt, x, qp->queue_id);
4092*4882a593Smuzhiyun if (rc)
4093*4882a593Smuzhiyun goto too_big;
4094*4882a593Smuzhiyun
4095*4882a593Smuzhiyun /* Only EQ 0 has slow path CQs configured */
4096*4882a593Smuzhiyun if (x)
4097*4882a593Smuzhiyun goto out;
4098*4882a593Smuzhiyun
4099*4882a593Smuzhiyun /* Slow-path mailbox CQ */
4100*4882a593Smuzhiyun qp = phba->sli4_hba.mbx_cq;
4101*4882a593Smuzhiyun len = __lpfc_idiag_print_cq(qp, "MBX", pbuffer, len);
4102*4882a593Smuzhiyun if (len >= max_cnt)
4103*4882a593Smuzhiyun goto too_big;
4104*4882a593Smuzhiyun
4105*4882a593Smuzhiyun /* Slow-path MBOX MQ */
4106*4882a593Smuzhiyun qp = phba->sli4_hba.mbx_wq;
4107*4882a593Smuzhiyun len = __lpfc_idiag_print_wq(qp, "MBX", pbuffer, len);
4108*4882a593Smuzhiyun if (len >= max_cnt)
4109*4882a593Smuzhiyun goto too_big;
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun /* Slow-path ELS response CQ */
4112*4882a593Smuzhiyun qp = phba->sli4_hba.els_cq;
4113*4882a593Smuzhiyun len = __lpfc_idiag_print_cq(qp, "ELS", pbuffer, len);
4114*4882a593Smuzhiyun /* Reset max counter */
4115*4882a593Smuzhiyun if (qp)
4116*4882a593Smuzhiyun qp->CQ_max_cqe = 0;
4117*4882a593Smuzhiyun if (len >= max_cnt)
4118*4882a593Smuzhiyun goto too_big;
4119*4882a593Smuzhiyun
4120*4882a593Smuzhiyun /* Slow-path ELS WQ */
4121*4882a593Smuzhiyun qp = phba->sli4_hba.els_wq;
4122*4882a593Smuzhiyun len = __lpfc_idiag_print_wq(qp, "ELS", pbuffer, len);
4123*4882a593Smuzhiyun if (len >= max_cnt)
4124*4882a593Smuzhiyun goto too_big;
4125*4882a593Smuzhiyun
4126*4882a593Smuzhiyun qp = phba->sli4_hba.hdr_rq;
4127*4882a593Smuzhiyun len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq,
4128*4882a593Smuzhiyun "ELS RQpair", pbuffer, len);
4129*4882a593Smuzhiyun if (len >= max_cnt)
4130*4882a593Smuzhiyun goto too_big;
4131*4882a593Smuzhiyun
4132*4882a593Smuzhiyun /* Slow-path NVME LS response CQ */
4133*4882a593Smuzhiyun qp = phba->sli4_hba.nvmels_cq;
4134*4882a593Smuzhiyun len = __lpfc_idiag_print_cq(qp, "NVME LS",
4135*4882a593Smuzhiyun pbuffer, len);
4136*4882a593Smuzhiyun /* Reset max counter */
4137*4882a593Smuzhiyun if (qp)
4138*4882a593Smuzhiyun qp->CQ_max_cqe = 0;
4139*4882a593Smuzhiyun if (len >= max_cnt)
4140*4882a593Smuzhiyun goto too_big;
4141*4882a593Smuzhiyun
4142*4882a593Smuzhiyun /* Slow-path NVME LS WQ */
4143*4882a593Smuzhiyun qp = phba->sli4_hba.nvmels_wq;
4144*4882a593Smuzhiyun len = __lpfc_idiag_print_wq(qp, "NVME LS",
4145*4882a593Smuzhiyun pbuffer, len);
4146*4882a593Smuzhiyun if (len >= max_cnt)
4147*4882a593Smuzhiyun goto too_big;
4148*4882a593Smuzhiyun
4149*4882a593Smuzhiyun goto out;
4150*4882a593Smuzhiyun }
4151*4882a593Smuzhiyun
4152*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
4153*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4154*4882a593Smuzhiyun
4155*4882a593Smuzhiyun too_big:
4156*4882a593Smuzhiyun len += scnprintf(pbuffer + len,
4157*4882a593Smuzhiyun LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n");
4158*4882a593Smuzhiyun out:
4159*4882a593Smuzhiyun spin_unlock_irq(&phba->hbalock);
4160*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4161*4882a593Smuzhiyun }
4162*4882a593Smuzhiyun
4163*4882a593Smuzhiyun /**
4164*4882a593Smuzhiyun * lpfc_idiag_que_param_check - queue access command parameter sanity check
4165*4882a593Smuzhiyun * @q: The pointer to queue structure.
4166*4882a593Smuzhiyun * @index: The index into a queue entry.
4167*4882a593Smuzhiyun * @count: The number of queue entries to access.
4168*4882a593Smuzhiyun *
4169*4882a593Smuzhiyun * Description:
4170*4882a593Smuzhiyun * The routine performs sanity check on device queue access method commands.
4171*4882a593Smuzhiyun *
4172*4882a593Smuzhiyun * Returns:
4173*4882a593Smuzhiyun * This function returns -EINVAL when fails the sanity check, otherwise, it
4174*4882a593Smuzhiyun * returns 0.
4175*4882a593Smuzhiyun **/
4176*4882a593Smuzhiyun static int
lpfc_idiag_que_param_check(struct lpfc_queue * q,int index,int count)4177*4882a593Smuzhiyun lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count)
4178*4882a593Smuzhiyun {
4179*4882a593Smuzhiyun /* Only support single entry read or browsing */
4180*4882a593Smuzhiyun if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE))
4181*4882a593Smuzhiyun return -EINVAL;
4182*4882a593Smuzhiyun if (index > q->entry_count - 1)
4183*4882a593Smuzhiyun return -EINVAL;
4184*4882a593Smuzhiyun return 0;
4185*4882a593Smuzhiyun }
4186*4882a593Smuzhiyun
4187*4882a593Smuzhiyun /**
4188*4882a593Smuzhiyun * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index
4189*4882a593Smuzhiyun * @pbuffer: The pointer to buffer to copy the read data into.
4190*4882a593Smuzhiyun * @pque: The pointer to the queue to be read.
4191*4882a593Smuzhiyun * @index: The index into the queue entry.
4192*4882a593Smuzhiyun *
4193*4882a593Smuzhiyun * Description:
4194*4882a593Smuzhiyun * This routine reads out a single entry from the given queue's index location
4195*4882a593Smuzhiyun * and copies it into the buffer provided.
4196*4882a593Smuzhiyun *
4197*4882a593Smuzhiyun * Returns:
4198*4882a593Smuzhiyun * This function returns 0 when it fails, otherwise, it returns the length of
4199*4882a593Smuzhiyun * the data read into the buffer provided.
4200*4882a593Smuzhiyun **/
4201*4882a593Smuzhiyun static int
lpfc_idiag_queacc_read_qe(char * pbuffer,int len,struct lpfc_queue * pque,uint32_t index)4202*4882a593Smuzhiyun lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque,
4203*4882a593Smuzhiyun uint32_t index)
4204*4882a593Smuzhiyun {
4205*4882a593Smuzhiyun int offset, esize;
4206*4882a593Smuzhiyun uint32_t *pentry;
4207*4882a593Smuzhiyun
4208*4882a593Smuzhiyun if (!pbuffer || !pque)
4209*4882a593Smuzhiyun return 0;
4210*4882a593Smuzhiyun
4211*4882a593Smuzhiyun esize = pque->entry_size;
4212*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
4213*4882a593Smuzhiyun "QE-INDEX[%04d]:\n", index);
4214*4882a593Smuzhiyun
4215*4882a593Smuzhiyun offset = 0;
4216*4882a593Smuzhiyun pentry = lpfc_sli4_qe(pque, index);
4217*4882a593Smuzhiyun while (esize > 0) {
4218*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
4219*4882a593Smuzhiyun "%08x ", *pentry);
4220*4882a593Smuzhiyun pentry++;
4221*4882a593Smuzhiyun offset += sizeof(uint32_t);
4222*4882a593Smuzhiyun esize -= sizeof(uint32_t);
4223*4882a593Smuzhiyun if (esize > 0 && !(offset % (4 * sizeof(uint32_t))))
4224*4882a593Smuzhiyun len += scnprintf(pbuffer+len,
4225*4882a593Smuzhiyun LPFC_QUE_ACC_BUF_SIZE-len, "\n");
4226*4882a593Smuzhiyun }
4227*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n");
4228*4882a593Smuzhiyun
4229*4882a593Smuzhiyun return len;
4230*4882a593Smuzhiyun }
4231*4882a593Smuzhiyun
4232*4882a593Smuzhiyun /**
4233*4882a593Smuzhiyun * lpfc_idiag_queacc_read - idiag debugfs read port queue
4234*4882a593Smuzhiyun * @file: The file pointer to read from.
4235*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
4236*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
4237*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4238*4882a593Smuzhiyun *
4239*4882a593Smuzhiyun * Description:
4240*4882a593Smuzhiyun * This routine reads data from the @phba device queue memory according to the
4241*4882a593Smuzhiyun * idiag command, and copies to user @buf. Depending on the queue dump read
4242*4882a593Smuzhiyun * command setup, it does either a single queue entry read or browing through
4243*4882a593Smuzhiyun * all entries of the queue.
4244*4882a593Smuzhiyun *
4245*4882a593Smuzhiyun * Returns:
4246*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
4247*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
4248*4882a593Smuzhiyun **/
4249*4882a593Smuzhiyun static ssize_t
lpfc_idiag_queacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4250*4882a593Smuzhiyun lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,
4251*4882a593Smuzhiyun loff_t *ppos)
4252*4882a593Smuzhiyun {
4253*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4254*4882a593Smuzhiyun uint32_t last_index, index, count;
4255*4882a593Smuzhiyun struct lpfc_queue *pque = NULL;
4256*4882a593Smuzhiyun char *pbuffer;
4257*4882a593Smuzhiyun int len = 0;
4258*4882a593Smuzhiyun
4259*4882a593Smuzhiyun /* This is a user read operation */
4260*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
4261*4882a593Smuzhiyun
4262*4882a593Smuzhiyun if (!debug->buffer)
4263*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL);
4264*4882a593Smuzhiyun if (!debug->buffer)
4265*4882a593Smuzhiyun return 0;
4266*4882a593Smuzhiyun pbuffer = debug->buffer;
4267*4882a593Smuzhiyun
4268*4882a593Smuzhiyun if (*ppos)
4269*4882a593Smuzhiyun return 0;
4270*4882a593Smuzhiyun
4271*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
4272*4882a593Smuzhiyun index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
4273*4882a593Smuzhiyun count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
4274*4882a593Smuzhiyun pque = (struct lpfc_queue *)idiag.ptr_private;
4275*4882a593Smuzhiyun } else
4276*4882a593Smuzhiyun return 0;
4277*4882a593Smuzhiyun
4278*4882a593Smuzhiyun /* Browse the queue starting from index */
4279*4882a593Smuzhiyun if (count == LPFC_QUE_ACC_BROWSE)
4280*4882a593Smuzhiyun goto que_browse;
4281*4882a593Smuzhiyun
4282*4882a593Smuzhiyun /* Read a single entry from the queue */
4283*4882a593Smuzhiyun len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
4284*4882a593Smuzhiyun
4285*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4286*4882a593Smuzhiyun
4287*4882a593Smuzhiyun que_browse:
4288*4882a593Smuzhiyun
4289*4882a593Smuzhiyun /* Browse all entries from the queue */
4290*4882a593Smuzhiyun last_index = idiag.offset.last_rd;
4291*4882a593Smuzhiyun index = last_index;
4292*4882a593Smuzhiyun
4293*4882a593Smuzhiyun while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) {
4294*4882a593Smuzhiyun len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
4295*4882a593Smuzhiyun index++;
4296*4882a593Smuzhiyun if (index > pque->entry_count - 1)
4297*4882a593Smuzhiyun break;
4298*4882a593Smuzhiyun }
4299*4882a593Smuzhiyun
4300*4882a593Smuzhiyun /* Set up the offset for next portion of pci cfg read */
4301*4882a593Smuzhiyun if (index > pque->entry_count - 1)
4302*4882a593Smuzhiyun index = 0;
4303*4882a593Smuzhiyun idiag.offset.last_rd = index;
4304*4882a593Smuzhiyun
4305*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4306*4882a593Smuzhiyun }
4307*4882a593Smuzhiyun
4308*4882a593Smuzhiyun /**
4309*4882a593Smuzhiyun * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands
4310*4882a593Smuzhiyun * @file: The file pointer to read from.
4311*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
4312*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
4313*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4314*4882a593Smuzhiyun *
4315*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and then
4316*4882a593Smuzhiyun * perform the syntax check for port queue read (dump) or write (set) command
4317*4882a593Smuzhiyun * accordingly. In the case of port queue read command, it sets up the command
4318*4882a593Smuzhiyun * in the idiag command struct for the following debugfs read operation. In
4319*4882a593Smuzhiyun * the case of port queue write operation, it executes the write operation
4320*4882a593Smuzhiyun * into the port queue entry accordingly.
4321*4882a593Smuzhiyun *
4322*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
4323*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
4324*4882a593Smuzhiyun * space.
4325*4882a593Smuzhiyun **/
4326*4882a593Smuzhiyun static ssize_t
lpfc_idiag_queacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)4327*4882a593Smuzhiyun lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
4328*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
4329*4882a593Smuzhiyun {
4330*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4331*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4332*4882a593Smuzhiyun uint32_t qidx, quetp, queid, index, count, offset, value;
4333*4882a593Smuzhiyun uint32_t *pentry;
4334*4882a593Smuzhiyun struct lpfc_queue *pque, *qp;
4335*4882a593Smuzhiyun int rc;
4336*4882a593Smuzhiyun
4337*4882a593Smuzhiyun /* This is a user write operation */
4338*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
4339*4882a593Smuzhiyun
4340*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
4341*4882a593Smuzhiyun if (rc < 0)
4342*4882a593Smuzhiyun return rc;
4343*4882a593Smuzhiyun
4344*4882a593Smuzhiyun /* Get and sanity check on command feilds */
4345*4882a593Smuzhiyun quetp = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX];
4346*4882a593Smuzhiyun queid = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX];
4347*4882a593Smuzhiyun index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
4348*4882a593Smuzhiyun count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
4349*4882a593Smuzhiyun offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX];
4350*4882a593Smuzhiyun value = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];
4351*4882a593Smuzhiyun
4352*4882a593Smuzhiyun /* Sanity check on command line arguments */
4353*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
4354*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
4355*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
4356*4882a593Smuzhiyun if (rc != LPFC_QUE_ACC_WR_CMD_ARG)
4357*4882a593Smuzhiyun goto error_out;
4358*4882a593Smuzhiyun if (count != 1)
4359*4882a593Smuzhiyun goto error_out;
4360*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
4361*4882a593Smuzhiyun if (rc != LPFC_QUE_ACC_RD_CMD_ARG)
4362*4882a593Smuzhiyun goto error_out;
4363*4882a593Smuzhiyun } else
4364*4882a593Smuzhiyun goto error_out;
4365*4882a593Smuzhiyun
4366*4882a593Smuzhiyun switch (quetp) {
4367*4882a593Smuzhiyun case LPFC_IDIAG_EQ:
4368*4882a593Smuzhiyun /* HBA event queue */
4369*4882a593Smuzhiyun if (phba->sli4_hba.hdwq) {
4370*4882a593Smuzhiyun for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
4371*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[qidx].hba_eq;
4372*4882a593Smuzhiyun if (qp && qp->queue_id == queid) {
4373*4882a593Smuzhiyun /* Sanity check */
4374*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(qp,
4375*4882a593Smuzhiyun index, count);
4376*4882a593Smuzhiyun if (rc)
4377*4882a593Smuzhiyun goto error_out;
4378*4882a593Smuzhiyun idiag.ptr_private = qp;
4379*4882a593Smuzhiyun goto pass_check;
4380*4882a593Smuzhiyun }
4381*4882a593Smuzhiyun }
4382*4882a593Smuzhiyun }
4383*4882a593Smuzhiyun goto error_out;
4384*4882a593Smuzhiyun break;
4385*4882a593Smuzhiyun case LPFC_IDIAG_CQ:
4386*4882a593Smuzhiyun /* MBX complete queue */
4387*4882a593Smuzhiyun if (phba->sli4_hba.mbx_cq &&
4388*4882a593Smuzhiyun phba->sli4_hba.mbx_cq->queue_id == queid) {
4389*4882a593Smuzhiyun /* Sanity check */
4390*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4391*4882a593Smuzhiyun phba->sli4_hba.mbx_cq, index, count);
4392*4882a593Smuzhiyun if (rc)
4393*4882a593Smuzhiyun goto error_out;
4394*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.mbx_cq;
4395*4882a593Smuzhiyun goto pass_check;
4396*4882a593Smuzhiyun }
4397*4882a593Smuzhiyun /* ELS complete queue */
4398*4882a593Smuzhiyun if (phba->sli4_hba.els_cq &&
4399*4882a593Smuzhiyun phba->sli4_hba.els_cq->queue_id == queid) {
4400*4882a593Smuzhiyun /* Sanity check */
4401*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4402*4882a593Smuzhiyun phba->sli4_hba.els_cq, index, count);
4403*4882a593Smuzhiyun if (rc)
4404*4882a593Smuzhiyun goto error_out;
4405*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.els_cq;
4406*4882a593Smuzhiyun goto pass_check;
4407*4882a593Smuzhiyun }
4408*4882a593Smuzhiyun /* NVME LS complete queue */
4409*4882a593Smuzhiyun if (phba->sli4_hba.nvmels_cq &&
4410*4882a593Smuzhiyun phba->sli4_hba.nvmels_cq->queue_id == queid) {
4411*4882a593Smuzhiyun /* Sanity check */
4412*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4413*4882a593Smuzhiyun phba->sli4_hba.nvmels_cq, index, count);
4414*4882a593Smuzhiyun if (rc)
4415*4882a593Smuzhiyun goto error_out;
4416*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.nvmels_cq;
4417*4882a593Smuzhiyun goto pass_check;
4418*4882a593Smuzhiyun }
4419*4882a593Smuzhiyun /* FCP complete queue */
4420*4882a593Smuzhiyun if (phba->sli4_hba.hdwq) {
4421*4882a593Smuzhiyun for (qidx = 0; qidx < phba->cfg_hdw_queue;
4422*4882a593Smuzhiyun qidx++) {
4423*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[qidx].io_cq;
4424*4882a593Smuzhiyun if (qp && qp->queue_id == queid) {
4425*4882a593Smuzhiyun /* Sanity check */
4426*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4427*4882a593Smuzhiyun qp, index, count);
4428*4882a593Smuzhiyun if (rc)
4429*4882a593Smuzhiyun goto error_out;
4430*4882a593Smuzhiyun idiag.ptr_private = qp;
4431*4882a593Smuzhiyun goto pass_check;
4432*4882a593Smuzhiyun }
4433*4882a593Smuzhiyun }
4434*4882a593Smuzhiyun }
4435*4882a593Smuzhiyun goto error_out;
4436*4882a593Smuzhiyun break;
4437*4882a593Smuzhiyun case LPFC_IDIAG_MQ:
4438*4882a593Smuzhiyun /* MBX work queue */
4439*4882a593Smuzhiyun if (phba->sli4_hba.mbx_wq &&
4440*4882a593Smuzhiyun phba->sli4_hba.mbx_wq->queue_id == queid) {
4441*4882a593Smuzhiyun /* Sanity check */
4442*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4443*4882a593Smuzhiyun phba->sli4_hba.mbx_wq, index, count);
4444*4882a593Smuzhiyun if (rc)
4445*4882a593Smuzhiyun goto error_out;
4446*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.mbx_wq;
4447*4882a593Smuzhiyun goto pass_check;
4448*4882a593Smuzhiyun }
4449*4882a593Smuzhiyun goto error_out;
4450*4882a593Smuzhiyun break;
4451*4882a593Smuzhiyun case LPFC_IDIAG_WQ:
4452*4882a593Smuzhiyun /* ELS work queue */
4453*4882a593Smuzhiyun if (phba->sli4_hba.els_wq &&
4454*4882a593Smuzhiyun phba->sli4_hba.els_wq->queue_id == queid) {
4455*4882a593Smuzhiyun /* Sanity check */
4456*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4457*4882a593Smuzhiyun phba->sli4_hba.els_wq, index, count);
4458*4882a593Smuzhiyun if (rc)
4459*4882a593Smuzhiyun goto error_out;
4460*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.els_wq;
4461*4882a593Smuzhiyun goto pass_check;
4462*4882a593Smuzhiyun }
4463*4882a593Smuzhiyun /* NVME LS work queue */
4464*4882a593Smuzhiyun if (phba->sli4_hba.nvmels_wq &&
4465*4882a593Smuzhiyun phba->sli4_hba.nvmels_wq->queue_id == queid) {
4466*4882a593Smuzhiyun /* Sanity check */
4467*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4468*4882a593Smuzhiyun phba->sli4_hba.nvmels_wq, index, count);
4469*4882a593Smuzhiyun if (rc)
4470*4882a593Smuzhiyun goto error_out;
4471*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.nvmels_wq;
4472*4882a593Smuzhiyun goto pass_check;
4473*4882a593Smuzhiyun }
4474*4882a593Smuzhiyun
4475*4882a593Smuzhiyun if (phba->sli4_hba.hdwq) {
4476*4882a593Smuzhiyun /* FCP/SCSI work queue */
4477*4882a593Smuzhiyun for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
4478*4882a593Smuzhiyun qp = phba->sli4_hba.hdwq[qidx].io_wq;
4479*4882a593Smuzhiyun if (qp && qp->queue_id == queid) {
4480*4882a593Smuzhiyun /* Sanity check */
4481*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4482*4882a593Smuzhiyun qp, index, count);
4483*4882a593Smuzhiyun if (rc)
4484*4882a593Smuzhiyun goto error_out;
4485*4882a593Smuzhiyun idiag.ptr_private = qp;
4486*4882a593Smuzhiyun goto pass_check;
4487*4882a593Smuzhiyun }
4488*4882a593Smuzhiyun }
4489*4882a593Smuzhiyun }
4490*4882a593Smuzhiyun
4491*4882a593Smuzhiyun goto error_out;
4492*4882a593Smuzhiyun break;
4493*4882a593Smuzhiyun case LPFC_IDIAG_RQ:
4494*4882a593Smuzhiyun /* HDR queue */
4495*4882a593Smuzhiyun if (phba->sli4_hba.hdr_rq &&
4496*4882a593Smuzhiyun phba->sli4_hba.hdr_rq->queue_id == queid) {
4497*4882a593Smuzhiyun /* Sanity check */
4498*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4499*4882a593Smuzhiyun phba->sli4_hba.hdr_rq, index, count);
4500*4882a593Smuzhiyun if (rc)
4501*4882a593Smuzhiyun goto error_out;
4502*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.hdr_rq;
4503*4882a593Smuzhiyun goto pass_check;
4504*4882a593Smuzhiyun }
4505*4882a593Smuzhiyun /* DAT queue */
4506*4882a593Smuzhiyun if (phba->sli4_hba.dat_rq &&
4507*4882a593Smuzhiyun phba->sli4_hba.dat_rq->queue_id == queid) {
4508*4882a593Smuzhiyun /* Sanity check */
4509*4882a593Smuzhiyun rc = lpfc_idiag_que_param_check(
4510*4882a593Smuzhiyun phba->sli4_hba.dat_rq, index, count);
4511*4882a593Smuzhiyun if (rc)
4512*4882a593Smuzhiyun goto error_out;
4513*4882a593Smuzhiyun idiag.ptr_private = phba->sli4_hba.dat_rq;
4514*4882a593Smuzhiyun goto pass_check;
4515*4882a593Smuzhiyun }
4516*4882a593Smuzhiyun goto error_out;
4517*4882a593Smuzhiyun break;
4518*4882a593Smuzhiyun default:
4519*4882a593Smuzhiyun goto error_out;
4520*4882a593Smuzhiyun break;
4521*4882a593Smuzhiyun }
4522*4882a593Smuzhiyun
4523*4882a593Smuzhiyun pass_check:
4524*4882a593Smuzhiyun
4525*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
4526*4882a593Smuzhiyun if (count == LPFC_QUE_ACC_BROWSE)
4527*4882a593Smuzhiyun idiag.offset.last_rd = index;
4528*4882a593Smuzhiyun }
4529*4882a593Smuzhiyun
4530*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
4531*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
4532*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
4533*4882a593Smuzhiyun /* Additional sanity checks on write operation */
4534*4882a593Smuzhiyun pque = (struct lpfc_queue *)idiag.ptr_private;
4535*4882a593Smuzhiyun if (offset > pque->entry_size/sizeof(uint32_t) - 1)
4536*4882a593Smuzhiyun goto error_out;
4537*4882a593Smuzhiyun pentry = lpfc_sli4_qe(pque, index);
4538*4882a593Smuzhiyun pentry += offset;
4539*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR)
4540*4882a593Smuzhiyun *pentry = value;
4541*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST)
4542*4882a593Smuzhiyun *pentry |= value;
4543*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL)
4544*4882a593Smuzhiyun *pentry &= ~value;
4545*4882a593Smuzhiyun }
4546*4882a593Smuzhiyun return nbytes;
4547*4882a593Smuzhiyun
4548*4882a593Smuzhiyun error_out:
4549*4882a593Smuzhiyun /* Clean out command structure on command error out */
4550*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
4551*4882a593Smuzhiyun return -EINVAL;
4552*4882a593Smuzhiyun }
4553*4882a593Smuzhiyun
4554*4882a593Smuzhiyun /**
4555*4882a593Smuzhiyun * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register
4556*4882a593Smuzhiyun * @phba: The pointer to hba structure.
4557*4882a593Smuzhiyun * @pbuffer: The pointer to the buffer to copy the data to.
4558*4882a593Smuzhiyun * @len: The length of bytes to copied.
4559*4882a593Smuzhiyun * @drbregid: The id to doorbell registers.
4560*4882a593Smuzhiyun *
4561*4882a593Smuzhiyun * Description:
4562*4882a593Smuzhiyun * This routine reads a doorbell register and copies its content to the
4563*4882a593Smuzhiyun * user buffer pointed to by @pbuffer.
4564*4882a593Smuzhiyun *
4565*4882a593Smuzhiyun * Returns:
4566*4882a593Smuzhiyun * This function returns the amount of data that was copied into @pbuffer.
4567*4882a593Smuzhiyun **/
4568*4882a593Smuzhiyun static int
lpfc_idiag_drbacc_read_reg(struct lpfc_hba * phba,char * pbuffer,int len,uint32_t drbregid)4569*4882a593Smuzhiyun lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
4570*4882a593Smuzhiyun int len, uint32_t drbregid)
4571*4882a593Smuzhiyun {
4572*4882a593Smuzhiyun
4573*4882a593Smuzhiyun if (!pbuffer)
4574*4882a593Smuzhiyun return 0;
4575*4882a593Smuzhiyun
4576*4882a593Smuzhiyun switch (drbregid) {
4577*4882a593Smuzhiyun case LPFC_DRB_EQ:
4578*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
4579*4882a593Smuzhiyun "EQ-DRB-REG: 0x%08x\n",
4580*4882a593Smuzhiyun readl(phba->sli4_hba.EQDBregaddr));
4581*4882a593Smuzhiyun break;
4582*4882a593Smuzhiyun case LPFC_DRB_CQ:
4583*4882a593Smuzhiyun len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
4584*4882a593Smuzhiyun "CQ-DRB-REG: 0x%08x\n",
4585*4882a593Smuzhiyun readl(phba->sli4_hba.CQDBregaddr));
4586*4882a593Smuzhiyun break;
4587*4882a593Smuzhiyun case LPFC_DRB_MQ:
4588*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
4589*4882a593Smuzhiyun "MQ-DRB-REG: 0x%08x\n",
4590*4882a593Smuzhiyun readl(phba->sli4_hba.MQDBregaddr));
4591*4882a593Smuzhiyun break;
4592*4882a593Smuzhiyun case LPFC_DRB_WQ:
4593*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
4594*4882a593Smuzhiyun "WQ-DRB-REG: 0x%08x\n",
4595*4882a593Smuzhiyun readl(phba->sli4_hba.WQDBregaddr));
4596*4882a593Smuzhiyun break;
4597*4882a593Smuzhiyun case LPFC_DRB_RQ:
4598*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
4599*4882a593Smuzhiyun "RQ-DRB-REG: 0x%08x\n",
4600*4882a593Smuzhiyun readl(phba->sli4_hba.RQDBregaddr));
4601*4882a593Smuzhiyun break;
4602*4882a593Smuzhiyun default:
4603*4882a593Smuzhiyun break;
4604*4882a593Smuzhiyun }
4605*4882a593Smuzhiyun
4606*4882a593Smuzhiyun return len;
4607*4882a593Smuzhiyun }
4608*4882a593Smuzhiyun
4609*4882a593Smuzhiyun /**
4610*4882a593Smuzhiyun * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell
4611*4882a593Smuzhiyun * @file: The file pointer to read from.
4612*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
4613*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
4614*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4615*4882a593Smuzhiyun *
4616*4882a593Smuzhiyun * Description:
4617*4882a593Smuzhiyun * This routine reads data from the @phba device doorbell register according
4618*4882a593Smuzhiyun * to the idiag command, and copies to user @buf. Depending on the doorbell
4619*4882a593Smuzhiyun * register read command setup, it does either a single doorbell register
4620*4882a593Smuzhiyun * read or dump all doorbell registers.
4621*4882a593Smuzhiyun *
4622*4882a593Smuzhiyun * Returns:
4623*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
4624*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
4625*4882a593Smuzhiyun **/
4626*4882a593Smuzhiyun static ssize_t
lpfc_idiag_drbacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4627*4882a593Smuzhiyun lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,
4628*4882a593Smuzhiyun loff_t *ppos)
4629*4882a593Smuzhiyun {
4630*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4631*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4632*4882a593Smuzhiyun uint32_t drb_reg_id, i;
4633*4882a593Smuzhiyun char *pbuffer;
4634*4882a593Smuzhiyun int len = 0;
4635*4882a593Smuzhiyun
4636*4882a593Smuzhiyun /* This is a user read operation */
4637*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
4638*4882a593Smuzhiyun
4639*4882a593Smuzhiyun if (!debug->buffer)
4640*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL);
4641*4882a593Smuzhiyun if (!debug->buffer)
4642*4882a593Smuzhiyun return 0;
4643*4882a593Smuzhiyun pbuffer = debug->buffer;
4644*4882a593Smuzhiyun
4645*4882a593Smuzhiyun if (*ppos)
4646*4882a593Smuzhiyun return 0;
4647*4882a593Smuzhiyun
4648*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD)
4649*4882a593Smuzhiyun drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
4650*4882a593Smuzhiyun else
4651*4882a593Smuzhiyun return 0;
4652*4882a593Smuzhiyun
4653*4882a593Smuzhiyun if (drb_reg_id == LPFC_DRB_ACC_ALL)
4654*4882a593Smuzhiyun for (i = 1; i <= LPFC_DRB_MAX; i++)
4655*4882a593Smuzhiyun len = lpfc_idiag_drbacc_read_reg(phba,
4656*4882a593Smuzhiyun pbuffer, len, i);
4657*4882a593Smuzhiyun else
4658*4882a593Smuzhiyun len = lpfc_idiag_drbacc_read_reg(phba,
4659*4882a593Smuzhiyun pbuffer, len, drb_reg_id);
4660*4882a593Smuzhiyun
4661*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4662*4882a593Smuzhiyun }
4663*4882a593Smuzhiyun
4664*4882a593Smuzhiyun /**
4665*4882a593Smuzhiyun * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands
4666*4882a593Smuzhiyun * @file: The file pointer to read from.
4667*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
4668*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
4669*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4670*4882a593Smuzhiyun *
4671*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and then
4672*4882a593Smuzhiyun * perform the syntax check for port doorbell register read (dump) or write
4673*4882a593Smuzhiyun * (set) command accordingly. In the case of port queue read command, it sets
4674*4882a593Smuzhiyun * up the command in the idiag command struct for the following debugfs read
4675*4882a593Smuzhiyun * operation. In the case of port doorbell register write operation, it
4676*4882a593Smuzhiyun * executes the write operation into the port doorbell register accordingly.
4677*4882a593Smuzhiyun *
4678*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
4679*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
4680*4882a593Smuzhiyun * space.
4681*4882a593Smuzhiyun **/
4682*4882a593Smuzhiyun static ssize_t
lpfc_idiag_drbacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)4683*4882a593Smuzhiyun lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
4684*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
4685*4882a593Smuzhiyun {
4686*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4687*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4688*4882a593Smuzhiyun uint32_t drb_reg_id, value, reg_val = 0;
4689*4882a593Smuzhiyun void __iomem *drb_reg;
4690*4882a593Smuzhiyun int rc;
4691*4882a593Smuzhiyun
4692*4882a593Smuzhiyun /* This is a user write operation */
4693*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
4694*4882a593Smuzhiyun
4695*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
4696*4882a593Smuzhiyun if (rc < 0)
4697*4882a593Smuzhiyun return rc;
4698*4882a593Smuzhiyun
4699*4882a593Smuzhiyun /* Sanity check on command line arguments */
4700*4882a593Smuzhiyun drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
4701*4882a593Smuzhiyun value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];
4702*4882a593Smuzhiyun
4703*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
4704*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
4705*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
4706*4882a593Smuzhiyun if (rc != LPFC_DRB_ACC_WR_CMD_ARG)
4707*4882a593Smuzhiyun goto error_out;
4708*4882a593Smuzhiyun if (drb_reg_id > LPFC_DRB_MAX)
4709*4882a593Smuzhiyun goto error_out;
4710*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) {
4711*4882a593Smuzhiyun if (rc != LPFC_DRB_ACC_RD_CMD_ARG)
4712*4882a593Smuzhiyun goto error_out;
4713*4882a593Smuzhiyun if ((drb_reg_id > LPFC_DRB_MAX) &&
4714*4882a593Smuzhiyun (drb_reg_id != LPFC_DRB_ACC_ALL))
4715*4882a593Smuzhiyun goto error_out;
4716*4882a593Smuzhiyun } else
4717*4882a593Smuzhiyun goto error_out;
4718*4882a593Smuzhiyun
4719*4882a593Smuzhiyun /* Perform the write access operation */
4720*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
4721*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
4722*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
4723*4882a593Smuzhiyun switch (drb_reg_id) {
4724*4882a593Smuzhiyun case LPFC_DRB_EQ:
4725*4882a593Smuzhiyun drb_reg = phba->sli4_hba.EQDBregaddr;
4726*4882a593Smuzhiyun break;
4727*4882a593Smuzhiyun case LPFC_DRB_CQ:
4728*4882a593Smuzhiyun drb_reg = phba->sli4_hba.CQDBregaddr;
4729*4882a593Smuzhiyun break;
4730*4882a593Smuzhiyun case LPFC_DRB_MQ:
4731*4882a593Smuzhiyun drb_reg = phba->sli4_hba.MQDBregaddr;
4732*4882a593Smuzhiyun break;
4733*4882a593Smuzhiyun case LPFC_DRB_WQ:
4734*4882a593Smuzhiyun drb_reg = phba->sli4_hba.WQDBregaddr;
4735*4882a593Smuzhiyun break;
4736*4882a593Smuzhiyun case LPFC_DRB_RQ:
4737*4882a593Smuzhiyun drb_reg = phba->sli4_hba.RQDBregaddr;
4738*4882a593Smuzhiyun break;
4739*4882a593Smuzhiyun default:
4740*4882a593Smuzhiyun goto error_out;
4741*4882a593Smuzhiyun }
4742*4882a593Smuzhiyun
4743*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR)
4744*4882a593Smuzhiyun reg_val = value;
4745*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) {
4746*4882a593Smuzhiyun reg_val = readl(drb_reg);
4747*4882a593Smuzhiyun reg_val |= value;
4748*4882a593Smuzhiyun }
4749*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
4750*4882a593Smuzhiyun reg_val = readl(drb_reg);
4751*4882a593Smuzhiyun reg_val &= ~value;
4752*4882a593Smuzhiyun }
4753*4882a593Smuzhiyun writel(reg_val, drb_reg);
4754*4882a593Smuzhiyun readl(drb_reg); /* flush */
4755*4882a593Smuzhiyun }
4756*4882a593Smuzhiyun return nbytes;
4757*4882a593Smuzhiyun
4758*4882a593Smuzhiyun error_out:
4759*4882a593Smuzhiyun /* Clean out command structure on command error out */
4760*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
4761*4882a593Smuzhiyun return -EINVAL;
4762*4882a593Smuzhiyun }
4763*4882a593Smuzhiyun
4764*4882a593Smuzhiyun /**
4765*4882a593Smuzhiyun * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
4766*4882a593Smuzhiyun * @phba: The pointer to hba structure.
4767*4882a593Smuzhiyun * @pbuffer: The pointer to the buffer to copy the data to.
4768*4882a593Smuzhiyun * @len: The length of bytes to copied.
4769*4882a593Smuzhiyun * @drbregid: The id to doorbell registers.
4770*4882a593Smuzhiyun *
4771*4882a593Smuzhiyun * Description:
4772*4882a593Smuzhiyun * This routine reads a control register and copies its content to the
4773*4882a593Smuzhiyun * user buffer pointed to by @pbuffer.
4774*4882a593Smuzhiyun *
4775*4882a593Smuzhiyun * Returns:
4776*4882a593Smuzhiyun * This function returns the amount of data that was copied into @pbuffer.
4777*4882a593Smuzhiyun **/
4778*4882a593Smuzhiyun static int
lpfc_idiag_ctlacc_read_reg(struct lpfc_hba * phba,char * pbuffer,int len,uint32_t ctlregid)4779*4882a593Smuzhiyun lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
4780*4882a593Smuzhiyun int len, uint32_t ctlregid)
4781*4882a593Smuzhiyun {
4782*4882a593Smuzhiyun
4783*4882a593Smuzhiyun if (!pbuffer)
4784*4882a593Smuzhiyun return 0;
4785*4882a593Smuzhiyun
4786*4882a593Smuzhiyun switch (ctlregid) {
4787*4882a593Smuzhiyun case LPFC_CTL_PORT_SEM:
4788*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4789*4882a593Smuzhiyun "Port SemReg: 0x%08x\n",
4790*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4791*4882a593Smuzhiyun LPFC_CTL_PORT_SEM_OFFSET));
4792*4882a593Smuzhiyun break;
4793*4882a593Smuzhiyun case LPFC_CTL_PORT_STA:
4794*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4795*4882a593Smuzhiyun "Port StaReg: 0x%08x\n",
4796*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4797*4882a593Smuzhiyun LPFC_CTL_PORT_STA_OFFSET));
4798*4882a593Smuzhiyun break;
4799*4882a593Smuzhiyun case LPFC_CTL_PORT_CTL:
4800*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4801*4882a593Smuzhiyun "Port CtlReg: 0x%08x\n",
4802*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4803*4882a593Smuzhiyun LPFC_CTL_PORT_CTL_OFFSET));
4804*4882a593Smuzhiyun break;
4805*4882a593Smuzhiyun case LPFC_CTL_PORT_ER1:
4806*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4807*4882a593Smuzhiyun "Port Er1Reg: 0x%08x\n",
4808*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4809*4882a593Smuzhiyun LPFC_CTL_PORT_ER1_OFFSET));
4810*4882a593Smuzhiyun break;
4811*4882a593Smuzhiyun case LPFC_CTL_PORT_ER2:
4812*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4813*4882a593Smuzhiyun "Port Er2Reg: 0x%08x\n",
4814*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4815*4882a593Smuzhiyun LPFC_CTL_PORT_ER2_OFFSET));
4816*4882a593Smuzhiyun break;
4817*4882a593Smuzhiyun case LPFC_CTL_PDEV_CTL:
4818*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4819*4882a593Smuzhiyun "PDev CtlReg: 0x%08x\n",
4820*4882a593Smuzhiyun readl(phba->sli4_hba.conf_regs_memmap_p +
4821*4882a593Smuzhiyun LPFC_CTL_PDEV_CTL_OFFSET));
4822*4882a593Smuzhiyun break;
4823*4882a593Smuzhiyun default:
4824*4882a593Smuzhiyun break;
4825*4882a593Smuzhiyun }
4826*4882a593Smuzhiyun return len;
4827*4882a593Smuzhiyun }
4828*4882a593Smuzhiyun
4829*4882a593Smuzhiyun /**
4830*4882a593Smuzhiyun * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register
4831*4882a593Smuzhiyun * @file: The file pointer to read from.
4832*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
4833*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
4834*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4835*4882a593Smuzhiyun *
4836*4882a593Smuzhiyun * Description:
4837*4882a593Smuzhiyun * This routine reads data from the @phba port and device registers according
4838*4882a593Smuzhiyun * to the idiag command, and copies to user @buf.
4839*4882a593Smuzhiyun *
4840*4882a593Smuzhiyun * Returns:
4841*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
4842*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
4843*4882a593Smuzhiyun **/
4844*4882a593Smuzhiyun static ssize_t
lpfc_idiag_ctlacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4845*4882a593Smuzhiyun lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes,
4846*4882a593Smuzhiyun loff_t *ppos)
4847*4882a593Smuzhiyun {
4848*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4849*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4850*4882a593Smuzhiyun uint32_t ctl_reg_id, i;
4851*4882a593Smuzhiyun char *pbuffer;
4852*4882a593Smuzhiyun int len = 0;
4853*4882a593Smuzhiyun
4854*4882a593Smuzhiyun /* This is a user read operation */
4855*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
4856*4882a593Smuzhiyun
4857*4882a593Smuzhiyun if (!debug->buffer)
4858*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL);
4859*4882a593Smuzhiyun if (!debug->buffer)
4860*4882a593Smuzhiyun return 0;
4861*4882a593Smuzhiyun pbuffer = debug->buffer;
4862*4882a593Smuzhiyun
4863*4882a593Smuzhiyun if (*ppos)
4864*4882a593Smuzhiyun return 0;
4865*4882a593Smuzhiyun
4866*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD)
4867*4882a593Smuzhiyun ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
4868*4882a593Smuzhiyun else
4869*4882a593Smuzhiyun return 0;
4870*4882a593Smuzhiyun
4871*4882a593Smuzhiyun if (ctl_reg_id == LPFC_CTL_ACC_ALL)
4872*4882a593Smuzhiyun for (i = 1; i <= LPFC_CTL_MAX; i++)
4873*4882a593Smuzhiyun len = lpfc_idiag_ctlacc_read_reg(phba,
4874*4882a593Smuzhiyun pbuffer, len, i);
4875*4882a593Smuzhiyun else
4876*4882a593Smuzhiyun len = lpfc_idiag_ctlacc_read_reg(phba,
4877*4882a593Smuzhiyun pbuffer, len, ctl_reg_id);
4878*4882a593Smuzhiyun
4879*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4880*4882a593Smuzhiyun }
4881*4882a593Smuzhiyun
4882*4882a593Smuzhiyun /**
4883*4882a593Smuzhiyun * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands
4884*4882a593Smuzhiyun * @file: The file pointer to read from.
4885*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
4886*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
4887*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
4888*4882a593Smuzhiyun *
4889*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and then
4890*4882a593Smuzhiyun * perform the syntax check for port and device control register read (dump)
4891*4882a593Smuzhiyun * or write (set) command accordingly.
4892*4882a593Smuzhiyun *
4893*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
4894*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
4895*4882a593Smuzhiyun * space.
4896*4882a593Smuzhiyun **/
4897*4882a593Smuzhiyun static ssize_t
lpfc_idiag_ctlacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)4898*4882a593Smuzhiyun lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf,
4899*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
4900*4882a593Smuzhiyun {
4901*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
4902*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4903*4882a593Smuzhiyun uint32_t ctl_reg_id, value, reg_val = 0;
4904*4882a593Smuzhiyun void __iomem *ctl_reg;
4905*4882a593Smuzhiyun int rc;
4906*4882a593Smuzhiyun
4907*4882a593Smuzhiyun /* This is a user write operation */
4908*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
4909*4882a593Smuzhiyun
4910*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
4911*4882a593Smuzhiyun if (rc < 0)
4912*4882a593Smuzhiyun return rc;
4913*4882a593Smuzhiyun
4914*4882a593Smuzhiyun /* Sanity check on command line arguments */
4915*4882a593Smuzhiyun ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
4916*4882a593Smuzhiyun value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX];
4917*4882a593Smuzhiyun
4918*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
4919*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
4920*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4921*4882a593Smuzhiyun if (rc != LPFC_CTL_ACC_WR_CMD_ARG)
4922*4882a593Smuzhiyun goto error_out;
4923*4882a593Smuzhiyun if (ctl_reg_id > LPFC_CTL_MAX)
4924*4882a593Smuzhiyun goto error_out;
4925*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) {
4926*4882a593Smuzhiyun if (rc != LPFC_CTL_ACC_RD_CMD_ARG)
4927*4882a593Smuzhiyun goto error_out;
4928*4882a593Smuzhiyun if ((ctl_reg_id > LPFC_CTL_MAX) &&
4929*4882a593Smuzhiyun (ctl_reg_id != LPFC_CTL_ACC_ALL))
4930*4882a593Smuzhiyun goto error_out;
4931*4882a593Smuzhiyun } else
4932*4882a593Smuzhiyun goto error_out;
4933*4882a593Smuzhiyun
4934*4882a593Smuzhiyun /* Perform the write access operation */
4935*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
4936*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
4937*4882a593Smuzhiyun idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4938*4882a593Smuzhiyun switch (ctl_reg_id) {
4939*4882a593Smuzhiyun case LPFC_CTL_PORT_SEM:
4940*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4941*4882a593Smuzhiyun LPFC_CTL_PORT_SEM_OFFSET;
4942*4882a593Smuzhiyun break;
4943*4882a593Smuzhiyun case LPFC_CTL_PORT_STA:
4944*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4945*4882a593Smuzhiyun LPFC_CTL_PORT_STA_OFFSET;
4946*4882a593Smuzhiyun break;
4947*4882a593Smuzhiyun case LPFC_CTL_PORT_CTL:
4948*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4949*4882a593Smuzhiyun LPFC_CTL_PORT_CTL_OFFSET;
4950*4882a593Smuzhiyun break;
4951*4882a593Smuzhiyun case LPFC_CTL_PORT_ER1:
4952*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4953*4882a593Smuzhiyun LPFC_CTL_PORT_ER1_OFFSET;
4954*4882a593Smuzhiyun break;
4955*4882a593Smuzhiyun case LPFC_CTL_PORT_ER2:
4956*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4957*4882a593Smuzhiyun LPFC_CTL_PORT_ER2_OFFSET;
4958*4882a593Smuzhiyun break;
4959*4882a593Smuzhiyun case LPFC_CTL_PDEV_CTL:
4960*4882a593Smuzhiyun ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4961*4882a593Smuzhiyun LPFC_CTL_PDEV_CTL_OFFSET;
4962*4882a593Smuzhiyun break;
4963*4882a593Smuzhiyun default:
4964*4882a593Smuzhiyun goto error_out;
4965*4882a593Smuzhiyun }
4966*4882a593Smuzhiyun
4967*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR)
4968*4882a593Smuzhiyun reg_val = value;
4969*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) {
4970*4882a593Smuzhiyun reg_val = readl(ctl_reg);
4971*4882a593Smuzhiyun reg_val |= value;
4972*4882a593Smuzhiyun }
4973*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4974*4882a593Smuzhiyun reg_val = readl(ctl_reg);
4975*4882a593Smuzhiyun reg_val &= ~value;
4976*4882a593Smuzhiyun }
4977*4882a593Smuzhiyun writel(reg_val, ctl_reg);
4978*4882a593Smuzhiyun readl(ctl_reg); /* flush */
4979*4882a593Smuzhiyun }
4980*4882a593Smuzhiyun return nbytes;
4981*4882a593Smuzhiyun
4982*4882a593Smuzhiyun error_out:
4983*4882a593Smuzhiyun /* Clean out command structure on command error out */
4984*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
4985*4882a593Smuzhiyun return -EINVAL;
4986*4882a593Smuzhiyun }
4987*4882a593Smuzhiyun
4988*4882a593Smuzhiyun /**
4989*4882a593Smuzhiyun * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup
4990*4882a593Smuzhiyun * @phba: Pointer to HBA context object.
4991*4882a593Smuzhiyun * @pbuffer: Pointer to data buffer.
4992*4882a593Smuzhiyun *
4993*4882a593Smuzhiyun * Description:
4994*4882a593Smuzhiyun * This routine gets the driver mailbox access debugfs setup information.
4995*4882a593Smuzhiyun *
4996*4882a593Smuzhiyun * Returns:
4997*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
4998*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
4999*4882a593Smuzhiyun **/
5000*4882a593Smuzhiyun static int
lpfc_idiag_mbxacc_get_setup(struct lpfc_hba * phba,char * pbuffer)5001*4882a593Smuzhiyun lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
5002*4882a593Smuzhiyun {
5003*4882a593Smuzhiyun uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
5004*4882a593Smuzhiyun int len = 0;
5005*4882a593Smuzhiyun
5006*4882a593Smuzhiyun mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5007*4882a593Smuzhiyun mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5008*4882a593Smuzhiyun mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5009*4882a593Smuzhiyun mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5010*4882a593Smuzhiyun
5011*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5012*4882a593Smuzhiyun "mbx_dump_map: 0x%08x\n", mbx_dump_map);
5013*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5014*4882a593Smuzhiyun "mbx_dump_cnt: %04d\n", mbx_dump_cnt);
5015*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5016*4882a593Smuzhiyun "mbx_word_cnt: %04d\n", mbx_word_cnt);
5017*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5018*4882a593Smuzhiyun "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
5019*4882a593Smuzhiyun
5020*4882a593Smuzhiyun return len;
5021*4882a593Smuzhiyun }
5022*4882a593Smuzhiyun
5023*4882a593Smuzhiyun /**
5024*4882a593Smuzhiyun * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access
5025*4882a593Smuzhiyun * @file: The file pointer to read from.
5026*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
5027*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
5028*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
5029*4882a593Smuzhiyun *
5030*4882a593Smuzhiyun * Description:
5031*4882a593Smuzhiyun * This routine reads data from the @phba driver mailbox access debugfs setup
5032*4882a593Smuzhiyun * information.
5033*4882a593Smuzhiyun *
5034*4882a593Smuzhiyun * Returns:
5035*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
5036*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
5037*4882a593Smuzhiyun **/
5038*4882a593Smuzhiyun static ssize_t
lpfc_idiag_mbxacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5039*4882a593Smuzhiyun lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes,
5040*4882a593Smuzhiyun loff_t *ppos)
5041*4882a593Smuzhiyun {
5042*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
5043*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
5044*4882a593Smuzhiyun char *pbuffer;
5045*4882a593Smuzhiyun int len = 0;
5046*4882a593Smuzhiyun
5047*4882a593Smuzhiyun /* This is a user read operation */
5048*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
5049*4882a593Smuzhiyun
5050*4882a593Smuzhiyun if (!debug->buffer)
5051*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL);
5052*4882a593Smuzhiyun if (!debug->buffer)
5053*4882a593Smuzhiyun return 0;
5054*4882a593Smuzhiyun pbuffer = debug->buffer;
5055*4882a593Smuzhiyun
5056*4882a593Smuzhiyun if (*ppos)
5057*4882a593Smuzhiyun return 0;
5058*4882a593Smuzhiyun
5059*4882a593Smuzhiyun if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) &&
5060*4882a593Smuzhiyun (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP))
5061*4882a593Smuzhiyun return 0;
5062*4882a593Smuzhiyun
5063*4882a593Smuzhiyun len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer);
5064*4882a593Smuzhiyun
5065*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
5066*4882a593Smuzhiyun }
5067*4882a593Smuzhiyun
5068*4882a593Smuzhiyun /**
5069*4882a593Smuzhiyun * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands
5070*4882a593Smuzhiyun * @file: The file pointer to read from.
5071*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
5072*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
5073*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
5074*4882a593Smuzhiyun *
5075*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and then
5076*4882a593Smuzhiyun * perform the syntax check for driver mailbox command (dump) and sets up the
5077*4882a593Smuzhiyun * necessary states in the idiag command struct accordingly.
5078*4882a593Smuzhiyun *
5079*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
5080*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
5081*4882a593Smuzhiyun * space.
5082*4882a593Smuzhiyun **/
5083*4882a593Smuzhiyun static ssize_t
lpfc_idiag_mbxacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)5084*4882a593Smuzhiyun lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf,
5085*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
5086*4882a593Smuzhiyun {
5087*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
5088*4882a593Smuzhiyun uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
5089*4882a593Smuzhiyun int rc;
5090*4882a593Smuzhiyun
5091*4882a593Smuzhiyun /* This is a user write operation */
5092*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
5093*4882a593Smuzhiyun
5094*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
5095*4882a593Smuzhiyun if (rc < 0)
5096*4882a593Smuzhiyun return rc;
5097*4882a593Smuzhiyun
5098*4882a593Smuzhiyun /* Sanity check on command line arguments */
5099*4882a593Smuzhiyun mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5100*4882a593Smuzhiyun mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5101*4882a593Smuzhiyun mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5102*4882a593Smuzhiyun mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5103*4882a593Smuzhiyun
5104*4882a593Smuzhiyun if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) {
5105*4882a593Smuzhiyun if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL))
5106*4882a593Smuzhiyun goto error_out;
5107*4882a593Smuzhiyun if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) &&
5108*4882a593Smuzhiyun (mbx_dump_map != LPFC_MBX_DMP_ALL))
5109*4882a593Smuzhiyun goto error_out;
5110*4882a593Smuzhiyun if (mbx_word_cnt > sizeof(MAILBOX_t))
5111*4882a593Smuzhiyun goto error_out;
5112*4882a593Smuzhiyun } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) {
5113*4882a593Smuzhiyun if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL))
5114*4882a593Smuzhiyun goto error_out;
5115*4882a593Smuzhiyun if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) &&
5116*4882a593Smuzhiyun (mbx_dump_map != LPFC_MBX_DMP_ALL))
5117*4882a593Smuzhiyun goto error_out;
5118*4882a593Smuzhiyun if (mbx_word_cnt > (BSG_MBOX_SIZE)/4)
5119*4882a593Smuzhiyun goto error_out;
5120*4882a593Smuzhiyun if (mbx_mbox_cmd != 0x9b)
5121*4882a593Smuzhiyun goto error_out;
5122*4882a593Smuzhiyun } else
5123*4882a593Smuzhiyun goto error_out;
5124*4882a593Smuzhiyun
5125*4882a593Smuzhiyun if (mbx_word_cnt == 0)
5126*4882a593Smuzhiyun goto error_out;
5127*4882a593Smuzhiyun if (rc != LPFC_MBX_DMP_ARG)
5128*4882a593Smuzhiyun goto error_out;
5129*4882a593Smuzhiyun if (mbx_mbox_cmd & ~0xff)
5130*4882a593Smuzhiyun goto error_out;
5131*4882a593Smuzhiyun
5132*4882a593Smuzhiyun /* condition for stop mailbox dump */
5133*4882a593Smuzhiyun if (mbx_dump_cnt == 0)
5134*4882a593Smuzhiyun goto reset_out;
5135*4882a593Smuzhiyun
5136*4882a593Smuzhiyun return nbytes;
5137*4882a593Smuzhiyun
5138*4882a593Smuzhiyun reset_out:
5139*4882a593Smuzhiyun /* Clean out command structure on command error out */
5140*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
5141*4882a593Smuzhiyun return nbytes;
5142*4882a593Smuzhiyun
5143*4882a593Smuzhiyun error_out:
5144*4882a593Smuzhiyun /* Clean out command structure on command error out */
5145*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
5146*4882a593Smuzhiyun return -EINVAL;
5147*4882a593Smuzhiyun }
5148*4882a593Smuzhiyun
5149*4882a593Smuzhiyun /**
5150*4882a593Smuzhiyun * lpfc_idiag_extacc_avail_get - get the available extents information
5151*4882a593Smuzhiyun * @phba: pointer to lpfc hba data structure.
5152*4882a593Smuzhiyun * @pbuffer: pointer to internal buffer.
5153*4882a593Smuzhiyun * @len: length into the internal buffer data has been copied.
5154*4882a593Smuzhiyun *
5155*4882a593Smuzhiyun * Description:
5156*4882a593Smuzhiyun * This routine is to get the available extent information.
5157*4882a593Smuzhiyun *
5158*4882a593Smuzhiyun * Returns:
5159*4882a593Smuzhiyun * overall lenth of the data read into the internal buffer.
5160*4882a593Smuzhiyun **/
5161*4882a593Smuzhiyun static int
lpfc_idiag_extacc_avail_get(struct lpfc_hba * phba,char * pbuffer,int len)5162*4882a593Smuzhiyun lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
5163*4882a593Smuzhiyun {
5164*4882a593Smuzhiyun uint16_t ext_cnt, ext_size;
5165*4882a593Smuzhiyun
5166*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5167*4882a593Smuzhiyun "\nAvailable Extents Information:\n");
5168*4882a593Smuzhiyun
5169*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5170*4882a593Smuzhiyun "\tPort Available VPI extents: ");
5171*4882a593Smuzhiyun lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
5172*4882a593Smuzhiyun &ext_cnt, &ext_size);
5173*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5174*4882a593Smuzhiyun "Count %3d, Size %3d\n", ext_cnt, ext_size);
5175*4882a593Smuzhiyun
5176*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5177*4882a593Smuzhiyun "\tPort Available VFI extents: ");
5178*4882a593Smuzhiyun lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
5179*4882a593Smuzhiyun &ext_cnt, &ext_size);
5180*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5181*4882a593Smuzhiyun "Count %3d, Size %3d\n", ext_cnt, ext_size);
5182*4882a593Smuzhiyun
5183*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5184*4882a593Smuzhiyun "\tPort Available RPI extents: ");
5185*4882a593Smuzhiyun lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
5186*4882a593Smuzhiyun &ext_cnt, &ext_size);
5187*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5188*4882a593Smuzhiyun "Count %3d, Size %3d\n", ext_cnt, ext_size);
5189*4882a593Smuzhiyun
5190*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5191*4882a593Smuzhiyun "\tPort Available XRI extents: ");
5192*4882a593Smuzhiyun lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
5193*4882a593Smuzhiyun &ext_cnt, &ext_size);
5194*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5195*4882a593Smuzhiyun "Count %3d, Size %3d\n", ext_cnt, ext_size);
5196*4882a593Smuzhiyun
5197*4882a593Smuzhiyun return len;
5198*4882a593Smuzhiyun }
5199*4882a593Smuzhiyun
5200*4882a593Smuzhiyun /**
5201*4882a593Smuzhiyun * lpfc_idiag_extacc_alloc_get - get the allocated extents information
5202*4882a593Smuzhiyun * @phba: pointer to lpfc hba data structure.
5203*4882a593Smuzhiyun * @pbuffer: pointer to internal buffer.
5204*4882a593Smuzhiyun * @len: length into the internal buffer data has been copied.
5205*4882a593Smuzhiyun *
5206*4882a593Smuzhiyun * Description:
5207*4882a593Smuzhiyun * This routine is to get the allocated extent information.
5208*4882a593Smuzhiyun *
5209*4882a593Smuzhiyun * Returns:
5210*4882a593Smuzhiyun * overall lenth of the data read into the internal buffer.
5211*4882a593Smuzhiyun **/
5212*4882a593Smuzhiyun static int
lpfc_idiag_extacc_alloc_get(struct lpfc_hba * phba,char * pbuffer,int len)5213*4882a593Smuzhiyun lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
5214*4882a593Smuzhiyun {
5215*4882a593Smuzhiyun uint16_t ext_cnt, ext_size;
5216*4882a593Smuzhiyun int rc;
5217*4882a593Smuzhiyun
5218*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5219*4882a593Smuzhiyun "\nAllocated Extents Information:\n");
5220*4882a593Smuzhiyun
5221*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5222*4882a593Smuzhiyun "\tHost Allocated VPI extents: ");
5223*4882a593Smuzhiyun rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
5224*4882a593Smuzhiyun &ext_cnt, &ext_size);
5225*4882a593Smuzhiyun if (!rc)
5226*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5227*4882a593Smuzhiyun "Port %d Extent %3d, Size %3d\n",
5228*4882a593Smuzhiyun phba->brd_no, ext_cnt, ext_size);
5229*4882a593Smuzhiyun else
5230*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5231*4882a593Smuzhiyun "N/A\n");
5232*4882a593Smuzhiyun
5233*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5234*4882a593Smuzhiyun "\tHost Allocated VFI extents: ");
5235*4882a593Smuzhiyun rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
5236*4882a593Smuzhiyun &ext_cnt, &ext_size);
5237*4882a593Smuzhiyun if (!rc)
5238*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5239*4882a593Smuzhiyun "Port %d Extent %3d, Size %3d\n",
5240*4882a593Smuzhiyun phba->brd_no, ext_cnt, ext_size);
5241*4882a593Smuzhiyun else
5242*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5243*4882a593Smuzhiyun "N/A\n");
5244*4882a593Smuzhiyun
5245*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5246*4882a593Smuzhiyun "\tHost Allocated RPI extents: ");
5247*4882a593Smuzhiyun rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
5248*4882a593Smuzhiyun &ext_cnt, &ext_size);
5249*4882a593Smuzhiyun if (!rc)
5250*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5251*4882a593Smuzhiyun "Port %d Extent %3d, Size %3d\n",
5252*4882a593Smuzhiyun phba->brd_no, ext_cnt, ext_size);
5253*4882a593Smuzhiyun else
5254*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5255*4882a593Smuzhiyun "N/A\n");
5256*4882a593Smuzhiyun
5257*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5258*4882a593Smuzhiyun "\tHost Allocated XRI extents: ");
5259*4882a593Smuzhiyun rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
5260*4882a593Smuzhiyun &ext_cnt, &ext_size);
5261*4882a593Smuzhiyun if (!rc)
5262*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5263*4882a593Smuzhiyun "Port %d Extent %3d, Size %3d\n",
5264*4882a593Smuzhiyun phba->brd_no, ext_cnt, ext_size);
5265*4882a593Smuzhiyun else
5266*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5267*4882a593Smuzhiyun "N/A\n");
5268*4882a593Smuzhiyun
5269*4882a593Smuzhiyun return len;
5270*4882a593Smuzhiyun }
5271*4882a593Smuzhiyun
5272*4882a593Smuzhiyun /**
5273*4882a593Smuzhiyun * lpfc_idiag_extacc_drivr_get - get driver extent information
5274*4882a593Smuzhiyun * @phba: pointer to lpfc hba data structure.
5275*4882a593Smuzhiyun * @pbuffer: pointer to internal buffer.
5276*4882a593Smuzhiyun * @len: length into the internal buffer data has been copied.
5277*4882a593Smuzhiyun *
5278*4882a593Smuzhiyun * Description:
5279*4882a593Smuzhiyun * This routine is to get the driver extent information.
5280*4882a593Smuzhiyun *
5281*4882a593Smuzhiyun * Returns:
5282*4882a593Smuzhiyun * overall lenth of the data read into the internal buffer.
5283*4882a593Smuzhiyun **/
5284*4882a593Smuzhiyun static int
lpfc_idiag_extacc_drivr_get(struct lpfc_hba * phba,char * pbuffer,int len)5285*4882a593Smuzhiyun lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
5286*4882a593Smuzhiyun {
5287*4882a593Smuzhiyun struct lpfc_rsrc_blks *rsrc_blks;
5288*4882a593Smuzhiyun int index;
5289*4882a593Smuzhiyun
5290*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5291*4882a593Smuzhiyun "\nDriver Extents Information:\n");
5292*4882a593Smuzhiyun
5293*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5294*4882a593Smuzhiyun "\tVPI extents:\n");
5295*4882a593Smuzhiyun index = 0;
5296*4882a593Smuzhiyun list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
5297*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5298*4882a593Smuzhiyun "\t\tBlock %3d: Start %4d, Count %4d\n",
5299*4882a593Smuzhiyun index, rsrc_blks->rsrc_start,
5300*4882a593Smuzhiyun rsrc_blks->rsrc_size);
5301*4882a593Smuzhiyun index++;
5302*4882a593Smuzhiyun }
5303*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5304*4882a593Smuzhiyun "\tVFI extents:\n");
5305*4882a593Smuzhiyun index = 0;
5306*4882a593Smuzhiyun list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
5307*4882a593Smuzhiyun list) {
5308*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5309*4882a593Smuzhiyun "\t\tBlock %3d: Start %4d, Count %4d\n",
5310*4882a593Smuzhiyun index, rsrc_blks->rsrc_start,
5311*4882a593Smuzhiyun rsrc_blks->rsrc_size);
5312*4882a593Smuzhiyun index++;
5313*4882a593Smuzhiyun }
5314*4882a593Smuzhiyun
5315*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5316*4882a593Smuzhiyun "\tRPI extents:\n");
5317*4882a593Smuzhiyun index = 0;
5318*4882a593Smuzhiyun list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
5319*4882a593Smuzhiyun list) {
5320*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5321*4882a593Smuzhiyun "\t\tBlock %3d: Start %4d, Count %4d\n",
5322*4882a593Smuzhiyun index, rsrc_blks->rsrc_start,
5323*4882a593Smuzhiyun rsrc_blks->rsrc_size);
5324*4882a593Smuzhiyun index++;
5325*4882a593Smuzhiyun }
5326*4882a593Smuzhiyun
5327*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5328*4882a593Smuzhiyun "\tXRI extents:\n");
5329*4882a593Smuzhiyun index = 0;
5330*4882a593Smuzhiyun list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
5331*4882a593Smuzhiyun list) {
5332*4882a593Smuzhiyun len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5333*4882a593Smuzhiyun "\t\tBlock %3d: Start %4d, Count %4d\n",
5334*4882a593Smuzhiyun index, rsrc_blks->rsrc_start,
5335*4882a593Smuzhiyun rsrc_blks->rsrc_size);
5336*4882a593Smuzhiyun index++;
5337*4882a593Smuzhiyun }
5338*4882a593Smuzhiyun
5339*4882a593Smuzhiyun return len;
5340*4882a593Smuzhiyun }
5341*4882a593Smuzhiyun
5342*4882a593Smuzhiyun /**
5343*4882a593Smuzhiyun * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands
5344*4882a593Smuzhiyun * @file: The file pointer to read from.
5345*4882a593Smuzhiyun * @buf: The buffer to copy the user data from.
5346*4882a593Smuzhiyun * @nbytes: The number of bytes to get.
5347*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
5348*4882a593Smuzhiyun *
5349*4882a593Smuzhiyun * This routine get the debugfs idiag command struct from user space and then
5350*4882a593Smuzhiyun * perform the syntax check for extent information access commands and sets
5351*4882a593Smuzhiyun * up the necessary states in the idiag command struct accordingly.
5352*4882a593Smuzhiyun *
5353*4882a593Smuzhiyun * It returns the @nbytges passing in from debugfs user space when successful.
5354*4882a593Smuzhiyun * In case of error conditions, it returns proper error code back to the user
5355*4882a593Smuzhiyun * space.
5356*4882a593Smuzhiyun **/
5357*4882a593Smuzhiyun static ssize_t
lpfc_idiag_extacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)5358*4882a593Smuzhiyun lpfc_idiag_extacc_write(struct file *file, const char __user *buf,
5359*4882a593Smuzhiyun size_t nbytes, loff_t *ppos)
5360*4882a593Smuzhiyun {
5361*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
5362*4882a593Smuzhiyun uint32_t ext_map;
5363*4882a593Smuzhiyun int rc;
5364*4882a593Smuzhiyun
5365*4882a593Smuzhiyun /* This is a user write operation */
5366*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_WR;
5367*4882a593Smuzhiyun
5368*4882a593Smuzhiyun rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
5369*4882a593Smuzhiyun if (rc < 0)
5370*4882a593Smuzhiyun return rc;
5371*4882a593Smuzhiyun
5372*4882a593Smuzhiyun ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
5373*4882a593Smuzhiyun
5374*4882a593Smuzhiyun if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
5375*4882a593Smuzhiyun goto error_out;
5376*4882a593Smuzhiyun if (rc != LPFC_EXT_ACC_CMD_ARG)
5377*4882a593Smuzhiyun goto error_out;
5378*4882a593Smuzhiyun if (!(ext_map & LPFC_EXT_ACC_ALL))
5379*4882a593Smuzhiyun goto error_out;
5380*4882a593Smuzhiyun
5381*4882a593Smuzhiyun return nbytes;
5382*4882a593Smuzhiyun error_out:
5383*4882a593Smuzhiyun /* Clean out command structure on command error out */
5384*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
5385*4882a593Smuzhiyun return -EINVAL;
5386*4882a593Smuzhiyun }
5387*4882a593Smuzhiyun
5388*4882a593Smuzhiyun /**
5389*4882a593Smuzhiyun * lpfc_idiag_extacc_read - idiag debugfs read access to extent information
5390*4882a593Smuzhiyun * @file: The file pointer to read from.
5391*4882a593Smuzhiyun * @buf: The buffer to copy the data to.
5392*4882a593Smuzhiyun * @nbytes: The number of bytes to read.
5393*4882a593Smuzhiyun * @ppos: The position in the file to start reading from.
5394*4882a593Smuzhiyun *
5395*4882a593Smuzhiyun * Description:
5396*4882a593Smuzhiyun * This routine reads data from the proper extent information according to
5397*4882a593Smuzhiyun * the idiag command, and copies to user @buf.
5398*4882a593Smuzhiyun *
5399*4882a593Smuzhiyun * Returns:
5400*4882a593Smuzhiyun * This function returns the amount of data that was read (this could be less
5401*4882a593Smuzhiyun * than @nbytes if the end of the file was reached) or a negative error value.
5402*4882a593Smuzhiyun **/
5403*4882a593Smuzhiyun static ssize_t
lpfc_idiag_extacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5404*4882a593Smuzhiyun lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
5405*4882a593Smuzhiyun loff_t *ppos)
5406*4882a593Smuzhiyun {
5407*4882a593Smuzhiyun struct lpfc_debug *debug = file->private_data;
5408*4882a593Smuzhiyun struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
5409*4882a593Smuzhiyun char *pbuffer;
5410*4882a593Smuzhiyun uint32_t ext_map;
5411*4882a593Smuzhiyun int len = 0;
5412*4882a593Smuzhiyun
5413*4882a593Smuzhiyun /* This is a user read operation */
5414*4882a593Smuzhiyun debug->op = LPFC_IDIAG_OP_RD;
5415*4882a593Smuzhiyun
5416*4882a593Smuzhiyun if (!debug->buffer)
5417*4882a593Smuzhiyun debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL);
5418*4882a593Smuzhiyun if (!debug->buffer)
5419*4882a593Smuzhiyun return 0;
5420*4882a593Smuzhiyun pbuffer = debug->buffer;
5421*4882a593Smuzhiyun if (*ppos)
5422*4882a593Smuzhiyun return 0;
5423*4882a593Smuzhiyun if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
5424*4882a593Smuzhiyun return 0;
5425*4882a593Smuzhiyun
5426*4882a593Smuzhiyun ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
5427*4882a593Smuzhiyun if (ext_map & LPFC_EXT_ACC_AVAIL)
5428*4882a593Smuzhiyun len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len);
5429*4882a593Smuzhiyun if (ext_map & LPFC_EXT_ACC_ALLOC)
5430*4882a593Smuzhiyun len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len);
5431*4882a593Smuzhiyun if (ext_map & LPFC_EXT_ACC_DRIVR)
5432*4882a593Smuzhiyun len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len);
5433*4882a593Smuzhiyun
5434*4882a593Smuzhiyun return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
5435*4882a593Smuzhiyun }
5436*4882a593Smuzhiyun
5437*4882a593Smuzhiyun #undef lpfc_debugfs_op_disc_trc
5438*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_disc_trc = {
5439*4882a593Smuzhiyun .owner = THIS_MODULE,
5440*4882a593Smuzhiyun .open = lpfc_debugfs_disc_trc_open,
5441*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5442*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5443*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5444*4882a593Smuzhiyun };
5445*4882a593Smuzhiyun
5446*4882a593Smuzhiyun #undef lpfc_debugfs_op_nodelist
5447*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_nodelist = {
5448*4882a593Smuzhiyun .owner = THIS_MODULE,
5449*4882a593Smuzhiyun .open = lpfc_debugfs_nodelist_open,
5450*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5451*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5452*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5453*4882a593Smuzhiyun };
5454*4882a593Smuzhiyun
5455*4882a593Smuzhiyun #undef lpfc_debugfs_op_multixripools
5456*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_multixripools = {
5457*4882a593Smuzhiyun .owner = THIS_MODULE,
5458*4882a593Smuzhiyun .open = lpfc_debugfs_multixripools_open,
5459*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5460*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5461*4882a593Smuzhiyun .write = lpfc_debugfs_multixripools_write,
5462*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5463*4882a593Smuzhiyun };
5464*4882a593Smuzhiyun
5465*4882a593Smuzhiyun #undef lpfc_debugfs_op_hbqinfo
5466*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_hbqinfo = {
5467*4882a593Smuzhiyun .owner = THIS_MODULE,
5468*4882a593Smuzhiyun .open = lpfc_debugfs_hbqinfo_open,
5469*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5470*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5471*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5472*4882a593Smuzhiyun };
5473*4882a593Smuzhiyun
5474*4882a593Smuzhiyun #ifdef LPFC_HDWQ_LOCK_STAT
5475*4882a593Smuzhiyun #undef lpfc_debugfs_op_lockstat
5476*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_lockstat = {
5477*4882a593Smuzhiyun .owner = THIS_MODULE,
5478*4882a593Smuzhiyun .open = lpfc_debugfs_lockstat_open,
5479*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5480*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5481*4882a593Smuzhiyun .write = lpfc_debugfs_lockstat_write,
5482*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5483*4882a593Smuzhiyun };
5484*4882a593Smuzhiyun #endif
5485*4882a593Smuzhiyun
5486*4882a593Smuzhiyun #undef lpfc_debugfs_ras_log
5487*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_ras_log = {
5488*4882a593Smuzhiyun .owner = THIS_MODULE,
5489*4882a593Smuzhiyun .open = lpfc_debugfs_ras_log_open,
5490*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5491*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5492*4882a593Smuzhiyun .release = lpfc_debugfs_ras_log_release,
5493*4882a593Smuzhiyun };
5494*4882a593Smuzhiyun
5495*4882a593Smuzhiyun #undef lpfc_debugfs_op_dumpHBASlim
5496*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
5497*4882a593Smuzhiyun .owner = THIS_MODULE,
5498*4882a593Smuzhiyun .open = lpfc_debugfs_dumpHBASlim_open,
5499*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5500*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5501*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5502*4882a593Smuzhiyun };
5503*4882a593Smuzhiyun
5504*4882a593Smuzhiyun #undef lpfc_debugfs_op_dumpHostSlim
5505*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
5506*4882a593Smuzhiyun .owner = THIS_MODULE,
5507*4882a593Smuzhiyun .open = lpfc_debugfs_dumpHostSlim_open,
5508*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5509*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5510*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5511*4882a593Smuzhiyun };
5512*4882a593Smuzhiyun
5513*4882a593Smuzhiyun #undef lpfc_debugfs_op_nvmestat
5514*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_nvmestat = {
5515*4882a593Smuzhiyun .owner = THIS_MODULE,
5516*4882a593Smuzhiyun .open = lpfc_debugfs_nvmestat_open,
5517*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5518*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5519*4882a593Smuzhiyun .write = lpfc_debugfs_nvmestat_write,
5520*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5521*4882a593Smuzhiyun };
5522*4882a593Smuzhiyun
5523*4882a593Smuzhiyun #undef lpfc_debugfs_op_scsistat
5524*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_scsistat = {
5525*4882a593Smuzhiyun .owner = THIS_MODULE,
5526*4882a593Smuzhiyun .open = lpfc_debugfs_scsistat_open,
5527*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5528*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5529*4882a593Smuzhiyun .write = lpfc_debugfs_scsistat_write,
5530*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5531*4882a593Smuzhiyun };
5532*4882a593Smuzhiyun
5533*4882a593Smuzhiyun #undef lpfc_debugfs_op_ioktime
5534*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_ioktime = {
5535*4882a593Smuzhiyun .owner = THIS_MODULE,
5536*4882a593Smuzhiyun .open = lpfc_debugfs_ioktime_open,
5537*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5538*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5539*4882a593Smuzhiyun .write = lpfc_debugfs_ioktime_write,
5540*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5541*4882a593Smuzhiyun };
5542*4882a593Smuzhiyun
5543*4882a593Smuzhiyun #undef lpfc_debugfs_op_nvmeio_trc
5544*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_nvmeio_trc = {
5545*4882a593Smuzhiyun .owner = THIS_MODULE,
5546*4882a593Smuzhiyun .open = lpfc_debugfs_nvmeio_trc_open,
5547*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5548*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5549*4882a593Smuzhiyun .write = lpfc_debugfs_nvmeio_trc_write,
5550*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5551*4882a593Smuzhiyun };
5552*4882a593Smuzhiyun
5553*4882a593Smuzhiyun #undef lpfc_debugfs_op_hdwqstat
5554*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_hdwqstat = {
5555*4882a593Smuzhiyun .owner = THIS_MODULE,
5556*4882a593Smuzhiyun .open = lpfc_debugfs_hdwqstat_open,
5557*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5558*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5559*4882a593Smuzhiyun .write = lpfc_debugfs_hdwqstat_write,
5560*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5561*4882a593Smuzhiyun };
5562*4882a593Smuzhiyun
5563*4882a593Smuzhiyun #undef lpfc_debugfs_op_dif_err
5564*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_dif_err = {
5565*4882a593Smuzhiyun .owner = THIS_MODULE,
5566*4882a593Smuzhiyun .open = simple_open,
5567*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5568*4882a593Smuzhiyun .read = lpfc_debugfs_dif_err_read,
5569*4882a593Smuzhiyun .write = lpfc_debugfs_dif_err_write,
5570*4882a593Smuzhiyun .release = lpfc_debugfs_dif_err_release,
5571*4882a593Smuzhiyun };
5572*4882a593Smuzhiyun
5573*4882a593Smuzhiyun #undef lpfc_debugfs_op_slow_ring_trc
5574*4882a593Smuzhiyun static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
5575*4882a593Smuzhiyun .owner = THIS_MODULE,
5576*4882a593Smuzhiyun .open = lpfc_debugfs_slow_ring_trc_open,
5577*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5578*4882a593Smuzhiyun .read = lpfc_debugfs_read,
5579*4882a593Smuzhiyun .release = lpfc_debugfs_release,
5580*4882a593Smuzhiyun };
5581*4882a593Smuzhiyun
5582*4882a593Smuzhiyun static struct dentry *lpfc_debugfs_root = NULL;
5583*4882a593Smuzhiyun static atomic_t lpfc_debugfs_hba_count;
5584*4882a593Smuzhiyun
5585*4882a593Smuzhiyun /*
5586*4882a593Smuzhiyun * File operations for the iDiag debugfs
5587*4882a593Smuzhiyun */
5588*4882a593Smuzhiyun #undef lpfc_idiag_op_pciCfg
5589*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_pciCfg = {
5590*4882a593Smuzhiyun .owner = THIS_MODULE,
5591*4882a593Smuzhiyun .open = lpfc_idiag_open,
5592*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5593*4882a593Smuzhiyun .read = lpfc_idiag_pcicfg_read,
5594*4882a593Smuzhiyun .write = lpfc_idiag_pcicfg_write,
5595*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5596*4882a593Smuzhiyun };
5597*4882a593Smuzhiyun
5598*4882a593Smuzhiyun #undef lpfc_idiag_op_barAcc
5599*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_barAcc = {
5600*4882a593Smuzhiyun .owner = THIS_MODULE,
5601*4882a593Smuzhiyun .open = lpfc_idiag_open,
5602*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5603*4882a593Smuzhiyun .read = lpfc_idiag_baracc_read,
5604*4882a593Smuzhiyun .write = lpfc_idiag_baracc_write,
5605*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5606*4882a593Smuzhiyun };
5607*4882a593Smuzhiyun
5608*4882a593Smuzhiyun #undef lpfc_idiag_op_queInfo
5609*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_queInfo = {
5610*4882a593Smuzhiyun .owner = THIS_MODULE,
5611*4882a593Smuzhiyun .open = lpfc_idiag_open,
5612*4882a593Smuzhiyun .read = lpfc_idiag_queinfo_read,
5613*4882a593Smuzhiyun .release = lpfc_idiag_release,
5614*4882a593Smuzhiyun };
5615*4882a593Smuzhiyun
5616*4882a593Smuzhiyun #undef lpfc_idiag_op_queAcc
5617*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_queAcc = {
5618*4882a593Smuzhiyun .owner = THIS_MODULE,
5619*4882a593Smuzhiyun .open = lpfc_idiag_open,
5620*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5621*4882a593Smuzhiyun .read = lpfc_idiag_queacc_read,
5622*4882a593Smuzhiyun .write = lpfc_idiag_queacc_write,
5623*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5624*4882a593Smuzhiyun };
5625*4882a593Smuzhiyun
5626*4882a593Smuzhiyun #undef lpfc_idiag_op_drbAcc
5627*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_drbAcc = {
5628*4882a593Smuzhiyun .owner = THIS_MODULE,
5629*4882a593Smuzhiyun .open = lpfc_idiag_open,
5630*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5631*4882a593Smuzhiyun .read = lpfc_idiag_drbacc_read,
5632*4882a593Smuzhiyun .write = lpfc_idiag_drbacc_write,
5633*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5634*4882a593Smuzhiyun };
5635*4882a593Smuzhiyun
5636*4882a593Smuzhiyun #undef lpfc_idiag_op_ctlAcc
5637*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_ctlAcc = {
5638*4882a593Smuzhiyun .owner = THIS_MODULE,
5639*4882a593Smuzhiyun .open = lpfc_idiag_open,
5640*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5641*4882a593Smuzhiyun .read = lpfc_idiag_ctlacc_read,
5642*4882a593Smuzhiyun .write = lpfc_idiag_ctlacc_write,
5643*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5644*4882a593Smuzhiyun };
5645*4882a593Smuzhiyun
5646*4882a593Smuzhiyun #undef lpfc_idiag_op_mbxAcc
5647*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_mbxAcc = {
5648*4882a593Smuzhiyun .owner = THIS_MODULE,
5649*4882a593Smuzhiyun .open = lpfc_idiag_open,
5650*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5651*4882a593Smuzhiyun .read = lpfc_idiag_mbxacc_read,
5652*4882a593Smuzhiyun .write = lpfc_idiag_mbxacc_write,
5653*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5654*4882a593Smuzhiyun };
5655*4882a593Smuzhiyun
5656*4882a593Smuzhiyun #undef lpfc_idiag_op_extAcc
5657*4882a593Smuzhiyun static const struct file_operations lpfc_idiag_op_extAcc = {
5658*4882a593Smuzhiyun .owner = THIS_MODULE,
5659*4882a593Smuzhiyun .open = lpfc_idiag_open,
5660*4882a593Smuzhiyun .llseek = lpfc_debugfs_lseek,
5661*4882a593Smuzhiyun .read = lpfc_idiag_extacc_read,
5662*4882a593Smuzhiyun .write = lpfc_idiag_extacc_write,
5663*4882a593Smuzhiyun .release = lpfc_idiag_cmd_release,
5664*4882a593Smuzhiyun };
5665*4882a593Smuzhiyun #endif
5666*4882a593Smuzhiyun
5667*4882a593Smuzhiyun /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
5668*4882a593Smuzhiyun * @phba: Pointer to HBA context object.
5669*4882a593Smuzhiyun * @dmabuf: Pointer to a DMA buffer descriptor.
5670*4882a593Smuzhiyun *
5671*4882a593Smuzhiyun * Description:
5672*4882a593Smuzhiyun * This routine dump a bsg pass-through non-embedded mailbox command with
5673*4882a593Smuzhiyun * external buffer.
5674*4882a593Smuzhiyun **/
5675*4882a593Smuzhiyun void
lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba * phba,enum nemb_type nemb_tp,enum mbox_type mbox_tp,enum dma_type dma_tp,enum sta_type sta_tp,struct lpfc_dmabuf * dmabuf,uint32_t ext_buf)5676*4882a593Smuzhiyun lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
5677*4882a593Smuzhiyun enum mbox_type mbox_tp, enum dma_type dma_tp,
5678*4882a593Smuzhiyun enum sta_type sta_tp,
5679*4882a593Smuzhiyun struct lpfc_dmabuf *dmabuf, uint32_t ext_buf)
5680*4882a593Smuzhiyun {
5681*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
5682*4882a593Smuzhiyun uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt;
5683*4882a593Smuzhiyun char line_buf[LPFC_MBX_ACC_LBUF_SZ];
5684*4882a593Smuzhiyun int len = 0;
5685*4882a593Smuzhiyun uint32_t do_dump = 0;
5686*4882a593Smuzhiyun uint32_t *pword;
5687*4882a593Smuzhiyun uint32_t i;
5688*4882a593Smuzhiyun
5689*4882a593Smuzhiyun if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)
5690*4882a593Smuzhiyun return;
5691*4882a593Smuzhiyun
5692*4882a593Smuzhiyun mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5693*4882a593Smuzhiyun mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5694*4882a593Smuzhiyun mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5695*4882a593Smuzhiyun mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5696*4882a593Smuzhiyun
5697*4882a593Smuzhiyun if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) ||
5698*4882a593Smuzhiyun (*mbx_dump_cnt == 0) ||
5699*4882a593Smuzhiyun (*mbx_word_cnt == 0))
5700*4882a593Smuzhiyun return;
5701*4882a593Smuzhiyun
5702*4882a593Smuzhiyun if (*mbx_mbox_cmd != 0x9B)
5703*4882a593Smuzhiyun return;
5704*4882a593Smuzhiyun
5705*4882a593Smuzhiyun if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) {
5706*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) {
5707*4882a593Smuzhiyun do_dump |= LPFC_BSG_DMP_MBX_RD_MBX;
5708*4882a593Smuzhiyun pr_err("\nRead mbox command (x%x), "
5709*4882a593Smuzhiyun "nemb:0x%x, extbuf_cnt:%d:\n",
5710*4882a593Smuzhiyun sta_tp, nemb_tp, ext_buf);
5711*4882a593Smuzhiyun }
5712*4882a593Smuzhiyun }
5713*4882a593Smuzhiyun if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) {
5714*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) {
5715*4882a593Smuzhiyun do_dump |= LPFC_BSG_DMP_MBX_RD_BUF;
5716*4882a593Smuzhiyun pr_err("\nRead mbox buffer (x%x), "
5717*4882a593Smuzhiyun "nemb:0x%x, extbuf_seq:%d:\n",
5718*4882a593Smuzhiyun sta_tp, nemb_tp, ext_buf);
5719*4882a593Smuzhiyun }
5720*4882a593Smuzhiyun }
5721*4882a593Smuzhiyun if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) {
5722*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) {
5723*4882a593Smuzhiyun do_dump |= LPFC_BSG_DMP_MBX_WR_MBX;
5724*4882a593Smuzhiyun pr_err("\nWrite mbox command (x%x), "
5725*4882a593Smuzhiyun "nemb:0x%x, extbuf_cnt:%d:\n",
5726*4882a593Smuzhiyun sta_tp, nemb_tp, ext_buf);
5727*4882a593Smuzhiyun }
5728*4882a593Smuzhiyun }
5729*4882a593Smuzhiyun if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) {
5730*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) {
5731*4882a593Smuzhiyun do_dump |= LPFC_BSG_DMP_MBX_WR_BUF;
5732*4882a593Smuzhiyun pr_err("\nWrite mbox buffer (x%x), "
5733*4882a593Smuzhiyun "nemb:0x%x, extbuf_seq:%d:\n",
5734*4882a593Smuzhiyun sta_tp, nemb_tp, ext_buf);
5735*4882a593Smuzhiyun }
5736*4882a593Smuzhiyun }
5737*4882a593Smuzhiyun
5738*4882a593Smuzhiyun /* dump buffer content */
5739*4882a593Smuzhiyun if (do_dump) {
5740*4882a593Smuzhiyun pword = (uint32_t *)dmabuf->virt;
5741*4882a593Smuzhiyun for (i = 0; i < *mbx_word_cnt; i++) {
5742*4882a593Smuzhiyun if (!(i % 8)) {
5743*4882a593Smuzhiyun if (i != 0)
5744*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5745*4882a593Smuzhiyun len = 0;
5746*4882a593Smuzhiyun len += scnprintf(line_buf+len,
5747*4882a593Smuzhiyun LPFC_MBX_ACC_LBUF_SZ-len,
5748*4882a593Smuzhiyun "%03d: ", i);
5749*4882a593Smuzhiyun }
5750*4882a593Smuzhiyun len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
5751*4882a593Smuzhiyun "%08x ", (uint32_t)*pword);
5752*4882a593Smuzhiyun pword++;
5753*4882a593Smuzhiyun }
5754*4882a593Smuzhiyun if ((i - 1) % 8)
5755*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5756*4882a593Smuzhiyun (*mbx_dump_cnt)--;
5757*4882a593Smuzhiyun }
5758*4882a593Smuzhiyun
5759*4882a593Smuzhiyun /* Clean out command structure on reaching dump count */
5760*4882a593Smuzhiyun if (*mbx_dump_cnt == 0)
5761*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
5762*4882a593Smuzhiyun return;
5763*4882a593Smuzhiyun #endif
5764*4882a593Smuzhiyun }
5765*4882a593Smuzhiyun
5766*4882a593Smuzhiyun /* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command
5767*4882a593Smuzhiyun * @phba: Pointer to HBA context object.
5768*4882a593Smuzhiyun * @dmabuf: Pointer to a DMA buffer descriptor.
5769*4882a593Smuzhiyun *
5770*4882a593Smuzhiyun * Description:
5771*4882a593Smuzhiyun * This routine dump a pass-through non-embedded mailbox command from issue
5772*4882a593Smuzhiyun * mailbox command.
5773*4882a593Smuzhiyun **/
5774*4882a593Smuzhiyun void
lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba * phba,MAILBOX_t * pmbox)5775*4882a593Smuzhiyun lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
5776*4882a593Smuzhiyun {
5777*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
5778*4882a593Smuzhiyun uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd;
5779*4882a593Smuzhiyun char line_buf[LPFC_MBX_ACC_LBUF_SZ];
5780*4882a593Smuzhiyun int len = 0;
5781*4882a593Smuzhiyun uint32_t *pword;
5782*4882a593Smuzhiyun uint8_t *pbyte;
5783*4882a593Smuzhiyun uint32_t i, j;
5784*4882a593Smuzhiyun
5785*4882a593Smuzhiyun if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP)
5786*4882a593Smuzhiyun return;
5787*4882a593Smuzhiyun
5788*4882a593Smuzhiyun mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5789*4882a593Smuzhiyun mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5790*4882a593Smuzhiyun mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5791*4882a593Smuzhiyun mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5792*4882a593Smuzhiyun
5793*4882a593Smuzhiyun if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) ||
5794*4882a593Smuzhiyun (*mbx_dump_cnt == 0) ||
5795*4882a593Smuzhiyun (*mbx_word_cnt == 0))
5796*4882a593Smuzhiyun return;
5797*4882a593Smuzhiyun
5798*4882a593Smuzhiyun if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) &&
5799*4882a593Smuzhiyun (*mbx_mbox_cmd != pmbox->mbxCommand))
5800*4882a593Smuzhiyun return;
5801*4882a593Smuzhiyun
5802*4882a593Smuzhiyun /* dump buffer content */
5803*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) {
5804*4882a593Smuzhiyun pr_err("Mailbox command:0x%x dump by word:\n",
5805*4882a593Smuzhiyun pmbox->mbxCommand);
5806*4882a593Smuzhiyun pword = (uint32_t *)pmbox;
5807*4882a593Smuzhiyun for (i = 0; i < *mbx_word_cnt; i++) {
5808*4882a593Smuzhiyun if (!(i % 8)) {
5809*4882a593Smuzhiyun if (i != 0)
5810*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5811*4882a593Smuzhiyun len = 0;
5812*4882a593Smuzhiyun memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
5813*4882a593Smuzhiyun len += scnprintf(line_buf+len,
5814*4882a593Smuzhiyun LPFC_MBX_ACC_LBUF_SZ-len,
5815*4882a593Smuzhiyun "%03d: ", i);
5816*4882a593Smuzhiyun }
5817*4882a593Smuzhiyun len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
5818*4882a593Smuzhiyun "%08x ",
5819*4882a593Smuzhiyun ((uint32_t)*pword) & 0xffffffff);
5820*4882a593Smuzhiyun pword++;
5821*4882a593Smuzhiyun }
5822*4882a593Smuzhiyun if ((i - 1) % 8)
5823*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5824*4882a593Smuzhiyun pr_err("\n");
5825*4882a593Smuzhiyun }
5826*4882a593Smuzhiyun if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) {
5827*4882a593Smuzhiyun pr_err("Mailbox command:0x%x dump by byte:\n",
5828*4882a593Smuzhiyun pmbox->mbxCommand);
5829*4882a593Smuzhiyun pbyte = (uint8_t *)pmbox;
5830*4882a593Smuzhiyun for (i = 0; i < *mbx_word_cnt; i++) {
5831*4882a593Smuzhiyun if (!(i % 8)) {
5832*4882a593Smuzhiyun if (i != 0)
5833*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5834*4882a593Smuzhiyun len = 0;
5835*4882a593Smuzhiyun memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
5836*4882a593Smuzhiyun len += scnprintf(line_buf+len,
5837*4882a593Smuzhiyun LPFC_MBX_ACC_LBUF_SZ-len,
5838*4882a593Smuzhiyun "%03d: ", i);
5839*4882a593Smuzhiyun }
5840*4882a593Smuzhiyun for (j = 0; j < 4; j++) {
5841*4882a593Smuzhiyun len += scnprintf(line_buf+len,
5842*4882a593Smuzhiyun LPFC_MBX_ACC_LBUF_SZ-len,
5843*4882a593Smuzhiyun "%02x",
5844*4882a593Smuzhiyun ((uint8_t)*pbyte) & 0xff);
5845*4882a593Smuzhiyun pbyte++;
5846*4882a593Smuzhiyun }
5847*4882a593Smuzhiyun len += scnprintf(line_buf+len,
5848*4882a593Smuzhiyun LPFC_MBX_ACC_LBUF_SZ-len, " ");
5849*4882a593Smuzhiyun }
5850*4882a593Smuzhiyun if ((i - 1) % 8)
5851*4882a593Smuzhiyun pr_err("%s\n", line_buf);
5852*4882a593Smuzhiyun pr_err("\n");
5853*4882a593Smuzhiyun }
5854*4882a593Smuzhiyun (*mbx_dump_cnt)--;
5855*4882a593Smuzhiyun
5856*4882a593Smuzhiyun /* Clean out command structure on reaching dump count */
5857*4882a593Smuzhiyun if (*mbx_dump_cnt == 0)
5858*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
5859*4882a593Smuzhiyun return;
5860*4882a593Smuzhiyun #endif
5861*4882a593Smuzhiyun }
5862*4882a593Smuzhiyun
5863*4882a593Smuzhiyun /**
5864*4882a593Smuzhiyun * lpfc_debugfs_initialize - Initialize debugfs for a vport
5865*4882a593Smuzhiyun * @vport: The vport pointer to initialize.
5866*4882a593Smuzhiyun *
5867*4882a593Smuzhiyun * Description:
5868*4882a593Smuzhiyun * When Debugfs is configured this routine sets up the lpfc debugfs file system.
5869*4882a593Smuzhiyun * If not already created, this routine will create the lpfc directory, and
5870*4882a593Smuzhiyun * lpfcX directory (for this HBA), and vportX directory for this vport. It will
5871*4882a593Smuzhiyun * also create each file used to access lpfc specific debugfs information.
5872*4882a593Smuzhiyun **/
5873*4882a593Smuzhiyun inline void
lpfc_debugfs_initialize(struct lpfc_vport * vport)5874*4882a593Smuzhiyun lpfc_debugfs_initialize(struct lpfc_vport *vport)
5875*4882a593Smuzhiyun {
5876*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
5877*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
5878*4882a593Smuzhiyun char name[64];
5879*4882a593Smuzhiyun uint32_t num, i;
5880*4882a593Smuzhiyun bool pport_setup = false;
5881*4882a593Smuzhiyun
5882*4882a593Smuzhiyun if (!lpfc_debugfs_enable)
5883*4882a593Smuzhiyun return;
5884*4882a593Smuzhiyun
5885*4882a593Smuzhiyun /* Setup lpfc root directory */
5886*4882a593Smuzhiyun if (!lpfc_debugfs_root) {
5887*4882a593Smuzhiyun lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
5888*4882a593Smuzhiyun atomic_set(&lpfc_debugfs_hba_count, 0);
5889*4882a593Smuzhiyun }
5890*4882a593Smuzhiyun if (!lpfc_debugfs_start_time)
5891*4882a593Smuzhiyun lpfc_debugfs_start_time = jiffies;
5892*4882a593Smuzhiyun
5893*4882a593Smuzhiyun /* Setup funcX directory for specific HBA PCI function */
5894*4882a593Smuzhiyun snprintf(name, sizeof(name), "fn%d", phba->brd_no);
5895*4882a593Smuzhiyun if (!phba->hba_debugfs_root) {
5896*4882a593Smuzhiyun pport_setup = true;
5897*4882a593Smuzhiyun phba->hba_debugfs_root =
5898*4882a593Smuzhiyun debugfs_create_dir(name, lpfc_debugfs_root);
5899*4882a593Smuzhiyun atomic_inc(&lpfc_debugfs_hba_count);
5900*4882a593Smuzhiyun atomic_set(&phba->debugfs_vport_count, 0);
5901*4882a593Smuzhiyun
5902*4882a593Smuzhiyun /* Multi-XRI pools */
5903*4882a593Smuzhiyun snprintf(name, sizeof(name), "multixripools");
5904*4882a593Smuzhiyun phba->debug_multixri_pools =
5905*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG | 0644,
5906*4882a593Smuzhiyun phba->hba_debugfs_root,
5907*4882a593Smuzhiyun phba,
5908*4882a593Smuzhiyun &lpfc_debugfs_op_multixripools);
5909*4882a593Smuzhiyun if (!phba->debug_multixri_pools) {
5910*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
5911*4882a593Smuzhiyun "0527 Cannot create debugfs multixripools\n");
5912*4882a593Smuzhiyun goto debug_failed;
5913*4882a593Smuzhiyun }
5914*4882a593Smuzhiyun
5915*4882a593Smuzhiyun /* RAS log */
5916*4882a593Smuzhiyun snprintf(name, sizeof(name), "ras_log");
5917*4882a593Smuzhiyun phba->debug_ras_log =
5918*4882a593Smuzhiyun debugfs_create_file(name, 0644,
5919*4882a593Smuzhiyun phba->hba_debugfs_root,
5920*4882a593Smuzhiyun phba, &lpfc_debugfs_ras_log);
5921*4882a593Smuzhiyun if (!phba->debug_ras_log) {
5922*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
5923*4882a593Smuzhiyun "6148 Cannot create debugfs"
5924*4882a593Smuzhiyun " ras_log\n");
5925*4882a593Smuzhiyun goto debug_failed;
5926*4882a593Smuzhiyun }
5927*4882a593Smuzhiyun
5928*4882a593Smuzhiyun /* Setup hbqinfo */
5929*4882a593Smuzhiyun snprintf(name, sizeof(name), "hbqinfo");
5930*4882a593Smuzhiyun phba->debug_hbqinfo =
5931*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG | 0644,
5932*4882a593Smuzhiyun phba->hba_debugfs_root,
5933*4882a593Smuzhiyun phba, &lpfc_debugfs_op_hbqinfo);
5934*4882a593Smuzhiyun
5935*4882a593Smuzhiyun #ifdef LPFC_HDWQ_LOCK_STAT
5936*4882a593Smuzhiyun /* Setup lockstat */
5937*4882a593Smuzhiyun snprintf(name, sizeof(name), "lockstat");
5938*4882a593Smuzhiyun phba->debug_lockstat =
5939*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG | 0644,
5940*4882a593Smuzhiyun phba->hba_debugfs_root,
5941*4882a593Smuzhiyun phba, &lpfc_debugfs_op_lockstat);
5942*4882a593Smuzhiyun if (!phba->debug_lockstat) {
5943*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
5944*4882a593Smuzhiyun "4610 Can't create debugfs lockstat\n");
5945*4882a593Smuzhiyun goto debug_failed;
5946*4882a593Smuzhiyun }
5947*4882a593Smuzhiyun #endif
5948*4882a593Smuzhiyun
5949*4882a593Smuzhiyun /* Setup dumpHBASlim */
5950*4882a593Smuzhiyun if (phba->sli_rev < LPFC_SLI_REV4) {
5951*4882a593Smuzhiyun snprintf(name, sizeof(name), "dumpHBASlim");
5952*4882a593Smuzhiyun phba->debug_dumpHBASlim =
5953*4882a593Smuzhiyun debugfs_create_file(name,
5954*4882a593Smuzhiyun S_IFREG|S_IRUGO|S_IWUSR,
5955*4882a593Smuzhiyun phba->hba_debugfs_root,
5956*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dumpHBASlim);
5957*4882a593Smuzhiyun } else
5958*4882a593Smuzhiyun phba->debug_dumpHBASlim = NULL;
5959*4882a593Smuzhiyun
5960*4882a593Smuzhiyun /* Setup dumpHostSlim */
5961*4882a593Smuzhiyun if (phba->sli_rev < LPFC_SLI_REV4) {
5962*4882a593Smuzhiyun snprintf(name, sizeof(name), "dumpHostSlim");
5963*4882a593Smuzhiyun phba->debug_dumpHostSlim =
5964*4882a593Smuzhiyun debugfs_create_file(name,
5965*4882a593Smuzhiyun S_IFREG|S_IRUGO|S_IWUSR,
5966*4882a593Smuzhiyun phba->hba_debugfs_root,
5967*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dumpHostSlim);
5968*4882a593Smuzhiyun } else
5969*4882a593Smuzhiyun phba->debug_dumpHostSlim = NULL;
5970*4882a593Smuzhiyun
5971*4882a593Smuzhiyun /* Setup DIF Error Injections */
5972*4882a593Smuzhiyun snprintf(name, sizeof(name), "InjErrLBA");
5973*4882a593Smuzhiyun phba->debug_InjErrLBA =
5974*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
5975*4882a593Smuzhiyun phba->hba_debugfs_root,
5976*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
5977*4882a593Smuzhiyun phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
5978*4882a593Smuzhiyun
5979*4882a593Smuzhiyun snprintf(name, sizeof(name), "InjErrNPortID");
5980*4882a593Smuzhiyun phba->debug_InjErrNPortID =
5981*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
5982*4882a593Smuzhiyun phba->hba_debugfs_root,
5983*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
5984*4882a593Smuzhiyun
5985*4882a593Smuzhiyun snprintf(name, sizeof(name), "InjErrWWPN");
5986*4882a593Smuzhiyun phba->debug_InjErrWWPN =
5987*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
5988*4882a593Smuzhiyun phba->hba_debugfs_root,
5989*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
5990*4882a593Smuzhiyun
5991*4882a593Smuzhiyun snprintf(name, sizeof(name), "writeGuardInjErr");
5992*4882a593Smuzhiyun phba->debug_writeGuard =
5993*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
5994*4882a593Smuzhiyun phba->hba_debugfs_root,
5995*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
5996*4882a593Smuzhiyun
5997*4882a593Smuzhiyun snprintf(name, sizeof(name), "writeAppInjErr");
5998*4882a593Smuzhiyun phba->debug_writeApp =
5999*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6000*4882a593Smuzhiyun phba->hba_debugfs_root,
6001*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
6002*4882a593Smuzhiyun
6003*4882a593Smuzhiyun snprintf(name, sizeof(name), "writeRefInjErr");
6004*4882a593Smuzhiyun phba->debug_writeRef =
6005*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6006*4882a593Smuzhiyun phba->hba_debugfs_root,
6007*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
6008*4882a593Smuzhiyun
6009*4882a593Smuzhiyun snprintf(name, sizeof(name), "readGuardInjErr");
6010*4882a593Smuzhiyun phba->debug_readGuard =
6011*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6012*4882a593Smuzhiyun phba->hba_debugfs_root,
6013*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
6014*4882a593Smuzhiyun
6015*4882a593Smuzhiyun snprintf(name, sizeof(name), "readAppInjErr");
6016*4882a593Smuzhiyun phba->debug_readApp =
6017*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6018*4882a593Smuzhiyun phba->hba_debugfs_root,
6019*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
6020*4882a593Smuzhiyun
6021*4882a593Smuzhiyun snprintf(name, sizeof(name), "readRefInjErr");
6022*4882a593Smuzhiyun phba->debug_readRef =
6023*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6024*4882a593Smuzhiyun phba->hba_debugfs_root,
6025*4882a593Smuzhiyun phba, &lpfc_debugfs_op_dif_err);
6026*4882a593Smuzhiyun
6027*4882a593Smuzhiyun /* Setup slow ring trace */
6028*4882a593Smuzhiyun if (lpfc_debugfs_max_slow_ring_trc) {
6029*4882a593Smuzhiyun num = lpfc_debugfs_max_slow_ring_trc - 1;
6030*4882a593Smuzhiyun if (num & lpfc_debugfs_max_slow_ring_trc) {
6031*4882a593Smuzhiyun /* Change to be a power of 2 */
6032*4882a593Smuzhiyun num = lpfc_debugfs_max_slow_ring_trc;
6033*4882a593Smuzhiyun i = 0;
6034*4882a593Smuzhiyun while (num > 1) {
6035*4882a593Smuzhiyun num = num >> 1;
6036*4882a593Smuzhiyun i++;
6037*4882a593Smuzhiyun }
6038*4882a593Smuzhiyun lpfc_debugfs_max_slow_ring_trc = (1 << i);
6039*4882a593Smuzhiyun pr_err("lpfc_debugfs_max_disc_trc changed to "
6040*4882a593Smuzhiyun "%d\n", lpfc_debugfs_max_disc_trc);
6041*4882a593Smuzhiyun }
6042*4882a593Smuzhiyun }
6043*4882a593Smuzhiyun
6044*4882a593Smuzhiyun snprintf(name, sizeof(name), "slow_ring_trace");
6045*4882a593Smuzhiyun phba->debug_slow_ring_trc =
6046*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6047*4882a593Smuzhiyun phba->hba_debugfs_root,
6048*4882a593Smuzhiyun phba, &lpfc_debugfs_op_slow_ring_trc);
6049*4882a593Smuzhiyun if (!phba->slow_ring_trc) {
6050*4882a593Smuzhiyun phba->slow_ring_trc = kmalloc(
6051*4882a593Smuzhiyun (sizeof(struct lpfc_debugfs_trc) *
6052*4882a593Smuzhiyun lpfc_debugfs_max_slow_ring_trc),
6053*4882a593Smuzhiyun GFP_KERNEL);
6054*4882a593Smuzhiyun if (!phba->slow_ring_trc) {
6055*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6056*4882a593Smuzhiyun "0416 Cannot create debugfs "
6057*4882a593Smuzhiyun "slow_ring buffer\n");
6058*4882a593Smuzhiyun goto debug_failed;
6059*4882a593Smuzhiyun }
6060*4882a593Smuzhiyun atomic_set(&phba->slow_ring_trc_cnt, 0);
6061*4882a593Smuzhiyun memset(phba->slow_ring_trc, 0,
6062*4882a593Smuzhiyun (sizeof(struct lpfc_debugfs_trc) *
6063*4882a593Smuzhiyun lpfc_debugfs_max_slow_ring_trc));
6064*4882a593Smuzhiyun }
6065*4882a593Smuzhiyun
6066*4882a593Smuzhiyun snprintf(name, sizeof(name), "nvmeio_trc");
6067*4882a593Smuzhiyun phba->debug_nvmeio_trc =
6068*4882a593Smuzhiyun debugfs_create_file(name, 0644,
6069*4882a593Smuzhiyun phba->hba_debugfs_root,
6070*4882a593Smuzhiyun phba, &lpfc_debugfs_op_nvmeio_trc);
6071*4882a593Smuzhiyun
6072*4882a593Smuzhiyun atomic_set(&phba->nvmeio_trc_cnt, 0);
6073*4882a593Smuzhiyun if (lpfc_debugfs_max_nvmeio_trc) {
6074*4882a593Smuzhiyun num = lpfc_debugfs_max_nvmeio_trc - 1;
6075*4882a593Smuzhiyun if (num & lpfc_debugfs_max_disc_trc) {
6076*4882a593Smuzhiyun /* Change to be a power of 2 */
6077*4882a593Smuzhiyun num = lpfc_debugfs_max_nvmeio_trc;
6078*4882a593Smuzhiyun i = 0;
6079*4882a593Smuzhiyun while (num > 1) {
6080*4882a593Smuzhiyun num = num >> 1;
6081*4882a593Smuzhiyun i++;
6082*4882a593Smuzhiyun }
6083*4882a593Smuzhiyun lpfc_debugfs_max_nvmeio_trc = (1 << i);
6084*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
6085*4882a593Smuzhiyun "0575 lpfc_debugfs_max_nvmeio_trc "
6086*4882a593Smuzhiyun "changed to %d\n",
6087*4882a593Smuzhiyun lpfc_debugfs_max_nvmeio_trc);
6088*4882a593Smuzhiyun }
6089*4882a593Smuzhiyun phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc;
6090*4882a593Smuzhiyun
6091*4882a593Smuzhiyun /* Allocate trace buffer and initialize */
6092*4882a593Smuzhiyun phba->nvmeio_trc = kzalloc(
6093*4882a593Smuzhiyun (sizeof(struct lpfc_debugfs_nvmeio_trc) *
6094*4882a593Smuzhiyun phba->nvmeio_trc_size), GFP_KERNEL);
6095*4882a593Smuzhiyun
6096*4882a593Smuzhiyun if (!phba->nvmeio_trc) {
6097*4882a593Smuzhiyun lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
6098*4882a593Smuzhiyun "0576 Cannot create debugfs "
6099*4882a593Smuzhiyun "nvmeio_trc buffer\n");
6100*4882a593Smuzhiyun goto nvmeio_off;
6101*4882a593Smuzhiyun }
6102*4882a593Smuzhiyun phba->nvmeio_trc_on = 1;
6103*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
6104*4882a593Smuzhiyun phba->nvmeio_trc = NULL;
6105*4882a593Smuzhiyun } else {
6106*4882a593Smuzhiyun nvmeio_off:
6107*4882a593Smuzhiyun phba->nvmeio_trc_size = 0;
6108*4882a593Smuzhiyun phba->nvmeio_trc_on = 0;
6109*4882a593Smuzhiyun phba->nvmeio_trc_output_idx = 0;
6110*4882a593Smuzhiyun phba->nvmeio_trc = NULL;
6111*4882a593Smuzhiyun }
6112*4882a593Smuzhiyun }
6113*4882a593Smuzhiyun
6114*4882a593Smuzhiyun snprintf(name, sizeof(name), "vport%d", vport->vpi);
6115*4882a593Smuzhiyun if (!vport->vport_debugfs_root) {
6116*4882a593Smuzhiyun vport->vport_debugfs_root =
6117*4882a593Smuzhiyun debugfs_create_dir(name, phba->hba_debugfs_root);
6118*4882a593Smuzhiyun atomic_inc(&phba->debugfs_vport_count);
6119*4882a593Smuzhiyun }
6120*4882a593Smuzhiyun
6121*4882a593Smuzhiyun if (lpfc_debugfs_max_disc_trc) {
6122*4882a593Smuzhiyun num = lpfc_debugfs_max_disc_trc - 1;
6123*4882a593Smuzhiyun if (num & lpfc_debugfs_max_disc_trc) {
6124*4882a593Smuzhiyun /* Change to be a power of 2 */
6125*4882a593Smuzhiyun num = lpfc_debugfs_max_disc_trc;
6126*4882a593Smuzhiyun i = 0;
6127*4882a593Smuzhiyun while (num > 1) {
6128*4882a593Smuzhiyun num = num >> 1;
6129*4882a593Smuzhiyun i++;
6130*4882a593Smuzhiyun }
6131*4882a593Smuzhiyun lpfc_debugfs_max_disc_trc = (1 << i);
6132*4882a593Smuzhiyun pr_err("lpfc_debugfs_max_disc_trc changed to %d\n",
6133*4882a593Smuzhiyun lpfc_debugfs_max_disc_trc);
6134*4882a593Smuzhiyun }
6135*4882a593Smuzhiyun }
6136*4882a593Smuzhiyun
6137*4882a593Smuzhiyun vport->disc_trc = kzalloc(
6138*4882a593Smuzhiyun (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
6139*4882a593Smuzhiyun GFP_KERNEL);
6140*4882a593Smuzhiyun
6141*4882a593Smuzhiyun if (!vport->disc_trc) {
6142*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6143*4882a593Smuzhiyun "0418 Cannot create debugfs disc trace "
6144*4882a593Smuzhiyun "buffer\n");
6145*4882a593Smuzhiyun goto debug_failed;
6146*4882a593Smuzhiyun }
6147*4882a593Smuzhiyun atomic_set(&vport->disc_trc_cnt, 0);
6148*4882a593Smuzhiyun
6149*4882a593Smuzhiyun snprintf(name, sizeof(name), "discovery_trace");
6150*4882a593Smuzhiyun vport->debug_disc_trc =
6151*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6152*4882a593Smuzhiyun vport->vport_debugfs_root,
6153*4882a593Smuzhiyun vport, &lpfc_debugfs_op_disc_trc);
6154*4882a593Smuzhiyun snprintf(name, sizeof(name), "nodelist");
6155*4882a593Smuzhiyun vport->debug_nodelist =
6156*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6157*4882a593Smuzhiyun vport->vport_debugfs_root,
6158*4882a593Smuzhiyun vport, &lpfc_debugfs_op_nodelist);
6159*4882a593Smuzhiyun
6160*4882a593Smuzhiyun snprintf(name, sizeof(name), "nvmestat");
6161*4882a593Smuzhiyun vport->debug_nvmestat =
6162*4882a593Smuzhiyun debugfs_create_file(name, 0644,
6163*4882a593Smuzhiyun vport->vport_debugfs_root,
6164*4882a593Smuzhiyun vport, &lpfc_debugfs_op_nvmestat);
6165*4882a593Smuzhiyun
6166*4882a593Smuzhiyun snprintf(name, sizeof(name), "scsistat");
6167*4882a593Smuzhiyun vport->debug_scsistat =
6168*4882a593Smuzhiyun debugfs_create_file(name, 0644,
6169*4882a593Smuzhiyun vport->vport_debugfs_root,
6170*4882a593Smuzhiyun vport, &lpfc_debugfs_op_scsistat);
6171*4882a593Smuzhiyun if (!vport->debug_scsistat) {
6172*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6173*4882a593Smuzhiyun "4611 Cannot create debugfs scsistat\n");
6174*4882a593Smuzhiyun goto debug_failed;
6175*4882a593Smuzhiyun }
6176*4882a593Smuzhiyun
6177*4882a593Smuzhiyun snprintf(name, sizeof(name), "ioktime");
6178*4882a593Smuzhiyun vport->debug_ioktime =
6179*4882a593Smuzhiyun debugfs_create_file(name, 0644,
6180*4882a593Smuzhiyun vport->vport_debugfs_root,
6181*4882a593Smuzhiyun vport, &lpfc_debugfs_op_ioktime);
6182*4882a593Smuzhiyun if (!vport->debug_ioktime) {
6183*4882a593Smuzhiyun lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6184*4882a593Smuzhiyun "0815 Cannot create debugfs ioktime\n");
6185*4882a593Smuzhiyun goto debug_failed;
6186*4882a593Smuzhiyun }
6187*4882a593Smuzhiyun
6188*4882a593Smuzhiyun snprintf(name, sizeof(name), "hdwqstat");
6189*4882a593Smuzhiyun vport->debug_hdwqstat =
6190*4882a593Smuzhiyun debugfs_create_file(name, 0644,
6191*4882a593Smuzhiyun vport->vport_debugfs_root,
6192*4882a593Smuzhiyun vport, &lpfc_debugfs_op_hdwqstat);
6193*4882a593Smuzhiyun
6194*4882a593Smuzhiyun /*
6195*4882a593Smuzhiyun * The following section is for additional directories/files for the
6196*4882a593Smuzhiyun * physical port.
6197*4882a593Smuzhiyun */
6198*4882a593Smuzhiyun
6199*4882a593Smuzhiyun if (!pport_setup)
6200*4882a593Smuzhiyun goto debug_failed;
6201*4882a593Smuzhiyun
6202*4882a593Smuzhiyun /*
6203*4882a593Smuzhiyun * iDiag debugfs root entry points for SLI4 device only
6204*4882a593Smuzhiyun */
6205*4882a593Smuzhiyun if (phba->sli_rev < LPFC_SLI_REV4)
6206*4882a593Smuzhiyun goto debug_failed;
6207*4882a593Smuzhiyun
6208*4882a593Smuzhiyun snprintf(name, sizeof(name), "iDiag");
6209*4882a593Smuzhiyun if (!phba->idiag_root) {
6210*4882a593Smuzhiyun phba->idiag_root =
6211*4882a593Smuzhiyun debugfs_create_dir(name, phba->hba_debugfs_root);
6212*4882a593Smuzhiyun /* Initialize iDiag data structure */
6213*4882a593Smuzhiyun memset(&idiag, 0, sizeof(idiag));
6214*4882a593Smuzhiyun }
6215*4882a593Smuzhiyun
6216*4882a593Smuzhiyun /* iDiag read PCI config space */
6217*4882a593Smuzhiyun snprintf(name, sizeof(name), "pciCfg");
6218*4882a593Smuzhiyun if (!phba->idiag_pci_cfg) {
6219*4882a593Smuzhiyun phba->idiag_pci_cfg =
6220*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6221*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_pciCfg);
6222*4882a593Smuzhiyun idiag.offset.last_rd = 0;
6223*4882a593Smuzhiyun }
6224*4882a593Smuzhiyun
6225*4882a593Smuzhiyun /* iDiag PCI BAR access */
6226*4882a593Smuzhiyun snprintf(name, sizeof(name), "barAcc");
6227*4882a593Smuzhiyun if (!phba->idiag_bar_acc) {
6228*4882a593Smuzhiyun phba->idiag_bar_acc =
6229*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6230*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_barAcc);
6231*4882a593Smuzhiyun idiag.offset.last_rd = 0;
6232*4882a593Smuzhiyun }
6233*4882a593Smuzhiyun
6234*4882a593Smuzhiyun /* iDiag get PCI function queue information */
6235*4882a593Smuzhiyun snprintf(name, sizeof(name), "queInfo");
6236*4882a593Smuzhiyun if (!phba->idiag_que_info) {
6237*4882a593Smuzhiyun phba->idiag_que_info =
6238*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO,
6239*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_queInfo);
6240*4882a593Smuzhiyun }
6241*4882a593Smuzhiyun
6242*4882a593Smuzhiyun /* iDiag access PCI function queue */
6243*4882a593Smuzhiyun snprintf(name, sizeof(name), "queAcc");
6244*4882a593Smuzhiyun if (!phba->idiag_que_acc) {
6245*4882a593Smuzhiyun phba->idiag_que_acc =
6246*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6247*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_queAcc);
6248*4882a593Smuzhiyun }
6249*4882a593Smuzhiyun
6250*4882a593Smuzhiyun /* iDiag access PCI function doorbell registers */
6251*4882a593Smuzhiyun snprintf(name, sizeof(name), "drbAcc");
6252*4882a593Smuzhiyun if (!phba->idiag_drb_acc) {
6253*4882a593Smuzhiyun phba->idiag_drb_acc =
6254*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6255*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_drbAcc);
6256*4882a593Smuzhiyun }
6257*4882a593Smuzhiyun
6258*4882a593Smuzhiyun /* iDiag access PCI function control registers */
6259*4882a593Smuzhiyun snprintf(name, sizeof(name), "ctlAcc");
6260*4882a593Smuzhiyun if (!phba->idiag_ctl_acc) {
6261*4882a593Smuzhiyun phba->idiag_ctl_acc =
6262*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6263*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc);
6264*4882a593Smuzhiyun }
6265*4882a593Smuzhiyun
6266*4882a593Smuzhiyun /* iDiag access mbox commands */
6267*4882a593Smuzhiyun snprintf(name, sizeof(name), "mbxAcc");
6268*4882a593Smuzhiyun if (!phba->idiag_mbx_acc) {
6269*4882a593Smuzhiyun phba->idiag_mbx_acc =
6270*4882a593Smuzhiyun debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6271*4882a593Smuzhiyun phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc);
6272*4882a593Smuzhiyun }
6273*4882a593Smuzhiyun
6274*4882a593Smuzhiyun /* iDiag extents access commands */
6275*4882a593Smuzhiyun if (phba->sli4_hba.extents_in_use) {
6276*4882a593Smuzhiyun snprintf(name, sizeof(name), "extAcc");
6277*4882a593Smuzhiyun if (!phba->idiag_ext_acc) {
6278*4882a593Smuzhiyun phba->idiag_ext_acc =
6279*4882a593Smuzhiyun debugfs_create_file(name,
6280*4882a593Smuzhiyun S_IFREG|S_IRUGO|S_IWUSR,
6281*4882a593Smuzhiyun phba->idiag_root, phba,
6282*4882a593Smuzhiyun &lpfc_idiag_op_extAcc);
6283*4882a593Smuzhiyun }
6284*4882a593Smuzhiyun }
6285*4882a593Smuzhiyun
6286*4882a593Smuzhiyun debug_failed:
6287*4882a593Smuzhiyun return;
6288*4882a593Smuzhiyun #endif
6289*4882a593Smuzhiyun }
6290*4882a593Smuzhiyun
6291*4882a593Smuzhiyun /**
6292*4882a593Smuzhiyun * lpfc_debugfs_terminate - Tear down debugfs infrastructure for this vport
6293*4882a593Smuzhiyun * @vport: The vport pointer to remove from debugfs.
6294*4882a593Smuzhiyun *
6295*4882a593Smuzhiyun * Description:
6296*4882a593Smuzhiyun * When Debugfs is configured this routine removes debugfs file system elements
6297*4882a593Smuzhiyun * that are specific to this vport. It also checks to see if there are any
6298*4882a593Smuzhiyun * users left for the debugfs directories associated with the HBA and driver. If
6299*4882a593Smuzhiyun * this is the last user of the HBA directory or driver directory then it will
6300*4882a593Smuzhiyun * remove those from the debugfs infrastructure as well.
6301*4882a593Smuzhiyun **/
6302*4882a593Smuzhiyun inline void
lpfc_debugfs_terminate(struct lpfc_vport * vport)6303*4882a593Smuzhiyun lpfc_debugfs_terminate(struct lpfc_vport *vport)
6304*4882a593Smuzhiyun {
6305*4882a593Smuzhiyun #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
6306*4882a593Smuzhiyun struct lpfc_hba *phba = vport->phba;
6307*4882a593Smuzhiyun
6308*4882a593Smuzhiyun kfree(vport->disc_trc);
6309*4882a593Smuzhiyun vport->disc_trc = NULL;
6310*4882a593Smuzhiyun
6311*4882a593Smuzhiyun debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
6312*4882a593Smuzhiyun vport->debug_disc_trc = NULL;
6313*4882a593Smuzhiyun
6314*4882a593Smuzhiyun debugfs_remove(vport->debug_nodelist); /* nodelist */
6315*4882a593Smuzhiyun vport->debug_nodelist = NULL;
6316*4882a593Smuzhiyun
6317*4882a593Smuzhiyun debugfs_remove(vport->debug_nvmestat); /* nvmestat */
6318*4882a593Smuzhiyun vport->debug_nvmestat = NULL;
6319*4882a593Smuzhiyun
6320*4882a593Smuzhiyun debugfs_remove(vport->debug_scsistat); /* scsistat */
6321*4882a593Smuzhiyun vport->debug_scsistat = NULL;
6322*4882a593Smuzhiyun
6323*4882a593Smuzhiyun debugfs_remove(vport->debug_ioktime); /* ioktime */
6324*4882a593Smuzhiyun vport->debug_ioktime = NULL;
6325*4882a593Smuzhiyun
6326*4882a593Smuzhiyun debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */
6327*4882a593Smuzhiyun vport->debug_hdwqstat = NULL;
6328*4882a593Smuzhiyun
6329*4882a593Smuzhiyun if (vport->vport_debugfs_root) {
6330*4882a593Smuzhiyun debugfs_remove(vport->vport_debugfs_root); /* vportX */
6331*4882a593Smuzhiyun vport->vport_debugfs_root = NULL;
6332*4882a593Smuzhiyun atomic_dec(&phba->debugfs_vport_count);
6333*4882a593Smuzhiyun }
6334*4882a593Smuzhiyun
6335*4882a593Smuzhiyun if (atomic_read(&phba->debugfs_vport_count) == 0) {
6336*4882a593Smuzhiyun
6337*4882a593Smuzhiyun debugfs_remove(phba->debug_multixri_pools); /* multixripools*/
6338*4882a593Smuzhiyun phba->debug_multixri_pools = NULL;
6339*4882a593Smuzhiyun
6340*4882a593Smuzhiyun debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
6341*4882a593Smuzhiyun phba->debug_hbqinfo = NULL;
6342*4882a593Smuzhiyun
6343*4882a593Smuzhiyun debugfs_remove(phba->debug_ras_log);
6344*4882a593Smuzhiyun phba->debug_ras_log = NULL;
6345*4882a593Smuzhiyun
6346*4882a593Smuzhiyun #ifdef LPFC_HDWQ_LOCK_STAT
6347*4882a593Smuzhiyun debugfs_remove(phba->debug_lockstat); /* lockstat */
6348*4882a593Smuzhiyun phba->debug_lockstat = NULL;
6349*4882a593Smuzhiyun #endif
6350*4882a593Smuzhiyun debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
6351*4882a593Smuzhiyun phba->debug_dumpHBASlim = NULL;
6352*4882a593Smuzhiyun
6353*4882a593Smuzhiyun debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
6354*4882a593Smuzhiyun phba->debug_dumpHostSlim = NULL;
6355*4882a593Smuzhiyun
6356*4882a593Smuzhiyun debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */
6357*4882a593Smuzhiyun phba->debug_InjErrLBA = NULL;
6358*4882a593Smuzhiyun
6359*4882a593Smuzhiyun debugfs_remove(phba->debug_InjErrNPortID);
6360*4882a593Smuzhiyun phba->debug_InjErrNPortID = NULL;
6361*4882a593Smuzhiyun
6362*4882a593Smuzhiyun debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */
6363*4882a593Smuzhiyun phba->debug_InjErrWWPN = NULL;
6364*4882a593Smuzhiyun
6365*4882a593Smuzhiyun debugfs_remove(phba->debug_writeGuard); /* writeGuard */
6366*4882a593Smuzhiyun phba->debug_writeGuard = NULL;
6367*4882a593Smuzhiyun
6368*4882a593Smuzhiyun debugfs_remove(phba->debug_writeApp); /* writeApp */
6369*4882a593Smuzhiyun phba->debug_writeApp = NULL;
6370*4882a593Smuzhiyun
6371*4882a593Smuzhiyun debugfs_remove(phba->debug_writeRef); /* writeRef */
6372*4882a593Smuzhiyun phba->debug_writeRef = NULL;
6373*4882a593Smuzhiyun
6374*4882a593Smuzhiyun debugfs_remove(phba->debug_readGuard); /* readGuard */
6375*4882a593Smuzhiyun phba->debug_readGuard = NULL;
6376*4882a593Smuzhiyun
6377*4882a593Smuzhiyun debugfs_remove(phba->debug_readApp); /* readApp */
6378*4882a593Smuzhiyun phba->debug_readApp = NULL;
6379*4882a593Smuzhiyun
6380*4882a593Smuzhiyun debugfs_remove(phba->debug_readRef); /* readRef */
6381*4882a593Smuzhiyun phba->debug_readRef = NULL;
6382*4882a593Smuzhiyun
6383*4882a593Smuzhiyun kfree(phba->slow_ring_trc);
6384*4882a593Smuzhiyun phba->slow_ring_trc = NULL;
6385*4882a593Smuzhiyun
6386*4882a593Smuzhiyun /* slow_ring_trace */
6387*4882a593Smuzhiyun debugfs_remove(phba->debug_slow_ring_trc);
6388*4882a593Smuzhiyun phba->debug_slow_ring_trc = NULL;
6389*4882a593Smuzhiyun
6390*4882a593Smuzhiyun debugfs_remove(phba->debug_nvmeio_trc);
6391*4882a593Smuzhiyun phba->debug_nvmeio_trc = NULL;
6392*4882a593Smuzhiyun
6393*4882a593Smuzhiyun kfree(phba->nvmeio_trc);
6394*4882a593Smuzhiyun phba->nvmeio_trc = NULL;
6395*4882a593Smuzhiyun
6396*4882a593Smuzhiyun /*
6397*4882a593Smuzhiyun * iDiag release
6398*4882a593Smuzhiyun */
6399*4882a593Smuzhiyun if (phba->sli_rev == LPFC_SLI_REV4) {
6400*4882a593Smuzhiyun /* iDiag extAcc */
6401*4882a593Smuzhiyun debugfs_remove(phba->idiag_ext_acc);
6402*4882a593Smuzhiyun phba->idiag_ext_acc = NULL;
6403*4882a593Smuzhiyun
6404*4882a593Smuzhiyun /* iDiag mbxAcc */
6405*4882a593Smuzhiyun debugfs_remove(phba->idiag_mbx_acc);
6406*4882a593Smuzhiyun phba->idiag_mbx_acc = NULL;
6407*4882a593Smuzhiyun
6408*4882a593Smuzhiyun /* iDiag ctlAcc */
6409*4882a593Smuzhiyun debugfs_remove(phba->idiag_ctl_acc);
6410*4882a593Smuzhiyun phba->idiag_ctl_acc = NULL;
6411*4882a593Smuzhiyun
6412*4882a593Smuzhiyun /* iDiag drbAcc */
6413*4882a593Smuzhiyun debugfs_remove(phba->idiag_drb_acc);
6414*4882a593Smuzhiyun phba->idiag_drb_acc = NULL;
6415*4882a593Smuzhiyun
6416*4882a593Smuzhiyun /* iDiag queAcc */
6417*4882a593Smuzhiyun debugfs_remove(phba->idiag_que_acc);
6418*4882a593Smuzhiyun phba->idiag_que_acc = NULL;
6419*4882a593Smuzhiyun
6420*4882a593Smuzhiyun /* iDiag queInfo */
6421*4882a593Smuzhiyun debugfs_remove(phba->idiag_que_info);
6422*4882a593Smuzhiyun phba->idiag_que_info = NULL;
6423*4882a593Smuzhiyun
6424*4882a593Smuzhiyun /* iDiag barAcc */
6425*4882a593Smuzhiyun debugfs_remove(phba->idiag_bar_acc);
6426*4882a593Smuzhiyun phba->idiag_bar_acc = NULL;
6427*4882a593Smuzhiyun
6428*4882a593Smuzhiyun /* iDiag pciCfg */
6429*4882a593Smuzhiyun debugfs_remove(phba->idiag_pci_cfg);
6430*4882a593Smuzhiyun phba->idiag_pci_cfg = NULL;
6431*4882a593Smuzhiyun
6432*4882a593Smuzhiyun /* Finally remove the iDiag debugfs root */
6433*4882a593Smuzhiyun debugfs_remove(phba->idiag_root);
6434*4882a593Smuzhiyun phba->idiag_root = NULL;
6435*4882a593Smuzhiyun }
6436*4882a593Smuzhiyun
6437*4882a593Smuzhiyun if (phba->hba_debugfs_root) {
6438*4882a593Smuzhiyun debugfs_remove(phba->hba_debugfs_root); /* fnX */
6439*4882a593Smuzhiyun phba->hba_debugfs_root = NULL;
6440*4882a593Smuzhiyun atomic_dec(&lpfc_debugfs_hba_count);
6441*4882a593Smuzhiyun }
6442*4882a593Smuzhiyun
6443*4882a593Smuzhiyun if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
6444*4882a593Smuzhiyun debugfs_remove(lpfc_debugfs_root); /* lpfc */
6445*4882a593Smuzhiyun lpfc_debugfs_root = NULL;
6446*4882a593Smuzhiyun }
6447*4882a593Smuzhiyun }
6448*4882a593Smuzhiyun #endif
6449*4882a593Smuzhiyun return;
6450*4882a593Smuzhiyun }
6451*4882a593Smuzhiyun
6452*4882a593Smuzhiyun /*
6453*4882a593Smuzhiyun * Driver debug utility routines outside of debugfs. The debug utility
6454*4882a593Smuzhiyun * routines implemented here is intended to be used in the instrumented
6455*4882a593Smuzhiyun * debug driver for debugging host or port issues.
6456*4882a593Smuzhiyun */
6457*4882a593Smuzhiyun
6458*4882a593Smuzhiyun /**
6459*4882a593Smuzhiyun * lpfc_debug_dump_all_queues - dump all the queues with a hba
6460*4882a593Smuzhiyun * @phba: Pointer to HBA context object.
6461*4882a593Smuzhiyun *
6462*4882a593Smuzhiyun * This function dumps entries of all the queues asociated with the @phba.
6463*4882a593Smuzhiyun **/
6464*4882a593Smuzhiyun void
lpfc_debug_dump_all_queues(struct lpfc_hba * phba)6465*4882a593Smuzhiyun lpfc_debug_dump_all_queues(struct lpfc_hba *phba)
6466*4882a593Smuzhiyun {
6467*4882a593Smuzhiyun int idx;
6468*4882a593Smuzhiyun
6469*4882a593Smuzhiyun /*
6470*4882a593Smuzhiyun * Dump Work Queues (WQs)
6471*4882a593Smuzhiyun */
6472*4882a593Smuzhiyun lpfc_debug_dump_wq(phba, DUMP_MBX, 0);
6473*4882a593Smuzhiyun lpfc_debug_dump_wq(phba, DUMP_ELS, 0);
6474*4882a593Smuzhiyun lpfc_debug_dump_wq(phba, DUMP_NVMELS, 0);
6475*4882a593Smuzhiyun
6476*4882a593Smuzhiyun for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
6477*4882a593Smuzhiyun lpfc_debug_dump_wq(phba, DUMP_IO, idx);
6478*4882a593Smuzhiyun
6479*4882a593Smuzhiyun lpfc_debug_dump_hdr_rq(phba);
6480*4882a593Smuzhiyun lpfc_debug_dump_dat_rq(phba);
6481*4882a593Smuzhiyun /*
6482*4882a593Smuzhiyun * Dump Complete Queues (CQs)
6483*4882a593Smuzhiyun */
6484*4882a593Smuzhiyun lpfc_debug_dump_cq(phba, DUMP_MBX, 0);
6485*4882a593Smuzhiyun lpfc_debug_dump_cq(phba, DUMP_ELS, 0);
6486*4882a593Smuzhiyun lpfc_debug_dump_cq(phba, DUMP_NVMELS, 0);
6487*4882a593Smuzhiyun
6488*4882a593Smuzhiyun for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
6489*4882a593Smuzhiyun lpfc_debug_dump_cq(phba, DUMP_IO, idx);
6490*4882a593Smuzhiyun
6491*4882a593Smuzhiyun /*
6492*4882a593Smuzhiyun * Dump Event Queues (EQs)
6493*4882a593Smuzhiyun */
6494*4882a593Smuzhiyun for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
6495*4882a593Smuzhiyun lpfc_debug_dump_hba_eq(phba, idx);
6496*4882a593Smuzhiyun }
6497