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