xref: /openbmc/linux/drivers/scsi/lpfc/lpfc_debugfs.c (revision e29758e7)
1858c9f6cSJames Smart /*******************************************************************
2858c9f6cSJames Smart  * This file is part of the Emulex Linux Device Driver for         *
3858c9f6cSJames Smart  * Fibre Channel Host Bus Adapters.                                *
422871fe3SJustin Tee  * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
53e21d1cbSJames Smart  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.  *
6f25e8e79SJames Smart  * Copyright (C) 2007-2015 Emulex.  All rights reserved.           *
7858c9f6cSJames Smart  * EMULEX and SLI are trademarks of Emulex.                        *
8d080abe0SJames Smart  * www.broadcom.com                                                *
9858c9f6cSJames Smart  *                                                                 *
10858c9f6cSJames Smart  * This program is free software; you can redistribute it and/or   *
11858c9f6cSJames Smart  * modify it under the terms of version 2 of the GNU General       *
12858c9f6cSJames Smart  * Public License as published by the Free Software Foundation.    *
13858c9f6cSJames Smart  * This program is distributed in the hope that it will be useful. *
14858c9f6cSJames Smart  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
15858c9f6cSJames Smart  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
16858c9f6cSJames Smart  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
17858c9f6cSJames Smart  * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
18858c9f6cSJames Smart  * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
19858c9f6cSJames Smart  * more details, a copy of which can be found in the file COPYING  *
20858c9f6cSJames Smart  * included with this package.                                     *
21858c9f6cSJames Smart  *******************************************************************/
22858c9f6cSJames Smart 
23858c9f6cSJames Smart #include <linux/blkdev.h>
24858c9f6cSJames Smart #include <linux/delay.h>
25acf3368fSPaul Gortmaker #include <linux/module.h>
26858c9f6cSJames Smart #include <linux/dma-mapping.h>
27858c9f6cSJames Smart #include <linux/idr.h>
28858c9f6cSJames Smart #include <linux/interrupt.h>
29858c9f6cSJames Smart #include <linux/kthread.h>
305a0e3ad6STejun Heo #include <linux/slab.h>
31858c9f6cSJames Smart #include <linux/pci.h>
32858c9f6cSJames Smart #include <linux/spinlock.h>
33858c9f6cSJames Smart #include <linux/ctype.h>
349e2edb41SJames Smart #include <linux/vmalloc.h>
35858c9f6cSJames Smart 
36858c9f6cSJames Smart #include <scsi/scsi.h>
37858c9f6cSJames Smart #include <scsi/scsi_device.h>
38858c9f6cSJames Smart #include <scsi/scsi_host.h>
39858c9f6cSJames Smart #include <scsi/scsi_transport_fc.h>
40bd2cdd5eSJames Smart #include <scsi/fc/fc_fs.h>
41bd2cdd5eSJames Smart 
42da0436e9SJames Smart #include "lpfc_hw4.h"
43858c9f6cSJames Smart #include "lpfc_hw.h"
44858c9f6cSJames Smart #include "lpfc_sli.h"
45da0436e9SJames Smart #include "lpfc_sli4.h"
46ea2151b4SJames Smart #include "lpfc_nl.h"
47858c9f6cSJames Smart #include "lpfc_disc.h"
48858c9f6cSJames Smart #include "lpfc.h"
49bd2cdd5eSJames Smart #include "lpfc_scsi.h"
50bd2cdd5eSJames Smart #include "lpfc_nvme.h"
51858c9f6cSJames Smart #include "lpfc_logmsg.h"
52858c9f6cSJames Smart #include "lpfc_crtn.h"
53858c9f6cSJames Smart #include "lpfc_vport.h"
54858c9f6cSJames Smart #include "lpfc_version.h"
55c95d6c6cSJames Smart #include "lpfc_compat.h"
56858c9f6cSJames Smart #include "lpfc_debugfs.h"
57b76f2dc9SJames Smart #include "lpfc_bsg.h"
58858c9f6cSJames Smart 
59923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
603621a710SJames Smart /*
61e59058c4SJames Smart  * debugfs interface
62858c9f6cSJames Smart  *
63858c9f6cSJames Smart  * To access this interface the user should:
64156f5a78SGeunSik Lim  * # mount -t debugfs none /sys/kernel/debug
65858c9f6cSJames Smart  *
66e59058c4SJames Smart  * The lpfc debugfs directory hierarchy is:
672a622bfbSJames Smart  * /sys/kernel/debug/lpfc/fnX/vportY
682a622bfbSJames Smart  * where X is the lpfc hba function unique_id
69858c9f6cSJames Smart  * where Y is the vport VPI on that hba
70858c9f6cSJames Smart  *
71858c9f6cSJames Smart  * Debugging services available per vport:
72858c9f6cSJames Smart  * discovery_trace
73858c9f6cSJames Smart  * This is an ACSII readable file that contains a trace of the last
74858c9f6cSJames Smart  * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
75e59058c4SJames Smart  * See lpfc_debugfs.h for different categories of  discovery events.
76e59058c4SJames Smart  * To enable the discovery trace, the following module parameters must be set:
77858c9f6cSJames Smart  * lpfc_debugfs_enable=1         Turns on lpfc debugfs filesystem support
78858c9f6cSJames Smart  * lpfc_debugfs_max_disc_trc=X   Where X is the event trace depth for
79858c9f6cSJames Smart  *                               EACH vport. X MUST also be a power of 2.
80858c9f6cSJames Smart  * lpfc_debugfs_mask_disc_trc=Y  Where Y is an event mask as defined in
81858c9f6cSJames Smart  *                               lpfc_debugfs.h .
82e59058c4SJames Smart  *
83e59058c4SJames Smart  * slow_ring_trace
84e59058c4SJames Smart  * This is an ACSII readable file that contains a trace of the last
85e59058c4SJames Smart  * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA.
86e59058c4SJames Smart  * To enable the slow ring trace, the following module parameters must be set:
87e59058c4SJames Smart  * lpfc_debugfs_enable=1         Turns on lpfc debugfs filesystem support
88e59058c4SJames Smart  * lpfc_debugfs_max_slow_ring_trc=X   Where X is the event trace depth for
89e59058c4SJames Smart  *                               the HBA. X MUST also be a power of 2.
90858c9f6cSJames Smart  */
9151ef4c26SJames Smart static int lpfc_debugfs_enable = 1;
92ab56dc2eSJames Smart module_param(lpfc_debugfs_enable, int, S_IRUGO);
93858c9f6cSJames Smart MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
94858c9f6cSJames Smart 
95a58cbd52SJames Smart /* This MUST be a power of 2 */
96c95d6c6cSJames Smart static int lpfc_debugfs_max_disc_trc;
97ab56dc2eSJames Smart module_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO);
98858c9f6cSJames Smart MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
99858c9f6cSJames Smart 	"Set debugfs discovery trace depth");
100858c9f6cSJames Smart 
101a58cbd52SJames Smart /* This MUST be a power of 2 */
102c95d6c6cSJames Smart static int lpfc_debugfs_max_slow_ring_trc;
103ab56dc2eSJames Smart module_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO);
104a58cbd52SJames Smart MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
105a58cbd52SJames Smart 	"Set debugfs slow ring trace depth");
106a58cbd52SJames Smart 
107bd2cdd5eSJames Smart /* This MUST be a power of 2 */
108bd2cdd5eSJames Smart static int lpfc_debugfs_max_nvmeio_trc;
109bd2cdd5eSJames Smart module_param(lpfc_debugfs_max_nvmeio_trc, int, 0444);
110bd2cdd5eSJames Smart MODULE_PARM_DESC(lpfc_debugfs_max_nvmeio_trc,
111bd2cdd5eSJames Smart 		 "Set debugfs NVME IO trace depth");
112bd2cdd5eSJames Smart 
113a257bf90SJames Smart static int lpfc_debugfs_mask_disc_trc;
114ab56dc2eSJames Smart module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO);
115858c9f6cSJames Smart MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
116858c9f6cSJames Smart 	"Set debugfs discovery trace mask");
117858c9f6cSJames Smart 
118858c9f6cSJames Smart #include <linux/debugfs.h>
119858c9f6cSJames Smart 
120311464ecSJames Smart static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
121311464ecSJames Smart static unsigned long lpfc_debugfs_start_time = 0L;
122858c9f6cSJames Smart 
1232a622bfbSJames Smart /* iDiag */
1242a622bfbSJames Smart static struct lpfc_idiag idiag;
1252a622bfbSJames Smart 
126e59058c4SJames Smart /**
1273621a710SJames Smart  * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer
128e59058c4SJames Smart  * @vport: The vport to gather the log info from.
129e59058c4SJames Smart  * @buf: The buffer to dump log into.
130e59058c4SJames Smart  * @size: The maximum amount of data to process.
131e59058c4SJames Smart  *
132e59058c4SJames Smart  * Description:
133e59058c4SJames Smart  * This routine gathers the lpfc discovery debugfs data from the @vport and
134e59058c4SJames Smart  * dumps it to @buf up to @size number of bytes. It will start at the next entry
135e59058c4SJames Smart  * in the log and process the log until the end of the buffer. Then it will
136e59058c4SJames Smart  * gather from the beginning of the log and process until the current entry.
137e59058c4SJames Smart  *
138e59058c4SJames Smart  * Notes:
139e59058c4SJames Smart  * Discovery logging will be disabled while while this routine dumps the log.
140e59058c4SJames Smart  *
141e59058c4SJames Smart  * Return Value:
142e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
143e59058c4SJames Smart  * not exceed @size.
144e59058c4SJames Smart  **/
145858c9f6cSJames Smart static int
lpfc_debugfs_disc_trc_data(struct lpfc_vport * vport,char * buf,int size)146858c9f6cSJames Smart lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
147858c9f6cSJames Smart {
148858c9f6cSJames Smart 	int i, index, len, enable;
149858c9f6cSJames Smart 	uint32_t ms;
150a58cbd52SJames Smart 	struct lpfc_debugfs_trc *dtp;
151b76f2dc9SJames Smart 	char *buffer;
152b76f2dc9SJames Smart 
153b76f2dc9SJames Smart 	buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
154b76f2dc9SJames Smart 	if (!buffer)
155b76f2dc9SJames Smart 		return 0;
156858c9f6cSJames Smart 
157858c9f6cSJames Smart 	enable = lpfc_debugfs_enable;
158858c9f6cSJames Smart 	lpfc_debugfs_enable = 0;
159858c9f6cSJames Smart 
160858c9f6cSJames Smart 	len = 0;
161858c9f6cSJames Smart 	index = (atomic_read(&vport->disc_trc_cnt) + 1) &
162858c9f6cSJames Smart 		(lpfc_debugfs_max_disc_trc - 1);
163858c9f6cSJames Smart 	for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
164858c9f6cSJames Smart 		dtp = vport->disc_trc + i;
165858c9f6cSJames Smart 		if (!dtp->fmt)
166858c9f6cSJames Smart 			continue;
167858c9f6cSJames Smart 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
168a58cbd52SJames Smart 		snprintf(buffer,
169a58cbd52SJames Smart 			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
170858c9f6cSJames Smart 			dtp->seq_cnt, ms, dtp->fmt);
171e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, buffer,
172858c9f6cSJames Smart 			dtp->data1, dtp->data2, dtp->data3);
173858c9f6cSJames Smart 	}
174858c9f6cSJames Smart 	for (i = 0; i < index; i++) {
175858c9f6cSJames Smart 		dtp = vport->disc_trc + i;
176858c9f6cSJames Smart 		if (!dtp->fmt)
177858c9f6cSJames Smart 			continue;
178858c9f6cSJames Smart 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
179a58cbd52SJames Smart 		snprintf(buffer,
180a58cbd52SJames Smart 			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
181858c9f6cSJames Smart 			dtp->seq_cnt, ms, dtp->fmt);
182e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, buffer,
183858c9f6cSJames Smart 			dtp->data1, dtp->data2, dtp->data3);
184858c9f6cSJames Smart 	}
185858c9f6cSJames Smart 
186858c9f6cSJames Smart 	lpfc_debugfs_enable = enable;
187b76f2dc9SJames Smart 	kfree(buffer);
188b76f2dc9SJames Smart 
189858c9f6cSJames Smart 	return len;
190858c9f6cSJames Smart }
191858c9f6cSJames Smart 
192e59058c4SJames Smart /**
1933621a710SJames Smart  * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer
194e59058c4SJames Smart  * @phba: The HBA to gather the log info from.
195e59058c4SJames Smart  * @buf: The buffer to dump log into.
196e59058c4SJames Smart  * @size: The maximum amount of data to process.
197e59058c4SJames Smart  *
198e59058c4SJames Smart  * Description:
199e59058c4SJames Smart  * This routine gathers the lpfc slow ring debugfs data from the @phba and
200e59058c4SJames Smart  * dumps it to @buf up to @size number of bytes. It will start at the next entry
201e59058c4SJames Smart  * in the log and process the log until the end of the buffer. Then it will
202e59058c4SJames Smart  * gather from the beginning of the log and process until the current entry.
203e59058c4SJames Smart  *
204e59058c4SJames Smart  * Notes:
205e59058c4SJames Smart  * Slow ring logging will be disabled while while this routine dumps the log.
206e59058c4SJames Smart  *
207e59058c4SJames Smart  * Return Value:
208e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
209e59058c4SJames Smart  * not exceed @size.
210e59058c4SJames Smart  **/
211858c9f6cSJames Smart static int
lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba * phba,char * buf,int size)212a58cbd52SJames Smart lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
213a58cbd52SJames Smart {
214a58cbd52SJames Smart 	int i, index, len, enable;
215a58cbd52SJames Smart 	uint32_t ms;
216a58cbd52SJames Smart 	struct lpfc_debugfs_trc *dtp;
217b76f2dc9SJames Smart 	char *buffer;
218a58cbd52SJames Smart 
219b76f2dc9SJames Smart 	buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
220b76f2dc9SJames Smart 	if (!buffer)
221b76f2dc9SJames Smart 		return 0;
222a58cbd52SJames Smart 
223a58cbd52SJames Smart 	enable = lpfc_debugfs_enable;
224a58cbd52SJames Smart 	lpfc_debugfs_enable = 0;
225a58cbd52SJames Smart 
226a58cbd52SJames Smart 	len = 0;
227a58cbd52SJames Smart 	index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) &
228a58cbd52SJames Smart 		(lpfc_debugfs_max_slow_ring_trc - 1);
229a58cbd52SJames Smart 	for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) {
230a58cbd52SJames Smart 		dtp = phba->slow_ring_trc + i;
231a58cbd52SJames Smart 		if (!dtp->fmt)
232a58cbd52SJames Smart 			continue;
233a58cbd52SJames Smart 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
234a58cbd52SJames Smart 		snprintf(buffer,
235a58cbd52SJames Smart 			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
236a58cbd52SJames Smart 			dtp->seq_cnt, ms, dtp->fmt);
237e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, buffer,
238a58cbd52SJames Smart 			dtp->data1, dtp->data2, dtp->data3);
239a58cbd52SJames Smart 	}
240a58cbd52SJames Smart 	for (i = 0; i < index; i++) {
241a58cbd52SJames Smart 		dtp = phba->slow_ring_trc + i;
242a58cbd52SJames Smart 		if (!dtp->fmt)
243a58cbd52SJames Smart 			continue;
244a58cbd52SJames Smart 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
245a58cbd52SJames Smart 		snprintf(buffer,
246a58cbd52SJames Smart 			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
247a58cbd52SJames Smart 			dtp->seq_cnt, ms, dtp->fmt);
248e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, buffer,
249a58cbd52SJames Smart 			dtp->data1, dtp->data2, dtp->data3);
250a58cbd52SJames Smart 	}
251a58cbd52SJames Smart 
252a58cbd52SJames Smart 	lpfc_debugfs_enable = enable;
253b76f2dc9SJames Smart 	kfree(buffer);
254b76f2dc9SJames Smart 
255a58cbd52SJames Smart 	return len;
256a58cbd52SJames Smart }
257a58cbd52SJames Smart 
258311464ecSJames Smart static int lpfc_debugfs_last_hbq = -1;
25978b2d852SJames Smart 
260e59058c4SJames Smart /**
2613621a710SJames Smart  * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer
262e59058c4SJames Smart  * @phba: The HBA to gather host buffer info from.
263e59058c4SJames Smart  * @buf: The buffer to dump log into.
264e59058c4SJames Smart  * @size: The maximum amount of data to process.
265e59058c4SJames Smart  *
266e59058c4SJames Smart  * Description:
267e59058c4SJames Smart  * This routine dumps the host buffer queue info from the @phba to @buf up to
268e59058c4SJames Smart  * @size number of bytes. A header that describes the current hbq state will be
269e59058c4SJames Smart  * dumped to @buf first and then info on each hbq entry will be dumped to @buf
270e59058c4SJames Smart  * until @size bytes have been dumped or all the hbq info has been dumped.
271e59058c4SJames Smart  *
272e59058c4SJames Smart  * Notes:
273e59058c4SJames Smart  * This routine will rotate through each configured HBQ each time called.
274e59058c4SJames Smart  *
275e59058c4SJames Smart  * Return Value:
276e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
277e59058c4SJames Smart  * not exceed @size.
278e59058c4SJames Smart  **/
27978b2d852SJames Smart static int
lpfc_debugfs_hbqinfo_data(struct lpfc_hba * phba,char * buf,int size)28078b2d852SJames Smart lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
28178b2d852SJames Smart {
28278b2d852SJames Smart 	int len = 0;
283eb016566SJames Smart 	int i, j, found, posted, low;
28478b2d852SJames Smart 	uint32_t phys, raw_index, getidx;
28578b2d852SJames Smart 	struct lpfc_hbq_init *hip;
28678b2d852SJames Smart 	struct hbq_s *hbqs;
28778b2d852SJames Smart 	struct lpfc_hbq_entry *hbqe;
28878b2d852SJames Smart 	struct lpfc_dmabuf *d_buf;
28978b2d852SJames Smart 	struct hbq_dmabuf *hbq_buf;
29078b2d852SJames Smart 
2913772a991SJames Smart 	if (phba->sli_rev != 3)
2923772a991SJames Smart 		return 0;
293eb016566SJames Smart 
29478b2d852SJames Smart 	spin_lock_irq(&phba->hbalock);
29578b2d852SJames Smart 
29678b2d852SJames Smart 	/* toggle between multiple hbqs, if any */
29778b2d852SJames Smart 	i = lpfc_sli_hbq_count();
29878b2d852SJames Smart 	if (i > 1) {
29978b2d852SJames Smart 		 lpfc_debugfs_last_hbq++;
30078b2d852SJames Smart 		 if (lpfc_debugfs_last_hbq >= i)
30178b2d852SJames Smart 			lpfc_debugfs_last_hbq = 0;
30278b2d852SJames Smart 	}
30378b2d852SJames Smart 	else
30478b2d852SJames Smart 		lpfc_debugfs_last_hbq = 0;
30578b2d852SJames Smart 
30678b2d852SJames Smart 	i = lpfc_debugfs_last_hbq;
30778b2d852SJames Smart 
308e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len, "HBQ %d Info\n", i);
30978b2d852SJames Smart 
31051ef4c26SJames Smart 	hbqs =  &phba->hbqs[i];
31178b2d852SJames Smart 	posted = 0;
31251ef4c26SJames Smart 	list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list)
31378b2d852SJames Smart 		posted++;
31478b2d852SJames Smart 
31578b2d852SJames Smart 	hip =  lpfc_hbq_defs[i];
316e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len,
31778b2d852SJames Smart 		"idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
31878b2d852SJames Smart 		hip->hbq_index, hip->profile, hip->rn,
31978b2d852SJames Smart 		hip->buffer_count, hip->init_count, hip->add_count, posted);
32078b2d852SJames Smart 
32178b2d852SJames Smart 	raw_index = phba->hbq_get[i];
32278b2d852SJames Smart 	getidx = le32_to_cpu(raw_index);
323e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len,
3241ab62072SColin Ian King 		"entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
325a8adb832SJames Smart 		hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
326a8adb832SJames Smart 		hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
32778b2d852SJames Smart 
32851ef4c26SJames Smart 	hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
32978b2d852SJames Smart 	for (j=0; j<hbqs->entry_count; j++) {
330e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len,
33178b2d852SJames Smart 			"%03d: %08x %04x %05x ", j,
332a8adb832SJames Smart 			le32_to_cpu(hbqe->bde.addrLow),
333a8adb832SJames Smart 			le32_to_cpu(hbqe->bde.tus.w),
334a8adb832SJames Smart 			le32_to_cpu(hbqe->buffer_tag));
33578b2d852SJames Smart 		i = 0;
33678b2d852SJames Smart 		found = 0;
33778b2d852SJames Smart 
33878b2d852SJames Smart 		/* First calculate if slot has an associated posted buffer */
33978b2d852SJames Smart 		low = hbqs->hbqPutIdx - posted;
34078b2d852SJames Smart 		if (low >= 0) {
34178b2d852SJames Smart 			if ((j >= hbqs->hbqPutIdx) || (j < low)) {
342e7f7b6f3SSilvio Cesare 				len +=  scnprintf(buf + len, size - len,
343e7f7b6f3SSilvio Cesare 						"Unused\n");
34478b2d852SJames Smart 				goto skipit;
34578b2d852SJames Smart 			}
34678b2d852SJames Smart 		}
34778b2d852SJames Smart 		else {
34878b2d852SJames Smart 			if ((j >= hbqs->hbqPutIdx) &&
34978b2d852SJames Smart 				(j < (hbqs->entry_count+low))) {
350e7f7b6f3SSilvio Cesare 				len +=  scnprintf(buf + len, size - len,
351e7f7b6f3SSilvio Cesare 						"Unused\n");
35278b2d852SJames Smart 				goto skipit;
35378b2d852SJames Smart 			}
35478b2d852SJames Smart 		}
35578b2d852SJames Smart 
35678b2d852SJames Smart 		/* Get the Buffer info for the posted buffer */
35751ef4c26SJames Smart 		list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
35878b2d852SJames Smart 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
35978b2d852SJames Smart 			phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
360a8adb832SJames Smart 			if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
361e7f7b6f3SSilvio Cesare 				len +=  scnprintf(buf+len, size-len,
36232350664SJames Smart 					"Buf%d: x%px %06x\n", i,
36378b2d852SJames Smart 					hbq_buf->dbuf.virt, hbq_buf->tag);
36478b2d852SJames Smart 				found = 1;
36578b2d852SJames Smart 				break;
36678b2d852SJames Smart 			}
36778b2d852SJames Smart 			i++;
36878b2d852SJames Smart 		}
36978b2d852SJames Smart 		if (!found) {
370e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf+len, size-len, "No DMAinfo?\n");
37178b2d852SJames Smart 		}
37278b2d852SJames Smart skipit:
37378b2d852SJames Smart 		hbqe++;
37478b2d852SJames Smart 		if (len > LPFC_HBQINFO_SIZE - 54)
37578b2d852SJames Smart 			break;
37678b2d852SJames Smart 	}
37778b2d852SJames Smart 	spin_unlock_irq(&phba->hbalock);
37878b2d852SJames Smart 	return len;
37978b2d852SJames Smart }
38078b2d852SJames Smart 
3816a828b0fSJames Smart static int lpfc_debugfs_last_xripool;
3826a828b0fSJames Smart 
3836a828b0fSJames Smart /**
3842c6400b7SLee Jones  * lpfc_debugfs_commonxripools_data - Dump Hardware Queue info to a buffer
3856a828b0fSJames Smart  * @phba: The HBA to gather host buffer info from.
3866a828b0fSJames Smart  * @buf: The buffer to dump log into.
3876a828b0fSJames Smart  * @size: The maximum amount of data to process.
3886a828b0fSJames Smart  *
3896a828b0fSJames Smart  * Description:
3906a828b0fSJames Smart  * This routine dumps the Hardware Queue info from the @phba to @buf up to
3916a828b0fSJames Smart  * @size number of bytes. A header that describes the current hdwq state will be
3926a828b0fSJames Smart  * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
3936a828b0fSJames Smart  * until @size bytes have been dumped or all the hdwq info has been dumped.
3946a828b0fSJames Smart  *
3956a828b0fSJames Smart  * Notes:
3966a828b0fSJames Smart  * This routine will rotate through each configured Hardware Queue each
3976a828b0fSJames Smart  * time called.
3986a828b0fSJames Smart  *
3996a828b0fSJames Smart  * Return Value:
4006a828b0fSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
4016a828b0fSJames Smart  * not exceed @size.
4026a828b0fSJames Smart  **/
4036a828b0fSJames Smart static int
lpfc_debugfs_commonxripools_data(struct lpfc_hba * phba,char * buf,int size)4046a828b0fSJames Smart lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size)
4056a828b0fSJames Smart {
4066a828b0fSJames Smart 	struct lpfc_sli4_hdw_queue *qp;
4076a828b0fSJames Smart 	int len = 0;
4086a828b0fSJames Smart 	int i, out;
4096a828b0fSJames Smart 	unsigned long iflag;
4106a828b0fSJames Smart 
4116a828b0fSJames Smart 	for (i = 0; i < phba->cfg_hdw_queue; i++) {
4126a828b0fSJames Smart 		if (len > (LPFC_DUMP_MULTIXRIPOOL_SIZE - 80))
4136a828b0fSJames Smart 			break;
4146a828b0fSJames Smart 		qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool];
4156a828b0fSJames Smart 
416e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i);
417c00f62e6SJames Smart 		spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
4186a828b0fSJames Smart 		spin_lock(&qp->io_buf_list_get_lock);
4196a828b0fSJames Smart 		spin_lock(&qp->io_buf_list_put_lock);
4206a828b0fSJames Smart 		out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs +
4216a828b0fSJames Smart 			qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs);
422e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
4236a828b0fSJames Smart 				 "tot:%d get:%d put:%d mt:%d "
4246a828b0fSJames Smart 				 "ABTS scsi:%d nvme:%d Out:%d\n",
4256a828b0fSJames Smart 			qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs,
4266a828b0fSJames Smart 			qp->empty_io_bufs, qp->abts_scsi_io_bufs,
4276a828b0fSJames Smart 			qp->abts_nvme_io_bufs, out);
4286a828b0fSJames Smart 		spin_unlock(&qp->io_buf_list_put_lock);
4296a828b0fSJames Smart 		spin_unlock(&qp->io_buf_list_get_lock);
430c00f62e6SJames Smart 		spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag);
4316a828b0fSJames Smart 
4326a828b0fSJames Smart 		lpfc_debugfs_last_xripool++;
4336a828b0fSJames Smart 		if (lpfc_debugfs_last_xripool >= phba->cfg_hdw_queue)
4346a828b0fSJames Smart 			lpfc_debugfs_last_xripool = 0;
4356a828b0fSJames Smart 	}
4366a828b0fSJames Smart 
4376a828b0fSJames Smart 	return len;
4386a828b0fSJames Smart }
4396a828b0fSJames Smart 
440c490850aSJames Smart /**
441c490850aSJames Smart  * lpfc_debugfs_multixripools_data - Display multi-XRI pools information
442c490850aSJames Smart  * @phba: The HBA to gather host buffer info from.
443c490850aSJames Smart  * @buf: The buffer to dump log into.
444c490850aSJames Smart  * @size: The maximum amount of data to process.
445c490850aSJames Smart  *
446c490850aSJames Smart  * Description:
447c490850aSJames Smart  * This routine displays current multi-XRI pools information including XRI
448c490850aSJames Smart  * count in public, private and txcmplq. It also displays current high and
449c490850aSJames Smart  * low watermark.
450c490850aSJames Smart  *
451c490850aSJames Smart  * Return Value:
452c490850aSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
453c490850aSJames Smart  * not exceed @size.
454c490850aSJames Smart  **/
455c490850aSJames Smart static int
lpfc_debugfs_multixripools_data(struct lpfc_hba * phba,char * buf,int size)456c490850aSJames Smart lpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size)
457c490850aSJames Smart {
458c490850aSJames Smart 	u32 i;
459c490850aSJames Smart 	u32 hwq_count;
460c490850aSJames Smart 	struct lpfc_sli4_hdw_queue *qp;
461c490850aSJames Smart 	struct lpfc_multixri_pool *multixri_pool;
462c490850aSJames Smart 	struct lpfc_pvt_pool *pvt_pool;
463c490850aSJames Smart 	struct lpfc_pbl_pool *pbl_pool;
464c490850aSJames Smart 	u32 txcmplq_cnt;
465c490850aSJames Smart 	char tmp[LPFC_DEBUG_OUT_LINE_SZ] = {0};
466c490850aSJames Smart 
4676a828b0fSJames Smart 	if (phba->sli_rev != LPFC_SLI_REV4)
4686a828b0fSJames Smart 		return 0;
4696a828b0fSJames Smart 
4706a828b0fSJames Smart 	if (!phba->sli4_hba.hdwq)
4716a828b0fSJames Smart 		return 0;
4726a828b0fSJames Smart 
4736a828b0fSJames Smart 	if (!phba->cfg_xri_rebalancing) {
4746a828b0fSJames Smart 		i = lpfc_debugfs_commonxripools_data(phba, buf, size);
4756a828b0fSJames Smart 		return i;
4766a828b0fSJames Smart 	}
4776a828b0fSJames Smart 
478c490850aSJames Smart 	/*
479c490850aSJames Smart 	 * Pbl: Current number of free XRIs in public pool
480c490850aSJames Smart 	 * Pvt: Current number of free XRIs in private pool
481c490850aSJames Smart 	 * Busy: Current number of outstanding XRIs
482c490850aSJames Smart 	 * HWM: Current high watermark
483c490850aSJames Smart 	 * pvt_empty: Incremented by 1 when IO submission fails (no xri)
484c490850aSJames Smart 	 * pbl_empty: Incremented by 1 when all pbl_pool are empty during
485c490850aSJames Smart 	 *            IO submission
486c490850aSJames Smart 	 */
487c490850aSJames Smart 	scnprintf(tmp, sizeof(tmp),
488c490850aSJames Smart 		  "HWQ:  Pbl  Pvt Busy  HWM |  pvt_empty  pbl_empty ");
489c490850aSJames Smart 	if (strlcat(buf, tmp, size) >= size)
490c490850aSJames Smart 		return strnlen(buf, size);
491c490850aSJames Smart 
492c490850aSJames Smart #ifdef LPFC_MXP_STAT
493c490850aSJames Smart 	/*
494c490850aSJames Smart 	 * MAXH: Max high watermark seen so far
495c490850aSJames Smart 	 * above_lmt: Incremented by 1 if xri_owned > xri_limit during
496c490850aSJames Smart 	 *            IO submission
497c490850aSJames Smart 	 * below_lmt: Incremented by 1 if xri_owned <= xri_limit  during
498c490850aSJames Smart 	 *            IO submission
499c490850aSJames Smart 	 * locPbl_hit: Incremented by 1 if successfully get a batch of XRI from
500c490850aSJames Smart 	 *             local pbl_pool
501c490850aSJames Smart 	 * othPbl_hit: Incremented by 1 if successfully get a batch of XRI from
502c490850aSJames Smart 	 *             other pbl_pool
503c490850aSJames Smart 	 */
504c490850aSJames Smart 	scnprintf(tmp, sizeof(tmp),
505c490850aSJames Smart 		  "MAXH  above_lmt  below_lmt locPbl_hit othPbl_hit");
506c490850aSJames Smart 	if (strlcat(buf, tmp, size) >= size)
507c490850aSJames Smart 		return strnlen(buf, size);
508c490850aSJames Smart 
509c490850aSJames Smart 	/*
510c490850aSJames Smart 	 * sPbl: snapshot of Pbl 15 sec after stat gets cleared
511c490850aSJames Smart 	 * sPvt: snapshot of Pvt 15 sec after stat gets cleared
512c490850aSJames Smart 	 * sBusy: snapshot of Busy 15 sec after stat gets cleared
513c490850aSJames Smart 	 */
514c490850aSJames Smart 	scnprintf(tmp, sizeof(tmp),
515c490850aSJames Smart 		  " | sPbl sPvt sBusy");
516c490850aSJames Smart 	if (strlcat(buf, tmp, size) >= size)
517c490850aSJames Smart 		return strnlen(buf, size);
518c490850aSJames Smart #endif
519c490850aSJames Smart 
520c490850aSJames Smart 	scnprintf(tmp, sizeof(tmp), "\n");
521c490850aSJames Smart 	if (strlcat(buf, tmp, size) >= size)
522c490850aSJames Smart 		return strnlen(buf, size);
523c490850aSJames Smart 
524c490850aSJames Smart 	hwq_count = phba->cfg_hdw_queue;
525c490850aSJames Smart 	for (i = 0; i < hwq_count; i++) {
526c490850aSJames Smart 		qp = &phba->sli4_hba.hdwq[i];
527c490850aSJames Smart 		multixri_pool = qp->p_multixri_pool;
528c490850aSJames Smart 		if (!multixri_pool)
529c490850aSJames Smart 			continue;
530c490850aSJames Smart 		pbl_pool = &multixri_pool->pbl_pool;
531c490850aSJames Smart 		pvt_pool = &multixri_pool->pvt_pool;
532c00f62e6SJames Smart 		txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt;
533c490850aSJames Smart 
534c490850aSJames Smart 		scnprintf(tmp, sizeof(tmp),
535c490850aSJames Smart 			  "%03d: %4d %4d %4d %4d | %10d %10d ",
536c490850aSJames Smart 			  i, pbl_pool->count, pvt_pool->count,
537c490850aSJames Smart 			  txcmplq_cnt, pvt_pool->high_watermark,
538c490850aSJames Smart 			  qp->empty_io_bufs, multixri_pool->pbl_empty_count);
539c490850aSJames Smart 		if (strlcat(buf, tmp, size) >= size)
540c490850aSJames Smart 			break;
541c490850aSJames Smart 
542c490850aSJames Smart #ifdef LPFC_MXP_STAT
543c490850aSJames Smart 		scnprintf(tmp, sizeof(tmp),
544c490850aSJames Smart 			  "%4d %10d %10d %10d %10d",
545c490850aSJames Smart 			  multixri_pool->stat_max_hwm,
546c490850aSJames Smart 			  multixri_pool->above_limit_count,
547c490850aSJames Smart 			  multixri_pool->below_limit_count,
548c490850aSJames Smart 			  multixri_pool->local_pbl_hit_count,
549c490850aSJames Smart 			  multixri_pool->other_pbl_hit_count);
550c490850aSJames Smart 		if (strlcat(buf, tmp, size) >= size)
551c490850aSJames Smart 			break;
552c490850aSJames Smart 
553c490850aSJames Smart 		scnprintf(tmp, sizeof(tmp),
554c490850aSJames Smart 			  " | %4d %4d %5d",
555c490850aSJames Smart 			  multixri_pool->stat_pbl_count,
556c490850aSJames Smart 			  multixri_pool->stat_pvt_count,
557c490850aSJames Smart 			  multixri_pool->stat_busy_count);
558c490850aSJames Smart 		if (strlcat(buf, tmp, size) >= size)
559c490850aSJames Smart 			break;
560c490850aSJames Smart #endif
561c490850aSJames Smart 
562c490850aSJames Smart 		scnprintf(tmp, sizeof(tmp), "\n");
563c490850aSJames Smart 		if (strlcat(buf, tmp, size) >= size)
564c490850aSJames Smart 			break;
565c490850aSJames Smart 	}
566c490850aSJames Smart 	return strnlen(buf, size);
567c490850aSJames Smart }
568c490850aSJames Smart 
5696a828b0fSJames Smart 
5706a828b0fSJames Smart #ifdef LPFC_HDWQ_LOCK_STAT
5716a828b0fSJames Smart static int lpfc_debugfs_last_lock;
5725e5b511dSJames Smart 
5735e5b511dSJames Smart /**
5746a828b0fSJames Smart  * lpfc_debugfs_lockstat_data - Dump Hardware Queue info to a buffer
5755e5b511dSJames Smart  * @phba: The HBA to gather host buffer info from.
5765e5b511dSJames Smart  * @buf: The buffer to dump log into.
5775e5b511dSJames Smart  * @size: The maximum amount of data to process.
5785e5b511dSJames Smart  *
5795e5b511dSJames Smart  * Description:
5805e5b511dSJames Smart  * This routine dumps the Hardware Queue info from the @phba to @buf up to
5815e5b511dSJames Smart  * @size number of bytes. A header that describes the current hdwq state will be
5825e5b511dSJames Smart  * dumped to @buf first and then info on each hdwq entry will be dumped to @buf
5835e5b511dSJames Smart  * until @size bytes have been dumped or all the hdwq info has been dumped.
5845e5b511dSJames Smart  *
5855e5b511dSJames Smart  * Notes:
5865e5b511dSJames Smart  * This routine will rotate through each configured Hardware Queue each
5875e5b511dSJames Smart  * time called.
5885e5b511dSJames Smart  *
5895e5b511dSJames Smart  * Return Value:
5905e5b511dSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
5915e5b511dSJames Smart  * not exceed @size.
5925e5b511dSJames Smart  **/
5935e5b511dSJames Smart static int
lpfc_debugfs_lockstat_data(struct lpfc_hba * phba,char * buf,int size)5946a828b0fSJames Smart lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size)
5955e5b511dSJames Smart {
5965e5b511dSJames Smart 	struct lpfc_sli4_hdw_queue *qp;
5975e5b511dSJames Smart 	int len = 0;
5986a828b0fSJames Smart 	int i;
5995e5b511dSJames Smart 
6005e5b511dSJames Smart 	if (phba->sli_rev != LPFC_SLI_REV4)
6015e5b511dSJames Smart 		return 0;
6025e5b511dSJames Smart 
6035e5b511dSJames Smart 	if (!phba->sli4_hba.hdwq)
6045e5b511dSJames Smart 		return 0;
6055e5b511dSJames Smart 
6065e5b511dSJames Smart 	for (i = 0; i < phba->cfg_hdw_queue; i++) {
6076a828b0fSJames Smart 		if (len > (LPFC_HDWQINFO_SIZE - 100))
6085e5b511dSJames Smart 			break;
6096a828b0fSJames Smart 		qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock];
6105e5b511dSJames Smart 
611e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i);
6126a828b0fSJames Smart 		if (phba->cfg_xri_rebalancing) {
613e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
6146a828b0fSJames Smart 					 "get_pvt:%d mv_pvt:%d "
6156a828b0fSJames Smart 					 "mv2pub:%d mv2pvt:%d "
6166a828b0fSJames Smart 					 "put_pvt:%d put_pub:%d wq:%d\n",
6176a828b0fSJames Smart 					 qp->lock_conflict.alloc_pvt_pool,
6186a828b0fSJames Smart 					 qp->lock_conflict.mv_from_pvt_pool,
6196a828b0fSJames Smart 					 qp->lock_conflict.mv_to_pub_pool,
6206a828b0fSJames Smart 					 qp->lock_conflict.mv_to_pvt_pool,
6216a828b0fSJames Smart 					 qp->lock_conflict.free_pvt_pool,
6226a828b0fSJames Smart 					 qp->lock_conflict.free_pub_pool,
6236a828b0fSJames Smart 					 qp->lock_conflict.wq_access);
6246a828b0fSJames Smart 		} else {
625e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
6266a828b0fSJames Smart 					 "get:%d put:%d free:%d wq:%d\n",
6276a828b0fSJames Smart 					 qp->lock_conflict.alloc_xri_get,
6286a828b0fSJames Smart 					 qp->lock_conflict.alloc_xri_put,
6296a828b0fSJames Smart 					 qp->lock_conflict.free_xri,
6306a828b0fSJames Smart 					 qp->lock_conflict.wq_access);
6316a828b0fSJames Smart 		}
6325e5b511dSJames Smart 
6336a828b0fSJames Smart 		lpfc_debugfs_last_lock++;
6346a828b0fSJames Smart 		if (lpfc_debugfs_last_lock >= phba->cfg_hdw_queue)
6356a828b0fSJames Smart 			lpfc_debugfs_last_lock = 0;
6365e5b511dSJames Smart 	}
6375e5b511dSJames Smart 
6385e5b511dSJames Smart 	return len;
6395e5b511dSJames Smart }
6406a828b0fSJames Smart #endif
6415e5b511dSJames Smart 
642c95d6c6cSJames Smart static int lpfc_debugfs_last_hba_slim_off;
643c95d6c6cSJames Smart 
644e59058c4SJames Smart /**
6453621a710SJames Smart  * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer
646e59058c4SJames Smart  * @phba: The HBA to gather SLIM info from.
647e59058c4SJames Smart  * @buf: The buffer to dump log into.
648e59058c4SJames Smart  * @size: The maximum amount of data to process.
649e59058c4SJames Smart  *
650e59058c4SJames Smart  * Description:
651e59058c4SJames Smart  * This routine dumps the current contents of HBA SLIM for the HBA associated
652e59058c4SJames Smart  * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data.
653e59058c4SJames Smart  *
654e59058c4SJames Smart  * Notes:
655e59058c4SJames Smart  * This routine will only dump up to 1024 bytes of data each time called and
656e59058c4SJames Smart  * should be called multiple times to dump the entire HBA SLIM.
657e59058c4SJames Smart  *
658e59058c4SJames Smart  * Return Value:
659e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
660e59058c4SJames Smart  * not exceed @size.
661e59058c4SJames Smart  **/
662a58cbd52SJames Smart static int
lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba * phba,char * buf,int size)663c95d6c6cSJames Smart lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
664a58cbd52SJames Smart {
665a58cbd52SJames Smart 	int len = 0;
666c95d6c6cSJames Smart 	int i, off;
667c95d6c6cSJames Smart 	uint32_t *ptr;
668b76f2dc9SJames Smart 	char *buffer;
669b76f2dc9SJames Smart 
670b76f2dc9SJames Smart 	buffer = kmalloc(1024, GFP_KERNEL);
671b76f2dc9SJames Smart 	if (!buffer)
672b76f2dc9SJames Smart 		return 0;
673c95d6c6cSJames Smart 
674c95d6c6cSJames Smart 	off = 0;
675c95d6c6cSJames Smart 	spin_lock_irq(&phba->hbalock);
676c95d6c6cSJames Smart 
677e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len, "HBA SLIM\n");
678c95d6c6cSJames Smart 	lpfc_memcpy_from_slim(buffer,
679a257bf90SJames Smart 		phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024);
680c95d6c6cSJames Smart 
681c95d6c6cSJames Smart 	ptr = (uint32_t *)&buffer[0];
682c95d6c6cSJames Smart 	off = lpfc_debugfs_last_hba_slim_off;
683c95d6c6cSJames Smart 
684c95d6c6cSJames Smart 	/* Set it up for the next time */
685c95d6c6cSJames Smart 	lpfc_debugfs_last_hba_slim_off += 1024;
686c95d6c6cSJames Smart 	if (lpfc_debugfs_last_hba_slim_off >= 4096)
687c95d6c6cSJames Smart 		lpfc_debugfs_last_hba_slim_off = 0;
688c95d6c6cSJames Smart 
689c95d6c6cSJames Smart 	i = 1024;
690c95d6c6cSJames Smart 	while (i > 0) {
691e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len,
692c95d6c6cSJames Smart 		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
693c95d6c6cSJames Smart 		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
694c95d6c6cSJames Smart 		*(ptr+5), *(ptr+6), *(ptr+7));
695c95d6c6cSJames Smart 		ptr += 8;
696c95d6c6cSJames Smart 		i -= (8 * sizeof(uint32_t));
697c95d6c6cSJames Smart 		off += (8 * sizeof(uint32_t));
698c95d6c6cSJames Smart 	}
699c95d6c6cSJames Smart 
700c95d6c6cSJames Smart 	spin_unlock_irq(&phba->hbalock);
701b76f2dc9SJames Smart 	kfree(buffer);
702b76f2dc9SJames Smart 
703c95d6c6cSJames Smart 	return len;
704c95d6c6cSJames Smart }
705c95d6c6cSJames Smart 
706e59058c4SJames Smart /**
7073621a710SJames Smart  * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer
708e59058c4SJames Smart  * @phba: The HBA to gather Host SLIM info from.
709e59058c4SJames Smart  * @buf: The buffer to dump log into.
710e59058c4SJames Smart  * @size: The maximum amount of data to process.
711e59058c4SJames Smart  *
712e59058c4SJames Smart  * Description:
713e59058c4SJames Smart  * This routine dumps the current contents of host SLIM for the host associated
714e59058c4SJames Smart  * with @phba to @buf up to @size bytes of data. The dump will contain the
715e59058c4SJames Smart  * Mailbox, PCB, Rings, and Registers that are located in host memory.
716e59058c4SJames Smart  *
717e59058c4SJames Smart  * Return Value:
718e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
719e59058c4SJames Smart  * not exceed @size.
720e59058c4SJames Smart  **/
721c95d6c6cSJames Smart static int
lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba * phba,char * buf,int size)722c95d6c6cSJames Smart lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
723c95d6c6cSJames Smart {
724c95d6c6cSJames Smart 	int len = 0;
725c95d6c6cSJames Smart 	int i, off;
726a58cbd52SJames Smart 	uint32_t word0, word1, word2, word3;
727a58cbd52SJames Smart 	uint32_t *ptr;
728a58cbd52SJames Smart 	struct lpfc_pgp *pgpp;
729a58cbd52SJames Smart 	struct lpfc_sli *psli = &phba->sli;
730a58cbd52SJames Smart 	struct lpfc_sli_ring *pring;
731a58cbd52SJames Smart 
732a58cbd52SJames Smart 	off = 0;
733a58cbd52SJames Smart 	spin_lock_irq(&phba->hbalock);
734a58cbd52SJames Smart 
735e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len, "SLIM Mailbox\n");
73634b02dcdSJames Smart 	ptr = (uint32_t *)phba->slim2p.virt;
737a58cbd52SJames Smart 	i = sizeof(MAILBOX_t);
738a58cbd52SJames Smart 	while (i > 0) {
739e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len,
740a58cbd52SJames Smart 		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
741a58cbd52SJames Smart 		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
742a58cbd52SJames Smart 		*(ptr+5), *(ptr+6), *(ptr+7));
743a58cbd52SJames Smart 		ptr += 8;
744a58cbd52SJames Smart 		i -= (8 * sizeof(uint32_t));
745a58cbd52SJames Smart 		off += (8 * sizeof(uint32_t));
746a58cbd52SJames Smart 	}
747a58cbd52SJames Smart 
748e7f7b6f3SSilvio Cesare 	len +=  scnprintf(buf+len, size-len, "SLIM PCB\n");
74934b02dcdSJames Smart 	ptr = (uint32_t *)phba->pcb;
750a58cbd52SJames Smart 	i = sizeof(PCB_t);
751a58cbd52SJames Smart 	while (i > 0) {
752e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len,
753a58cbd52SJames Smart 		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
754a58cbd52SJames Smart 		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
755a58cbd52SJames Smart 		*(ptr+5), *(ptr+6), *(ptr+7));
756a58cbd52SJames Smart 		ptr += 8;
757a58cbd52SJames Smart 		i -= (8 * sizeof(uint32_t));
758a58cbd52SJames Smart 		off += (8 * sizeof(uint32_t));
759a58cbd52SJames Smart 	}
760a58cbd52SJames Smart 
761895427bdSJames Smart 	if (phba->sli_rev <= LPFC_SLI_REV3) {
76234b02dcdSJames Smart 		for (i = 0; i < 4; i++) {
76334b02dcdSJames Smart 			pgpp = &phba->port_gp[i];
764895427bdSJames Smart 			pring = &psli->sli3_ring[i];
765e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf+len, size-len,
766895427bdSJames Smart 					 "Ring %d: CMD GetInx:%d "
767895427bdSJames Smart 					 "(Max:%d Next:%d "
768895427bdSJames Smart 					 "Local:%d flg:x%x)  "
769895427bdSJames Smart 					 "RSP PutInx:%d Max:%d\n",
770895427bdSJames Smart 					 i, pgpp->cmdGetInx,
771895427bdSJames Smart 					 pring->sli.sli3.numCiocb,
7727e56aa25SJames Smart 					 pring->sli.sli3.next_cmdidx,
7737e56aa25SJames Smart 					 pring->sli.sli3.local_getidx,
7747e56aa25SJames Smart 					 pring->flag, pgpp->rspPutInx,
7757e56aa25SJames Smart 					 pring->sli.sli3.numRiocb);
77634b02dcdSJames Smart 		}
7773772a991SJames Smart 
778a58cbd52SJames Smart 		word0 = readl(phba->HAregaddr);
779a58cbd52SJames Smart 		word1 = readl(phba->CAregaddr);
780a58cbd52SJames Smart 		word2 = readl(phba->HSregaddr);
781a58cbd52SJames Smart 		word3 = readl(phba->HCregaddr);
782e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
7833772a991SJames Smart 				 "HC:%08x\n", word0, word1, word2, word3);
7843772a991SJames Smart 	}
785a58cbd52SJames Smart 	spin_unlock_irq(&phba->hbalock);
786a58cbd52SJames Smart 	return len;
787a58cbd52SJames Smart }
788a58cbd52SJames Smart 
789e59058c4SJames Smart /**
7903621a710SJames Smart  * lpfc_debugfs_nodelist_data - Dump target node list to a buffer
791e59058c4SJames Smart  * @vport: The vport to gather target node info from.
792e59058c4SJames Smart  * @buf: The buffer to dump log into.
793e59058c4SJames Smart  * @size: The maximum amount of data to process.
794e59058c4SJames Smart  *
795e59058c4SJames Smart  * Description:
796e59058c4SJames Smart  * This routine dumps the current target node list associated with @vport to
797e59058c4SJames Smart  * @buf up to @size bytes of data. Each node entry in the dump will contain a
798e59058c4SJames Smart  * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields.
799e59058c4SJames Smart  *
800e59058c4SJames Smart  * Return Value:
801e59058c4SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
802e59058c4SJames Smart  * not exceed @size.
803e59058c4SJames Smart  **/
804a58cbd52SJames Smart static int
lpfc_debugfs_nodelist_data(struct lpfc_vport * vport,char * buf,int size)805858c9f6cSJames Smart lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
806858c9f6cSJames Smart {
807858c9f6cSJames Smart 	int len = 0;
808f91bc594SJames Smart 	int i, iocnt, outio, cnt;
809858c9f6cSJames Smart 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
8102b65e182SJames Smart 	struct lpfc_hba  *phba = vport->phba;
811858c9f6cSJames Smart 	struct lpfc_nodelist *ndlp;
8122ea259eeSJames Smart 	unsigned char *statep;
813bd2cdd5eSJames Smart 	struct nvme_fc_local_port *localport;
8149e210178SJames Smart 	struct nvme_fc_remote_port *nrport = NULL;
81501466024SJames Smart 	struct lpfc_nvme_rport *rport;
816858c9f6cSJames Smart 
817858c9f6cSJames Smart 	cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
818f91bc594SJames Smart 	outio = 0;
819858c9f6cSJames Smart 
820e7f7b6f3SSilvio Cesare 	len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
821858c9f6cSJames Smart 	spin_lock_irq(shost->host_lock);
822858c9f6cSJames Smart 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
823f91bc594SJames Smart 		iocnt = 0;
824858c9f6cSJames Smart 		if (!cnt) {
825e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf+len, size-len,
826858c9f6cSJames Smart 				"Missing Nodelist Entries\n");
827858c9f6cSJames Smart 			break;
828858c9f6cSJames Smart 		}
829858c9f6cSJames Smart 		cnt--;
830858c9f6cSJames Smart 		switch (ndlp->nlp_state) {
831858c9f6cSJames Smart 		case NLP_STE_UNUSED_NODE:
832858c9f6cSJames Smart 			statep = "UNUSED";
833858c9f6cSJames Smart 			break;
834858c9f6cSJames Smart 		case NLP_STE_PLOGI_ISSUE:
835858c9f6cSJames Smart 			statep = "PLOGI ";
836858c9f6cSJames Smart 			break;
837858c9f6cSJames Smart 		case NLP_STE_ADISC_ISSUE:
838858c9f6cSJames Smart 			statep = "ADISC ";
839858c9f6cSJames Smart 			break;
840858c9f6cSJames Smart 		case NLP_STE_REG_LOGIN_ISSUE:
841858c9f6cSJames Smart 			statep = "REGLOG";
842858c9f6cSJames Smart 			break;
843858c9f6cSJames Smart 		case NLP_STE_PRLI_ISSUE:
844858c9f6cSJames Smart 			statep = "PRLI  ";
845858c9f6cSJames Smart 			break;
846086a345fSJames Smart 		case NLP_STE_LOGO_ISSUE:
847086a345fSJames Smart 			statep = "LOGO  ";
848086a345fSJames Smart 			break;
849858c9f6cSJames Smart 		case NLP_STE_UNMAPPED_NODE:
850858c9f6cSJames Smart 			statep = "UNMAP ";
851f91bc594SJames Smart 			iocnt = 1;
852858c9f6cSJames Smart 			break;
853858c9f6cSJames Smart 		case NLP_STE_MAPPED_NODE:
854858c9f6cSJames Smart 			statep = "MAPPED";
855f91bc594SJames Smart 			iocnt = 1;
856858c9f6cSJames Smart 			break;
857858c9f6cSJames Smart 		case NLP_STE_NPR_NODE:
858858c9f6cSJames Smart 			statep = "NPR   ";
859858c9f6cSJames Smart 			break;
860858c9f6cSJames Smart 		default:
861858c9f6cSJames Smart 			statep = "UNKNOWN";
862858c9f6cSJames Smart 		}
863e7f7b6f3SSilvio Cesare 		len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
864858c9f6cSJames Smart 				statep, ndlp->nlp_DID);
865e7f7b6f3SSilvio Cesare 		len += scnprintf(buf+len, size-len,
866fe83e3b9SJames Smart 				"WWPN x%016llx ",
8672ea259eeSJames Smart 				wwn_to_u64(ndlp->nlp_portname.u.wwn));
868e7f7b6f3SSilvio Cesare 		len += scnprintf(buf+len, size-len,
869fe83e3b9SJames Smart 				"WWNN x%016llx ",
8702ea259eeSJames Smart 				wwn_to_u64(ndlp->nlp_nodename.u.wwn));
87101131e7aSJames Smart 		len += scnprintf(buf+len, size-len, "RPI:x%04x ",
872086a345fSJames Smart 				 ndlp->nlp_rpi);
873e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, "flag:x%08x ",
874086a345fSJames Smart 			ndlp->nlp_flag);
875858c9f6cSJames Smart 		if (!ndlp->nlp_type)
876e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE ");
877858c9f6cSJames Smart 		if (ndlp->nlp_type & NLP_FC_NODE)
878e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, "FC_NODE ");
879f91bc594SJames Smart 		if (ndlp->nlp_type & NLP_FABRIC) {
880e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, "FABRIC ");
881f91bc594SJames Smart 			iocnt = 0;
882f91bc594SJames Smart 		}
883858c9f6cSJames Smart 		if (ndlp->nlp_type & NLP_FCP_TARGET)
884e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ",
885858c9f6cSJames Smart 				ndlp->nlp_sid);
886858c9f6cSJames Smart 		if (ndlp->nlp_type & NLP_FCP_INITIATOR)
887e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, "FCP_INITIATOR ");
8887d790f04SJames Smart 		if (ndlp->nlp_type & NLP_NVME_TARGET)
889e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len,
8907d790f04SJames Smart 					size - len, "NVME_TGT sid:%d ",
8917d790f04SJames Smart 					NLP_NO_SID);
8927d790f04SJames Smart 		if (ndlp->nlp_type & NLP_NVME_INITIATOR)
893e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len,
8947d790f04SJames Smart 					size - len, "NVME_INITIATOR ");
895bb6fd33eSJames Smart 		len += scnprintf(buf+len, size-len, "refcnt:%d",
8962c935bc5SPeter Zijlstra 			kref_read(&ndlp->kref));
897f91bc594SJames Smart 		if (iocnt) {
898f91bc594SJames Smart 			i = atomic_read(&ndlp->cmd_pending);
899e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
900f91bc594SJames Smart 					" OutIO:x%x Qdepth x%x",
901f91bc594SJames Smart 					i, ndlp->cmd_qdepth);
902f91bc594SJames Smart 			outio += i;
903f91bc594SJames Smart 		}
904bb6fd33eSJames Smart 		len += scnprintf(buf+len, size-len, " xpt:x%x",
905bb6fd33eSJames Smart 				 ndlp->fc4_xpt_flags);
906bb6fd33eSJames Smart 		if (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)
907e7f7b6f3SSilvio Cesare 			len += scnprintf(buf+len, size-len, " defer:%x",
908dea16bdaSJames Smart 					 ndlp->nlp_defer_did);
909e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf+len, size-len, "\n");
910858c9f6cSJames Smart 	}
911858c9f6cSJames Smart 	spin_unlock_irq(shost->host_lock);
9122ea259eeSJames Smart 
913e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len,
914f91bc594SJames Smart 			"\nOutstanding IO x%x\n",  outio);
915f91bc594SJames Smart 
9162b65e182SJames Smart 	if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) {
917e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
9182b65e182SJames Smart 				"\nNVME Targetport Entry ...\n");
9192b65e182SJames Smart 
9202b65e182SJames Smart 		/* Port state is only one of two values for now. */
9212b65e182SJames Smart 		if (phba->targetport->port_id)
9222b65e182SJames Smart 			statep = "REGISTERED";
9232b65e182SJames Smart 		else
9242b65e182SJames Smart 			statep = "INIT";
925e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
9262b65e182SJames Smart 				"TGT WWNN x%llx WWPN x%llx State %s\n",
9272b65e182SJames Smart 				wwn_to_u64(vport->fc_nodename.u.wwn),
9282b65e182SJames Smart 				wwn_to_u64(vport->fc_portname.u.wwn),
9292b65e182SJames Smart 				statep);
930e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
9312b65e182SJames Smart 				"    Targetport DID x%06x\n",
9322b65e182SJames Smart 				phba->targetport->port_id);
9332b65e182SJames Smart 		goto out_exit;
9342b65e182SJames Smart 	}
9352b65e182SJames Smart 
936e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len,
937bd2cdd5eSJames Smart 				"\nNVME Lport/Rport Entries ...\n");
938bd2cdd5eSJames Smart 
939bd2cdd5eSJames Smart 	localport = vport->localport;
940bd2cdd5eSJames Smart 	if (!localport)
941bd2cdd5eSJames Smart 		goto out_exit;
942bd2cdd5eSJames Smart 
943bd2cdd5eSJames Smart 	spin_lock_irq(shost->host_lock);
944bd2cdd5eSJames Smart 
945bd2cdd5eSJames Smart 	/* Port state is only one of two values for now. */
946bd2cdd5eSJames Smart 	if (localport->port_id)
947bd2cdd5eSJames Smart 		statep = "ONLINE";
948bd2cdd5eSJames Smart 	else
949bd2cdd5eSJames Smart 		statep = "UNKNOWN ";
950bd2cdd5eSJames Smart 
951e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len,
952bd2cdd5eSJames Smart 			"Lport DID x%06x PortState %s\n",
953bd2cdd5eSJames Smart 			localport->port_id, statep);
954bd2cdd5eSJames Smart 
955e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len, "\tRport List:\n");
95680cc0043SJames Smart 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
957bd2cdd5eSJames Smart 		/* local short-hand pointer. */
958c6adba15SJames Smart 		spin_lock(&ndlp->lock);
95901466024SJames Smart 		rport = lpfc_ndlp_get_nrport(ndlp);
9609e210178SJames Smart 		if (rport)
96101466024SJames Smart 			nrport = rport->remoteport;
962f8d29432SArnd Bergmann 		else
963f8d29432SArnd Bergmann 			nrport = NULL;
964c6adba15SJames Smart 		spin_unlock(&ndlp->lock);
96501466024SJames Smart 		if (!nrport)
96601466024SJames Smart 			continue;
967bd2cdd5eSJames Smart 
968bd2cdd5eSJames Smart 		/* Port state is only one of two values for now. */
969bd2cdd5eSJames Smart 		switch (nrport->port_state) {
970bd2cdd5eSJames Smart 		case FC_OBJSTATE_ONLINE:
971bd2cdd5eSJames Smart 			statep = "ONLINE";
972bd2cdd5eSJames Smart 			break;
973bd2cdd5eSJames Smart 		case FC_OBJSTATE_UNKNOWN:
974bd2cdd5eSJames Smart 			statep = "UNKNOWN ";
975bd2cdd5eSJames Smart 			break;
976bd2cdd5eSJames Smart 		default:
977bd2cdd5eSJames Smart 			statep = "UNSUPPORTED";
978bd2cdd5eSJames Smart 			break;
979bd2cdd5eSJames Smart 		}
980bd2cdd5eSJames Smart 
981bd2cdd5eSJames Smart 		/* Tab in to show lport ownership. */
982e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
983bd2cdd5eSJames Smart 				"\t%s Port ID:x%06x ",
984bd2cdd5eSJames Smart 				statep, nrport->port_id);
985e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len, "WWPN x%llx ",
986bd2cdd5eSJames Smart 				nrport->port_name);
987e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len, "WWNN x%llx ",
988bd2cdd5eSJames Smart 				nrport->node_name);
9897d790f04SJames Smart 
9907d790f04SJames Smart 		/* An NVME rport can have multiple roles. */
9917d790f04SJames Smart 		if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR)
992e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf + len, size - len,
9937d790f04SJames Smart 					 "INITIATOR ");
9947d790f04SJames Smart 		if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET)
995e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf + len, size - len,
9967d790f04SJames Smart 					 "TARGET ");
9977d790f04SJames Smart 		if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY)
998e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf + len, size - len,
9997d790f04SJames Smart 					 "DISCSRVC ");
10007d790f04SJames Smart 		if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
10017d790f04SJames Smart 					  FC_PORT_ROLE_NVME_TARGET |
10027d790f04SJames Smart 					  FC_PORT_ROLE_NVME_DISCOVERY))
1003e7f7b6f3SSilvio Cesare 			len +=  scnprintf(buf + len, size - len,
1004bd2cdd5eSJames Smart 					 "UNKNOWN ROLE x%x",
1005bd2cdd5eSJames Smart 					 nrport->port_role);
1006bd2cdd5eSJames Smart 		/* Terminate the string. */
1007e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf + len, size - len, "\n");
1008bd2cdd5eSJames Smart 	}
1009bd2cdd5eSJames Smart 
1010bd2cdd5eSJames Smart 	spin_unlock_irq(shost->host_lock);
1011bd2cdd5eSJames Smart  out_exit:
1012bd2cdd5eSJames Smart 	return len;
1013bd2cdd5eSJames Smart }
1014bd2cdd5eSJames Smart 
1015bd2cdd5eSJames Smart /**
1016bd2cdd5eSJames Smart  * lpfc_debugfs_nvmestat_data - Dump target node list to a buffer
1017bd2cdd5eSJames Smart  * @vport: The vport to gather target node info from.
1018bd2cdd5eSJames Smart  * @buf: The buffer to dump log into.
1019bd2cdd5eSJames Smart  * @size: The maximum amount of data to process.
1020bd2cdd5eSJames Smart  *
1021bd2cdd5eSJames Smart  * Description:
1022bd2cdd5eSJames Smart  * This routine dumps the NVME statistics associated with @vport
1023bd2cdd5eSJames Smart  *
1024bd2cdd5eSJames Smart  * Return Value:
1025bd2cdd5eSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
1026bd2cdd5eSJames Smart  * not exceed @size.
1027bd2cdd5eSJames Smart  **/
1028bd2cdd5eSJames Smart static int
lpfc_debugfs_nvmestat_data(struct lpfc_vport * vport,char * buf,int size)1029bd2cdd5eSJames Smart lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
1030bd2cdd5eSJames Smart {
1031bd2cdd5eSJames Smart 	struct lpfc_hba   *phba = vport->phba;
10322b65e182SJames Smart 	struct lpfc_nvmet_tgtport *tgtp;
10337cacae2aSJames Smart 	struct lpfc_async_xchg_ctx *ctxp, *next_ctxp;
10344b056682SJames Smart 	struct nvme_fc_local_port *localport;
10354c47efc1SJames Smart 	struct lpfc_fc4_ctrl_stat *cstat;
10364b056682SJames Smart 	struct lpfc_nvme_lport *lport;
103766a210ffSJames Smart 	uint64_t data1, data2, data3;
103866a210ffSJames Smart 	uint64_t tot, totin, totout;
10396a828b0fSJames Smart 	int cnt, i;
1040bd2cdd5eSJames Smart 	int len = 0;
1041bd2cdd5eSJames Smart 
10422b65e182SJames Smart 	if (phba->nvmet_support) {
10432b65e182SJames Smart 		if (!phba->targetport)
10442b65e182SJames Smart 			return len;
10452b65e182SJames Smart 		tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
1046e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
10472b65e182SJames Smart 				"\nNVME Targetport Statistics\n");
10482b65e182SJames Smart 
1049e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
10502b65e182SJames Smart 				"LS: Rcv %08x Drop %08x Abort %08x\n",
10512b65e182SJames Smart 				atomic_read(&tgtp->rcv_ls_req_in),
10522b65e182SJames Smart 				atomic_read(&tgtp->rcv_ls_req_drop),
10532b65e182SJames Smart 				atomic_read(&tgtp->xmt_ls_abort));
10542b65e182SJames Smart 		if (atomic_read(&tgtp->rcv_ls_req_in) !=
10552b65e182SJames Smart 		    atomic_read(&tgtp->rcv_ls_req_out)) {
1056e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
10572b65e182SJames Smart 					"Rcv LS: in %08x != out %08x\n",
10582b65e182SJames Smart 					atomic_read(&tgtp->rcv_ls_req_in),
10592b65e182SJames Smart 					atomic_read(&tgtp->rcv_ls_req_out));
10602b65e182SJames Smart 		}
10612b65e182SJames Smart 
1062e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
10634b056682SJames Smart 				"LS: Xmt %08x Drop %08x Cmpl %08x\n",
10642b65e182SJames Smart 				atomic_read(&tgtp->xmt_ls_rsp),
10652b65e182SJames Smart 				atomic_read(&tgtp->xmt_ls_drop),
10664b056682SJames Smart 				atomic_read(&tgtp->xmt_ls_rsp_cmpl));
10674b056682SJames Smart 
1068e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
10694b056682SJames Smart 				"LS: RSP Abort %08x xb %08x Err %08x\n",
10704b056682SJames Smart 				atomic_read(&tgtp->xmt_ls_rsp_aborted),
10714b056682SJames Smart 				atomic_read(&tgtp->xmt_ls_rsp_xb_set),
10722b65e182SJames Smart 				atomic_read(&tgtp->xmt_ls_rsp_error));
10732b65e182SJames Smart 
1074e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
107550738420SJames Smart 				"FCP: Rcv %08x Defer %08x Release %08x "
107650738420SJames Smart 				"Drop %08x\n",
10772b65e182SJames Smart 				atomic_read(&tgtp->rcv_fcp_cmd_in),
107850738420SJames Smart 				atomic_read(&tgtp->rcv_fcp_cmd_defer),
107950738420SJames Smart 				atomic_read(&tgtp->xmt_fcp_release),
10802b65e182SJames Smart 				atomic_read(&tgtp->rcv_fcp_cmd_drop));
10812b65e182SJames Smart 
10822b65e182SJames Smart 		if (atomic_read(&tgtp->rcv_fcp_cmd_in) !=
10832b65e182SJames Smart 		    atomic_read(&tgtp->rcv_fcp_cmd_out)) {
1084e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
10852b65e182SJames Smart 					"Rcv FCP: in %08x != out %08x\n",
10862b65e182SJames Smart 					atomic_read(&tgtp->rcv_fcp_cmd_in),
10872b65e182SJames Smart 					atomic_read(&tgtp->rcv_fcp_cmd_out));
10882b65e182SJames Smart 		}
10892b65e182SJames Smart 
1090e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
109186c67379SJames Smart 				"FCP Rsp: read %08x readrsp %08x "
109286c67379SJames Smart 				"write %08x rsp %08x\n",
10932b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_read),
10942b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_read_rsp),
10952b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_write),
10962b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp));
10972b65e182SJames Smart 
1098e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
10992b65e182SJames Smart 				"FCP Rsp Cmpl: %08x err %08x drop %08x\n",
11002b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp_cmpl),
11012b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp_error),
11022b65e182SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp_drop));
11032b65e182SJames Smart 
1104e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
11054b056682SJames Smart 				"FCP Rsp Abort: %08x xb %08x xricqe  %08x\n",
11064b056682SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp_aborted),
11074b056682SJames Smart 				atomic_read(&tgtp->xmt_fcp_rsp_xb_set),
11084b056682SJames Smart 				atomic_read(&tgtp->xmt_fcp_xri_abort_cqe));
11094b056682SJames Smart 
1110e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
1111547077a4SJames Smart 				"ABORT: Xmt %08x Cmpl %08x\n",
1112547077a4SJames Smart 				atomic_read(&tgtp->xmt_fcp_abort),
1113547077a4SJames Smart 				atomic_read(&tgtp->xmt_fcp_abort_cmpl));
1114547077a4SJames Smart 
1115e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
1116547077a4SJames Smart 				"ABORT: Sol %08x  Usol %08x Err %08x Cmpl %08x",
1117547077a4SJames Smart 				atomic_read(&tgtp->xmt_abort_sol),
1118547077a4SJames Smart 				atomic_read(&tgtp->xmt_abort_unsol),
11192b65e182SJames Smart 				atomic_read(&tgtp->xmt_abort_rsp),
1120547077a4SJames Smart 				atomic_read(&tgtp->xmt_abort_rsp_error));
11212b65e182SJames Smart 
1122e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf + len, size - len, "\n");
112386c67379SJames Smart 
112486c67379SJames Smart 		cnt = 0;
11255e5b511dSJames Smart 		spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
112686c67379SJames Smart 		list_for_each_entry_safe(ctxp, next_ctxp,
112786c67379SJames Smart 				&phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
112886c67379SJames Smart 				list) {
112986c67379SJames Smart 			cnt++;
113086c67379SJames Smart 		}
11315e5b511dSJames Smart 		spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
113286c67379SJames Smart 		if (cnt) {
1133e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
113486c67379SJames Smart 					"ABORT: %d ctx entries\n", cnt);
11355e5b511dSJames Smart 			spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
113686c67379SJames Smart 			list_for_each_entry_safe(ctxp, next_ctxp,
113786c67379SJames Smart 				    &phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
113886c67379SJames Smart 				    list) {
113986c67379SJames Smart 				if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ))
114086c67379SJames Smart 					break;
1141e7f7b6f3SSilvio Cesare 				len += scnprintf(buf + len, size - len,
114286c67379SJames Smart 						"Entry: oxid %x state %x "
114386c67379SJames Smart 						"flag %x\n",
114486c67379SJames Smart 						ctxp->oxid, ctxp->state,
114586c67379SJames Smart 						ctxp->flag);
114686c67379SJames Smart 			}
11475e5b511dSJames Smart 			spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
114886c67379SJames Smart 		}
1149a8cf5dfeSJames Smart 
115066d7ce93SDick Kennedy 		/* Calculate outstanding IOs */
115166d7ce93SDick Kennedy 		tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
115266d7ce93SDick Kennedy 		tot += atomic_read(&tgtp->xmt_fcp_release);
115366d7ce93SDick Kennedy 		tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot;
11542cee7808SJames Smart 
1155e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
11562cee7808SJames Smart 				"IO_CTX: %08x  WAIT: cur %08x tot %08x\n"
11572cee7808SJames Smart 				"CTX Outstanding %08llx\n",
1158966bb5b7SJames Smart 				phba->sli4_hba.nvmet_xri_cnt,
1159a8cf5dfeSJames Smart 				phba->sli4_hba.nvmet_io_wait_cnt,
11602cee7808SJames Smart 				phba->sli4_hba.nvmet_io_wait_total,
11612cee7808SJames Smart 				tot);
11622b65e182SJames Smart 	} else {
1163f6e84790SJames Smart 		if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME))
1164bd2cdd5eSJames Smart 			return len;
1165bd2cdd5eSJames Smart 
11664b056682SJames Smart 		localport = vport->localport;
11674b056682SJames Smart 		if (!localport)
11684b056682SJames Smart 			return len;
11694b056682SJames Smart 		lport = (struct lpfc_nvme_lport *)localport->private;
11704b056682SJames Smart 		if (!lport)
11714b056682SJames Smart 			return len;
11724b056682SJames Smart 
1173e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
11744c47efc1SJames Smart 				"\nNVME HDWQ Statistics\n");
117566a210ffSJames Smart 
1176e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
117766a210ffSJames Smart 				"LS: Xmt %016x Cmpl %016x\n",
117866a210ffSJames Smart 				atomic_read(&lport->fc4NvmeLsRequests),
117966a210ffSJames Smart 				atomic_read(&lport->fc4NvmeLsCmpls));
118066a210ffSJames Smart 
118166a210ffSJames Smart 		totin = 0;
118266a210ffSJames Smart 		totout = 0;
1183cdb42becSJames Smart 		for (i = 0; i < phba->cfg_hdw_queue; i++) {
11844c47efc1SJames Smart 			cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
11854c47efc1SJames Smart 			tot = cstat->io_cmpls;
118666a210ffSJames Smart 			totin += tot;
11874c47efc1SJames Smart 			data1 = cstat->input_requests;
11884c47efc1SJames Smart 			data2 = cstat->output_requests;
11894c47efc1SJames Smart 			data3 = cstat->control_requests;
119066a210ffSJames Smart 			totout += (data1 + data2 + data3);
119166a210ffSJames Smart 
119266a210ffSJames Smart 			/* Limit to 32, debugfs display buffer limitation */
119366a210ffSJames Smart 			if (i >= 32)
119466a210ffSJames Smart 				continue;
119566a210ffSJames Smart 
1196e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, PAGE_SIZE - len,
11974c47efc1SJames Smart 					"HDWQ (%d): Rd %016llx Wr %016llx "
119866a210ffSJames Smart 					"IO %016llx ",
119966a210ffSJames Smart 					i, data1, data2, data3);
1200e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, PAGE_SIZE - len,
120166a210ffSJames Smart 					"Cmpl %016llx OutIO %016llx\n",
120266a210ffSJames Smart 					tot, ((data1 + data2 + data3) - tot));
120366a210ffSJames Smart 		}
1204e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, PAGE_SIZE - len,
120566a210ffSJames Smart 				"Total FCP Cmpl %016llx Issue %016llx "
120666a210ffSJames Smart 				"OutIO %016llx\n",
120766a210ffSJames Smart 				totin, totout, totout - totin);
120866a210ffSJames Smart 
1209e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
12104b056682SJames Smart 				"LS Xmt Err: Abrt %08x Err %08x  "
12114b056682SJames Smart 				"Cmpl Err: xb %08x Err %08x\n",
12124b056682SJames Smart 				atomic_read(&lport->xmt_ls_abort),
12134b056682SJames Smart 				atomic_read(&lport->xmt_ls_err),
12144b056682SJames Smart 				atomic_read(&lport->cmpl_ls_xb),
12154b056682SJames Smart 				atomic_read(&lport->cmpl_ls_err));
12164b056682SJames Smart 
1217e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
12184b056682SJames Smart 				"FCP Xmt Err: noxri %06x nondlp %06x "
121944c2757bSJames Smart 				"qdepth %06x wqerr %06x err %06x Abrt %06x\n",
12204b056682SJames Smart 				atomic_read(&lport->xmt_fcp_noxri),
12214b056682SJames Smart 				atomic_read(&lport->xmt_fcp_bad_ndlp),
12224b056682SJames Smart 				atomic_read(&lport->xmt_fcp_qdepth),
12234b056682SJames Smart 				atomic_read(&lport->xmt_fcp_wqerr),
122444c2757bSJames Smart 				atomic_read(&lport->xmt_fcp_err),
12254b056682SJames Smart 				atomic_read(&lport->xmt_fcp_abort));
12264b056682SJames Smart 
1227e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, size - len,
12284b056682SJames Smart 				"FCP Cmpl Err: xb %08x Err %08x\n",
12294b056682SJames Smart 				atomic_read(&lport->cmpl_fcp_xb),
12304b056682SJames Smart 				atomic_read(&lport->cmpl_fcp_err));
12314b056682SJames Smart 
1232bd2cdd5eSJames Smart 	}
1233bd2cdd5eSJames Smart 
1234bd2cdd5eSJames Smart 	return len;
1235bd2cdd5eSJames Smart }
1236bd2cdd5eSJames Smart 
12374c47efc1SJames Smart /**
12384c47efc1SJames Smart  * lpfc_debugfs_scsistat_data - Dump target node list to a buffer
12394c47efc1SJames Smart  * @vport: The vport to gather target node info from.
12404c47efc1SJames Smart  * @buf: The buffer to dump log into.
12414c47efc1SJames Smart  * @size: The maximum amount of data to process.
12424c47efc1SJames Smart  *
12434c47efc1SJames Smart  * Description:
12444c47efc1SJames Smart  * This routine dumps the SCSI statistics associated with @vport
12454c47efc1SJames Smart  *
12464c47efc1SJames Smart  * Return Value:
12474c47efc1SJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
12484c47efc1SJames Smart  * not exceed @size.
12494c47efc1SJames Smart  **/
12504c47efc1SJames Smart static int
lpfc_debugfs_scsistat_data(struct lpfc_vport * vport,char * buf,int size)12514c47efc1SJames Smart lpfc_debugfs_scsistat_data(struct lpfc_vport *vport, char *buf, int size)
12524c47efc1SJames Smart {
12534c47efc1SJames Smart 	int len;
12544c47efc1SJames Smart 	struct lpfc_hba *phba = vport->phba;
12554c47efc1SJames Smart 	struct lpfc_fc4_ctrl_stat *cstat;
12564c47efc1SJames Smart 	u64 data1, data2, data3;
12574c47efc1SJames Smart 	u64 tot, totin, totout;
12584c47efc1SJames Smart 	int i;
12594c47efc1SJames Smart 	char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
12604c47efc1SJames Smart 
1261f6e84790SJames Smart 	if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
12624c47efc1SJames Smart 	    (phba->sli_rev != LPFC_SLI_REV4))
12634c47efc1SJames Smart 		return 0;
12644c47efc1SJames Smart 
12654c47efc1SJames Smart 	scnprintf(buf, size, "SCSI HDWQ Statistics\n");
12664c47efc1SJames Smart 
12674c47efc1SJames Smart 	totin = 0;
12684c47efc1SJames Smart 	totout = 0;
12694c47efc1SJames Smart 	for (i = 0; i < phba->cfg_hdw_queue; i++) {
12704c47efc1SJames Smart 		cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
12714c47efc1SJames Smart 		tot = cstat->io_cmpls;
12724c47efc1SJames Smart 		totin += tot;
12734c47efc1SJames Smart 		data1 = cstat->input_requests;
12744c47efc1SJames Smart 		data2 = cstat->output_requests;
12754c47efc1SJames Smart 		data3 = cstat->control_requests;
12764c47efc1SJames Smart 		totout += (data1 + data2 + data3);
12774c47efc1SJames Smart 
12784c47efc1SJames Smart 		scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx "
12794c47efc1SJames Smart 			  "IO %016llx ", i, data1, data2, data3);
12804c47efc1SJames Smart 		if (strlcat(buf, tmp, size) >= size)
12814c47efc1SJames Smart 			goto buffer_done;
12824c47efc1SJames Smart 
12834c47efc1SJames Smart 		scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n",
12844c47efc1SJames Smart 			  tot, ((data1 + data2 + data3) - tot));
12854c47efc1SJames Smart 		if (strlcat(buf, tmp, size) >= size)
12864c47efc1SJames Smart 			goto buffer_done;
12874c47efc1SJames Smart 	}
12884c47efc1SJames Smart 	scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx "
12894c47efc1SJames Smart 		  "OutIO %016llx\n", totin, totout, totout - totin);
12904c47efc1SJames Smart 	strlcat(buf, tmp, size);
12914c47efc1SJames Smart 
12924c47efc1SJames Smart buffer_done:
12934c47efc1SJames Smart 	len = strnlen(buf, size);
12944c47efc1SJames Smart 
12954c47efc1SJames Smart 	return len;
12964c47efc1SJames Smart }
1297bd2cdd5eSJames Smart 
12982fcbc569SJames Smart void
lpfc_io_ktime(struct lpfc_hba * phba,struct lpfc_io_buf * lpfc_cmd)12992fcbc569SJames Smart lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
13002fcbc569SJames Smart {
13012fcbc569SJames Smart 	uint64_t seg1, seg2, seg3, seg4;
13022fcbc569SJames Smart 	uint64_t segsum;
13032fcbc569SJames Smart 
13042fcbc569SJames Smart 	if (!lpfc_cmd->ts_last_cmd ||
13052fcbc569SJames Smart 	    !lpfc_cmd->ts_cmd_start ||
13062fcbc569SJames Smart 	    !lpfc_cmd->ts_cmd_wqput ||
13072fcbc569SJames Smart 	    !lpfc_cmd->ts_isr_cmpl ||
13082fcbc569SJames Smart 	    !lpfc_cmd->ts_data_io)
13092fcbc569SJames Smart 		return;
13102fcbc569SJames Smart 
13112fcbc569SJames Smart 	if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start)
13122fcbc569SJames Smart 		return;
13132fcbc569SJames Smart 	if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd)
13142fcbc569SJames Smart 		return;
13152fcbc569SJames Smart 	if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start)
13162fcbc569SJames Smart 		return;
13172fcbc569SJames Smart 	if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput)
13182fcbc569SJames Smart 		return;
13192fcbc569SJames Smart 	if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl)
13202fcbc569SJames Smart 		return;
13212fcbc569SJames Smart 	/*
13222fcbc569SJames Smart 	 * Segment 1 - Time from Last FCP command cmpl is handed
13232fcbc569SJames Smart 	 * off to NVME Layer to start of next command.
13242fcbc569SJames Smart 	 * Segment 2 - Time from Driver receives a IO cmd start
13252fcbc569SJames Smart 	 * from NVME Layer to WQ put is done on IO cmd.
13262fcbc569SJames Smart 	 * Segment 3 - Time from Driver WQ put is done on IO cmd
13272fcbc569SJames Smart 	 * to MSI-X ISR for IO cmpl.
13282fcbc569SJames Smart 	 * Segment 4 - Time from MSI-X ISR for IO cmpl to when
13292fcbc569SJames Smart 	 * cmpl is handled off to the NVME Layer.
13302fcbc569SJames Smart 	 */
13312fcbc569SJames Smart 	seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd;
13322fcbc569SJames Smart 	if (seg1 > 5000000)  /* 5 ms - for sequential IOs only */
13332fcbc569SJames Smart 		seg1 = 0;
13342fcbc569SJames Smart 
13352fcbc569SJames Smart 	/* Calculate times relative to start of IO */
13362fcbc569SJames Smart 	seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start);
13372fcbc569SJames Smart 	segsum = seg2;
13382fcbc569SJames Smart 	seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start;
13392fcbc569SJames Smart 	if (segsum > seg3)
13402fcbc569SJames Smart 		return;
13412fcbc569SJames Smart 	seg3 -= segsum;
13422fcbc569SJames Smart 	segsum += seg3;
13432fcbc569SJames Smart 
13442fcbc569SJames Smart 	seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start;
13452fcbc569SJames Smart 	if (segsum > seg4)
13462fcbc569SJames Smart 		return;
13472fcbc569SJames Smart 	seg4 -= segsum;
13482fcbc569SJames Smart 
13492fcbc569SJames Smart 	phba->ktime_data_samples++;
13502fcbc569SJames Smart 	phba->ktime_seg1_total += seg1;
13512fcbc569SJames Smart 	if (seg1 < phba->ktime_seg1_min)
13522fcbc569SJames Smart 		phba->ktime_seg1_min = seg1;
13532fcbc569SJames Smart 	else if (seg1 > phba->ktime_seg1_max)
13542fcbc569SJames Smart 		phba->ktime_seg1_max = seg1;
13552fcbc569SJames Smart 	phba->ktime_seg2_total += seg2;
13562fcbc569SJames Smart 	if (seg2 < phba->ktime_seg2_min)
13572fcbc569SJames Smart 		phba->ktime_seg2_min = seg2;
13582fcbc569SJames Smart 	else if (seg2 > phba->ktime_seg2_max)
13592fcbc569SJames Smart 		phba->ktime_seg2_max = seg2;
13602fcbc569SJames Smart 	phba->ktime_seg3_total += seg3;
13612fcbc569SJames Smart 	if (seg3 < phba->ktime_seg3_min)
13622fcbc569SJames Smart 		phba->ktime_seg3_min = seg3;
13632fcbc569SJames Smart 	else if (seg3 > phba->ktime_seg3_max)
13642fcbc569SJames Smart 		phba->ktime_seg3_max = seg3;
13652fcbc569SJames Smart 	phba->ktime_seg4_total += seg4;
13662fcbc569SJames Smart 	if (seg4 < phba->ktime_seg4_min)
13672fcbc569SJames Smart 		phba->ktime_seg4_min = seg4;
13682fcbc569SJames Smart 	else if (seg4 > phba->ktime_seg4_max)
13692fcbc569SJames Smart 		phba->ktime_seg4_max = seg4;
13702fcbc569SJames Smart 
13712fcbc569SJames Smart 	lpfc_cmd->ts_last_cmd = 0;
13722fcbc569SJames Smart 	lpfc_cmd->ts_cmd_start = 0;
13732fcbc569SJames Smart 	lpfc_cmd->ts_cmd_wqput  = 0;
13742fcbc569SJames Smart 	lpfc_cmd->ts_isr_cmpl = 0;
13752fcbc569SJames Smart 	lpfc_cmd->ts_data_io = 0;
13762fcbc569SJames Smart }
13772fcbc569SJames Smart 
1378bd2cdd5eSJames Smart /**
13792fcbc569SJames Smart  * lpfc_debugfs_ioktime_data - Dump target node list to a buffer
1380bd2cdd5eSJames Smart  * @vport: The vport to gather target node info from.
1381bd2cdd5eSJames Smart  * @buf: The buffer to dump log into.
1382bd2cdd5eSJames Smart  * @size: The maximum amount of data to process.
1383bd2cdd5eSJames Smart  *
1384bd2cdd5eSJames Smart  * Description:
1385bd2cdd5eSJames Smart  * This routine dumps the NVME statistics associated with @vport
1386bd2cdd5eSJames Smart  *
1387bd2cdd5eSJames Smart  * Return Value:
1388bd2cdd5eSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
1389bd2cdd5eSJames Smart  * not exceed @size.
1390bd2cdd5eSJames Smart  **/
1391bd2cdd5eSJames Smart static int
lpfc_debugfs_ioktime_data(struct lpfc_vport * vport,char * buf,int size)13922fcbc569SJames Smart lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size)
1393bd2cdd5eSJames Smart {
1394bd2cdd5eSJames Smart 	struct lpfc_hba   *phba = vport->phba;
1395bd2cdd5eSJames Smart 	int len = 0;
1396bd2cdd5eSJames Smart 
1397bd2cdd5eSJames Smart 	if (phba->nvmet_support == 0) {
13982fcbc569SJames Smart 		/* Initiator */
1399e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, PAGE_SIZE - len,
1400bd2cdd5eSJames Smart 				"ktime %s: Total Samples: %lld\n",
1401bd2cdd5eSJames Smart 				(phba->ktime_on ?  "Enabled" : "Disabled"),
1402bd2cdd5eSJames Smart 				phba->ktime_data_samples);
1403bd2cdd5eSJames Smart 		if (phba->ktime_data_samples == 0)
1404bd2cdd5eSJames Smart 			return len;
1405bd2cdd5eSJames Smart 
1406e7f7b6f3SSilvio Cesare 		len += scnprintf(
1407bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
14082fcbc569SJames Smart 			"Segment 1: Last Cmd cmpl "
14092fcbc569SJames Smart 			"done -to- Start of next Cmd (in driver)\n");
1410e7f7b6f3SSilvio Cesare 		len += scnprintf(
1411bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1412bd2cdd5eSJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
141390ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg1_total,
141490ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
1415bd2cdd5eSJames Smart 			phba->ktime_seg1_min,
1416bd2cdd5eSJames Smart 			phba->ktime_seg1_max);
1417e7f7b6f3SSilvio Cesare 		len += scnprintf(
1418bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
14192fcbc569SJames Smart 			"Segment 2: Driver start of Cmd "
1420bd2cdd5eSJames Smart 			"-to- Firmware WQ doorbell\n");
1421e7f7b6f3SSilvio Cesare 		len += scnprintf(
1422bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1423bd2cdd5eSJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
142490ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg2_total,
142590ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
1426bd2cdd5eSJames Smart 			phba->ktime_seg2_min,
1427bd2cdd5eSJames Smart 			phba->ktime_seg2_max);
1428e7f7b6f3SSilvio Cesare 		len += scnprintf(
1429bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1430bd2cdd5eSJames Smart 			"Segment 3: Firmware WQ doorbell -to- "
1431bd2cdd5eSJames Smart 			"MSI-X ISR cmpl\n");
1432e7f7b6f3SSilvio Cesare 		len += scnprintf(
1433bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1434bd2cdd5eSJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
143590ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg3_total,
143690ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
1437bd2cdd5eSJames Smart 			phba->ktime_seg3_min,
1438bd2cdd5eSJames Smart 			phba->ktime_seg3_max);
1439e7f7b6f3SSilvio Cesare 		len += scnprintf(
1440bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1441bd2cdd5eSJames Smart 			"Segment 4: MSI-X ISR cmpl -to- "
14422fcbc569SJames Smart 			"Cmd cmpl done\n");
1443e7f7b6f3SSilvio Cesare 		len += scnprintf(
1444bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1445bd2cdd5eSJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
144690ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg4_total,
144790ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
1448bd2cdd5eSJames Smart 			phba->ktime_seg4_min,
1449bd2cdd5eSJames Smart 			phba->ktime_seg4_max);
1450e7f7b6f3SSilvio Cesare 		len += scnprintf(
1451bd2cdd5eSJames Smart 			buf + len, PAGE_SIZE - len,
1452bd2cdd5eSJames Smart 			"Total IO avg time: %08lld\n",
145390ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg1_total +
1454bd2cdd5eSJames Smart 			phba->ktime_seg2_total  +
1455bd2cdd5eSJames Smart 			phba->ktime_seg3_total +
145690ec7c9dSArnd Bergmann 			phba->ktime_seg4_total,
1457bd2cdd5eSJames Smart 			phba->ktime_data_samples));
1458bd2cdd5eSJames Smart 		return len;
1459bd2cdd5eSJames Smart 	}
14602b65e182SJames Smart 
14612b65e182SJames Smart 	/* NVME Target */
1462e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14632b65e182SJames Smart 			"ktime %s: Total Samples: %lld %lld\n",
14642b65e182SJames Smart 			(phba->ktime_on ? "Enabled" : "Disabled"),
14652b65e182SJames Smart 			phba->ktime_data_samples,
14662b65e182SJames Smart 			phba->ktime_status_samples);
14672b65e182SJames Smart 	if (phba->ktime_data_samples == 0)
14682b65e182SJames Smart 		return len;
14692b65e182SJames Smart 
1470e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14712b65e182SJames Smart 			"Segment 1: MSI-X ISR Rcv cmd -to- "
14722b65e182SJames Smart 			"cmd pass to NVME Layer\n");
1473e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14742b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
147590ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg1_total,
147690ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
14772b65e182SJames Smart 			phba->ktime_seg1_min,
14782b65e182SJames Smart 			phba->ktime_seg1_max);
1479e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14802b65e182SJames Smart 			"Segment 2: cmd pass to NVME Layer- "
14812b65e182SJames Smart 			"-to- Driver rcv cmd OP (action)\n");
1482e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14832b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
148490ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg2_total,
148590ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
14862b65e182SJames Smart 			phba->ktime_seg2_min,
14872b65e182SJames Smart 			phba->ktime_seg2_max);
1488e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14892b65e182SJames Smart 			"Segment 3: Driver rcv cmd OP -to- "
14902b65e182SJames Smart 			"Firmware WQ doorbell: cmd\n");
1491e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14922b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
149390ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg3_total,
149490ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
14952b65e182SJames Smart 			phba->ktime_seg3_min,
14962b65e182SJames Smart 			phba->ktime_seg3_max);
1497e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
14982b65e182SJames Smart 			"Segment 4: Firmware WQ doorbell: cmd "
14992b65e182SJames Smart 			"-to- MSI-X ISR for cmd cmpl\n");
1500e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15012b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
150290ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg4_total,
150390ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
15042b65e182SJames Smart 			phba->ktime_seg4_min,
15052b65e182SJames Smart 			phba->ktime_seg4_max);
1506e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15072b65e182SJames Smart 			"Segment 5: MSI-X ISR for cmd cmpl "
15082b65e182SJames Smart 			"-to- NVME layer passed cmd done\n");
1509e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15102b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
151190ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg5_total,
151290ec7c9dSArnd Bergmann 				phba->ktime_data_samples),
15132b65e182SJames Smart 			phba->ktime_seg5_min,
15142b65e182SJames Smart 			phba->ktime_seg5_max);
15152b65e182SJames Smart 
15162b65e182SJames Smart 	if (phba->ktime_status_samples == 0) {
1517e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, PAGE_SIZE-len,
15182b65e182SJames Smart 				"Total: cmd received by MSI-X ISR "
15192b65e182SJames Smart 				"-to- cmd completed on wire\n");
1520e7f7b6f3SSilvio Cesare 		len += scnprintf(buf + len, PAGE_SIZE-len,
15212b65e182SJames Smart 				"avg:%08lld min:%08lld "
15222b65e182SJames Smart 				"max %08lld\n",
152390ec7c9dSArnd Bergmann 				div_u64(phba->ktime_seg10_total,
152490ec7c9dSArnd Bergmann 					phba->ktime_data_samples),
15252b65e182SJames Smart 				phba->ktime_seg10_min,
15262b65e182SJames Smart 				phba->ktime_seg10_max);
15272b65e182SJames Smart 		return len;
15282b65e182SJames Smart 	}
15292b65e182SJames Smart 
1530e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15312b65e182SJames Smart 			"Segment 6: NVME layer passed cmd done "
15322b65e182SJames Smart 			"-to- Driver rcv rsp status OP\n");
1533e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15342b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
153590ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg6_total,
153690ec7c9dSArnd Bergmann 				phba->ktime_status_samples),
15372b65e182SJames Smart 			phba->ktime_seg6_min,
15382b65e182SJames Smart 			phba->ktime_seg6_max);
1539e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15402b65e182SJames Smart 			"Segment 7: Driver rcv rsp status OP "
15412b65e182SJames Smart 			"-to- Firmware WQ doorbell: status\n");
1542e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15432b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
154490ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg7_total,
154590ec7c9dSArnd Bergmann 				phba->ktime_status_samples),
15462b65e182SJames Smart 			phba->ktime_seg7_min,
15472b65e182SJames Smart 			phba->ktime_seg7_max);
1548e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15492b65e182SJames Smart 			"Segment 8: Firmware WQ doorbell: status"
15502b65e182SJames Smart 			" -to- MSI-X ISR for status cmpl\n");
1551e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15522b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
155390ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg8_total,
155490ec7c9dSArnd Bergmann 				phba->ktime_status_samples),
15552b65e182SJames Smart 			phba->ktime_seg8_min,
15562b65e182SJames Smart 			phba->ktime_seg8_max);
1557e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15582b65e182SJames Smart 			"Segment 9: MSI-X ISR for status cmpl  "
15592b65e182SJames Smart 			"-to- NVME layer passed status done\n");
1560e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15612b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
156290ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg9_total,
156390ec7c9dSArnd Bergmann 				phba->ktime_status_samples),
15642b65e182SJames Smart 			phba->ktime_seg9_min,
15652b65e182SJames Smart 			phba->ktime_seg9_max);
1566e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15672b65e182SJames Smart 			"Total: cmd received by MSI-X ISR -to- "
15682b65e182SJames Smart 			"cmd completed on wire\n");
1569e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, PAGE_SIZE-len,
15702b65e182SJames Smart 			"avg:%08lld min:%08lld max %08lld\n",
157190ec7c9dSArnd Bergmann 			div_u64(phba->ktime_seg10_total,
157290ec7c9dSArnd Bergmann 				phba->ktime_status_samples),
15732b65e182SJames Smart 			phba->ktime_seg10_min,
15742b65e182SJames Smart 			phba->ktime_seg10_max);
1575bd2cdd5eSJames Smart 	return len;
1576bd2cdd5eSJames Smart }
1577bd2cdd5eSJames Smart 
1578bd2cdd5eSJames Smart /**
1579bd2cdd5eSJames Smart  * lpfc_debugfs_nvmeio_trc_data - Dump NVME IO trace list to a buffer
1580bd2cdd5eSJames Smart  * @phba: The phba to gather target node info from.
1581bd2cdd5eSJames Smart  * @buf: The buffer to dump log into.
1582bd2cdd5eSJames Smart  * @size: The maximum amount of data to process.
1583bd2cdd5eSJames Smart  *
1584bd2cdd5eSJames Smart  * Description:
1585bd2cdd5eSJames Smart  * This routine dumps the NVME IO trace associated with @phba
1586bd2cdd5eSJames Smart  *
1587bd2cdd5eSJames Smart  * Return Value:
1588bd2cdd5eSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
1589bd2cdd5eSJames Smart  * not exceed @size.
1590bd2cdd5eSJames Smart  **/
1591bd2cdd5eSJames Smart static int
lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba * phba,char * buf,int size)1592bd2cdd5eSJames Smart lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
1593bd2cdd5eSJames Smart {
1594bd2cdd5eSJames Smart 	struct lpfc_debugfs_nvmeio_trc *dtp;
1595bd2cdd5eSJames Smart 	int i, state, index, skip;
1596bd2cdd5eSJames Smart 	int len = 0;
1597bd2cdd5eSJames Smart 
1598bd2cdd5eSJames Smart 	state = phba->nvmeio_trc_on;
1599bd2cdd5eSJames Smart 
1600bd2cdd5eSJames Smart 	index = (atomic_read(&phba->nvmeio_trc_cnt) + 1) &
1601bd2cdd5eSJames Smart 		(phba->nvmeio_trc_size - 1);
1602bd2cdd5eSJames Smart 	skip = phba->nvmeio_trc_output_idx;
1603bd2cdd5eSJames Smart 
1604e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len,
1605bd2cdd5eSJames Smart 			"%s IO Trace %s: next_idx %d skip %d size %d\n",
1606bd2cdd5eSJames Smart 			(phba->nvmet_support ? "NVME" : "NVMET"),
1607bd2cdd5eSJames Smart 			(state ? "Enabled" : "Disabled"),
1608bd2cdd5eSJames Smart 			index, skip, phba->nvmeio_trc_size);
1609bd2cdd5eSJames Smart 
1610bd2cdd5eSJames Smart 	if (!phba->nvmeio_trc || state)
1611bd2cdd5eSJames Smart 		return len;
1612bd2cdd5eSJames Smart 
1613bd2cdd5eSJames Smart 	/* trace MUST bhe off to continue */
1614bd2cdd5eSJames Smart 
1615bd2cdd5eSJames Smart 	for (i = index; i < phba->nvmeio_trc_size; i++) {
1616bd2cdd5eSJames Smart 		if (skip) {
1617bd2cdd5eSJames Smart 			skip--;
1618bd2cdd5eSJames Smart 			continue;
1619bd2cdd5eSJames Smart 		}
1620bd2cdd5eSJames Smart 		dtp = phba->nvmeio_trc + i;
1621bd2cdd5eSJames Smart 		phba->nvmeio_trc_output_idx++;
1622bd2cdd5eSJames Smart 
1623bd2cdd5eSJames Smart 		if (!dtp->fmt)
1624bd2cdd5eSJames Smart 			continue;
1625bd2cdd5eSJames Smart 
1626e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf + len, size - len, dtp->fmt,
1627bd2cdd5eSJames Smart 			dtp->data1, dtp->data2, dtp->data3);
1628bd2cdd5eSJames Smart 
1629bd2cdd5eSJames Smart 		if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
1630bd2cdd5eSJames Smart 			phba->nvmeio_trc_output_idx = 0;
1631e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
1632bd2cdd5eSJames Smart 					"Trace Complete\n");
1633bd2cdd5eSJames Smart 			goto out;
1634bd2cdd5eSJames Smart 		}
1635bd2cdd5eSJames Smart 
1636bd2cdd5eSJames Smart 		if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
1637e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
1638bd2cdd5eSJames Smart 					"Trace Continue (%d of %d)\n",
1639bd2cdd5eSJames Smart 					phba->nvmeio_trc_output_idx,
1640bd2cdd5eSJames Smart 					phba->nvmeio_trc_size);
1641bd2cdd5eSJames Smart 			goto out;
1642bd2cdd5eSJames Smart 		}
1643bd2cdd5eSJames Smart 	}
1644bd2cdd5eSJames Smart 	for (i = 0; i < index; i++) {
1645bd2cdd5eSJames Smart 		if (skip) {
1646bd2cdd5eSJames Smart 			skip--;
1647bd2cdd5eSJames Smart 			continue;
1648bd2cdd5eSJames Smart 		}
1649bd2cdd5eSJames Smart 		dtp = phba->nvmeio_trc + i;
1650bd2cdd5eSJames Smart 		phba->nvmeio_trc_output_idx++;
1651bd2cdd5eSJames Smart 
1652bd2cdd5eSJames Smart 		if (!dtp->fmt)
1653bd2cdd5eSJames Smart 			continue;
1654bd2cdd5eSJames Smart 
1655e7f7b6f3SSilvio Cesare 		len +=  scnprintf(buf + len, size - len, dtp->fmt,
1656bd2cdd5eSJames Smart 			dtp->data1, dtp->data2, dtp->data3);
1657bd2cdd5eSJames Smart 
1658bd2cdd5eSJames Smart 		if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
1659bd2cdd5eSJames Smart 			phba->nvmeio_trc_output_idx = 0;
1660e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
1661bd2cdd5eSJames Smart 					"Trace Complete\n");
1662bd2cdd5eSJames Smart 			goto out;
1663bd2cdd5eSJames Smart 		}
1664bd2cdd5eSJames Smart 
1665bd2cdd5eSJames Smart 		if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
1666e7f7b6f3SSilvio Cesare 			len += scnprintf(buf + len, size - len,
1667bd2cdd5eSJames Smart 					"Trace Continue (%d of %d)\n",
1668bd2cdd5eSJames Smart 					phba->nvmeio_trc_output_idx,
1669bd2cdd5eSJames Smart 					phba->nvmeio_trc_size);
1670bd2cdd5eSJames Smart 			goto out;
1671bd2cdd5eSJames Smart 		}
1672bd2cdd5eSJames Smart 	}
1673bd2cdd5eSJames Smart 
1674e7f7b6f3SSilvio Cesare 	len += scnprintf(buf + len, size - len,
1675bd2cdd5eSJames Smart 			"Trace Done\n");
1676bd2cdd5eSJames Smart out:
1677bd2cdd5eSJames Smart 	return len;
1678bd2cdd5eSJames Smart }
1679bd2cdd5eSJames Smart 
1680bd2cdd5eSJames Smart /**
1681840eda96SJames Smart  * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer
1682bd2cdd5eSJames Smart  * @vport: The vport to gather target node info from.
1683bd2cdd5eSJames Smart  * @buf: The buffer to dump log into.
1684bd2cdd5eSJames Smart  * @size: The maximum amount of data to process.
1685bd2cdd5eSJames Smart  *
1686bd2cdd5eSJames Smart  * Description:
1687840eda96SJames Smart  * This routine dumps the NVME + SCSI statistics associated with @vport
1688bd2cdd5eSJames Smart  *
1689bd2cdd5eSJames Smart  * Return Value:
1690bd2cdd5eSJames Smart  * This routine returns the amount of bytes that were dumped into @buf and will
1691bd2cdd5eSJames Smart  * not exceed @size.
1692bd2cdd5eSJames Smart  **/
1693bd2cdd5eSJames Smart static int
lpfc_debugfs_hdwqstat_data(struct lpfc_vport * vport,char * buf,int size)1694840eda96SJames Smart lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size)
1695bd2cdd5eSJames Smart {
1696bd2cdd5eSJames Smart 	struct lpfc_hba   *phba = vport->phba;
1697840eda96SJames Smart 	struct lpfc_hdwq_stat *c_stat;
1698840eda96SJames Smart 	int i, j, len;
169963df6d63SJames Smart 	uint32_t tot_xmt;
170063df6d63SJames Smart 	uint32_t tot_rcv;
170163df6d63SJames Smart 	uint32_t tot_cmpl;
1702840eda96SJames Smart 	char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};
1703bd2cdd5eSJames Smart 
1704840eda96SJames Smart 	scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n");
1705840eda96SJames Smart 	if (strlcat(buf, tmp, size) >= size)
1706840eda96SJames Smart 		goto buffer_done;
1707840eda96SJames Smart 
1708840eda96SJames Smart 	scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ",
1709840eda96SJames Smart 		  (phba->hdwqstat_on &
1710840eda96SJames Smart 		  (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ?
171163df6d63SJames Smart 		  "Enabled" : "Disabled"));
1712840eda96SJames Smart 	if (strlcat(buf, tmp, size) >= size)
1713840eda96SJames Smart 		goto buffer_done;
1714840eda96SJames Smart 
1715840eda96SJames Smart 	scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ",
1716840eda96SJames Smart 		  (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ?
1717840eda96SJames Smart 		  "Enabled" : "Disabled"));
1718840eda96SJames Smart 	if (strlcat(buf, tmp, size) >= size)
1719840eda96SJames Smart 		goto buffer_done;
1720840eda96SJames Smart 
1721840eda96SJames Smart 	scnprintf(tmp, sizeof(tmp), "\n\n");
1722840eda96SJames Smart 	if (strlcat(buf, tmp, size) >= size)
1723840eda96SJames Smart 		goto buffer_done;
172463df6d63SJames Smart 
172563df6d63SJames Smart 	for (i = 0; i < phba->cfg_hdw_queue; i++) {
172663df6d63SJames Smart 		tot_rcv = 0;
172763df6d63SJames Smart 		tot_xmt = 0;
172863df6d63SJames Smart 		tot_cmpl = 0;
1729840eda96SJames Smart 
1730840eda96SJames Smart 		for_each_present_cpu(j) {
1731840eda96SJames Smart 			c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j);
1732840eda96SJames Smart 
1733840eda96SJames Smart 			/* Only display for this HDWQ */
1734840eda96SJames Smart 			if (i != c_stat->hdwq_no)
1735840eda96SJames Smart 				continue;
1736840eda96SJames Smart 
1737840eda96SJames Smart 			/* Only display non-zero counters */
1738840eda96SJames Smart 			if (!c_stat->xmt_io && !c_stat->cmpl_io &&
1739840eda96SJames Smart 			    !c_stat->rcv_io)
1740840eda96SJames Smart 				continue;
1741840eda96SJames Smart 
1742840eda96SJames Smart 			if (!tot_xmt && !tot_cmpl && !tot_rcv) {
1743840eda96SJames Smart 				/* Print HDWQ string only the first time */
1744840eda96SJames Smart 				scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i);
1745840eda96SJames Smart 				if (strlcat(buf, tmp, size) >= size)
1746840eda96SJames Smart 					goto buffer_done;
174763df6d63SJames Smart 			}
174863df6d63SJames Smart 
1749840eda96SJames Smart 			tot_xmt += c_stat->xmt_io;
1750840eda96SJames Smart 			tot_cmpl += c_stat->cmpl_io;
1751840eda96SJames Smart 			if (phba->nvmet_support)
1752840eda96SJames Smart 				tot_rcv += c_stat->rcv_io;
1753840eda96SJames Smart 
1754840eda96SJames Smart 			scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j);
1755840eda96SJames Smart 			if (strlcat(buf, tmp, size) >= size)
1756840eda96SJames Smart 				goto buffer_done;
1757840eda96SJames Smart 
1758840eda96SJames Smart 			if (phba->nvmet_support) {
1759840eda96SJames Smart 				scnprintf(tmp, sizeof(tmp),
1760840eda96SJames Smart 					  "XMT 0x%x CMPL 0x%x RCV 0x%x |",
1761840eda96SJames Smart 					  c_stat->xmt_io, c_stat->cmpl_io,
1762840eda96SJames Smart 					  c_stat->rcv_io);
1763840eda96SJames Smart 				if (strlcat(buf, tmp, size) >= size)
1764840eda96SJames Smart 					goto buffer_done;
1765840eda96SJames Smart 			} else {
1766840eda96SJames Smart 				scnprintf(tmp, sizeof(tmp),
1767840eda96SJames Smart 					  "XMT 0x%x CMPL 0x%x |",
1768840eda96SJames Smart 					  c_stat->xmt_io, c_stat->cmpl_io);
1769840eda96SJames Smart 				if (strlcat(buf, tmp, size) >= size)
1770840eda96SJames Smart 					goto buffer_done;
1771840eda96SJames Smart 			}
1772840eda96SJames Smart 		}
1773840eda96SJames Smart 
1774840eda96SJames Smart 		/* Check if nothing to display */
177563df6d63SJames Smart 		if (!tot_xmt && !tot_cmpl && !tot_rcv)
177663df6d63SJames Smart 			continue;
177763df6d63SJames Smart 
1778840eda96SJames Smart 		scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: ");
1779840eda96SJames Smart 		if (strlcat(buf, tmp, size) >= size)
1780840eda96SJames Smart 			goto buffer_done;
1781840eda96SJames Smart 
178263df6d63SJames Smart 		if (phba->nvmet_support) {
1783840eda96SJames Smart 			scnprintf(tmp, sizeof(tmp),
1784840eda96SJames Smart 				  "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n",
1785840eda96SJames Smart 				  tot_xmt, tot_cmpl, tot_rcv);
1786840eda96SJames Smart 			if (strlcat(buf, tmp, size) >= size)
1787840eda96SJames Smart 				goto buffer_done;
178863df6d63SJames Smart 		} else {
1789840eda96SJames Smart 			scnprintf(tmp, sizeof(tmp),
1790840eda96SJames Smart 				  "XMT 0x%x CMPL 0x%x]\n\n",
1791840eda96SJames Smart 				  tot_xmt, tot_cmpl);
1792840eda96SJames Smart 			if (strlcat(buf, tmp, size) >= size)
1793840eda96SJames Smart 				goto buffer_done;
179463df6d63SJames Smart 		}
17952b65e182SJames Smart 	}
1796840eda96SJames Smart 
1797840eda96SJames Smart buffer_done:
1798840eda96SJames Smart 	len = strnlen(buf, size);
1799858c9f6cSJames Smart 	return len;
1800858c9f6cSJames Smart }
18012ea259eeSJames Smart 
1802858c9f6cSJames Smart #endif
1803858c9f6cSJames Smart 
1804e59058c4SJames Smart /**
18053621a710SJames Smart  * lpfc_debugfs_disc_trc - Store discovery trace log
1806e59058c4SJames Smart  * @vport: The vport to associate this trace string with for retrieval.
1807e59058c4SJames Smart  * @mask: Log entry classification.
1808e59058c4SJames Smart  * @fmt: Format string to be displayed when dumping the log.
1809e59058c4SJames Smart  * @data1: 1st data parameter to be applied to @fmt.
1810e59058c4SJames Smart  * @data2: 2nd data parameter to be applied to @fmt.
1811e59058c4SJames Smart  * @data3: 3rd data parameter to be applied to @fmt.
1812e59058c4SJames Smart  *
1813e59058c4SJames Smart  * Description:
1814e59058c4SJames Smart  * This routine is used by the driver code to add a debugfs log entry to the
1815e59058c4SJames Smart  * discovery trace buffer associated with @vport. Only entries with a @mask that
1816e59058c4SJames Smart  * match the current debugfs discovery mask will be saved. Entries that do not
1817e59058c4SJames Smart  * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like
1818e59058c4SJames Smart  * printf when displaying the log.
1819e59058c4SJames Smart  **/
1820858c9f6cSJames Smart inline void
lpfc_debugfs_disc_trc(struct lpfc_vport * vport,int mask,char * fmt,uint32_t data1,uint32_t data2,uint32_t data3)1821858c9f6cSJames Smart lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
1822858c9f6cSJames Smart 	uint32_t data1, uint32_t data2, uint32_t data3)
1823858c9f6cSJames Smart {
1824923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1825a58cbd52SJames Smart 	struct lpfc_debugfs_trc *dtp;
1826858c9f6cSJames Smart 	int index;
1827858c9f6cSJames Smart 
1828858c9f6cSJames Smart 	if (!(lpfc_debugfs_mask_disc_trc & mask))
1829858c9f6cSJames Smart 		return;
1830858c9f6cSJames Smart 
1831858c9f6cSJames Smart 	if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
1832858c9f6cSJames Smart 		!vport || !vport->disc_trc)
1833858c9f6cSJames Smart 		return;
1834858c9f6cSJames Smart 
1835858c9f6cSJames Smart 	index = atomic_inc_return(&vport->disc_trc_cnt) &
1836858c9f6cSJames Smart 		(lpfc_debugfs_max_disc_trc - 1);
1837858c9f6cSJames Smart 	dtp = vport->disc_trc + index;
1838858c9f6cSJames Smart 	dtp->fmt = fmt;
1839858c9f6cSJames Smart 	dtp->data1 = data1;
1840858c9f6cSJames Smart 	dtp->data2 = data2;
1841858c9f6cSJames Smart 	dtp->data3 = data3;
1842a58cbd52SJames Smart 	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
1843a58cbd52SJames Smart 	dtp->jif = jiffies;
1844a58cbd52SJames Smart #endif
1845a58cbd52SJames Smart 	return;
1846a58cbd52SJames Smart }
1847a58cbd52SJames Smart 
1848e59058c4SJames Smart /**
18493621a710SJames Smart  * lpfc_debugfs_slow_ring_trc - Store slow ring trace log
1850e59058c4SJames Smart  * @phba: The phba to associate this trace string with for retrieval.
1851e59058c4SJames Smart  * @fmt: Format string to be displayed when dumping the log.
1852e59058c4SJames Smart  * @data1: 1st data parameter to be applied to @fmt.
1853e59058c4SJames Smart  * @data2: 2nd data parameter to be applied to @fmt.
1854e59058c4SJames Smart  * @data3: 3rd data parameter to be applied to @fmt.
1855e59058c4SJames Smart  *
1856e59058c4SJames Smart  * Description:
1857e59058c4SJames Smart  * This routine is used by the driver code to add a debugfs log entry to the
1858e59058c4SJames Smart  * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and
1859e59058c4SJames Smart  * @data3 are used like printf when displaying the log.
1860e59058c4SJames Smart  **/
1861a58cbd52SJames Smart inline void
lpfc_debugfs_slow_ring_trc(struct lpfc_hba * phba,char * fmt,uint32_t data1,uint32_t data2,uint32_t data3)1862a58cbd52SJames Smart lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt,
1863a58cbd52SJames Smart 	uint32_t data1, uint32_t data2, uint32_t data3)
1864a58cbd52SJames Smart {
1865923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1866a58cbd52SJames Smart 	struct lpfc_debugfs_trc *dtp;
1867a58cbd52SJames Smart 	int index;
1868a58cbd52SJames Smart 
1869a58cbd52SJames Smart 	if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc ||
1870a58cbd52SJames Smart 		!phba || !phba->slow_ring_trc)
1871a58cbd52SJames Smart 		return;
1872a58cbd52SJames Smart 
1873a58cbd52SJames Smart 	index = atomic_inc_return(&phba->slow_ring_trc_cnt) &
1874a58cbd52SJames Smart 		(lpfc_debugfs_max_slow_ring_trc - 1);
1875a58cbd52SJames Smart 	dtp = phba->slow_ring_trc + index;
1876a58cbd52SJames Smart 	dtp->fmt = fmt;
1877a58cbd52SJames Smart 	dtp->data1 = data1;
1878a58cbd52SJames Smart 	dtp->data2 = data2;
1879a58cbd52SJames Smart 	dtp->data3 = data3;
1880a58cbd52SJames Smart 	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
1881858c9f6cSJames Smart 	dtp->jif = jiffies;
1882858c9f6cSJames Smart #endif
1883858c9f6cSJames Smart 	return;
1884858c9f6cSJames Smart }
1885858c9f6cSJames Smart 
1886bd2cdd5eSJames Smart /**
1887bd2cdd5eSJames Smart  * lpfc_debugfs_nvme_trc - Store NVME/NVMET trace log
1888bd2cdd5eSJames Smart  * @phba: The phba to associate this trace string with for retrieval.
1889bd2cdd5eSJames Smart  * @fmt: Format string to be displayed when dumping the log.
1890bd2cdd5eSJames Smart  * @data1: 1st data parameter to be applied to @fmt.
1891bd2cdd5eSJames Smart  * @data2: 2nd data parameter to be applied to @fmt.
1892bd2cdd5eSJames Smart  * @data3: 3rd data parameter to be applied to @fmt.
1893bd2cdd5eSJames Smart  *
1894bd2cdd5eSJames Smart  * Description:
1895bd2cdd5eSJames Smart  * This routine is used by the driver code to add a debugfs log entry to the
1896bd2cdd5eSJames Smart  * nvme trace buffer associated with @phba. @fmt, @data1, @data2, and
1897bd2cdd5eSJames Smart  * @data3 are used like printf when displaying the log.
1898bd2cdd5eSJames Smart  **/
1899bd2cdd5eSJames Smart inline void
lpfc_debugfs_nvme_trc(struct lpfc_hba * phba,char * fmt,uint16_t data1,uint16_t data2,uint32_t data3)1900bd2cdd5eSJames Smart lpfc_debugfs_nvme_trc(struct lpfc_hba *phba, char *fmt,
1901bd2cdd5eSJames Smart 		      uint16_t data1, uint16_t data2, uint32_t data3)
1902bd2cdd5eSJames Smart {
1903bd2cdd5eSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1904bd2cdd5eSJames Smart 	struct lpfc_debugfs_nvmeio_trc *dtp;
1905bd2cdd5eSJames Smart 	int index;
1906bd2cdd5eSJames Smart 
1907bd2cdd5eSJames Smart 	if (!phba->nvmeio_trc_on || !phba->nvmeio_trc)
1908bd2cdd5eSJames Smart 		return;
1909bd2cdd5eSJames Smart 
1910bd2cdd5eSJames Smart 	index = atomic_inc_return(&phba->nvmeio_trc_cnt) &
1911bd2cdd5eSJames Smart 		(phba->nvmeio_trc_size - 1);
1912bd2cdd5eSJames Smart 	dtp = phba->nvmeio_trc + index;
1913bd2cdd5eSJames Smart 	dtp->fmt = fmt;
1914bd2cdd5eSJames Smart 	dtp->data1 = data1;
1915bd2cdd5eSJames Smart 	dtp->data2 = data2;
1916bd2cdd5eSJames Smart 	dtp->data3 = data3;
1917bd2cdd5eSJames Smart #endif
1918bd2cdd5eSJames Smart }
1919bd2cdd5eSJames Smart 
1920923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
1921e59058c4SJames Smart /**
19223621a710SJames Smart  * lpfc_debugfs_disc_trc_open - Open the discovery trace log
1923e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
1924e59058c4SJames Smart  * @file: The file pointer to attach the log output.
1925e59058c4SJames Smart  *
1926e59058c4SJames Smart  * Description:
1927e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
1928e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
1929e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
1930e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
1931e59058c4SJames Smart  *
1932e59058c4SJames Smart  * Returns:
193379ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
1934e59058c4SJames Smart  * error value.
1935e59058c4SJames Smart  **/
1936858c9f6cSJames Smart static int
lpfc_debugfs_disc_trc_open(struct inode * inode,struct file * file)1937858c9f6cSJames Smart lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
1938858c9f6cSJames Smart {
1939858c9f6cSJames Smart 	struct lpfc_vport *vport = inode->i_private;
1940858c9f6cSJames Smart 	struct lpfc_debug *debug;
1941858c9f6cSJames Smart 	int size;
1942858c9f6cSJames Smart 	int rc = -ENOMEM;
1943858c9f6cSJames Smart 
1944858c9f6cSJames Smart 	if (!lpfc_debugfs_max_disc_trc) {
1945858c9f6cSJames Smart 		rc = -ENOSPC;
1946858c9f6cSJames Smart 		goto out;
1947858c9f6cSJames Smart 	}
1948858c9f6cSJames Smart 
1949858c9f6cSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
1950858c9f6cSJames Smart 	if (!debug)
1951858c9f6cSJames Smart 		goto out;
1952858c9f6cSJames Smart 
1953e59058c4SJames Smart 	/* Round to page boundary */
1954a58cbd52SJames Smart 	size =  (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
1955858c9f6cSJames Smart 	size = PAGE_ALIGN(size);
1956858c9f6cSJames Smart 
1957858c9f6cSJames Smart 	debug->buffer = kmalloc(size, GFP_KERNEL);
1958858c9f6cSJames Smart 	if (!debug->buffer) {
1959858c9f6cSJames Smart 		kfree(debug);
1960858c9f6cSJames Smart 		goto out;
1961858c9f6cSJames Smart 	}
1962858c9f6cSJames Smart 
1963858c9f6cSJames Smart 	debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
1964858c9f6cSJames Smart 	file->private_data = debug;
1965858c9f6cSJames Smart 
1966858c9f6cSJames Smart 	rc = 0;
1967858c9f6cSJames Smart out:
1968858c9f6cSJames Smart 	return rc;
1969858c9f6cSJames Smart }
1970858c9f6cSJames Smart 
1971e59058c4SJames Smart /**
19723621a710SJames Smart  * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log
1973e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
1974e59058c4SJames Smart  * @file: The file pointer to attach the log output.
1975e59058c4SJames Smart  *
1976e59058c4SJames Smart  * Description:
1977e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
1978e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
1979e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
1980e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
1981e59058c4SJames Smart  *
1982e59058c4SJames Smart  * Returns:
198379ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
1984e59058c4SJames Smart  * error value.
1985e59058c4SJames Smart  **/
1986858c9f6cSJames Smart static int
lpfc_debugfs_slow_ring_trc_open(struct inode * inode,struct file * file)1987a58cbd52SJames Smart lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file)
1988a58cbd52SJames Smart {
1989a58cbd52SJames Smart 	struct lpfc_hba *phba = inode->i_private;
1990a58cbd52SJames Smart 	struct lpfc_debug *debug;
1991a58cbd52SJames Smart 	int size;
1992a58cbd52SJames Smart 	int rc = -ENOMEM;
1993a58cbd52SJames Smart 
1994a58cbd52SJames Smart 	if (!lpfc_debugfs_max_slow_ring_trc) {
1995a58cbd52SJames Smart 		rc = -ENOSPC;
1996a58cbd52SJames Smart 		goto out;
1997a58cbd52SJames Smart 	}
1998a58cbd52SJames Smart 
1999a58cbd52SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2000a58cbd52SJames Smart 	if (!debug)
2001a58cbd52SJames Smart 		goto out;
2002a58cbd52SJames Smart 
2003e59058c4SJames Smart 	/* Round to page boundary */
2004a58cbd52SJames Smart 	size =  (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
2005a58cbd52SJames Smart 	size = PAGE_ALIGN(size);
2006a58cbd52SJames Smart 
2007a58cbd52SJames Smart 	debug->buffer = kmalloc(size, GFP_KERNEL);
2008a58cbd52SJames Smart 	if (!debug->buffer) {
2009a58cbd52SJames Smart 		kfree(debug);
2010a58cbd52SJames Smart 		goto out;
2011a58cbd52SJames Smart 	}
2012a58cbd52SJames Smart 
2013a58cbd52SJames Smart 	debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size);
2014a58cbd52SJames Smart 	file->private_data = debug;
2015a58cbd52SJames Smart 
2016a58cbd52SJames Smart 	rc = 0;
2017a58cbd52SJames Smart out:
2018a58cbd52SJames Smart 	return rc;
2019a58cbd52SJames Smart }
2020a58cbd52SJames Smart 
2021e59058c4SJames Smart /**
20223621a710SJames Smart  * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer
2023e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
2024e59058c4SJames Smart  * @file: The file pointer to attach the log output.
2025e59058c4SJames Smart  *
2026e59058c4SJames Smart  * Description:
2027e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
2028e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
2029e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
2030e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
2031e59058c4SJames Smart  *
2032e59058c4SJames Smart  * Returns:
203379ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
2034e59058c4SJames Smart  * error value.
2035e59058c4SJames Smart  **/
2036a58cbd52SJames Smart static int
lpfc_debugfs_hbqinfo_open(struct inode * inode,struct file * file)203778b2d852SJames Smart lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file)
203878b2d852SJames Smart {
203978b2d852SJames Smart 	struct lpfc_hba *phba = inode->i_private;
204078b2d852SJames Smart 	struct lpfc_debug *debug;
204178b2d852SJames Smart 	int rc = -ENOMEM;
204278b2d852SJames Smart 
204378b2d852SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
204478b2d852SJames Smart 	if (!debug)
204578b2d852SJames Smart 		goto out;
204678b2d852SJames Smart 
2047e59058c4SJames Smart 	/* Round to page boundary */
204878b2d852SJames Smart 	debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL);
204978b2d852SJames Smart 	if (!debug->buffer) {
205078b2d852SJames Smart 		kfree(debug);
205178b2d852SJames Smart 		goto out;
205278b2d852SJames Smart 	}
205378b2d852SJames Smart 
205478b2d852SJames Smart 	debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer,
205578b2d852SJames Smart 		LPFC_HBQINFO_SIZE);
205678b2d852SJames Smart 	file->private_data = debug;
205778b2d852SJames Smart 
205878b2d852SJames Smart 	rc = 0;
205978b2d852SJames Smart out:
206078b2d852SJames Smart 	return rc;
206178b2d852SJames Smart }
206278b2d852SJames Smart 
2063e59058c4SJames Smart /**
2064c490850aSJames Smart  * lpfc_debugfs_multixripools_open - Open the multixripool debugfs buffer
2065c490850aSJames Smart  * @inode: The inode pointer that contains a hba pointer.
2066c490850aSJames Smart  * @file: The file pointer to attach the log output.
2067c490850aSJames Smart  *
2068c490850aSJames Smart  * Description:
2069c490850aSJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
2070c490850aSJames Smart  * the hba from the i_private field in @inode, allocates the necessary buffer
2071c490850aSJames Smart  * for the log, fills the buffer from the in-memory log for this hba, and then
2072c490850aSJames Smart  * returns a pointer to that log in the private_data field in @file.
2073c490850aSJames Smart  *
2074c490850aSJames Smart  * Returns:
2075c490850aSJames Smart  * This function returns zero if successful. On error it will return a negative
2076c490850aSJames Smart  * error value.
2077c490850aSJames Smart  **/
2078c490850aSJames Smart static int
lpfc_debugfs_multixripools_open(struct inode * inode,struct file * file)2079c490850aSJames Smart lpfc_debugfs_multixripools_open(struct inode *inode, struct file *file)
2080c490850aSJames Smart {
2081c490850aSJames Smart 	struct lpfc_hba *phba = inode->i_private;
2082c490850aSJames Smart 	struct lpfc_debug *debug;
2083c490850aSJames Smart 	int rc = -ENOMEM;
2084c490850aSJames Smart 
2085c490850aSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2086c490850aSJames Smart 	if (!debug)
2087c490850aSJames Smart 		goto out;
2088c490850aSJames Smart 
2089c490850aSJames Smart 	/* Round to page boundary */
2090c490850aSJames Smart 	debug->buffer = kzalloc(LPFC_DUMP_MULTIXRIPOOL_SIZE, GFP_KERNEL);
2091c490850aSJames Smart 	if (!debug->buffer) {
2092c490850aSJames Smart 		kfree(debug);
2093c490850aSJames Smart 		goto out;
2094c490850aSJames Smart 	}
2095c490850aSJames Smart 
2096c490850aSJames Smart 	debug->len = lpfc_debugfs_multixripools_data(
2097c490850aSJames Smart 		phba, debug->buffer, LPFC_DUMP_MULTIXRIPOOL_SIZE);
2098c490850aSJames Smart 
2099c490850aSJames Smart 	debug->i_private = inode->i_private;
2100c490850aSJames Smart 	file->private_data = debug;
2101c490850aSJames Smart 
2102c490850aSJames Smart 	rc = 0;
2103c490850aSJames Smart out:
2104c490850aSJames Smart 	return rc;
2105c490850aSJames Smart }
2106c490850aSJames Smart 
21076a828b0fSJames Smart #ifdef LPFC_HDWQ_LOCK_STAT
2108c490850aSJames Smart /**
21096a828b0fSJames Smart  * lpfc_debugfs_lockstat_open - Open the lockstat debugfs buffer
21105e5b511dSJames Smart  * @inode: The inode pointer that contains a vport pointer.
21115e5b511dSJames Smart  * @file: The file pointer to attach the log output.
21125e5b511dSJames Smart  *
21135e5b511dSJames Smart  * Description:
21145e5b511dSJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
21155e5b511dSJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
21165e5b511dSJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
21175e5b511dSJames Smart  * returns a pointer to that log in the private_data field in @file.
21185e5b511dSJames Smart  *
21195e5b511dSJames Smart  * Returns:
21205e5b511dSJames Smart  * This function returns zero if successful. On error it will return a negative
21215e5b511dSJames Smart  * error value.
21225e5b511dSJames Smart  **/
21235e5b511dSJames Smart static int
lpfc_debugfs_lockstat_open(struct inode * inode,struct file * file)21246a828b0fSJames Smart lpfc_debugfs_lockstat_open(struct inode *inode, struct file *file)
21255e5b511dSJames Smart {
21265e5b511dSJames Smart 	struct lpfc_hba *phba = inode->i_private;
21275e5b511dSJames Smart 	struct lpfc_debug *debug;
21285e5b511dSJames Smart 	int rc = -ENOMEM;
21295e5b511dSJames Smart 
21305e5b511dSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
21315e5b511dSJames Smart 	if (!debug)
21325e5b511dSJames Smart 		goto out;
21335e5b511dSJames Smart 
21345e5b511dSJames Smart 	/* Round to page boundary */
21355e5b511dSJames Smart 	debug->buffer = kmalloc(LPFC_HDWQINFO_SIZE, GFP_KERNEL);
21365e5b511dSJames Smart 	if (!debug->buffer) {
21375e5b511dSJames Smart 		kfree(debug);
21385e5b511dSJames Smart 		goto out;
21395e5b511dSJames Smart 	}
21405e5b511dSJames Smart 
21416a828b0fSJames Smart 	debug->len = lpfc_debugfs_lockstat_data(phba, debug->buffer,
21425e5b511dSJames Smart 		LPFC_HBQINFO_SIZE);
21435e5b511dSJames Smart 	file->private_data = debug;
21445e5b511dSJames Smart 
21455e5b511dSJames Smart 	rc = 0;
21465e5b511dSJames Smart out:
21475e5b511dSJames Smart 	return rc;
21485e5b511dSJames Smart }
21495e5b511dSJames Smart 
21506a828b0fSJames Smart static ssize_t
lpfc_debugfs_lockstat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)21516a828b0fSJames Smart lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf,
21526a828b0fSJames Smart 			    size_t nbytes, loff_t *ppos)
21536a828b0fSJames Smart {
21546a828b0fSJames Smart 	struct lpfc_debug *debug = file->private_data;
21556a828b0fSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
21566a828b0fSJames Smart 	struct lpfc_sli4_hdw_queue *qp;
21576a828b0fSJames Smart 	char mybuf[64];
21586a828b0fSJames Smart 	char *pbuf;
21596a828b0fSJames Smart 	int i;
2160c6087b82SJustin Tee 	size_t bsize;
21616a828b0fSJames Smart 
21626a828b0fSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
21636a828b0fSJames Smart 
2164c6087b82SJustin Tee 	bsize = min(nbytes, (sizeof(mybuf) - 1));
2165c6087b82SJustin Tee 
2166c6087b82SJustin Tee 	if (copy_from_user(mybuf, buf, bsize))
21676a828b0fSJames Smart 		return -EFAULT;
21686a828b0fSJames Smart 	pbuf = &mybuf[0];
21696a828b0fSJames Smart 
21706a828b0fSJames Smart 	if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
21716a828b0fSJames Smart 	    (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
21726a828b0fSJames Smart 		for (i = 0; i < phba->cfg_hdw_queue; i++) {
21736a828b0fSJames Smart 			qp = &phba->sli4_hba.hdwq[i];
21746a828b0fSJames Smart 			qp->lock_conflict.alloc_xri_get = 0;
21756a828b0fSJames Smart 			qp->lock_conflict.alloc_xri_put = 0;
21766a828b0fSJames Smart 			qp->lock_conflict.free_xri = 0;
21776a828b0fSJames Smart 			qp->lock_conflict.wq_access = 0;
21786a828b0fSJames Smart 			qp->lock_conflict.alloc_pvt_pool = 0;
21796a828b0fSJames Smart 			qp->lock_conflict.mv_from_pvt_pool = 0;
21806a828b0fSJames Smart 			qp->lock_conflict.mv_to_pub_pool = 0;
21816a828b0fSJames Smart 			qp->lock_conflict.mv_to_pvt_pool = 0;
21826a828b0fSJames Smart 			qp->lock_conflict.free_pvt_pool = 0;
21836a828b0fSJames Smart 			qp->lock_conflict.free_pub_pool = 0;
21846a828b0fSJames Smart 			qp->lock_conflict.wq_access = 0;
21856a828b0fSJames Smart 		}
21866a828b0fSJames Smart 	}
2187c6087b82SJustin Tee 	return bsize;
21886a828b0fSJames Smart }
21896a828b0fSJames Smart #endif
21906a828b0fSJames Smart 
lpfc_debugfs_ras_log_data(struct lpfc_hba * phba,char * buffer,int size)21917b10db55SYueHaibing static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
21927b10db55SYueHaibing 				     char *buffer, int size)
219395bfc6d8SJames Smart {
219495bfc6d8SJames Smart 	int copied = 0;
219595bfc6d8SJames Smart 	struct lpfc_dmabuf *dmabuf, *next;
219695bfc6d8SJames Smart 
21979a20cc10SJames Smart 	memset(buffer, 0, size);
21989a20cc10SJames Smart 
2199e29758e7SJustin Tee 	spin_lock_irq(&phba->ras_fwlog_lock);
220095bfc6d8SJames Smart 	if (phba->ras_fwlog.state != ACTIVE) {
2201e29758e7SJustin Tee 		spin_unlock_irq(&phba->ras_fwlog_lock);
220295bfc6d8SJames Smart 		return -EINVAL;
220395bfc6d8SJames Smart 	}
2204e29758e7SJustin Tee 	spin_unlock_irq(&phba->ras_fwlog_lock);
220595bfc6d8SJames Smart 
220695bfc6d8SJames Smart 	list_for_each_entry_safe(dmabuf, next,
220795bfc6d8SJames Smart 				 &phba->ras_fwlog.fwlog_buff_list, list) {
22089a20cc10SJames Smart 		/* Check if copying will go over size and a '\0' char */
22099a20cc10SJames Smart 		if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) {
22109a20cc10SJames Smart 			memcpy(buffer + copied, dmabuf->virt,
22119a20cc10SJames Smart 			       size - copied - 1);
22129a20cc10SJames Smart 			copied += size - copied - 1;
22139a20cc10SJames Smart 			break;
22149a20cc10SJames Smart 		}
221595bfc6d8SJames Smart 		memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
221695bfc6d8SJames Smart 		copied += LPFC_RAS_MAX_ENTRY_SIZE;
221795bfc6d8SJames Smart 	}
221895bfc6d8SJames Smart 	return copied;
221995bfc6d8SJames Smart }
222095bfc6d8SJames Smart 
222195bfc6d8SJames Smart static int
lpfc_debugfs_ras_log_release(struct inode * inode,struct file * file)222295bfc6d8SJames Smart lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file)
222395bfc6d8SJames Smart {
222495bfc6d8SJames Smart 	struct lpfc_debug *debug = file->private_data;
222595bfc6d8SJames Smart 
222695bfc6d8SJames Smart 	vfree(debug->buffer);
222795bfc6d8SJames Smart 	kfree(debug);
222895bfc6d8SJames Smart 
222995bfc6d8SJames Smart 	return 0;
223095bfc6d8SJames Smart }
223195bfc6d8SJames Smart 
223295bfc6d8SJames Smart /**
223395bfc6d8SJames Smart  * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer
223495bfc6d8SJames Smart  * @inode: The inode pointer that contains a vport pointer.
223595bfc6d8SJames Smart  * @file: The file pointer to attach the log output.
223695bfc6d8SJames Smart  *
223795bfc6d8SJames Smart  * Description:
223895bfc6d8SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
223995bfc6d8SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
224095bfc6d8SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
224195bfc6d8SJames Smart  * returns a pointer to that log in the private_data field in @file.
224295bfc6d8SJames Smart  *
224395bfc6d8SJames Smart  * Returns:
224495bfc6d8SJames Smart  * This function returns zero if successful. On error it will return a negative
224595bfc6d8SJames Smart  * error value.
224695bfc6d8SJames Smart  **/
224795bfc6d8SJames Smart static int
lpfc_debugfs_ras_log_open(struct inode * inode,struct file * file)224895bfc6d8SJames Smart lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
224995bfc6d8SJames Smart {
225095bfc6d8SJames Smart 	struct lpfc_hba *phba = inode->i_private;
225195bfc6d8SJames Smart 	struct lpfc_debug *debug;
225295bfc6d8SJames Smart 	int size;
225395bfc6d8SJames Smart 	int rc = -ENOMEM;
225495bfc6d8SJames Smart 
2255e29758e7SJustin Tee 	spin_lock_irq(&phba->ras_fwlog_lock);
225695bfc6d8SJames Smart 	if (phba->ras_fwlog.state != ACTIVE) {
2257e29758e7SJustin Tee 		spin_unlock_irq(&phba->ras_fwlog_lock);
225895bfc6d8SJames Smart 		rc = -EINVAL;
225995bfc6d8SJames Smart 		goto out;
226095bfc6d8SJames Smart 	}
2261e29758e7SJustin Tee 	spin_unlock_irq(&phba->ras_fwlog_lock);
2262a48e2c32SGustavo A. R. Silva 
2263a48e2c32SGustavo A. R. Silva 	if (check_mul_overflow(LPFC_RAS_MIN_BUFF_POST_SIZE,
2264a48e2c32SGustavo A. R. Silva 			       phba->cfg_ras_fwlog_buffsize, &size))
2265a48e2c32SGustavo A. R. Silva 		goto out;
2266a48e2c32SGustavo A. R. Silva 
2267a48e2c32SGustavo A. R. Silva 	debug = kzalloc(sizeof(*debug), GFP_KERNEL);
226895bfc6d8SJames Smart 	if (!debug)
226995bfc6d8SJames Smart 		goto out;
227095bfc6d8SJames Smart 
227195bfc6d8SJames Smart 	debug->buffer = vmalloc(size);
227295bfc6d8SJames Smart 	if (!debug->buffer)
227395bfc6d8SJames Smart 		goto free_debug;
227495bfc6d8SJames Smart 
227595bfc6d8SJames Smart 	debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size);
227695bfc6d8SJames Smart 	if (debug->len < 0) {
227795bfc6d8SJames Smart 		rc = -EINVAL;
227895bfc6d8SJames Smart 		goto free_buffer;
227995bfc6d8SJames Smart 	}
228095bfc6d8SJames Smart 	file->private_data = debug;
228195bfc6d8SJames Smart 
228295bfc6d8SJames Smart 	return 0;
228395bfc6d8SJames Smart 
228495bfc6d8SJames Smart free_buffer:
228595bfc6d8SJames Smart 	vfree(debug->buffer);
228695bfc6d8SJames Smart free_debug:
228795bfc6d8SJames Smart 	kfree(debug);
228895bfc6d8SJames Smart out:
228995bfc6d8SJames Smart 	return rc;
229095bfc6d8SJames Smart }
229195bfc6d8SJames Smart 
22925e5b511dSJames Smart /**
22933621a710SJames Smart  * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer
2294e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
2295e59058c4SJames Smart  * @file: The file pointer to attach the log output.
2296e59058c4SJames Smart  *
2297e59058c4SJames Smart  * Description:
2298e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
2299e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
2300e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
2301e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
2302e59058c4SJames Smart  *
2303e59058c4SJames Smart  * Returns:
230479ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
2305e59058c4SJames Smart  * error value.
2306e59058c4SJames Smart  **/
230778b2d852SJames Smart static int
lpfc_debugfs_dumpHBASlim_open(struct inode * inode,struct file * file)2308c95d6c6cSJames Smart lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
2309a58cbd52SJames Smart {
2310a58cbd52SJames Smart 	struct lpfc_hba *phba = inode->i_private;
2311a58cbd52SJames Smart 	struct lpfc_debug *debug;
2312a58cbd52SJames Smart 	int rc = -ENOMEM;
2313a58cbd52SJames Smart 
2314a58cbd52SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2315a58cbd52SJames Smart 	if (!debug)
2316a58cbd52SJames Smart 		goto out;
2317a58cbd52SJames Smart 
2318e59058c4SJames Smart 	/* Round to page boundary */
2319c95d6c6cSJames Smart 	debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
2320a58cbd52SJames Smart 	if (!debug->buffer) {
2321a58cbd52SJames Smart 		kfree(debug);
2322a58cbd52SJames Smart 		goto out;
2323a58cbd52SJames Smart 	}
2324a58cbd52SJames Smart 
2325c95d6c6cSJames Smart 	debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
2326c95d6c6cSJames Smart 		LPFC_DUMPHBASLIM_SIZE);
2327c95d6c6cSJames Smart 	file->private_data = debug;
2328c95d6c6cSJames Smart 
2329c95d6c6cSJames Smart 	rc = 0;
2330c95d6c6cSJames Smart out:
2331c95d6c6cSJames Smart 	return rc;
2332c95d6c6cSJames Smart }
2333c95d6c6cSJames Smart 
2334e59058c4SJames Smart /**
23353621a710SJames Smart  * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer
2336e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
2337e59058c4SJames Smart  * @file: The file pointer to attach the log output.
2338e59058c4SJames Smart  *
2339e59058c4SJames Smart  * Description:
2340e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
2341e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
2342e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
2343e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
2344e59058c4SJames Smart  *
2345e59058c4SJames Smart  * Returns:
234679ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
2347e59058c4SJames Smart  * error value.
2348e59058c4SJames Smart  **/
2349c95d6c6cSJames Smart static int
lpfc_debugfs_dumpHostSlim_open(struct inode * inode,struct file * file)2350c95d6c6cSJames Smart lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
2351c95d6c6cSJames Smart {
2352c95d6c6cSJames Smart 	struct lpfc_hba *phba = inode->i_private;
2353c95d6c6cSJames Smart 	struct lpfc_debug *debug;
2354c95d6c6cSJames Smart 	int rc = -ENOMEM;
2355c95d6c6cSJames Smart 
2356c95d6c6cSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2357c95d6c6cSJames Smart 	if (!debug)
2358c95d6c6cSJames Smart 		goto out;
2359c95d6c6cSJames Smart 
2360e59058c4SJames Smart 	/* Round to page boundary */
2361c95d6c6cSJames Smart 	debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
2362c95d6c6cSJames Smart 	if (!debug->buffer) {
2363c95d6c6cSJames Smart 		kfree(debug);
2364c95d6c6cSJames Smart 		goto out;
2365c95d6c6cSJames Smart 	}
2366c95d6c6cSJames Smart 
2367c95d6c6cSJames Smart 	debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
2368c95d6c6cSJames Smart 		LPFC_DUMPHOSTSLIM_SIZE);
2369a58cbd52SJames Smart 	file->private_data = debug;
2370a58cbd52SJames Smart 
2371a58cbd52SJames Smart 	rc = 0;
2372a58cbd52SJames Smart out:
2373a58cbd52SJames Smart 	return rc;
2374a58cbd52SJames Smart }
2375a58cbd52SJames Smart 
2376f9bb2da1SJames Smart static ssize_t
lpfc_debugfs_dif_err_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)2377f9bb2da1SJames Smart lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
2378f9bb2da1SJames Smart 	size_t nbytes, loff_t *ppos)
2379f9bb2da1SJames Smart {
2380b583043eSAl Viro 	struct dentry *dent = file->f_path.dentry;
2381f9bb2da1SJames Smart 	struct lpfc_hba *phba = file->private_data;
23829a6b09c0SJames Smart 	char cbuf[32];
23834ac9b226SJames Smart 	uint64_t tmp = 0;
2384f9bb2da1SJames Smart 	int cnt = 0;
2385f9bb2da1SJames Smart 
2386f9bb2da1SJames Smart 	if (dent == phba->debug_writeGuard)
2387e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
2388f9bb2da1SJames Smart 	else if (dent == phba->debug_writeApp)
2389e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
2390f9bb2da1SJames Smart 	else if (dent == phba->debug_writeRef)
2391e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
2392acd6859bSJames Smart 	else if (dent == phba->debug_readGuard)
2393e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
2394f9bb2da1SJames Smart 	else if (dent == phba->debug_readApp)
2395e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
2396f9bb2da1SJames Smart 	else if (dent == phba->debug_readRef)
2397e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
23984ac9b226SJames Smart 	else if (dent == phba->debug_InjErrNPortID)
2399e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "0x%06x\n",
2400e7f7b6f3SSilvio Cesare 				phba->lpfc_injerr_nportid);
24014ac9b226SJames Smart 	else if (dent == phba->debug_InjErrWWPN) {
24024ac9b226SJames Smart 		memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name));
24034ac9b226SJames Smart 		tmp = cpu_to_be64(tmp);
2404e7f7b6f3SSilvio Cesare 		cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp);
24054ac9b226SJames Smart 	} else if (dent == phba->debug_InjErrLBA) {
24064ac9b226SJames Smart 		if (phba->lpfc_injerr_lba == (sector_t)(-1))
2407e7f7b6f3SSilvio Cesare 			cnt = scnprintf(cbuf, 32, "off\n");
2408f9bb2da1SJames Smart 		else
2409e7f7b6f3SSilvio Cesare 			cnt = scnprintf(cbuf, 32, "0x%llx\n",
24104ac9b226SJames Smart 				 (uint64_t) phba->lpfc_injerr_lba);
24119a6b09c0SJames Smart 	} else
2412f9bb2da1SJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2413f9bb2da1SJames Smart 			 "0547 Unknown debugfs error injection entry\n");
2414f9bb2da1SJames Smart 
2415f9bb2da1SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt);
2416f9bb2da1SJames Smart }
2417f9bb2da1SJames Smart 
2418f9bb2da1SJames Smart static ssize_t
lpfc_debugfs_dif_err_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2419f9bb2da1SJames Smart lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
2420f9bb2da1SJames Smart 	size_t nbytes, loff_t *ppos)
2421f9bb2da1SJames Smart {
2422b583043eSAl Viro 	struct dentry *dent = file->f_path.dentry;
2423f9bb2da1SJames Smart 	struct lpfc_hba *phba = file->private_data;
24240872774dSAlan 	char dstbuf[33];
24254ac9b226SJames Smart 	uint64_t tmp = 0;
2426f9bb2da1SJames Smart 	int size;
2427f9bb2da1SJames Smart 
24280872774dSAlan 	memset(dstbuf, 0, 33);
2429f9bb2da1SJames Smart 	size = (nbytes < 32) ? nbytes : 32;
2430f9bb2da1SJames Smart 	if (copy_from_user(dstbuf, buf, size))
243119f1bc7eSDan Carpenter 		return -EFAULT;
2432f9bb2da1SJames Smart 
24339a6b09c0SJames Smart 	if (dent == phba->debug_InjErrLBA) {
2434a7fc071aSDick Kennedy 		if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') &&
2435a7fc071aSDick Kennedy 		    (dstbuf[2] == 'f'))
24364ac9b226SJames Smart 			tmp = (uint64_t)(-1);
24379a6b09c0SJames Smart 	}
24389a6b09c0SJames Smart 
24394ac9b226SJames Smart 	if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp)))
244019f1bc7eSDan Carpenter 		return -EINVAL;
2441f9bb2da1SJames Smart 
2442f9bb2da1SJames Smart 	if (dent == phba->debug_writeGuard)
2443f9bb2da1SJames Smart 		phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp;
2444f9bb2da1SJames Smart 	else if (dent == phba->debug_writeApp)
2445f9bb2da1SJames Smart 		phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
2446f9bb2da1SJames Smart 	else if (dent == phba->debug_writeRef)
2447f9bb2da1SJames Smart 		phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
2448acd6859bSJames Smart 	else if (dent == phba->debug_readGuard)
2449acd6859bSJames Smart 		phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
2450f9bb2da1SJames Smart 	else if (dent == phba->debug_readApp)
2451f9bb2da1SJames Smart 		phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
2452f9bb2da1SJames Smart 	else if (dent == phba->debug_readRef)
2453f9bb2da1SJames Smart 		phba->lpfc_injerr_rref_cnt = (uint32_t)tmp;
2454f9bb2da1SJames Smart 	else if (dent == phba->debug_InjErrLBA)
2455f9bb2da1SJames Smart 		phba->lpfc_injerr_lba = (sector_t)tmp;
24564ac9b226SJames Smart 	else if (dent == phba->debug_InjErrNPortID)
24574ac9b226SJames Smart 		phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID);
24584ac9b226SJames Smart 	else if (dent == phba->debug_InjErrWWPN) {
24594ac9b226SJames Smart 		tmp = cpu_to_be64(tmp);
24604ac9b226SJames Smart 		memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name));
24614ac9b226SJames Smart 	} else
2462f9bb2da1SJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2463f9bb2da1SJames Smart 			 "0548 Unknown debugfs error injection entry\n");
2464f9bb2da1SJames Smart 
2465f9bb2da1SJames Smart 	return nbytes;
2466f9bb2da1SJames Smart }
2467f9bb2da1SJames Smart 
2468f9bb2da1SJames Smart static int
lpfc_debugfs_dif_err_release(struct inode * inode,struct file * file)2469f9bb2da1SJames Smart lpfc_debugfs_dif_err_release(struct inode *inode, struct file *file)
2470f9bb2da1SJames Smart {
2471f9bb2da1SJames Smart 	return 0;
2472f9bb2da1SJames Smart }
2473f9bb2da1SJames Smart 
2474e59058c4SJames Smart /**
24753621a710SJames Smart  * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file
2476e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer.
2477e59058c4SJames Smart  * @file: The file pointer to attach the log output.
2478e59058c4SJames Smart  *
2479e59058c4SJames Smart  * Description:
2480e59058c4SJames Smart  * This routine is the entry point for the debugfs open file operation. It gets
2481e59058c4SJames Smart  * the vport from the i_private field in @inode, allocates the necessary buffer
2482e59058c4SJames Smart  * for the log, fills the buffer from the in-memory log for this vport, and then
2483e59058c4SJames Smart  * returns a pointer to that log in the private_data field in @file.
2484e59058c4SJames Smart  *
2485e59058c4SJames Smart  * Returns:
248679ce48dfSGeert Uytterhoeven  * This function returns zero if successful. On error it will return a negative
2487e59058c4SJames Smart  * error value.
2488e59058c4SJames Smart  **/
2489a58cbd52SJames Smart static int
lpfc_debugfs_nodelist_open(struct inode * inode,struct file * file)2490858c9f6cSJames Smart lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
2491858c9f6cSJames Smart {
2492858c9f6cSJames Smart 	struct lpfc_vport *vport = inode->i_private;
2493858c9f6cSJames Smart 	struct lpfc_debug *debug;
2494858c9f6cSJames Smart 	int rc = -ENOMEM;
2495858c9f6cSJames Smart 
2496858c9f6cSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2497858c9f6cSJames Smart 	if (!debug)
2498858c9f6cSJames Smart 		goto out;
2499858c9f6cSJames Smart 
2500e59058c4SJames Smart 	/* Round to page boundary */
2501858c9f6cSJames Smart 	debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
2502858c9f6cSJames Smart 	if (!debug->buffer) {
2503858c9f6cSJames Smart 		kfree(debug);
2504858c9f6cSJames Smart 		goto out;
2505858c9f6cSJames Smart 	}
2506858c9f6cSJames Smart 
2507858c9f6cSJames Smart 	debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
2508858c9f6cSJames Smart 		LPFC_NODELIST_SIZE);
2509858c9f6cSJames Smart 	file->private_data = debug;
2510858c9f6cSJames Smart 
2511858c9f6cSJames Smart 	rc = 0;
2512858c9f6cSJames Smart out:
2513858c9f6cSJames Smart 	return rc;
2514858c9f6cSJames Smart }
2515858c9f6cSJames Smart 
2516e59058c4SJames Smart /**
25173621a710SJames Smart  * lpfc_debugfs_lseek - Seek through a debugfs file
2518e59058c4SJames Smart  * @file: The file pointer to seek through.
2519e59058c4SJames Smart  * @off: The offset to seek to or the amount to seek by.
2520e59058c4SJames Smart  * @whence: Indicates how to seek.
2521e59058c4SJames Smart  *
2522e59058c4SJames Smart  * Description:
2523e59058c4SJames Smart  * This routine is the entry point for the debugfs lseek file operation. The
2524e59058c4SJames Smart  * @whence parameter indicates whether @off is the offset to directly seek to,
2525e59058c4SJames Smart  * or if it is a value to seek forward or reverse by. This function figures out
2526e59058c4SJames Smart  * what the new offset of the debugfs file will be and assigns that value to the
2527e59058c4SJames Smart  * f_pos field of @file.
2528e59058c4SJames Smart  *
2529e59058c4SJames Smart  * Returns:
2530e59058c4SJames Smart  * This function returns the new offset if successful and returns a negative
2531e59058c4SJames Smart  * error if unable to process the seek.
2532e59058c4SJames Smart  **/
2533858c9f6cSJames Smart static loff_t
lpfc_debugfs_lseek(struct file * file,loff_t off,int whence)2534858c9f6cSJames Smart lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
2535858c9f6cSJames Smart {
25367233c774SAl Viro 	struct lpfc_debug *debug = file->private_data;
25377233c774SAl Viro 	return fixed_size_llseek(file, off, whence, debug->len);
2538858c9f6cSJames Smart }
2539858c9f6cSJames Smart 
2540e59058c4SJames Smart /**
25413621a710SJames Smart  * lpfc_debugfs_read - Read a debugfs file
2542e59058c4SJames Smart  * @file: The file pointer to read from.
2543e59058c4SJames Smart  * @buf: The buffer to copy the data to.
2544e59058c4SJames Smart  * @nbytes: The number of bytes to read.
2545e59058c4SJames Smart  * @ppos: The position in the file to start reading from.
2546e59058c4SJames Smart  *
2547e59058c4SJames Smart  * Description:
2548e59058c4SJames Smart  * This routine reads data from from the buffer indicated in the private_data
2549e59058c4SJames Smart  * field of @file. It will start reading at @ppos and copy up to @nbytes of
2550e59058c4SJames Smart  * data to @buf.
2551e59058c4SJames Smart  *
2552e59058c4SJames Smart  * Returns:
2553e59058c4SJames Smart  * This function returns the amount of data that was read (this could be less
2554e59058c4SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
2555e59058c4SJames Smart  **/
2556858c9f6cSJames Smart static ssize_t
lpfc_debugfs_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)2557858c9f6cSJames Smart lpfc_debugfs_read(struct file *file, char __user *buf,
2558858c9f6cSJames Smart 		  size_t nbytes, loff_t *ppos)
2559858c9f6cSJames Smart {
2560858c9f6cSJames Smart 	struct lpfc_debug *debug = file->private_data;
25612a622bfbSJames Smart 
2562858c9f6cSJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
2563858c9f6cSJames Smart 				       debug->len);
2564858c9f6cSJames Smart }
2565858c9f6cSJames Smart 
2566e59058c4SJames Smart /**
25673621a710SJames Smart  * lpfc_debugfs_release - Release the buffer used to store debugfs file data
2568e59058c4SJames Smart  * @inode: The inode pointer that contains a vport pointer. (unused)
2569e59058c4SJames Smart  * @file: The file pointer that contains the buffer to release.
2570e59058c4SJames Smart  *
2571e59058c4SJames Smart  * Description:
2572e59058c4SJames Smart  * This routine frees the buffer that was allocated when the debugfs file was
2573e59058c4SJames Smart  * opened.
2574e59058c4SJames Smart  *
2575e59058c4SJames Smart  * Returns:
2576e59058c4SJames Smart  * This function returns zero.
2577e59058c4SJames Smart  **/
2578858c9f6cSJames Smart static int
lpfc_debugfs_release(struct inode * inode,struct file * file)2579858c9f6cSJames Smart lpfc_debugfs_release(struct inode *inode, struct file *file)
2580858c9f6cSJames Smart {
2581858c9f6cSJames Smart 	struct lpfc_debug *debug = file->private_data;
2582858c9f6cSJames Smart 
2583858c9f6cSJames Smart 	kfree(debug->buffer);
2584858c9f6cSJames Smart 	kfree(debug);
2585858c9f6cSJames Smart 
2586858c9f6cSJames Smart 	return 0;
2587858c9f6cSJames Smart }
2588858c9f6cSJames Smart 
2589c490850aSJames Smart /**
2590c490850aSJames Smart  * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics
2591c490850aSJames Smart  * @file: The file pointer to read from.
2592c490850aSJames Smart  * @buf: The buffer to copy the user data from.
2593c490850aSJames Smart  * @nbytes: The number of bytes to get.
2594c490850aSJames Smart  * @ppos: The position in the file to start reading from.
2595c490850aSJames Smart  *
2596c490850aSJames Smart  * Description:
2597c490850aSJames Smart  * This routine clears multi-XRI pools statistics when buf contains "clear".
2598c490850aSJames Smart  *
2599c490850aSJames Smart  * Return Value:
2600c490850aSJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
2601c490850aSJames Smart  * In case of error conditions, it returns proper error code back to the user
2602c490850aSJames Smart  * space.
2603c490850aSJames Smart  **/
2604c490850aSJames Smart static ssize_t
lpfc_debugfs_multixripools_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2605c490850aSJames Smart lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf,
2606c490850aSJames Smart 				 size_t nbytes, loff_t *ppos)
2607c490850aSJames Smart {
2608c490850aSJames Smart 	struct lpfc_debug *debug = file->private_data;
2609c490850aSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
2610c490850aSJames Smart 	char mybuf[64];
2611c490850aSJames Smart 	char *pbuf;
2612c490850aSJames Smart 	u32 i;
2613c490850aSJames Smart 	u32 hwq_count;
2614c490850aSJames Smart 	struct lpfc_sli4_hdw_queue *qp;
2615c490850aSJames Smart 	struct lpfc_multixri_pool *multixri_pool;
2616c490850aSJames Smart 
2617f8191d40SJames Smart 	if (nbytes > sizeof(mybuf) - 1)
2618f8191d40SJames Smart 		nbytes = sizeof(mybuf) - 1;
2619c490850aSJames Smart 
2620c490850aSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
2621c490850aSJames Smart 
2622c490850aSJames Smart 	if (copy_from_user(mybuf, buf, nbytes))
2623c490850aSJames Smart 		return -EFAULT;
2624c490850aSJames Smart 	pbuf = &mybuf[0];
2625c490850aSJames Smart 
2626c490850aSJames Smart 	if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) {
2627c490850aSJames Smart 		hwq_count = phba->cfg_hdw_queue;
2628c490850aSJames Smart 		for (i = 0; i < hwq_count; i++) {
2629c490850aSJames Smart 			qp = &phba->sli4_hba.hdwq[i];
2630c490850aSJames Smart 			multixri_pool = qp->p_multixri_pool;
2631c490850aSJames Smart 			if (!multixri_pool)
2632c490850aSJames Smart 				continue;
2633c490850aSJames Smart 
2634c490850aSJames Smart 			qp->empty_io_bufs = 0;
2635c490850aSJames Smart 			multixri_pool->pbl_empty_count = 0;
2636c490850aSJames Smart #ifdef LPFC_MXP_STAT
2637c490850aSJames Smart 			multixri_pool->above_limit_count = 0;
2638c490850aSJames Smart 			multixri_pool->below_limit_count = 0;
2639c490850aSJames Smart 			multixri_pool->stat_max_hwm = 0;
2640c490850aSJames Smart 			multixri_pool->local_pbl_hit_count = 0;
2641c490850aSJames Smart 			multixri_pool->other_pbl_hit_count = 0;
2642c490850aSJames Smart 
2643c490850aSJames Smart 			multixri_pool->stat_pbl_count = 0;
2644c490850aSJames Smart 			multixri_pool->stat_pvt_count = 0;
2645c490850aSJames Smart 			multixri_pool->stat_busy_count = 0;
2646c490850aSJames Smart 			multixri_pool->stat_snapshot_taken = 0;
2647c490850aSJames Smart #endif
2648c490850aSJames Smart 		}
2649c490850aSJames Smart 		return strlen(pbuf);
2650c490850aSJames Smart 	}
2651c490850aSJames Smart 
2652c490850aSJames Smart 	return -EINVAL;
2653c490850aSJames Smart }
2654bd2cdd5eSJames Smart 
2655bd2cdd5eSJames Smart static int
lpfc_debugfs_nvmestat_open(struct inode * inode,struct file * file)2656bd2cdd5eSJames Smart lpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file)
2657bd2cdd5eSJames Smart {
2658bd2cdd5eSJames Smart 	struct lpfc_vport *vport = inode->i_private;
2659bd2cdd5eSJames Smart 	struct lpfc_debug *debug;
2660bd2cdd5eSJames Smart 	int rc = -ENOMEM;
2661bd2cdd5eSJames Smart 
2662bd2cdd5eSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2663bd2cdd5eSJames Smart 	if (!debug)
2664bd2cdd5eSJames Smart 		goto out;
2665bd2cdd5eSJames Smart 
2666bd2cdd5eSJames Smart 	 /* Round to page boundary */
2667bd2cdd5eSJames Smart 	debug->buffer = kmalloc(LPFC_NVMESTAT_SIZE, GFP_KERNEL);
2668bd2cdd5eSJames Smart 	if (!debug->buffer) {
2669bd2cdd5eSJames Smart 		kfree(debug);
2670bd2cdd5eSJames Smart 		goto out;
2671bd2cdd5eSJames Smart 	}
2672bd2cdd5eSJames Smart 
2673bd2cdd5eSJames Smart 	debug->len = lpfc_debugfs_nvmestat_data(vport, debug->buffer,
2674bd2cdd5eSJames Smart 		LPFC_NVMESTAT_SIZE);
2675bd2cdd5eSJames Smart 
2676bd2cdd5eSJames Smart 	debug->i_private = inode->i_private;
2677bd2cdd5eSJames Smart 	file->private_data = debug;
2678bd2cdd5eSJames Smart 
2679bd2cdd5eSJames Smart 	rc = 0;
2680bd2cdd5eSJames Smart out:
2681bd2cdd5eSJames Smart 	return rc;
2682bd2cdd5eSJames Smart }
2683bd2cdd5eSJames Smart 
26842b65e182SJames Smart static ssize_t
lpfc_debugfs_nvmestat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)26852b65e182SJames Smart lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf,
26862b65e182SJames Smart 			    size_t nbytes, loff_t *ppos)
26872b65e182SJames Smart {
26882b65e182SJames Smart 	struct lpfc_debug *debug = file->private_data;
26892b65e182SJames Smart 	struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
26902b65e182SJames Smart 	struct lpfc_hba   *phba = vport->phba;
26912b65e182SJames Smart 	struct lpfc_nvmet_tgtport *tgtp;
26922b65e182SJames Smart 	char mybuf[64];
26932b65e182SJames Smart 	char *pbuf;
26942b65e182SJames Smart 
26952b65e182SJames Smart 	if (!phba->targetport)
26962b65e182SJames Smart 		return -ENXIO;
26972b65e182SJames Smart 
2698f8191d40SJames Smart 	if (nbytes > sizeof(mybuf) - 1)
2699f8191d40SJames Smart 		nbytes = sizeof(mybuf) - 1;
27002b65e182SJames Smart 
27012b65e182SJames Smart 	memset(mybuf, 0, sizeof(mybuf));
27022b65e182SJames Smart 
27032b65e182SJames Smart 	if (copy_from_user(mybuf, buf, nbytes))
27042b65e182SJames Smart 		return -EFAULT;
27052b65e182SJames Smart 	pbuf = &mybuf[0];
27062b65e182SJames Smart 
27072b65e182SJames Smart 	tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
27082b65e182SJames Smart 	if ((strncmp(pbuf, "reset", strlen("reset")) == 0) ||
27092b65e182SJames Smart 	    (strncmp(pbuf, "zero", strlen("zero")) == 0)) {
27102b65e182SJames Smart 		atomic_set(&tgtp->rcv_ls_req_in, 0);
27112b65e182SJames Smart 		atomic_set(&tgtp->rcv_ls_req_out, 0);
27122b65e182SJames Smart 		atomic_set(&tgtp->rcv_ls_req_drop, 0);
27132b65e182SJames Smart 		atomic_set(&tgtp->xmt_ls_abort, 0);
2714547077a4SJames Smart 		atomic_set(&tgtp->xmt_ls_abort_cmpl, 0);
27152b65e182SJames Smart 		atomic_set(&tgtp->xmt_ls_rsp, 0);
27162b65e182SJames Smart 		atomic_set(&tgtp->xmt_ls_drop, 0);
27172b65e182SJames Smart 		atomic_set(&tgtp->xmt_ls_rsp_error, 0);
27182b65e182SJames Smart 		atomic_set(&tgtp->xmt_ls_rsp_cmpl, 0);
27192b65e182SJames Smart 
27202b65e182SJames Smart 		atomic_set(&tgtp->rcv_fcp_cmd_in, 0);
27212b65e182SJames Smart 		atomic_set(&tgtp->rcv_fcp_cmd_out, 0);
27222b65e182SJames Smart 		atomic_set(&tgtp->rcv_fcp_cmd_drop, 0);
27232b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_drop, 0);
27242b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_read_rsp, 0);
27252b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_read, 0);
27262b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_write, 0);
27272b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_rsp, 0);
2728547077a4SJames Smart 		atomic_set(&tgtp->xmt_fcp_release, 0);
27292b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_rsp_cmpl, 0);
27302b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_rsp_error, 0);
27312b65e182SJames Smart 		atomic_set(&tgtp->xmt_fcp_rsp_drop, 0);
27322b65e182SJames Smart 
2733547077a4SJames Smart 		atomic_set(&tgtp->xmt_fcp_abort, 0);
2734547077a4SJames Smart 		atomic_set(&tgtp->xmt_fcp_abort_cmpl, 0);
2735547077a4SJames Smart 		atomic_set(&tgtp->xmt_abort_sol, 0);
2736547077a4SJames Smart 		atomic_set(&tgtp->xmt_abort_unsol, 0);
27372b65e182SJames Smart 		atomic_set(&tgtp->xmt_abort_rsp, 0);
27382b65e182SJames Smart 		atomic_set(&tgtp->xmt_abort_rsp_error, 0);
27392b65e182SJames Smart 	}
27402b65e182SJames Smart 	return nbytes;
27412b65e182SJames Smart }
27422b65e182SJames Smart 
2743bd2cdd5eSJames Smart static int
lpfc_debugfs_scsistat_open(struct inode * inode,struct file * file)27444c47efc1SJames Smart lpfc_debugfs_scsistat_open(struct inode *inode, struct file *file)
27454c47efc1SJames Smart {
27464c47efc1SJames Smart 	struct lpfc_vport *vport = inode->i_private;
27474c47efc1SJames Smart 	struct lpfc_debug *debug;
27484c47efc1SJames Smart 	int rc = -ENOMEM;
27494c47efc1SJames Smart 
27504c47efc1SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
27514c47efc1SJames Smart 	if (!debug)
27524c47efc1SJames Smart 		goto out;
27534c47efc1SJames Smart 
27544c47efc1SJames Smart 	 /* Round to page boundary */
27554c47efc1SJames Smart 	debug->buffer = kzalloc(LPFC_SCSISTAT_SIZE, GFP_KERNEL);
27564c47efc1SJames Smart 	if (!debug->buffer) {
27574c47efc1SJames Smart 		kfree(debug);
27584c47efc1SJames Smart 		goto out;
27594c47efc1SJames Smart 	}
27604c47efc1SJames Smart 
27614c47efc1SJames Smart 	debug->len = lpfc_debugfs_scsistat_data(vport, debug->buffer,
27624c47efc1SJames Smart 		LPFC_SCSISTAT_SIZE);
27634c47efc1SJames Smart 
27644c47efc1SJames Smart 	debug->i_private = inode->i_private;
27654c47efc1SJames Smart 	file->private_data = debug;
27664c47efc1SJames Smart 
27674c47efc1SJames Smart 	rc = 0;
27684c47efc1SJames Smart out:
27694c47efc1SJames Smart 	return rc;
27704c47efc1SJames Smart }
27714c47efc1SJames Smart 
27724c47efc1SJames Smart static ssize_t
lpfc_debugfs_scsistat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)27734c47efc1SJames Smart lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf,
27744c47efc1SJames Smart 			    size_t nbytes, loff_t *ppos)
27754c47efc1SJames Smart {
27764c47efc1SJames Smart 	struct lpfc_debug *debug = file->private_data;
27774c47efc1SJames Smart 	struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
27784c47efc1SJames Smart 	struct lpfc_hba *phba = vport->phba;
27794c47efc1SJames Smart 	char mybuf[6] = {0};
27804c47efc1SJames Smart 	int i;
27814c47efc1SJames Smart 
27824c47efc1SJames Smart 	if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ?
27834c47efc1SJames Smart 				       (sizeof(mybuf) - 1) : nbytes))
27844c47efc1SJames Smart 		return -EFAULT;
27854c47efc1SJames Smart 
27864c47efc1SJames Smart 	if ((strncmp(&mybuf[0], "reset", strlen("reset")) == 0) ||
27874c47efc1SJames Smart 	    (strncmp(&mybuf[0], "zero", strlen("zero")) == 0)) {
27884c47efc1SJames Smart 		for (i = 0; i < phba->cfg_hdw_queue; i++) {
27894c47efc1SJames Smart 			memset(&phba->sli4_hba.hdwq[i].scsi_cstat, 0,
27904c47efc1SJames Smart 			       sizeof(phba->sli4_hba.hdwq[i].scsi_cstat));
27914c47efc1SJames Smart 		}
27924c47efc1SJames Smart 	}
27934c47efc1SJames Smart 
27944c47efc1SJames Smart 	return nbytes;
27954c47efc1SJames Smart }
27964c47efc1SJames Smart 
27974c47efc1SJames Smart static int
lpfc_debugfs_ioktime_open(struct inode * inode,struct file * file)27982fcbc569SJames Smart lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file)
2799bd2cdd5eSJames Smart {
2800bd2cdd5eSJames Smart 	struct lpfc_vport *vport = inode->i_private;
2801bd2cdd5eSJames Smart 	struct lpfc_debug *debug;
2802bd2cdd5eSJames Smart 	int rc = -ENOMEM;
2803bd2cdd5eSJames Smart 
2804bd2cdd5eSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2805bd2cdd5eSJames Smart 	if (!debug)
2806bd2cdd5eSJames Smart 		goto out;
2807bd2cdd5eSJames Smart 
2808bd2cdd5eSJames Smart 	 /* Round to page boundary */
28092fcbc569SJames Smart 	debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL);
2810bd2cdd5eSJames Smart 	if (!debug->buffer) {
2811bd2cdd5eSJames Smart 		kfree(debug);
2812bd2cdd5eSJames Smart 		goto out;
2813bd2cdd5eSJames Smart 	}
2814bd2cdd5eSJames Smart 
28152fcbc569SJames Smart 	debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer,
28162fcbc569SJames Smart 		LPFC_IOKTIME_SIZE);
2817bd2cdd5eSJames Smart 
2818bd2cdd5eSJames Smart 	debug->i_private = inode->i_private;
2819bd2cdd5eSJames Smart 	file->private_data = debug;
2820bd2cdd5eSJames Smart 
2821bd2cdd5eSJames Smart 	rc = 0;
2822bd2cdd5eSJames Smart out:
2823bd2cdd5eSJames Smart 	return rc;
2824bd2cdd5eSJames Smart }
2825bd2cdd5eSJames Smart 
2826bd2cdd5eSJames Smart static ssize_t
lpfc_debugfs_ioktime_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)28272fcbc569SJames Smart lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf,
2828bd2cdd5eSJames Smart 			   size_t nbytes, loff_t *ppos)
2829bd2cdd5eSJames Smart {
2830bd2cdd5eSJames Smart 	struct lpfc_debug *debug = file->private_data;
2831bd2cdd5eSJames Smart 	struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
2832bd2cdd5eSJames Smart 	struct lpfc_hba   *phba = vport->phba;
2833bd2cdd5eSJames Smart 	char mybuf[64];
2834bd2cdd5eSJames Smart 	char *pbuf;
2835bd2cdd5eSJames Smart 
2836f8191d40SJames Smart 	if (nbytes > sizeof(mybuf) - 1)
2837f8191d40SJames Smart 		nbytes = sizeof(mybuf) - 1;
2838bd2cdd5eSJames Smart 
2839bd2cdd5eSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
2840bd2cdd5eSJames Smart 
2841bd2cdd5eSJames Smart 	if (copy_from_user(mybuf, buf, nbytes))
2842bd2cdd5eSJames Smart 		return -EFAULT;
2843bd2cdd5eSJames Smart 	pbuf = &mybuf[0];
2844bd2cdd5eSJames Smart 
2845bd2cdd5eSJames Smart 	if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
2846bd2cdd5eSJames Smart 		phba->ktime_data_samples = 0;
2847bd2cdd5eSJames Smart 		phba->ktime_status_samples = 0;
2848bd2cdd5eSJames Smart 		phba->ktime_seg1_total = 0;
2849bd2cdd5eSJames Smart 		phba->ktime_seg1_max = 0;
2850bd2cdd5eSJames Smart 		phba->ktime_seg1_min = 0xffffffff;
2851bd2cdd5eSJames Smart 		phba->ktime_seg2_total = 0;
2852bd2cdd5eSJames Smart 		phba->ktime_seg2_max = 0;
2853bd2cdd5eSJames Smart 		phba->ktime_seg2_min = 0xffffffff;
2854bd2cdd5eSJames Smart 		phba->ktime_seg3_total = 0;
2855bd2cdd5eSJames Smart 		phba->ktime_seg3_max = 0;
2856bd2cdd5eSJames Smart 		phba->ktime_seg3_min = 0xffffffff;
2857bd2cdd5eSJames Smart 		phba->ktime_seg4_total = 0;
2858bd2cdd5eSJames Smart 		phba->ktime_seg4_max = 0;
2859bd2cdd5eSJames Smart 		phba->ktime_seg4_min = 0xffffffff;
2860bd2cdd5eSJames Smart 		phba->ktime_seg5_total = 0;
2861bd2cdd5eSJames Smart 		phba->ktime_seg5_max = 0;
2862bd2cdd5eSJames Smart 		phba->ktime_seg5_min = 0xffffffff;
2863bd2cdd5eSJames Smart 		phba->ktime_seg6_total = 0;
2864bd2cdd5eSJames Smart 		phba->ktime_seg6_max = 0;
2865bd2cdd5eSJames Smart 		phba->ktime_seg6_min = 0xffffffff;
2866bd2cdd5eSJames Smart 		phba->ktime_seg7_total = 0;
2867bd2cdd5eSJames Smart 		phba->ktime_seg7_max = 0;
2868bd2cdd5eSJames Smart 		phba->ktime_seg7_min = 0xffffffff;
2869bd2cdd5eSJames Smart 		phba->ktime_seg8_total = 0;
2870bd2cdd5eSJames Smart 		phba->ktime_seg8_max = 0;
2871bd2cdd5eSJames Smart 		phba->ktime_seg8_min = 0xffffffff;
2872bd2cdd5eSJames Smart 		phba->ktime_seg9_total = 0;
2873bd2cdd5eSJames Smart 		phba->ktime_seg9_max = 0;
2874bd2cdd5eSJames Smart 		phba->ktime_seg9_min = 0xffffffff;
2875bd2cdd5eSJames Smart 		phba->ktime_seg10_total = 0;
2876bd2cdd5eSJames Smart 		phba->ktime_seg10_max = 0;
2877bd2cdd5eSJames Smart 		phba->ktime_seg10_min = 0xffffffff;
2878bd2cdd5eSJames Smart 
2879bd2cdd5eSJames Smart 		phba->ktime_on = 1;
2880bd2cdd5eSJames Smart 		return strlen(pbuf);
2881bd2cdd5eSJames Smart 	} else if ((strncmp(pbuf, "off",
2882bd2cdd5eSJames Smart 		   sizeof("off") - 1) == 0)) {
2883bd2cdd5eSJames Smart 		phba->ktime_on = 0;
2884bd2cdd5eSJames Smart 		return strlen(pbuf);
2885bd2cdd5eSJames Smart 	} else if ((strncmp(pbuf, "zero",
2886bd2cdd5eSJames Smart 		   sizeof("zero") - 1) == 0)) {
2887bd2cdd5eSJames Smart 		phba->ktime_data_samples = 0;
2888bd2cdd5eSJames Smart 		phba->ktime_status_samples = 0;
2889bd2cdd5eSJames Smart 		phba->ktime_seg1_total = 0;
2890bd2cdd5eSJames Smart 		phba->ktime_seg1_max = 0;
2891bd2cdd5eSJames Smart 		phba->ktime_seg1_min = 0xffffffff;
2892bd2cdd5eSJames Smart 		phba->ktime_seg2_total = 0;
2893bd2cdd5eSJames Smart 		phba->ktime_seg2_max = 0;
2894bd2cdd5eSJames Smart 		phba->ktime_seg2_min = 0xffffffff;
2895bd2cdd5eSJames Smart 		phba->ktime_seg3_total = 0;
2896bd2cdd5eSJames Smart 		phba->ktime_seg3_max = 0;
2897bd2cdd5eSJames Smart 		phba->ktime_seg3_min = 0xffffffff;
2898bd2cdd5eSJames Smart 		phba->ktime_seg4_total = 0;
2899bd2cdd5eSJames Smart 		phba->ktime_seg4_max = 0;
2900bd2cdd5eSJames Smart 		phba->ktime_seg4_min = 0xffffffff;
2901bd2cdd5eSJames Smart 		phba->ktime_seg5_total = 0;
2902bd2cdd5eSJames Smart 		phba->ktime_seg5_max = 0;
2903bd2cdd5eSJames Smart 		phba->ktime_seg5_min = 0xffffffff;
2904bd2cdd5eSJames Smart 		phba->ktime_seg6_total = 0;
2905bd2cdd5eSJames Smart 		phba->ktime_seg6_max = 0;
2906bd2cdd5eSJames Smart 		phba->ktime_seg6_min = 0xffffffff;
2907bd2cdd5eSJames Smart 		phba->ktime_seg7_total = 0;
2908bd2cdd5eSJames Smart 		phba->ktime_seg7_max = 0;
2909bd2cdd5eSJames Smart 		phba->ktime_seg7_min = 0xffffffff;
2910bd2cdd5eSJames Smart 		phba->ktime_seg8_total = 0;
2911bd2cdd5eSJames Smart 		phba->ktime_seg8_max = 0;
2912bd2cdd5eSJames Smart 		phba->ktime_seg8_min = 0xffffffff;
2913bd2cdd5eSJames Smart 		phba->ktime_seg9_total = 0;
2914bd2cdd5eSJames Smart 		phba->ktime_seg9_max = 0;
2915bd2cdd5eSJames Smart 		phba->ktime_seg9_min = 0xffffffff;
2916bd2cdd5eSJames Smart 		phba->ktime_seg10_total = 0;
2917bd2cdd5eSJames Smart 		phba->ktime_seg10_max = 0;
2918bd2cdd5eSJames Smart 		phba->ktime_seg10_min = 0xffffffff;
2919bd2cdd5eSJames Smart 		return strlen(pbuf);
2920bd2cdd5eSJames Smart 	}
2921bd2cdd5eSJames Smart 	return -EINVAL;
2922bd2cdd5eSJames Smart }
2923bd2cdd5eSJames Smart 
2924bd2cdd5eSJames Smart static int
lpfc_debugfs_nvmeio_trc_open(struct inode * inode,struct file * file)2925bd2cdd5eSJames Smart lpfc_debugfs_nvmeio_trc_open(struct inode *inode, struct file *file)
2926bd2cdd5eSJames Smart {
2927bd2cdd5eSJames Smart 	struct lpfc_hba *phba = inode->i_private;
2928bd2cdd5eSJames Smart 	struct lpfc_debug *debug;
2929bd2cdd5eSJames Smart 	int rc = -ENOMEM;
2930bd2cdd5eSJames Smart 
2931bd2cdd5eSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
2932bd2cdd5eSJames Smart 	if (!debug)
2933bd2cdd5eSJames Smart 		goto out;
2934bd2cdd5eSJames Smart 
2935bd2cdd5eSJames Smart 	 /* Round to page boundary */
2936bd2cdd5eSJames Smart 	debug->buffer = kmalloc(LPFC_NVMEIO_TRC_SIZE, GFP_KERNEL);
2937bd2cdd5eSJames Smart 	if (!debug->buffer) {
2938bd2cdd5eSJames Smart 		kfree(debug);
2939bd2cdd5eSJames Smart 		goto out;
2940bd2cdd5eSJames Smart 	}
2941bd2cdd5eSJames Smart 
2942bd2cdd5eSJames Smart 	debug->len = lpfc_debugfs_nvmeio_trc_data(phba, debug->buffer,
2943bd2cdd5eSJames Smart 		LPFC_NVMEIO_TRC_SIZE);
2944bd2cdd5eSJames Smart 
2945bd2cdd5eSJames Smart 	debug->i_private = inode->i_private;
2946bd2cdd5eSJames Smart 	file->private_data = debug;
2947bd2cdd5eSJames Smart 
2948bd2cdd5eSJames Smart 	rc = 0;
2949bd2cdd5eSJames Smart out:
2950bd2cdd5eSJames Smart 	return rc;
2951bd2cdd5eSJames Smart }
2952bd2cdd5eSJames Smart 
2953bd2cdd5eSJames Smart static ssize_t
lpfc_debugfs_nvmeio_trc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)2954bd2cdd5eSJames Smart lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf,
2955bd2cdd5eSJames Smart 			      size_t nbytes, loff_t *ppos)
2956bd2cdd5eSJames Smart {
2957bd2cdd5eSJames Smart 	struct lpfc_debug *debug = file->private_data;
2958bd2cdd5eSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
2959bd2cdd5eSJames Smart 	int i;
2960bd2cdd5eSJames Smart 	unsigned long sz;
2961bd2cdd5eSJames Smart 	char mybuf[64];
2962bd2cdd5eSJames Smart 	char *pbuf;
2963bd2cdd5eSJames Smart 
2964f8191d40SJames Smart 	if (nbytes > sizeof(mybuf) - 1)
2965f8191d40SJames Smart 		nbytes = sizeof(mybuf) - 1;
2966bd2cdd5eSJames Smart 
2967bd2cdd5eSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
2968bd2cdd5eSJames Smart 
2969bd2cdd5eSJames Smart 	if (copy_from_user(mybuf, buf, nbytes))
2970bd2cdd5eSJames Smart 		return -EFAULT;
2971bd2cdd5eSJames Smart 	pbuf = &mybuf[0];
2972bd2cdd5eSJames Smart 
2973bd2cdd5eSJames Smart 	if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) {
2974bd2cdd5eSJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2975bd2cdd5eSJames Smart 				"0570 nvmeio_trc_off\n");
2976bd2cdd5eSJames Smart 		phba->nvmeio_trc_output_idx = 0;
2977bd2cdd5eSJames Smart 		phba->nvmeio_trc_on = 0;
2978bd2cdd5eSJames Smart 		return strlen(pbuf);
2979bd2cdd5eSJames Smart 	} else if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
2980bd2cdd5eSJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2981bd2cdd5eSJames Smart 				"0571 nvmeio_trc_on\n");
2982bd2cdd5eSJames Smart 		phba->nvmeio_trc_output_idx = 0;
2983bd2cdd5eSJames Smart 		phba->nvmeio_trc_on = 1;
2984bd2cdd5eSJames Smart 		return strlen(pbuf);
2985bd2cdd5eSJames Smart 	}
2986bd2cdd5eSJames Smart 
2987bd2cdd5eSJames Smart 	/* We must be off to allocate the trace buffer */
2988bd2cdd5eSJames Smart 	if (phba->nvmeio_trc_on != 0)
2989bd2cdd5eSJames Smart 		return -EINVAL;
2990bd2cdd5eSJames Smart 
2991bd2cdd5eSJames Smart 	/* If not on or off, the parameter is the trace buffer size */
2992bd2cdd5eSJames Smart 	i = kstrtoul(pbuf, 0, &sz);
2993bd2cdd5eSJames Smart 	if (i)
2994bd2cdd5eSJames Smart 		return -EINVAL;
2995bd2cdd5eSJames Smart 	phba->nvmeio_trc_size = (uint32_t)sz;
2996bd2cdd5eSJames Smart 
2997bd2cdd5eSJames Smart 	/* It must be a power of 2 - round down */
2998bd2cdd5eSJames Smart 	i = 0;
2999bd2cdd5eSJames Smart 	while (sz > 1) {
3000bd2cdd5eSJames Smart 		sz = sz >> 1;
3001bd2cdd5eSJames Smart 		i++;
3002bd2cdd5eSJames Smart 	}
3003bd2cdd5eSJames Smart 	sz = (1 << i);
3004bd2cdd5eSJames Smart 	if (phba->nvmeio_trc_size != sz)
3005bd2cdd5eSJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3006bd2cdd5eSJames Smart 				"0572 nvmeio_trc_size changed to %ld\n",
3007bd2cdd5eSJames Smart 				sz);
3008bd2cdd5eSJames Smart 	phba->nvmeio_trc_size = (uint32_t)sz;
3009bd2cdd5eSJames Smart 
3010bd2cdd5eSJames Smart 	/* If one previously exists, free it */
3011bd2cdd5eSJames Smart 	kfree(phba->nvmeio_trc);
3012bd2cdd5eSJames Smart 
3013bd2cdd5eSJames Smart 	/* Allocate new trace buffer and initialize */
30141c356ec5SVasyl Gomonovych 	phba->nvmeio_trc = kzalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) *
3015bd2cdd5eSJames Smart 				    sz), GFP_KERNEL);
3016bd2cdd5eSJames Smart 	if (!phba->nvmeio_trc) {
3017bd2cdd5eSJames Smart 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3018bd2cdd5eSJames Smart 				"0573 Cannot create debugfs "
3019bd2cdd5eSJames Smart 				"nvmeio_trc buffer\n");
3020bd2cdd5eSJames Smart 		return -ENOMEM;
3021bd2cdd5eSJames Smart 	}
3022bd2cdd5eSJames Smart 	atomic_set(&phba->nvmeio_trc_cnt, 0);
3023bd2cdd5eSJames Smart 	phba->nvmeio_trc_on = 0;
3024bd2cdd5eSJames Smart 	phba->nvmeio_trc_output_idx = 0;
3025bd2cdd5eSJames Smart 
3026bd2cdd5eSJames Smart 	return strlen(pbuf);
3027bd2cdd5eSJames Smart }
3028bd2cdd5eSJames Smart 
3029bd2cdd5eSJames Smart static int
lpfc_debugfs_hdwqstat_open(struct inode * inode,struct file * file)3030840eda96SJames Smart lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file)
3031bd2cdd5eSJames Smart {
3032bd2cdd5eSJames Smart 	struct lpfc_vport *vport = inode->i_private;
3033bd2cdd5eSJames Smart 	struct lpfc_debug *debug;
3034bd2cdd5eSJames Smart 	int rc = -ENOMEM;
3035bd2cdd5eSJames Smart 
3036bd2cdd5eSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
3037bd2cdd5eSJames Smart 	if (!debug)
3038bd2cdd5eSJames Smart 		goto out;
3039bd2cdd5eSJames Smart 
3040bd2cdd5eSJames Smart 	 /* Round to page boundary */
3041840eda96SJames Smart 	debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL);
3042bd2cdd5eSJames Smart 	if (!debug->buffer) {
3043bd2cdd5eSJames Smart 		kfree(debug);
3044bd2cdd5eSJames Smart 		goto out;
3045bd2cdd5eSJames Smart 	}
3046bd2cdd5eSJames Smart 
3047840eda96SJames Smart 	debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer,
3048840eda96SJames Smart 						LPFC_SCSISTAT_SIZE);
3049bd2cdd5eSJames Smart 
3050bd2cdd5eSJames Smart 	debug->i_private = inode->i_private;
3051bd2cdd5eSJames Smart 	file->private_data = debug;
3052bd2cdd5eSJames Smart 
3053bd2cdd5eSJames Smart 	rc = 0;
3054bd2cdd5eSJames Smart out:
3055bd2cdd5eSJames Smart 	return rc;
3056bd2cdd5eSJames Smart }
3057bd2cdd5eSJames Smart 
3058bd2cdd5eSJames Smart static ssize_t
lpfc_debugfs_hdwqstat_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)3059840eda96SJames Smart lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf,
3060bd2cdd5eSJames Smart 			    size_t nbytes, loff_t *ppos)
3061bd2cdd5eSJames Smart {
3062bd2cdd5eSJames Smart 	struct lpfc_debug *debug = file->private_data;
3063bd2cdd5eSJames Smart 	struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private;
3064bd2cdd5eSJames Smart 	struct lpfc_hba   *phba = vport->phba;
3065840eda96SJames Smart 	struct lpfc_hdwq_stat *c_stat;
3066bd2cdd5eSJames Smart 	char mybuf[64];
3067bd2cdd5eSJames Smart 	char *pbuf;
3068840eda96SJames Smart 	int i;
3069bd2cdd5eSJames Smart 
3070f8191d40SJames Smart 	if (nbytes > sizeof(mybuf) - 1)
3071f8191d40SJames Smart 		nbytes = sizeof(mybuf) - 1;
3072bd2cdd5eSJames Smart 
3073bd2cdd5eSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
3074bd2cdd5eSJames Smart 
3075bd2cdd5eSJames Smart 	if (copy_from_user(mybuf, buf, nbytes))
3076bd2cdd5eSJames Smart 		return -EFAULT;
3077bd2cdd5eSJames Smart 	pbuf = &mybuf[0];
3078bd2cdd5eSJames Smart 
3079bd2cdd5eSJames Smart 	if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) {
30802b65e182SJames Smart 		if (phba->nvmet_support)
3081840eda96SJames Smart 			phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
30822b65e182SJames Smart 		else
3083840eda96SJames Smart 			phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO |
30846a828b0fSJames Smart 				LPFC_CHECK_SCSI_IO);
30856a828b0fSJames Smart 		return strlen(pbuf);
30866a828b0fSJames Smart 	} else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) {
30876a828b0fSJames Smart 		if (phba->nvmet_support)
3088840eda96SJames Smart 			phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO;
30896a828b0fSJames Smart 		else
3090840eda96SJames Smart 			phba->hdwqstat_on |= LPFC_CHECK_NVME_IO;
3091bd2cdd5eSJames Smart 		return strlen(pbuf);
30926a828b0fSJames Smart 	} else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) {
3093840eda96SJames Smart 		if (!phba->nvmet_support)
3094840eda96SJames Smart 			phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO;
30956a828b0fSJames Smart 		return strlen(pbuf);
3096840eda96SJames Smart 	} else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) {
3097840eda96SJames Smart 		phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO |
3098840eda96SJames Smart 				       LPFC_CHECK_NVMET_IO);
3099840eda96SJames Smart 		return strlen(pbuf);
3100840eda96SJames Smart 	} else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) {
3101840eda96SJames Smart 		phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO;
3102f358dd0cSJames Smart 		return strlen(pbuf);
3103bd2cdd5eSJames Smart 	} else if ((strncmp(pbuf, "off",
3104bd2cdd5eSJames Smart 		   sizeof("off") - 1) == 0)) {
3105840eda96SJames Smart 		phba->hdwqstat_on = LPFC_CHECK_OFF;
3106bd2cdd5eSJames Smart 		return strlen(pbuf);
3107bd2cdd5eSJames Smart 	} else if ((strncmp(pbuf, "zero",
3108bd2cdd5eSJames Smart 		   sizeof("zero") - 1) == 0)) {
3109840eda96SJames Smart 		for_each_present_cpu(i) {
3110840eda96SJames Smart 			c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i);
3111840eda96SJames Smart 			c_stat->xmt_io = 0;
3112840eda96SJames Smart 			c_stat->cmpl_io = 0;
3113840eda96SJames Smart 			c_stat->rcv_io = 0;
3114bd2cdd5eSJames Smart 		}
3115bd2cdd5eSJames Smart 		return strlen(pbuf);
3116bd2cdd5eSJames Smart 	}
3117bd2cdd5eSJames Smart 	return -EINVAL;
3118bd2cdd5eSJames Smart }
3119bd2cdd5eSJames Smart 
31202a622bfbSJames Smart /*
312186a80846SJames Smart  * ---------------------------------
31222a622bfbSJames Smart  * iDiag debugfs file access methods
312386a80846SJames Smart  * ---------------------------------
31242a622bfbSJames Smart  *
312586a80846SJames Smart  * All access methods are through the proper SLI4 PCI function's debugfs
312686a80846SJames Smart  * iDiag directory:
31272a622bfbSJames Smart  *
31282a622bfbSJames Smart  *     /sys/kernel/debug/lpfc/fn<#>/iDiag
31292a622bfbSJames Smart  */
31302a622bfbSJames Smart 
31312a622bfbSJames Smart /**
31322a622bfbSJames Smart  * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space
31332a622bfbSJames Smart  * @buf: The pointer to the user space buffer.
31342a622bfbSJames Smart  * @nbytes: The number of bytes in the user space buffer.
31352a622bfbSJames Smart  * @idiag_cmd: pointer to the idiag command struct.
31362a622bfbSJames Smart  *
31372a622bfbSJames Smart  * This routine reads data from debugfs user space buffer and parses the
31382a622bfbSJames Smart  * buffer for getting the idiag command and arguments. The while space in
31392a622bfbSJames Smart  * between the set of data is used as the parsing separator.
31402a622bfbSJames Smart  *
31412a622bfbSJames Smart  * This routine returns 0 when successful, it returns proper error code
31422a622bfbSJames Smart  * back to the user space in error conditions.
31432a622bfbSJames Smart  */
lpfc_idiag_cmd_get(const char __user * buf,size_t nbytes,struct lpfc_idiag_cmd * idiag_cmd)31442a622bfbSJames Smart static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes,
31452a622bfbSJames Smart 			      struct lpfc_idiag_cmd *idiag_cmd)
31462a622bfbSJames Smart {
31472a622bfbSJames Smart 	char mybuf[64];
31482a622bfbSJames Smart 	char *pbuf, *step_str;
3149b11d48e8SStephen Boyd 	int i;
3150b11d48e8SStephen Boyd 	size_t bsize;
31512a622bfbSJames Smart 
31522a622bfbSJames Smart 	memset(mybuf, 0, sizeof(mybuf));
31532a622bfbSJames Smart 	memset(idiag_cmd, 0, sizeof(*idiag_cmd));
31542a622bfbSJames Smart 	bsize = min(nbytes, (sizeof(mybuf)-1));
31552a622bfbSJames Smart 
31562a622bfbSJames Smart 	if (copy_from_user(mybuf, buf, bsize))
31572a622bfbSJames Smart 		return -EFAULT;
31582a622bfbSJames Smart 	pbuf = &mybuf[0];
31592a622bfbSJames Smart 	step_str = strsep(&pbuf, "\t ");
31602a622bfbSJames Smart 
31612a622bfbSJames Smart 	/* The opcode must present */
31622a622bfbSJames Smart 	if (!step_str)
31632a622bfbSJames Smart 		return -EINVAL;
31642a622bfbSJames Smart 
31652a622bfbSJames Smart 	idiag_cmd->opcode = simple_strtol(step_str, NULL, 0);
31662a622bfbSJames Smart 	if (idiag_cmd->opcode == 0)
31672a622bfbSJames Smart 		return -EINVAL;
31682a622bfbSJames Smart 
31692a622bfbSJames Smart 	for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) {
31702a622bfbSJames Smart 		step_str = strsep(&pbuf, "\t ");
31712a622bfbSJames Smart 		if (!step_str)
317286a80846SJames Smart 			return i;
31732a622bfbSJames Smart 		idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0);
31742a622bfbSJames Smart 	}
317586a80846SJames Smart 	return i;
31762a622bfbSJames Smart }
31772a622bfbSJames Smart 
31782a622bfbSJames Smart /**
31792a622bfbSJames Smart  * lpfc_idiag_open - idiag open debugfs
31802a622bfbSJames Smart  * @inode: The inode pointer that contains a pointer to phba.
31812a622bfbSJames Smart  * @file: The file pointer to attach the file operation.
31822a622bfbSJames Smart  *
31832a622bfbSJames Smart  * Description:
31842a622bfbSJames Smart  * This routine is the entry point for the debugfs open file operation. It
31852a622bfbSJames Smart  * gets the reference to phba from the i_private field in @inode, it then
31862a622bfbSJames Smart  * allocates buffer for the file operation, performs the necessary PCI config
31872a622bfbSJames Smart  * space read into the allocated buffer according to the idiag user command
31882a622bfbSJames Smart  * setup, and then returns a pointer to buffer in the private_data field in
31892a622bfbSJames Smart  * @file.
31902a622bfbSJames Smart  *
31912a622bfbSJames Smart  * Returns:
31922a622bfbSJames Smart  * This function returns zero if successful. On error it will return an
31932a622bfbSJames Smart  * negative error value.
31942a622bfbSJames Smart  **/
31952a622bfbSJames Smart static int
lpfc_idiag_open(struct inode * inode,struct file * file)31962a622bfbSJames Smart lpfc_idiag_open(struct inode *inode, struct file *file)
31972a622bfbSJames Smart {
31982a622bfbSJames Smart 	struct lpfc_debug *debug;
31992a622bfbSJames Smart 
32002a622bfbSJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
32012a622bfbSJames Smart 	if (!debug)
32022a622bfbSJames Smart 		return -ENOMEM;
32032a622bfbSJames Smart 
32042a622bfbSJames Smart 	debug->i_private = inode->i_private;
32052a622bfbSJames Smart 	debug->buffer = NULL;
32062a622bfbSJames Smart 	file->private_data = debug;
32072a622bfbSJames Smart 
32082a622bfbSJames Smart 	return 0;
32092a622bfbSJames Smart }
32102a622bfbSJames Smart 
32112a622bfbSJames Smart /**
32122a622bfbSJames Smart  * lpfc_idiag_release - Release idiag access file operation
32132a622bfbSJames Smart  * @inode: The inode pointer that contains a vport pointer. (unused)
32142a622bfbSJames Smart  * @file: The file pointer that contains the buffer to release.
32152a622bfbSJames Smart  *
32162a622bfbSJames Smart  * Description:
32172a622bfbSJames Smart  * This routine is the generic release routine for the idiag access file
32182a622bfbSJames Smart  * operation, it frees the buffer that was allocated when the debugfs file
32192a622bfbSJames Smart  * was opened.
32202a622bfbSJames Smart  *
32212a622bfbSJames Smart  * Returns:
32222a622bfbSJames Smart  * This function returns zero.
32232a622bfbSJames Smart  **/
32242a622bfbSJames Smart static int
lpfc_idiag_release(struct inode * inode,struct file * file)32252a622bfbSJames Smart lpfc_idiag_release(struct inode *inode, struct file *file)
32262a622bfbSJames Smart {
32272a622bfbSJames Smart 	struct lpfc_debug *debug = file->private_data;
32282a622bfbSJames Smart 
32292a622bfbSJames Smart 	/* Free the buffers to the file operation */
32302a622bfbSJames Smart 	kfree(debug->buffer);
32312a622bfbSJames Smart 	kfree(debug);
32322a622bfbSJames Smart 
32332a622bfbSJames Smart 	return 0;
32342a622bfbSJames Smart }
32352a622bfbSJames Smart 
32362a622bfbSJames Smart /**
32372a622bfbSJames Smart  * lpfc_idiag_cmd_release - Release idiag cmd access file operation
32382a622bfbSJames Smart  * @inode: The inode pointer that contains a vport pointer. (unused)
32392a622bfbSJames Smart  * @file: The file pointer that contains the buffer to release.
32402a622bfbSJames Smart  *
32412a622bfbSJames Smart  * Description:
32422a622bfbSJames Smart  * This routine frees the buffer that was allocated when the debugfs file
32432a622bfbSJames Smart  * was opened. It also reset the fields in the idiag command struct in the
324486a80846SJames Smart  * case of command for write operation.
32452a622bfbSJames Smart  *
32462a622bfbSJames Smart  * Returns:
32472a622bfbSJames Smart  * This function returns zero.
32482a622bfbSJames Smart  **/
32492a622bfbSJames Smart static int
lpfc_idiag_cmd_release(struct inode * inode,struct file * file)32502a622bfbSJames Smart lpfc_idiag_cmd_release(struct inode *inode, struct file *file)
32512a622bfbSJames Smart {
32522a622bfbSJames Smart 	struct lpfc_debug *debug = file->private_data;
32532a622bfbSJames Smart 
325486a80846SJames Smart 	if (debug->op == LPFC_IDIAG_OP_WR) {
325586a80846SJames Smart 		switch (idiag.cmd.opcode) {
325686a80846SJames Smart 		case LPFC_IDIAG_CMD_PCICFG_WR:
325786a80846SJames Smart 		case LPFC_IDIAG_CMD_PCICFG_ST:
325886a80846SJames Smart 		case LPFC_IDIAG_CMD_PCICFG_CL:
325986a80846SJames Smart 		case LPFC_IDIAG_CMD_QUEACC_WR:
326086a80846SJames Smart 		case LPFC_IDIAG_CMD_QUEACC_ST:
326186a80846SJames Smart 		case LPFC_IDIAG_CMD_QUEACC_CL:
32622a622bfbSJames Smart 			memset(&idiag, 0, sizeof(idiag));
326386a80846SJames Smart 			break;
326486a80846SJames Smart 		default:
326586a80846SJames Smart 			break;
326686a80846SJames Smart 		}
326786a80846SJames Smart 	}
32682a622bfbSJames Smart 
32692a622bfbSJames Smart 	/* Free the buffers to the file operation */
32702a622bfbSJames Smart 	kfree(debug->buffer);
32712a622bfbSJames Smart 	kfree(debug);
32722a622bfbSJames Smart 
32732a622bfbSJames Smart 	return 0;
32742a622bfbSJames Smart }
32752a622bfbSJames Smart 
32762a622bfbSJames Smart /**
32772a622bfbSJames Smart  * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg
32782a622bfbSJames Smart  * @file: The file pointer to read from.
32792a622bfbSJames Smart  * @buf: The buffer to copy the data to.
32802a622bfbSJames Smart  * @nbytes: The number of bytes to read.
32812a622bfbSJames Smart  * @ppos: The position in the file to start reading from.
32822a622bfbSJames Smart  *
32832a622bfbSJames Smart  * Description:
32842a622bfbSJames Smart  * This routine reads data from the @phba pci config space according to the
32852a622bfbSJames Smart  * idiag command, and copies to user @buf. Depending on the PCI config space
32862a622bfbSJames Smart  * read command setup, it does either a single register read of a byte
32872a622bfbSJames Smart  * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all
32882a622bfbSJames Smart  * registers from the 4K extended PCI config space.
32892a622bfbSJames Smart  *
32902a622bfbSJames Smart  * Returns:
32912a622bfbSJames Smart  * This function returns the amount of data that was read (this could be less
32922a622bfbSJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
32932a622bfbSJames Smart  **/
32942a622bfbSJames Smart static ssize_t
lpfc_idiag_pcicfg_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)32952a622bfbSJames Smart lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
32962a622bfbSJames Smart 		       loff_t *ppos)
32972a622bfbSJames Smart {
32982a622bfbSJames Smart 	struct lpfc_debug *debug = file->private_data;
32992a622bfbSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
33002a622bfbSJames Smart 	int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE;
33012a622bfbSJames Smart 	int where, count;
33022a622bfbSJames Smart 	char *pbuffer;
33032a622bfbSJames Smart 	struct pci_dev *pdev;
33042a622bfbSJames Smart 	uint32_t u32val;
33052a622bfbSJames Smart 	uint16_t u16val;
33062a622bfbSJames Smart 	uint8_t u8val;
33072a622bfbSJames Smart 
33082a622bfbSJames Smart 	pdev = phba->pcidev;
33092a622bfbSJames Smart 	if (!pdev)
33102a622bfbSJames Smart 		return 0;
33112a622bfbSJames Smart 
33122a622bfbSJames Smart 	/* This is a user read operation */
33132a622bfbSJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
33142a622bfbSJames Smart 
33152a622bfbSJames Smart 	if (!debug->buffer)
33162a622bfbSJames Smart 		debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL);
33172a622bfbSJames Smart 	if (!debug->buffer)
33182a622bfbSJames Smart 		return 0;
33192a622bfbSJames Smart 	pbuffer = debug->buffer;
33202a622bfbSJames Smart 
33212a622bfbSJames Smart 	if (*ppos)
33222a622bfbSJames Smart 		return 0;
33232a622bfbSJames Smart 
33242a622bfbSJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
3325b76f2dc9SJames Smart 		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3326b76f2dc9SJames Smart 		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
33272a622bfbSJames Smart 	} else
33282a622bfbSJames Smart 		return 0;
33292a622bfbSJames Smart 
33302a622bfbSJames Smart 	/* Read single PCI config space register */
33312a622bfbSJames Smart 	switch (count) {
33322a622bfbSJames Smart 	case SIZE_U8: /* byte (8 bits) */
33332a622bfbSJames Smart 		pci_read_config_byte(pdev, where, &u8val);
3334e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33352a622bfbSJames Smart 				"%03x: %02x\n", where, u8val);
33362a622bfbSJames Smart 		break;
33372a622bfbSJames Smart 	case SIZE_U16: /* word (16 bits) */
33382a622bfbSJames Smart 		pci_read_config_word(pdev, where, &u16val);
3339e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33402a622bfbSJames Smart 				"%03x: %04x\n", where, u16val);
33412a622bfbSJames Smart 		break;
33422a622bfbSJames Smart 	case SIZE_U32: /* double word (32 bits) */
33432a622bfbSJames Smart 		pci_read_config_dword(pdev, where, &u32val);
3344e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33452a622bfbSJames Smart 				"%03x: %08x\n", where, u32val);
33462a622bfbSJames Smart 		break;
334786a80846SJames Smart 	case LPFC_PCI_CFG_BROWSE: /* browse all */
33482a622bfbSJames Smart 		goto pcicfg_browse;
33492a622bfbSJames Smart 	default:
33502a622bfbSJames Smart 		/* illegal count */
33512a622bfbSJames Smart 		len = 0;
33522a622bfbSJames Smart 		break;
33532a622bfbSJames Smart 	}
33542a622bfbSJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
33552a622bfbSJames Smart 
33562a622bfbSJames Smart pcicfg_browse:
33572a622bfbSJames Smart 
33582a622bfbSJames Smart 	/* Browse all PCI config space registers */
33592a622bfbSJames Smart 	offset_label = idiag.offset.last_rd;
33602a622bfbSJames Smart 	offset = offset_label;
33612a622bfbSJames Smart 
33622a622bfbSJames Smart 	/* Read PCI config space */
3363e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33642a622bfbSJames Smart 			"%03x: ", offset_label);
33652a622bfbSJames Smart 	while (index > 0) {
33662a622bfbSJames Smart 		pci_read_config_dword(pdev, offset, &u32val);
3367e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33682a622bfbSJames Smart 				"%08x ", u32val);
33692a622bfbSJames Smart 		offset += sizeof(uint32_t);
3370b76f2dc9SJames Smart 		if (offset >= LPFC_PCI_CFG_SIZE) {
3371e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len,
3372b76f2dc9SJames Smart 					LPFC_PCI_CFG_SIZE-len, "\n");
3373b76f2dc9SJames Smart 			break;
3374b76f2dc9SJames Smart 		}
33752a622bfbSJames Smart 		index -= sizeof(uint32_t);
33762a622bfbSJames Smart 		if (!index)
3377e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33782a622bfbSJames Smart 					"\n");
33792a622bfbSJames Smart 		else if (!(index % (8 * sizeof(uint32_t)))) {
33802a622bfbSJames Smart 			offset_label += (8 * sizeof(uint32_t));
3381e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
33822a622bfbSJames Smart 					"\n%03x: ", offset_label);
33832a622bfbSJames Smart 		}
33842a622bfbSJames Smart 	}
33852a622bfbSJames Smart 
33862a622bfbSJames Smart 	/* Set up the offset for next portion of pci cfg read */
3387b76f2dc9SJames Smart 	if (index == 0) {
33882a622bfbSJames Smart 		idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
33892a622bfbSJames Smart 		if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
33902a622bfbSJames Smart 			idiag.offset.last_rd = 0;
3391b76f2dc9SJames Smart 	} else
3392b76f2dc9SJames Smart 		idiag.offset.last_rd = 0;
33932a622bfbSJames Smart 
33942a622bfbSJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
33952a622bfbSJames Smart }
33962a622bfbSJames Smart 
33972a622bfbSJames Smart /**
33982a622bfbSJames Smart  * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands
33992a622bfbSJames Smart  * @file: The file pointer to read from.
34002a622bfbSJames Smart  * @buf: The buffer to copy the user data from.
34012a622bfbSJames Smart  * @nbytes: The number of bytes to get.
34022a622bfbSJames Smart  * @ppos: The position in the file to start reading from.
34032a622bfbSJames Smart  *
34042a622bfbSJames Smart  * This routine get the debugfs idiag command struct from user space and
34052a622bfbSJames Smart  * then perform the syntax check for PCI config space read or write command
34062a622bfbSJames Smart  * accordingly. In the case of PCI config space read command, it sets up
34072a622bfbSJames Smart  * the command in the idiag command struct for the debugfs read operation.
34082a622bfbSJames Smart  * In the case of PCI config space write operation, it executes the write
34092a622bfbSJames Smart  * operation into the PCI config space accordingly.
34102a622bfbSJames Smart  *
34112a622bfbSJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
34122a622bfbSJames Smart  * In case of error conditions, it returns proper error code back to the user
34132a622bfbSJames Smart  * space.
34142a622bfbSJames Smart  */
34152a622bfbSJames Smart static ssize_t
lpfc_idiag_pcicfg_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)34162a622bfbSJames Smart lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
34172a622bfbSJames Smart 			size_t nbytes, loff_t *ppos)
34182a622bfbSJames Smart {
34192a622bfbSJames Smart 	struct lpfc_debug *debug = file->private_data;
34202a622bfbSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
34212a622bfbSJames Smart 	uint32_t where, value, count;
34222a622bfbSJames Smart 	uint32_t u32val;
34232a622bfbSJames Smart 	uint16_t u16val;
34242a622bfbSJames Smart 	uint8_t u8val;
34252a622bfbSJames Smart 	struct pci_dev *pdev;
34262a622bfbSJames Smart 	int rc;
34272a622bfbSJames Smart 
34282a622bfbSJames Smart 	pdev = phba->pcidev;
34292a622bfbSJames Smart 	if (!pdev)
34302a622bfbSJames Smart 		return -EFAULT;
34312a622bfbSJames Smart 
34322a622bfbSJames Smart 	/* This is a user write operation */
34332a622bfbSJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
34342a622bfbSJames Smart 
34352a622bfbSJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
343686a80846SJames Smart 	if (rc < 0)
34372a622bfbSJames Smart 		return rc;
34382a622bfbSJames Smart 
34392a622bfbSJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
344086a80846SJames Smart 		/* Sanity check on PCI config read command line arguments */
344186a80846SJames Smart 		if (rc != LPFC_PCI_CFG_RD_CMD_ARG)
344286a80846SJames Smart 			goto error_out;
34432a622bfbSJames Smart 		/* Read command from PCI config space, set up command fields */
3444b76f2dc9SJames Smart 		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3445b76f2dc9SJames Smart 		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
344686a80846SJames Smart 		if (count == LPFC_PCI_CFG_BROWSE) {
344786a80846SJames Smart 			if (where % sizeof(uint32_t))
34482a622bfbSJames Smart 				goto error_out;
344986a80846SJames Smart 			/* Starting offset to browse */
345086a80846SJames Smart 			idiag.offset.last_rd = where;
34512a622bfbSJames Smart 		} else if ((count != sizeof(uint8_t)) &&
34522a622bfbSJames Smart 			   (count != sizeof(uint16_t)) &&
34532a622bfbSJames Smart 			   (count != sizeof(uint32_t)))
34542a622bfbSJames Smart 			goto error_out;
34552a622bfbSJames Smart 		if (count == sizeof(uint8_t)) {
34562a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
34572a622bfbSJames Smart 				goto error_out;
34582a622bfbSJames Smart 			if (where % sizeof(uint8_t))
34592a622bfbSJames Smart 				goto error_out;
34602a622bfbSJames Smart 		}
34612a622bfbSJames Smart 		if (count == sizeof(uint16_t)) {
34622a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
34632a622bfbSJames Smart 				goto error_out;
34642a622bfbSJames Smart 			if (where % sizeof(uint16_t))
34652a622bfbSJames Smart 				goto error_out;
34662a622bfbSJames Smart 		}
34672a622bfbSJames Smart 		if (count == sizeof(uint32_t)) {
34682a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
34692a622bfbSJames Smart 				goto error_out;
34702a622bfbSJames Smart 			if (where % sizeof(uint32_t))
34712a622bfbSJames Smart 				goto error_out;
34722a622bfbSJames Smart 		}
34732a622bfbSJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR ||
34742a622bfbSJames Smart 		   idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST ||
34752a622bfbSJames Smart 		   idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
347686a80846SJames Smart 		/* Sanity check on PCI config write command line arguments */
347786a80846SJames Smart 		if (rc != LPFC_PCI_CFG_WR_CMD_ARG)
347886a80846SJames Smart 			goto error_out;
34792a622bfbSJames Smart 		/* Write command to PCI config space, read-modify-write */
3480b76f2dc9SJames Smart 		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
3481b76f2dc9SJames Smart 		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
3482b76f2dc9SJames Smart 		value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];
34832a622bfbSJames Smart 		/* Sanity checks */
34842a622bfbSJames Smart 		if ((count != sizeof(uint8_t)) &&
34852a622bfbSJames Smart 		    (count != sizeof(uint16_t)) &&
34862a622bfbSJames Smart 		    (count != sizeof(uint32_t)))
34872a622bfbSJames Smart 			goto error_out;
34882a622bfbSJames Smart 		if (count == sizeof(uint8_t)) {
34892a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
34902a622bfbSJames Smart 				goto error_out;
34912a622bfbSJames Smart 			if (where % sizeof(uint8_t))
34922a622bfbSJames Smart 				goto error_out;
34932a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
34942a622bfbSJames Smart 				pci_write_config_byte(pdev, where,
34952a622bfbSJames Smart 						      (uint8_t)value);
34962a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
34972a622bfbSJames Smart 				rc = pci_read_config_byte(pdev, where, &u8val);
34982a622bfbSJames Smart 				if (!rc) {
34992a622bfbSJames Smart 					u8val |= (uint8_t)value;
35002a622bfbSJames Smart 					pci_write_config_byte(pdev, where,
35012a622bfbSJames Smart 							      u8val);
35022a622bfbSJames Smart 				}
35032a622bfbSJames Smart 			}
35042a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
35052a622bfbSJames Smart 				rc = pci_read_config_byte(pdev, where, &u8val);
35062a622bfbSJames Smart 				if (!rc) {
35072a622bfbSJames Smart 					u8val &= (uint8_t)(~value);
35082a622bfbSJames Smart 					pci_write_config_byte(pdev, where,
35092a622bfbSJames Smart 							      u8val);
35102a622bfbSJames Smart 				}
35112a622bfbSJames Smart 			}
35122a622bfbSJames Smart 		}
35132a622bfbSJames Smart 		if (count == sizeof(uint16_t)) {
35142a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
35152a622bfbSJames Smart 				goto error_out;
35162a622bfbSJames Smart 			if (where % sizeof(uint16_t))
35172a622bfbSJames Smart 				goto error_out;
35182a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
35192a622bfbSJames Smart 				pci_write_config_word(pdev, where,
35202a622bfbSJames Smart 						      (uint16_t)value);
35212a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
35222a622bfbSJames Smart 				rc = pci_read_config_word(pdev, where, &u16val);
35232a622bfbSJames Smart 				if (!rc) {
35242a622bfbSJames Smart 					u16val |= (uint16_t)value;
35252a622bfbSJames Smart 					pci_write_config_word(pdev, where,
35262a622bfbSJames Smart 							      u16val);
35272a622bfbSJames Smart 				}
35282a622bfbSJames Smart 			}
35292a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
35302a622bfbSJames Smart 				rc = pci_read_config_word(pdev, where, &u16val);
35312a622bfbSJames Smart 				if (!rc) {
35322a622bfbSJames Smart 					u16val &= (uint16_t)(~value);
35332a622bfbSJames Smart 					pci_write_config_word(pdev, where,
35342a622bfbSJames Smart 							      u16val);
35352a622bfbSJames Smart 				}
35362a622bfbSJames Smart 			}
35372a622bfbSJames Smart 		}
35382a622bfbSJames Smart 		if (count == sizeof(uint32_t)) {
35392a622bfbSJames Smart 			if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
35402a622bfbSJames Smart 				goto error_out;
35412a622bfbSJames Smart 			if (where % sizeof(uint32_t))
35422a622bfbSJames Smart 				goto error_out;
35432a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
35442a622bfbSJames Smart 				pci_write_config_dword(pdev, where, value);
35452a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
35462a622bfbSJames Smart 				rc = pci_read_config_dword(pdev, where,
35472a622bfbSJames Smart 							   &u32val);
35482a622bfbSJames Smart 				if (!rc) {
35492a622bfbSJames Smart 					u32val |= value;
35502a622bfbSJames Smart 					pci_write_config_dword(pdev, where,
35512a622bfbSJames Smart 							       u32val);
35522a622bfbSJames Smart 				}
35532a622bfbSJames Smart 			}
35542a622bfbSJames Smart 			if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
35552a622bfbSJames Smart 				rc = pci_read_config_dword(pdev, where,
35562a622bfbSJames Smart 							   &u32val);
35572a622bfbSJames Smart 				if (!rc) {
35582a622bfbSJames Smart 					u32val &= ~value;
35592a622bfbSJames Smart 					pci_write_config_dword(pdev, where,
35602a622bfbSJames Smart 							       u32val);
35612a622bfbSJames Smart 				}
35622a622bfbSJames Smart 			}
35632a622bfbSJames Smart 		}
35642a622bfbSJames Smart 	} else
35652a622bfbSJames Smart 		/* All other opecodes are illegal for now */
35662a622bfbSJames Smart 		goto error_out;
35672a622bfbSJames Smart 
35682a622bfbSJames Smart 	return nbytes;
35692a622bfbSJames Smart error_out:
35702a622bfbSJames Smart 	memset(&idiag, 0, sizeof(idiag));
35712a622bfbSJames Smart 	return -EINVAL;
35722a622bfbSJames Smart }
35732a622bfbSJames Smart 
35742a622bfbSJames Smart /**
3575b76f2dc9SJames Smart  * lpfc_idiag_baracc_read - idiag debugfs pci bar access read
3576b76f2dc9SJames Smart  * @file: The file pointer to read from.
3577b76f2dc9SJames Smart  * @buf: The buffer to copy the data to.
3578b76f2dc9SJames Smart  * @nbytes: The number of bytes to read.
3579b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
3580b76f2dc9SJames Smart  *
3581b76f2dc9SJames Smart  * Description:
3582b76f2dc9SJames Smart  * This routine reads data from the @phba pci bar memory mapped space
3583b76f2dc9SJames Smart  * according to the idiag command, and copies to user @buf.
3584b76f2dc9SJames Smart  *
3585b76f2dc9SJames Smart  * Returns:
3586b76f2dc9SJames Smart  * This function returns the amount of data that was read (this could be less
3587b76f2dc9SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
3588b76f2dc9SJames Smart  **/
3589b76f2dc9SJames Smart static ssize_t
lpfc_idiag_baracc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)3590b76f2dc9SJames Smart lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
3591b76f2dc9SJames Smart 		       loff_t *ppos)
3592b76f2dc9SJames Smart {
3593b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
3594b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3595b76f2dc9SJames Smart 	int offset_label, offset, offset_run, len = 0, index;
3596b76f2dc9SJames Smart 	int bar_num, acc_range, bar_size;
3597b76f2dc9SJames Smart 	char *pbuffer;
3598b76f2dc9SJames Smart 	void __iomem *mem_mapped_bar;
3599b76f2dc9SJames Smart 	uint32_t if_type;
3600b76f2dc9SJames Smart 	struct pci_dev *pdev;
3601b76f2dc9SJames Smart 	uint32_t u32val;
3602b76f2dc9SJames Smart 
3603b76f2dc9SJames Smart 	pdev = phba->pcidev;
3604b76f2dc9SJames Smart 	if (!pdev)
3605b76f2dc9SJames Smart 		return 0;
3606b76f2dc9SJames Smart 
3607b76f2dc9SJames Smart 	/* This is a user read operation */
3608b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
3609b76f2dc9SJames Smart 
3610b76f2dc9SJames Smart 	if (!debug->buffer)
3611b76f2dc9SJames Smart 		debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL);
3612b76f2dc9SJames Smart 	if (!debug->buffer)
3613b76f2dc9SJames Smart 		return 0;
3614b76f2dc9SJames Smart 	pbuffer = debug->buffer;
3615b76f2dc9SJames Smart 
3616b76f2dc9SJames Smart 	if (*ppos)
3617b76f2dc9SJames Smart 		return 0;
3618b76f2dc9SJames Smart 
3619b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
3620b76f2dc9SJames Smart 		bar_num   = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
3621b76f2dc9SJames Smart 		offset    = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
3622b76f2dc9SJames Smart 		acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
3623b76f2dc9SJames Smart 		bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
3624b76f2dc9SJames Smart 	} else
3625b76f2dc9SJames Smart 		return 0;
3626b76f2dc9SJames Smart 
3627b76f2dc9SJames Smart 	if (acc_range == 0)
3628b76f2dc9SJames Smart 		return 0;
3629b76f2dc9SJames Smart 
3630b76f2dc9SJames Smart 	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
3631b76f2dc9SJames Smart 	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3632b76f2dc9SJames Smart 		if (bar_num == IDIAG_BARACC_BAR_0)
3633b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3634b76f2dc9SJames Smart 		else if (bar_num == IDIAG_BARACC_BAR_1)
3635b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
3636b76f2dc9SJames Smart 		else if (bar_num == IDIAG_BARACC_BAR_2)
3637b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
3638b76f2dc9SJames Smart 		else
3639b76f2dc9SJames Smart 			return 0;
3640b76f2dc9SJames Smart 	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3641b76f2dc9SJames Smart 		if (bar_num == IDIAG_BARACC_BAR_0)
3642b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3643b76f2dc9SJames Smart 		else
3644b76f2dc9SJames Smart 			return 0;
3645b76f2dc9SJames Smart 	} else
3646b76f2dc9SJames Smart 		return 0;
3647b76f2dc9SJames Smart 
3648b76f2dc9SJames Smart 	/* Read single PCI bar space register */
3649b76f2dc9SJames Smart 	if (acc_range == SINGLE_WORD) {
3650b76f2dc9SJames Smart 		offset_run = offset;
3651b76f2dc9SJames Smart 		u32val = readl(mem_mapped_bar + offset_run);
3652e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3653b76f2dc9SJames Smart 				"%05x: %08x\n", offset_run, u32val);
3654b76f2dc9SJames Smart 	} else
3655b76f2dc9SJames Smart 		goto baracc_browse;
3656b76f2dc9SJames Smart 
3657b76f2dc9SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3658b76f2dc9SJames Smart 
3659b76f2dc9SJames Smart baracc_browse:
3660b76f2dc9SJames Smart 
3661b76f2dc9SJames Smart 	/* Browse all PCI bar space registers */
3662b76f2dc9SJames Smart 	offset_label = idiag.offset.last_rd;
3663b76f2dc9SJames Smart 	offset_run = offset_label;
3664b76f2dc9SJames Smart 
3665b76f2dc9SJames Smart 	/* Read PCI bar memory mapped space */
3666e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3667b76f2dc9SJames Smart 			"%05x: ", offset_label);
3668b76f2dc9SJames Smart 	index = LPFC_PCI_BAR_RD_SIZE;
3669b76f2dc9SJames Smart 	while (index > 0) {
3670b76f2dc9SJames Smart 		u32val = readl(mem_mapped_bar + offset_run);
3671e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
3672b76f2dc9SJames Smart 				"%08x ", u32val);
3673b76f2dc9SJames Smart 		offset_run += sizeof(uint32_t);
3674b76f2dc9SJames Smart 		if (acc_range == LPFC_PCI_BAR_BROWSE) {
3675b76f2dc9SJames Smart 			if (offset_run >= bar_size) {
3676e7f7b6f3SSilvio Cesare 				len += scnprintf(pbuffer+len,
3677b76f2dc9SJames Smart 					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3678b76f2dc9SJames Smart 				break;
3679b76f2dc9SJames Smart 			}
3680b76f2dc9SJames Smart 		} else {
3681b76f2dc9SJames Smart 			if (offset_run >= offset +
3682b76f2dc9SJames Smart 			    (acc_range * sizeof(uint32_t))) {
3683e7f7b6f3SSilvio Cesare 				len += scnprintf(pbuffer+len,
3684b76f2dc9SJames Smart 					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3685b76f2dc9SJames Smart 				break;
3686b76f2dc9SJames Smart 			}
3687b76f2dc9SJames Smart 		}
3688b76f2dc9SJames Smart 		index -= sizeof(uint32_t);
3689b76f2dc9SJames Smart 		if (!index)
3690e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len,
3691b76f2dc9SJames Smart 					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
3692b76f2dc9SJames Smart 		else if (!(index % (8 * sizeof(uint32_t)))) {
3693b76f2dc9SJames Smart 			offset_label += (8 * sizeof(uint32_t));
3694e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len,
3695b76f2dc9SJames Smart 					LPFC_PCI_BAR_RD_BUF_SIZE-len,
3696b76f2dc9SJames Smart 					"\n%05x: ", offset_label);
3697b76f2dc9SJames Smart 		}
3698b76f2dc9SJames Smart 	}
3699b76f2dc9SJames Smart 
3700b76f2dc9SJames Smart 	/* Set up the offset for next portion of pci bar read */
3701b76f2dc9SJames Smart 	if (index == 0) {
3702b76f2dc9SJames Smart 		idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE;
3703b76f2dc9SJames Smart 		if (acc_range == LPFC_PCI_BAR_BROWSE) {
3704b76f2dc9SJames Smart 			if (idiag.offset.last_rd >= bar_size)
3705b76f2dc9SJames Smart 				idiag.offset.last_rd = 0;
3706b76f2dc9SJames Smart 		} else {
3707b76f2dc9SJames Smart 			if (offset_run >= offset +
3708b76f2dc9SJames Smart 			    (acc_range * sizeof(uint32_t)))
3709b76f2dc9SJames Smart 				idiag.offset.last_rd = offset;
3710b76f2dc9SJames Smart 		}
3711b76f2dc9SJames Smart 	} else {
3712b76f2dc9SJames Smart 		if (acc_range == LPFC_PCI_BAR_BROWSE)
3713b76f2dc9SJames Smart 			idiag.offset.last_rd = 0;
3714b76f2dc9SJames Smart 		else
3715b76f2dc9SJames Smart 			idiag.offset.last_rd = offset;
3716b76f2dc9SJames Smart 	}
3717b76f2dc9SJames Smart 
3718b76f2dc9SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
3719b76f2dc9SJames Smart }
3720b76f2dc9SJames Smart 
3721b76f2dc9SJames Smart /**
3722b76f2dc9SJames Smart  * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands
3723b76f2dc9SJames Smart  * @file: The file pointer to read from.
3724b76f2dc9SJames Smart  * @buf: The buffer to copy the user data from.
3725b76f2dc9SJames Smart  * @nbytes: The number of bytes to get.
3726b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
3727b76f2dc9SJames Smart  *
3728b76f2dc9SJames Smart  * This routine get the debugfs idiag command struct from user space and
3729b76f2dc9SJames Smart  * then perform the syntax check for PCI bar memory mapped space read or
3730b76f2dc9SJames Smart  * write command accordingly. In the case of PCI bar memory mapped space
3731b76f2dc9SJames Smart  * read command, it sets up the command in the idiag command struct for
3732b76f2dc9SJames Smart  * the debugfs read operation. In the case of PCI bar memorpy mapped space
3733b76f2dc9SJames Smart  * write operation, it executes the write operation into the PCI bar memory
3734b76f2dc9SJames Smart  * mapped space accordingly.
3735b76f2dc9SJames Smart  *
3736b76f2dc9SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
3737b76f2dc9SJames Smart  * In case of error conditions, it returns proper error code back to the user
3738b76f2dc9SJames Smart  * space.
3739b76f2dc9SJames Smart  */
3740b76f2dc9SJames Smart static ssize_t
lpfc_idiag_baracc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)3741b76f2dc9SJames Smart lpfc_idiag_baracc_write(struct file *file, const char __user *buf,
3742b76f2dc9SJames Smart 			size_t nbytes, loff_t *ppos)
3743b76f2dc9SJames Smart {
3744b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
3745b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
3746b76f2dc9SJames Smart 	uint32_t bar_num, bar_size, offset, value, acc_range;
3747b76f2dc9SJames Smart 	struct pci_dev *pdev;
3748b76f2dc9SJames Smart 	void __iomem *mem_mapped_bar;
3749b76f2dc9SJames Smart 	uint32_t if_type;
3750b76f2dc9SJames Smart 	uint32_t u32val;
3751b76f2dc9SJames Smart 	int rc;
3752b76f2dc9SJames Smart 
3753b76f2dc9SJames Smart 	pdev = phba->pcidev;
3754b76f2dc9SJames Smart 	if (!pdev)
3755b76f2dc9SJames Smart 		return -EFAULT;
3756b76f2dc9SJames Smart 
3757b76f2dc9SJames Smart 	/* This is a user write operation */
3758b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
3759b76f2dc9SJames Smart 
3760b76f2dc9SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
3761b76f2dc9SJames Smart 	if (rc < 0)
3762b76f2dc9SJames Smart 		return rc;
3763b76f2dc9SJames Smart 
3764b76f2dc9SJames Smart 	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
3765b76f2dc9SJames Smart 	bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
3766b76f2dc9SJames Smart 
3767b76f2dc9SJames Smart 	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3768b76f2dc9SJames Smart 		if ((bar_num != IDIAG_BARACC_BAR_0) &&
3769b76f2dc9SJames Smart 		    (bar_num != IDIAG_BARACC_BAR_1) &&
3770b76f2dc9SJames Smart 		    (bar_num != IDIAG_BARACC_BAR_2))
3771b76f2dc9SJames Smart 			goto error_out;
3772b76f2dc9SJames Smart 	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3773b76f2dc9SJames Smart 		if (bar_num != IDIAG_BARACC_BAR_0)
3774b76f2dc9SJames Smart 			goto error_out;
3775b76f2dc9SJames Smart 	} else
3776b76f2dc9SJames Smart 		goto error_out;
3777b76f2dc9SJames Smart 
3778b76f2dc9SJames Smart 	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
3779b76f2dc9SJames Smart 		if (bar_num == IDIAG_BARACC_BAR_0) {
3780b76f2dc9SJames Smart 			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3781b76f2dc9SJames Smart 				LPFC_PCI_IF0_BAR0_SIZE;
3782b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3783b76f2dc9SJames Smart 		} else if (bar_num == IDIAG_BARACC_BAR_1) {
3784b76f2dc9SJames Smart 			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3785b76f2dc9SJames Smart 				LPFC_PCI_IF0_BAR1_SIZE;
3786b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
3787b76f2dc9SJames Smart 		} else if (bar_num == IDIAG_BARACC_BAR_2) {
3788b76f2dc9SJames Smart 			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3789b76f2dc9SJames Smart 				LPFC_PCI_IF0_BAR2_SIZE;
3790b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
3791b76f2dc9SJames Smart 		} else
3792b76f2dc9SJames Smart 			goto error_out;
3793b76f2dc9SJames Smart 	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
3794b76f2dc9SJames Smart 		if (bar_num == IDIAG_BARACC_BAR_0) {
3795b76f2dc9SJames Smart 			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
3796b76f2dc9SJames Smart 				LPFC_PCI_IF2_BAR0_SIZE;
3797b76f2dc9SJames Smart 			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
3798b76f2dc9SJames Smart 		} else
3799b76f2dc9SJames Smart 			goto error_out;
3800b76f2dc9SJames Smart 	} else
3801b76f2dc9SJames Smart 		goto error_out;
3802b76f2dc9SJames Smart 
3803b76f2dc9SJames Smart 	offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
3804b76f2dc9SJames Smart 	if (offset % sizeof(uint32_t))
3805b76f2dc9SJames Smart 		goto error_out;
3806b76f2dc9SJames Smart 
3807b76f2dc9SJames Smart 	bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
3808b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
3809b76f2dc9SJames Smart 		/* Sanity check on PCI config read command line arguments */
3810b76f2dc9SJames Smart 		if (rc != LPFC_PCI_BAR_RD_CMD_ARG)
3811b76f2dc9SJames Smart 			goto error_out;
3812b76f2dc9SJames Smart 		acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
3813b76f2dc9SJames Smart 		if (acc_range == LPFC_PCI_BAR_BROWSE) {
3814b76f2dc9SJames Smart 			if (offset > bar_size - sizeof(uint32_t))
3815b76f2dc9SJames Smart 				goto error_out;
3816b76f2dc9SJames Smart 			/* Starting offset to browse */
3817b76f2dc9SJames Smart 			idiag.offset.last_rd = offset;
3818b76f2dc9SJames Smart 		} else if (acc_range > SINGLE_WORD) {
3819b76f2dc9SJames Smart 			if (offset + acc_range * sizeof(uint32_t) > bar_size)
3820b76f2dc9SJames Smart 				goto error_out;
3821b76f2dc9SJames Smart 			/* Starting offset to browse */
3822b76f2dc9SJames Smart 			idiag.offset.last_rd = offset;
3823b76f2dc9SJames Smart 		} else if (acc_range != SINGLE_WORD)
3824b76f2dc9SJames Smart 			goto error_out;
3825b76f2dc9SJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR ||
3826b76f2dc9SJames Smart 		   idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST ||
3827b76f2dc9SJames Smart 		   idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
3828b76f2dc9SJames Smart 		/* Sanity check on PCI bar write command line arguments */
3829b76f2dc9SJames Smart 		if (rc != LPFC_PCI_BAR_WR_CMD_ARG)
3830b76f2dc9SJames Smart 			goto error_out;
3831b76f2dc9SJames Smart 		/* Write command to PCI bar space, read-modify-write */
3832b76f2dc9SJames Smart 		acc_range = SINGLE_WORD;
3833b76f2dc9SJames Smart 		value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX];
3834b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) {
3835b76f2dc9SJames Smart 			writel(value, mem_mapped_bar + offset);
3836b76f2dc9SJames Smart 			readl(mem_mapped_bar + offset);
3837b76f2dc9SJames Smart 		}
3838b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) {
3839b76f2dc9SJames Smart 			u32val = readl(mem_mapped_bar + offset);
3840b76f2dc9SJames Smart 			u32val |= value;
3841b76f2dc9SJames Smart 			writel(u32val, mem_mapped_bar + offset);
3842b76f2dc9SJames Smart 			readl(mem_mapped_bar + offset);
3843b76f2dc9SJames Smart 		}
3844b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
3845b76f2dc9SJames Smart 			u32val = readl(mem_mapped_bar + offset);
3846b76f2dc9SJames Smart 			u32val &= ~value;
3847b76f2dc9SJames Smart 			writel(u32val, mem_mapped_bar + offset);
3848b76f2dc9SJames Smart 			readl(mem_mapped_bar + offset);
3849b76f2dc9SJames Smart 		}
3850b76f2dc9SJames Smart 	} else
3851b76f2dc9SJames Smart 		/* All other opecodes are illegal for now */
3852b76f2dc9SJames Smart 		goto error_out;
3853b76f2dc9SJames Smart 
3854b76f2dc9SJames Smart 	return nbytes;
3855b76f2dc9SJames Smart error_out:
3856b76f2dc9SJames Smart 	memset(&idiag, 0, sizeof(idiag));
3857b76f2dc9SJames Smart 	return -EINVAL;
3858b76f2dc9SJames Smart }
3859b76f2dc9SJames Smart 
386007bcd98eSJames Smart static int
__lpfc_idiag_print_wq(struct lpfc_queue * qp,char * wqtype,char * pbuffer,int len)386107bcd98eSJames Smart __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype,
386207bcd98eSJames Smart 			char *pbuffer, int len)
386307bcd98eSJames Smart {
386407bcd98eSJames Smart 	if (!qp)
386507bcd98eSJames Smart 		return len;
386607bcd98eSJames Smart 
3867e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
386807bcd98eSJames Smart 			"\t\t%s WQ info: ", wqtype);
3869e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
387007bcd98eSJames Smart 			"AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n",
387107bcd98eSJames Smart 			qp->assoc_qid, qp->q_cnt_1,
387207bcd98eSJames Smart 			(unsigned long long)qp->q_cnt_4);
3873e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
38747869da18SJames Smart 			"\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
387532517fc0SJames Smart 			"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]",
387607bcd98eSJames Smart 			qp->queue_id, qp->entry_count,
387707bcd98eSJames Smart 			qp->entry_size, qp->host_index,
387832517fc0SJames Smart 			qp->hba_index, qp->notify_interval);
3879e7f7b6f3SSilvio Cesare 	len +=  scnprintf(pbuffer + len,
388007bcd98eSJames Smart 			LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
388107bcd98eSJames Smart 	return len;
388207bcd98eSJames Smart }
388307bcd98eSJames Smart 
388407bcd98eSJames Smart static int
lpfc_idiag_wqs_for_cq(struct lpfc_hba * phba,char * wqtype,char * pbuffer,int * len,int max_cnt,int cq_id)388507bcd98eSJames Smart lpfc_idiag_wqs_for_cq(struct lpfc_hba *phba, char *wqtype, char *pbuffer,
388607bcd98eSJames Smart 		int *len, int max_cnt, int cq_id)
388707bcd98eSJames Smart {
388807bcd98eSJames Smart 	struct lpfc_queue *qp;
388907bcd98eSJames Smart 	int qidx;
389007bcd98eSJames Smart 
3891cdb42becSJames Smart 	for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
3892c00f62e6SJames Smart 		qp = phba->sli4_hba.hdwq[qidx].io_wq;
389307bcd98eSJames Smart 		if (qp->assoc_qid != cq_id)
389407bcd98eSJames Smart 			continue;
389507bcd98eSJames Smart 		*len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len);
389607bcd98eSJames Smart 		if (*len >= max_cnt)
389707bcd98eSJames Smart 			return 1;
389807bcd98eSJames Smart 	}
389907bcd98eSJames Smart 	return 0;
390007bcd98eSJames Smart }
390107bcd98eSJames Smart 
390207bcd98eSJames Smart static int
__lpfc_idiag_print_cq(struct lpfc_queue * qp,char * cqtype,char * pbuffer,int len)390307bcd98eSJames Smart __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype,
390407bcd98eSJames Smart 			char *pbuffer, int len)
390507bcd98eSJames Smart {
390607bcd98eSJames Smart 	if (!qp)
390707bcd98eSJames Smart 		return len;
390807bcd98eSJames Smart 
3909e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
391007bcd98eSJames Smart 			"\t%s CQ info: ", cqtype);
3911e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
391207bcd98eSJames Smart 			"AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x "
391307bcd98eSJames Smart 			"xabt:x%x wq:x%llx]\n",
391407bcd98eSJames Smart 			qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
391507bcd98eSJames Smart 			qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
3916e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
39177869da18SJames Smart 			"\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
391832517fc0SJames Smart 			"HST-IDX[%04d], NTFI[%03d], PLMT[%03d]",
391907bcd98eSJames Smart 			qp->queue_id, qp->entry_count,
392007bcd98eSJames Smart 			qp->entry_size, qp->host_index,
392132517fc0SJames Smart 			qp->notify_interval, qp->max_proc_limit);
392207bcd98eSJames Smart 
3923e7f7b6f3SSilvio Cesare 	len +=  scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
3924e7f7b6f3SSilvio Cesare 			"\n");
392507bcd98eSJames Smart 
392607bcd98eSJames Smart 	return len;
392707bcd98eSJames Smart }
392807bcd98eSJames Smart 
392907bcd98eSJames Smart static int
__lpfc_idiag_print_rqpair(struct lpfc_queue * qp,struct lpfc_queue * datqp,char * rqtype,char * pbuffer,int len)393007bcd98eSJames Smart __lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp,
393107bcd98eSJames Smart 			char *rqtype, char *pbuffer, int len)
393207bcd98eSJames Smart {
393307bcd98eSJames Smart 	if (!qp || !datqp)
393407bcd98eSJames Smart 		return len;
393507bcd98eSJames Smart 
3936e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
393707bcd98eSJames Smart 			"\t\t%s RQ info: ", rqtype);
3938e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
393907bcd98eSJames Smart 			"AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x "
3940547077a4SJames Smart 			"posted:x%x rcv:x%llx]\n",
394107bcd98eSJames Smart 			qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
394207bcd98eSJames Smart 			qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
3943e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
39447869da18SJames Smart 			"\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
394532517fc0SJames Smart 			"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
394607bcd98eSJames Smart 			qp->queue_id, qp->entry_count, qp->entry_size,
394732517fc0SJames Smart 			qp->host_index, qp->hba_index, qp->notify_interval);
3948e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
39497869da18SJames Smart 			"\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
395032517fc0SJames Smart 			"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
395107bcd98eSJames Smart 			datqp->queue_id, datqp->entry_count,
395207bcd98eSJames Smart 			datqp->entry_size, datqp->host_index,
395332517fc0SJames Smart 			datqp->hba_index, datqp->notify_interval);
395407bcd98eSJames Smart 	return len;
395507bcd98eSJames Smart }
395607bcd98eSJames Smart 
395707bcd98eSJames Smart static int
lpfc_idiag_cqs_for_eq(struct lpfc_hba * phba,char * pbuffer,int * len,int max_cnt,int eqidx,int eq_id)395807bcd98eSJames Smart lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer,
39592d7dbc4cSJames Smart 		int *len, int max_cnt, int eqidx, int eq_id)
396007bcd98eSJames Smart {
396107bcd98eSJames Smart 	struct lpfc_queue *qp;
39626a828b0fSJames Smart 	int rc;
396307bcd98eSJames Smart 
3964c00f62e6SJames Smart 	qp = phba->sli4_hba.hdwq[eqidx].io_cq;
396507bcd98eSJames Smart 
3966c00f62e6SJames Smart 	*len = __lpfc_idiag_print_cq(qp, "IO", pbuffer, *len);
396707bcd98eSJames Smart 
396807bcd98eSJames Smart 	/* Reset max counter */
396907bcd98eSJames Smart 	qp->CQ_max_cqe = 0;
397007bcd98eSJames Smart 
397107bcd98eSJames Smart 	if (*len >= max_cnt)
397207bcd98eSJames Smart 		return 1;
397307bcd98eSJames Smart 
3974c00f62e6SJames Smart 	rc = lpfc_idiag_wqs_for_cq(phba, "IO", pbuffer, len,
397507bcd98eSJames Smart 				   max_cnt, qp->queue_id);
397607bcd98eSJames Smart 	if (rc)
397707bcd98eSJames Smart 		return 1;
397807bcd98eSJames Smart 
3979bcb24f65SJames Smart 	if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) {
39802d7dbc4cSJames Smart 		/* NVMET CQset */
39812d7dbc4cSJames Smart 		qp = phba->sli4_hba.nvmet_cqset[eqidx];
39822d7dbc4cSJames Smart 		*len = __lpfc_idiag_print_cq(qp, "NVMET CQset", pbuffer, *len);
39832d7dbc4cSJames Smart 
39842d7dbc4cSJames Smart 		/* Reset max counter */
39852d7dbc4cSJames Smart 		qp->CQ_max_cqe = 0;
39862d7dbc4cSJames Smart 
39872d7dbc4cSJames Smart 		if (*len >= max_cnt)
39882d7dbc4cSJames Smart 			return 1;
39892d7dbc4cSJames Smart 
39902d7dbc4cSJames Smart 		/* RQ header */
39912d7dbc4cSJames Smart 		qp = phba->sli4_hba.nvmet_mrq_hdr[eqidx];
39922d7dbc4cSJames Smart 		*len = __lpfc_idiag_print_rqpair(qp,
39932d7dbc4cSJames Smart 				phba->sli4_hba.nvmet_mrq_data[eqidx],
39942d7dbc4cSJames Smart 				"NVMET MRQ", pbuffer, *len);
39952d7dbc4cSJames Smart 
39962d7dbc4cSJames Smart 		if (*len >= max_cnt)
39972d7dbc4cSJames Smart 			return 1;
39982d7dbc4cSJames Smart 	}
39992d7dbc4cSJames Smart 
400007bcd98eSJames Smart 	return 0;
400107bcd98eSJames Smart }
400207bcd98eSJames Smart 
400307bcd98eSJames Smart static int
__lpfc_idiag_print_eq(struct lpfc_queue * qp,char * eqtype,char * pbuffer,int len)400407bcd98eSJames Smart __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype,
400507bcd98eSJames Smart 			char *pbuffer, int len)
400607bcd98eSJames Smart {
400707bcd98eSJames Smart 	if (!qp)
400807bcd98eSJames Smart 		return len;
400907bcd98eSJames Smart 
4010e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
401107bcd98eSJames Smart 			"\n%s EQ info: EQ-STAT[max:x%x noE:x%x "
401207d494f7SJames Smart 			"cqe_proc:x%x eqe_proc:x%llx eqd %d]\n",
401307bcd98eSJames Smart 			eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3,
40140cf07f84SJames Smart 			(unsigned long long)qp->q_cnt_4, qp->q_mode);
4015e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
40167869da18SJames Smart 			"EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
401732517fc0SJames Smart 			"HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]",
401807bcd98eSJames Smart 			qp->queue_id, qp->entry_count, qp->entry_size,
401932517fc0SJames Smart 			qp->host_index, qp->notify_interval,
402032517fc0SJames Smart 			qp->max_proc_limit, qp->chann);
4021e7f7b6f3SSilvio Cesare 	len +=  scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
4022e7f7b6f3SSilvio Cesare 			"\n");
402307bcd98eSJames Smart 
402407bcd98eSJames Smart 	return len;
402507bcd98eSJames Smart }
402607bcd98eSJames Smart 
4027b76f2dc9SJames Smart /**
40282a622bfbSJames Smart  * lpfc_idiag_queinfo_read - idiag debugfs read queue information
40292a622bfbSJames Smart  * @file: The file pointer to read from.
40302a622bfbSJames Smart  * @buf: The buffer to copy the data to.
40312a622bfbSJames Smart  * @nbytes: The number of bytes to read.
40322a622bfbSJames Smart  * @ppos: The position in the file to start reading from.
40332a622bfbSJames Smart  *
40342a622bfbSJames Smart  * Description:
40352a622bfbSJames Smart  * This routine reads data from the @phba SLI4 PCI function queue information,
40362a622bfbSJames Smart  * and copies to user @buf.
403707bcd98eSJames Smart  * This routine only returns 1 EQs worth of information. It remembers the last
403807bcd98eSJames Smart  * EQ read and jumps to the next EQ. Thus subsequent calls to queInfo will
403907bcd98eSJames Smart  * retrieve all EQs allocated for the phba.
40402a622bfbSJames Smart  *
40412a622bfbSJames Smart  * Returns:
40422a622bfbSJames Smart  * This function returns the amount of data that was read (this could be less
40432a622bfbSJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
40442a622bfbSJames Smart  **/
40452a622bfbSJames Smart static ssize_t
lpfc_idiag_queinfo_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)40462a622bfbSJames Smart lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
40472a622bfbSJames Smart 			loff_t *ppos)
40482a622bfbSJames Smart {
40492a622bfbSJames Smart 	struct lpfc_debug *debug = file->private_data;
40502a622bfbSJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
40512a622bfbSJames Smart 	char *pbuffer;
405207bcd98eSJames Smart 	int max_cnt, rc, x, len = 0;
4053c85a65acSJames Smart 	struct lpfc_queue *qp = NULL;
4054c85a65acSJames Smart 
40552a622bfbSJames Smart 	if (!debug->buffer)
40562a622bfbSJames Smart 		debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL);
40572a622bfbSJames Smart 	if (!debug->buffer)
40582a622bfbSJames Smart 		return 0;
40592a622bfbSJames Smart 	pbuffer = debug->buffer;
406007bcd98eSJames Smart 	max_cnt = LPFC_QUE_INFO_GET_BUF_SIZE - 256;
40612a622bfbSJames Smart 
40622a622bfbSJames Smart 	if (*ppos)
40632a622bfbSJames Smart 		return 0;
40642a622bfbSJames Smart 
4065c85a65acSJames Smart 	spin_lock_irq(&phba->hbalock);
4066c85a65acSJames Smart 
4067c85a65acSJames Smart 	/* Fast-path event queue */
4068cdb42becSJames Smart 	if (phba->sli4_hba.hdwq && phba->cfg_hdw_queue) {
4069c85a65acSJames Smart 
407007bcd98eSJames Smart 		x = phba->lpfc_idiag_last_eq;
407107bcd98eSJames Smart 		phba->lpfc_idiag_last_eq++;
4072cdb42becSJames Smart 		if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue)
407307bcd98eSJames Smart 			phba->lpfc_idiag_last_eq = 0;
407407bcd98eSJames Smart 
4075e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer + len,
4076e7f7b6f3SSilvio Cesare 				 LPFC_QUE_INFO_GET_BUF_SIZE - len,
40776a828b0fSJames Smart 				 "HDWQ %d out of %d HBA HDWQs\n",
4078cdb42becSJames Smart 				 x, phba->cfg_hdw_queue);
4079c85a65acSJames Smart 
4080c85a65acSJames Smart 		/* Fast-path EQ */
4081cdb42becSJames Smart 		qp = phba->sli4_hba.hdwq[x].hba_eq;
4082c85a65acSJames Smart 		if (!qp)
408307bcd98eSJames Smart 			goto out;
4084c85a65acSJames Smart 
408507bcd98eSJames Smart 		len = __lpfc_idiag_print_eq(qp, "HBA", pbuffer, len);
4086c85a65acSJames Smart 
4087c85a65acSJames Smart 		/* Reset max counter */
4088c85a65acSJames Smart 		qp->EQ_max_eqe = 0;
4089c85a65acSJames Smart 
4090c85a65acSJames Smart 		if (len >= max_cnt)
4091c85a65acSJames Smart 			goto too_big;
4092c85a65acSJames Smart 
4093895427bdSJames Smart 		/* will dump both fcp and nvme cqs/wqs for the eq */
409407bcd98eSJames Smart 		rc = lpfc_idiag_cqs_for_eq(phba, pbuffer, &len,
40952d7dbc4cSJames Smart 			max_cnt, x, qp->queue_id);
409607bcd98eSJames Smart 		if (rc)
4097c85a65acSJames Smart 			goto too_big;
4098c85a65acSJames Smart 
4099c85a65acSJames Smart 		/* Only EQ 0 has slow path CQs configured */
410007bcd98eSJames Smart 		if (x)
410107bcd98eSJames Smart 			goto out;
4102c85a65acSJames Smart 
4103c85a65acSJames Smart 		/* Slow-path mailbox CQ */
4104c85a65acSJames Smart 		qp = phba->sli4_hba.mbx_cq;
410507bcd98eSJames Smart 		len = __lpfc_idiag_print_cq(qp, "MBX", pbuffer, len);
4106c85a65acSJames Smart 		if (len >= max_cnt)
4107c85a65acSJames Smart 			goto too_big;
4108c85a65acSJames Smart 
4109c85a65acSJames Smart 		/* Slow-path MBOX MQ */
4110c85a65acSJames Smart 		qp = phba->sli4_hba.mbx_wq;
411107bcd98eSJames Smart 		len = __lpfc_idiag_print_wq(qp, "MBX", pbuffer, len);
4112c85a65acSJames Smart 		if (len >= max_cnt)
4113c85a65acSJames Smart 			goto too_big;
4114c85a65acSJames Smart 
4115c85a65acSJames Smart 		/* Slow-path ELS response CQ */
4116c85a65acSJames Smart 		qp = phba->sli4_hba.els_cq;
411707bcd98eSJames Smart 		len = __lpfc_idiag_print_cq(qp, "ELS", pbuffer, len);
4118c85a65acSJames Smart 		/* Reset max counter */
411907bcd98eSJames Smart 		if (qp)
4120c85a65acSJames Smart 			qp->CQ_max_cqe = 0;
4121c85a65acSJames Smart 		if (len >= max_cnt)
4122c85a65acSJames Smart 			goto too_big;
4123c85a65acSJames Smart 
4124c85a65acSJames Smart 		/* Slow-path ELS WQ */
4125c85a65acSJames Smart 		qp = phba->sli4_hba.els_wq;
412607bcd98eSJames Smart 		len = __lpfc_idiag_print_wq(qp, "ELS", pbuffer, len);
4127c85a65acSJames Smart 		if (len >= max_cnt)
4128c85a65acSJames Smart 			goto too_big;
4129c85a65acSJames Smart 
413007d494f7SJames Smart 		qp = phba->sli4_hba.hdr_rq;
413107d494f7SJames Smart 		len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq,
413207d494f7SJames Smart 						"ELS RQpair", pbuffer, len);
413307d494f7SJames Smart 		if (len >= max_cnt)
413407d494f7SJames Smart 			goto too_big;
413507d494f7SJames Smart 
4136895427bdSJames Smart 		/* Slow-path NVME LS response CQ */
4137895427bdSJames Smart 		qp = phba->sli4_hba.nvmels_cq;
4138895427bdSJames Smart 		len = __lpfc_idiag_print_cq(qp, "NVME LS",
4139895427bdSJames Smart 						pbuffer, len);
4140895427bdSJames Smart 		/* Reset max counter */
4141895427bdSJames Smart 		if (qp)
4142895427bdSJames Smart 			qp->CQ_max_cqe = 0;
4143895427bdSJames Smart 		if (len >= max_cnt)
4144895427bdSJames Smart 			goto too_big;
4145895427bdSJames Smart 
4146895427bdSJames Smart 		/* Slow-path NVME LS WQ */
4147895427bdSJames Smart 		qp = phba->sli4_hba.nvmels_wq;
4148895427bdSJames Smart 		len = __lpfc_idiag_print_wq(qp, "NVME LS",
4149895427bdSJames Smart 						pbuffer, len);
4150895427bdSJames Smart 		if (len >= max_cnt)
4151895427bdSJames Smart 			goto too_big;
4152895427bdSJames Smart 
415307bcd98eSJames Smart 		goto out;
4154c85a65acSJames Smart 	}
4155c85a65acSJames Smart 
4156c85a65acSJames Smart 	spin_unlock_irq(&phba->hbalock);
4157c85a65acSJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4158c85a65acSJames Smart 
4159c85a65acSJames Smart too_big:
4160e7f7b6f3SSilvio Cesare 	len +=  scnprintf(pbuffer + len,
4161c85a65acSJames Smart 		LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n");
416207bcd98eSJames Smart out:
4163c85a65acSJames Smart 	spin_unlock_irq(&phba->hbalock);
41642a622bfbSJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
41652a622bfbSJames Smart }
41662a622bfbSJames Smart 
416786a80846SJames Smart /**
416886a80846SJames Smart  * lpfc_idiag_que_param_check - queue access command parameter sanity check
416986a80846SJames Smart  * @q: The pointer to queue structure.
417086a80846SJames Smart  * @index: The index into a queue entry.
417186a80846SJames Smart  * @count: The number of queue entries to access.
417286a80846SJames Smart  *
417386a80846SJames Smart  * Description:
417486a80846SJames Smart  * The routine performs sanity check on device queue access method commands.
417586a80846SJames Smart  *
417686a80846SJames Smart  * Returns:
417786a80846SJames Smart  * This function returns -EINVAL when fails the sanity check, otherwise, it
417886a80846SJames Smart  * returns 0.
417986a80846SJames Smart  **/
418086a80846SJames Smart static int
lpfc_idiag_que_param_check(struct lpfc_queue * q,int index,int count)418186a80846SJames Smart lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count)
418286a80846SJames Smart {
418386a80846SJames Smart 	/* Only support single entry read or browsing */
418486a80846SJames Smart 	if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE))
418586a80846SJames Smart 		return -EINVAL;
418686a80846SJames Smart 	if (index > q->entry_count - 1)
418786a80846SJames Smart 		return -EINVAL;
418886a80846SJames Smart 	return 0;
418986a80846SJames Smart }
419086a80846SJames Smart 
419186a80846SJames Smart /**
419286a80846SJames Smart  * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index
419386a80846SJames Smart  * @pbuffer: The pointer to buffer to copy the read data into.
4194e61e0740SLee Jones  * @len: Length of the buffer.
419586a80846SJames Smart  * @pque: The pointer to the queue to be read.
419686a80846SJames Smart  * @index: The index into the queue entry.
419786a80846SJames Smart  *
419886a80846SJames Smart  * Description:
419986a80846SJames Smart  * This routine reads out a single entry from the given queue's index location
420086a80846SJames Smart  * and copies it into the buffer provided.
420186a80846SJames Smart  *
420286a80846SJames Smart  * Returns:
420386a80846SJames Smart  * This function returns 0 when it fails, otherwise, it returns the length of
420486a80846SJames Smart  * the data read into the buffer provided.
420586a80846SJames Smart  **/
420686a80846SJames Smart static int
lpfc_idiag_queacc_read_qe(char * pbuffer,int len,struct lpfc_queue * pque,uint32_t index)420786a80846SJames Smart lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque,
420886a80846SJames Smart 			  uint32_t index)
420986a80846SJames Smart {
421086a80846SJames Smart 	int offset, esize;
421186a80846SJames Smart 	uint32_t *pentry;
421286a80846SJames Smart 
421386a80846SJames Smart 	if (!pbuffer || !pque)
421486a80846SJames Smart 		return 0;
421586a80846SJames Smart 
421686a80846SJames Smart 	esize = pque->entry_size;
4217e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
421886a80846SJames Smart 			"QE-INDEX[%04d]:\n", index);
421986a80846SJames Smart 
422086a80846SJames Smart 	offset = 0;
42219afbee3dSJames Smart 	pentry = lpfc_sli4_qe(pque, index);
422286a80846SJames Smart 	while (esize > 0) {
4223e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
422486a80846SJames Smart 				"%08x ", *pentry);
422586a80846SJames Smart 		pentry++;
422686a80846SJames Smart 		offset += sizeof(uint32_t);
422786a80846SJames Smart 		esize -= sizeof(uint32_t);
422886a80846SJames Smart 		if (esize > 0 && !(offset % (4 * sizeof(uint32_t))))
4229e7f7b6f3SSilvio Cesare 			len += scnprintf(pbuffer+len,
423086a80846SJames Smart 					LPFC_QUE_ACC_BUF_SIZE-len, "\n");
423186a80846SJames Smart 	}
4232e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n");
423386a80846SJames Smart 
423486a80846SJames Smart 	return len;
423586a80846SJames Smart }
423686a80846SJames Smart 
423786a80846SJames Smart /**
423886a80846SJames Smart  * lpfc_idiag_queacc_read - idiag debugfs read port queue
423986a80846SJames Smart  * @file: The file pointer to read from.
424086a80846SJames Smart  * @buf: The buffer to copy the data to.
424186a80846SJames Smart  * @nbytes: The number of bytes to read.
424286a80846SJames Smart  * @ppos: The position in the file to start reading from.
424386a80846SJames Smart  *
424486a80846SJames Smart  * Description:
424586a80846SJames Smart  * This routine reads data from the @phba device queue memory according to the
424686a80846SJames Smart  * idiag command, and copies to user @buf. Depending on the queue dump read
424786a80846SJames Smart  * command setup, it does either a single queue entry read or browing through
424886a80846SJames Smart  * all entries of the queue.
424986a80846SJames Smart  *
425086a80846SJames Smart  * Returns:
425186a80846SJames Smart  * This function returns the amount of data that was read (this could be less
425286a80846SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
425386a80846SJames Smart  **/
425486a80846SJames Smart static ssize_t
lpfc_idiag_queacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)425586a80846SJames Smart lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,
425686a80846SJames Smart 		       loff_t *ppos)
425786a80846SJames Smart {
425886a80846SJames Smart 	struct lpfc_debug *debug = file->private_data;
425986a80846SJames Smart 	uint32_t last_index, index, count;
426086a80846SJames Smart 	struct lpfc_queue *pque = NULL;
426186a80846SJames Smart 	char *pbuffer;
426286a80846SJames Smart 	int len = 0;
426386a80846SJames Smart 
426486a80846SJames Smart 	/* This is a user read operation */
426586a80846SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
426686a80846SJames Smart 
426786a80846SJames Smart 	if (!debug->buffer)
426886a80846SJames Smart 		debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL);
426986a80846SJames Smart 	if (!debug->buffer)
427086a80846SJames Smart 		return 0;
427186a80846SJames Smart 	pbuffer = debug->buffer;
427286a80846SJames Smart 
427386a80846SJames Smart 	if (*ppos)
427486a80846SJames Smart 		return 0;
427586a80846SJames Smart 
427686a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
4277b76f2dc9SJames Smart 		index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
4278b76f2dc9SJames Smart 		count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
427986a80846SJames Smart 		pque = (struct lpfc_queue *)idiag.ptr_private;
428086a80846SJames Smart 	} else
428186a80846SJames Smart 		return 0;
428286a80846SJames Smart 
428386a80846SJames Smart 	/* Browse the queue starting from index */
428486a80846SJames Smart 	if (count == LPFC_QUE_ACC_BROWSE)
428586a80846SJames Smart 		goto que_browse;
428686a80846SJames Smart 
428786a80846SJames Smart 	/* Read a single entry from the queue */
428886a80846SJames Smart 	len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
428986a80846SJames Smart 
429086a80846SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
429186a80846SJames Smart 
429286a80846SJames Smart que_browse:
429386a80846SJames Smart 
429486a80846SJames Smart 	/* Browse all entries from the queue */
429586a80846SJames Smart 	last_index = idiag.offset.last_rd;
429686a80846SJames Smart 	index = last_index;
429786a80846SJames Smart 
429886a80846SJames Smart 	while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) {
429986a80846SJames Smart 		len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index);
430086a80846SJames Smart 		index++;
430186a80846SJames Smart 		if (index > pque->entry_count - 1)
430286a80846SJames Smart 			break;
430386a80846SJames Smart 	}
430486a80846SJames Smart 
430586a80846SJames Smart 	/* Set up the offset for next portion of pci cfg read */
430686a80846SJames Smart 	if (index > pque->entry_count - 1)
430786a80846SJames Smart 		index = 0;
430886a80846SJames Smart 	idiag.offset.last_rd = index;
430986a80846SJames Smart 
431086a80846SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
431186a80846SJames Smart }
431286a80846SJames Smart 
431386a80846SJames Smart /**
431486a80846SJames Smart  * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands
431586a80846SJames Smart  * @file: The file pointer to read from.
431686a80846SJames Smart  * @buf: The buffer to copy the user data from.
431786a80846SJames Smart  * @nbytes: The number of bytes to get.
431886a80846SJames Smart  * @ppos: The position in the file to start reading from.
431986a80846SJames Smart  *
432086a80846SJames Smart  * This routine get the debugfs idiag command struct from user space and then
432186a80846SJames Smart  * perform the syntax check for port queue read (dump) or write (set) command
432286a80846SJames Smart  * accordingly. In the case of port queue read command, it sets up the command
432386a80846SJames Smart  * in the idiag command struct for the following debugfs read operation. In
432486a80846SJames Smart  * the case of port queue write operation, it executes the write operation
432586a80846SJames Smart  * into the port queue entry accordingly.
432686a80846SJames Smart  *
432786a80846SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
432886a80846SJames Smart  * In case of error conditions, it returns proper error code back to the user
432986a80846SJames Smart  * space.
433086a80846SJames Smart  **/
433186a80846SJames Smart static ssize_t
lpfc_idiag_queacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)433286a80846SJames Smart lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
433386a80846SJames Smart 			size_t nbytes, loff_t *ppos)
433486a80846SJames Smart {
433586a80846SJames Smart 	struct lpfc_debug *debug = file->private_data;
433686a80846SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
433786a80846SJames Smart 	uint32_t qidx, quetp, queid, index, count, offset, value;
433886a80846SJames Smart 	uint32_t *pentry;
4339895427bdSJames Smart 	struct lpfc_queue *pque, *qp;
434086a80846SJames Smart 	int rc;
434186a80846SJames Smart 
434286a80846SJames Smart 	/* This is a user write operation */
434386a80846SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
434486a80846SJames Smart 
434586a80846SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
434686a80846SJames Smart 	if (rc < 0)
434786a80846SJames Smart 		return rc;
434886a80846SJames Smart 
434986a80846SJames Smart 	/* Get and sanity check on command feilds */
4350b76f2dc9SJames Smart 	quetp  = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX];
4351b76f2dc9SJames Smart 	queid  = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX];
4352b76f2dc9SJames Smart 	index  = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
4353b76f2dc9SJames Smart 	count  = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
4354b76f2dc9SJames Smart 	offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX];
4355b76f2dc9SJames Smart 	value  = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];
435686a80846SJames Smart 
435786a80846SJames Smart 	/* Sanity check on command line arguments */
435886a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
435986a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
436086a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
436186a80846SJames Smart 		if (rc != LPFC_QUE_ACC_WR_CMD_ARG)
436286a80846SJames Smart 			goto error_out;
436386a80846SJames Smart 		if (count != 1)
436486a80846SJames Smart 			goto error_out;
436586a80846SJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
436686a80846SJames Smart 		if (rc != LPFC_QUE_ACC_RD_CMD_ARG)
436786a80846SJames Smart 			goto error_out;
436886a80846SJames Smart 	} else
436986a80846SJames Smart 		goto error_out;
437086a80846SJames Smart 
437186a80846SJames Smart 	switch (quetp) {
437286a80846SJames Smart 	case LPFC_IDIAG_EQ:
437367d12733SJames Smart 		/* HBA event queue */
4374cdb42becSJames Smart 		if (phba->sli4_hba.hdwq) {
4375cdb42becSJames Smart 			for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
4376cdb42becSJames Smart 				qp = phba->sli4_hba.hdwq[qidx].hba_eq;
4377895427bdSJames Smart 				if (qp && qp->queue_id == queid) {
437886a80846SJames Smart 					/* Sanity check */
4379895427bdSJames Smart 					rc = lpfc_idiag_que_param_check(qp,
438086a80846SJames Smart 						index, count);
438186a80846SJames Smart 					if (rc)
438286a80846SJames Smart 						goto error_out;
4383895427bdSJames Smart 					idiag.ptr_private = qp;
438486a80846SJames Smart 					goto pass_check;
438586a80846SJames Smart 				}
438686a80846SJames Smart 			}
43872e90f4b5SJames Smart 		}
438886a80846SJames Smart 		goto error_out;
4389170b7d2dSTom Rix 
439086a80846SJames Smart 	case LPFC_IDIAG_CQ:
439186a80846SJames Smart 		/* MBX complete queue */
43922e90f4b5SJames Smart 		if (phba->sli4_hba.mbx_cq &&
43932e90f4b5SJames Smart 		    phba->sli4_hba.mbx_cq->queue_id == queid) {
439486a80846SJames Smart 			/* Sanity check */
439586a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
439686a80846SJames Smart 					phba->sli4_hba.mbx_cq, index, count);
439786a80846SJames Smart 			if (rc)
439886a80846SJames Smart 				goto error_out;
439986a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.mbx_cq;
440086a80846SJames Smart 			goto pass_check;
440186a80846SJames Smart 		}
440286a80846SJames Smart 		/* ELS complete queue */
44032e90f4b5SJames Smart 		if (phba->sli4_hba.els_cq &&
44042e90f4b5SJames Smart 		    phba->sli4_hba.els_cq->queue_id == queid) {
440586a80846SJames Smart 			/* Sanity check */
440686a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
440786a80846SJames Smart 					phba->sli4_hba.els_cq, index, count);
440886a80846SJames Smart 			if (rc)
440986a80846SJames Smart 				goto error_out;
441086a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.els_cq;
441186a80846SJames Smart 			goto pass_check;
441286a80846SJames Smart 		}
4413895427bdSJames Smart 		/* NVME LS complete queue */
4414895427bdSJames Smart 		if (phba->sli4_hba.nvmels_cq &&
4415895427bdSJames Smart 		    phba->sli4_hba.nvmels_cq->queue_id == queid) {
441686a80846SJames Smart 			/* Sanity check */
441786a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
4418895427bdSJames Smart 					phba->sli4_hba.nvmels_cq, index, count);
441986a80846SJames Smart 			if (rc)
442086a80846SJames Smart 				goto error_out;
4421895427bdSJames Smart 			idiag.ptr_private = phba->sli4_hba.nvmels_cq;
442286a80846SJames Smart 			goto pass_check;
442386a80846SJames Smart 		}
4424895427bdSJames Smart 		/* FCP complete queue */
4425cdb42becSJames Smart 		if (phba->sli4_hba.hdwq) {
4426cdb42becSJames Smart 			for (qidx = 0; qidx < phba->cfg_hdw_queue;
4427895427bdSJames Smart 								qidx++) {
4428c00f62e6SJames Smart 				qp = phba->sli4_hba.hdwq[qidx].io_cq;
4429895427bdSJames Smart 				if (qp && qp->queue_id == queid) {
4430895427bdSJames Smart 					/* Sanity check */
4431895427bdSJames Smart 					rc = lpfc_idiag_que_param_check(
4432895427bdSJames Smart 						qp, index, count);
4433895427bdSJames Smart 					if (rc)
4434895427bdSJames Smart 						goto error_out;
4435895427bdSJames Smart 					idiag.ptr_private = qp;
4436895427bdSJames Smart 					goto pass_check;
4437895427bdSJames Smart 				}
4438895427bdSJames Smart 			}
44392e90f4b5SJames Smart 		}
444086a80846SJames Smart 		goto error_out;
4441170b7d2dSTom Rix 
444286a80846SJames Smart 	case LPFC_IDIAG_MQ:
444386a80846SJames Smart 		/* MBX work queue */
44442e90f4b5SJames Smart 		if (phba->sli4_hba.mbx_wq &&
44452e90f4b5SJames Smart 		    phba->sli4_hba.mbx_wq->queue_id == queid) {
444686a80846SJames Smart 			/* Sanity check */
444786a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
444886a80846SJames Smart 					phba->sli4_hba.mbx_wq, index, count);
444986a80846SJames Smart 			if (rc)
445086a80846SJames Smart 				goto error_out;
445186a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.mbx_wq;
445286a80846SJames Smart 			goto pass_check;
445386a80846SJames Smart 		}
44542e90f4b5SJames Smart 		goto error_out;
4455170b7d2dSTom Rix 
445686a80846SJames Smart 	case LPFC_IDIAG_WQ:
445786a80846SJames Smart 		/* ELS work queue */
44582e90f4b5SJames Smart 		if (phba->sli4_hba.els_wq &&
44592e90f4b5SJames Smart 		    phba->sli4_hba.els_wq->queue_id == queid) {
446086a80846SJames Smart 			/* Sanity check */
446186a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
446286a80846SJames Smart 					phba->sli4_hba.els_wq, index, count);
446386a80846SJames Smart 			if (rc)
446486a80846SJames Smart 				goto error_out;
446586a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.els_wq;
446686a80846SJames Smart 			goto pass_check;
446786a80846SJames Smart 		}
4468895427bdSJames Smart 		/* NVME LS work queue */
4469895427bdSJames Smart 		if (phba->sli4_hba.nvmels_wq &&
4470895427bdSJames Smart 		    phba->sli4_hba.nvmels_wq->queue_id == queid) {
4471895427bdSJames Smart 			/* Sanity check */
4472895427bdSJames Smart 			rc = lpfc_idiag_que_param_check(
4473895427bdSJames Smart 					phba->sli4_hba.nvmels_wq, index, count);
4474895427bdSJames Smart 			if (rc)
4475895427bdSJames Smart 				goto error_out;
4476895427bdSJames Smart 			idiag.ptr_private = phba->sli4_hba.nvmels_wq;
4477895427bdSJames Smart 			goto pass_check;
4478895427bdSJames Smart 		}
4479cdb42becSJames Smart 
4480cdb42becSJames Smart 		if (phba->sli4_hba.hdwq) {
4481cdb42becSJames Smart 			/* FCP/SCSI work queue */
4482cdb42becSJames Smart 			for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
4483c00f62e6SJames Smart 				qp = phba->sli4_hba.hdwq[qidx].io_wq;
4484895427bdSJames Smart 				if (qp && qp->queue_id == queid) {
4485895427bdSJames Smart 					/* Sanity check */
4486895427bdSJames Smart 					rc = lpfc_idiag_que_param_check(
4487895427bdSJames Smart 						qp, index, count);
4488895427bdSJames Smart 					if (rc)
4489895427bdSJames Smart 						goto error_out;
4490895427bdSJames Smart 					idiag.ptr_private = qp;
449186a80846SJames Smart 					goto pass_check;
449286a80846SJames Smart 				}
449386a80846SJames Smart 			}
44942e90f4b5SJames Smart 		}
449586a80846SJames Smart 		goto error_out;
4496170b7d2dSTom Rix 
449786a80846SJames Smart 	case LPFC_IDIAG_RQ:
449886a80846SJames Smart 		/* HDR queue */
44992e90f4b5SJames Smart 		if (phba->sli4_hba.hdr_rq &&
45002e90f4b5SJames Smart 		    phba->sli4_hba.hdr_rq->queue_id == queid) {
450186a80846SJames Smart 			/* Sanity check */
450286a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
450386a80846SJames Smart 					phba->sli4_hba.hdr_rq, index, count);
450486a80846SJames Smart 			if (rc)
450586a80846SJames Smart 				goto error_out;
450686a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.hdr_rq;
450786a80846SJames Smart 			goto pass_check;
450886a80846SJames Smart 		}
450986a80846SJames Smart 		/* DAT queue */
45102e90f4b5SJames Smart 		if (phba->sli4_hba.dat_rq &&
45112e90f4b5SJames Smart 		    phba->sli4_hba.dat_rq->queue_id == queid) {
451286a80846SJames Smart 			/* Sanity check */
451386a80846SJames Smart 			rc = lpfc_idiag_que_param_check(
451486a80846SJames Smart 					phba->sli4_hba.dat_rq, index, count);
451586a80846SJames Smart 			if (rc)
451686a80846SJames Smart 				goto error_out;
451786a80846SJames Smart 			idiag.ptr_private = phba->sli4_hba.dat_rq;
451886a80846SJames Smart 			goto pass_check;
451986a80846SJames Smart 		}
452086a80846SJames Smart 		goto error_out;
452186a80846SJames Smart 	default:
452286a80846SJames Smart 		goto error_out;
452386a80846SJames Smart 	}
452486a80846SJames Smart 
452586a80846SJames Smart pass_check:
452686a80846SJames Smart 
452786a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
452886a80846SJames Smart 		if (count == LPFC_QUE_ACC_BROWSE)
452986a80846SJames Smart 			idiag.offset.last_rd = index;
453086a80846SJames Smart 	}
453186a80846SJames Smart 
453286a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
453386a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST ||
453486a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) {
453586a80846SJames Smart 		/* Additional sanity checks on write operation */
453686a80846SJames Smart 		pque = (struct lpfc_queue *)idiag.ptr_private;
453786a80846SJames Smart 		if (offset > pque->entry_size/sizeof(uint32_t) - 1)
453886a80846SJames Smart 			goto error_out;
45399afbee3dSJames Smart 		pentry = lpfc_sli4_qe(pque, index);
454086a80846SJames Smart 		pentry += offset;
454186a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR)
454286a80846SJames Smart 			*pentry = value;
454386a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST)
454486a80846SJames Smart 			*pentry |= value;
454586a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL)
454686a80846SJames Smart 			*pentry &= ~value;
454786a80846SJames Smart 	}
454886a80846SJames Smart 	return nbytes;
454986a80846SJames Smart 
455086a80846SJames Smart error_out:
455186a80846SJames Smart 	/* Clean out command structure on command error out */
455286a80846SJames Smart 	memset(&idiag, 0, sizeof(idiag));
455386a80846SJames Smart 	return -EINVAL;
455486a80846SJames Smart }
455586a80846SJames Smart 
455686a80846SJames Smart /**
455786a80846SJames Smart  * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register
455886a80846SJames Smart  * @phba: The pointer to hba structure.
455986a80846SJames Smart  * @pbuffer: The pointer to the buffer to copy the data to.
456092684bfcSMatteo Croce  * @len: The length of bytes to copied.
456186a80846SJames Smart  * @drbregid: The id to doorbell registers.
456286a80846SJames Smart  *
456386a80846SJames Smart  * Description:
456486a80846SJames Smart  * This routine reads a doorbell register and copies its content to the
456586a80846SJames Smart  * user buffer pointed to by @pbuffer.
456686a80846SJames Smart  *
456786a80846SJames Smart  * Returns:
456886a80846SJames Smart  * This function returns the amount of data that was copied into @pbuffer.
456986a80846SJames Smart  **/
457086a80846SJames Smart static int
lpfc_idiag_drbacc_read_reg(struct lpfc_hba * phba,char * pbuffer,int len,uint32_t drbregid)457186a80846SJames Smart lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
457286a80846SJames Smart 			   int len, uint32_t drbregid)
457386a80846SJames Smart {
457486a80846SJames Smart 
457586a80846SJames Smart 	if (!pbuffer)
457686a80846SJames Smart 		return 0;
457786a80846SJames Smart 
457886a80846SJames Smart 	switch (drbregid) {
45799dd35425SJames Smart 	case LPFC_DRB_EQ:
4580e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
45819dd35425SJames Smart 				"EQ-DRB-REG: 0x%08x\n",
45829dd35425SJames Smart 				readl(phba->sli4_hba.EQDBregaddr));
45839dd35425SJames Smart 		break;
45849dd35425SJames Smart 	case LPFC_DRB_CQ:
4585e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
45869dd35425SJames Smart 				"CQ-DRB-REG: 0x%08x\n",
45879dd35425SJames Smart 				readl(phba->sli4_hba.CQDBregaddr));
458886a80846SJames Smart 		break;
458986a80846SJames Smart 	case LPFC_DRB_MQ:
4590e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
459186a80846SJames Smart 				"MQ-DRB-REG:   0x%08x\n",
459286a80846SJames Smart 				readl(phba->sli4_hba.MQDBregaddr));
459386a80846SJames Smart 		break;
459486a80846SJames Smart 	case LPFC_DRB_WQ:
4595e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
459686a80846SJames Smart 				"WQ-DRB-REG:   0x%08x\n",
459786a80846SJames Smart 				readl(phba->sli4_hba.WQDBregaddr));
459886a80846SJames Smart 		break;
459986a80846SJames Smart 	case LPFC_DRB_RQ:
4600e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
460186a80846SJames Smart 				"RQ-DRB-REG:   0x%08x\n",
460286a80846SJames Smart 				readl(phba->sli4_hba.RQDBregaddr));
460386a80846SJames Smart 		break;
460486a80846SJames Smart 	default:
460586a80846SJames Smart 		break;
460686a80846SJames Smart 	}
460786a80846SJames Smart 
460886a80846SJames Smart 	return len;
460986a80846SJames Smart }
461086a80846SJames Smart 
461186a80846SJames Smart /**
461286a80846SJames Smart  * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell
461386a80846SJames Smart  * @file: The file pointer to read from.
461486a80846SJames Smart  * @buf: The buffer to copy the data to.
461586a80846SJames Smart  * @nbytes: The number of bytes to read.
461686a80846SJames Smart  * @ppos: The position in the file to start reading from.
461786a80846SJames Smart  *
461886a80846SJames Smart  * Description:
461986a80846SJames Smart  * This routine reads data from the @phba device doorbell register according
462086a80846SJames Smart  * to the idiag command, and copies to user @buf. Depending on the doorbell
462186a80846SJames Smart  * register read command setup, it does either a single doorbell register
462286a80846SJames Smart  * read or dump all doorbell registers.
462386a80846SJames Smart  *
462486a80846SJames Smart  * Returns:
462586a80846SJames Smart  * This function returns the amount of data that was read (this could be less
462686a80846SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
462786a80846SJames Smart  **/
462886a80846SJames Smart static ssize_t
lpfc_idiag_drbacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)462986a80846SJames Smart lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,
463086a80846SJames Smart 		       loff_t *ppos)
463186a80846SJames Smart {
463286a80846SJames Smart 	struct lpfc_debug *debug = file->private_data;
463386a80846SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
463486a80846SJames Smart 	uint32_t drb_reg_id, i;
463586a80846SJames Smart 	char *pbuffer;
463686a80846SJames Smart 	int len = 0;
463786a80846SJames Smart 
463886a80846SJames Smart 	/* This is a user read operation */
463986a80846SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
464086a80846SJames Smart 
464186a80846SJames Smart 	if (!debug->buffer)
464286a80846SJames Smart 		debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL);
464386a80846SJames Smart 	if (!debug->buffer)
464486a80846SJames Smart 		return 0;
464586a80846SJames Smart 	pbuffer = debug->buffer;
464686a80846SJames Smart 
464786a80846SJames Smart 	if (*ppos)
464886a80846SJames Smart 		return 0;
464986a80846SJames Smart 
465086a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD)
4651b76f2dc9SJames Smart 		drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
465286a80846SJames Smart 	else
465386a80846SJames Smart 		return 0;
465486a80846SJames Smart 
465586a80846SJames Smart 	if (drb_reg_id == LPFC_DRB_ACC_ALL)
465686a80846SJames Smart 		for (i = 1; i <= LPFC_DRB_MAX; i++)
465786a80846SJames Smart 			len = lpfc_idiag_drbacc_read_reg(phba,
465886a80846SJames Smart 							 pbuffer, len, i);
465986a80846SJames Smart 	else
466086a80846SJames Smart 		len = lpfc_idiag_drbacc_read_reg(phba,
466186a80846SJames Smart 						 pbuffer, len, drb_reg_id);
466286a80846SJames Smart 
466386a80846SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
466486a80846SJames Smart }
466586a80846SJames Smart 
466686a80846SJames Smart /**
466786a80846SJames Smart  * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands
466886a80846SJames Smart  * @file: The file pointer to read from.
466986a80846SJames Smart  * @buf: The buffer to copy the user data from.
467086a80846SJames Smart  * @nbytes: The number of bytes to get.
467186a80846SJames Smart  * @ppos: The position in the file to start reading from.
467286a80846SJames Smart  *
467386a80846SJames Smart  * This routine get the debugfs idiag command struct from user space and then
467486a80846SJames Smart  * perform the syntax check for port doorbell register read (dump) or write
467586a80846SJames Smart  * (set) command accordingly. In the case of port queue read command, it sets
467686a80846SJames Smart  * up the command in the idiag command struct for the following debugfs read
467786a80846SJames Smart  * operation. In the case of port doorbell register write operation, it
467886a80846SJames Smart  * executes the write operation into the port doorbell register accordingly.
467986a80846SJames Smart  *
468086a80846SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
468186a80846SJames Smart  * In case of error conditions, it returns proper error code back to the user
468286a80846SJames Smart  * space.
468386a80846SJames Smart  **/
468486a80846SJames Smart static ssize_t
lpfc_idiag_drbacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)468586a80846SJames Smart lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
468686a80846SJames Smart 			size_t nbytes, loff_t *ppos)
468786a80846SJames Smart {
468886a80846SJames Smart 	struct lpfc_debug *debug = file->private_data;
468986a80846SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4690b76f2dc9SJames Smart 	uint32_t drb_reg_id, value, reg_val = 0;
469186a80846SJames Smart 	void __iomem *drb_reg;
469286a80846SJames Smart 	int rc;
469386a80846SJames Smart 
469486a80846SJames Smart 	/* This is a user write operation */
469586a80846SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
469686a80846SJames Smart 
469786a80846SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
469886a80846SJames Smart 	if (rc < 0)
469986a80846SJames Smart 		return rc;
470086a80846SJames Smart 
470186a80846SJames Smart 	/* Sanity check on command line arguments */
4702b76f2dc9SJames Smart 	drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
4703b76f2dc9SJames Smart 	value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];
470486a80846SJames Smart 
470586a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
470686a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
470786a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
470886a80846SJames Smart 		if (rc != LPFC_DRB_ACC_WR_CMD_ARG)
470986a80846SJames Smart 			goto error_out;
471086a80846SJames Smart 		if (drb_reg_id > LPFC_DRB_MAX)
471186a80846SJames Smart 			goto error_out;
471286a80846SJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) {
471386a80846SJames Smart 		if (rc != LPFC_DRB_ACC_RD_CMD_ARG)
471486a80846SJames Smart 			goto error_out;
471586a80846SJames Smart 		if ((drb_reg_id > LPFC_DRB_MAX) &&
471686a80846SJames Smart 		    (drb_reg_id != LPFC_DRB_ACC_ALL))
471786a80846SJames Smart 			goto error_out;
471886a80846SJames Smart 	} else
471986a80846SJames Smart 		goto error_out;
472086a80846SJames Smart 
472186a80846SJames Smart 	/* Perform the write access operation */
472286a80846SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
472386a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
472486a80846SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
472586a80846SJames Smart 		switch (drb_reg_id) {
47269dd35425SJames Smart 		case LPFC_DRB_EQ:
47279dd35425SJames Smart 			drb_reg = phba->sli4_hba.EQDBregaddr;
47289dd35425SJames Smart 			break;
47299dd35425SJames Smart 		case LPFC_DRB_CQ:
47309dd35425SJames Smart 			drb_reg = phba->sli4_hba.CQDBregaddr;
473186a80846SJames Smart 			break;
473286a80846SJames Smart 		case LPFC_DRB_MQ:
473386a80846SJames Smart 			drb_reg = phba->sli4_hba.MQDBregaddr;
473486a80846SJames Smart 			break;
473586a80846SJames Smart 		case LPFC_DRB_WQ:
473686a80846SJames Smart 			drb_reg = phba->sli4_hba.WQDBregaddr;
473786a80846SJames Smart 			break;
473886a80846SJames Smart 		case LPFC_DRB_RQ:
473986a80846SJames Smart 			drb_reg = phba->sli4_hba.RQDBregaddr;
474086a80846SJames Smart 			break;
474186a80846SJames Smart 		default:
474286a80846SJames Smart 			goto error_out;
474386a80846SJames Smart 		}
474486a80846SJames Smart 
474586a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR)
474686a80846SJames Smart 			reg_val = value;
474786a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) {
474886a80846SJames Smart 			reg_val = readl(drb_reg);
474986a80846SJames Smart 			reg_val |= value;
475086a80846SJames Smart 		}
475186a80846SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
475286a80846SJames Smart 			reg_val = readl(drb_reg);
475386a80846SJames Smart 			reg_val &= ~value;
475486a80846SJames Smart 		}
475586a80846SJames Smart 		writel(reg_val, drb_reg);
475686a80846SJames Smart 		readl(drb_reg); /* flush */
475786a80846SJames Smart 	}
475886a80846SJames Smart 	return nbytes;
475986a80846SJames Smart 
476086a80846SJames Smart error_out:
476186a80846SJames Smart 	/* Clean out command structure on command error out */
476286a80846SJames Smart 	memset(&idiag, 0, sizeof(idiag));
476386a80846SJames Smart 	return -EINVAL;
476486a80846SJames Smart }
476586a80846SJames Smart 
4766b76f2dc9SJames Smart /**
4767b76f2dc9SJames Smart  * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
4768b76f2dc9SJames Smart  * @phba: The pointer to hba structure.
4769b76f2dc9SJames Smart  * @pbuffer: The pointer to the buffer to copy the data to.
477092684bfcSMatteo Croce  * @len: The length of bytes to copied.
4771e61e0740SLee Jones  * @ctlregid: The id to doorbell registers.
4772b76f2dc9SJames Smart  *
4773b76f2dc9SJames Smart  * Description:
4774b76f2dc9SJames Smart  * This routine reads a control register and copies its content to the
4775b76f2dc9SJames Smart  * user buffer pointed to by @pbuffer.
4776b76f2dc9SJames Smart  *
4777b76f2dc9SJames Smart  * Returns:
4778b76f2dc9SJames Smart  * This function returns the amount of data that was copied into @pbuffer.
4779b76f2dc9SJames Smart  **/
4780b76f2dc9SJames Smart static int
lpfc_idiag_ctlacc_read_reg(struct lpfc_hba * phba,char * pbuffer,int len,uint32_t ctlregid)4781b76f2dc9SJames Smart lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
4782b76f2dc9SJames Smart 			   int len, uint32_t ctlregid)
4783b76f2dc9SJames Smart {
4784b76f2dc9SJames Smart 
4785b76f2dc9SJames Smart 	if (!pbuffer)
4786b76f2dc9SJames Smart 		return 0;
4787b76f2dc9SJames Smart 
4788b76f2dc9SJames Smart 	switch (ctlregid) {
4789b76f2dc9SJames Smart 	case LPFC_CTL_PORT_SEM:
4790e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4791b76f2dc9SJames Smart 				"Port SemReg:   0x%08x\n",
4792b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4793b76f2dc9SJames Smart 				      LPFC_CTL_PORT_SEM_OFFSET));
4794b76f2dc9SJames Smart 		break;
4795b76f2dc9SJames Smart 	case LPFC_CTL_PORT_STA:
4796e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4797b76f2dc9SJames Smart 				"Port StaReg:   0x%08x\n",
4798b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4799b76f2dc9SJames Smart 				      LPFC_CTL_PORT_STA_OFFSET));
4800b76f2dc9SJames Smart 		break;
4801b76f2dc9SJames Smart 	case LPFC_CTL_PORT_CTL:
4802e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4803b76f2dc9SJames Smart 				"Port CtlReg:   0x%08x\n",
4804b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4805b76f2dc9SJames Smart 				      LPFC_CTL_PORT_CTL_OFFSET));
4806b76f2dc9SJames Smart 		break;
4807b76f2dc9SJames Smart 	case LPFC_CTL_PORT_ER1:
4808e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4809b76f2dc9SJames Smart 				"Port Er1Reg:   0x%08x\n",
4810b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4811b76f2dc9SJames Smart 				      LPFC_CTL_PORT_ER1_OFFSET));
4812b76f2dc9SJames Smart 		break;
4813b76f2dc9SJames Smart 	case LPFC_CTL_PORT_ER2:
4814e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4815b76f2dc9SJames Smart 				"Port Er2Reg:   0x%08x\n",
4816b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4817b76f2dc9SJames Smart 				      LPFC_CTL_PORT_ER2_OFFSET));
4818b76f2dc9SJames Smart 		break;
4819b76f2dc9SJames Smart 	case LPFC_CTL_PDEV_CTL:
4820e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
4821b76f2dc9SJames Smart 				"PDev CtlReg:   0x%08x\n",
4822b76f2dc9SJames Smart 				readl(phba->sli4_hba.conf_regs_memmap_p +
4823b76f2dc9SJames Smart 				      LPFC_CTL_PDEV_CTL_OFFSET));
4824b76f2dc9SJames Smart 		break;
4825b76f2dc9SJames Smart 	default:
4826b76f2dc9SJames Smart 		break;
4827b76f2dc9SJames Smart 	}
4828b76f2dc9SJames Smart 	return len;
4829b76f2dc9SJames Smart }
4830b76f2dc9SJames Smart 
4831b76f2dc9SJames Smart /**
4832b76f2dc9SJames Smart  * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register
4833b76f2dc9SJames Smart  * @file: The file pointer to read from.
4834b76f2dc9SJames Smart  * @buf: The buffer to copy the data to.
4835b76f2dc9SJames Smart  * @nbytes: The number of bytes to read.
4836b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
4837b76f2dc9SJames Smart  *
4838b76f2dc9SJames Smart  * Description:
4839b76f2dc9SJames Smart  * This routine reads data from the @phba port and device registers according
4840b76f2dc9SJames Smart  * to the idiag command, and copies to user @buf.
4841b76f2dc9SJames Smart  *
4842b76f2dc9SJames Smart  * Returns:
4843b76f2dc9SJames Smart  * This function returns the amount of data that was read (this could be less
4844b76f2dc9SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
4845b76f2dc9SJames Smart  **/
4846b76f2dc9SJames Smart static ssize_t
lpfc_idiag_ctlacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)4847b76f2dc9SJames Smart lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes,
4848b76f2dc9SJames Smart 		       loff_t *ppos)
4849b76f2dc9SJames Smart {
4850b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
4851b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4852b76f2dc9SJames Smart 	uint32_t ctl_reg_id, i;
4853b76f2dc9SJames Smart 	char *pbuffer;
4854b76f2dc9SJames Smart 	int len = 0;
4855b76f2dc9SJames Smart 
4856b76f2dc9SJames Smart 	/* This is a user read operation */
4857b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
4858b76f2dc9SJames Smart 
4859b76f2dc9SJames Smart 	if (!debug->buffer)
4860b76f2dc9SJames Smart 		debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL);
4861b76f2dc9SJames Smart 	if (!debug->buffer)
4862b76f2dc9SJames Smart 		return 0;
4863b76f2dc9SJames Smart 	pbuffer = debug->buffer;
4864b76f2dc9SJames Smart 
4865b76f2dc9SJames Smart 	if (*ppos)
4866b76f2dc9SJames Smart 		return 0;
4867b76f2dc9SJames Smart 
4868b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD)
4869b76f2dc9SJames Smart 		ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
4870b76f2dc9SJames Smart 	else
4871b76f2dc9SJames Smart 		return 0;
4872b76f2dc9SJames Smart 
4873b76f2dc9SJames Smart 	if (ctl_reg_id == LPFC_CTL_ACC_ALL)
4874b76f2dc9SJames Smart 		for (i = 1; i <= LPFC_CTL_MAX; i++)
4875b76f2dc9SJames Smart 			len = lpfc_idiag_ctlacc_read_reg(phba,
4876b76f2dc9SJames Smart 							 pbuffer, len, i);
4877b76f2dc9SJames Smart 	else
4878b76f2dc9SJames Smart 		len = lpfc_idiag_ctlacc_read_reg(phba,
4879b76f2dc9SJames Smart 						 pbuffer, len, ctl_reg_id);
4880b76f2dc9SJames Smart 
4881b76f2dc9SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
4882b76f2dc9SJames Smart }
4883b76f2dc9SJames Smart 
4884b76f2dc9SJames Smart /**
4885b76f2dc9SJames Smart  * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands
4886b76f2dc9SJames Smart  * @file: The file pointer to read from.
4887b76f2dc9SJames Smart  * @buf: The buffer to copy the user data from.
4888b76f2dc9SJames Smart  * @nbytes: The number of bytes to get.
4889b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
4890b76f2dc9SJames Smart  *
4891b76f2dc9SJames Smart  * This routine get the debugfs idiag command struct from user space and then
4892b76f2dc9SJames Smart  * perform the syntax check for port and device control register read (dump)
4893b76f2dc9SJames Smart  * or write (set) command accordingly.
4894b76f2dc9SJames Smart  *
4895b76f2dc9SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
4896b76f2dc9SJames Smart  * In case of error conditions, it returns proper error code back to the user
4897b76f2dc9SJames Smart  * space.
4898b76f2dc9SJames Smart  **/
4899b76f2dc9SJames Smart static ssize_t
lpfc_idiag_ctlacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)4900b76f2dc9SJames Smart lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf,
4901b76f2dc9SJames Smart 			size_t nbytes, loff_t *ppos)
4902b76f2dc9SJames Smart {
4903b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
4904b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
4905b76f2dc9SJames Smart 	uint32_t ctl_reg_id, value, reg_val = 0;
4906b76f2dc9SJames Smart 	void __iomem *ctl_reg;
4907b76f2dc9SJames Smart 	int rc;
4908b76f2dc9SJames Smart 
4909b76f2dc9SJames Smart 	/* This is a user write operation */
4910b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
4911b76f2dc9SJames Smart 
4912b76f2dc9SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
4913b76f2dc9SJames Smart 	if (rc < 0)
4914b76f2dc9SJames Smart 		return rc;
4915b76f2dc9SJames Smart 
4916b76f2dc9SJames Smart 	/* Sanity check on command line arguments */
4917b76f2dc9SJames Smart 	ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
4918b76f2dc9SJames Smart 	value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX];
4919b76f2dc9SJames Smart 
4920b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
4921b76f2dc9SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
4922b76f2dc9SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4923b76f2dc9SJames Smart 		if (rc != LPFC_CTL_ACC_WR_CMD_ARG)
4924b76f2dc9SJames Smart 			goto error_out;
4925b76f2dc9SJames Smart 		if (ctl_reg_id > LPFC_CTL_MAX)
4926b76f2dc9SJames Smart 			goto error_out;
4927b76f2dc9SJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) {
4928b76f2dc9SJames Smart 		if (rc != LPFC_CTL_ACC_RD_CMD_ARG)
4929b76f2dc9SJames Smart 			goto error_out;
4930b76f2dc9SJames Smart 		if ((ctl_reg_id > LPFC_CTL_MAX) &&
4931b76f2dc9SJames Smart 		    (ctl_reg_id != LPFC_CTL_ACC_ALL))
4932b76f2dc9SJames Smart 			goto error_out;
4933b76f2dc9SJames Smart 	} else
4934b76f2dc9SJames Smart 		goto error_out;
4935b76f2dc9SJames Smart 
4936b76f2dc9SJames Smart 	/* Perform the write access operation */
4937b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
4938b76f2dc9SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
4939b76f2dc9SJames Smart 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4940b76f2dc9SJames Smart 		switch (ctl_reg_id) {
4941b76f2dc9SJames Smart 		case LPFC_CTL_PORT_SEM:
4942b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4943b76f2dc9SJames Smart 					LPFC_CTL_PORT_SEM_OFFSET;
4944b76f2dc9SJames Smart 			break;
4945b76f2dc9SJames Smart 		case LPFC_CTL_PORT_STA:
4946b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4947b76f2dc9SJames Smart 					LPFC_CTL_PORT_STA_OFFSET;
4948b76f2dc9SJames Smart 			break;
4949b76f2dc9SJames Smart 		case LPFC_CTL_PORT_CTL:
4950b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4951b76f2dc9SJames Smart 					LPFC_CTL_PORT_CTL_OFFSET;
4952b76f2dc9SJames Smart 			break;
4953b76f2dc9SJames Smart 		case LPFC_CTL_PORT_ER1:
4954b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4955b76f2dc9SJames Smart 					LPFC_CTL_PORT_ER1_OFFSET;
4956b76f2dc9SJames Smart 			break;
4957b76f2dc9SJames Smart 		case LPFC_CTL_PORT_ER2:
4958b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4959b76f2dc9SJames Smart 					LPFC_CTL_PORT_ER2_OFFSET;
4960b76f2dc9SJames Smart 			break;
4961b76f2dc9SJames Smart 		case LPFC_CTL_PDEV_CTL:
4962b76f2dc9SJames Smart 			ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
4963b76f2dc9SJames Smart 					LPFC_CTL_PDEV_CTL_OFFSET;
4964b76f2dc9SJames Smart 			break;
4965b76f2dc9SJames Smart 		default:
4966b76f2dc9SJames Smart 			goto error_out;
4967b76f2dc9SJames Smart 		}
4968b76f2dc9SJames Smart 
4969b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR)
4970b76f2dc9SJames Smart 			reg_val = value;
4971b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) {
4972b76f2dc9SJames Smart 			reg_val = readl(ctl_reg);
4973b76f2dc9SJames Smart 			reg_val |= value;
4974b76f2dc9SJames Smart 		}
4975b76f2dc9SJames Smart 		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
4976b76f2dc9SJames Smart 			reg_val = readl(ctl_reg);
4977b76f2dc9SJames Smart 			reg_val &= ~value;
4978b76f2dc9SJames Smart 		}
4979b76f2dc9SJames Smart 		writel(reg_val, ctl_reg);
4980b76f2dc9SJames Smart 		readl(ctl_reg); /* flush */
4981b76f2dc9SJames Smart 	}
4982b76f2dc9SJames Smart 	return nbytes;
4983b76f2dc9SJames Smart 
4984b76f2dc9SJames Smart error_out:
4985b76f2dc9SJames Smart 	/* Clean out command structure on command error out */
4986b76f2dc9SJames Smart 	memset(&idiag, 0, sizeof(idiag));
4987b76f2dc9SJames Smart 	return -EINVAL;
4988b76f2dc9SJames Smart }
4989b76f2dc9SJames Smart 
4990b76f2dc9SJames Smart /**
4991b76f2dc9SJames Smart  * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup
4992b76f2dc9SJames Smart  * @phba: Pointer to HBA context object.
4993b76f2dc9SJames Smart  * @pbuffer: Pointer to data buffer.
4994b76f2dc9SJames Smart  *
4995b76f2dc9SJames Smart  * Description:
4996b76f2dc9SJames Smart  * This routine gets the driver mailbox access debugfs setup information.
4997b76f2dc9SJames Smart  *
4998b76f2dc9SJames Smart  * Returns:
4999b76f2dc9SJames Smart  * This function returns the amount of data that was read (this could be less
5000b76f2dc9SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
5001b76f2dc9SJames Smart  **/
5002b76f2dc9SJames Smart static int
lpfc_idiag_mbxacc_get_setup(struct lpfc_hba * phba,char * pbuffer)5003b76f2dc9SJames Smart lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
5004b76f2dc9SJames Smart {
5005b76f2dc9SJames Smart 	uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
5006b76f2dc9SJames Smart 	int len = 0;
5007b76f2dc9SJames Smart 
5008b76f2dc9SJames Smart 	mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5009b76f2dc9SJames Smart 	mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5010b76f2dc9SJames Smart 	mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5011b76f2dc9SJames Smart 	mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5012b76f2dc9SJames Smart 
5013e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5014b76f2dc9SJames Smart 			"mbx_dump_map: 0x%08x\n", mbx_dump_map);
5015e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5016b76f2dc9SJames Smart 			"mbx_dump_cnt: %04d\n", mbx_dump_cnt);
5017e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5018b76f2dc9SJames Smart 			"mbx_word_cnt: %04d\n", mbx_word_cnt);
5019e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
5020b76f2dc9SJames Smart 			"mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
5021b76f2dc9SJames Smart 
5022b76f2dc9SJames Smart 	return len;
5023b76f2dc9SJames Smart }
5024b76f2dc9SJames Smart 
5025b76f2dc9SJames Smart /**
5026b76f2dc9SJames Smart  * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access
5027b76f2dc9SJames Smart  * @file: The file pointer to read from.
5028b76f2dc9SJames Smart  * @buf: The buffer to copy the data to.
5029b76f2dc9SJames Smart  * @nbytes: The number of bytes to read.
5030b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
5031b76f2dc9SJames Smart  *
5032b76f2dc9SJames Smart  * Description:
5033b76f2dc9SJames Smart  * This routine reads data from the @phba driver mailbox access debugfs setup
5034b76f2dc9SJames Smart  * information.
5035b76f2dc9SJames Smart  *
5036b76f2dc9SJames Smart  * Returns:
5037b76f2dc9SJames Smart  * This function returns the amount of data that was read (this could be less
5038b76f2dc9SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
5039b76f2dc9SJames Smart  **/
5040b76f2dc9SJames Smart static ssize_t
lpfc_idiag_mbxacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5041b76f2dc9SJames Smart lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes,
5042b76f2dc9SJames Smart 		       loff_t *ppos)
5043b76f2dc9SJames Smart {
5044b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
5045b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
5046b76f2dc9SJames Smart 	char *pbuffer;
5047b76f2dc9SJames Smart 	int len = 0;
5048b76f2dc9SJames Smart 
5049b76f2dc9SJames Smart 	/* This is a user read operation */
5050b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
5051b76f2dc9SJames Smart 
5052b76f2dc9SJames Smart 	if (!debug->buffer)
5053b76f2dc9SJames Smart 		debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL);
5054b76f2dc9SJames Smart 	if (!debug->buffer)
5055b76f2dc9SJames Smart 		return 0;
5056b76f2dc9SJames Smart 	pbuffer = debug->buffer;
5057b76f2dc9SJames Smart 
5058b76f2dc9SJames Smart 	if (*ppos)
5059b76f2dc9SJames Smart 		return 0;
5060b76f2dc9SJames Smart 
5061b76f2dc9SJames Smart 	if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) &&
5062b76f2dc9SJames Smart 	    (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP))
5063b76f2dc9SJames Smart 		return 0;
5064b76f2dc9SJames Smart 
5065b76f2dc9SJames Smart 	len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer);
5066b76f2dc9SJames Smart 
5067b76f2dc9SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
5068b76f2dc9SJames Smart }
5069b76f2dc9SJames Smart 
5070b76f2dc9SJames Smart /**
5071b76f2dc9SJames Smart  * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands
5072b76f2dc9SJames Smart  * @file: The file pointer to read from.
5073b76f2dc9SJames Smart  * @buf: The buffer to copy the user data from.
5074b76f2dc9SJames Smart  * @nbytes: The number of bytes to get.
5075b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
5076b76f2dc9SJames Smart  *
5077b76f2dc9SJames Smart  * This routine get the debugfs idiag command struct from user space and then
5078b76f2dc9SJames Smart  * perform the syntax check for driver mailbox command (dump) and sets up the
5079b76f2dc9SJames Smart  * necessary states in the idiag command struct accordingly.
5080b76f2dc9SJames Smart  *
5081b76f2dc9SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
5082b76f2dc9SJames Smart  * In case of error conditions, it returns proper error code back to the user
5083b76f2dc9SJames Smart  * space.
5084b76f2dc9SJames Smart  **/
5085b76f2dc9SJames Smart static ssize_t
lpfc_idiag_mbxacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)5086b76f2dc9SJames Smart lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf,
5087b76f2dc9SJames Smart 			size_t nbytes, loff_t *ppos)
5088b76f2dc9SJames Smart {
5089b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
5090b76f2dc9SJames Smart 	uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
5091b76f2dc9SJames Smart 	int rc;
5092b76f2dc9SJames Smart 
5093b76f2dc9SJames Smart 	/* This is a user write operation */
5094b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
5095b76f2dc9SJames Smart 
5096b76f2dc9SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
5097b76f2dc9SJames Smart 	if (rc < 0)
5098b76f2dc9SJames Smart 		return rc;
5099b76f2dc9SJames Smart 
5100b76f2dc9SJames Smart 	/* Sanity check on command line arguments */
5101b76f2dc9SJames Smart 	mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5102b76f2dc9SJames Smart 	mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5103b76f2dc9SJames Smart 	mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5104b76f2dc9SJames Smart 	mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5105b76f2dc9SJames Smart 
5106b76f2dc9SJames Smart 	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) {
5107b76f2dc9SJames Smart 		if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL))
5108b76f2dc9SJames Smart 			goto error_out;
5109b76f2dc9SJames Smart 		if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) &&
5110b76f2dc9SJames Smart 		    (mbx_dump_map != LPFC_MBX_DMP_ALL))
5111b76f2dc9SJames Smart 			goto error_out;
5112b76f2dc9SJames Smart 		if (mbx_word_cnt > sizeof(MAILBOX_t))
5113b76f2dc9SJames Smart 			goto error_out;
5114b76f2dc9SJames Smart 	} else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) {
5115b76f2dc9SJames Smart 		if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL))
5116b76f2dc9SJames Smart 			goto error_out;
5117b76f2dc9SJames Smart 		if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) &&
5118b76f2dc9SJames Smart 		    (mbx_dump_map != LPFC_MBX_DMP_ALL))
5119b76f2dc9SJames Smart 			goto error_out;
5120b76f2dc9SJames Smart 		if (mbx_word_cnt > (BSG_MBOX_SIZE)/4)
5121b76f2dc9SJames Smart 			goto error_out;
5122b76f2dc9SJames Smart 		if (mbx_mbox_cmd != 0x9b)
5123b76f2dc9SJames Smart 			goto error_out;
5124b76f2dc9SJames Smart 	} else
5125b76f2dc9SJames Smart 		goto error_out;
5126b76f2dc9SJames Smart 
5127b76f2dc9SJames Smart 	if (mbx_word_cnt == 0)
5128b76f2dc9SJames Smart 		goto error_out;
5129b76f2dc9SJames Smart 	if (rc != LPFC_MBX_DMP_ARG)
5130b76f2dc9SJames Smart 		goto error_out;
5131b76f2dc9SJames Smart 	if (mbx_mbox_cmd & ~0xff)
5132b76f2dc9SJames Smart 		goto error_out;
5133b76f2dc9SJames Smart 
5134b76f2dc9SJames Smart 	/* condition for stop mailbox dump */
5135b76f2dc9SJames Smart 	if (mbx_dump_cnt == 0)
5136b76f2dc9SJames Smart 		goto reset_out;
5137b76f2dc9SJames Smart 
5138b76f2dc9SJames Smart 	return nbytes;
5139b76f2dc9SJames Smart 
5140b76f2dc9SJames Smart reset_out:
5141b76f2dc9SJames Smart 	/* Clean out command structure on command error out */
5142b76f2dc9SJames Smart 	memset(&idiag, 0, sizeof(idiag));
5143b76f2dc9SJames Smart 	return nbytes;
5144b76f2dc9SJames Smart 
5145b76f2dc9SJames Smart error_out:
5146b76f2dc9SJames Smart 	/* Clean out command structure on command error out */
5147b76f2dc9SJames Smart 	memset(&idiag, 0, sizeof(idiag));
5148b76f2dc9SJames Smart 	return -EINVAL;
5149b76f2dc9SJames Smart }
5150b76f2dc9SJames Smart 
5151b76f2dc9SJames Smart /**
5152b76f2dc9SJames Smart  * lpfc_idiag_extacc_avail_get - get the available extents information
5153b76f2dc9SJames Smart  * @phba: pointer to lpfc hba data structure.
5154b76f2dc9SJames Smart  * @pbuffer: pointer to internal buffer.
5155b76f2dc9SJames Smart  * @len: length into the internal buffer data has been copied.
5156b76f2dc9SJames Smart  *
5157b76f2dc9SJames Smart  * Description:
5158b76f2dc9SJames Smart  * This routine is to get the available extent information.
5159b76f2dc9SJames Smart  *
5160b76f2dc9SJames Smart  * Returns:
516189bbf550Swengjianfeng  * overall length of the data read into the internal buffer.
5162b76f2dc9SJames Smart  **/
5163b76f2dc9SJames Smart static int
lpfc_idiag_extacc_avail_get(struct lpfc_hba * phba,char * pbuffer,int len)5164b76f2dc9SJames Smart lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
5165b76f2dc9SJames Smart {
5166a4de8356SJames Smart 	uint16_t ext_cnt = 0, ext_size = 0;
5167b76f2dc9SJames Smart 
5168e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5169b76f2dc9SJames Smart 			"\nAvailable Extents Information:\n");
5170b76f2dc9SJames Smart 
5171e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5172b76f2dc9SJames Smart 			"\tPort Available VPI extents: ");
5173b76f2dc9SJames Smart 	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
5174b76f2dc9SJames Smart 				       &ext_cnt, &ext_size);
5175e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5176b76f2dc9SJames Smart 			"Count %3d, Size %3d\n", ext_cnt, ext_size);
5177b76f2dc9SJames Smart 
5178e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5179b76f2dc9SJames Smart 			"\tPort Available VFI extents: ");
5180b76f2dc9SJames Smart 	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
5181b76f2dc9SJames Smart 				       &ext_cnt, &ext_size);
5182e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5183b76f2dc9SJames Smart 			"Count %3d, Size %3d\n", ext_cnt, ext_size);
5184b76f2dc9SJames Smart 
5185e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5186b76f2dc9SJames Smart 			"\tPort Available RPI extents: ");
5187b76f2dc9SJames Smart 	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
5188b76f2dc9SJames Smart 				       &ext_cnt, &ext_size);
5189e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5190b76f2dc9SJames Smart 			"Count %3d, Size %3d\n", ext_cnt, ext_size);
5191b76f2dc9SJames Smart 
5192e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5193b76f2dc9SJames Smart 			"\tPort Available XRI extents: ");
5194b76f2dc9SJames Smart 	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
5195b76f2dc9SJames Smart 				       &ext_cnt, &ext_size);
5196e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5197b76f2dc9SJames Smart 			"Count %3d, Size %3d\n", ext_cnt, ext_size);
5198b76f2dc9SJames Smart 
5199b76f2dc9SJames Smart 	return len;
5200b76f2dc9SJames Smart }
5201b76f2dc9SJames Smart 
5202b76f2dc9SJames Smart /**
5203b76f2dc9SJames Smart  * lpfc_idiag_extacc_alloc_get - get the allocated extents information
5204b76f2dc9SJames Smart  * @phba: pointer to lpfc hba data structure.
5205b76f2dc9SJames Smart  * @pbuffer: pointer to internal buffer.
5206b76f2dc9SJames Smart  * @len: length into the internal buffer data has been copied.
5207b76f2dc9SJames Smart  *
5208b76f2dc9SJames Smart  * Description:
5209b76f2dc9SJames Smart  * This routine is to get the allocated extent information.
5210b76f2dc9SJames Smart  *
5211b76f2dc9SJames Smart  * Returns:
521289bbf550Swengjianfeng  * overall length of the data read into the internal buffer.
5213b76f2dc9SJames Smart  **/
5214b76f2dc9SJames Smart static int
lpfc_idiag_extacc_alloc_get(struct lpfc_hba * phba,char * pbuffer,int len)5215b76f2dc9SJames Smart lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
5216b76f2dc9SJames Smart {
5217b76f2dc9SJames Smart 	uint16_t ext_cnt, ext_size;
5218b76f2dc9SJames Smart 	int rc;
5219b76f2dc9SJames Smart 
5220e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5221b76f2dc9SJames Smart 			"\nAllocated Extents Information:\n");
5222b76f2dc9SJames Smart 
5223e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5224b76f2dc9SJames Smart 			"\tHost Allocated VPI extents: ");
5225b76f2dc9SJames Smart 	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
5226b76f2dc9SJames Smart 					    &ext_cnt, &ext_size);
5227b76f2dc9SJames Smart 	if (!rc)
5228e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5229b76f2dc9SJames Smart 				"Port %d Extent %3d, Size %3d\n",
5230b76f2dc9SJames Smart 				phba->brd_no, ext_cnt, ext_size);
5231b76f2dc9SJames Smart 	else
5232e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5233b76f2dc9SJames Smart 				"N/A\n");
5234b76f2dc9SJames Smart 
5235e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5236b76f2dc9SJames Smart 			"\tHost Allocated VFI extents: ");
5237b76f2dc9SJames Smart 	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
5238b76f2dc9SJames Smart 					    &ext_cnt, &ext_size);
5239b76f2dc9SJames Smart 	if (!rc)
5240e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5241b76f2dc9SJames Smart 				"Port %d Extent %3d, Size %3d\n",
5242b76f2dc9SJames Smart 				phba->brd_no, ext_cnt, ext_size);
5243b76f2dc9SJames Smart 	else
5244e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5245b76f2dc9SJames Smart 				"N/A\n");
5246b76f2dc9SJames Smart 
5247e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5248b76f2dc9SJames Smart 			"\tHost Allocated RPI extents: ");
5249b76f2dc9SJames Smart 	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
5250b76f2dc9SJames Smart 					    &ext_cnt, &ext_size);
5251b76f2dc9SJames Smart 	if (!rc)
5252e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5253b76f2dc9SJames Smart 				"Port %d Extent %3d, Size %3d\n",
5254b76f2dc9SJames Smart 				phba->brd_no, ext_cnt, ext_size);
5255b76f2dc9SJames Smart 	else
5256e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5257b76f2dc9SJames Smart 				"N/A\n");
5258b76f2dc9SJames Smart 
5259e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5260b76f2dc9SJames Smart 			"\tHost Allocated XRI extents: ");
5261b76f2dc9SJames Smart 	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
5262b76f2dc9SJames Smart 					    &ext_cnt, &ext_size);
5263b76f2dc9SJames Smart 	if (!rc)
5264e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5265b76f2dc9SJames Smart 				"Port %d Extent %3d, Size %3d\n",
5266b76f2dc9SJames Smart 				phba->brd_no, ext_cnt, ext_size);
5267b76f2dc9SJames Smart 	else
5268e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5269b76f2dc9SJames Smart 				"N/A\n");
5270b76f2dc9SJames Smart 
5271b76f2dc9SJames Smart 	return len;
5272b76f2dc9SJames Smart }
5273b76f2dc9SJames Smart 
5274b76f2dc9SJames Smart /**
5275b76f2dc9SJames Smart  * lpfc_idiag_extacc_drivr_get - get driver extent information
5276b76f2dc9SJames Smart  * @phba: pointer to lpfc hba data structure.
5277b76f2dc9SJames Smart  * @pbuffer: pointer to internal buffer.
5278b76f2dc9SJames Smart  * @len: length into the internal buffer data has been copied.
5279b76f2dc9SJames Smart  *
5280b76f2dc9SJames Smart  * Description:
5281b76f2dc9SJames Smart  * This routine is to get the driver extent information.
5282b76f2dc9SJames Smart  *
5283b76f2dc9SJames Smart  * Returns:
528489bbf550Swengjianfeng  * overall length of the data read into the internal buffer.
5285b76f2dc9SJames Smart  **/
5286b76f2dc9SJames Smart static int
lpfc_idiag_extacc_drivr_get(struct lpfc_hba * phba,char * pbuffer,int len)5287b76f2dc9SJames Smart lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
5288b76f2dc9SJames Smart {
5289b76f2dc9SJames Smart 	struct lpfc_rsrc_blks *rsrc_blks;
5290b76f2dc9SJames Smart 	int index;
5291b76f2dc9SJames Smart 
5292e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5293b76f2dc9SJames Smart 			"\nDriver Extents Information:\n");
5294b76f2dc9SJames Smart 
5295e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5296b76f2dc9SJames Smart 			"\tVPI extents:\n");
5297b76f2dc9SJames Smart 	index = 0;
5298b76f2dc9SJames Smart 	list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
5299e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5300b76f2dc9SJames Smart 				"\t\tBlock %3d: Start %4d, Count %4d\n",
5301b76f2dc9SJames Smart 				index, rsrc_blks->rsrc_start,
5302b76f2dc9SJames Smart 				rsrc_blks->rsrc_size);
5303b76f2dc9SJames Smart 		index++;
5304b76f2dc9SJames Smart 	}
5305e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5306b76f2dc9SJames Smart 			"\tVFI extents:\n");
5307b76f2dc9SJames Smart 	index = 0;
5308b76f2dc9SJames Smart 	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
5309b76f2dc9SJames Smart 			    list) {
5310e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5311b76f2dc9SJames Smart 				"\t\tBlock %3d: Start %4d, Count %4d\n",
5312b76f2dc9SJames Smart 				index, rsrc_blks->rsrc_start,
5313b76f2dc9SJames Smart 				rsrc_blks->rsrc_size);
5314b76f2dc9SJames Smart 		index++;
5315b76f2dc9SJames Smart 	}
5316b76f2dc9SJames Smart 
5317e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5318b76f2dc9SJames Smart 			"\tRPI extents:\n");
5319b76f2dc9SJames Smart 	index = 0;
5320b76f2dc9SJames Smart 	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
5321b76f2dc9SJames Smart 			    list) {
5322e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5323b76f2dc9SJames Smart 				"\t\tBlock %3d: Start %4d, Count %4d\n",
5324b76f2dc9SJames Smart 				index, rsrc_blks->rsrc_start,
5325b76f2dc9SJames Smart 				rsrc_blks->rsrc_size);
5326b76f2dc9SJames Smart 		index++;
5327b76f2dc9SJames Smart 	}
5328b76f2dc9SJames Smart 
5329e7f7b6f3SSilvio Cesare 	len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5330b76f2dc9SJames Smart 			"\tXRI extents:\n");
5331b76f2dc9SJames Smart 	index = 0;
5332b76f2dc9SJames Smart 	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
5333b76f2dc9SJames Smart 			    list) {
5334e7f7b6f3SSilvio Cesare 		len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
5335b76f2dc9SJames Smart 				"\t\tBlock %3d: Start %4d, Count %4d\n",
5336b76f2dc9SJames Smart 				index, rsrc_blks->rsrc_start,
5337b76f2dc9SJames Smart 				rsrc_blks->rsrc_size);
5338b76f2dc9SJames Smart 		index++;
5339b76f2dc9SJames Smart 	}
5340b76f2dc9SJames Smart 
5341b76f2dc9SJames Smart 	return len;
5342b76f2dc9SJames Smart }
5343b76f2dc9SJames Smart 
5344b76f2dc9SJames Smart /**
5345b76f2dc9SJames Smart  * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands
5346b76f2dc9SJames Smart  * @file: The file pointer to read from.
5347b76f2dc9SJames Smart  * @buf: The buffer to copy the user data from.
5348b76f2dc9SJames Smart  * @nbytes: The number of bytes to get.
5349b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
5350b76f2dc9SJames Smart  *
5351b76f2dc9SJames Smart  * This routine get the debugfs idiag command struct from user space and then
5352b76f2dc9SJames Smart  * perform the syntax check for extent information access commands and sets
5353b76f2dc9SJames Smart  * up the necessary states in the idiag command struct accordingly.
5354b76f2dc9SJames Smart  *
5355b76f2dc9SJames Smart  * It returns the @nbytges passing in from debugfs user space when successful.
5356b76f2dc9SJames Smart  * In case of error conditions, it returns proper error code back to the user
5357b76f2dc9SJames Smart  * space.
5358b76f2dc9SJames Smart  **/
5359b76f2dc9SJames Smart static ssize_t
lpfc_idiag_extacc_write(struct file * file,const char __user * buf,size_t nbytes,loff_t * ppos)5360b76f2dc9SJames Smart lpfc_idiag_extacc_write(struct file *file, const char __user *buf,
5361b76f2dc9SJames Smart 			size_t nbytes, loff_t *ppos)
5362b76f2dc9SJames Smart {
5363b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
5364b76f2dc9SJames Smart 	uint32_t ext_map;
5365b76f2dc9SJames Smart 	int rc;
5366b76f2dc9SJames Smart 
5367b76f2dc9SJames Smart 	/* This is a user write operation */
5368b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_WR;
5369b76f2dc9SJames Smart 
5370b76f2dc9SJames Smart 	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
5371b76f2dc9SJames Smart 	if (rc < 0)
5372b76f2dc9SJames Smart 		return rc;
5373b76f2dc9SJames Smart 
5374b76f2dc9SJames Smart 	ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
5375b76f2dc9SJames Smart 
5376b76f2dc9SJames Smart 	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
5377b76f2dc9SJames Smart 		goto error_out;
5378b76f2dc9SJames Smart 	if (rc != LPFC_EXT_ACC_CMD_ARG)
5379b76f2dc9SJames Smart 		goto error_out;
5380b76f2dc9SJames Smart 	if (!(ext_map & LPFC_EXT_ACC_ALL))
5381b76f2dc9SJames Smart 		goto error_out;
5382b76f2dc9SJames Smart 
5383b76f2dc9SJames Smart 	return nbytes;
5384b76f2dc9SJames Smart error_out:
5385b76f2dc9SJames Smart 	/* Clean out command structure on command error out */
5386b76f2dc9SJames Smart 	memset(&idiag, 0, sizeof(idiag));
5387b76f2dc9SJames Smart 	return -EINVAL;
5388b76f2dc9SJames Smart }
5389b76f2dc9SJames Smart 
5390b76f2dc9SJames Smart /**
5391b76f2dc9SJames Smart  * lpfc_idiag_extacc_read - idiag debugfs read access to extent information
5392b76f2dc9SJames Smart  * @file: The file pointer to read from.
5393b76f2dc9SJames Smart  * @buf: The buffer to copy the data to.
5394b76f2dc9SJames Smart  * @nbytes: The number of bytes to read.
5395b76f2dc9SJames Smart  * @ppos: The position in the file to start reading from.
5396b76f2dc9SJames Smart  *
5397b76f2dc9SJames Smart  * Description:
5398b76f2dc9SJames Smart  * This routine reads data from the proper extent information according to
5399b76f2dc9SJames Smart  * the idiag command, and copies to user @buf.
5400b76f2dc9SJames Smart  *
5401b76f2dc9SJames Smart  * Returns:
5402b76f2dc9SJames Smart  * This function returns the amount of data that was read (this could be less
5403b76f2dc9SJames Smart  * than @nbytes if the end of the file was reached) or a negative error value.
5404b76f2dc9SJames Smart  **/
5405b76f2dc9SJames Smart static ssize_t
lpfc_idiag_extacc_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)5406b76f2dc9SJames Smart lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
5407b76f2dc9SJames Smart 		       loff_t *ppos)
5408b76f2dc9SJames Smart {
5409b76f2dc9SJames Smart 	struct lpfc_debug *debug = file->private_data;
5410b76f2dc9SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
5411b76f2dc9SJames Smart 	char *pbuffer;
5412b76f2dc9SJames Smart 	uint32_t ext_map;
5413b76f2dc9SJames Smart 	int len = 0;
5414b76f2dc9SJames Smart 
5415b76f2dc9SJames Smart 	/* This is a user read operation */
5416b76f2dc9SJames Smart 	debug->op = LPFC_IDIAG_OP_RD;
5417b76f2dc9SJames Smart 
5418b76f2dc9SJames Smart 	if (!debug->buffer)
5419b76f2dc9SJames Smart 		debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL);
5420b76f2dc9SJames Smart 	if (!debug->buffer)
5421b76f2dc9SJames Smart 		return 0;
5422b76f2dc9SJames Smart 	pbuffer = debug->buffer;
5423b76f2dc9SJames Smart 	if (*ppos)
5424b76f2dc9SJames Smart 		return 0;
5425b76f2dc9SJames Smart 	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
5426b76f2dc9SJames Smart 		return 0;
5427b76f2dc9SJames Smart 
5428b76f2dc9SJames Smart 	ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
5429b76f2dc9SJames Smart 	if (ext_map & LPFC_EXT_ACC_AVAIL)
5430b76f2dc9SJames Smart 		len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len);
5431b76f2dc9SJames Smart 	if (ext_map & LPFC_EXT_ACC_ALLOC)
5432b76f2dc9SJames Smart 		len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len);
5433b76f2dc9SJames Smart 	if (ext_map & LPFC_EXT_ACC_DRIVR)
5434b76f2dc9SJames Smart 		len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len);
5435b76f2dc9SJames Smart 
5436b76f2dc9SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
5437b76f2dc9SJames Smart }
5438b76f2dc9SJames Smart 
54399f778708SJames Smart static int
lpfc_cgn_buffer_open(struct inode * inode,struct file * file)54409f778708SJames Smart lpfc_cgn_buffer_open(struct inode *inode, struct file *file)
54419f778708SJames Smart {
54429f778708SJames Smart 	struct lpfc_debug *debug;
54439f778708SJames Smart 	int rc = -ENOMEM;
54449f778708SJames Smart 
54459f778708SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
54469f778708SJames Smart 	if (!debug)
54479f778708SJames Smart 		goto out;
54489f778708SJames Smart 
54499f778708SJames Smart 	debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE);
54509f778708SJames Smart 	if (!debug->buffer) {
54519f778708SJames Smart 		kfree(debug);
54529f778708SJames Smart 		goto out;
54539f778708SJames Smart 	}
54549f778708SJames Smart 
54559f778708SJames Smart 	debug->i_private = inode->i_private;
54569f778708SJames Smart 	file->private_data = debug;
54579f778708SJames Smart 
54589f778708SJames Smart 	rc = 0;
54599f778708SJames Smart out:
54609f778708SJames Smart 	return rc;
54619f778708SJames Smart }
54629f778708SJames Smart 
54639f778708SJames Smart static ssize_t
lpfc_cgn_buffer_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)54649f778708SJames Smart lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes,
54659f778708SJames Smart 		     loff_t *ppos)
54669f778708SJames Smart {
54679f778708SJames Smart 	struct lpfc_debug *debug = file->private_data;
54689f778708SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
54699f778708SJames Smart 	char *buffer = debug->buffer;
54709f778708SJames Smart 	uint32_t *ptr;
54719f778708SJames Smart 	int cnt, len = 0;
54729f778708SJames Smart 
54739f778708SJames Smart 	if (!phba->sli4_hba.pc_sli4_params.mi_ver || !phba->cgn_i) {
54749f778708SJames Smart 		len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54759f778708SJames Smart 				 "Congestion Mgmt is not supported\n");
54769f778708SJames Smart 		goto out;
54779f778708SJames Smart 	}
54789f778708SJames Smart 	ptr = (uint32_t *)phba->cgn_i->virt;
54799f778708SJames Smart 	len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54809f778708SJames Smart 			 "Congestion Buffer Header\n");
54819f778708SJames Smart 	/* Dump the first 32 bytes */
54829f778708SJames Smart 	cnt = 32;
54839f778708SJames Smart 	len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54849f778708SJames Smart 			 "000: %08x %08x %08x %08x %08x %08x %08x %08x\n",
54859f778708SJames Smart 			 *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
54869f778708SJames Smart 			 *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7));
54879f778708SJames Smart 	ptr += 8;
54889f778708SJames Smart 	len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54899f778708SJames Smart 			 "Congestion Buffer Data\n");
54909f778708SJames Smart 	while (cnt < sizeof(struct lpfc_cgn_info)) {
54919f778708SJames Smart 		if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) {
54929f778708SJames Smart 			len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54939f778708SJames Smart 					 "Truncated . . .\n");
54946014a246SJames Smart 			goto out;
54959f778708SJames Smart 		}
54969f778708SJames Smart 		len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
54979f778708SJames Smart 				 "%03x: %08x %08x %08x %08x "
54989f778708SJames Smart 				 "%08x %08x %08x %08x\n",
54999f778708SJames Smart 				 cnt, *ptr, *(ptr + 1), *(ptr + 2),
55009f778708SJames Smart 				 *(ptr + 3), *(ptr + 4), *(ptr + 5),
55019f778708SJames Smart 				 *(ptr + 6), *(ptr + 7));
55029f778708SJames Smart 		cnt += 32;
55039f778708SJames Smart 		ptr += 8;
55049f778708SJames Smart 	}
55056014a246SJames Smart 	if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) {
55066014a246SJames Smart 		len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
55076014a246SJames Smart 				 "Truncated . . .\n");
55086014a246SJames Smart 		goto out;
55096014a246SJames Smart 	}
55106014a246SJames Smart 	len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
55116014a246SJames Smart 			 "Parameter Data\n");
55126014a246SJames Smart 	ptr = (uint32_t *)&phba->cgn_p;
55136014a246SJames Smart 	len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len,
55146014a246SJames Smart 			 "%08x %08x %08x %08x\n",
55156014a246SJames Smart 			 *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
55169f778708SJames Smart out:
55179f778708SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, buffer, len);
55189f778708SJames Smart }
55199f778708SJames Smart 
55209f778708SJames Smart static int
lpfc_cgn_buffer_release(struct inode * inode,struct file * file)55219f778708SJames Smart lpfc_cgn_buffer_release(struct inode *inode, struct file *file)
55229f778708SJames Smart {
55239f778708SJames Smart 	struct lpfc_debug *debug = file->private_data;
55249f778708SJames Smart 
55259f778708SJames Smart 	vfree(debug->buffer);
55269f778708SJames Smart 	kfree(debug);
55279f778708SJames Smart 
55289f778708SJames Smart 	return 0;
55299f778708SJames Smart }
55309f778708SJames Smart 
55319f778708SJames Smart static int
lpfc_rx_monitor_open(struct inode * inode,struct file * file)55329f778708SJames Smart lpfc_rx_monitor_open(struct inode *inode, struct file *file)
55339f778708SJames Smart {
55349f778708SJames Smart 	struct lpfc_rx_monitor_debug *debug;
55359f778708SJames Smart 	int rc = -ENOMEM;
55369f778708SJames Smart 
55379f778708SJames Smart 	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
55389f778708SJames Smart 	if (!debug)
55399f778708SJames Smart 		goto out;
55409f778708SJames Smart 
5541bd269188SJames Smart 	debug->buffer = vmalloc(MAX_DEBUGFS_RX_INFO_SIZE);
55429f778708SJames Smart 	if (!debug->buffer) {
55439f778708SJames Smart 		kfree(debug);
55449f778708SJames Smart 		goto out;
55459f778708SJames Smart 	}
55469f778708SJames Smart 
55479f778708SJames Smart 	debug->i_private = inode->i_private;
55489f778708SJames Smart 	file->private_data = debug;
55499f778708SJames Smart 
55509f778708SJames Smart 	rc = 0;
55519f778708SJames Smart out:
55529f778708SJames Smart 	return rc;
55539f778708SJames Smart }
55549f778708SJames Smart 
55559f778708SJames Smart static ssize_t
lpfc_rx_monitor_read(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)55569f778708SJames Smart lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes,
55579f778708SJames Smart 		     loff_t *ppos)
55589f778708SJames Smart {
55599f778708SJames Smart 	struct lpfc_rx_monitor_debug *debug = file->private_data;
55609f778708SJames Smart 	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
55619f778708SJames Smart 	char *buffer = debug->buffer;
55629f778708SJames Smart 
5563bd269188SJames Smart 	if (!phba->rx_monitor) {
5564bd269188SJames Smart 		scnprintf(buffer, MAX_DEBUGFS_RX_INFO_SIZE,
5565bd269188SJames Smart 			  "Rx Monitor Info is empty.\n");
5566bd269188SJames Smart 	} else {
5567bd269188SJames Smart 		lpfc_rx_monitor_report(phba, phba->rx_monitor, buffer,
5568bd269188SJames Smart 				       MAX_DEBUGFS_RX_INFO_SIZE,
5569bd269188SJames Smart 				       LPFC_MAX_RXMONITOR_ENTRY);
55709f778708SJames Smart 	}
55719f778708SJames Smart 
5572bd269188SJames Smart 	return simple_read_from_buffer(buf, nbytes, ppos, buffer,
5573bd269188SJames Smart 				       strlen(buffer));
55749f778708SJames Smart }
55759f778708SJames Smart 
55769f778708SJames Smart static int
lpfc_rx_monitor_release(struct inode * inode,struct file * file)55779f778708SJames Smart lpfc_rx_monitor_release(struct inode *inode, struct file *file)
55789f778708SJames Smart {
55799f778708SJames Smart 	struct lpfc_rx_monitor_debug *debug = file->private_data;
55809f778708SJames Smart 
55819f778708SJames Smart 	vfree(debug->buffer);
55829f778708SJames Smart 	kfree(debug);
55839f778708SJames Smart 
55849f778708SJames Smart 	return 0;
55859f778708SJames Smart }
55869f778708SJames Smart 
5587858c9f6cSJames Smart #undef lpfc_debugfs_op_disc_trc
558871fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_disc_trc = {
5589858c9f6cSJames Smart 	.owner =        THIS_MODULE,
5590858c9f6cSJames Smart 	.open =         lpfc_debugfs_disc_trc_open,
5591858c9f6cSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5592858c9f6cSJames Smart 	.read =         lpfc_debugfs_read,
5593858c9f6cSJames Smart 	.release =      lpfc_debugfs_release,
5594858c9f6cSJames Smart };
5595858c9f6cSJames Smart 
5596858c9f6cSJames Smart #undef lpfc_debugfs_op_nodelist
559771fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_nodelist = {
5598858c9f6cSJames Smart 	.owner =        THIS_MODULE,
5599858c9f6cSJames Smart 	.open =         lpfc_debugfs_nodelist_open,
5600858c9f6cSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5601858c9f6cSJames Smart 	.read =         lpfc_debugfs_read,
5602858c9f6cSJames Smart 	.release =      lpfc_debugfs_release,
5603858c9f6cSJames Smart };
5604858c9f6cSJames Smart 
5605c490850aSJames Smart #undef lpfc_debugfs_op_multixripools
5606c490850aSJames Smart static const struct file_operations lpfc_debugfs_op_multixripools = {
5607c490850aSJames Smart 	.owner =        THIS_MODULE,
5608c490850aSJames Smart 	.open =         lpfc_debugfs_multixripools_open,
5609c490850aSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5610c490850aSJames Smart 	.read =         lpfc_debugfs_read,
5611c490850aSJames Smart 	.write =	lpfc_debugfs_multixripools_write,
5612c490850aSJames Smart 	.release =      lpfc_debugfs_release,
5613c490850aSJames Smart };
5614c490850aSJames Smart 
561578b2d852SJames Smart #undef lpfc_debugfs_op_hbqinfo
561671fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_hbqinfo = {
561778b2d852SJames Smart 	.owner =        THIS_MODULE,
561878b2d852SJames Smart 	.open =         lpfc_debugfs_hbqinfo_open,
561978b2d852SJames Smart 	.llseek =       lpfc_debugfs_lseek,
562078b2d852SJames Smart 	.read =         lpfc_debugfs_read,
562178b2d852SJames Smart 	.release =      lpfc_debugfs_release,
562278b2d852SJames Smart };
562378b2d852SJames Smart 
56246a828b0fSJames Smart #ifdef LPFC_HDWQ_LOCK_STAT
56256a828b0fSJames Smart #undef lpfc_debugfs_op_lockstat
56266a828b0fSJames Smart static const struct file_operations lpfc_debugfs_op_lockstat = {
56275e5b511dSJames Smart 	.owner =        THIS_MODULE,
56286a828b0fSJames Smart 	.open =         lpfc_debugfs_lockstat_open,
56295e5b511dSJames Smart 	.llseek =       lpfc_debugfs_lseek,
56305e5b511dSJames Smart 	.read =         lpfc_debugfs_read,
56316a828b0fSJames Smart 	.write =        lpfc_debugfs_lockstat_write,
56325e5b511dSJames Smart 	.release =      lpfc_debugfs_release,
56335e5b511dSJames Smart };
56346a828b0fSJames Smart #endif
56355e5b511dSJames Smart 
563695bfc6d8SJames Smart #undef lpfc_debugfs_ras_log
563795bfc6d8SJames Smart static const struct file_operations lpfc_debugfs_ras_log = {
563895bfc6d8SJames Smart 	.owner =        THIS_MODULE,
563995bfc6d8SJames Smart 	.open =         lpfc_debugfs_ras_log_open,
564095bfc6d8SJames Smart 	.llseek =       lpfc_debugfs_lseek,
564195bfc6d8SJames Smart 	.read =         lpfc_debugfs_read,
564295bfc6d8SJames Smart 	.release =      lpfc_debugfs_ras_log_release,
564395bfc6d8SJames Smart };
564495bfc6d8SJames Smart 
5645c95d6c6cSJames Smart #undef lpfc_debugfs_op_dumpHBASlim
564671fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
5647a58cbd52SJames Smart 	.owner =        THIS_MODULE,
5648c95d6c6cSJames Smart 	.open =         lpfc_debugfs_dumpHBASlim_open,
5649c95d6c6cSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5650c95d6c6cSJames Smart 	.read =         lpfc_debugfs_read,
5651c95d6c6cSJames Smart 	.release =      lpfc_debugfs_release,
5652c95d6c6cSJames Smart };
5653c95d6c6cSJames Smart 
5654c95d6c6cSJames Smart #undef lpfc_debugfs_op_dumpHostSlim
565571fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
5656c95d6c6cSJames Smart 	.owner =        THIS_MODULE,
5657c95d6c6cSJames Smart 	.open =         lpfc_debugfs_dumpHostSlim_open,
5658a58cbd52SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5659a58cbd52SJames Smart 	.read =         lpfc_debugfs_read,
5660a58cbd52SJames Smart 	.release =      lpfc_debugfs_release,
5661a58cbd52SJames Smart };
5662a58cbd52SJames Smart 
5663bd2cdd5eSJames Smart #undef lpfc_debugfs_op_nvmestat
5664bd2cdd5eSJames Smart static const struct file_operations lpfc_debugfs_op_nvmestat = {
5665bd2cdd5eSJames Smart 	.owner =        THIS_MODULE,
5666bd2cdd5eSJames Smart 	.open =         lpfc_debugfs_nvmestat_open,
5667bd2cdd5eSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5668bd2cdd5eSJames Smart 	.read =         lpfc_debugfs_read,
56692b65e182SJames Smart 	.write =	lpfc_debugfs_nvmestat_write,
5670bd2cdd5eSJames Smart 	.release =      lpfc_debugfs_release,
5671bd2cdd5eSJames Smart };
5672bd2cdd5eSJames Smart 
56734c47efc1SJames Smart #undef lpfc_debugfs_op_scsistat
56744c47efc1SJames Smart static const struct file_operations lpfc_debugfs_op_scsistat = {
56754c47efc1SJames Smart 	.owner =        THIS_MODULE,
56764c47efc1SJames Smart 	.open =         lpfc_debugfs_scsistat_open,
56774c47efc1SJames Smart 	.llseek =       lpfc_debugfs_lseek,
56784c47efc1SJames Smart 	.read =         lpfc_debugfs_read,
56794c47efc1SJames Smart 	.write =	lpfc_debugfs_scsistat_write,
56804c47efc1SJames Smart 	.release =      lpfc_debugfs_release,
56814c47efc1SJames Smart };
56824c47efc1SJames Smart 
56832fcbc569SJames Smart #undef lpfc_debugfs_op_ioktime
56842fcbc569SJames Smart static const struct file_operations lpfc_debugfs_op_ioktime = {
5685bd2cdd5eSJames Smart 	.owner =        THIS_MODULE,
56862fcbc569SJames Smart 	.open =         lpfc_debugfs_ioktime_open,
5687bd2cdd5eSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5688bd2cdd5eSJames Smart 	.read =         lpfc_debugfs_read,
56892fcbc569SJames Smart 	.write =	lpfc_debugfs_ioktime_write,
5690bd2cdd5eSJames Smart 	.release =      lpfc_debugfs_release,
5691bd2cdd5eSJames Smart };
5692bd2cdd5eSJames Smart 
5693bd2cdd5eSJames Smart #undef lpfc_debugfs_op_nvmeio_trc
5694bd2cdd5eSJames Smart static const struct file_operations lpfc_debugfs_op_nvmeio_trc = {
5695bd2cdd5eSJames Smart 	.owner =        THIS_MODULE,
5696bd2cdd5eSJames Smart 	.open =         lpfc_debugfs_nvmeio_trc_open,
5697bd2cdd5eSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5698bd2cdd5eSJames Smart 	.read =         lpfc_debugfs_read,
5699bd2cdd5eSJames Smart 	.write =	lpfc_debugfs_nvmeio_trc_write,
5700bd2cdd5eSJames Smart 	.release =      lpfc_debugfs_release,
5701bd2cdd5eSJames Smart };
5702bd2cdd5eSJames Smart 
5703840eda96SJames Smart #undef lpfc_debugfs_op_hdwqstat
5704840eda96SJames Smart static const struct file_operations lpfc_debugfs_op_hdwqstat = {
5705bd2cdd5eSJames Smart 	.owner =        THIS_MODULE,
5706840eda96SJames Smart 	.open =         lpfc_debugfs_hdwqstat_open,
5707bd2cdd5eSJames Smart 	.llseek =       lpfc_debugfs_lseek,
5708bd2cdd5eSJames Smart 	.read =         lpfc_debugfs_read,
5709840eda96SJames Smart 	.write =	lpfc_debugfs_hdwqstat_write,
5710bd2cdd5eSJames Smart 	.release =      lpfc_debugfs_release,
5711bd2cdd5eSJames Smart };
5712bd2cdd5eSJames Smart 
5713f9bb2da1SJames Smart #undef lpfc_debugfs_op_dif_err
5714f9bb2da1SJames Smart static const struct file_operations lpfc_debugfs_op_dif_err = {
5715f9bb2da1SJames Smart 	.owner =	THIS_MODULE,
5716234e3405SStephen Boyd 	.open =		simple_open,
5717f9bb2da1SJames Smart 	.llseek =	lpfc_debugfs_lseek,
5718f9bb2da1SJames Smart 	.read =		lpfc_debugfs_dif_err_read,
5719f9bb2da1SJames Smart 	.write =	lpfc_debugfs_dif_err_write,
5720f9bb2da1SJames Smart 	.release =	lpfc_debugfs_dif_err_release,
5721f9bb2da1SJames Smart };
5722f9bb2da1SJames Smart 
5723a58cbd52SJames Smart #undef lpfc_debugfs_op_slow_ring_trc
572471fa7421SJan Engelhardt static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
5725a58cbd52SJames Smart 	.owner =        THIS_MODULE,
5726a58cbd52SJames Smart 	.open =         lpfc_debugfs_slow_ring_trc_open,
5727a58cbd52SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5728a58cbd52SJames Smart 	.read =         lpfc_debugfs_read,
5729a58cbd52SJames Smart 	.release =      lpfc_debugfs_release,
5730a58cbd52SJames Smart };
5731a58cbd52SJames Smart 
5732858c9f6cSJames Smart static struct dentry *lpfc_debugfs_root = NULL;
5733858c9f6cSJames Smart static atomic_t lpfc_debugfs_hba_count;
57342a622bfbSJames Smart 
57352a622bfbSJames Smart /*
57362a622bfbSJames Smart  * File operations for the iDiag debugfs
57372a622bfbSJames Smart  */
57382a622bfbSJames Smart #undef lpfc_idiag_op_pciCfg
57392a622bfbSJames Smart static const struct file_operations lpfc_idiag_op_pciCfg = {
57402a622bfbSJames Smart 	.owner =        THIS_MODULE,
57412a622bfbSJames Smart 	.open =         lpfc_idiag_open,
57422a622bfbSJames Smart 	.llseek =       lpfc_debugfs_lseek,
57432a622bfbSJames Smart 	.read =         lpfc_idiag_pcicfg_read,
57442a622bfbSJames Smart 	.write =        lpfc_idiag_pcicfg_write,
57452a622bfbSJames Smart 	.release =      lpfc_idiag_cmd_release,
57462a622bfbSJames Smart };
57472a622bfbSJames Smart 
5748b76f2dc9SJames Smart #undef lpfc_idiag_op_barAcc
5749b76f2dc9SJames Smart static const struct file_operations lpfc_idiag_op_barAcc = {
5750b76f2dc9SJames Smart 	.owner =        THIS_MODULE,
5751b76f2dc9SJames Smart 	.open =         lpfc_idiag_open,
5752b76f2dc9SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5753b76f2dc9SJames Smart 	.read =         lpfc_idiag_baracc_read,
5754b76f2dc9SJames Smart 	.write =        lpfc_idiag_baracc_write,
5755b76f2dc9SJames Smart 	.release =      lpfc_idiag_cmd_release,
5756b76f2dc9SJames Smart };
5757b76f2dc9SJames Smart 
57582a622bfbSJames Smart #undef lpfc_idiag_op_queInfo
57592a622bfbSJames Smart static const struct file_operations lpfc_idiag_op_queInfo = {
57602a622bfbSJames Smart 	.owner =        THIS_MODULE,
57612a622bfbSJames Smart 	.open =         lpfc_idiag_open,
57622a622bfbSJames Smart 	.read =         lpfc_idiag_queinfo_read,
57632a622bfbSJames Smart 	.release =      lpfc_idiag_release,
57642a622bfbSJames Smart };
57652a622bfbSJames Smart 
5766b76f2dc9SJames Smart #undef lpfc_idiag_op_queAcc
576786a80846SJames Smart static const struct file_operations lpfc_idiag_op_queAcc = {
576886a80846SJames Smart 	.owner =        THIS_MODULE,
576986a80846SJames Smart 	.open =         lpfc_idiag_open,
577086a80846SJames Smart 	.llseek =       lpfc_debugfs_lseek,
577186a80846SJames Smart 	.read =         lpfc_idiag_queacc_read,
577286a80846SJames Smart 	.write =        lpfc_idiag_queacc_write,
577386a80846SJames Smart 	.release =      lpfc_idiag_cmd_release,
577486a80846SJames Smart };
577586a80846SJames Smart 
5776b76f2dc9SJames Smart #undef lpfc_idiag_op_drbAcc
577786a80846SJames Smart static const struct file_operations lpfc_idiag_op_drbAcc = {
577886a80846SJames Smart 	.owner =        THIS_MODULE,
577986a80846SJames Smart 	.open =         lpfc_idiag_open,
578086a80846SJames Smart 	.llseek =       lpfc_debugfs_lseek,
578186a80846SJames Smart 	.read =         lpfc_idiag_drbacc_read,
578286a80846SJames Smart 	.write =        lpfc_idiag_drbacc_write,
578386a80846SJames Smart 	.release =      lpfc_idiag_cmd_release,
578486a80846SJames Smart };
578586a80846SJames Smart 
5786b76f2dc9SJames Smart #undef lpfc_idiag_op_ctlAcc
5787b76f2dc9SJames Smart static const struct file_operations lpfc_idiag_op_ctlAcc = {
5788b76f2dc9SJames Smart 	.owner =        THIS_MODULE,
5789b76f2dc9SJames Smart 	.open =         lpfc_idiag_open,
5790b76f2dc9SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5791b76f2dc9SJames Smart 	.read =         lpfc_idiag_ctlacc_read,
5792b76f2dc9SJames Smart 	.write =        lpfc_idiag_ctlacc_write,
5793b76f2dc9SJames Smart 	.release =      lpfc_idiag_cmd_release,
5794b76f2dc9SJames Smart };
5795b76f2dc9SJames Smart 
5796b76f2dc9SJames Smart #undef lpfc_idiag_op_mbxAcc
5797b76f2dc9SJames Smart static const struct file_operations lpfc_idiag_op_mbxAcc = {
5798b76f2dc9SJames Smart 	.owner =        THIS_MODULE,
5799b76f2dc9SJames Smart 	.open =         lpfc_idiag_open,
5800b76f2dc9SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5801b76f2dc9SJames Smart 	.read =         lpfc_idiag_mbxacc_read,
5802b76f2dc9SJames Smart 	.write =        lpfc_idiag_mbxacc_write,
5803b76f2dc9SJames Smart 	.release =      lpfc_idiag_cmd_release,
5804b76f2dc9SJames Smart };
5805b76f2dc9SJames Smart 
5806b76f2dc9SJames Smart #undef lpfc_idiag_op_extAcc
5807b76f2dc9SJames Smart static const struct file_operations lpfc_idiag_op_extAcc = {
5808b76f2dc9SJames Smart 	.owner =        THIS_MODULE,
5809b76f2dc9SJames Smart 	.open =         lpfc_idiag_open,
5810b76f2dc9SJames Smart 	.llseek =       lpfc_debugfs_lseek,
5811b76f2dc9SJames Smart 	.read =         lpfc_idiag_extacc_read,
5812b76f2dc9SJames Smart 	.write =        lpfc_idiag_extacc_write,
5813b76f2dc9SJames Smart 	.release =      lpfc_idiag_cmd_release,
5814b76f2dc9SJames Smart };
58159f778708SJames Smart #undef lpfc_cgn_buffer_op
58169f778708SJames Smart static const struct file_operations lpfc_cgn_buffer_op = {
58179f778708SJames Smart 	.owner =        THIS_MODULE,
58189f778708SJames Smart 	.open =         lpfc_cgn_buffer_open,
58199f778708SJames Smart 	.llseek =       lpfc_debugfs_lseek,
58209f778708SJames Smart 	.read =         lpfc_cgn_buffer_read,
58219f778708SJames Smart 	.release =      lpfc_cgn_buffer_release,
58229f778708SJames Smart };
58239f778708SJames Smart 
58249f778708SJames Smart #undef lpfc_rx_monitor_op
58259f778708SJames Smart static const struct file_operations lpfc_rx_monitor_op = {
58269f778708SJames Smart 	.owner =        THIS_MODULE,
58279f778708SJames Smart 	.open =         lpfc_rx_monitor_open,
58289f778708SJames Smart 	.llseek =       lpfc_debugfs_lseek,
58299f778708SJames Smart 	.read =         lpfc_rx_monitor_read,
58309f778708SJames Smart 	.release =      lpfc_rx_monitor_release,
58319f778708SJames Smart };
5832201743b9SArnd Bergmann #endif
5833858c9f6cSJames Smart 
5834b76f2dc9SJames Smart /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
5835b76f2dc9SJames Smart  * @phba: Pointer to HBA context object.
5836b76f2dc9SJames Smart  * @dmabuf: Pointer to a DMA buffer descriptor.
5837b76f2dc9SJames Smart  *
5838b76f2dc9SJames Smart  * Description:
5839b76f2dc9SJames Smart  * This routine dump a bsg pass-through non-embedded mailbox command with
5840b76f2dc9SJames Smart  * external buffer.
5841b76f2dc9SJames Smart  **/
5842b76f2dc9SJames Smart 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)5843b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
5844b76f2dc9SJames Smart 				enum mbox_type mbox_tp, enum dma_type dma_tp,
5845b76f2dc9SJames Smart 				enum sta_type sta_tp,
5846b76f2dc9SJames Smart 				struct lpfc_dmabuf *dmabuf, uint32_t ext_buf)
5847b76f2dc9SJames Smart {
5848b76f2dc9SJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
5849b76f2dc9SJames Smart 	uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt;
5850b76f2dc9SJames Smart 	char line_buf[LPFC_MBX_ACC_LBUF_SZ];
5851b76f2dc9SJames Smart 	int len = 0;
5852b76f2dc9SJames Smart 	uint32_t do_dump = 0;
5853b76f2dc9SJames Smart 	uint32_t *pword;
5854b76f2dc9SJames Smart 	uint32_t i;
5855b76f2dc9SJames Smart 
5856b76f2dc9SJames Smart 	if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)
5857b76f2dc9SJames Smart 		return;
5858b76f2dc9SJames Smart 
5859b76f2dc9SJames Smart 	mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5860b76f2dc9SJames Smart 	mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5861b76f2dc9SJames Smart 	mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5862b76f2dc9SJames Smart 	mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5863b76f2dc9SJames Smart 
5864b76f2dc9SJames Smart 	if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) ||
5865b76f2dc9SJames Smart 	    (*mbx_dump_cnt == 0) ||
5866b76f2dc9SJames Smart 	    (*mbx_word_cnt == 0))
5867b76f2dc9SJames Smart 		return;
5868b76f2dc9SJames Smart 
5869b76f2dc9SJames Smart 	if (*mbx_mbox_cmd != 0x9B)
5870b76f2dc9SJames Smart 		return;
5871b76f2dc9SJames Smart 
5872b76f2dc9SJames Smart 	if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) {
5873b76f2dc9SJames Smart 		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) {
5874b76f2dc9SJames Smart 			do_dump |= LPFC_BSG_DMP_MBX_RD_MBX;
58752ea259eeSJames Smart 			pr_err("\nRead mbox command (x%x), "
5876b76f2dc9SJames Smart 			       "nemb:0x%x, extbuf_cnt:%d:\n",
5877b76f2dc9SJames Smart 			       sta_tp, nemb_tp, ext_buf);
5878b76f2dc9SJames Smart 		}
5879b76f2dc9SJames Smart 	}
5880b76f2dc9SJames Smart 	if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) {
5881b76f2dc9SJames Smart 		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) {
5882b76f2dc9SJames Smart 			do_dump |= LPFC_BSG_DMP_MBX_RD_BUF;
58832ea259eeSJames Smart 			pr_err("\nRead mbox buffer (x%x), "
5884b76f2dc9SJames Smart 			       "nemb:0x%x, extbuf_seq:%d:\n",
5885b76f2dc9SJames Smart 			       sta_tp, nemb_tp, ext_buf);
5886b76f2dc9SJames Smart 		}
5887b76f2dc9SJames Smart 	}
5888b76f2dc9SJames Smart 	if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) {
5889b76f2dc9SJames Smart 		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) {
5890b76f2dc9SJames Smart 			do_dump |= LPFC_BSG_DMP_MBX_WR_MBX;
58912ea259eeSJames Smart 			pr_err("\nWrite mbox command (x%x), "
5892b76f2dc9SJames Smart 			       "nemb:0x%x, extbuf_cnt:%d:\n",
5893b76f2dc9SJames Smart 			       sta_tp, nemb_tp, ext_buf);
5894b76f2dc9SJames Smart 		}
5895b76f2dc9SJames Smart 	}
5896b76f2dc9SJames Smart 	if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) {
5897b76f2dc9SJames Smart 		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) {
5898b76f2dc9SJames Smart 			do_dump |= LPFC_BSG_DMP_MBX_WR_BUF;
58992ea259eeSJames Smart 			pr_err("\nWrite mbox buffer (x%x), "
5900b76f2dc9SJames Smart 			       "nemb:0x%x, extbuf_seq:%d:\n",
5901b76f2dc9SJames Smart 			       sta_tp, nemb_tp, ext_buf);
5902b76f2dc9SJames Smart 		}
5903b76f2dc9SJames Smart 	}
5904b76f2dc9SJames Smart 
5905b76f2dc9SJames Smart 	/* dump buffer content */
5906b76f2dc9SJames Smart 	if (do_dump) {
5907b76f2dc9SJames Smart 		pword = (uint32_t *)dmabuf->virt;
5908b76f2dc9SJames Smart 		for (i = 0; i < *mbx_word_cnt; i++) {
5909b76f2dc9SJames Smart 			if (!(i % 8)) {
5910b76f2dc9SJames Smart 				if (i != 0)
59112ea259eeSJames Smart 					pr_err("%s\n", line_buf);
5912b76f2dc9SJames Smart 				len = 0;
5913e7f7b6f3SSilvio Cesare 				len += scnprintf(line_buf+len,
5914b76f2dc9SJames Smart 						LPFC_MBX_ACC_LBUF_SZ-len,
5915b76f2dc9SJames Smart 						"%03d: ", i);
5916b76f2dc9SJames Smart 			}
5917e7f7b6f3SSilvio Cesare 			len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
5918b76f2dc9SJames Smart 					"%08x ", (uint32_t)*pword);
5919b76f2dc9SJames Smart 			pword++;
5920b76f2dc9SJames Smart 		}
5921b76f2dc9SJames Smart 		if ((i - 1) % 8)
59222ea259eeSJames Smart 			pr_err("%s\n", line_buf);
5923b76f2dc9SJames Smart 		(*mbx_dump_cnt)--;
5924b76f2dc9SJames Smart 	}
5925b76f2dc9SJames Smart 
5926b76f2dc9SJames Smart 	/* Clean out command structure on reaching dump count */
5927b76f2dc9SJames Smart 	if (*mbx_dump_cnt == 0)
5928b76f2dc9SJames Smart 		memset(&idiag, 0, sizeof(idiag));
5929b76f2dc9SJames Smart 	return;
5930b76f2dc9SJames Smart #endif
5931b76f2dc9SJames Smart }
5932b76f2dc9SJames Smart 
5933b76f2dc9SJames Smart /* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command
5934b76f2dc9SJames Smart  * @phba: Pointer to HBA context object.
5935b76f2dc9SJames Smart  * @dmabuf: Pointer to a DMA buffer descriptor.
5936b76f2dc9SJames Smart  *
5937b76f2dc9SJames Smart  * Description:
5938b76f2dc9SJames Smart  * This routine dump a pass-through non-embedded mailbox command from issue
5939b76f2dc9SJames Smart  * mailbox command.
5940b76f2dc9SJames Smart  **/
5941b76f2dc9SJames Smart void
lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba * phba,MAILBOX_t * pmbox)5942b76f2dc9SJames Smart lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
5943b76f2dc9SJames Smart {
5944b76f2dc9SJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
5945b76f2dc9SJames Smart 	uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd;
5946b76f2dc9SJames Smart 	char line_buf[LPFC_MBX_ACC_LBUF_SZ];
5947b76f2dc9SJames Smart 	int len = 0;
5948b76f2dc9SJames Smart 	uint32_t *pword;
5949b76f2dc9SJames Smart 	uint8_t *pbyte;
5950b76f2dc9SJames Smart 	uint32_t i, j;
5951b76f2dc9SJames Smart 
5952b76f2dc9SJames Smart 	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP)
5953b76f2dc9SJames Smart 		return;
5954b76f2dc9SJames Smart 
5955b76f2dc9SJames Smart 	mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
5956b76f2dc9SJames Smart 	mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
5957b76f2dc9SJames Smart 	mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
5958b76f2dc9SJames Smart 	mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
5959b76f2dc9SJames Smart 
5960b76f2dc9SJames Smart 	if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) ||
5961b76f2dc9SJames Smart 	    (*mbx_dump_cnt == 0) ||
5962b76f2dc9SJames Smart 	    (*mbx_word_cnt == 0))
5963b76f2dc9SJames Smart 		return;
5964b76f2dc9SJames Smart 
5965b76f2dc9SJames Smart 	if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) &&
5966b76f2dc9SJames Smart 	    (*mbx_mbox_cmd != pmbox->mbxCommand))
5967b76f2dc9SJames Smart 		return;
5968b76f2dc9SJames Smart 
5969b76f2dc9SJames Smart 	/* dump buffer content */
5970b76f2dc9SJames Smart 	if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) {
59712ea259eeSJames Smart 		pr_err("Mailbox command:0x%x dump by word:\n",
5972b76f2dc9SJames Smart 		       pmbox->mbxCommand);
5973b76f2dc9SJames Smart 		pword = (uint32_t *)pmbox;
5974b76f2dc9SJames Smart 		for (i = 0; i < *mbx_word_cnt; i++) {
5975b76f2dc9SJames Smart 			if (!(i % 8)) {
5976b76f2dc9SJames Smart 				if (i != 0)
59772ea259eeSJames Smart 					pr_err("%s\n", line_buf);
5978b76f2dc9SJames Smart 				len = 0;
5979b76f2dc9SJames Smart 				memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
5980e7f7b6f3SSilvio Cesare 				len += scnprintf(line_buf+len,
5981b76f2dc9SJames Smart 						LPFC_MBX_ACC_LBUF_SZ-len,
5982b76f2dc9SJames Smart 						"%03d: ", i);
5983b76f2dc9SJames Smart 			}
5984e7f7b6f3SSilvio Cesare 			len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
5985b76f2dc9SJames Smart 					"%08x ",
5986b76f2dc9SJames Smart 					((uint32_t)*pword) & 0xffffffff);
5987b76f2dc9SJames Smart 			pword++;
5988b76f2dc9SJames Smart 		}
5989b76f2dc9SJames Smart 		if ((i - 1) % 8)
59902ea259eeSJames Smart 			pr_err("%s\n", line_buf);
59912ea259eeSJames Smart 		pr_err("\n");
5992b76f2dc9SJames Smart 	}
5993b76f2dc9SJames Smart 	if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) {
59942ea259eeSJames Smart 		pr_err("Mailbox command:0x%x dump by byte:\n",
5995b76f2dc9SJames Smart 		       pmbox->mbxCommand);
5996b76f2dc9SJames Smart 		pbyte = (uint8_t *)pmbox;
5997b76f2dc9SJames Smart 		for (i = 0; i < *mbx_word_cnt; i++) {
5998b76f2dc9SJames Smart 			if (!(i % 8)) {
5999b76f2dc9SJames Smart 				if (i != 0)
60002ea259eeSJames Smart 					pr_err("%s\n", line_buf);
6001b76f2dc9SJames Smart 				len = 0;
6002b76f2dc9SJames Smart 				memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
6003e7f7b6f3SSilvio Cesare 				len += scnprintf(line_buf+len,
6004b76f2dc9SJames Smart 						LPFC_MBX_ACC_LBUF_SZ-len,
6005b76f2dc9SJames Smart 						"%03d: ", i);
6006b76f2dc9SJames Smart 			}
6007b76f2dc9SJames Smart 			for (j = 0; j < 4; j++) {
6008e7f7b6f3SSilvio Cesare 				len += scnprintf(line_buf+len,
6009b76f2dc9SJames Smart 						LPFC_MBX_ACC_LBUF_SZ-len,
6010b76f2dc9SJames Smart 						"%02x",
6011b76f2dc9SJames Smart 						((uint8_t)*pbyte) & 0xff);
6012b76f2dc9SJames Smart 				pbyte++;
6013b76f2dc9SJames Smart 			}
6014e7f7b6f3SSilvio Cesare 			len += scnprintf(line_buf+len,
6015b76f2dc9SJames Smart 					LPFC_MBX_ACC_LBUF_SZ-len, " ");
6016b76f2dc9SJames Smart 		}
6017b76f2dc9SJames Smart 		if ((i - 1) % 8)
60182ea259eeSJames Smart 			pr_err("%s\n", line_buf);
60192ea259eeSJames Smart 		pr_err("\n");
6020b76f2dc9SJames Smart 	}
6021b76f2dc9SJames Smart 	(*mbx_dump_cnt)--;
6022b76f2dc9SJames Smart 
6023b76f2dc9SJames Smart 	/* Clean out command structure on reaching dump count */
6024b76f2dc9SJames Smart 	if (*mbx_dump_cnt == 0)
6025b76f2dc9SJames Smart 		memset(&idiag, 0, sizeof(idiag));
6026b76f2dc9SJames Smart 	return;
6027b76f2dc9SJames Smart #endif
6028b76f2dc9SJames Smart }
6029b76f2dc9SJames Smart 
6030e59058c4SJames Smart /**
60313621a710SJames Smart  * lpfc_debugfs_initialize - Initialize debugfs for a vport
6032e59058c4SJames Smart  * @vport: The vport pointer to initialize.
6033e59058c4SJames Smart  *
6034e59058c4SJames Smart  * Description:
6035e59058c4SJames Smart  * When Debugfs is configured this routine sets up the lpfc debugfs file system.
6036e59058c4SJames Smart  * If not already created, this routine will create the lpfc directory, and
6037e59058c4SJames Smart  * lpfcX directory (for this HBA), and vportX directory for this vport. It will
6038e59058c4SJames Smart  * also create each file used to access lpfc specific debugfs information.
6039e59058c4SJames Smart  **/
6040858c9f6cSJames Smart inline void
lpfc_debugfs_initialize(struct lpfc_vport * vport)6041858c9f6cSJames Smart lpfc_debugfs_initialize(struct lpfc_vport *vport)
6042858c9f6cSJames Smart {
6043923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
6044858c9f6cSJames Smart 	struct lpfc_hba   *phba = vport->phba;
6045858c9f6cSJames Smart 	char name[64];
6046858c9f6cSJames Smart 	uint32_t num, i;
6047f6c3bdfbSJames Smart 	bool pport_setup = false;
6048858c9f6cSJames Smart 
6049858c9f6cSJames Smart 	if (!lpfc_debugfs_enable)
6050858c9f6cSJames Smart 		return;
6051858c9f6cSJames Smart 
6052a58cbd52SJames Smart 	/* Setup lpfc root directory */
6053a58cbd52SJames Smart 	if (!lpfc_debugfs_root) {
6054a58cbd52SJames Smart 		lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
6055a58cbd52SJames Smart 		atomic_set(&lpfc_debugfs_hba_count, 0);
6056a58cbd52SJames Smart 	}
6057a58cbd52SJames Smart 	if (!lpfc_debugfs_start_time)
6058a58cbd52SJames Smart 		lpfc_debugfs_start_time = jiffies;
6059a58cbd52SJames Smart 
60602a622bfbSJames Smart 	/* Setup funcX directory for specific HBA PCI function */
60612a622bfbSJames Smart 	snprintf(name, sizeof(name), "fn%d", phba->brd_no);
6062a58cbd52SJames Smart 	if (!phba->hba_debugfs_root) {
6063f6c3bdfbSJames Smart 		pport_setup = true;
6064a58cbd52SJames Smart 		phba->hba_debugfs_root =
6065a58cbd52SJames Smart 			debugfs_create_dir(name, lpfc_debugfs_root);
6066a58cbd52SJames Smart 		atomic_inc(&lpfc_debugfs_hba_count);
6067a58cbd52SJames Smart 		atomic_set(&phba->debugfs_vport_count, 0);
6068a58cbd52SJames Smart 
6069c490850aSJames Smart 		/* Multi-XRI pools */
6070c490850aSJames Smart 		snprintf(name, sizeof(name), "multixripools");
6071c490850aSJames Smart 		phba->debug_multixri_pools =
6072c490850aSJames Smart 			debugfs_create_file(name, S_IFREG | 0644,
6073c490850aSJames Smart 					    phba->hba_debugfs_root,
6074c490850aSJames Smart 					    phba,
6075c490850aSJames Smart 					    &lpfc_debugfs_op_multixripools);
60767dcc683dSJinjie Ruan 		if (IS_ERR(phba->debug_multixri_pools)) {
6077c490850aSJames Smart 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6078c490850aSJames Smart 					 "0527 Cannot create debugfs multixripools\n");
6079c490850aSJames Smart 			goto debug_failed;
6080c490850aSJames Smart 		}
6081c490850aSJames Smart 
60829f778708SJames Smart 		/* Congestion Info Buffer */
60839f778708SJames Smart 		scnprintf(name, sizeof(name), "cgn_buffer");
60849f778708SJames Smart 		phba->debug_cgn_buffer =
60859f778708SJames Smart 			debugfs_create_file(name, S_IFREG | 0644,
60869f778708SJames Smart 					    phba->hba_debugfs_root,
60879f778708SJames Smart 					    phba, &lpfc_cgn_buffer_op);
60887dcc683dSJinjie Ruan 		if (IS_ERR(phba->debug_cgn_buffer)) {
60899f778708SJames Smart 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
60909f778708SJames Smart 					 "6527 Cannot create debugfs "
60919f778708SJames Smart 					 "cgn_buffer\n");
60929f778708SJames Smart 			goto debug_failed;
60939f778708SJames Smart 		}
60949f778708SJames Smart 
60959f778708SJames Smart 		/* RX Monitor */
60969f778708SJames Smart 		scnprintf(name, sizeof(name), "rx_monitor");
60979f778708SJames Smart 		phba->debug_rx_monitor =
60989f778708SJames Smart 			debugfs_create_file(name, S_IFREG | 0644,
60999f778708SJames Smart 					    phba->hba_debugfs_root,
61009f778708SJames Smart 					    phba, &lpfc_rx_monitor_op);
61017dcc683dSJinjie Ruan 		if (IS_ERR(phba->debug_rx_monitor)) {
61029f778708SJames Smart 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
61039f778708SJames Smart 					 "6528 Cannot create debugfs "
61049f778708SJames Smart 					 "rx_monitor\n");
61059f778708SJames Smart 			goto debug_failed;
61069f778708SJames Smart 		}
61079f778708SJames Smart 
610895bfc6d8SJames Smart 		/* RAS log */
610995bfc6d8SJames Smart 		snprintf(name, sizeof(name), "ras_log");
611095bfc6d8SJames Smart 		phba->debug_ras_log =
611195bfc6d8SJames Smart 			debugfs_create_file(name, 0644,
611295bfc6d8SJames Smart 					    phba->hba_debugfs_root,
611395bfc6d8SJames Smart 					    phba, &lpfc_debugfs_ras_log);
61147dcc683dSJinjie Ruan 		if (IS_ERR(phba->debug_ras_log)) {
611595bfc6d8SJames Smart 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
611695bfc6d8SJames Smart 					 "6148 Cannot create debugfs"
611795bfc6d8SJames Smart 					 " ras_log\n");
611895bfc6d8SJames Smart 			goto debug_failed;
611995bfc6d8SJames Smart 		}
612095bfc6d8SJames Smart 
612178b2d852SJames Smart 		/* Setup hbqinfo */
612278b2d852SJames Smart 		snprintf(name, sizeof(name), "hbqinfo");
612378b2d852SJames Smart 		phba->debug_hbqinfo =
612463df6d63SJames Smart 			debugfs_create_file(name, S_IFREG | 0644,
612578b2d852SJames Smart 					    phba->hba_debugfs_root,
612678b2d852SJames Smart 					    phba, &lpfc_debugfs_op_hbqinfo);
612778b2d852SJames Smart 
61286a828b0fSJames Smart #ifdef LPFC_HDWQ_LOCK_STAT
61296a828b0fSJames Smart 		/* Setup lockstat */
61306a828b0fSJames Smart 		snprintf(name, sizeof(name), "lockstat");
61316a828b0fSJames Smart 		phba->debug_lockstat =
61325e5b511dSJames Smart 			debugfs_create_file(name, S_IFREG | 0644,
61335e5b511dSJames Smart 					    phba->hba_debugfs_root,
61346a828b0fSJames Smart 					    phba, &lpfc_debugfs_op_lockstat);
61357dcc683dSJinjie Ruan 		if (IS_ERR(phba->debug_lockstat)) {
61365e5b511dSJames Smart 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6137a9b83986SColin Ian King 					 "4610 Can't create debugfs lockstat\n");
61385e5b511dSJames Smart 			goto debug_failed;
61395e5b511dSJames Smart 		}
61406a828b0fSJames Smart #endif
61415e5b511dSJames Smart 
6142c95d6c6cSJames Smart 		/* Setup dumpHBASlim */
61432a622bfbSJames Smart 		if (phba->sli_rev < LPFC_SLI_REV4) {
6144c95d6c6cSJames Smart 			snprintf(name, sizeof(name), "dumpHBASlim");
6145c95d6c6cSJames Smart 			phba->debug_dumpHBASlim =
61462a622bfbSJames Smart 				debugfs_create_file(name,
61472a622bfbSJames Smart 					S_IFREG|S_IRUGO|S_IWUSR,
6148a58cbd52SJames Smart 					phba->hba_debugfs_root,
6149c95d6c6cSJames Smart 					phba, &lpfc_debugfs_op_dumpHBASlim);
61502a622bfbSJames Smart 		} else
61512a622bfbSJames Smart 			phba->debug_dumpHBASlim = NULL;
6152c95d6c6cSJames Smart 
6153c95d6c6cSJames Smart 		/* Setup dumpHostSlim */
61542a622bfbSJames Smart 		if (phba->sli_rev < LPFC_SLI_REV4) {
6155c95d6c6cSJames Smart 			snprintf(name, sizeof(name), "dumpHostSlim");
6156c95d6c6cSJames Smart 			phba->debug_dumpHostSlim =
61572a622bfbSJames Smart 				debugfs_create_file(name,
61582a622bfbSJames Smart 					S_IFREG|S_IRUGO|S_IWUSR,
6159c95d6c6cSJames Smart 					phba->hba_debugfs_root,
6160c95d6c6cSJames Smart 					phba, &lpfc_debugfs_op_dumpHostSlim);
61612a622bfbSJames Smart 		} else
6162b28d108bSFelipe Pena 			phba->debug_dumpHostSlim = NULL;
6163a58cbd52SJames Smart 
6164f9bb2da1SJames Smart 		/* Setup DIF Error Injections */
6165f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "InjErrLBA");
6166f9bb2da1SJames Smart 		phba->debug_InjErrLBA =
6167f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6168f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6169f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6170f9bb2da1SJames Smart 		phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
6171f9bb2da1SJames Smart 
61724ac9b226SJames Smart 		snprintf(name, sizeof(name), "InjErrNPortID");
61734ac9b226SJames Smart 		phba->debug_InjErrNPortID =
61744ac9b226SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
61754ac9b226SJames Smart 			phba->hba_debugfs_root,
61764ac9b226SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
61774ac9b226SJames Smart 
61784ac9b226SJames Smart 		snprintf(name, sizeof(name), "InjErrWWPN");
61794ac9b226SJames Smart 		phba->debug_InjErrWWPN =
61804ac9b226SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
61814ac9b226SJames Smart 			phba->hba_debugfs_root,
61824ac9b226SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
61834ac9b226SJames Smart 
6184f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "writeGuardInjErr");
6185f9bb2da1SJames Smart 		phba->debug_writeGuard =
6186f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6187f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6188f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6189f9bb2da1SJames Smart 
6190f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "writeAppInjErr");
6191f9bb2da1SJames Smart 		phba->debug_writeApp =
6192f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6193f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6194f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6195f9bb2da1SJames Smart 
6196f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "writeRefInjErr");
6197f9bb2da1SJames Smart 		phba->debug_writeRef =
6198f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6199f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6200f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6201f9bb2da1SJames Smart 
6202acd6859bSJames Smart 		snprintf(name, sizeof(name), "readGuardInjErr");
6203acd6859bSJames Smart 		phba->debug_readGuard =
6204acd6859bSJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6205acd6859bSJames Smart 			phba->hba_debugfs_root,
6206acd6859bSJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6207acd6859bSJames Smart 
6208f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "readAppInjErr");
6209f9bb2da1SJames Smart 		phba->debug_readApp =
6210f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6211f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6212f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6213f9bb2da1SJames Smart 
6214f9bb2da1SJames Smart 		snprintf(name, sizeof(name), "readRefInjErr");
6215f9bb2da1SJames Smart 		phba->debug_readRef =
6216f9bb2da1SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6217f9bb2da1SJames Smart 			phba->hba_debugfs_root,
6218f9bb2da1SJames Smart 			phba, &lpfc_debugfs_op_dif_err);
6219f9bb2da1SJames Smart 
6220a58cbd52SJames Smart 		/* Setup slow ring trace */
6221a58cbd52SJames Smart 		if (lpfc_debugfs_max_slow_ring_trc) {
6222a58cbd52SJames Smart 			num = lpfc_debugfs_max_slow_ring_trc - 1;
6223a58cbd52SJames Smart 			if (num & lpfc_debugfs_max_slow_ring_trc) {
6224a58cbd52SJames Smart 				/* Change to be a power of 2 */
6225a58cbd52SJames Smart 				num = lpfc_debugfs_max_slow_ring_trc;
6226a58cbd52SJames Smart 				i = 0;
6227a58cbd52SJames Smart 				while (num > 1) {
6228a58cbd52SJames Smart 					num = num >> 1;
6229a58cbd52SJames Smart 					i++;
6230a58cbd52SJames Smart 				}
6231a58cbd52SJames Smart 				lpfc_debugfs_max_slow_ring_trc = (1 << i);
62322ea259eeSJames Smart 				pr_err("lpfc_debugfs_max_disc_trc changed to "
6233e8b62011SJames Smart 				       "%d\n", lpfc_debugfs_max_disc_trc);
6234a58cbd52SJames Smart 			}
6235a58cbd52SJames Smart 		}
6236a58cbd52SJames Smart 
6237a58cbd52SJames Smart 		snprintf(name, sizeof(name), "slow_ring_trace");
6238a58cbd52SJames Smart 		phba->debug_slow_ring_trc =
6239a58cbd52SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6240a58cbd52SJames Smart 				 phba->hba_debugfs_root,
6241a58cbd52SJames Smart 				 phba, &lpfc_debugfs_op_slow_ring_trc);
6242a58cbd52SJames Smart 		if (!phba->slow_ring_trc) {
6243dc264641SJulia Lawall 			phba->slow_ring_trc = kcalloc(
6244dc264641SJulia Lawall 				lpfc_debugfs_max_slow_ring_trc,
6245dc264641SJulia Lawall 				sizeof(struct lpfc_debugfs_trc),
6246a58cbd52SJames Smart 				GFP_KERNEL);
6247a58cbd52SJames Smart 			if (!phba->slow_ring_trc) {
6248e8b62011SJames Smart 				lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6249d7c255b2SJames Smart 						 "0416 Cannot create debugfs "
6250e8b62011SJames Smart 						 "slow_ring buffer\n");
6251a58cbd52SJames Smart 				goto debug_failed;
6252a58cbd52SJames Smart 			}
6253a58cbd52SJames Smart 			atomic_set(&phba->slow_ring_trc_cnt, 0);
6254a58cbd52SJames Smart 		}
62552ea259eeSJames Smart 
6256bd2cdd5eSJames Smart 		snprintf(name, sizeof(name), "nvmeio_trc");
6257bd2cdd5eSJames Smart 		phba->debug_nvmeio_trc =
6258bd2cdd5eSJames Smart 			debugfs_create_file(name, 0644,
6259bd2cdd5eSJames Smart 					    phba->hba_debugfs_root,
6260bd2cdd5eSJames Smart 					    phba, &lpfc_debugfs_op_nvmeio_trc);
6261bd2cdd5eSJames Smart 
6262bd2cdd5eSJames Smart 		atomic_set(&phba->nvmeio_trc_cnt, 0);
6263bd2cdd5eSJames Smart 		if (lpfc_debugfs_max_nvmeio_trc) {
6264bd2cdd5eSJames Smart 			num = lpfc_debugfs_max_nvmeio_trc - 1;
6265bd2cdd5eSJames Smart 			if (num & lpfc_debugfs_max_disc_trc) {
6266bd2cdd5eSJames Smart 				/* Change to be a power of 2 */
6267bd2cdd5eSJames Smart 				num = lpfc_debugfs_max_nvmeio_trc;
6268bd2cdd5eSJames Smart 				i = 0;
6269bd2cdd5eSJames Smart 				while (num > 1) {
6270bd2cdd5eSJames Smart 					num = num >> 1;
6271bd2cdd5eSJames Smart 					i++;
6272bd2cdd5eSJames Smart 				}
6273bd2cdd5eSJames Smart 				lpfc_debugfs_max_nvmeio_trc = (1 << i);
6274bd2cdd5eSJames Smart 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
6275bd2cdd5eSJames Smart 						"0575 lpfc_debugfs_max_nvmeio_trc "
6276bd2cdd5eSJames Smart 						"changed to %d\n",
6277bd2cdd5eSJames Smart 						lpfc_debugfs_max_nvmeio_trc);
6278bd2cdd5eSJames Smart 			}
6279bd2cdd5eSJames Smart 			phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc;
6280bd2cdd5eSJames Smart 
6281bd2cdd5eSJames Smart 			/* Allocate trace buffer and initialize */
62821c356ec5SVasyl Gomonovych 			phba->nvmeio_trc = kzalloc(
6283bd2cdd5eSJames Smart 				(sizeof(struct lpfc_debugfs_nvmeio_trc) *
6284bd2cdd5eSJames Smart 				phba->nvmeio_trc_size), GFP_KERNEL);
6285bd2cdd5eSJames Smart 
6286bd2cdd5eSJames Smart 			if (!phba->nvmeio_trc) {
6287bd2cdd5eSJames Smart 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
6288bd2cdd5eSJames Smart 						"0576 Cannot create debugfs "
6289bd2cdd5eSJames Smart 						"nvmeio_trc buffer\n");
6290bd2cdd5eSJames Smart 				goto nvmeio_off;
6291bd2cdd5eSJames Smart 			}
6292bd2cdd5eSJames Smart 			phba->nvmeio_trc_on = 1;
6293bd2cdd5eSJames Smart 			phba->nvmeio_trc_output_idx = 0;
6294bd2cdd5eSJames Smart 			phba->nvmeio_trc = NULL;
6295bd2cdd5eSJames Smart 		} else {
6296bd2cdd5eSJames Smart nvmeio_off:
6297bd2cdd5eSJames Smart 			phba->nvmeio_trc_size = 0;
6298bd2cdd5eSJames Smart 			phba->nvmeio_trc_on = 0;
6299bd2cdd5eSJames Smart 			phba->nvmeio_trc_output_idx = 0;
6300bd2cdd5eSJames Smart 			phba->nvmeio_trc = NULL;
6301bd2cdd5eSJames Smart 		}
6302a58cbd52SJames Smart 	}
6303a58cbd52SJames Smart 
6304a58cbd52SJames Smart 	snprintf(name, sizeof(name), "vport%d", vport->vpi);
6305a58cbd52SJames Smart 	if (!vport->vport_debugfs_root) {
6306a58cbd52SJames Smart 		vport->vport_debugfs_root =
6307a58cbd52SJames Smart 			debugfs_create_dir(name, phba->hba_debugfs_root);
6308a58cbd52SJames Smart 		atomic_inc(&phba->debugfs_vport_count);
6309a58cbd52SJames Smart 	}
6310a58cbd52SJames Smart 
6311858c9f6cSJames Smart 	if (lpfc_debugfs_max_disc_trc) {
6312858c9f6cSJames Smart 		num = lpfc_debugfs_max_disc_trc - 1;
6313858c9f6cSJames Smart 		if (num & lpfc_debugfs_max_disc_trc) {
6314858c9f6cSJames Smart 			/* Change to be a power of 2 */
6315858c9f6cSJames Smart 			num = lpfc_debugfs_max_disc_trc;
6316858c9f6cSJames Smart 			i = 0;
6317858c9f6cSJames Smart 			while (num > 1) {
6318858c9f6cSJames Smart 				num = num >> 1;
6319858c9f6cSJames Smart 				i++;
6320858c9f6cSJames Smart 			}
6321858c9f6cSJames Smart 			lpfc_debugfs_max_disc_trc = (1 << i);
63222ea259eeSJames Smart 			pr_err("lpfc_debugfs_max_disc_trc changed to %d\n",
6323858c9f6cSJames Smart 			       lpfc_debugfs_max_disc_trc);
6324858c9f6cSJames Smart 		}
6325858c9f6cSJames Smart 	}
6326858c9f6cSJames Smart 
6327ff86ba59SAdrian Bunk 	vport->disc_trc = kzalloc(
6328a58cbd52SJames Smart 		(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
6329858c9f6cSJames Smart 		GFP_KERNEL);
6330858c9f6cSJames Smart 
6331a58cbd52SJames Smart 	if (!vport->disc_trc) {
6332e8b62011SJames Smart 		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6333d7c255b2SJames Smart 				 "0418 Cannot create debugfs disc trace "
6334e8b62011SJames Smart 				 "buffer\n");
6335858c9f6cSJames Smart 		goto debug_failed;
6336a58cbd52SJames Smart 	}
6337a58cbd52SJames Smart 	atomic_set(&vport->disc_trc_cnt, 0);
6338858c9f6cSJames Smart 
6339858c9f6cSJames Smart 	snprintf(name, sizeof(name), "discovery_trace");
6340858c9f6cSJames Smart 	vport->debug_disc_trc =
6341858c9f6cSJames Smart 		debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6342858c9f6cSJames Smart 				 vport->vport_debugfs_root,
6343858c9f6cSJames Smart 				 vport, &lpfc_debugfs_op_disc_trc);
6344858c9f6cSJames Smart 	snprintf(name, sizeof(name), "nodelist");
6345858c9f6cSJames Smart 	vport->debug_nodelist =
6346858c9f6cSJames Smart 		debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6347858c9f6cSJames Smart 				 vport->vport_debugfs_root,
6348858c9f6cSJames Smart 				 vport, &lpfc_debugfs_op_nodelist);
63492a622bfbSJames Smart 
6350bd2cdd5eSJames Smart 	snprintf(name, sizeof(name), "nvmestat");
6351bd2cdd5eSJames Smart 	vport->debug_nvmestat =
6352bd2cdd5eSJames Smart 		debugfs_create_file(name, 0644,
6353bd2cdd5eSJames Smart 				    vport->vport_debugfs_root,
6354bd2cdd5eSJames Smart 				    vport, &lpfc_debugfs_op_nvmestat);
6355bd2cdd5eSJames Smart 
63564c47efc1SJames Smart 	snprintf(name, sizeof(name), "scsistat");
63574c47efc1SJames Smart 	vport->debug_scsistat =
63584c47efc1SJames Smart 		debugfs_create_file(name, 0644,
63594c47efc1SJames Smart 				    vport->vport_debugfs_root,
63604c47efc1SJames Smart 				    vport, &lpfc_debugfs_op_scsistat);
63617dcc683dSJinjie Ruan 	if (IS_ERR(vport->debug_scsistat)) {
63624c47efc1SJames Smart 		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
6363c835c085SJames Smart 				 "4611 Cannot create debugfs scsistat\n");
63644c47efc1SJames Smart 		goto debug_failed;
63654c47efc1SJames Smart 	}
63664c47efc1SJames Smart 
63672fcbc569SJames Smart 	snprintf(name, sizeof(name), "ioktime");
63682fcbc569SJames Smart 	vport->debug_ioktime =
6369bd2cdd5eSJames Smart 		debugfs_create_file(name, 0644,
6370bd2cdd5eSJames Smart 				    vport->vport_debugfs_root,
63712fcbc569SJames Smart 				    vport, &lpfc_debugfs_op_ioktime);
63727dcc683dSJinjie Ruan 	if (IS_ERR(vport->debug_ioktime)) {
63732fcbc569SJames Smart 		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
63742fcbc569SJames Smart 				 "0815 Cannot create debugfs ioktime\n");
63752fcbc569SJames Smart 		goto debug_failed;
63762fcbc569SJames Smart 	}
6377bd2cdd5eSJames Smart 
6378840eda96SJames Smart 	snprintf(name, sizeof(name), "hdwqstat");
6379840eda96SJames Smart 	vport->debug_hdwqstat =
6380bd2cdd5eSJames Smart 		debugfs_create_file(name, 0644,
6381bd2cdd5eSJames Smart 				    vport->vport_debugfs_root,
6382840eda96SJames Smart 				    vport, &lpfc_debugfs_op_hdwqstat);
6383bd2cdd5eSJames Smart 
63842a622bfbSJames Smart 	/*
6385f6c3bdfbSJames Smart 	 * The following section is for additional directories/files for the
6386f6c3bdfbSJames Smart 	 * physical port.
6387f6c3bdfbSJames Smart 	 */
6388f6c3bdfbSJames Smart 
6389f6c3bdfbSJames Smart 	if (!pport_setup)
6390f6c3bdfbSJames Smart 		goto debug_failed;
6391f6c3bdfbSJames Smart 
6392f6c3bdfbSJames Smart 	/*
63932a622bfbSJames Smart 	 * iDiag debugfs root entry points for SLI4 device only
63942a622bfbSJames Smart 	 */
63952a622bfbSJames Smart 	if (phba->sli_rev < LPFC_SLI_REV4)
63962a622bfbSJames Smart 		goto debug_failed;
63972a622bfbSJames Smart 
63982a622bfbSJames Smart 	snprintf(name, sizeof(name), "iDiag");
63992a622bfbSJames Smart 	if (!phba->idiag_root) {
64002a622bfbSJames Smart 		phba->idiag_root =
64012a622bfbSJames Smart 			debugfs_create_dir(name, phba->hba_debugfs_root);
64022a622bfbSJames Smart 		/* Initialize iDiag data structure */
64032a622bfbSJames Smart 		memset(&idiag, 0, sizeof(idiag));
64042a622bfbSJames Smart 	}
64052a622bfbSJames Smart 
64062a622bfbSJames Smart 	/* iDiag read PCI config space */
64072a622bfbSJames Smart 	snprintf(name, sizeof(name), "pciCfg");
64082a622bfbSJames Smart 	if (!phba->idiag_pci_cfg) {
64092a622bfbSJames Smart 		phba->idiag_pci_cfg =
64102a622bfbSJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
64112a622bfbSJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_pciCfg);
64122a622bfbSJames Smart 		idiag.offset.last_rd = 0;
64132a622bfbSJames Smart 	}
64142a622bfbSJames Smart 
6415b76f2dc9SJames Smart 	/* iDiag PCI BAR access */
6416b76f2dc9SJames Smart 	snprintf(name, sizeof(name), "barAcc");
6417b76f2dc9SJames Smart 	if (!phba->idiag_bar_acc) {
6418b76f2dc9SJames Smart 		phba->idiag_bar_acc =
6419b76f2dc9SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6420b76f2dc9SJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_barAcc);
6421b76f2dc9SJames Smart 		idiag.offset.last_rd = 0;
6422b76f2dc9SJames Smart 	}
6423b76f2dc9SJames Smart 
64242a622bfbSJames Smart 	/* iDiag get PCI function queue information */
64252a622bfbSJames Smart 	snprintf(name, sizeof(name), "queInfo");
64262a622bfbSJames Smart 	if (!phba->idiag_que_info) {
64272a622bfbSJames Smart 		phba->idiag_que_info =
64282a622bfbSJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO,
64292a622bfbSJames Smart 			phba->idiag_root, phba, &lpfc_idiag_op_queInfo);
64302a622bfbSJames Smart 	}
64312a622bfbSJames Smart 
643286a80846SJames Smart 	/* iDiag access PCI function queue */
643386a80846SJames Smart 	snprintf(name, sizeof(name), "queAcc");
643486a80846SJames Smart 	if (!phba->idiag_que_acc) {
643586a80846SJames Smart 		phba->idiag_que_acc =
643686a80846SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
643786a80846SJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_queAcc);
643886a80846SJames Smart 	}
643986a80846SJames Smart 
644086a80846SJames Smart 	/* iDiag access PCI function doorbell registers */
644186a80846SJames Smart 	snprintf(name, sizeof(name), "drbAcc");
644286a80846SJames Smart 	if (!phba->idiag_drb_acc) {
644386a80846SJames Smart 		phba->idiag_drb_acc =
644486a80846SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
644586a80846SJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_drbAcc);
644686a80846SJames Smart 	}
644786a80846SJames Smart 
6448b76f2dc9SJames Smart 	/* iDiag access PCI function control registers */
6449b76f2dc9SJames Smart 	snprintf(name, sizeof(name), "ctlAcc");
6450b76f2dc9SJames Smart 	if (!phba->idiag_ctl_acc) {
6451b76f2dc9SJames Smart 		phba->idiag_ctl_acc =
6452b76f2dc9SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6453b76f2dc9SJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc);
6454b76f2dc9SJames Smart 	}
6455b76f2dc9SJames Smart 
6456b76f2dc9SJames Smart 	/* iDiag access mbox commands */
6457b76f2dc9SJames Smart 	snprintf(name, sizeof(name), "mbxAcc");
6458b76f2dc9SJames Smart 	if (!phba->idiag_mbx_acc) {
6459b76f2dc9SJames Smart 		phba->idiag_mbx_acc =
6460b76f2dc9SJames Smart 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
6461b76f2dc9SJames Smart 				phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc);
6462b76f2dc9SJames Smart 	}
6463b76f2dc9SJames Smart 
6464b76f2dc9SJames Smart 	/* iDiag extents access commands */
6465b76f2dc9SJames Smart 	if (phba->sli4_hba.extents_in_use) {
6466b76f2dc9SJames Smart 		snprintf(name, sizeof(name), "extAcc");
6467b76f2dc9SJames Smart 		if (!phba->idiag_ext_acc) {
6468b76f2dc9SJames Smart 			phba->idiag_ext_acc =
6469b76f2dc9SJames Smart 				debugfs_create_file(name,
6470b76f2dc9SJames Smart 						    S_IFREG|S_IRUGO|S_IWUSR,
6471b76f2dc9SJames Smart 						    phba->idiag_root, phba,
6472b76f2dc9SJames Smart 						    &lpfc_idiag_op_extAcc);
6473b76f2dc9SJames Smart 		}
6474b76f2dc9SJames Smart 	}
6475b76f2dc9SJames Smart 
6476858c9f6cSJames Smart debug_failed:
6477858c9f6cSJames Smart 	return;
6478858c9f6cSJames Smart #endif
6479858c9f6cSJames Smart }
6480858c9f6cSJames Smart 
6481e59058c4SJames Smart /**
64823621a710SJames Smart  * lpfc_debugfs_terminate -  Tear down debugfs infrastructure for this vport
6483e59058c4SJames Smart  * @vport: The vport pointer to remove from debugfs.
6484e59058c4SJames Smart  *
6485e59058c4SJames Smart  * Description:
6486e59058c4SJames Smart  * When Debugfs is configured this routine removes debugfs file system elements
6487e59058c4SJames Smart  * that are specific to this vport. It also checks to see if there are any
6488e59058c4SJames Smart  * users left for the debugfs directories associated with the HBA and driver. If
6489e59058c4SJames Smart  * this is the last user of the HBA directory or driver directory then it will
6490e59058c4SJames Smart  * remove those from the debugfs infrastructure as well.
6491e59058c4SJames Smart  **/
6492858c9f6cSJames Smart inline void
lpfc_debugfs_terminate(struct lpfc_vport * vport)6493858c9f6cSJames Smart lpfc_debugfs_terminate(struct lpfc_vport *vport)
6494858c9f6cSJames Smart {
6495923e4b6aSJames Smart #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
6496858c9f6cSJames Smart 	struct lpfc_hba   *phba = vport->phba;
6497858c9f6cSJames Smart 
6498858c9f6cSJames Smart 	kfree(vport->disc_trc);
6499858c9f6cSJames Smart 	vport->disc_trc = NULL;
6500bd2cdd5eSJames Smart 
6501858c9f6cSJames Smart 	debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
6502858c9f6cSJames Smart 	vport->debug_disc_trc = NULL;
6503bd2cdd5eSJames Smart 
6504858c9f6cSJames Smart 	debugfs_remove(vport->debug_nodelist); /* nodelist */
6505858c9f6cSJames Smart 	vport->debug_nodelist = NULL;
6506bd2cdd5eSJames Smart 
6507bd2cdd5eSJames Smart 	debugfs_remove(vport->debug_nvmestat); /* nvmestat */
6508bd2cdd5eSJames Smart 	vport->debug_nvmestat = NULL;
6509bd2cdd5eSJames Smart 
65104c47efc1SJames Smart 	debugfs_remove(vport->debug_scsistat); /* scsistat */
65114c47efc1SJames Smart 	vport->debug_scsistat = NULL;
65124c47efc1SJames Smart 
65132fcbc569SJames Smart 	debugfs_remove(vport->debug_ioktime); /* ioktime */
65142fcbc569SJames Smart 	vport->debug_ioktime = NULL;
6515bd2cdd5eSJames Smart 
6516840eda96SJames Smart 	debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */
6517840eda96SJames Smart 	vport->debug_hdwqstat = NULL;
6518bd2cdd5eSJames Smart 
6519858c9f6cSJames Smart 	if (vport->vport_debugfs_root) {
6520858c9f6cSJames Smart 		debugfs_remove(vport->vport_debugfs_root); /* vportX */
6521858c9f6cSJames Smart 		vport->vport_debugfs_root = NULL;
6522858c9f6cSJames Smart 		atomic_dec(&phba->debugfs_vport_count);
6523858c9f6cSJames Smart 	}
6524bd2cdd5eSJames Smart 
6525858c9f6cSJames Smart 	if (atomic_read(&phba->debugfs_vport_count) == 0) {
6526a58cbd52SJames Smart 
6527c490850aSJames Smart 		debugfs_remove(phba->debug_multixri_pools); /* multixripools*/
6528c490850aSJames Smart 		phba->debug_multixri_pools = NULL;
6529c490850aSJames Smart 
653078b2d852SJames Smart 		debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
653178b2d852SJames Smart 		phba->debug_hbqinfo = NULL;
6532bd2cdd5eSJames Smart 
65339f778708SJames Smart 		debugfs_remove(phba->debug_cgn_buffer);
65349f778708SJames Smart 		phba->debug_cgn_buffer = NULL;
65359f778708SJames Smart 
65369f778708SJames Smart 		debugfs_remove(phba->debug_rx_monitor);
65379f778708SJames Smart 		phba->debug_rx_monitor = NULL;
65389f778708SJames Smart 
653995bfc6d8SJames Smart 		debugfs_remove(phba->debug_ras_log);
654095bfc6d8SJames Smart 		phba->debug_ras_log = NULL;
654195bfc6d8SJames Smart 
65426a828b0fSJames Smart #ifdef LPFC_HDWQ_LOCK_STAT
65436a828b0fSJames Smart 		debugfs_remove(phba->debug_lockstat); /* lockstat */
65446a828b0fSJames Smart 		phba->debug_lockstat = NULL;
65456a828b0fSJames Smart #endif
6546c95d6c6cSJames Smart 		debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
6547c95d6c6cSJames Smart 		phba->debug_dumpHBASlim = NULL;
6548bd2cdd5eSJames Smart 
6549c95d6c6cSJames Smart 		debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
6550c95d6c6cSJames Smart 		phba->debug_dumpHostSlim = NULL;
6551bd2cdd5eSJames Smart 
6552f9bb2da1SJames Smart 		debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */
6553f9bb2da1SJames Smart 		phba->debug_InjErrLBA = NULL;
6554bd2cdd5eSJames Smart 
65554ac9b226SJames Smart 		debugfs_remove(phba->debug_InjErrNPortID);
65564ac9b226SJames Smart 		phba->debug_InjErrNPortID = NULL;
6557bd2cdd5eSJames Smart 
65584ac9b226SJames Smart 		debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */
65594ac9b226SJames Smart 		phba->debug_InjErrWWPN = NULL;
6560bd2cdd5eSJames Smart 
6561f9bb2da1SJames Smart 		debugfs_remove(phba->debug_writeGuard); /* writeGuard */
6562f9bb2da1SJames Smart 		phba->debug_writeGuard = NULL;
6563bd2cdd5eSJames Smart 
6564f9bb2da1SJames Smart 		debugfs_remove(phba->debug_writeApp); /* writeApp */
6565f9bb2da1SJames Smart 		phba->debug_writeApp = NULL;
6566bd2cdd5eSJames Smart 
6567f9bb2da1SJames Smart 		debugfs_remove(phba->debug_writeRef); /* writeRef */
6568f9bb2da1SJames Smart 		phba->debug_writeRef = NULL;
6569bd2cdd5eSJames Smart 
6570acd6859bSJames Smart 		debugfs_remove(phba->debug_readGuard); /* readGuard */
6571acd6859bSJames Smart 		phba->debug_readGuard = NULL;
6572bd2cdd5eSJames Smart 
6573f9bb2da1SJames Smart 		debugfs_remove(phba->debug_readApp); /* readApp */
6574f9bb2da1SJames Smart 		phba->debug_readApp = NULL;
6575bd2cdd5eSJames Smart 
6576f9bb2da1SJames Smart 		debugfs_remove(phba->debug_readRef); /* readRef */
6577f9bb2da1SJames Smart 		phba->debug_readRef = NULL;
6578e2a0a9d6SJames Smart 
6579a58cbd52SJames Smart 		kfree(phba->slow_ring_trc);
6580a58cbd52SJames Smart 		phba->slow_ring_trc = NULL;
6581bd2cdd5eSJames Smart 
6582a58cbd52SJames Smart 		/* slow_ring_trace */
6583a58cbd52SJames Smart 		debugfs_remove(phba->debug_slow_ring_trc);
6584a58cbd52SJames Smart 		phba->debug_slow_ring_trc = NULL;
6585bd2cdd5eSJames Smart 
6586bd2cdd5eSJames Smart 		debugfs_remove(phba->debug_nvmeio_trc);
6587bd2cdd5eSJames Smart 		phba->debug_nvmeio_trc = NULL;
6588bd2cdd5eSJames Smart 
6589bd2cdd5eSJames Smart 		kfree(phba->nvmeio_trc);
6590bd2cdd5eSJames Smart 		phba->nvmeio_trc = NULL;
6591a58cbd52SJames Smart 
65922a622bfbSJames Smart 		/*
65932a622bfbSJames Smart 		 * iDiag release
65942a622bfbSJames Smart 		 */
65952a622bfbSJames Smart 		if (phba->sli_rev == LPFC_SLI_REV4) {
6596b76f2dc9SJames Smart 			/* iDiag extAcc */
6597b76f2dc9SJames Smart 			debugfs_remove(phba->idiag_ext_acc);
6598b76f2dc9SJames Smart 			phba->idiag_ext_acc = NULL;
6599bd2cdd5eSJames Smart 
6600b76f2dc9SJames Smart 			/* iDiag mbxAcc */
6601b76f2dc9SJames Smart 			debugfs_remove(phba->idiag_mbx_acc);
6602b76f2dc9SJames Smart 			phba->idiag_mbx_acc = NULL;
6603bd2cdd5eSJames Smart 
6604b76f2dc9SJames Smart 			/* iDiag ctlAcc */
6605b76f2dc9SJames Smart 			debugfs_remove(phba->idiag_ctl_acc);
6606b76f2dc9SJames Smart 			phba->idiag_ctl_acc = NULL;
6607bd2cdd5eSJames Smart 
660886a80846SJames Smart 			/* iDiag drbAcc */
660986a80846SJames Smart 			debugfs_remove(phba->idiag_drb_acc);
661086a80846SJames Smart 			phba->idiag_drb_acc = NULL;
6611bd2cdd5eSJames Smart 
661286a80846SJames Smart 			/* iDiag queAcc */
661386a80846SJames Smart 			debugfs_remove(phba->idiag_que_acc);
661486a80846SJames Smart 			phba->idiag_que_acc = NULL;
6615bd2cdd5eSJames Smart 
66162a622bfbSJames Smart 			/* iDiag queInfo */
66172a622bfbSJames Smart 			debugfs_remove(phba->idiag_que_info);
66182a622bfbSJames Smart 			phba->idiag_que_info = NULL;
6619bd2cdd5eSJames Smart 
6620b76f2dc9SJames Smart 			/* iDiag barAcc */
6621b76f2dc9SJames Smart 			debugfs_remove(phba->idiag_bar_acc);
6622b76f2dc9SJames Smart 			phba->idiag_bar_acc = NULL;
6623bd2cdd5eSJames Smart 
66242a622bfbSJames Smart 			/* iDiag pciCfg */
66252a622bfbSJames Smart 			debugfs_remove(phba->idiag_pci_cfg);
66262a622bfbSJames Smart 			phba->idiag_pci_cfg = NULL;
66272a622bfbSJames Smart 
66282a622bfbSJames Smart 			/* Finally remove the iDiag debugfs root */
66292a622bfbSJames Smart 			debugfs_remove(phba->idiag_root);
66302a622bfbSJames Smart 			phba->idiag_root = NULL;
66312a622bfbSJames Smart 		}
66322a622bfbSJames Smart 
6633a58cbd52SJames Smart 		if (phba->hba_debugfs_root) {
66342a622bfbSJames Smart 			debugfs_remove(phba->hba_debugfs_root); /* fnX */
6635a58cbd52SJames Smart 			phba->hba_debugfs_root = NULL;
6636858c9f6cSJames Smart 			atomic_dec(&lpfc_debugfs_hba_count);
6637a58cbd52SJames Smart 		}
6638a58cbd52SJames Smart 
6639667a7662SJames Smart 		if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
6640858c9f6cSJames Smart 			debugfs_remove(lpfc_debugfs_root); /* lpfc */
6641858c9f6cSJames Smart 			lpfc_debugfs_root = NULL;
6642858c9f6cSJames Smart 		}
6643667a7662SJames Smart 	}
6644858c9f6cSJames Smart #endif
6645a58cbd52SJames Smart 	return;
6646858c9f6cSJames Smart }
6647809c7536SJames Smart 
6648809c7536SJames Smart /*
6649809c7536SJames Smart  * Driver debug utility routines outside of debugfs. The debug utility
6650809c7536SJames Smart  * routines implemented here is intended to be used in the instrumented
6651809c7536SJames Smart  * debug driver for debugging host or port issues.
6652809c7536SJames Smart  */
6653809c7536SJames Smart 
6654809c7536SJames Smart /**
6655809c7536SJames Smart  * lpfc_debug_dump_all_queues - dump all the queues with a hba
6656809c7536SJames Smart  * @phba: Pointer to HBA context object.
6657809c7536SJames Smart  *
6658809c7536SJames Smart  * This function dumps entries of all the queues asociated with the @phba.
6659809c7536SJames Smart  **/
6660809c7536SJames Smart void
lpfc_debug_dump_all_queues(struct lpfc_hba * phba)6661809c7536SJames Smart lpfc_debug_dump_all_queues(struct lpfc_hba *phba)
6662809c7536SJames Smart {
66631d9d5a98SJames Smart 	int idx;
6664809c7536SJames Smart 
6665809c7536SJames Smart 	/*
6666809c7536SJames Smart 	 * Dump Work Queues (WQs)
6667809c7536SJames Smart 	 */
66681d9d5a98SJames Smart 	lpfc_debug_dump_wq(phba, DUMP_MBX, 0);
66691d9d5a98SJames Smart 	lpfc_debug_dump_wq(phba, DUMP_ELS, 0);
6670895427bdSJames Smart 	lpfc_debug_dump_wq(phba, DUMP_NVMELS, 0);
6671809c7536SJames Smart 
6672cdb42becSJames Smart 	for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
6673c00f62e6SJames Smart 		lpfc_debug_dump_wq(phba, DUMP_IO, idx);
6674895427bdSJames Smart 
6675809c7536SJames Smart 	lpfc_debug_dump_hdr_rq(phba);
6676809c7536SJames Smart 	lpfc_debug_dump_dat_rq(phba);
6677809c7536SJames Smart 	/*
6678809c7536SJames Smart 	 * Dump Complete Queues (CQs)
6679809c7536SJames Smart 	 */
66801d9d5a98SJames Smart 	lpfc_debug_dump_cq(phba, DUMP_MBX, 0);
66811d9d5a98SJames Smart 	lpfc_debug_dump_cq(phba, DUMP_ELS, 0);
6682895427bdSJames Smart 	lpfc_debug_dump_cq(phba, DUMP_NVMELS, 0);
6683809c7536SJames Smart 
6684cdb42becSJames Smart 	for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
6685c00f62e6SJames Smart 		lpfc_debug_dump_cq(phba, DUMP_IO, idx);
6686895427bdSJames Smart 
6687809c7536SJames Smart 	/*
6688809c7536SJames Smart 	 * Dump Event Queues (EQs)
6689809c7536SJames Smart 	 */
6690cdb42becSJames Smart 	for (idx = 0; idx < phba->cfg_hdw_queue; idx++)
66911d9d5a98SJames Smart 		lpfc_debug_dump_hba_eq(phba, idx);
6692809c7536SJames Smart }
6693