162306a36Sopenharmony_ci/******************************************************************* 262306a36Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for * 362306a36Sopenharmony_ci * Fibre Channel Host Bus Adapters. * 462306a36Sopenharmony_ci * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * 562306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * 662306a36Sopenharmony_ci * Copyright (C) 2007-2015 Emulex. All rights reserved. * 762306a36Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex. * 862306a36Sopenharmony_ci * www.broadcom.com * 962306a36Sopenharmony_ci * * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or * 1162306a36Sopenharmony_ci * modify it under the terms of version 2 of the GNU General * 1262306a36Sopenharmony_ci * Public License as published by the Free Software Foundation. * 1362306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful. * 1462306a36Sopenharmony_ci * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 1562306a36Sopenharmony_ci * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 1762306a36Sopenharmony_ci * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 1862306a36Sopenharmony_ci * TO BE LEGALLY INVALID. See the GNU General Public License for * 1962306a36Sopenharmony_ci * more details, a copy of which can be found in the file COPYING * 2062306a36Sopenharmony_ci * included with this package. * 2162306a36Sopenharmony_ci *******************************************************************/ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/blkdev.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2762306a36Sopenharmony_ci#include <linux/idr.h> 2862306a36Sopenharmony_ci#include <linux/interrupt.h> 2962306a36Sopenharmony_ci#include <linux/kthread.h> 3062306a36Sopenharmony_ci#include <linux/slab.h> 3162306a36Sopenharmony_ci#include <linux/pci.h> 3262306a36Sopenharmony_ci#include <linux/spinlock.h> 3362306a36Sopenharmony_ci#include <linux/ctype.h> 3462306a36Sopenharmony_ci#include <linux/vmalloc.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <scsi/scsi.h> 3762306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3862306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3962306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 4062306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "lpfc_hw4.h" 4362306a36Sopenharmony_ci#include "lpfc_hw.h" 4462306a36Sopenharmony_ci#include "lpfc_sli.h" 4562306a36Sopenharmony_ci#include "lpfc_sli4.h" 4662306a36Sopenharmony_ci#include "lpfc_nl.h" 4762306a36Sopenharmony_ci#include "lpfc_disc.h" 4862306a36Sopenharmony_ci#include "lpfc.h" 4962306a36Sopenharmony_ci#include "lpfc_scsi.h" 5062306a36Sopenharmony_ci#include "lpfc_nvme.h" 5162306a36Sopenharmony_ci#include "lpfc_logmsg.h" 5262306a36Sopenharmony_ci#include "lpfc_crtn.h" 5362306a36Sopenharmony_ci#include "lpfc_vport.h" 5462306a36Sopenharmony_ci#include "lpfc_version.h" 5562306a36Sopenharmony_ci#include "lpfc_compat.h" 5662306a36Sopenharmony_ci#include "lpfc_debugfs.h" 5762306a36Sopenharmony_ci#include "lpfc_bsg.h" 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * debugfs interface 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * To access this interface the user should: 6462306a36Sopenharmony_ci * # mount -t debugfs none /sys/kernel/debug 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * The lpfc debugfs directory hierarchy is: 6762306a36Sopenharmony_ci * /sys/kernel/debug/lpfc/fnX/vportY 6862306a36Sopenharmony_ci * where X is the lpfc hba function unique_id 6962306a36Sopenharmony_ci * where Y is the vport VPI on that hba 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Debugging services available per vport: 7262306a36Sopenharmony_ci * discovery_trace 7362306a36Sopenharmony_ci * This is an ACSII readable file that contains a trace of the last 7462306a36Sopenharmony_ci * lpfc_debugfs_max_disc_trc events that happened on a specific vport. 7562306a36Sopenharmony_ci * See lpfc_debugfs.h for different categories of discovery events. 7662306a36Sopenharmony_ci * To enable the discovery trace, the following module parameters must be set: 7762306a36Sopenharmony_ci * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support 7862306a36Sopenharmony_ci * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for 7962306a36Sopenharmony_ci * EACH vport. X MUST also be a power of 2. 8062306a36Sopenharmony_ci * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in 8162306a36Sopenharmony_ci * lpfc_debugfs.h . 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * slow_ring_trace 8462306a36Sopenharmony_ci * This is an ACSII readable file that contains a trace of the last 8562306a36Sopenharmony_ci * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA. 8662306a36Sopenharmony_ci * To enable the slow ring trace, the following module parameters must be set: 8762306a36Sopenharmony_ci * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support 8862306a36Sopenharmony_ci * lpfc_debugfs_max_slow_ring_trc=X Where X is the event trace depth for 8962306a36Sopenharmony_ci * the HBA. X MUST also be a power of 2. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic int lpfc_debugfs_enable = 1; 9262306a36Sopenharmony_cimodule_param(lpfc_debugfs_enable, int, S_IRUGO); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services"); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* This MUST be a power of 2 */ 9662306a36Sopenharmony_cistatic int lpfc_debugfs_max_disc_trc; 9762306a36Sopenharmony_cimodule_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO); 9862306a36Sopenharmony_ciMODULE_PARM_DESC(lpfc_debugfs_max_disc_trc, 9962306a36Sopenharmony_ci "Set debugfs discovery trace depth"); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* This MUST be a power of 2 */ 10262306a36Sopenharmony_cistatic int lpfc_debugfs_max_slow_ring_trc; 10362306a36Sopenharmony_cimodule_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO); 10462306a36Sopenharmony_ciMODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, 10562306a36Sopenharmony_ci "Set debugfs slow ring trace depth"); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* This MUST be a power of 2 */ 10862306a36Sopenharmony_cistatic int lpfc_debugfs_max_nvmeio_trc; 10962306a36Sopenharmony_cimodule_param(lpfc_debugfs_max_nvmeio_trc, int, 0444); 11062306a36Sopenharmony_ciMODULE_PARM_DESC(lpfc_debugfs_max_nvmeio_trc, 11162306a36Sopenharmony_ci "Set debugfs NVME IO trace depth"); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int lpfc_debugfs_mask_disc_trc; 11462306a36Sopenharmony_cimodule_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO); 11562306a36Sopenharmony_ciMODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, 11662306a36Sopenharmony_ci "Set debugfs discovery trace mask"); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#include <linux/debugfs.h> 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0); 12162306a36Sopenharmony_cistatic unsigned long lpfc_debugfs_start_time = 0L; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* iDiag */ 12462306a36Sopenharmony_cistatic struct lpfc_idiag idiag; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/** 12762306a36Sopenharmony_ci * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer 12862306a36Sopenharmony_ci * @vport: The vport to gather the log info from. 12962306a36Sopenharmony_ci * @buf: The buffer to dump log into. 13062306a36Sopenharmony_ci * @size: The maximum amount of data to process. 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * Description: 13362306a36Sopenharmony_ci * This routine gathers the lpfc discovery debugfs data from the @vport and 13462306a36Sopenharmony_ci * dumps it to @buf up to @size number of bytes. It will start at the next entry 13562306a36Sopenharmony_ci * in the log and process the log until the end of the buffer. Then it will 13662306a36Sopenharmony_ci * gather from the beginning of the log and process until the current entry. 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Notes: 13962306a36Sopenharmony_ci * Discovery logging will be disabled while while this routine dumps the log. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Return Value: 14262306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 14362306a36Sopenharmony_ci * not exceed @size. 14462306a36Sopenharmony_ci **/ 14562306a36Sopenharmony_cistatic int 14662306a36Sopenharmony_cilpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int i, index, len, enable; 14962306a36Sopenharmony_ci uint32_t ms; 15062306a36Sopenharmony_ci struct lpfc_debugfs_trc *dtp; 15162306a36Sopenharmony_ci char *buffer; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); 15462306a36Sopenharmony_ci if (!buffer) 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci enable = lpfc_debugfs_enable; 15862306a36Sopenharmony_ci lpfc_debugfs_enable = 0; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci len = 0; 16162306a36Sopenharmony_ci index = (atomic_read(&vport->disc_trc_cnt) + 1) & 16262306a36Sopenharmony_ci (lpfc_debugfs_max_disc_trc - 1); 16362306a36Sopenharmony_ci for (i = index; i < lpfc_debugfs_max_disc_trc; i++) { 16462306a36Sopenharmony_ci dtp = vport->disc_trc + i; 16562306a36Sopenharmony_ci if (!dtp->fmt) 16662306a36Sopenharmony_ci continue; 16762306a36Sopenharmony_ci ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); 16862306a36Sopenharmony_ci snprintf(buffer, 16962306a36Sopenharmony_ci LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", 17062306a36Sopenharmony_ci dtp->seq_cnt, ms, dtp->fmt); 17162306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, buffer, 17262306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci for (i = 0; i < index; i++) { 17562306a36Sopenharmony_ci dtp = vport->disc_trc + i; 17662306a36Sopenharmony_ci if (!dtp->fmt) 17762306a36Sopenharmony_ci continue; 17862306a36Sopenharmony_ci ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); 17962306a36Sopenharmony_ci snprintf(buffer, 18062306a36Sopenharmony_ci LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", 18162306a36Sopenharmony_ci dtp->seq_cnt, ms, dtp->fmt); 18262306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, buffer, 18362306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci lpfc_debugfs_enable = enable; 18762306a36Sopenharmony_ci kfree(buffer); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return len; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/** 19362306a36Sopenharmony_ci * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer 19462306a36Sopenharmony_ci * @phba: The HBA to gather the log info from. 19562306a36Sopenharmony_ci * @buf: The buffer to dump log into. 19662306a36Sopenharmony_ci * @size: The maximum amount of data to process. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * Description: 19962306a36Sopenharmony_ci * This routine gathers the lpfc slow ring debugfs data from the @phba and 20062306a36Sopenharmony_ci * dumps it to @buf up to @size number of bytes. It will start at the next entry 20162306a36Sopenharmony_ci * in the log and process the log until the end of the buffer. Then it will 20262306a36Sopenharmony_ci * gather from the beginning of the log and process until the current entry. 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * Notes: 20562306a36Sopenharmony_ci * Slow ring logging will be disabled while while this routine dumps the log. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Return Value: 20862306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 20962306a36Sopenharmony_ci * not exceed @size. 21062306a36Sopenharmony_ci **/ 21162306a36Sopenharmony_cistatic int 21262306a36Sopenharmony_cilpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int i, index, len, enable; 21562306a36Sopenharmony_ci uint32_t ms; 21662306a36Sopenharmony_ci struct lpfc_debugfs_trc *dtp; 21762306a36Sopenharmony_ci char *buffer; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); 22062306a36Sopenharmony_ci if (!buffer) 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci enable = lpfc_debugfs_enable; 22462306a36Sopenharmony_ci lpfc_debugfs_enable = 0; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci len = 0; 22762306a36Sopenharmony_ci index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) & 22862306a36Sopenharmony_ci (lpfc_debugfs_max_slow_ring_trc - 1); 22962306a36Sopenharmony_ci for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) { 23062306a36Sopenharmony_ci dtp = phba->slow_ring_trc + i; 23162306a36Sopenharmony_ci if (!dtp->fmt) 23262306a36Sopenharmony_ci continue; 23362306a36Sopenharmony_ci ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); 23462306a36Sopenharmony_ci snprintf(buffer, 23562306a36Sopenharmony_ci LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", 23662306a36Sopenharmony_ci dtp->seq_cnt, ms, dtp->fmt); 23762306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, buffer, 23862306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci for (i = 0; i < index; i++) { 24162306a36Sopenharmony_ci dtp = phba->slow_ring_trc + i; 24262306a36Sopenharmony_ci if (!dtp->fmt) 24362306a36Sopenharmony_ci continue; 24462306a36Sopenharmony_ci ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); 24562306a36Sopenharmony_ci snprintf(buffer, 24662306a36Sopenharmony_ci LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", 24762306a36Sopenharmony_ci dtp->seq_cnt, ms, dtp->fmt); 24862306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, buffer, 24962306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci lpfc_debugfs_enable = enable; 25362306a36Sopenharmony_ci kfree(buffer); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return len; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int lpfc_debugfs_last_hbq = -1; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/** 26162306a36Sopenharmony_ci * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer 26262306a36Sopenharmony_ci * @phba: The HBA to gather host buffer info from. 26362306a36Sopenharmony_ci * @buf: The buffer to dump log into. 26462306a36Sopenharmony_ci * @size: The maximum amount of data to process. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Description: 26762306a36Sopenharmony_ci * This routine dumps the host buffer queue info from the @phba to @buf up to 26862306a36Sopenharmony_ci * @size number of bytes. A header that describes the current hbq state will be 26962306a36Sopenharmony_ci * dumped to @buf first and then info on each hbq entry will be dumped to @buf 27062306a36Sopenharmony_ci * until @size bytes have been dumped or all the hbq info has been dumped. 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * Notes: 27362306a36Sopenharmony_ci * This routine will rotate through each configured HBQ each time called. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * Return Value: 27662306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 27762306a36Sopenharmony_ci * not exceed @size. 27862306a36Sopenharmony_ci **/ 27962306a36Sopenharmony_cistatic int 28062306a36Sopenharmony_cilpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int len = 0; 28362306a36Sopenharmony_ci int i, j, found, posted, low; 28462306a36Sopenharmony_ci uint32_t phys, raw_index, getidx; 28562306a36Sopenharmony_ci struct lpfc_hbq_init *hip; 28662306a36Sopenharmony_ci struct hbq_s *hbqs; 28762306a36Sopenharmony_ci struct lpfc_hbq_entry *hbqe; 28862306a36Sopenharmony_ci struct lpfc_dmabuf *d_buf; 28962306a36Sopenharmony_ci struct hbq_dmabuf *hbq_buf; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (phba->sli_rev != 3) 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* toggle between multiple hbqs, if any */ 29762306a36Sopenharmony_ci i = lpfc_sli_hbq_count(); 29862306a36Sopenharmony_ci if (i > 1) { 29962306a36Sopenharmony_ci lpfc_debugfs_last_hbq++; 30062306a36Sopenharmony_ci if (lpfc_debugfs_last_hbq >= i) 30162306a36Sopenharmony_ci lpfc_debugfs_last_hbq = 0; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci else 30462306a36Sopenharmony_ci lpfc_debugfs_last_hbq = 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci i = lpfc_debugfs_last_hbq; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci hbqs = &phba->hbqs[i]; 31162306a36Sopenharmony_ci posted = 0; 31262306a36Sopenharmony_ci list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) 31362306a36Sopenharmony_ci posted++; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci hip = lpfc_hbq_defs[i]; 31662306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 31762306a36Sopenharmony_ci "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n", 31862306a36Sopenharmony_ci hip->hbq_index, hip->profile, hip->rn, 31962306a36Sopenharmony_ci hip->buffer_count, hip->init_count, hip->add_count, posted); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci raw_index = phba->hbq_get[i]; 32262306a36Sopenharmony_ci getidx = le32_to_cpu(raw_index); 32362306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 32462306a36Sopenharmony_ci "entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", 32562306a36Sopenharmony_ci hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, 32662306a36Sopenharmony_ci hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; 32962306a36Sopenharmony_ci for (j=0; j<hbqs->entry_count; j++) { 33062306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 33162306a36Sopenharmony_ci "%03d: %08x %04x %05x ", j, 33262306a36Sopenharmony_ci le32_to_cpu(hbqe->bde.addrLow), 33362306a36Sopenharmony_ci le32_to_cpu(hbqe->bde.tus.w), 33462306a36Sopenharmony_ci le32_to_cpu(hbqe->buffer_tag)); 33562306a36Sopenharmony_ci i = 0; 33662306a36Sopenharmony_ci found = 0; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* First calculate if slot has an associated posted buffer */ 33962306a36Sopenharmony_ci low = hbqs->hbqPutIdx - posted; 34062306a36Sopenharmony_ci if (low >= 0) { 34162306a36Sopenharmony_ci if ((j >= hbqs->hbqPutIdx) || (j < low)) { 34262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 34362306a36Sopenharmony_ci "Unused\n"); 34462306a36Sopenharmony_ci goto skipit; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci else { 34862306a36Sopenharmony_ci if ((j >= hbqs->hbqPutIdx) && 34962306a36Sopenharmony_ci (j < (hbqs->entry_count+low))) { 35062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 35162306a36Sopenharmony_ci "Unused\n"); 35262306a36Sopenharmony_ci goto skipit; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Get the Buffer info for the posted buffer */ 35762306a36Sopenharmony_ci list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { 35862306a36Sopenharmony_ci hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); 35962306a36Sopenharmony_ci phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); 36062306a36Sopenharmony_ci if (phys == le32_to_cpu(hbqe->bde.addrLow)) { 36162306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 36262306a36Sopenharmony_ci "Buf%d: x%px %06x\n", i, 36362306a36Sopenharmony_ci hbq_buf->dbuf.virt, hbq_buf->tag); 36462306a36Sopenharmony_ci found = 1; 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci i++; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci if (!found) { 37062306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "No DMAinfo?\n"); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ciskipit: 37362306a36Sopenharmony_ci hbqe++; 37462306a36Sopenharmony_ci if (len > LPFC_HBQINFO_SIZE - 54) 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 37862306a36Sopenharmony_ci return len; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int lpfc_debugfs_last_xripool; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/** 38462306a36Sopenharmony_ci * lpfc_debugfs_commonxripools_data - Dump Hardware Queue info to a buffer 38562306a36Sopenharmony_ci * @phba: The HBA to gather host buffer info from. 38662306a36Sopenharmony_ci * @buf: The buffer to dump log into. 38762306a36Sopenharmony_ci * @size: The maximum amount of data to process. 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * Description: 39062306a36Sopenharmony_ci * This routine dumps the Hardware Queue info from the @phba to @buf up to 39162306a36Sopenharmony_ci * @size number of bytes. A header that describes the current hdwq state will be 39262306a36Sopenharmony_ci * dumped to @buf first and then info on each hdwq entry will be dumped to @buf 39362306a36Sopenharmony_ci * until @size bytes have been dumped or all the hdwq info has been dumped. 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * Notes: 39662306a36Sopenharmony_ci * This routine will rotate through each configured Hardware Queue each 39762306a36Sopenharmony_ci * time called. 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Return Value: 40062306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 40162306a36Sopenharmony_ci * not exceed @size. 40262306a36Sopenharmony_ci **/ 40362306a36Sopenharmony_cistatic int 40462306a36Sopenharmony_cilpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct lpfc_sli4_hdw_queue *qp; 40762306a36Sopenharmony_ci int len = 0; 40862306a36Sopenharmony_ci int i, out; 40962306a36Sopenharmony_ci unsigned long iflag; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 41262306a36Sopenharmony_ci if (len > (LPFC_DUMP_MULTIXRIPOOL_SIZE - 80)) 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool]; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i); 41762306a36Sopenharmony_ci spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); 41862306a36Sopenharmony_ci spin_lock(&qp->io_buf_list_get_lock); 41962306a36Sopenharmony_ci spin_lock(&qp->io_buf_list_put_lock); 42062306a36Sopenharmony_ci out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs + 42162306a36Sopenharmony_ci qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs); 42262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 42362306a36Sopenharmony_ci "tot:%d get:%d put:%d mt:%d " 42462306a36Sopenharmony_ci "ABTS scsi:%d nvme:%d Out:%d\n", 42562306a36Sopenharmony_ci qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs, 42662306a36Sopenharmony_ci qp->empty_io_bufs, qp->abts_scsi_io_bufs, 42762306a36Sopenharmony_ci qp->abts_nvme_io_bufs, out); 42862306a36Sopenharmony_ci spin_unlock(&qp->io_buf_list_put_lock); 42962306a36Sopenharmony_ci spin_unlock(&qp->io_buf_list_get_lock); 43062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci lpfc_debugfs_last_xripool++; 43362306a36Sopenharmony_ci if (lpfc_debugfs_last_xripool >= phba->cfg_hdw_queue) 43462306a36Sopenharmony_ci lpfc_debugfs_last_xripool = 0; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return len; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * lpfc_debugfs_multixripools_data - Display multi-XRI pools information 44262306a36Sopenharmony_ci * @phba: The HBA to gather host buffer info from. 44362306a36Sopenharmony_ci * @buf: The buffer to dump log into. 44462306a36Sopenharmony_ci * @size: The maximum amount of data to process. 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * Description: 44762306a36Sopenharmony_ci * This routine displays current multi-XRI pools information including XRI 44862306a36Sopenharmony_ci * count in public, private and txcmplq. It also displays current high and 44962306a36Sopenharmony_ci * low watermark. 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * Return Value: 45262306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 45362306a36Sopenharmony_ci * not exceed @size. 45462306a36Sopenharmony_ci **/ 45562306a36Sopenharmony_cistatic int 45662306a36Sopenharmony_cilpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci u32 i; 45962306a36Sopenharmony_ci u32 hwq_count; 46062306a36Sopenharmony_ci struct lpfc_sli4_hdw_queue *qp; 46162306a36Sopenharmony_ci struct lpfc_multixri_pool *multixri_pool; 46262306a36Sopenharmony_ci struct lpfc_pvt_pool *pvt_pool; 46362306a36Sopenharmony_ci struct lpfc_pbl_pool *pbl_pool; 46462306a36Sopenharmony_ci u32 txcmplq_cnt; 46562306a36Sopenharmony_ci char tmp[LPFC_DEBUG_OUT_LINE_SZ] = {0}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (phba->sli_rev != LPFC_SLI_REV4) 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!phba->sli4_hba.hdwq) 47162306a36Sopenharmony_ci return 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!phba->cfg_xri_rebalancing) { 47462306a36Sopenharmony_ci i = lpfc_debugfs_commonxripools_data(phba, buf, size); 47562306a36Sopenharmony_ci return i; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * Pbl: Current number of free XRIs in public pool 48062306a36Sopenharmony_ci * Pvt: Current number of free XRIs in private pool 48162306a36Sopenharmony_ci * Busy: Current number of outstanding XRIs 48262306a36Sopenharmony_ci * HWM: Current high watermark 48362306a36Sopenharmony_ci * pvt_empty: Incremented by 1 when IO submission fails (no xri) 48462306a36Sopenharmony_ci * pbl_empty: Incremented by 1 when all pbl_pool are empty during 48562306a36Sopenharmony_ci * IO submission 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 48862306a36Sopenharmony_ci "HWQ: Pbl Pvt Busy HWM | pvt_empty pbl_empty "); 48962306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 49062306a36Sopenharmony_ci return strnlen(buf, size); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * MAXH: Max high watermark seen so far 49562306a36Sopenharmony_ci * above_lmt: Incremented by 1 if xri_owned > xri_limit during 49662306a36Sopenharmony_ci * IO submission 49762306a36Sopenharmony_ci * below_lmt: Incremented by 1 if xri_owned <= xri_limit during 49862306a36Sopenharmony_ci * IO submission 49962306a36Sopenharmony_ci * locPbl_hit: Incremented by 1 if successfully get a batch of XRI from 50062306a36Sopenharmony_ci * local pbl_pool 50162306a36Sopenharmony_ci * othPbl_hit: Incremented by 1 if successfully get a batch of XRI from 50262306a36Sopenharmony_ci * other pbl_pool 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 50562306a36Sopenharmony_ci "MAXH above_lmt below_lmt locPbl_hit othPbl_hit"); 50662306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 50762306a36Sopenharmony_ci return strnlen(buf, size); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * sPbl: snapshot of Pbl 15 sec after stat gets cleared 51162306a36Sopenharmony_ci * sPvt: snapshot of Pvt 15 sec after stat gets cleared 51262306a36Sopenharmony_ci * sBusy: snapshot of Busy 15 sec after stat gets cleared 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 51562306a36Sopenharmony_ci " | sPbl sPvt sBusy"); 51662306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 51762306a36Sopenharmony_ci return strnlen(buf, size); 51862306a36Sopenharmony_ci#endif 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "\n"); 52162306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 52262306a36Sopenharmony_ci return strnlen(buf, size); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci hwq_count = phba->cfg_hdw_queue; 52562306a36Sopenharmony_ci for (i = 0; i < hwq_count; i++) { 52662306a36Sopenharmony_ci qp = &phba->sli4_hba.hdwq[i]; 52762306a36Sopenharmony_ci multixri_pool = qp->p_multixri_pool; 52862306a36Sopenharmony_ci if (!multixri_pool) 52962306a36Sopenharmony_ci continue; 53062306a36Sopenharmony_ci pbl_pool = &multixri_pool->pbl_pool; 53162306a36Sopenharmony_ci pvt_pool = &multixri_pool->pvt_pool; 53262306a36Sopenharmony_ci txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 53562306a36Sopenharmony_ci "%03d: %4d %4d %4d %4d | %10d %10d ", 53662306a36Sopenharmony_ci i, pbl_pool->count, pvt_pool->count, 53762306a36Sopenharmony_ci txcmplq_cnt, pvt_pool->high_watermark, 53862306a36Sopenharmony_ci qp->empty_io_bufs, multixri_pool->pbl_empty_count); 53962306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT 54362306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 54462306a36Sopenharmony_ci "%4d %10d %10d %10d %10d", 54562306a36Sopenharmony_ci multixri_pool->stat_max_hwm, 54662306a36Sopenharmony_ci multixri_pool->above_limit_count, 54762306a36Sopenharmony_ci multixri_pool->below_limit_count, 54862306a36Sopenharmony_ci multixri_pool->local_pbl_hit_count, 54962306a36Sopenharmony_ci multixri_pool->other_pbl_hit_count); 55062306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 55462306a36Sopenharmony_ci " | %4d %4d %5d", 55562306a36Sopenharmony_ci multixri_pool->stat_pbl_count, 55662306a36Sopenharmony_ci multixri_pool->stat_pvt_count, 55762306a36Sopenharmony_ci multixri_pool->stat_busy_count); 55862306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci#endif 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "\n"); 56362306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci return strnlen(buf, size); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci#ifdef LPFC_HDWQ_LOCK_STAT 57162306a36Sopenharmony_cistatic int lpfc_debugfs_last_lock; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * lpfc_debugfs_lockstat_data - Dump Hardware Queue info to a buffer 57562306a36Sopenharmony_ci * @phba: The HBA to gather host buffer info from. 57662306a36Sopenharmony_ci * @buf: The buffer to dump log into. 57762306a36Sopenharmony_ci * @size: The maximum amount of data to process. 57862306a36Sopenharmony_ci * 57962306a36Sopenharmony_ci * Description: 58062306a36Sopenharmony_ci * This routine dumps the Hardware Queue info from the @phba to @buf up to 58162306a36Sopenharmony_ci * @size number of bytes. A header that describes the current hdwq state will be 58262306a36Sopenharmony_ci * dumped to @buf first and then info on each hdwq entry will be dumped to @buf 58362306a36Sopenharmony_ci * until @size bytes have been dumped or all the hdwq info has been dumped. 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * Notes: 58662306a36Sopenharmony_ci * This routine will rotate through each configured Hardware Queue each 58762306a36Sopenharmony_ci * time called. 58862306a36Sopenharmony_ci * 58962306a36Sopenharmony_ci * Return Value: 59062306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 59162306a36Sopenharmony_ci * not exceed @size. 59262306a36Sopenharmony_ci **/ 59362306a36Sopenharmony_cistatic int 59462306a36Sopenharmony_cilpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct lpfc_sli4_hdw_queue *qp; 59762306a36Sopenharmony_ci int len = 0; 59862306a36Sopenharmony_ci int i; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (phba->sli_rev != LPFC_SLI_REV4) 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!phba->sli4_hba.hdwq) 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 60762306a36Sopenharmony_ci if (len > (LPFC_HDWQINFO_SIZE - 100)) 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock]; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i); 61262306a36Sopenharmony_ci if (phba->cfg_xri_rebalancing) { 61362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 61462306a36Sopenharmony_ci "get_pvt:%d mv_pvt:%d " 61562306a36Sopenharmony_ci "mv2pub:%d mv2pvt:%d " 61662306a36Sopenharmony_ci "put_pvt:%d put_pub:%d wq:%d\n", 61762306a36Sopenharmony_ci qp->lock_conflict.alloc_pvt_pool, 61862306a36Sopenharmony_ci qp->lock_conflict.mv_from_pvt_pool, 61962306a36Sopenharmony_ci qp->lock_conflict.mv_to_pub_pool, 62062306a36Sopenharmony_ci qp->lock_conflict.mv_to_pvt_pool, 62162306a36Sopenharmony_ci qp->lock_conflict.free_pvt_pool, 62262306a36Sopenharmony_ci qp->lock_conflict.free_pub_pool, 62362306a36Sopenharmony_ci qp->lock_conflict.wq_access); 62462306a36Sopenharmony_ci } else { 62562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 62662306a36Sopenharmony_ci "get:%d put:%d free:%d wq:%d\n", 62762306a36Sopenharmony_ci qp->lock_conflict.alloc_xri_get, 62862306a36Sopenharmony_ci qp->lock_conflict.alloc_xri_put, 62962306a36Sopenharmony_ci qp->lock_conflict.free_xri, 63062306a36Sopenharmony_ci qp->lock_conflict.wq_access); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci lpfc_debugfs_last_lock++; 63462306a36Sopenharmony_ci if (lpfc_debugfs_last_lock >= phba->cfg_hdw_queue) 63562306a36Sopenharmony_ci lpfc_debugfs_last_lock = 0; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return len; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int lpfc_debugfs_last_hba_slim_off; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/** 64562306a36Sopenharmony_ci * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer 64662306a36Sopenharmony_ci * @phba: The HBA to gather SLIM info from. 64762306a36Sopenharmony_ci * @buf: The buffer to dump log into. 64862306a36Sopenharmony_ci * @size: The maximum amount of data to process. 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * Description: 65162306a36Sopenharmony_ci * This routine dumps the current contents of HBA SLIM for the HBA associated 65262306a36Sopenharmony_ci * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data. 65362306a36Sopenharmony_ci * 65462306a36Sopenharmony_ci * Notes: 65562306a36Sopenharmony_ci * This routine will only dump up to 1024 bytes of data each time called and 65662306a36Sopenharmony_ci * should be called multiple times to dump the entire HBA SLIM. 65762306a36Sopenharmony_ci * 65862306a36Sopenharmony_ci * Return Value: 65962306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 66062306a36Sopenharmony_ci * not exceed @size. 66162306a36Sopenharmony_ci **/ 66262306a36Sopenharmony_cistatic int 66362306a36Sopenharmony_cilpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci int len = 0; 66662306a36Sopenharmony_ci int i, off; 66762306a36Sopenharmony_ci uint32_t *ptr; 66862306a36Sopenharmony_ci char *buffer; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci buffer = kmalloc(1024, GFP_KERNEL); 67162306a36Sopenharmony_ci if (!buffer) 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci off = 0; 67562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "HBA SLIM\n"); 67862306a36Sopenharmony_ci lpfc_memcpy_from_slim(buffer, 67962306a36Sopenharmony_ci phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ptr = (uint32_t *)&buffer[0]; 68262306a36Sopenharmony_ci off = lpfc_debugfs_last_hba_slim_off; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Set it up for the next time */ 68562306a36Sopenharmony_ci lpfc_debugfs_last_hba_slim_off += 1024; 68662306a36Sopenharmony_ci if (lpfc_debugfs_last_hba_slim_off >= 4096) 68762306a36Sopenharmony_ci lpfc_debugfs_last_hba_slim_off = 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci i = 1024; 69062306a36Sopenharmony_ci while (i > 0) { 69162306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 69262306a36Sopenharmony_ci "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", 69362306a36Sopenharmony_ci off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), 69462306a36Sopenharmony_ci *(ptr+5), *(ptr+6), *(ptr+7)); 69562306a36Sopenharmony_ci ptr += 8; 69662306a36Sopenharmony_ci i -= (8 * sizeof(uint32_t)); 69762306a36Sopenharmony_ci off += (8 * sizeof(uint32_t)); 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 70162306a36Sopenharmony_ci kfree(buffer); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return len; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/** 70762306a36Sopenharmony_ci * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer 70862306a36Sopenharmony_ci * @phba: The HBA to gather Host SLIM info from. 70962306a36Sopenharmony_ci * @buf: The buffer to dump log into. 71062306a36Sopenharmony_ci * @size: The maximum amount of data to process. 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * Description: 71362306a36Sopenharmony_ci * This routine dumps the current contents of host SLIM for the host associated 71462306a36Sopenharmony_ci * with @phba to @buf up to @size bytes of data. The dump will contain the 71562306a36Sopenharmony_ci * Mailbox, PCB, Rings, and Registers that are located in host memory. 71662306a36Sopenharmony_ci * 71762306a36Sopenharmony_ci * Return Value: 71862306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 71962306a36Sopenharmony_ci * not exceed @size. 72062306a36Sopenharmony_ci **/ 72162306a36Sopenharmony_cistatic int 72262306a36Sopenharmony_cilpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci int len = 0; 72562306a36Sopenharmony_ci int i, off; 72662306a36Sopenharmony_ci uint32_t word0, word1, word2, word3; 72762306a36Sopenharmony_ci uint32_t *ptr; 72862306a36Sopenharmony_ci struct lpfc_pgp *pgpp; 72962306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 73062306a36Sopenharmony_ci struct lpfc_sli_ring *pring; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci off = 0; 73362306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "SLIM Mailbox\n"); 73662306a36Sopenharmony_ci ptr = (uint32_t *)phba->slim2p.virt; 73762306a36Sopenharmony_ci i = sizeof(MAILBOX_t); 73862306a36Sopenharmony_ci while (i > 0) { 73962306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 74062306a36Sopenharmony_ci "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", 74162306a36Sopenharmony_ci off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), 74262306a36Sopenharmony_ci *(ptr+5), *(ptr+6), *(ptr+7)); 74362306a36Sopenharmony_ci ptr += 8; 74462306a36Sopenharmony_ci i -= (8 * sizeof(uint32_t)); 74562306a36Sopenharmony_ci off += (8 * sizeof(uint32_t)); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "SLIM PCB\n"); 74962306a36Sopenharmony_ci ptr = (uint32_t *)phba->pcb; 75062306a36Sopenharmony_ci i = sizeof(PCB_t); 75162306a36Sopenharmony_ci while (i > 0) { 75262306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 75362306a36Sopenharmony_ci "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", 75462306a36Sopenharmony_ci off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), 75562306a36Sopenharmony_ci *(ptr+5), *(ptr+6), *(ptr+7)); 75662306a36Sopenharmony_ci ptr += 8; 75762306a36Sopenharmony_ci i -= (8 * sizeof(uint32_t)); 75862306a36Sopenharmony_ci off += (8 * sizeof(uint32_t)); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (phba->sli_rev <= LPFC_SLI_REV3) { 76262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 76362306a36Sopenharmony_ci pgpp = &phba->port_gp[i]; 76462306a36Sopenharmony_ci pring = &psli->sli3_ring[i]; 76562306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 76662306a36Sopenharmony_ci "Ring %d: CMD GetInx:%d " 76762306a36Sopenharmony_ci "(Max:%d Next:%d " 76862306a36Sopenharmony_ci "Local:%d flg:x%x) " 76962306a36Sopenharmony_ci "RSP PutInx:%d Max:%d\n", 77062306a36Sopenharmony_ci i, pgpp->cmdGetInx, 77162306a36Sopenharmony_ci pring->sli.sli3.numCiocb, 77262306a36Sopenharmony_ci pring->sli.sli3.next_cmdidx, 77362306a36Sopenharmony_ci pring->sli.sli3.local_getidx, 77462306a36Sopenharmony_ci pring->flag, pgpp->rspPutInx, 77562306a36Sopenharmony_ci pring->sli.sli3.numRiocb); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci word0 = readl(phba->HAregaddr); 77962306a36Sopenharmony_ci word1 = readl(phba->CAregaddr); 78062306a36Sopenharmony_ci word2 = readl(phba->HSregaddr); 78162306a36Sopenharmony_ci word3 = readl(phba->HCregaddr); 78262306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " 78362306a36Sopenharmony_ci "HC:%08x\n", word0, word1, word2, word3); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 78662306a36Sopenharmony_ci return len; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * lpfc_debugfs_nodelist_data - Dump target node list to a buffer 79162306a36Sopenharmony_ci * @vport: The vport to gather target node info from. 79262306a36Sopenharmony_ci * @buf: The buffer to dump log into. 79362306a36Sopenharmony_ci * @size: The maximum amount of data to process. 79462306a36Sopenharmony_ci * 79562306a36Sopenharmony_ci * Description: 79662306a36Sopenharmony_ci * This routine dumps the current target node list associated with @vport to 79762306a36Sopenharmony_ci * @buf up to @size bytes of data. Each node entry in the dump will contain a 79862306a36Sopenharmony_ci * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields. 79962306a36Sopenharmony_ci * 80062306a36Sopenharmony_ci * Return Value: 80162306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 80262306a36Sopenharmony_ci * not exceed @size. 80362306a36Sopenharmony_ci **/ 80462306a36Sopenharmony_cistatic int 80562306a36Sopenharmony_cilpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci int len = 0; 80862306a36Sopenharmony_ci int i, iocnt, outio, cnt; 80962306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 81062306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 81162306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 81262306a36Sopenharmony_ci unsigned char *statep; 81362306a36Sopenharmony_ci struct nvme_fc_local_port *localport; 81462306a36Sopenharmony_ci struct nvme_fc_remote_port *nrport = NULL; 81562306a36Sopenharmony_ci struct lpfc_nvme_rport *rport; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); 81862306a36Sopenharmony_ci outio = 0; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n"); 82162306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 82262306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 82362306a36Sopenharmony_ci iocnt = 0; 82462306a36Sopenharmony_ci if (!cnt) { 82562306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 82662306a36Sopenharmony_ci "Missing Nodelist Entries\n"); 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci cnt--; 83062306a36Sopenharmony_ci switch (ndlp->nlp_state) { 83162306a36Sopenharmony_ci case NLP_STE_UNUSED_NODE: 83262306a36Sopenharmony_ci statep = "UNUSED"; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci case NLP_STE_PLOGI_ISSUE: 83562306a36Sopenharmony_ci statep = "PLOGI "; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci case NLP_STE_ADISC_ISSUE: 83862306a36Sopenharmony_ci statep = "ADISC "; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case NLP_STE_REG_LOGIN_ISSUE: 84162306a36Sopenharmony_ci statep = "REGLOG"; 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci case NLP_STE_PRLI_ISSUE: 84462306a36Sopenharmony_ci statep = "PRLI "; 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci case NLP_STE_LOGO_ISSUE: 84762306a36Sopenharmony_ci statep = "LOGO "; 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case NLP_STE_UNMAPPED_NODE: 85062306a36Sopenharmony_ci statep = "UNMAP "; 85162306a36Sopenharmony_ci iocnt = 1; 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case NLP_STE_MAPPED_NODE: 85462306a36Sopenharmony_ci statep = "MAPPED"; 85562306a36Sopenharmony_ci iocnt = 1; 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci case NLP_STE_NPR_NODE: 85862306a36Sopenharmony_ci statep = "NPR "; 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci default: 86162306a36Sopenharmony_ci statep = "UNKNOWN"; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "%s DID:x%06x ", 86462306a36Sopenharmony_ci statep, ndlp->nlp_DID); 86562306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 86662306a36Sopenharmony_ci "WWPN x%016llx ", 86762306a36Sopenharmony_ci wwn_to_u64(ndlp->nlp_portname.u.wwn)); 86862306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, 86962306a36Sopenharmony_ci "WWNN x%016llx ", 87062306a36Sopenharmony_ci wwn_to_u64(ndlp->nlp_nodename.u.wwn)); 87162306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "RPI:x%04x ", 87262306a36Sopenharmony_ci ndlp->nlp_rpi); 87362306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "flag:x%08x ", 87462306a36Sopenharmony_ci ndlp->nlp_flag); 87562306a36Sopenharmony_ci if (!ndlp->nlp_type) 87662306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); 87762306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FC_NODE) 87862306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "FC_NODE "); 87962306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FABRIC) { 88062306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "FABRIC "); 88162306a36Sopenharmony_ci iocnt = 0; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FCP_TARGET) 88462306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ", 88562306a36Sopenharmony_ci ndlp->nlp_sid); 88662306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FCP_INITIATOR) 88762306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "FCP_INITIATOR "); 88862306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_TARGET) 88962306a36Sopenharmony_ci len += scnprintf(buf + len, 89062306a36Sopenharmony_ci size - len, "NVME_TGT sid:%d ", 89162306a36Sopenharmony_ci NLP_NO_SID); 89262306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_INITIATOR) 89362306a36Sopenharmony_ci len += scnprintf(buf + len, 89462306a36Sopenharmony_ci size - len, "NVME_INITIATOR "); 89562306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "refcnt:%d", 89662306a36Sopenharmony_ci kref_read(&ndlp->kref)); 89762306a36Sopenharmony_ci if (iocnt) { 89862306a36Sopenharmony_ci i = atomic_read(&ndlp->cmd_pending); 89962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 90062306a36Sopenharmony_ci " OutIO:x%x Qdepth x%x", 90162306a36Sopenharmony_ci i, ndlp->cmd_qdepth); 90262306a36Sopenharmony_ci outio += i; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, " xpt:x%x", 90562306a36Sopenharmony_ci ndlp->fc4_xpt_flags); 90662306a36Sopenharmony_ci if (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING) 90762306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, " defer:%x", 90862306a36Sopenharmony_ci ndlp->nlp_defer_did); 90962306a36Sopenharmony_ci len += scnprintf(buf+len, size-len, "\n"); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 91462306a36Sopenharmony_ci "\nOutstanding IO x%x\n", outio); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) { 91762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 91862306a36Sopenharmony_ci "\nNVME Targetport Entry ...\n"); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* Port state is only one of two values for now. */ 92162306a36Sopenharmony_ci if (phba->targetport->port_id) 92262306a36Sopenharmony_ci statep = "REGISTERED"; 92362306a36Sopenharmony_ci else 92462306a36Sopenharmony_ci statep = "INIT"; 92562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 92662306a36Sopenharmony_ci "TGT WWNN x%llx WWPN x%llx State %s\n", 92762306a36Sopenharmony_ci wwn_to_u64(vport->fc_nodename.u.wwn), 92862306a36Sopenharmony_ci wwn_to_u64(vport->fc_portname.u.wwn), 92962306a36Sopenharmony_ci statep); 93062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 93162306a36Sopenharmony_ci " Targetport DID x%06x\n", 93262306a36Sopenharmony_ci phba->targetport->port_id); 93362306a36Sopenharmony_ci goto out_exit; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 93762306a36Sopenharmony_ci "\nNVME Lport/Rport Entries ...\n"); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci localport = vport->localport; 94062306a36Sopenharmony_ci if (!localport) 94162306a36Sopenharmony_ci goto out_exit; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Port state is only one of two values for now. */ 94662306a36Sopenharmony_ci if (localport->port_id) 94762306a36Sopenharmony_ci statep = "ONLINE"; 94862306a36Sopenharmony_ci else 94962306a36Sopenharmony_ci statep = "UNKNOWN "; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 95262306a36Sopenharmony_ci "Lport DID x%06x PortState %s\n", 95362306a36Sopenharmony_ci localport->port_id, statep); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\tRport List:\n"); 95662306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 95762306a36Sopenharmony_ci /* local short-hand pointer. */ 95862306a36Sopenharmony_ci spin_lock(&ndlp->lock); 95962306a36Sopenharmony_ci rport = lpfc_ndlp_get_nrport(ndlp); 96062306a36Sopenharmony_ci if (rport) 96162306a36Sopenharmony_ci nrport = rport->remoteport; 96262306a36Sopenharmony_ci else 96362306a36Sopenharmony_ci nrport = NULL; 96462306a36Sopenharmony_ci spin_unlock(&ndlp->lock); 96562306a36Sopenharmony_ci if (!nrport) 96662306a36Sopenharmony_ci continue; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Port state is only one of two values for now. */ 96962306a36Sopenharmony_ci switch (nrport->port_state) { 97062306a36Sopenharmony_ci case FC_OBJSTATE_ONLINE: 97162306a36Sopenharmony_ci statep = "ONLINE"; 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci case FC_OBJSTATE_UNKNOWN: 97462306a36Sopenharmony_ci statep = "UNKNOWN "; 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci default: 97762306a36Sopenharmony_ci statep = "UNSUPPORTED"; 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Tab in to show lport ownership. */ 98262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 98362306a36Sopenharmony_ci "\t%s Port ID:x%06x ", 98462306a36Sopenharmony_ci statep, nrport->port_id); 98562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "WWPN x%llx ", 98662306a36Sopenharmony_ci nrport->port_name); 98762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "WWNN x%llx ", 98862306a36Sopenharmony_ci nrport->node_name); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* An NVME rport can have multiple roles. */ 99162306a36Sopenharmony_ci if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) 99262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 99362306a36Sopenharmony_ci "INITIATOR "); 99462306a36Sopenharmony_ci if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) 99562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 99662306a36Sopenharmony_ci "TARGET "); 99762306a36Sopenharmony_ci if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) 99862306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 99962306a36Sopenharmony_ci "DISCSRVC "); 100062306a36Sopenharmony_ci if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | 100162306a36Sopenharmony_ci FC_PORT_ROLE_NVME_TARGET | 100262306a36Sopenharmony_ci FC_PORT_ROLE_NVME_DISCOVERY)) 100362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 100462306a36Sopenharmony_ci "UNKNOWN ROLE x%x", 100562306a36Sopenharmony_ci nrport->port_role); 100662306a36Sopenharmony_ci /* Terminate the string. */ 100762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 101162306a36Sopenharmony_ci out_exit: 101262306a36Sopenharmony_ci return len; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci/** 101662306a36Sopenharmony_ci * lpfc_debugfs_nvmestat_data - Dump target node list to a buffer 101762306a36Sopenharmony_ci * @vport: The vport to gather target node info from. 101862306a36Sopenharmony_ci * @buf: The buffer to dump log into. 101962306a36Sopenharmony_ci * @size: The maximum amount of data to process. 102062306a36Sopenharmony_ci * 102162306a36Sopenharmony_ci * Description: 102262306a36Sopenharmony_ci * This routine dumps the NVME statistics associated with @vport 102362306a36Sopenharmony_ci * 102462306a36Sopenharmony_ci * Return Value: 102562306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 102662306a36Sopenharmony_ci * not exceed @size. 102762306a36Sopenharmony_ci **/ 102862306a36Sopenharmony_cistatic int 102962306a36Sopenharmony_cilpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 103262306a36Sopenharmony_ci struct lpfc_nvmet_tgtport *tgtp; 103362306a36Sopenharmony_ci struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; 103462306a36Sopenharmony_ci struct nvme_fc_local_port *localport; 103562306a36Sopenharmony_ci struct lpfc_fc4_ctrl_stat *cstat; 103662306a36Sopenharmony_ci struct lpfc_nvme_lport *lport; 103762306a36Sopenharmony_ci uint64_t data1, data2, data3; 103862306a36Sopenharmony_ci uint64_t tot, totin, totout; 103962306a36Sopenharmony_ci int cnt, i; 104062306a36Sopenharmony_ci int len = 0; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (phba->nvmet_support) { 104362306a36Sopenharmony_ci if (!phba->targetport) 104462306a36Sopenharmony_ci return len; 104562306a36Sopenharmony_ci tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; 104662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 104762306a36Sopenharmony_ci "\nNVME Targetport Statistics\n"); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 105062306a36Sopenharmony_ci "LS: Rcv %08x Drop %08x Abort %08x\n", 105162306a36Sopenharmony_ci atomic_read(&tgtp->rcv_ls_req_in), 105262306a36Sopenharmony_ci atomic_read(&tgtp->rcv_ls_req_drop), 105362306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_abort)); 105462306a36Sopenharmony_ci if (atomic_read(&tgtp->rcv_ls_req_in) != 105562306a36Sopenharmony_ci atomic_read(&tgtp->rcv_ls_req_out)) { 105662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 105762306a36Sopenharmony_ci "Rcv LS: in %08x != out %08x\n", 105862306a36Sopenharmony_ci atomic_read(&tgtp->rcv_ls_req_in), 105962306a36Sopenharmony_ci atomic_read(&tgtp->rcv_ls_req_out)); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 106362306a36Sopenharmony_ci "LS: Xmt %08x Drop %08x Cmpl %08x\n", 106462306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_rsp), 106562306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_drop), 106662306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_rsp_cmpl)); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 106962306a36Sopenharmony_ci "LS: RSP Abort %08x xb %08x Err %08x\n", 107062306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_rsp_aborted), 107162306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_rsp_xb_set), 107262306a36Sopenharmony_ci atomic_read(&tgtp->xmt_ls_rsp_error)); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 107562306a36Sopenharmony_ci "FCP: Rcv %08x Defer %08x Release %08x " 107662306a36Sopenharmony_ci "Drop %08x\n", 107762306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_in), 107862306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_defer), 107962306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_release), 108062306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_drop)); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (atomic_read(&tgtp->rcv_fcp_cmd_in) != 108362306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_out)) { 108462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 108562306a36Sopenharmony_ci "Rcv FCP: in %08x != out %08x\n", 108662306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_in), 108762306a36Sopenharmony_ci atomic_read(&tgtp->rcv_fcp_cmd_out)); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 109162306a36Sopenharmony_ci "FCP Rsp: read %08x readrsp %08x " 109262306a36Sopenharmony_ci "write %08x rsp %08x\n", 109362306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_read), 109462306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_read_rsp), 109562306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_write), 109662306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp)); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 109962306a36Sopenharmony_ci "FCP Rsp Cmpl: %08x err %08x drop %08x\n", 110062306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp_cmpl), 110162306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp_error), 110262306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp_drop)); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 110562306a36Sopenharmony_ci "FCP Rsp Abort: %08x xb %08x xricqe %08x\n", 110662306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp_aborted), 110762306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_rsp_xb_set), 110862306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_xri_abort_cqe)); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 111162306a36Sopenharmony_ci "ABORT: Xmt %08x Cmpl %08x\n", 111262306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_abort), 111362306a36Sopenharmony_ci atomic_read(&tgtp->xmt_fcp_abort_cmpl)); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 111662306a36Sopenharmony_ci "ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x", 111762306a36Sopenharmony_ci atomic_read(&tgtp->xmt_abort_sol), 111862306a36Sopenharmony_ci atomic_read(&tgtp->xmt_abort_unsol), 111962306a36Sopenharmony_ci atomic_read(&tgtp->xmt_abort_rsp), 112062306a36Sopenharmony_ci atomic_read(&tgtp->xmt_abort_rsp_error)); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci cnt = 0; 112562306a36Sopenharmony_ci spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); 112662306a36Sopenharmony_ci list_for_each_entry_safe(ctxp, next_ctxp, 112762306a36Sopenharmony_ci &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, 112862306a36Sopenharmony_ci list) { 112962306a36Sopenharmony_ci cnt++; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); 113262306a36Sopenharmony_ci if (cnt) { 113362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 113462306a36Sopenharmony_ci "ABORT: %d ctx entries\n", cnt); 113562306a36Sopenharmony_ci spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); 113662306a36Sopenharmony_ci list_for_each_entry_safe(ctxp, next_ctxp, 113762306a36Sopenharmony_ci &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, 113862306a36Sopenharmony_ci list) { 113962306a36Sopenharmony_ci if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) 114062306a36Sopenharmony_ci break; 114162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 114262306a36Sopenharmony_ci "Entry: oxid %x state %x " 114362306a36Sopenharmony_ci "flag %x\n", 114462306a36Sopenharmony_ci ctxp->oxid, ctxp->state, 114562306a36Sopenharmony_ci ctxp->flag); 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* Calculate outstanding IOs */ 115162306a36Sopenharmony_ci tot = atomic_read(&tgtp->rcv_fcp_cmd_drop); 115262306a36Sopenharmony_ci tot += atomic_read(&tgtp->xmt_fcp_release); 115362306a36Sopenharmony_ci tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 115662306a36Sopenharmony_ci "IO_CTX: %08x WAIT: cur %08x tot %08x\n" 115762306a36Sopenharmony_ci "CTX Outstanding %08llx\n", 115862306a36Sopenharmony_ci phba->sli4_hba.nvmet_xri_cnt, 115962306a36Sopenharmony_ci phba->sli4_hba.nvmet_io_wait_cnt, 116062306a36Sopenharmony_ci phba->sli4_hba.nvmet_io_wait_total, 116162306a36Sopenharmony_ci tot); 116262306a36Sopenharmony_ci } else { 116362306a36Sopenharmony_ci if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) 116462306a36Sopenharmony_ci return len; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci localport = vport->localport; 116762306a36Sopenharmony_ci if (!localport) 116862306a36Sopenharmony_ci return len; 116962306a36Sopenharmony_ci lport = (struct lpfc_nvme_lport *)localport->private; 117062306a36Sopenharmony_ci if (!lport) 117162306a36Sopenharmony_ci return len; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 117462306a36Sopenharmony_ci "\nNVME HDWQ Statistics\n"); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 117762306a36Sopenharmony_ci "LS: Xmt %016x Cmpl %016x\n", 117862306a36Sopenharmony_ci atomic_read(&lport->fc4NvmeLsRequests), 117962306a36Sopenharmony_ci atomic_read(&lport->fc4NvmeLsCmpls)); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci totin = 0; 118262306a36Sopenharmony_ci totout = 0; 118362306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 118462306a36Sopenharmony_ci cstat = &phba->sli4_hba.hdwq[i].nvme_cstat; 118562306a36Sopenharmony_ci tot = cstat->io_cmpls; 118662306a36Sopenharmony_ci totin += tot; 118762306a36Sopenharmony_ci data1 = cstat->input_requests; 118862306a36Sopenharmony_ci data2 = cstat->output_requests; 118962306a36Sopenharmony_ci data3 = cstat->control_requests; 119062306a36Sopenharmony_ci totout += (data1 + data2 + data3); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* Limit to 32, debugfs display buffer limitation */ 119362306a36Sopenharmony_ci if (i >= 32) 119462306a36Sopenharmony_ci continue; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 119762306a36Sopenharmony_ci "HDWQ (%d): Rd %016llx Wr %016llx " 119862306a36Sopenharmony_ci "IO %016llx ", 119962306a36Sopenharmony_ci i, data1, data2, data3); 120062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 120162306a36Sopenharmony_ci "Cmpl %016llx OutIO %016llx\n", 120262306a36Sopenharmony_ci tot, ((data1 + data2 + data3) - tot)); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 120562306a36Sopenharmony_ci "Total FCP Cmpl %016llx Issue %016llx " 120662306a36Sopenharmony_ci "OutIO %016llx\n", 120762306a36Sopenharmony_ci totin, totout, totout - totin); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 121062306a36Sopenharmony_ci "LS Xmt Err: Abrt %08x Err %08x " 121162306a36Sopenharmony_ci "Cmpl Err: xb %08x Err %08x\n", 121262306a36Sopenharmony_ci atomic_read(&lport->xmt_ls_abort), 121362306a36Sopenharmony_ci atomic_read(&lport->xmt_ls_err), 121462306a36Sopenharmony_ci atomic_read(&lport->cmpl_ls_xb), 121562306a36Sopenharmony_ci atomic_read(&lport->cmpl_ls_err)); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 121862306a36Sopenharmony_ci "FCP Xmt Err: noxri %06x nondlp %06x " 121962306a36Sopenharmony_ci "qdepth %06x wqerr %06x err %06x Abrt %06x\n", 122062306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_noxri), 122162306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_bad_ndlp), 122262306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_qdepth), 122362306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_wqerr), 122462306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_err), 122562306a36Sopenharmony_ci atomic_read(&lport->xmt_fcp_abort)); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 122862306a36Sopenharmony_ci "FCP Cmpl Err: xb %08x Err %08x\n", 122962306a36Sopenharmony_ci atomic_read(&lport->cmpl_fcp_xb), 123062306a36Sopenharmony_ci atomic_read(&lport->cmpl_fcp_err)); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return len; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci/** 123862306a36Sopenharmony_ci * lpfc_debugfs_scsistat_data - Dump target node list to a buffer 123962306a36Sopenharmony_ci * @vport: The vport to gather target node info from. 124062306a36Sopenharmony_ci * @buf: The buffer to dump log into. 124162306a36Sopenharmony_ci * @size: The maximum amount of data to process. 124262306a36Sopenharmony_ci * 124362306a36Sopenharmony_ci * Description: 124462306a36Sopenharmony_ci * This routine dumps the SCSI statistics associated with @vport 124562306a36Sopenharmony_ci * 124662306a36Sopenharmony_ci * Return Value: 124762306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 124862306a36Sopenharmony_ci * not exceed @size. 124962306a36Sopenharmony_ci **/ 125062306a36Sopenharmony_cistatic int 125162306a36Sopenharmony_cilpfc_debugfs_scsistat_data(struct lpfc_vport *vport, char *buf, int size) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci int len; 125462306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 125562306a36Sopenharmony_ci struct lpfc_fc4_ctrl_stat *cstat; 125662306a36Sopenharmony_ci u64 data1, data2, data3; 125762306a36Sopenharmony_ci u64 tot, totin, totout; 125862306a36Sopenharmony_ci int i; 125962306a36Sopenharmony_ci char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0}; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP) || 126262306a36Sopenharmony_ci (phba->sli_rev != LPFC_SLI_REV4)) 126362306a36Sopenharmony_ci return 0; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci scnprintf(buf, size, "SCSI HDWQ Statistics\n"); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci totin = 0; 126862306a36Sopenharmony_ci totout = 0; 126962306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 127062306a36Sopenharmony_ci cstat = &phba->sli4_hba.hdwq[i].scsi_cstat; 127162306a36Sopenharmony_ci tot = cstat->io_cmpls; 127262306a36Sopenharmony_ci totin += tot; 127362306a36Sopenharmony_ci data1 = cstat->input_requests; 127462306a36Sopenharmony_ci data2 = cstat->output_requests; 127562306a36Sopenharmony_ci data3 = cstat->control_requests; 127662306a36Sopenharmony_ci totout += (data1 + data2 + data3); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx " 127962306a36Sopenharmony_ci "IO %016llx ", i, data1, data2, data3); 128062306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 128162306a36Sopenharmony_ci goto buffer_done; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n", 128462306a36Sopenharmony_ci tot, ((data1 + data2 + data3) - tot)); 128562306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 128662306a36Sopenharmony_ci goto buffer_done; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx " 128962306a36Sopenharmony_ci "OutIO %016llx\n", totin, totout, totout - totin); 129062306a36Sopenharmony_ci strlcat(buf, tmp, size); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cibuffer_done: 129362306a36Sopenharmony_ci len = strnlen(buf, size); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return len; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_civoid 129962306a36Sopenharmony_cilpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci uint64_t seg1, seg2, seg3, seg4; 130262306a36Sopenharmony_ci uint64_t segsum; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (!lpfc_cmd->ts_last_cmd || 130562306a36Sopenharmony_ci !lpfc_cmd->ts_cmd_start || 130662306a36Sopenharmony_ci !lpfc_cmd->ts_cmd_wqput || 130762306a36Sopenharmony_ci !lpfc_cmd->ts_isr_cmpl || 130862306a36Sopenharmony_ci !lpfc_cmd->ts_data_io) 130962306a36Sopenharmony_ci return; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start) 131262306a36Sopenharmony_ci return; 131362306a36Sopenharmony_ci if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd) 131462306a36Sopenharmony_ci return; 131562306a36Sopenharmony_ci if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start) 131662306a36Sopenharmony_ci return; 131762306a36Sopenharmony_ci if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput) 131862306a36Sopenharmony_ci return; 131962306a36Sopenharmony_ci if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl) 132062306a36Sopenharmony_ci return; 132162306a36Sopenharmony_ci /* 132262306a36Sopenharmony_ci * Segment 1 - Time from Last FCP command cmpl is handed 132362306a36Sopenharmony_ci * off to NVME Layer to start of next command. 132462306a36Sopenharmony_ci * Segment 2 - Time from Driver receives a IO cmd start 132562306a36Sopenharmony_ci * from NVME Layer to WQ put is done on IO cmd. 132662306a36Sopenharmony_ci * Segment 3 - Time from Driver WQ put is done on IO cmd 132762306a36Sopenharmony_ci * to MSI-X ISR for IO cmpl. 132862306a36Sopenharmony_ci * Segment 4 - Time from MSI-X ISR for IO cmpl to when 132962306a36Sopenharmony_ci * cmpl is handled off to the NVME Layer. 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_ci seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd; 133262306a36Sopenharmony_ci if (seg1 > 5000000) /* 5 ms - for sequential IOs only */ 133362306a36Sopenharmony_ci seg1 = 0; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* Calculate times relative to start of IO */ 133662306a36Sopenharmony_ci seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start); 133762306a36Sopenharmony_ci segsum = seg2; 133862306a36Sopenharmony_ci seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start; 133962306a36Sopenharmony_ci if (segsum > seg3) 134062306a36Sopenharmony_ci return; 134162306a36Sopenharmony_ci seg3 -= segsum; 134262306a36Sopenharmony_ci segsum += seg3; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start; 134562306a36Sopenharmony_ci if (segsum > seg4) 134662306a36Sopenharmony_ci return; 134762306a36Sopenharmony_ci seg4 -= segsum; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci phba->ktime_data_samples++; 135062306a36Sopenharmony_ci phba->ktime_seg1_total += seg1; 135162306a36Sopenharmony_ci if (seg1 < phba->ktime_seg1_min) 135262306a36Sopenharmony_ci phba->ktime_seg1_min = seg1; 135362306a36Sopenharmony_ci else if (seg1 > phba->ktime_seg1_max) 135462306a36Sopenharmony_ci phba->ktime_seg1_max = seg1; 135562306a36Sopenharmony_ci phba->ktime_seg2_total += seg2; 135662306a36Sopenharmony_ci if (seg2 < phba->ktime_seg2_min) 135762306a36Sopenharmony_ci phba->ktime_seg2_min = seg2; 135862306a36Sopenharmony_ci else if (seg2 > phba->ktime_seg2_max) 135962306a36Sopenharmony_ci phba->ktime_seg2_max = seg2; 136062306a36Sopenharmony_ci phba->ktime_seg3_total += seg3; 136162306a36Sopenharmony_ci if (seg3 < phba->ktime_seg3_min) 136262306a36Sopenharmony_ci phba->ktime_seg3_min = seg3; 136362306a36Sopenharmony_ci else if (seg3 > phba->ktime_seg3_max) 136462306a36Sopenharmony_ci phba->ktime_seg3_max = seg3; 136562306a36Sopenharmony_ci phba->ktime_seg4_total += seg4; 136662306a36Sopenharmony_ci if (seg4 < phba->ktime_seg4_min) 136762306a36Sopenharmony_ci phba->ktime_seg4_min = seg4; 136862306a36Sopenharmony_ci else if (seg4 > phba->ktime_seg4_max) 136962306a36Sopenharmony_ci phba->ktime_seg4_max = seg4; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci lpfc_cmd->ts_last_cmd = 0; 137262306a36Sopenharmony_ci lpfc_cmd->ts_cmd_start = 0; 137362306a36Sopenharmony_ci lpfc_cmd->ts_cmd_wqput = 0; 137462306a36Sopenharmony_ci lpfc_cmd->ts_isr_cmpl = 0; 137562306a36Sopenharmony_ci lpfc_cmd->ts_data_io = 0; 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci/** 137962306a36Sopenharmony_ci * lpfc_debugfs_ioktime_data - Dump target node list to a buffer 138062306a36Sopenharmony_ci * @vport: The vport to gather target node info from. 138162306a36Sopenharmony_ci * @buf: The buffer to dump log into. 138262306a36Sopenharmony_ci * @size: The maximum amount of data to process. 138362306a36Sopenharmony_ci * 138462306a36Sopenharmony_ci * Description: 138562306a36Sopenharmony_ci * This routine dumps the NVME statistics associated with @vport 138662306a36Sopenharmony_ci * 138762306a36Sopenharmony_ci * Return Value: 138862306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 138962306a36Sopenharmony_ci * not exceed @size. 139062306a36Sopenharmony_ci **/ 139162306a36Sopenharmony_cistatic int 139262306a36Sopenharmony_cilpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 139562306a36Sopenharmony_ci int len = 0; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (phba->nvmet_support == 0) { 139862306a36Sopenharmony_ci /* Initiator */ 139962306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, 140062306a36Sopenharmony_ci "ktime %s: Total Samples: %lld\n", 140162306a36Sopenharmony_ci (phba->ktime_on ? "Enabled" : "Disabled"), 140262306a36Sopenharmony_ci phba->ktime_data_samples); 140362306a36Sopenharmony_ci if (phba->ktime_data_samples == 0) 140462306a36Sopenharmony_ci return len; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci len += scnprintf( 140762306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 140862306a36Sopenharmony_ci "Segment 1: Last Cmd cmpl " 140962306a36Sopenharmony_ci "done -to- Start of next Cmd (in driver)\n"); 141062306a36Sopenharmony_ci len += scnprintf( 141162306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 141262306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 141362306a36Sopenharmony_ci div_u64(phba->ktime_seg1_total, 141462306a36Sopenharmony_ci phba->ktime_data_samples), 141562306a36Sopenharmony_ci phba->ktime_seg1_min, 141662306a36Sopenharmony_ci phba->ktime_seg1_max); 141762306a36Sopenharmony_ci len += scnprintf( 141862306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 141962306a36Sopenharmony_ci "Segment 2: Driver start of Cmd " 142062306a36Sopenharmony_ci "-to- Firmware WQ doorbell\n"); 142162306a36Sopenharmony_ci len += scnprintf( 142262306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 142362306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 142462306a36Sopenharmony_ci div_u64(phba->ktime_seg2_total, 142562306a36Sopenharmony_ci phba->ktime_data_samples), 142662306a36Sopenharmony_ci phba->ktime_seg2_min, 142762306a36Sopenharmony_ci phba->ktime_seg2_max); 142862306a36Sopenharmony_ci len += scnprintf( 142962306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 143062306a36Sopenharmony_ci "Segment 3: Firmware WQ doorbell -to- " 143162306a36Sopenharmony_ci "MSI-X ISR cmpl\n"); 143262306a36Sopenharmony_ci len += scnprintf( 143362306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 143462306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 143562306a36Sopenharmony_ci div_u64(phba->ktime_seg3_total, 143662306a36Sopenharmony_ci phba->ktime_data_samples), 143762306a36Sopenharmony_ci phba->ktime_seg3_min, 143862306a36Sopenharmony_ci phba->ktime_seg3_max); 143962306a36Sopenharmony_ci len += scnprintf( 144062306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 144162306a36Sopenharmony_ci "Segment 4: MSI-X ISR cmpl -to- " 144262306a36Sopenharmony_ci "Cmd cmpl done\n"); 144362306a36Sopenharmony_ci len += scnprintf( 144462306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 144562306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 144662306a36Sopenharmony_ci div_u64(phba->ktime_seg4_total, 144762306a36Sopenharmony_ci phba->ktime_data_samples), 144862306a36Sopenharmony_ci phba->ktime_seg4_min, 144962306a36Sopenharmony_ci phba->ktime_seg4_max); 145062306a36Sopenharmony_ci len += scnprintf( 145162306a36Sopenharmony_ci buf + len, PAGE_SIZE - len, 145262306a36Sopenharmony_ci "Total IO avg time: %08lld\n", 145362306a36Sopenharmony_ci div_u64(phba->ktime_seg1_total + 145462306a36Sopenharmony_ci phba->ktime_seg2_total + 145562306a36Sopenharmony_ci phba->ktime_seg3_total + 145662306a36Sopenharmony_ci phba->ktime_seg4_total, 145762306a36Sopenharmony_ci phba->ktime_data_samples)); 145862306a36Sopenharmony_ci return len; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* NVME Target */ 146262306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 146362306a36Sopenharmony_ci "ktime %s: Total Samples: %lld %lld\n", 146462306a36Sopenharmony_ci (phba->ktime_on ? "Enabled" : "Disabled"), 146562306a36Sopenharmony_ci phba->ktime_data_samples, 146662306a36Sopenharmony_ci phba->ktime_status_samples); 146762306a36Sopenharmony_ci if (phba->ktime_data_samples == 0) 146862306a36Sopenharmony_ci return len; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 147162306a36Sopenharmony_ci "Segment 1: MSI-X ISR Rcv cmd -to- " 147262306a36Sopenharmony_ci "cmd pass to NVME Layer\n"); 147362306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 147462306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 147562306a36Sopenharmony_ci div_u64(phba->ktime_seg1_total, 147662306a36Sopenharmony_ci phba->ktime_data_samples), 147762306a36Sopenharmony_ci phba->ktime_seg1_min, 147862306a36Sopenharmony_ci phba->ktime_seg1_max); 147962306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 148062306a36Sopenharmony_ci "Segment 2: cmd pass to NVME Layer- " 148162306a36Sopenharmony_ci "-to- Driver rcv cmd OP (action)\n"); 148262306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 148362306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 148462306a36Sopenharmony_ci div_u64(phba->ktime_seg2_total, 148562306a36Sopenharmony_ci phba->ktime_data_samples), 148662306a36Sopenharmony_ci phba->ktime_seg2_min, 148762306a36Sopenharmony_ci phba->ktime_seg2_max); 148862306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 148962306a36Sopenharmony_ci "Segment 3: Driver rcv cmd OP -to- " 149062306a36Sopenharmony_ci "Firmware WQ doorbell: cmd\n"); 149162306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 149262306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 149362306a36Sopenharmony_ci div_u64(phba->ktime_seg3_total, 149462306a36Sopenharmony_ci phba->ktime_data_samples), 149562306a36Sopenharmony_ci phba->ktime_seg3_min, 149662306a36Sopenharmony_ci phba->ktime_seg3_max); 149762306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 149862306a36Sopenharmony_ci "Segment 4: Firmware WQ doorbell: cmd " 149962306a36Sopenharmony_ci "-to- MSI-X ISR for cmd cmpl\n"); 150062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 150162306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 150262306a36Sopenharmony_ci div_u64(phba->ktime_seg4_total, 150362306a36Sopenharmony_ci phba->ktime_data_samples), 150462306a36Sopenharmony_ci phba->ktime_seg4_min, 150562306a36Sopenharmony_ci phba->ktime_seg4_max); 150662306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 150762306a36Sopenharmony_ci "Segment 5: MSI-X ISR for cmd cmpl " 150862306a36Sopenharmony_ci "-to- NVME layer passed cmd done\n"); 150962306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 151062306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 151162306a36Sopenharmony_ci div_u64(phba->ktime_seg5_total, 151262306a36Sopenharmony_ci phba->ktime_data_samples), 151362306a36Sopenharmony_ci phba->ktime_seg5_min, 151462306a36Sopenharmony_ci phba->ktime_seg5_max); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if (phba->ktime_status_samples == 0) { 151762306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 151862306a36Sopenharmony_ci "Total: cmd received by MSI-X ISR " 151962306a36Sopenharmony_ci "-to- cmd completed on wire\n"); 152062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 152162306a36Sopenharmony_ci "avg:%08lld min:%08lld " 152262306a36Sopenharmony_ci "max %08lld\n", 152362306a36Sopenharmony_ci div_u64(phba->ktime_seg10_total, 152462306a36Sopenharmony_ci phba->ktime_data_samples), 152562306a36Sopenharmony_ci phba->ktime_seg10_min, 152662306a36Sopenharmony_ci phba->ktime_seg10_max); 152762306a36Sopenharmony_ci return len; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 153162306a36Sopenharmony_ci "Segment 6: NVME layer passed cmd done " 153262306a36Sopenharmony_ci "-to- Driver rcv rsp status OP\n"); 153362306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 153462306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 153562306a36Sopenharmony_ci div_u64(phba->ktime_seg6_total, 153662306a36Sopenharmony_ci phba->ktime_status_samples), 153762306a36Sopenharmony_ci phba->ktime_seg6_min, 153862306a36Sopenharmony_ci phba->ktime_seg6_max); 153962306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 154062306a36Sopenharmony_ci "Segment 7: Driver rcv rsp status OP " 154162306a36Sopenharmony_ci "-to- Firmware WQ doorbell: status\n"); 154262306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 154362306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 154462306a36Sopenharmony_ci div_u64(phba->ktime_seg7_total, 154562306a36Sopenharmony_ci phba->ktime_status_samples), 154662306a36Sopenharmony_ci phba->ktime_seg7_min, 154762306a36Sopenharmony_ci phba->ktime_seg7_max); 154862306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 154962306a36Sopenharmony_ci "Segment 8: Firmware WQ doorbell: status" 155062306a36Sopenharmony_ci " -to- MSI-X ISR for status cmpl\n"); 155162306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 155262306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 155362306a36Sopenharmony_ci div_u64(phba->ktime_seg8_total, 155462306a36Sopenharmony_ci phba->ktime_status_samples), 155562306a36Sopenharmony_ci phba->ktime_seg8_min, 155662306a36Sopenharmony_ci phba->ktime_seg8_max); 155762306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 155862306a36Sopenharmony_ci "Segment 9: MSI-X ISR for status cmpl " 155962306a36Sopenharmony_ci "-to- NVME layer passed status done\n"); 156062306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 156162306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 156262306a36Sopenharmony_ci div_u64(phba->ktime_seg9_total, 156362306a36Sopenharmony_ci phba->ktime_status_samples), 156462306a36Sopenharmony_ci phba->ktime_seg9_min, 156562306a36Sopenharmony_ci phba->ktime_seg9_max); 156662306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 156762306a36Sopenharmony_ci "Total: cmd received by MSI-X ISR -to- " 156862306a36Sopenharmony_ci "cmd completed on wire\n"); 156962306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE-len, 157062306a36Sopenharmony_ci "avg:%08lld min:%08lld max %08lld\n", 157162306a36Sopenharmony_ci div_u64(phba->ktime_seg10_total, 157262306a36Sopenharmony_ci phba->ktime_status_samples), 157362306a36Sopenharmony_ci phba->ktime_seg10_min, 157462306a36Sopenharmony_ci phba->ktime_seg10_max); 157562306a36Sopenharmony_ci return len; 157662306a36Sopenharmony_ci} 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci/** 157962306a36Sopenharmony_ci * lpfc_debugfs_nvmeio_trc_data - Dump NVME IO trace list to a buffer 158062306a36Sopenharmony_ci * @phba: The phba to gather target node info from. 158162306a36Sopenharmony_ci * @buf: The buffer to dump log into. 158262306a36Sopenharmony_ci * @size: The maximum amount of data to process. 158362306a36Sopenharmony_ci * 158462306a36Sopenharmony_ci * Description: 158562306a36Sopenharmony_ci * This routine dumps the NVME IO trace associated with @phba 158662306a36Sopenharmony_ci * 158762306a36Sopenharmony_ci * Return Value: 158862306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 158962306a36Sopenharmony_ci * not exceed @size. 159062306a36Sopenharmony_ci **/ 159162306a36Sopenharmony_cistatic int 159262306a36Sopenharmony_cilpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci struct lpfc_debugfs_nvmeio_trc *dtp; 159562306a36Sopenharmony_ci int i, state, index, skip; 159662306a36Sopenharmony_ci int len = 0; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci state = phba->nvmeio_trc_on; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci index = (atomic_read(&phba->nvmeio_trc_cnt) + 1) & 160162306a36Sopenharmony_ci (phba->nvmeio_trc_size - 1); 160262306a36Sopenharmony_ci skip = phba->nvmeio_trc_output_idx; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 160562306a36Sopenharmony_ci "%s IO Trace %s: next_idx %d skip %d size %d\n", 160662306a36Sopenharmony_ci (phba->nvmet_support ? "NVME" : "NVMET"), 160762306a36Sopenharmony_ci (state ? "Enabled" : "Disabled"), 160862306a36Sopenharmony_ci index, skip, phba->nvmeio_trc_size); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (!phba->nvmeio_trc || state) 161162306a36Sopenharmony_ci return len; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* trace MUST bhe off to continue */ 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci for (i = index; i < phba->nvmeio_trc_size; i++) { 161662306a36Sopenharmony_ci if (skip) { 161762306a36Sopenharmony_ci skip--; 161862306a36Sopenharmony_ci continue; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci dtp = phba->nvmeio_trc + i; 162162306a36Sopenharmony_ci phba->nvmeio_trc_output_idx++; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (!dtp->fmt) 162462306a36Sopenharmony_ci continue; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, dtp->fmt, 162762306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { 163062306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 163162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 163262306a36Sopenharmony_ci "Trace Complete\n"); 163362306a36Sopenharmony_ci goto out; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) { 163762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 163862306a36Sopenharmony_ci "Trace Continue (%d of %d)\n", 163962306a36Sopenharmony_ci phba->nvmeio_trc_output_idx, 164062306a36Sopenharmony_ci phba->nvmeio_trc_size); 164162306a36Sopenharmony_ci goto out; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci for (i = 0; i < index; i++) { 164562306a36Sopenharmony_ci if (skip) { 164662306a36Sopenharmony_ci skip--; 164762306a36Sopenharmony_ci continue; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci dtp = phba->nvmeio_trc + i; 165062306a36Sopenharmony_ci phba->nvmeio_trc_output_idx++; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci if (!dtp->fmt) 165362306a36Sopenharmony_ci continue; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, dtp->fmt, 165662306a36Sopenharmony_ci dtp->data1, dtp->data2, dtp->data3); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) { 165962306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 166062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 166162306a36Sopenharmony_ci "Trace Complete\n"); 166262306a36Sopenharmony_ci goto out; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) { 166662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 166762306a36Sopenharmony_ci "Trace Continue (%d of %d)\n", 166862306a36Sopenharmony_ci phba->nvmeio_trc_output_idx, 166962306a36Sopenharmony_ci phba->nvmeio_trc_size); 167062306a36Sopenharmony_ci goto out; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 167562306a36Sopenharmony_ci "Trace Done\n"); 167662306a36Sopenharmony_ciout: 167762306a36Sopenharmony_ci return len; 167862306a36Sopenharmony_ci} 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci/** 168162306a36Sopenharmony_ci * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer 168262306a36Sopenharmony_ci * @vport: The vport to gather target node info from. 168362306a36Sopenharmony_ci * @buf: The buffer to dump log into. 168462306a36Sopenharmony_ci * @size: The maximum amount of data to process. 168562306a36Sopenharmony_ci * 168662306a36Sopenharmony_ci * Description: 168762306a36Sopenharmony_ci * This routine dumps the NVME + SCSI statistics associated with @vport 168862306a36Sopenharmony_ci * 168962306a36Sopenharmony_ci * Return Value: 169062306a36Sopenharmony_ci * This routine returns the amount of bytes that were dumped into @buf and will 169162306a36Sopenharmony_ci * not exceed @size. 169262306a36Sopenharmony_ci **/ 169362306a36Sopenharmony_cistatic int 169462306a36Sopenharmony_cilpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 169762306a36Sopenharmony_ci struct lpfc_hdwq_stat *c_stat; 169862306a36Sopenharmony_ci int i, j, len; 169962306a36Sopenharmony_ci uint32_t tot_xmt; 170062306a36Sopenharmony_ci uint32_t tot_rcv; 170162306a36Sopenharmony_ci uint32_t tot_cmpl; 170262306a36Sopenharmony_ci char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0}; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n"); 170562306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 170662306a36Sopenharmony_ci goto buffer_done; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ", 170962306a36Sopenharmony_ci (phba->hdwqstat_on & 171062306a36Sopenharmony_ci (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ? 171162306a36Sopenharmony_ci "Enabled" : "Disabled")); 171262306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 171362306a36Sopenharmony_ci goto buffer_done; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ", 171662306a36Sopenharmony_ci (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ? 171762306a36Sopenharmony_ci "Enabled" : "Disabled")); 171862306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 171962306a36Sopenharmony_ci goto buffer_done; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "\n\n"); 172262306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 172362306a36Sopenharmony_ci goto buffer_done; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 172662306a36Sopenharmony_ci tot_rcv = 0; 172762306a36Sopenharmony_ci tot_xmt = 0; 172862306a36Sopenharmony_ci tot_cmpl = 0; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci for_each_present_cpu(j) { 173162306a36Sopenharmony_ci c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci /* Only display for this HDWQ */ 173462306a36Sopenharmony_ci if (i != c_stat->hdwq_no) 173562306a36Sopenharmony_ci continue; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci /* Only display non-zero counters */ 173862306a36Sopenharmony_ci if (!c_stat->xmt_io && !c_stat->cmpl_io && 173962306a36Sopenharmony_ci !c_stat->rcv_io) 174062306a36Sopenharmony_ci continue; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci if (!tot_xmt && !tot_cmpl && !tot_rcv) { 174362306a36Sopenharmony_ci /* Print HDWQ string only the first time */ 174462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i); 174562306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 174662306a36Sopenharmony_ci goto buffer_done; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci tot_xmt += c_stat->xmt_io; 175062306a36Sopenharmony_ci tot_cmpl += c_stat->cmpl_io; 175162306a36Sopenharmony_ci if (phba->nvmet_support) 175262306a36Sopenharmony_ci tot_rcv += c_stat->rcv_io; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j); 175562306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 175662306a36Sopenharmony_ci goto buffer_done; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (phba->nvmet_support) { 175962306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 176062306a36Sopenharmony_ci "XMT 0x%x CMPL 0x%x RCV 0x%x |", 176162306a36Sopenharmony_ci c_stat->xmt_io, c_stat->cmpl_io, 176262306a36Sopenharmony_ci c_stat->rcv_io); 176362306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 176462306a36Sopenharmony_ci goto buffer_done; 176562306a36Sopenharmony_ci } else { 176662306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 176762306a36Sopenharmony_ci "XMT 0x%x CMPL 0x%x |", 176862306a36Sopenharmony_ci c_stat->xmt_io, c_stat->cmpl_io); 176962306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 177062306a36Sopenharmony_ci goto buffer_done; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* Check if nothing to display */ 177562306a36Sopenharmony_ci if (!tot_xmt && !tot_cmpl && !tot_rcv) 177662306a36Sopenharmony_ci continue; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: "); 177962306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 178062306a36Sopenharmony_ci goto buffer_done; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (phba->nvmet_support) { 178362306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 178462306a36Sopenharmony_ci "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n", 178562306a36Sopenharmony_ci tot_xmt, tot_cmpl, tot_rcv); 178662306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 178762306a36Sopenharmony_ci goto buffer_done; 178862306a36Sopenharmony_ci } else { 178962306a36Sopenharmony_ci scnprintf(tmp, sizeof(tmp), 179062306a36Sopenharmony_ci "XMT 0x%x CMPL 0x%x]\n\n", 179162306a36Sopenharmony_ci tot_xmt, tot_cmpl); 179262306a36Sopenharmony_ci if (strlcat(buf, tmp, size) >= size) 179362306a36Sopenharmony_ci goto buffer_done; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cibuffer_done: 179862306a36Sopenharmony_ci len = strnlen(buf, size); 179962306a36Sopenharmony_ci return len; 180062306a36Sopenharmony_ci} 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci#endif 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci/** 180562306a36Sopenharmony_ci * lpfc_debugfs_disc_trc - Store discovery trace log 180662306a36Sopenharmony_ci * @vport: The vport to associate this trace string with for retrieval. 180762306a36Sopenharmony_ci * @mask: Log entry classification. 180862306a36Sopenharmony_ci * @fmt: Format string to be displayed when dumping the log. 180962306a36Sopenharmony_ci * @data1: 1st data parameter to be applied to @fmt. 181062306a36Sopenharmony_ci * @data2: 2nd data parameter to be applied to @fmt. 181162306a36Sopenharmony_ci * @data3: 3rd data parameter to be applied to @fmt. 181262306a36Sopenharmony_ci * 181362306a36Sopenharmony_ci * Description: 181462306a36Sopenharmony_ci * This routine is used by the driver code to add a debugfs log entry to the 181562306a36Sopenharmony_ci * discovery trace buffer associated with @vport. Only entries with a @mask that 181662306a36Sopenharmony_ci * match the current debugfs discovery mask will be saved. Entries that do not 181762306a36Sopenharmony_ci * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like 181862306a36Sopenharmony_ci * printf when displaying the log. 181962306a36Sopenharmony_ci **/ 182062306a36Sopenharmony_ciinline void 182162306a36Sopenharmony_cilpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt, 182262306a36Sopenharmony_ci uint32_t data1, uint32_t data2, uint32_t data3) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 182562306a36Sopenharmony_ci struct lpfc_debugfs_trc *dtp; 182662306a36Sopenharmony_ci int index; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (!(lpfc_debugfs_mask_disc_trc & mask)) 182962306a36Sopenharmony_ci return; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc || 183262306a36Sopenharmony_ci !vport || !vport->disc_trc) 183362306a36Sopenharmony_ci return; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci index = atomic_inc_return(&vport->disc_trc_cnt) & 183662306a36Sopenharmony_ci (lpfc_debugfs_max_disc_trc - 1); 183762306a36Sopenharmony_ci dtp = vport->disc_trc + index; 183862306a36Sopenharmony_ci dtp->fmt = fmt; 183962306a36Sopenharmony_ci dtp->data1 = data1; 184062306a36Sopenharmony_ci dtp->data2 = data2; 184162306a36Sopenharmony_ci dtp->data3 = data3; 184262306a36Sopenharmony_ci dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); 184362306a36Sopenharmony_ci dtp->jif = jiffies; 184462306a36Sopenharmony_ci#endif 184562306a36Sopenharmony_ci return; 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci/** 184962306a36Sopenharmony_ci * lpfc_debugfs_slow_ring_trc - Store slow ring trace log 185062306a36Sopenharmony_ci * @phba: The phba to associate this trace string with for retrieval. 185162306a36Sopenharmony_ci * @fmt: Format string to be displayed when dumping the log. 185262306a36Sopenharmony_ci * @data1: 1st data parameter to be applied to @fmt. 185362306a36Sopenharmony_ci * @data2: 2nd data parameter to be applied to @fmt. 185462306a36Sopenharmony_ci * @data3: 3rd data parameter to be applied to @fmt. 185562306a36Sopenharmony_ci * 185662306a36Sopenharmony_ci * Description: 185762306a36Sopenharmony_ci * This routine is used by the driver code to add a debugfs log entry to the 185862306a36Sopenharmony_ci * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and 185962306a36Sopenharmony_ci * @data3 are used like printf when displaying the log. 186062306a36Sopenharmony_ci **/ 186162306a36Sopenharmony_ciinline void 186262306a36Sopenharmony_cilpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt, 186362306a36Sopenharmony_ci uint32_t data1, uint32_t data2, uint32_t data3) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 186662306a36Sopenharmony_ci struct lpfc_debugfs_trc *dtp; 186762306a36Sopenharmony_ci int index; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc || 187062306a36Sopenharmony_ci !phba || !phba->slow_ring_trc) 187162306a36Sopenharmony_ci return; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci index = atomic_inc_return(&phba->slow_ring_trc_cnt) & 187462306a36Sopenharmony_ci (lpfc_debugfs_max_slow_ring_trc - 1); 187562306a36Sopenharmony_ci dtp = phba->slow_ring_trc + index; 187662306a36Sopenharmony_ci dtp->fmt = fmt; 187762306a36Sopenharmony_ci dtp->data1 = data1; 187862306a36Sopenharmony_ci dtp->data2 = data2; 187962306a36Sopenharmony_ci dtp->data3 = data3; 188062306a36Sopenharmony_ci dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); 188162306a36Sopenharmony_ci dtp->jif = jiffies; 188262306a36Sopenharmony_ci#endif 188362306a36Sopenharmony_ci return; 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci/** 188762306a36Sopenharmony_ci * lpfc_debugfs_nvme_trc - Store NVME/NVMET trace log 188862306a36Sopenharmony_ci * @phba: The phba to associate this trace string with for retrieval. 188962306a36Sopenharmony_ci * @fmt: Format string to be displayed when dumping the log. 189062306a36Sopenharmony_ci * @data1: 1st data parameter to be applied to @fmt. 189162306a36Sopenharmony_ci * @data2: 2nd data parameter to be applied to @fmt. 189262306a36Sopenharmony_ci * @data3: 3rd data parameter to be applied to @fmt. 189362306a36Sopenharmony_ci * 189462306a36Sopenharmony_ci * Description: 189562306a36Sopenharmony_ci * This routine is used by the driver code to add a debugfs log entry to the 189662306a36Sopenharmony_ci * nvme trace buffer associated with @phba. @fmt, @data1, @data2, and 189762306a36Sopenharmony_ci * @data3 are used like printf when displaying the log. 189862306a36Sopenharmony_ci **/ 189962306a36Sopenharmony_ciinline void 190062306a36Sopenharmony_cilpfc_debugfs_nvme_trc(struct lpfc_hba *phba, char *fmt, 190162306a36Sopenharmony_ci uint16_t data1, uint16_t data2, uint32_t data3) 190262306a36Sopenharmony_ci{ 190362306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 190462306a36Sopenharmony_ci struct lpfc_debugfs_nvmeio_trc *dtp; 190562306a36Sopenharmony_ci int index; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if (!phba->nvmeio_trc_on || !phba->nvmeio_trc) 190862306a36Sopenharmony_ci return; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci index = atomic_inc_return(&phba->nvmeio_trc_cnt) & 191162306a36Sopenharmony_ci (phba->nvmeio_trc_size - 1); 191262306a36Sopenharmony_ci dtp = phba->nvmeio_trc + index; 191362306a36Sopenharmony_ci dtp->fmt = fmt; 191462306a36Sopenharmony_ci dtp->data1 = data1; 191562306a36Sopenharmony_ci dtp->data2 = data2; 191662306a36Sopenharmony_ci dtp->data3 = data3; 191762306a36Sopenharmony_ci#endif 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 192162306a36Sopenharmony_ci/** 192262306a36Sopenharmony_ci * lpfc_debugfs_disc_trc_open - Open the discovery trace log 192362306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 192462306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 192562306a36Sopenharmony_ci * 192662306a36Sopenharmony_ci * Description: 192762306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 192862306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 192962306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 193062306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 193162306a36Sopenharmony_ci * 193262306a36Sopenharmony_ci * Returns: 193362306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 193462306a36Sopenharmony_ci * error value. 193562306a36Sopenharmony_ci **/ 193662306a36Sopenharmony_cistatic int 193762306a36Sopenharmony_cilpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 194062306a36Sopenharmony_ci struct lpfc_debug *debug; 194162306a36Sopenharmony_ci int size; 194262306a36Sopenharmony_ci int rc = -ENOMEM; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (!lpfc_debugfs_max_disc_trc) { 194562306a36Sopenharmony_ci rc = -ENOSPC; 194662306a36Sopenharmony_ci goto out; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 195062306a36Sopenharmony_ci if (!debug) 195162306a36Sopenharmony_ci goto out; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci /* Round to page boundary */ 195462306a36Sopenharmony_ci size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); 195562306a36Sopenharmony_ci size = PAGE_ALIGN(size); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci debug->buffer = kmalloc(size, GFP_KERNEL); 195862306a36Sopenharmony_ci if (!debug->buffer) { 195962306a36Sopenharmony_ci kfree(debug); 196062306a36Sopenharmony_ci goto out; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size); 196462306a36Sopenharmony_ci file->private_data = debug; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci rc = 0; 196762306a36Sopenharmony_ciout: 196862306a36Sopenharmony_ci return rc; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci/** 197262306a36Sopenharmony_ci * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log 197362306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 197462306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 197562306a36Sopenharmony_ci * 197662306a36Sopenharmony_ci * Description: 197762306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 197862306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 197962306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 198062306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 198162306a36Sopenharmony_ci * 198262306a36Sopenharmony_ci * Returns: 198362306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 198462306a36Sopenharmony_ci * error value. 198562306a36Sopenharmony_ci **/ 198662306a36Sopenharmony_cistatic int 198762306a36Sopenharmony_cilpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file) 198862306a36Sopenharmony_ci{ 198962306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 199062306a36Sopenharmony_ci struct lpfc_debug *debug; 199162306a36Sopenharmony_ci int size; 199262306a36Sopenharmony_ci int rc = -ENOMEM; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci if (!lpfc_debugfs_max_slow_ring_trc) { 199562306a36Sopenharmony_ci rc = -ENOSPC; 199662306a36Sopenharmony_ci goto out; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 200062306a36Sopenharmony_ci if (!debug) 200162306a36Sopenharmony_ci goto out; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci /* Round to page boundary */ 200462306a36Sopenharmony_ci size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); 200562306a36Sopenharmony_ci size = PAGE_ALIGN(size); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci debug->buffer = kmalloc(size, GFP_KERNEL); 200862306a36Sopenharmony_ci if (!debug->buffer) { 200962306a36Sopenharmony_ci kfree(debug); 201062306a36Sopenharmony_ci goto out; 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size); 201462306a36Sopenharmony_ci file->private_data = debug; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci rc = 0; 201762306a36Sopenharmony_ciout: 201862306a36Sopenharmony_ci return rc; 201962306a36Sopenharmony_ci} 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci/** 202262306a36Sopenharmony_ci * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer 202362306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 202462306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 202562306a36Sopenharmony_ci * 202662306a36Sopenharmony_ci * Description: 202762306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 202862306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 202962306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 203062306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 203162306a36Sopenharmony_ci * 203262306a36Sopenharmony_ci * Returns: 203362306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 203462306a36Sopenharmony_ci * error value. 203562306a36Sopenharmony_ci **/ 203662306a36Sopenharmony_cistatic int 203762306a36Sopenharmony_cilpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file) 203862306a36Sopenharmony_ci{ 203962306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 204062306a36Sopenharmony_ci struct lpfc_debug *debug; 204162306a36Sopenharmony_ci int rc = -ENOMEM; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 204462306a36Sopenharmony_ci if (!debug) 204562306a36Sopenharmony_ci goto out; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci /* Round to page boundary */ 204862306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL); 204962306a36Sopenharmony_ci if (!debug->buffer) { 205062306a36Sopenharmony_ci kfree(debug); 205162306a36Sopenharmony_ci goto out; 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer, 205562306a36Sopenharmony_ci LPFC_HBQINFO_SIZE); 205662306a36Sopenharmony_ci file->private_data = debug; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci rc = 0; 205962306a36Sopenharmony_ciout: 206062306a36Sopenharmony_ci return rc; 206162306a36Sopenharmony_ci} 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci/** 206462306a36Sopenharmony_ci * lpfc_debugfs_multixripools_open - Open the multixripool debugfs buffer 206562306a36Sopenharmony_ci * @inode: The inode pointer that contains a hba pointer. 206662306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 206762306a36Sopenharmony_ci * 206862306a36Sopenharmony_ci * Description: 206962306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 207062306a36Sopenharmony_ci * the hba from the i_private field in @inode, allocates the necessary buffer 207162306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this hba, and then 207262306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 207362306a36Sopenharmony_ci * 207462306a36Sopenharmony_ci * Returns: 207562306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 207662306a36Sopenharmony_ci * error value. 207762306a36Sopenharmony_ci **/ 207862306a36Sopenharmony_cistatic int 207962306a36Sopenharmony_cilpfc_debugfs_multixripools_open(struct inode *inode, struct file *file) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 208262306a36Sopenharmony_ci struct lpfc_debug *debug; 208362306a36Sopenharmony_ci int rc = -ENOMEM; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 208662306a36Sopenharmony_ci if (!debug) 208762306a36Sopenharmony_ci goto out; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* Round to page boundary */ 209062306a36Sopenharmony_ci debug->buffer = kzalloc(LPFC_DUMP_MULTIXRIPOOL_SIZE, GFP_KERNEL); 209162306a36Sopenharmony_ci if (!debug->buffer) { 209262306a36Sopenharmony_ci kfree(debug); 209362306a36Sopenharmony_ci goto out; 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci debug->len = lpfc_debugfs_multixripools_data( 209762306a36Sopenharmony_ci phba, debug->buffer, LPFC_DUMP_MULTIXRIPOOL_SIZE); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci debug->i_private = inode->i_private; 210062306a36Sopenharmony_ci file->private_data = debug; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci rc = 0; 210362306a36Sopenharmony_ciout: 210462306a36Sopenharmony_ci return rc; 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci#ifdef LPFC_HDWQ_LOCK_STAT 210862306a36Sopenharmony_ci/** 210962306a36Sopenharmony_ci * lpfc_debugfs_lockstat_open - Open the lockstat debugfs buffer 211062306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 211162306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 211262306a36Sopenharmony_ci * 211362306a36Sopenharmony_ci * Description: 211462306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 211562306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 211662306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 211762306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 211862306a36Sopenharmony_ci * 211962306a36Sopenharmony_ci * Returns: 212062306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 212162306a36Sopenharmony_ci * error value. 212262306a36Sopenharmony_ci **/ 212362306a36Sopenharmony_cistatic int 212462306a36Sopenharmony_cilpfc_debugfs_lockstat_open(struct inode *inode, struct file *file) 212562306a36Sopenharmony_ci{ 212662306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 212762306a36Sopenharmony_ci struct lpfc_debug *debug; 212862306a36Sopenharmony_ci int rc = -ENOMEM; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 213162306a36Sopenharmony_ci if (!debug) 213262306a36Sopenharmony_ci goto out; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci /* Round to page boundary */ 213562306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_HDWQINFO_SIZE, GFP_KERNEL); 213662306a36Sopenharmony_ci if (!debug->buffer) { 213762306a36Sopenharmony_ci kfree(debug); 213862306a36Sopenharmony_ci goto out; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci debug->len = lpfc_debugfs_lockstat_data(phba, debug->buffer, 214262306a36Sopenharmony_ci LPFC_HBQINFO_SIZE); 214362306a36Sopenharmony_ci file->private_data = debug; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci rc = 0; 214662306a36Sopenharmony_ciout: 214762306a36Sopenharmony_ci return rc; 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic ssize_t 215162306a36Sopenharmony_cilpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, 215262306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 215562306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 215662306a36Sopenharmony_ci struct lpfc_sli4_hdw_queue *qp; 215762306a36Sopenharmony_ci char mybuf[64]; 215862306a36Sopenharmony_ci char *pbuf; 215962306a36Sopenharmony_ci int i; 216062306a36Sopenharmony_ci size_t bsize; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci bsize = min(nbytes, (sizeof(mybuf) - 1)); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, bsize)) 216762306a36Sopenharmony_ci return -EFAULT; 216862306a36Sopenharmony_ci pbuf = &mybuf[0]; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if ((strncmp(pbuf, "reset", strlen("reset")) == 0) || 217162306a36Sopenharmony_ci (strncmp(pbuf, "zero", strlen("zero")) == 0)) { 217262306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 217362306a36Sopenharmony_ci qp = &phba->sli4_hba.hdwq[i]; 217462306a36Sopenharmony_ci qp->lock_conflict.alloc_xri_get = 0; 217562306a36Sopenharmony_ci qp->lock_conflict.alloc_xri_put = 0; 217662306a36Sopenharmony_ci qp->lock_conflict.free_xri = 0; 217762306a36Sopenharmony_ci qp->lock_conflict.wq_access = 0; 217862306a36Sopenharmony_ci qp->lock_conflict.alloc_pvt_pool = 0; 217962306a36Sopenharmony_ci qp->lock_conflict.mv_from_pvt_pool = 0; 218062306a36Sopenharmony_ci qp->lock_conflict.mv_to_pub_pool = 0; 218162306a36Sopenharmony_ci qp->lock_conflict.mv_to_pvt_pool = 0; 218262306a36Sopenharmony_ci qp->lock_conflict.free_pvt_pool = 0; 218362306a36Sopenharmony_ci qp->lock_conflict.free_pub_pool = 0; 218462306a36Sopenharmony_ci qp->lock_conflict.wq_access = 0; 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci return bsize; 218862306a36Sopenharmony_ci} 218962306a36Sopenharmony_ci#endif 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_cistatic int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba, 219262306a36Sopenharmony_ci char *buffer, int size) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci int copied = 0; 219562306a36Sopenharmony_ci struct lpfc_dmabuf *dmabuf, *next; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci memset(buffer, 0, size); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 220062306a36Sopenharmony_ci if (phba->ras_fwlog.state != ACTIVE) { 220162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 220262306a36Sopenharmony_ci return -EINVAL; 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci list_for_each_entry_safe(dmabuf, next, 220762306a36Sopenharmony_ci &phba->ras_fwlog.fwlog_buff_list, list) { 220862306a36Sopenharmony_ci /* Check if copying will go over size and a '\0' char */ 220962306a36Sopenharmony_ci if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) { 221062306a36Sopenharmony_ci memcpy(buffer + copied, dmabuf->virt, 221162306a36Sopenharmony_ci size - copied - 1); 221262306a36Sopenharmony_ci copied += size - copied - 1; 221362306a36Sopenharmony_ci break; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE); 221662306a36Sopenharmony_ci copied += LPFC_RAS_MAX_ENTRY_SIZE; 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci return copied; 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_cistatic int 222262306a36Sopenharmony_cilpfc_debugfs_ras_log_release(struct inode *inode, struct file *file) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci vfree(debug->buffer); 222762306a36Sopenharmony_ci kfree(debug); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci return 0; 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci/** 223362306a36Sopenharmony_ci * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer 223462306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 223562306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 223662306a36Sopenharmony_ci * 223762306a36Sopenharmony_ci * Description: 223862306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 223962306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 224062306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 224162306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 224262306a36Sopenharmony_ci * 224362306a36Sopenharmony_ci * Returns: 224462306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 224562306a36Sopenharmony_ci * error value. 224662306a36Sopenharmony_ci **/ 224762306a36Sopenharmony_cistatic int 224862306a36Sopenharmony_cilpfc_debugfs_ras_log_open(struct inode *inode, struct file *file) 224962306a36Sopenharmony_ci{ 225062306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 225162306a36Sopenharmony_ci struct lpfc_debug *debug; 225262306a36Sopenharmony_ci int size; 225362306a36Sopenharmony_ci int rc = -ENOMEM; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 225662306a36Sopenharmony_ci if (phba->ras_fwlog.state != ACTIVE) { 225762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 225862306a36Sopenharmony_ci rc = -EINVAL; 225962306a36Sopenharmony_ci goto out; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (check_mul_overflow(LPFC_RAS_MIN_BUFF_POST_SIZE, 226462306a36Sopenharmony_ci phba->cfg_ras_fwlog_buffsize, &size)) 226562306a36Sopenharmony_ci goto out; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci debug = kzalloc(sizeof(*debug), GFP_KERNEL); 226862306a36Sopenharmony_ci if (!debug) 226962306a36Sopenharmony_ci goto out; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci debug->buffer = vmalloc(size); 227262306a36Sopenharmony_ci if (!debug->buffer) 227362306a36Sopenharmony_ci goto free_debug; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size); 227662306a36Sopenharmony_ci if (debug->len < 0) { 227762306a36Sopenharmony_ci rc = -EINVAL; 227862306a36Sopenharmony_ci goto free_buffer; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci file->private_data = debug; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_cifree_buffer: 228562306a36Sopenharmony_ci vfree(debug->buffer); 228662306a36Sopenharmony_cifree_debug: 228762306a36Sopenharmony_ci kfree(debug); 228862306a36Sopenharmony_ciout: 228962306a36Sopenharmony_ci return rc; 229062306a36Sopenharmony_ci} 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci/** 229362306a36Sopenharmony_ci * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer 229462306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 229562306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 229662306a36Sopenharmony_ci * 229762306a36Sopenharmony_ci * Description: 229862306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 229962306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 230062306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 230162306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 230262306a36Sopenharmony_ci * 230362306a36Sopenharmony_ci * Returns: 230462306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 230562306a36Sopenharmony_ci * error value. 230662306a36Sopenharmony_ci **/ 230762306a36Sopenharmony_cistatic int 230862306a36Sopenharmony_cilpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) 230962306a36Sopenharmony_ci{ 231062306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 231162306a36Sopenharmony_ci struct lpfc_debug *debug; 231262306a36Sopenharmony_ci int rc = -ENOMEM; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 231562306a36Sopenharmony_ci if (!debug) 231662306a36Sopenharmony_ci goto out; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci /* Round to page boundary */ 231962306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL); 232062306a36Sopenharmony_ci if (!debug->buffer) { 232162306a36Sopenharmony_ci kfree(debug); 232262306a36Sopenharmony_ci goto out; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer, 232662306a36Sopenharmony_ci LPFC_DUMPHBASLIM_SIZE); 232762306a36Sopenharmony_ci file->private_data = debug; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci rc = 0; 233062306a36Sopenharmony_ciout: 233162306a36Sopenharmony_ci return rc; 233262306a36Sopenharmony_ci} 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci/** 233562306a36Sopenharmony_ci * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer 233662306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 233762306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 233862306a36Sopenharmony_ci * 233962306a36Sopenharmony_ci * Description: 234062306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 234162306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 234262306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 234362306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 234462306a36Sopenharmony_ci * 234562306a36Sopenharmony_ci * Returns: 234662306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 234762306a36Sopenharmony_ci * error value. 234862306a36Sopenharmony_ci **/ 234962306a36Sopenharmony_cistatic int 235062306a36Sopenharmony_cilpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) 235162306a36Sopenharmony_ci{ 235262306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 235362306a36Sopenharmony_ci struct lpfc_debug *debug; 235462306a36Sopenharmony_ci int rc = -ENOMEM; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 235762306a36Sopenharmony_ci if (!debug) 235862306a36Sopenharmony_ci goto out; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci /* Round to page boundary */ 236162306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL); 236262306a36Sopenharmony_ci if (!debug->buffer) { 236362306a36Sopenharmony_ci kfree(debug); 236462306a36Sopenharmony_ci goto out; 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer, 236862306a36Sopenharmony_ci LPFC_DUMPHOSTSLIM_SIZE); 236962306a36Sopenharmony_ci file->private_data = debug; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci rc = 0; 237262306a36Sopenharmony_ciout: 237362306a36Sopenharmony_ci return rc; 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_cistatic ssize_t 237762306a36Sopenharmony_cilpfc_debugfs_dif_err_read(struct file *file, char __user *buf, 237862306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 237962306a36Sopenharmony_ci{ 238062306a36Sopenharmony_ci struct dentry *dent = file->f_path.dentry; 238162306a36Sopenharmony_ci struct lpfc_hba *phba = file->private_data; 238262306a36Sopenharmony_ci char cbuf[32]; 238362306a36Sopenharmony_ci uint64_t tmp = 0; 238462306a36Sopenharmony_ci int cnt = 0; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (dent == phba->debug_writeGuard) 238762306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); 238862306a36Sopenharmony_ci else if (dent == phba->debug_writeApp) 238962306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); 239062306a36Sopenharmony_ci else if (dent == phba->debug_writeRef) 239162306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); 239262306a36Sopenharmony_ci else if (dent == phba->debug_readGuard) 239362306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); 239462306a36Sopenharmony_ci else if (dent == phba->debug_readApp) 239562306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); 239662306a36Sopenharmony_ci else if (dent == phba->debug_readRef) 239762306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); 239862306a36Sopenharmony_ci else if (dent == phba->debug_InjErrNPortID) 239962306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "0x%06x\n", 240062306a36Sopenharmony_ci phba->lpfc_injerr_nportid); 240162306a36Sopenharmony_ci else if (dent == phba->debug_InjErrWWPN) { 240262306a36Sopenharmony_ci memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); 240362306a36Sopenharmony_ci tmp = cpu_to_be64(tmp); 240462306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp); 240562306a36Sopenharmony_ci } else if (dent == phba->debug_InjErrLBA) { 240662306a36Sopenharmony_ci if (phba->lpfc_injerr_lba == (sector_t)(-1)) 240762306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "off\n"); 240862306a36Sopenharmony_ci else 240962306a36Sopenharmony_ci cnt = scnprintf(cbuf, 32, "0x%llx\n", 241062306a36Sopenharmony_ci (uint64_t) phba->lpfc_injerr_lba); 241162306a36Sopenharmony_ci } else 241262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 241362306a36Sopenharmony_ci "0547 Unknown debugfs error injection entry\n"); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt); 241662306a36Sopenharmony_ci} 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_cistatic ssize_t 241962306a36Sopenharmony_cilpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, 242062306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 242162306a36Sopenharmony_ci{ 242262306a36Sopenharmony_ci struct dentry *dent = file->f_path.dentry; 242362306a36Sopenharmony_ci struct lpfc_hba *phba = file->private_data; 242462306a36Sopenharmony_ci char dstbuf[33]; 242562306a36Sopenharmony_ci uint64_t tmp = 0; 242662306a36Sopenharmony_ci int size; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci memset(dstbuf, 0, 33); 242962306a36Sopenharmony_ci size = (nbytes < 32) ? nbytes : 32; 243062306a36Sopenharmony_ci if (copy_from_user(dstbuf, buf, size)) 243162306a36Sopenharmony_ci return -EFAULT; 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci if (dent == phba->debug_InjErrLBA) { 243462306a36Sopenharmony_ci if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && 243562306a36Sopenharmony_ci (dstbuf[2] == 'f')) 243662306a36Sopenharmony_ci tmp = (uint64_t)(-1); 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) 244062306a36Sopenharmony_ci return -EINVAL; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci if (dent == phba->debug_writeGuard) 244362306a36Sopenharmony_ci phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; 244462306a36Sopenharmony_ci else if (dent == phba->debug_writeApp) 244562306a36Sopenharmony_ci phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; 244662306a36Sopenharmony_ci else if (dent == phba->debug_writeRef) 244762306a36Sopenharmony_ci phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; 244862306a36Sopenharmony_ci else if (dent == phba->debug_readGuard) 244962306a36Sopenharmony_ci phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp; 245062306a36Sopenharmony_ci else if (dent == phba->debug_readApp) 245162306a36Sopenharmony_ci phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; 245262306a36Sopenharmony_ci else if (dent == phba->debug_readRef) 245362306a36Sopenharmony_ci phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; 245462306a36Sopenharmony_ci else if (dent == phba->debug_InjErrLBA) 245562306a36Sopenharmony_ci phba->lpfc_injerr_lba = (sector_t)tmp; 245662306a36Sopenharmony_ci else if (dent == phba->debug_InjErrNPortID) 245762306a36Sopenharmony_ci phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); 245862306a36Sopenharmony_ci else if (dent == phba->debug_InjErrWWPN) { 245962306a36Sopenharmony_ci tmp = cpu_to_be64(tmp); 246062306a36Sopenharmony_ci memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); 246162306a36Sopenharmony_ci } else 246262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 246362306a36Sopenharmony_ci "0548 Unknown debugfs error injection entry\n"); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci return nbytes; 246662306a36Sopenharmony_ci} 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_cistatic int 246962306a36Sopenharmony_cilpfc_debugfs_dif_err_release(struct inode *inode, struct file *file) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci return 0; 247262306a36Sopenharmony_ci} 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci/** 247562306a36Sopenharmony_ci * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file 247662306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. 247762306a36Sopenharmony_ci * @file: The file pointer to attach the log output. 247862306a36Sopenharmony_ci * 247962306a36Sopenharmony_ci * Description: 248062306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It gets 248162306a36Sopenharmony_ci * the vport from the i_private field in @inode, allocates the necessary buffer 248262306a36Sopenharmony_ci * for the log, fills the buffer from the in-memory log for this vport, and then 248362306a36Sopenharmony_ci * returns a pointer to that log in the private_data field in @file. 248462306a36Sopenharmony_ci * 248562306a36Sopenharmony_ci * Returns: 248662306a36Sopenharmony_ci * This function returns zero if successful. On error it will return a negative 248762306a36Sopenharmony_ci * error value. 248862306a36Sopenharmony_ci **/ 248962306a36Sopenharmony_cistatic int 249062306a36Sopenharmony_cilpfc_debugfs_nodelist_open(struct inode *inode, struct file *file) 249162306a36Sopenharmony_ci{ 249262306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 249362306a36Sopenharmony_ci struct lpfc_debug *debug; 249462306a36Sopenharmony_ci int rc = -ENOMEM; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 249762306a36Sopenharmony_ci if (!debug) 249862306a36Sopenharmony_ci goto out; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci /* Round to page boundary */ 250162306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL); 250262306a36Sopenharmony_ci if (!debug->buffer) { 250362306a36Sopenharmony_ci kfree(debug); 250462306a36Sopenharmony_ci goto out; 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer, 250862306a36Sopenharmony_ci LPFC_NODELIST_SIZE); 250962306a36Sopenharmony_ci file->private_data = debug; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci rc = 0; 251262306a36Sopenharmony_ciout: 251362306a36Sopenharmony_ci return rc; 251462306a36Sopenharmony_ci} 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci/** 251762306a36Sopenharmony_ci * lpfc_debugfs_lseek - Seek through a debugfs file 251862306a36Sopenharmony_ci * @file: The file pointer to seek through. 251962306a36Sopenharmony_ci * @off: The offset to seek to or the amount to seek by. 252062306a36Sopenharmony_ci * @whence: Indicates how to seek. 252162306a36Sopenharmony_ci * 252262306a36Sopenharmony_ci * Description: 252362306a36Sopenharmony_ci * This routine is the entry point for the debugfs lseek file operation. The 252462306a36Sopenharmony_ci * @whence parameter indicates whether @off is the offset to directly seek to, 252562306a36Sopenharmony_ci * or if it is a value to seek forward or reverse by. This function figures out 252662306a36Sopenharmony_ci * what the new offset of the debugfs file will be and assigns that value to the 252762306a36Sopenharmony_ci * f_pos field of @file. 252862306a36Sopenharmony_ci * 252962306a36Sopenharmony_ci * Returns: 253062306a36Sopenharmony_ci * This function returns the new offset if successful and returns a negative 253162306a36Sopenharmony_ci * error if unable to process the seek. 253262306a36Sopenharmony_ci **/ 253362306a36Sopenharmony_cistatic loff_t 253462306a36Sopenharmony_cilpfc_debugfs_lseek(struct file *file, loff_t off, int whence) 253562306a36Sopenharmony_ci{ 253662306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 253762306a36Sopenharmony_ci return fixed_size_llseek(file, off, whence, debug->len); 253862306a36Sopenharmony_ci} 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci/** 254162306a36Sopenharmony_ci * lpfc_debugfs_read - Read a debugfs file 254262306a36Sopenharmony_ci * @file: The file pointer to read from. 254362306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 254462306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 254562306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 254662306a36Sopenharmony_ci * 254762306a36Sopenharmony_ci * Description: 254862306a36Sopenharmony_ci * This routine reads data from from the buffer indicated in the private_data 254962306a36Sopenharmony_ci * field of @file. It will start reading at @ppos and copy up to @nbytes of 255062306a36Sopenharmony_ci * data to @buf. 255162306a36Sopenharmony_ci * 255262306a36Sopenharmony_ci * Returns: 255362306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 255462306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 255562306a36Sopenharmony_ci **/ 255662306a36Sopenharmony_cistatic ssize_t 255762306a36Sopenharmony_cilpfc_debugfs_read(struct file *file, char __user *buf, 255862306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 255962306a36Sopenharmony_ci{ 256062306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer, 256362306a36Sopenharmony_ci debug->len); 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci/** 256762306a36Sopenharmony_ci * lpfc_debugfs_release - Release the buffer used to store debugfs file data 256862306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. (unused) 256962306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release. 257062306a36Sopenharmony_ci * 257162306a36Sopenharmony_ci * Description: 257262306a36Sopenharmony_ci * This routine frees the buffer that was allocated when the debugfs file was 257362306a36Sopenharmony_ci * opened. 257462306a36Sopenharmony_ci * 257562306a36Sopenharmony_ci * Returns: 257662306a36Sopenharmony_ci * This function returns zero. 257762306a36Sopenharmony_ci **/ 257862306a36Sopenharmony_cistatic int 257962306a36Sopenharmony_cilpfc_debugfs_release(struct inode *inode, struct file *file) 258062306a36Sopenharmony_ci{ 258162306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci kfree(debug->buffer); 258462306a36Sopenharmony_ci kfree(debug); 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci return 0; 258762306a36Sopenharmony_ci} 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci/** 259062306a36Sopenharmony_ci * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics 259162306a36Sopenharmony_ci * @file: The file pointer to read from. 259262306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 259362306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 259462306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 259562306a36Sopenharmony_ci * 259662306a36Sopenharmony_ci * Description: 259762306a36Sopenharmony_ci * This routine clears multi-XRI pools statistics when buf contains "clear". 259862306a36Sopenharmony_ci * 259962306a36Sopenharmony_ci * Return Value: 260062306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 260162306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 260262306a36Sopenharmony_ci * space. 260362306a36Sopenharmony_ci **/ 260462306a36Sopenharmony_cistatic ssize_t 260562306a36Sopenharmony_cilpfc_debugfs_multixripools_write(struct file *file, const char __user *buf, 260662306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 260762306a36Sopenharmony_ci{ 260862306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 260962306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 261062306a36Sopenharmony_ci char mybuf[64]; 261162306a36Sopenharmony_ci char *pbuf; 261262306a36Sopenharmony_ci u32 i; 261362306a36Sopenharmony_ci u32 hwq_count; 261462306a36Sopenharmony_ci struct lpfc_sli4_hdw_queue *qp; 261562306a36Sopenharmony_ci struct lpfc_multixri_pool *multixri_pool; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci if (nbytes > sizeof(mybuf) - 1) 261862306a36Sopenharmony_ci nbytes = sizeof(mybuf) - 1; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, nbytes)) 262362306a36Sopenharmony_ci return -EFAULT; 262462306a36Sopenharmony_ci pbuf = &mybuf[0]; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci if ((strncmp(pbuf, "clear", strlen("clear"))) == 0) { 262762306a36Sopenharmony_ci hwq_count = phba->cfg_hdw_queue; 262862306a36Sopenharmony_ci for (i = 0; i < hwq_count; i++) { 262962306a36Sopenharmony_ci qp = &phba->sli4_hba.hdwq[i]; 263062306a36Sopenharmony_ci multixri_pool = qp->p_multixri_pool; 263162306a36Sopenharmony_ci if (!multixri_pool) 263262306a36Sopenharmony_ci continue; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci qp->empty_io_bufs = 0; 263562306a36Sopenharmony_ci multixri_pool->pbl_empty_count = 0; 263662306a36Sopenharmony_ci#ifdef LPFC_MXP_STAT 263762306a36Sopenharmony_ci multixri_pool->above_limit_count = 0; 263862306a36Sopenharmony_ci multixri_pool->below_limit_count = 0; 263962306a36Sopenharmony_ci multixri_pool->stat_max_hwm = 0; 264062306a36Sopenharmony_ci multixri_pool->local_pbl_hit_count = 0; 264162306a36Sopenharmony_ci multixri_pool->other_pbl_hit_count = 0; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci multixri_pool->stat_pbl_count = 0; 264462306a36Sopenharmony_ci multixri_pool->stat_pvt_count = 0; 264562306a36Sopenharmony_ci multixri_pool->stat_busy_count = 0; 264662306a36Sopenharmony_ci multixri_pool->stat_snapshot_taken = 0; 264762306a36Sopenharmony_ci#endif 264862306a36Sopenharmony_ci } 264962306a36Sopenharmony_ci return strlen(pbuf); 265062306a36Sopenharmony_ci } 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci return -EINVAL; 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_cistatic int 265662306a36Sopenharmony_cilpfc_debugfs_nvmestat_open(struct inode *inode, struct file *file) 265762306a36Sopenharmony_ci{ 265862306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 265962306a36Sopenharmony_ci struct lpfc_debug *debug; 266062306a36Sopenharmony_ci int rc = -ENOMEM; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 266362306a36Sopenharmony_ci if (!debug) 266462306a36Sopenharmony_ci goto out; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci /* Round to page boundary */ 266762306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_NVMESTAT_SIZE, GFP_KERNEL); 266862306a36Sopenharmony_ci if (!debug->buffer) { 266962306a36Sopenharmony_ci kfree(debug); 267062306a36Sopenharmony_ci goto out; 267162306a36Sopenharmony_ci } 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci debug->len = lpfc_debugfs_nvmestat_data(vport, debug->buffer, 267462306a36Sopenharmony_ci LPFC_NVMESTAT_SIZE); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci debug->i_private = inode->i_private; 267762306a36Sopenharmony_ci file->private_data = debug; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci rc = 0; 268062306a36Sopenharmony_ciout: 268162306a36Sopenharmony_ci return rc; 268262306a36Sopenharmony_ci} 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_cistatic ssize_t 268562306a36Sopenharmony_cilpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf, 268662306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 268762306a36Sopenharmony_ci{ 268862306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 268962306a36Sopenharmony_ci struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; 269062306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 269162306a36Sopenharmony_ci struct lpfc_nvmet_tgtport *tgtp; 269262306a36Sopenharmony_ci char mybuf[64]; 269362306a36Sopenharmony_ci char *pbuf; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (!phba->targetport) 269662306a36Sopenharmony_ci return -ENXIO; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci if (nbytes > sizeof(mybuf) - 1) 269962306a36Sopenharmony_ci nbytes = sizeof(mybuf) - 1; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, nbytes)) 270462306a36Sopenharmony_ci return -EFAULT; 270562306a36Sopenharmony_ci pbuf = &mybuf[0]; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; 270862306a36Sopenharmony_ci if ((strncmp(pbuf, "reset", strlen("reset")) == 0) || 270962306a36Sopenharmony_ci (strncmp(pbuf, "zero", strlen("zero")) == 0)) { 271062306a36Sopenharmony_ci atomic_set(&tgtp->rcv_ls_req_in, 0); 271162306a36Sopenharmony_ci atomic_set(&tgtp->rcv_ls_req_out, 0); 271262306a36Sopenharmony_ci atomic_set(&tgtp->rcv_ls_req_drop, 0); 271362306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_abort, 0); 271462306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_abort_cmpl, 0); 271562306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_rsp, 0); 271662306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_drop, 0); 271762306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_rsp_error, 0); 271862306a36Sopenharmony_ci atomic_set(&tgtp->xmt_ls_rsp_cmpl, 0); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci atomic_set(&tgtp->rcv_fcp_cmd_in, 0); 272162306a36Sopenharmony_ci atomic_set(&tgtp->rcv_fcp_cmd_out, 0); 272262306a36Sopenharmony_ci atomic_set(&tgtp->rcv_fcp_cmd_drop, 0); 272362306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_drop, 0); 272462306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_read_rsp, 0); 272562306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_read, 0); 272662306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_write, 0); 272762306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_rsp, 0); 272862306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_release, 0); 272962306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_rsp_cmpl, 0); 273062306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_rsp_error, 0); 273162306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_rsp_drop, 0); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_abort, 0); 273462306a36Sopenharmony_ci atomic_set(&tgtp->xmt_fcp_abort_cmpl, 0); 273562306a36Sopenharmony_ci atomic_set(&tgtp->xmt_abort_sol, 0); 273662306a36Sopenharmony_ci atomic_set(&tgtp->xmt_abort_unsol, 0); 273762306a36Sopenharmony_ci atomic_set(&tgtp->xmt_abort_rsp, 0); 273862306a36Sopenharmony_ci atomic_set(&tgtp->xmt_abort_rsp_error, 0); 273962306a36Sopenharmony_ci } 274062306a36Sopenharmony_ci return nbytes; 274162306a36Sopenharmony_ci} 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_cistatic int 274462306a36Sopenharmony_cilpfc_debugfs_scsistat_open(struct inode *inode, struct file *file) 274562306a36Sopenharmony_ci{ 274662306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 274762306a36Sopenharmony_ci struct lpfc_debug *debug; 274862306a36Sopenharmony_ci int rc = -ENOMEM; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 275162306a36Sopenharmony_ci if (!debug) 275262306a36Sopenharmony_ci goto out; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci /* Round to page boundary */ 275562306a36Sopenharmony_ci debug->buffer = kzalloc(LPFC_SCSISTAT_SIZE, GFP_KERNEL); 275662306a36Sopenharmony_ci if (!debug->buffer) { 275762306a36Sopenharmony_ci kfree(debug); 275862306a36Sopenharmony_ci goto out; 275962306a36Sopenharmony_ci } 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci debug->len = lpfc_debugfs_scsistat_data(vport, debug->buffer, 276262306a36Sopenharmony_ci LPFC_SCSISTAT_SIZE); 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci debug->i_private = inode->i_private; 276562306a36Sopenharmony_ci file->private_data = debug; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci rc = 0; 276862306a36Sopenharmony_ciout: 276962306a36Sopenharmony_ci return rc; 277062306a36Sopenharmony_ci} 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_cistatic ssize_t 277362306a36Sopenharmony_cilpfc_debugfs_scsistat_write(struct file *file, const char __user *buf, 277462306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 277762306a36Sopenharmony_ci struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; 277862306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 277962306a36Sopenharmony_ci char mybuf[6] = {0}; 278062306a36Sopenharmony_ci int i; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ? 278362306a36Sopenharmony_ci (sizeof(mybuf) - 1) : nbytes)) 278462306a36Sopenharmony_ci return -EFAULT; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci if ((strncmp(&mybuf[0], "reset", strlen("reset")) == 0) || 278762306a36Sopenharmony_ci (strncmp(&mybuf[0], "zero", strlen("zero")) == 0)) { 278862306a36Sopenharmony_ci for (i = 0; i < phba->cfg_hdw_queue; i++) { 278962306a36Sopenharmony_ci memset(&phba->sli4_hba.hdwq[i].scsi_cstat, 0, 279062306a36Sopenharmony_ci sizeof(phba->sli4_hba.hdwq[i].scsi_cstat)); 279162306a36Sopenharmony_ci } 279262306a36Sopenharmony_ci } 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci return nbytes; 279562306a36Sopenharmony_ci} 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_cistatic int 279862306a36Sopenharmony_cilpfc_debugfs_ioktime_open(struct inode *inode, struct file *file) 279962306a36Sopenharmony_ci{ 280062306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 280162306a36Sopenharmony_ci struct lpfc_debug *debug; 280262306a36Sopenharmony_ci int rc = -ENOMEM; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 280562306a36Sopenharmony_ci if (!debug) 280662306a36Sopenharmony_ci goto out; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci /* Round to page boundary */ 280962306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL); 281062306a36Sopenharmony_ci if (!debug->buffer) { 281162306a36Sopenharmony_ci kfree(debug); 281262306a36Sopenharmony_ci goto out; 281362306a36Sopenharmony_ci } 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer, 281662306a36Sopenharmony_ci LPFC_IOKTIME_SIZE); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci debug->i_private = inode->i_private; 281962306a36Sopenharmony_ci file->private_data = debug; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci rc = 0; 282262306a36Sopenharmony_ciout: 282362306a36Sopenharmony_ci return rc; 282462306a36Sopenharmony_ci} 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_cistatic ssize_t 282762306a36Sopenharmony_cilpfc_debugfs_ioktime_write(struct file *file, const char __user *buf, 282862306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 282962306a36Sopenharmony_ci{ 283062306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 283162306a36Sopenharmony_ci struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; 283262306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 283362306a36Sopenharmony_ci char mybuf[64]; 283462306a36Sopenharmony_ci char *pbuf; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci if (nbytes > sizeof(mybuf) - 1) 283762306a36Sopenharmony_ci nbytes = sizeof(mybuf) - 1; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, nbytes)) 284262306a36Sopenharmony_ci return -EFAULT; 284362306a36Sopenharmony_ci pbuf = &mybuf[0]; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) { 284662306a36Sopenharmony_ci phba->ktime_data_samples = 0; 284762306a36Sopenharmony_ci phba->ktime_status_samples = 0; 284862306a36Sopenharmony_ci phba->ktime_seg1_total = 0; 284962306a36Sopenharmony_ci phba->ktime_seg1_max = 0; 285062306a36Sopenharmony_ci phba->ktime_seg1_min = 0xffffffff; 285162306a36Sopenharmony_ci phba->ktime_seg2_total = 0; 285262306a36Sopenharmony_ci phba->ktime_seg2_max = 0; 285362306a36Sopenharmony_ci phba->ktime_seg2_min = 0xffffffff; 285462306a36Sopenharmony_ci phba->ktime_seg3_total = 0; 285562306a36Sopenharmony_ci phba->ktime_seg3_max = 0; 285662306a36Sopenharmony_ci phba->ktime_seg3_min = 0xffffffff; 285762306a36Sopenharmony_ci phba->ktime_seg4_total = 0; 285862306a36Sopenharmony_ci phba->ktime_seg4_max = 0; 285962306a36Sopenharmony_ci phba->ktime_seg4_min = 0xffffffff; 286062306a36Sopenharmony_ci phba->ktime_seg5_total = 0; 286162306a36Sopenharmony_ci phba->ktime_seg5_max = 0; 286262306a36Sopenharmony_ci phba->ktime_seg5_min = 0xffffffff; 286362306a36Sopenharmony_ci phba->ktime_seg6_total = 0; 286462306a36Sopenharmony_ci phba->ktime_seg6_max = 0; 286562306a36Sopenharmony_ci phba->ktime_seg6_min = 0xffffffff; 286662306a36Sopenharmony_ci phba->ktime_seg7_total = 0; 286762306a36Sopenharmony_ci phba->ktime_seg7_max = 0; 286862306a36Sopenharmony_ci phba->ktime_seg7_min = 0xffffffff; 286962306a36Sopenharmony_ci phba->ktime_seg8_total = 0; 287062306a36Sopenharmony_ci phba->ktime_seg8_max = 0; 287162306a36Sopenharmony_ci phba->ktime_seg8_min = 0xffffffff; 287262306a36Sopenharmony_ci phba->ktime_seg9_total = 0; 287362306a36Sopenharmony_ci phba->ktime_seg9_max = 0; 287462306a36Sopenharmony_ci phba->ktime_seg9_min = 0xffffffff; 287562306a36Sopenharmony_ci phba->ktime_seg10_total = 0; 287662306a36Sopenharmony_ci phba->ktime_seg10_max = 0; 287762306a36Sopenharmony_ci phba->ktime_seg10_min = 0xffffffff; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci phba->ktime_on = 1; 288062306a36Sopenharmony_ci return strlen(pbuf); 288162306a36Sopenharmony_ci } else if ((strncmp(pbuf, "off", 288262306a36Sopenharmony_ci sizeof("off") - 1) == 0)) { 288362306a36Sopenharmony_ci phba->ktime_on = 0; 288462306a36Sopenharmony_ci return strlen(pbuf); 288562306a36Sopenharmony_ci } else if ((strncmp(pbuf, "zero", 288662306a36Sopenharmony_ci sizeof("zero") - 1) == 0)) { 288762306a36Sopenharmony_ci phba->ktime_data_samples = 0; 288862306a36Sopenharmony_ci phba->ktime_status_samples = 0; 288962306a36Sopenharmony_ci phba->ktime_seg1_total = 0; 289062306a36Sopenharmony_ci phba->ktime_seg1_max = 0; 289162306a36Sopenharmony_ci phba->ktime_seg1_min = 0xffffffff; 289262306a36Sopenharmony_ci phba->ktime_seg2_total = 0; 289362306a36Sopenharmony_ci phba->ktime_seg2_max = 0; 289462306a36Sopenharmony_ci phba->ktime_seg2_min = 0xffffffff; 289562306a36Sopenharmony_ci phba->ktime_seg3_total = 0; 289662306a36Sopenharmony_ci phba->ktime_seg3_max = 0; 289762306a36Sopenharmony_ci phba->ktime_seg3_min = 0xffffffff; 289862306a36Sopenharmony_ci phba->ktime_seg4_total = 0; 289962306a36Sopenharmony_ci phba->ktime_seg4_max = 0; 290062306a36Sopenharmony_ci phba->ktime_seg4_min = 0xffffffff; 290162306a36Sopenharmony_ci phba->ktime_seg5_total = 0; 290262306a36Sopenharmony_ci phba->ktime_seg5_max = 0; 290362306a36Sopenharmony_ci phba->ktime_seg5_min = 0xffffffff; 290462306a36Sopenharmony_ci phba->ktime_seg6_total = 0; 290562306a36Sopenharmony_ci phba->ktime_seg6_max = 0; 290662306a36Sopenharmony_ci phba->ktime_seg6_min = 0xffffffff; 290762306a36Sopenharmony_ci phba->ktime_seg7_total = 0; 290862306a36Sopenharmony_ci phba->ktime_seg7_max = 0; 290962306a36Sopenharmony_ci phba->ktime_seg7_min = 0xffffffff; 291062306a36Sopenharmony_ci phba->ktime_seg8_total = 0; 291162306a36Sopenharmony_ci phba->ktime_seg8_max = 0; 291262306a36Sopenharmony_ci phba->ktime_seg8_min = 0xffffffff; 291362306a36Sopenharmony_ci phba->ktime_seg9_total = 0; 291462306a36Sopenharmony_ci phba->ktime_seg9_max = 0; 291562306a36Sopenharmony_ci phba->ktime_seg9_min = 0xffffffff; 291662306a36Sopenharmony_ci phba->ktime_seg10_total = 0; 291762306a36Sopenharmony_ci phba->ktime_seg10_max = 0; 291862306a36Sopenharmony_ci phba->ktime_seg10_min = 0xffffffff; 291962306a36Sopenharmony_ci return strlen(pbuf); 292062306a36Sopenharmony_ci } 292162306a36Sopenharmony_ci return -EINVAL; 292262306a36Sopenharmony_ci} 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_cistatic int 292562306a36Sopenharmony_cilpfc_debugfs_nvmeio_trc_open(struct inode *inode, struct file *file) 292662306a36Sopenharmony_ci{ 292762306a36Sopenharmony_ci struct lpfc_hba *phba = inode->i_private; 292862306a36Sopenharmony_ci struct lpfc_debug *debug; 292962306a36Sopenharmony_ci int rc = -ENOMEM; 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 293262306a36Sopenharmony_ci if (!debug) 293362306a36Sopenharmony_ci goto out; 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci /* Round to page boundary */ 293662306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_NVMEIO_TRC_SIZE, GFP_KERNEL); 293762306a36Sopenharmony_ci if (!debug->buffer) { 293862306a36Sopenharmony_ci kfree(debug); 293962306a36Sopenharmony_ci goto out; 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci debug->len = lpfc_debugfs_nvmeio_trc_data(phba, debug->buffer, 294362306a36Sopenharmony_ci LPFC_NVMEIO_TRC_SIZE); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci debug->i_private = inode->i_private; 294662306a36Sopenharmony_ci file->private_data = debug; 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci rc = 0; 294962306a36Sopenharmony_ciout: 295062306a36Sopenharmony_ci return rc; 295162306a36Sopenharmony_ci} 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_cistatic ssize_t 295462306a36Sopenharmony_cilpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, 295562306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 295662306a36Sopenharmony_ci{ 295762306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 295862306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 295962306a36Sopenharmony_ci int i; 296062306a36Sopenharmony_ci unsigned long sz; 296162306a36Sopenharmony_ci char mybuf[64]; 296262306a36Sopenharmony_ci char *pbuf; 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (nbytes > sizeof(mybuf) - 1) 296562306a36Sopenharmony_ci nbytes = sizeof(mybuf) - 1; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, nbytes)) 297062306a36Sopenharmony_ci return -EFAULT; 297162306a36Sopenharmony_ci pbuf = &mybuf[0]; 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ci if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) { 297462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 297562306a36Sopenharmony_ci "0570 nvmeio_trc_off\n"); 297662306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 297762306a36Sopenharmony_ci phba->nvmeio_trc_on = 0; 297862306a36Sopenharmony_ci return strlen(pbuf); 297962306a36Sopenharmony_ci } else if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) { 298062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 298162306a36Sopenharmony_ci "0571 nvmeio_trc_on\n"); 298262306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 298362306a36Sopenharmony_ci phba->nvmeio_trc_on = 1; 298462306a36Sopenharmony_ci return strlen(pbuf); 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci /* We must be off to allocate the trace buffer */ 298862306a36Sopenharmony_ci if (phba->nvmeio_trc_on != 0) 298962306a36Sopenharmony_ci return -EINVAL; 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci /* If not on or off, the parameter is the trace buffer size */ 299262306a36Sopenharmony_ci i = kstrtoul(pbuf, 0, &sz); 299362306a36Sopenharmony_ci if (i) 299462306a36Sopenharmony_ci return -EINVAL; 299562306a36Sopenharmony_ci phba->nvmeio_trc_size = (uint32_t)sz; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci /* It must be a power of 2 - round down */ 299862306a36Sopenharmony_ci i = 0; 299962306a36Sopenharmony_ci while (sz > 1) { 300062306a36Sopenharmony_ci sz = sz >> 1; 300162306a36Sopenharmony_ci i++; 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci sz = (1 << i); 300462306a36Sopenharmony_ci if (phba->nvmeio_trc_size != sz) 300562306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 300662306a36Sopenharmony_ci "0572 nvmeio_trc_size changed to %ld\n", 300762306a36Sopenharmony_ci sz); 300862306a36Sopenharmony_ci phba->nvmeio_trc_size = (uint32_t)sz; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci /* If one previously exists, free it */ 301162306a36Sopenharmony_ci kfree(phba->nvmeio_trc); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci /* Allocate new trace buffer and initialize */ 301462306a36Sopenharmony_ci phba->nvmeio_trc = kzalloc((sizeof(struct lpfc_debugfs_nvmeio_trc) * 301562306a36Sopenharmony_ci sz), GFP_KERNEL); 301662306a36Sopenharmony_ci if (!phba->nvmeio_trc) { 301762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 301862306a36Sopenharmony_ci "0573 Cannot create debugfs " 301962306a36Sopenharmony_ci "nvmeio_trc buffer\n"); 302062306a36Sopenharmony_ci return -ENOMEM; 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci atomic_set(&phba->nvmeio_trc_cnt, 0); 302362306a36Sopenharmony_ci phba->nvmeio_trc_on = 0; 302462306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci return strlen(pbuf); 302762306a36Sopenharmony_ci} 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_cistatic int 303062306a36Sopenharmony_cilpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci struct lpfc_vport *vport = inode->i_private; 303362306a36Sopenharmony_ci struct lpfc_debug *debug; 303462306a36Sopenharmony_ci int rc = -ENOMEM; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 303762306a36Sopenharmony_ci if (!debug) 303862306a36Sopenharmony_ci goto out; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci /* Round to page boundary */ 304162306a36Sopenharmony_ci debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL); 304262306a36Sopenharmony_ci if (!debug->buffer) { 304362306a36Sopenharmony_ci kfree(debug); 304462306a36Sopenharmony_ci goto out; 304562306a36Sopenharmony_ci } 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer, 304862306a36Sopenharmony_ci LPFC_SCSISTAT_SIZE); 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci debug->i_private = inode->i_private; 305162306a36Sopenharmony_ci file->private_data = debug; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci rc = 0; 305462306a36Sopenharmony_ciout: 305562306a36Sopenharmony_ci return rc; 305662306a36Sopenharmony_ci} 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_cistatic ssize_t 305962306a36Sopenharmony_cilpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf, 306062306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 306162306a36Sopenharmony_ci{ 306262306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 306362306a36Sopenharmony_ci struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; 306462306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 306562306a36Sopenharmony_ci struct lpfc_hdwq_stat *c_stat; 306662306a36Sopenharmony_ci char mybuf[64]; 306762306a36Sopenharmony_ci char *pbuf; 306862306a36Sopenharmony_ci int i; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci if (nbytes > sizeof(mybuf) - 1) 307162306a36Sopenharmony_ci nbytes = sizeof(mybuf) - 1; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, nbytes)) 307662306a36Sopenharmony_ci return -EFAULT; 307762306a36Sopenharmony_ci pbuf = &mybuf[0]; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) { 308062306a36Sopenharmony_ci if (phba->nvmet_support) 308162306a36Sopenharmony_ci phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; 308262306a36Sopenharmony_ci else 308362306a36Sopenharmony_ci phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO | 308462306a36Sopenharmony_ci LPFC_CHECK_SCSI_IO); 308562306a36Sopenharmony_ci return strlen(pbuf); 308662306a36Sopenharmony_ci } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) { 308762306a36Sopenharmony_ci if (phba->nvmet_support) 308862306a36Sopenharmony_ci phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; 308962306a36Sopenharmony_ci else 309062306a36Sopenharmony_ci phba->hdwqstat_on |= LPFC_CHECK_NVME_IO; 309162306a36Sopenharmony_ci return strlen(pbuf); 309262306a36Sopenharmony_ci } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) { 309362306a36Sopenharmony_ci if (!phba->nvmet_support) 309462306a36Sopenharmony_ci phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO; 309562306a36Sopenharmony_ci return strlen(pbuf); 309662306a36Sopenharmony_ci } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) { 309762306a36Sopenharmony_ci phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO | 309862306a36Sopenharmony_ci LPFC_CHECK_NVMET_IO); 309962306a36Sopenharmony_ci return strlen(pbuf); 310062306a36Sopenharmony_ci } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) { 310162306a36Sopenharmony_ci phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO; 310262306a36Sopenharmony_ci return strlen(pbuf); 310362306a36Sopenharmony_ci } else if ((strncmp(pbuf, "off", 310462306a36Sopenharmony_ci sizeof("off") - 1) == 0)) { 310562306a36Sopenharmony_ci phba->hdwqstat_on = LPFC_CHECK_OFF; 310662306a36Sopenharmony_ci return strlen(pbuf); 310762306a36Sopenharmony_ci } else if ((strncmp(pbuf, "zero", 310862306a36Sopenharmony_ci sizeof("zero") - 1) == 0)) { 310962306a36Sopenharmony_ci for_each_present_cpu(i) { 311062306a36Sopenharmony_ci c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i); 311162306a36Sopenharmony_ci c_stat->xmt_io = 0; 311262306a36Sopenharmony_ci c_stat->cmpl_io = 0; 311362306a36Sopenharmony_ci c_stat->rcv_io = 0; 311462306a36Sopenharmony_ci } 311562306a36Sopenharmony_ci return strlen(pbuf); 311662306a36Sopenharmony_ci } 311762306a36Sopenharmony_ci return -EINVAL; 311862306a36Sopenharmony_ci} 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci/* 312162306a36Sopenharmony_ci * --------------------------------- 312262306a36Sopenharmony_ci * iDiag debugfs file access methods 312362306a36Sopenharmony_ci * --------------------------------- 312462306a36Sopenharmony_ci * 312562306a36Sopenharmony_ci * All access methods are through the proper SLI4 PCI function's debugfs 312662306a36Sopenharmony_ci * iDiag directory: 312762306a36Sopenharmony_ci * 312862306a36Sopenharmony_ci * /sys/kernel/debug/lpfc/fn<#>/iDiag 312962306a36Sopenharmony_ci */ 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci/** 313262306a36Sopenharmony_ci * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space 313362306a36Sopenharmony_ci * @buf: The pointer to the user space buffer. 313462306a36Sopenharmony_ci * @nbytes: The number of bytes in the user space buffer. 313562306a36Sopenharmony_ci * @idiag_cmd: pointer to the idiag command struct. 313662306a36Sopenharmony_ci * 313762306a36Sopenharmony_ci * This routine reads data from debugfs user space buffer and parses the 313862306a36Sopenharmony_ci * buffer for getting the idiag command and arguments. The while space in 313962306a36Sopenharmony_ci * between the set of data is used as the parsing separator. 314062306a36Sopenharmony_ci * 314162306a36Sopenharmony_ci * This routine returns 0 when successful, it returns proper error code 314262306a36Sopenharmony_ci * back to the user space in error conditions. 314362306a36Sopenharmony_ci */ 314462306a36Sopenharmony_cistatic int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, 314562306a36Sopenharmony_ci struct lpfc_idiag_cmd *idiag_cmd) 314662306a36Sopenharmony_ci{ 314762306a36Sopenharmony_ci char mybuf[64]; 314862306a36Sopenharmony_ci char *pbuf, *step_str; 314962306a36Sopenharmony_ci int i; 315062306a36Sopenharmony_ci size_t bsize; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci memset(mybuf, 0, sizeof(mybuf)); 315362306a36Sopenharmony_ci memset(idiag_cmd, 0, sizeof(*idiag_cmd)); 315462306a36Sopenharmony_ci bsize = min(nbytes, (sizeof(mybuf)-1)); 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci if (copy_from_user(mybuf, buf, bsize)) 315762306a36Sopenharmony_ci return -EFAULT; 315862306a36Sopenharmony_ci pbuf = &mybuf[0]; 315962306a36Sopenharmony_ci step_str = strsep(&pbuf, "\t "); 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci /* The opcode must present */ 316262306a36Sopenharmony_ci if (!step_str) 316362306a36Sopenharmony_ci return -EINVAL; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci idiag_cmd->opcode = simple_strtol(step_str, NULL, 0); 316662306a36Sopenharmony_ci if (idiag_cmd->opcode == 0) 316762306a36Sopenharmony_ci return -EINVAL; 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { 317062306a36Sopenharmony_ci step_str = strsep(&pbuf, "\t "); 317162306a36Sopenharmony_ci if (!step_str) 317262306a36Sopenharmony_ci return i; 317362306a36Sopenharmony_ci idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci return i; 317662306a36Sopenharmony_ci} 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci/** 317962306a36Sopenharmony_ci * lpfc_idiag_open - idiag open debugfs 318062306a36Sopenharmony_ci * @inode: The inode pointer that contains a pointer to phba. 318162306a36Sopenharmony_ci * @file: The file pointer to attach the file operation. 318262306a36Sopenharmony_ci * 318362306a36Sopenharmony_ci * Description: 318462306a36Sopenharmony_ci * This routine is the entry point for the debugfs open file operation. It 318562306a36Sopenharmony_ci * gets the reference to phba from the i_private field in @inode, it then 318662306a36Sopenharmony_ci * allocates buffer for the file operation, performs the necessary PCI config 318762306a36Sopenharmony_ci * space read into the allocated buffer according to the idiag user command 318862306a36Sopenharmony_ci * setup, and then returns a pointer to buffer in the private_data field in 318962306a36Sopenharmony_ci * @file. 319062306a36Sopenharmony_ci * 319162306a36Sopenharmony_ci * Returns: 319262306a36Sopenharmony_ci * This function returns zero if successful. On error it will return an 319362306a36Sopenharmony_ci * negative error value. 319462306a36Sopenharmony_ci **/ 319562306a36Sopenharmony_cistatic int 319662306a36Sopenharmony_cilpfc_idiag_open(struct inode *inode, struct file *file) 319762306a36Sopenharmony_ci{ 319862306a36Sopenharmony_ci struct lpfc_debug *debug; 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 320162306a36Sopenharmony_ci if (!debug) 320262306a36Sopenharmony_ci return -ENOMEM; 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci debug->i_private = inode->i_private; 320562306a36Sopenharmony_ci debug->buffer = NULL; 320662306a36Sopenharmony_ci file->private_data = debug; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci return 0; 320962306a36Sopenharmony_ci} 321062306a36Sopenharmony_ci 321162306a36Sopenharmony_ci/** 321262306a36Sopenharmony_ci * lpfc_idiag_release - Release idiag access file operation 321362306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. (unused) 321462306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release. 321562306a36Sopenharmony_ci * 321662306a36Sopenharmony_ci * Description: 321762306a36Sopenharmony_ci * This routine is the generic release routine for the idiag access file 321862306a36Sopenharmony_ci * operation, it frees the buffer that was allocated when the debugfs file 321962306a36Sopenharmony_ci * was opened. 322062306a36Sopenharmony_ci * 322162306a36Sopenharmony_ci * Returns: 322262306a36Sopenharmony_ci * This function returns zero. 322362306a36Sopenharmony_ci **/ 322462306a36Sopenharmony_cistatic int 322562306a36Sopenharmony_cilpfc_idiag_release(struct inode *inode, struct file *file) 322662306a36Sopenharmony_ci{ 322762306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci /* Free the buffers to the file operation */ 323062306a36Sopenharmony_ci kfree(debug->buffer); 323162306a36Sopenharmony_ci kfree(debug); 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci return 0; 323462306a36Sopenharmony_ci} 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci/** 323762306a36Sopenharmony_ci * lpfc_idiag_cmd_release - Release idiag cmd access file operation 323862306a36Sopenharmony_ci * @inode: The inode pointer that contains a vport pointer. (unused) 323962306a36Sopenharmony_ci * @file: The file pointer that contains the buffer to release. 324062306a36Sopenharmony_ci * 324162306a36Sopenharmony_ci * Description: 324262306a36Sopenharmony_ci * This routine frees the buffer that was allocated when the debugfs file 324362306a36Sopenharmony_ci * was opened. It also reset the fields in the idiag command struct in the 324462306a36Sopenharmony_ci * case of command for write operation. 324562306a36Sopenharmony_ci * 324662306a36Sopenharmony_ci * Returns: 324762306a36Sopenharmony_ci * This function returns zero. 324862306a36Sopenharmony_ci **/ 324962306a36Sopenharmony_cistatic int 325062306a36Sopenharmony_cilpfc_idiag_cmd_release(struct inode *inode, struct file *file) 325162306a36Sopenharmony_ci{ 325262306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (debug->op == LPFC_IDIAG_OP_WR) { 325562306a36Sopenharmony_ci switch (idiag.cmd.opcode) { 325662306a36Sopenharmony_ci case LPFC_IDIAG_CMD_PCICFG_WR: 325762306a36Sopenharmony_ci case LPFC_IDIAG_CMD_PCICFG_ST: 325862306a36Sopenharmony_ci case LPFC_IDIAG_CMD_PCICFG_CL: 325962306a36Sopenharmony_ci case LPFC_IDIAG_CMD_QUEACC_WR: 326062306a36Sopenharmony_ci case LPFC_IDIAG_CMD_QUEACC_ST: 326162306a36Sopenharmony_ci case LPFC_IDIAG_CMD_QUEACC_CL: 326262306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 326362306a36Sopenharmony_ci break; 326462306a36Sopenharmony_ci default: 326562306a36Sopenharmony_ci break; 326662306a36Sopenharmony_ci } 326762306a36Sopenharmony_ci } 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ci /* Free the buffers to the file operation */ 327062306a36Sopenharmony_ci kfree(debug->buffer); 327162306a36Sopenharmony_ci kfree(debug); 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci return 0; 327462306a36Sopenharmony_ci} 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci/** 327762306a36Sopenharmony_ci * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg 327862306a36Sopenharmony_ci * @file: The file pointer to read from. 327962306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 328062306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 328162306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 328262306a36Sopenharmony_ci * 328362306a36Sopenharmony_ci * Description: 328462306a36Sopenharmony_ci * This routine reads data from the @phba pci config space according to the 328562306a36Sopenharmony_ci * idiag command, and copies to user @buf. Depending on the PCI config space 328662306a36Sopenharmony_ci * read command setup, it does either a single register read of a byte 328762306a36Sopenharmony_ci * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all 328862306a36Sopenharmony_ci * registers from the 4K extended PCI config space. 328962306a36Sopenharmony_ci * 329062306a36Sopenharmony_ci * Returns: 329162306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 329262306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 329362306a36Sopenharmony_ci **/ 329462306a36Sopenharmony_cistatic ssize_t 329562306a36Sopenharmony_cilpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, 329662306a36Sopenharmony_ci loff_t *ppos) 329762306a36Sopenharmony_ci{ 329862306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 329962306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 330062306a36Sopenharmony_ci int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE; 330162306a36Sopenharmony_ci int where, count; 330262306a36Sopenharmony_ci char *pbuffer; 330362306a36Sopenharmony_ci struct pci_dev *pdev; 330462306a36Sopenharmony_ci uint32_t u32val; 330562306a36Sopenharmony_ci uint16_t u16val; 330662306a36Sopenharmony_ci uint8_t u8val; 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci pdev = phba->pcidev; 330962306a36Sopenharmony_ci if (!pdev) 331062306a36Sopenharmony_ci return 0; 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci /* This is a user read operation */ 331362306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci if (!debug->buffer) 331662306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL); 331762306a36Sopenharmony_ci if (!debug->buffer) 331862306a36Sopenharmony_ci return 0; 331962306a36Sopenharmony_ci pbuffer = debug->buffer; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci if (*ppos) 332262306a36Sopenharmony_ci return 0; 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { 332562306a36Sopenharmony_ci where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; 332662306a36Sopenharmony_ci count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; 332762306a36Sopenharmony_ci } else 332862306a36Sopenharmony_ci return 0; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci /* Read single PCI config space register */ 333162306a36Sopenharmony_ci switch (count) { 333262306a36Sopenharmony_ci case SIZE_U8: /* byte (8 bits) */ 333362306a36Sopenharmony_ci pci_read_config_byte(pdev, where, &u8val); 333462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 333562306a36Sopenharmony_ci "%03x: %02x\n", where, u8val); 333662306a36Sopenharmony_ci break; 333762306a36Sopenharmony_ci case SIZE_U16: /* word (16 bits) */ 333862306a36Sopenharmony_ci pci_read_config_word(pdev, where, &u16val); 333962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 334062306a36Sopenharmony_ci "%03x: %04x\n", where, u16val); 334162306a36Sopenharmony_ci break; 334262306a36Sopenharmony_ci case SIZE_U32: /* double word (32 bits) */ 334362306a36Sopenharmony_ci pci_read_config_dword(pdev, where, &u32val); 334462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 334562306a36Sopenharmony_ci "%03x: %08x\n", where, u32val); 334662306a36Sopenharmony_ci break; 334762306a36Sopenharmony_ci case LPFC_PCI_CFG_BROWSE: /* browse all */ 334862306a36Sopenharmony_ci goto pcicfg_browse; 334962306a36Sopenharmony_ci default: 335062306a36Sopenharmony_ci /* illegal count */ 335162306a36Sopenharmony_ci len = 0; 335262306a36Sopenharmony_ci break; 335362306a36Sopenharmony_ci } 335462306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_cipcicfg_browse: 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci /* Browse all PCI config space registers */ 335962306a36Sopenharmony_ci offset_label = idiag.offset.last_rd; 336062306a36Sopenharmony_ci offset = offset_label; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci /* Read PCI config space */ 336362306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 336462306a36Sopenharmony_ci "%03x: ", offset_label); 336562306a36Sopenharmony_ci while (index > 0) { 336662306a36Sopenharmony_ci pci_read_config_dword(pdev, offset, &u32val); 336762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 336862306a36Sopenharmony_ci "%08x ", u32val); 336962306a36Sopenharmony_ci offset += sizeof(uint32_t); 337062306a36Sopenharmony_ci if (offset >= LPFC_PCI_CFG_SIZE) { 337162306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 337262306a36Sopenharmony_ci LPFC_PCI_CFG_SIZE-len, "\n"); 337362306a36Sopenharmony_ci break; 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci index -= sizeof(uint32_t); 337662306a36Sopenharmony_ci if (!index) 337762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 337862306a36Sopenharmony_ci "\n"); 337962306a36Sopenharmony_ci else if (!(index % (8 * sizeof(uint32_t)))) { 338062306a36Sopenharmony_ci offset_label += (8 * sizeof(uint32_t)); 338162306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, 338262306a36Sopenharmony_ci "\n%03x: ", offset_label); 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci } 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci /* Set up the offset for next portion of pci cfg read */ 338762306a36Sopenharmony_ci if (index == 0) { 338862306a36Sopenharmony_ci idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; 338962306a36Sopenharmony_ci if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) 339062306a36Sopenharmony_ci idiag.offset.last_rd = 0; 339162306a36Sopenharmony_ci } else 339262306a36Sopenharmony_ci idiag.offset.last_rd = 0; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 339562306a36Sopenharmony_ci} 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci/** 339862306a36Sopenharmony_ci * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands 339962306a36Sopenharmony_ci * @file: The file pointer to read from. 340062306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 340162306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 340262306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 340362306a36Sopenharmony_ci * 340462306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and 340562306a36Sopenharmony_ci * then perform the syntax check for PCI config space read or write command 340662306a36Sopenharmony_ci * accordingly. In the case of PCI config space read command, it sets up 340762306a36Sopenharmony_ci * the command in the idiag command struct for the debugfs read operation. 340862306a36Sopenharmony_ci * In the case of PCI config space write operation, it executes the write 340962306a36Sopenharmony_ci * operation into the PCI config space accordingly. 341062306a36Sopenharmony_ci * 341162306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 341262306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 341362306a36Sopenharmony_ci * space. 341462306a36Sopenharmony_ci */ 341562306a36Sopenharmony_cistatic ssize_t 341662306a36Sopenharmony_cilpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, 341762306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 341862306a36Sopenharmony_ci{ 341962306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 342062306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 342162306a36Sopenharmony_ci uint32_t where, value, count; 342262306a36Sopenharmony_ci uint32_t u32val; 342362306a36Sopenharmony_ci uint16_t u16val; 342462306a36Sopenharmony_ci uint8_t u8val; 342562306a36Sopenharmony_ci struct pci_dev *pdev; 342662306a36Sopenharmony_ci int rc; 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci pdev = phba->pcidev; 342962306a36Sopenharmony_ci if (!pdev) 343062306a36Sopenharmony_ci return -EFAULT; 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci /* This is a user write operation */ 343362306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 343662306a36Sopenharmony_ci if (rc < 0) 343762306a36Sopenharmony_ci return rc; 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { 344062306a36Sopenharmony_ci /* Sanity check on PCI config read command line arguments */ 344162306a36Sopenharmony_ci if (rc != LPFC_PCI_CFG_RD_CMD_ARG) 344262306a36Sopenharmony_ci goto error_out; 344362306a36Sopenharmony_ci /* Read command from PCI config space, set up command fields */ 344462306a36Sopenharmony_ci where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; 344562306a36Sopenharmony_ci count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; 344662306a36Sopenharmony_ci if (count == LPFC_PCI_CFG_BROWSE) { 344762306a36Sopenharmony_ci if (where % sizeof(uint32_t)) 344862306a36Sopenharmony_ci goto error_out; 344962306a36Sopenharmony_ci /* Starting offset to browse */ 345062306a36Sopenharmony_ci idiag.offset.last_rd = where; 345162306a36Sopenharmony_ci } else if ((count != sizeof(uint8_t)) && 345262306a36Sopenharmony_ci (count != sizeof(uint16_t)) && 345362306a36Sopenharmony_ci (count != sizeof(uint32_t))) 345462306a36Sopenharmony_ci goto error_out; 345562306a36Sopenharmony_ci if (count == sizeof(uint8_t)) { 345662306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t)) 345762306a36Sopenharmony_ci goto error_out; 345862306a36Sopenharmony_ci if (where % sizeof(uint8_t)) 345962306a36Sopenharmony_ci goto error_out; 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ci if (count == sizeof(uint16_t)) { 346262306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t)) 346362306a36Sopenharmony_ci goto error_out; 346462306a36Sopenharmony_ci if (where % sizeof(uint16_t)) 346562306a36Sopenharmony_ci goto error_out; 346662306a36Sopenharmony_ci } 346762306a36Sopenharmony_ci if (count == sizeof(uint32_t)) { 346862306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t)) 346962306a36Sopenharmony_ci goto error_out; 347062306a36Sopenharmony_ci if (where % sizeof(uint32_t)) 347162306a36Sopenharmony_ci goto error_out; 347262306a36Sopenharmony_ci } 347362306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || 347462306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || 347562306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { 347662306a36Sopenharmony_ci /* Sanity check on PCI config write command line arguments */ 347762306a36Sopenharmony_ci if (rc != LPFC_PCI_CFG_WR_CMD_ARG) 347862306a36Sopenharmony_ci goto error_out; 347962306a36Sopenharmony_ci /* Write command to PCI config space, read-modify-write */ 348062306a36Sopenharmony_ci where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; 348162306a36Sopenharmony_ci count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; 348262306a36Sopenharmony_ci value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX]; 348362306a36Sopenharmony_ci /* Sanity checks */ 348462306a36Sopenharmony_ci if ((count != sizeof(uint8_t)) && 348562306a36Sopenharmony_ci (count != sizeof(uint16_t)) && 348662306a36Sopenharmony_ci (count != sizeof(uint32_t))) 348762306a36Sopenharmony_ci goto error_out; 348862306a36Sopenharmony_ci if (count == sizeof(uint8_t)) { 348962306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t)) 349062306a36Sopenharmony_ci goto error_out; 349162306a36Sopenharmony_ci if (where % sizeof(uint8_t)) 349262306a36Sopenharmony_ci goto error_out; 349362306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) 349462306a36Sopenharmony_ci pci_write_config_byte(pdev, where, 349562306a36Sopenharmony_ci (uint8_t)value); 349662306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { 349762306a36Sopenharmony_ci rc = pci_read_config_byte(pdev, where, &u8val); 349862306a36Sopenharmony_ci if (!rc) { 349962306a36Sopenharmony_ci u8val |= (uint8_t)value; 350062306a36Sopenharmony_ci pci_write_config_byte(pdev, where, 350162306a36Sopenharmony_ci u8val); 350262306a36Sopenharmony_ci } 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { 350562306a36Sopenharmony_ci rc = pci_read_config_byte(pdev, where, &u8val); 350662306a36Sopenharmony_ci if (!rc) { 350762306a36Sopenharmony_ci u8val &= (uint8_t)(~value); 350862306a36Sopenharmony_ci pci_write_config_byte(pdev, where, 350962306a36Sopenharmony_ci u8val); 351062306a36Sopenharmony_ci } 351162306a36Sopenharmony_ci } 351262306a36Sopenharmony_ci } 351362306a36Sopenharmony_ci if (count == sizeof(uint16_t)) { 351462306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t)) 351562306a36Sopenharmony_ci goto error_out; 351662306a36Sopenharmony_ci if (where % sizeof(uint16_t)) 351762306a36Sopenharmony_ci goto error_out; 351862306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) 351962306a36Sopenharmony_ci pci_write_config_word(pdev, where, 352062306a36Sopenharmony_ci (uint16_t)value); 352162306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { 352262306a36Sopenharmony_ci rc = pci_read_config_word(pdev, where, &u16val); 352362306a36Sopenharmony_ci if (!rc) { 352462306a36Sopenharmony_ci u16val |= (uint16_t)value; 352562306a36Sopenharmony_ci pci_write_config_word(pdev, where, 352662306a36Sopenharmony_ci u16val); 352762306a36Sopenharmony_ci } 352862306a36Sopenharmony_ci } 352962306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { 353062306a36Sopenharmony_ci rc = pci_read_config_word(pdev, where, &u16val); 353162306a36Sopenharmony_ci if (!rc) { 353262306a36Sopenharmony_ci u16val &= (uint16_t)(~value); 353362306a36Sopenharmony_ci pci_write_config_word(pdev, where, 353462306a36Sopenharmony_ci u16val); 353562306a36Sopenharmony_ci } 353662306a36Sopenharmony_ci } 353762306a36Sopenharmony_ci } 353862306a36Sopenharmony_ci if (count == sizeof(uint32_t)) { 353962306a36Sopenharmony_ci if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t)) 354062306a36Sopenharmony_ci goto error_out; 354162306a36Sopenharmony_ci if (where % sizeof(uint32_t)) 354262306a36Sopenharmony_ci goto error_out; 354362306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) 354462306a36Sopenharmony_ci pci_write_config_dword(pdev, where, value); 354562306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { 354662306a36Sopenharmony_ci rc = pci_read_config_dword(pdev, where, 354762306a36Sopenharmony_ci &u32val); 354862306a36Sopenharmony_ci if (!rc) { 354962306a36Sopenharmony_ci u32val |= value; 355062306a36Sopenharmony_ci pci_write_config_dword(pdev, where, 355162306a36Sopenharmony_ci u32val); 355262306a36Sopenharmony_ci } 355362306a36Sopenharmony_ci } 355462306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { 355562306a36Sopenharmony_ci rc = pci_read_config_dword(pdev, where, 355662306a36Sopenharmony_ci &u32val); 355762306a36Sopenharmony_ci if (!rc) { 355862306a36Sopenharmony_ci u32val &= ~value; 355962306a36Sopenharmony_ci pci_write_config_dword(pdev, where, 356062306a36Sopenharmony_ci u32val); 356162306a36Sopenharmony_ci } 356262306a36Sopenharmony_ci } 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci } else 356562306a36Sopenharmony_ci /* All other opecodes are illegal for now */ 356662306a36Sopenharmony_ci goto error_out; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci return nbytes; 356962306a36Sopenharmony_cierror_out: 357062306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 357162306a36Sopenharmony_ci return -EINVAL; 357262306a36Sopenharmony_ci} 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci/** 357562306a36Sopenharmony_ci * lpfc_idiag_baracc_read - idiag debugfs pci bar access read 357662306a36Sopenharmony_ci * @file: The file pointer to read from. 357762306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 357862306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 357962306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 358062306a36Sopenharmony_ci * 358162306a36Sopenharmony_ci * Description: 358262306a36Sopenharmony_ci * This routine reads data from the @phba pci bar memory mapped space 358362306a36Sopenharmony_ci * according to the idiag command, and copies to user @buf. 358462306a36Sopenharmony_ci * 358562306a36Sopenharmony_ci * Returns: 358662306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 358762306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 358862306a36Sopenharmony_ci **/ 358962306a36Sopenharmony_cistatic ssize_t 359062306a36Sopenharmony_cilpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, 359162306a36Sopenharmony_ci loff_t *ppos) 359262306a36Sopenharmony_ci{ 359362306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 359462306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 359562306a36Sopenharmony_ci int offset_label, offset, offset_run, len = 0, index; 359662306a36Sopenharmony_ci int bar_num, acc_range, bar_size; 359762306a36Sopenharmony_ci char *pbuffer; 359862306a36Sopenharmony_ci void __iomem *mem_mapped_bar; 359962306a36Sopenharmony_ci uint32_t if_type; 360062306a36Sopenharmony_ci struct pci_dev *pdev; 360162306a36Sopenharmony_ci uint32_t u32val; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci pdev = phba->pcidev; 360462306a36Sopenharmony_ci if (!pdev) 360562306a36Sopenharmony_ci return 0; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci /* This is a user read operation */ 360862306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci if (!debug->buffer) 361162306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL); 361262306a36Sopenharmony_ci if (!debug->buffer) 361362306a36Sopenharmony_ci return 0; 361462306a36Sopenharmony_ci pbuffer = debug->buffer; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci if (*ppos) 361762306a36Sopenharmony_ci return 0; 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { 362062306a36Sopenharmony_ci bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; 362162306a36Sopenharmony_ci offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; 362262306a36Sopenharmony_ci acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; 362362306a36Sopenharmony_ci bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; 362462306a36Sopenharmony_ci } else 362562306a36Sopenharmony_ci return 0; 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci if (acc_range == 0) 362862306a36Sopenharmony_ci return 0; 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); 363162306a36Sopenharmony_ci if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { 363262306a36Sopenharmony_ci if (bar_num == IDIAG_BARACC_BAR_0) 363362306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; 363462306a36Sopenharmony_ci else if (bar_num == IDIAG_BARACC_BAR_1) 363562306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; 363662306a36Sopenharmony_ci else if (bar_num == IDIAG_BARACC_BAR_2) 363762306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; 363862306a36Sopenharmony_ci else 363962306a36Sopenharmony_ci return 0; 364062306a36Sopenharmony_ci } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { 364162306a36Sopenharmony_ci if (bar_num == IDIAG_BARACC_BAR_0) 364262306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; 364362306a36Sopenharmony_ci else 364462306a36Sopenharmony_ci return 0; 364562306a36Sopenharmony_ci } else 364662306a36Sopenharmony_ci return 0; 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci /* Read single PCI bar space register */ 364962306a36Sopenharmony_ci if (acc_range == SINGLE_WORD) { 365062306a36Sopenharmony_ci offset_run = offset; 365162306a36Sopenharmony_ci u32val = readl(mem_mapped_bar + offset_run); 365262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, 365362306a36Sopenharmony_ci "%05x: %08x\n", offset_run, u32val); 365462306a36Sopenharmony_ci } else 365562306a36Sopenharmony_ci goto baracc_browse; 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_cibaracc_browse: 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci /* Browse all PCI bar space registers */ 366262306a36Sopenharmony_ci offset_label = idiag.offset.last_rd; 366362306a36Sopenharmony_ci offset_run = offset_label; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci /* Read PCI bar memory mapped space */ 366662306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, 366762306a36Sopenharmony_ci "%05x: ", offset_label); 366862306a36Sopenharmony_ci index = LPFC_PCI_BAR_RD_SIZE; 366962306a36Sopenharmony_ci while (index > 0) { 367062306a36Sopenharmony_ci u32val = readl(mem_mapped_bar + offset_run); 367162306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, 367262306a36Sopenharmony_ci "%08x ", u32val); 367362306a36Sopenharmony_ci offset_run += sizeof(uint32_t); 367462306a36Sopenharmony_ci if (acc_range == LPFC_PCI_BAR_BROWSE) { 367562306a36Sopenharmony_ci if (offset_run >= bar_size) { 367662306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 367762306a36Sopenharmony_ci LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); 367862306a36Sopenharmony_ci break; 367962306a36Sopenharmony_ci } 368062306a36Sopenharmony_ci } else { 368162306a36Sopenharmony_ci if (offset_run >= offset + 368262306a36Sopenharmony_ci (acc_range * sizeof(uint32_t))) { 368362306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 368462306a36Sopenharmony_ci LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); 368562306a36Sopenharmony_ci break; 368662306a36Sopenharmony_ci } 368762306a36Sopenharmony_ci } 368862306a36Sopenharmony_ci index -= sizeof(uint32_t); 368962306a36Sopenharmony_ci if (!index) 369062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 369162306a36Sopenharmony_ci LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); 369262306a36Sopenharmony_ci else if (!(index % (8 * sizeof(uint32_t)))) { 369362306a36Sopenharmony_ci offset_label += (8 * sizeof(uint32_t)); 369462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 369562306a36Sopenharmony_ci LPFC_PCI_BAR_RD_BUF_SIZE-len, 369662306a36Sopenharmony_ci "\n%05x: ", offset_label); 369762306a36Sopenharmony_ci } 369862306a36Sopenharmony_ci } 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_ci /* Set up the offset for next portion of pci bar read */ 370162306a36Sopenharmony_ci if (index == 0) { 370262306a36Sopenharmony_ci idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE; 370362306a36Sopenharmony_ci if (acc_range == LPFC_PCI_BAR_BROWSE) { 370462306a36Sopenharmony_ci if (idiag.offset.last_rd >= bar_size) 370562306a36Sopenharmony_ci idiag.offset.last_rd = 0; 370662306a36Sopenharmony_ci } else { 370762306a36Sopenharmony_ci if (offset_run >= offset + 370862306a36Sopenharmony_ci (acc_range * sizeof(uint32_t))) 370962306a36Sopenharmony_ci idiag.offset.last_rd = offset; 371062306a36Sopenharmony_ci } 371162306a36Sopenharmony_ci } else { 371262306a36Sopenharmony_ci if (acc_range == LPFC_PCI_BAR_BROWSE) 371362306a36Sopenharmony_ci idiag.offset.last_rd = 0; 371462306a36Sopenharmony_ci else 371562306a36Sopenharmony_ci idiag.offset.last_rd = offset; 371662306a36Sopenharmony_ci } 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 371962306a36Sopenharmony_ci} 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci/** 372262306a36Sopenharmony_ci * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands 372362306a36Sopenharmony_ci * @file: The file pointer to read from. 372462306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 372562306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 372662306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 372762306a36Sopenharmony_ci * 372862306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and 372962306a36Sopenharmony_ci * then perform the syntax check for PCI bar memory mapped space read or 373062306a36Sopenharmony_ci * write command accordingly. In the case of PCI bar memory mapped space 373162306a36Sopenharmony_ci * read command, it sets up the command in the idiag command struct for 373262306a36Sopenharmony_ci * the debugfs read operation. In the case of PCI bar memorpy mapped space 373362306a36Sopenharmony_ci * write operation, it executes the write operation into the PCI bar memory 373462306a36Sopenharmony_ci * mapped space accordingly. 373562306a36Sopenharmony_ci * 373662306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 373762306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 373862306a36Sopenharmony_ci * space. 373962306a36Sopenharmony_ci */ 374062306a36Sopenharmony_cistatic ssize_t 374162306a36Sopenharmony_cilpfc_idiag_baracc_write(struct file *file, const char __user *buf, 374262306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 374362306a36Sopenharmony_ci{ 374462306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 374562306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 374662306a36Sopenharmony_ci uint32_t bar_num, bar_size, offset, value, acc_range; 374762306a36Sopenharmony_ci struct pci_dev *pdev; 374862306a36Sopenharmony_ci void __iomem *mem_mapped_bar; 374962306a36Sopenharmony_ci uint32_t if_type; 375062306a36Sopenharmony_ci uint32_t u32val; 375162306a36Sopenharmony_ci int rc; 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci pdev = phba->pcidev; 375462306a36Sopenharmony_ci if (!pdev) 375562306a36Sopenharmony_ci return -EFAULT; 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci /* This is a user write operation */ 375862306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 376162306a36Sopenharmony_ci if (rc < 0) 376262306a36Sopenharmony_ci return rc; 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); 376562306a36Sopenharmony_ci bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { 376862306a36Sopenharmony_ci if ((bar_num != IDIAG_BARACC_BAR_0) && 376962306a36Sopenharmony_ci (bar_num != IDIAG_BARACC_BAR_1) && 377062306a36Sopenharmony_ci (bar_num != IDIAG_BARACC_BAR_2)) 377162306a36Sopenharmony_ci goto error_out; 377262306a36Sopenharmony_ci } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { 377362306a36Sopenharmony_ci if (bar_num != IDIAG_BARACC_BAR_0) 377462306a36Sopenharmony_ci goto error_out; 377562306a36Sopenharmony_ci } else 377662306a36Sopenharmony_ci goto error_out; 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { 377962306a36Sopenharmony_ci if (bar_num == IDIAG_BARACC_BAR_0) { 378062306a36Sopenharmony_ci idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = 378162306a36Sopenharmony_ci LPFC_PCI_IF0_BAR0_SIZE; 378262306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; 378362306a36Sopenharmony_ci } else if (bar_num == IDIAG_BARACC_BAR_1) { 378462306a36Sopenharmony_ci idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = 378562306a36Sopenharmony_ci LPFC_PCI_IF0_BAR1_SIZE; 378662306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; 378762306a36Sopenharmony_ci } else if (bar_num == IDIAG_BARACC_BAR_2) { 378862306a36Sopenharmony_ci idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = 378962306a36Sopenharmony_ci LPFC_PCI_IF0_BAR2_SIZE; 379062306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; 379162306a36Sopenharmony_ci } else 379262306a36Sopenharmony_ci goto error_out; 379362306a36Sopenharmony_ci } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { 379462306a36Sopenharmony_ci if (bar_num == IDIAG_BARACC_BAR_0) { 379562306a36Sopenharmony_ci idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = 379662306a36Sopenharmony_ci LPFC_PCI_IF2_BAR0_SIZE; 379762306a36Sopenharmony_ci mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; 379862306a36Sopenharmony_ci } else 379962306a36Sopenharmony_ci goto error_out; 380062306a36Sopenharmony_ci } else 380162306a36Sopenharmony_ci goto error_out; 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; 380462306a36Sopenharmony_ci if (offset % sizeof(uint32_t)) 380562306a36Sopenharmony_ci goto error_out; 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; 380862306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { 380962306a36Sopenharmony_ci /* Sanity check on PCI config read command line arguments */ 381062306a36Sopenharmony_ci if (rc != LPFC_PCI_BAR_RD_CMD_ARG) 381162306a36Sopenharmony_ci goto error_out; 381262306a36Sopenharmony_ci acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; 381362306a36Sopenharmony_ci if (acc_range == LPFC_PCI_BAR_BROWSE) { 381462306a36Sopenharmony_ci if (offset > bar_size - sizeof(uint32_t)) 381562306a36Sopenharmony_ci goto error_out; 381662306a36Sopenharmony_ci /* Starting offset to browse */ 381762306a36Sopenharmony_ci idiag.offset.last_rd = offset; 381862306a36Sopenharmony_ci } else if (acc_range > SINGLE_WORD) { 381962306a36Sopenharmony_ci if (offset + acc_range * sizeof(uint32_t) > bar_size) 382062306a36Sopenharmony_ci goto error_out; 382162306a36Sopenharmony_ci /* Starting offset to browse */ 382262306a36Sopenharmony_ci idiag.offset.last_rd = offset; 382362306a36Sopenharmony_ci } else if (acc_range != SINGLE_WORD) 382462306a36Sopenharmony_ci goto error_out; 382562306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR || 382662306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST || 382762306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { 382862306a36Sopenharmony_ci /* Sanity check on PCI bar write command line arguments */ 382962306a36Sopenharmony_ci if (rc != LPFC_PCI_BAR_WR_CMD_ARG) 383062306a36Sopenharmony_ci goto error_out; 383162306a36Sopenharmony_ci /* Write command to PCI bar space, read-modify-write */ 383262306a36Sopenharmony_ci acc_range = SINGLE_WORD; 383362306a36Sopenharmony_ci value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX]; 383462306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) { 383562306a36Sopenharmony_ci writel(value, mem_mapped_bar + offset); 383662306a36Sopenharmony_ci readl(mem_mapped_bar + offset); 383762306a36Sopenharmony_ci } 383862306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) { 383962306a36Sopenharmony_ci u32val = readl(mem_mapped_bar + offset); 384062306a36Sopenharmony_ci u32val |= value; 384162306a36Sopenharmony_ci writel(u32val, mem_mapped_bar + offset); 384262306a36Sopenharmony_ci readl(mem_mapped_bar + offset); 384362306a36Sopenharmony_ci } 384462306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { 384562306a36Sopenharmony_ci u32val = readl(mem_mapped_bar + offset); 384662306a36Sopenharmony_ci u32val &= ~value; 384762306a36Sopenharmony_ci writel(u32val, mem_mapped_bar + offset); 384862306a36Sopenharmony_ci readl(mem_mapped_bar + offset); 384962306a36Sopenharmony_ci } 385062306a36Sopenharmony_ci } else 385162306a36Sopenharmony_ci /* All other opecodes are illegal for now */ 385262306a36Sopenharmony_ci goto error_out; 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci return nbytes; 385562306a36Sopenharmony_cierror_out: 385662306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 385762306a36Sopenharmony_ci return -EINVAL; 385862306a36Sopenharmony_ci} 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_cistatic int 386162306a36Sopenharmony_ci__lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype, 386262306a36Sopenharmony_ci char *pbuffer, int len) 386362306a36Sopenharmony_ci{ 386462306a36Sopenharmony_ci if (!qp) 386562306a36Sopenharmony_ci return len; 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 386862306a36Sopenharmony_ci "\t\t%s WQ info: ", wqtype); 386962306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 387062306a36Sopenharmony_ci "AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n", 387162306a36Sopenharmony_ci qp->assoc_qid, qp->q_cnt_1, 387262306a36Sopenharmony_ci (unsigned long long)qp->q_cnt_4); 387362306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 387462306a36Sopenharmony_ci "\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " 387562306a36Sopenharmony_ci "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]", 387662306a36Sopenharmony_ci qp->queue_id, qp->entry_count, 387762306a36Sopenharmony_ci qp->entry_size, qp->host_index, 387862306a36Sopenharmony_ci qp->hba_index, qp->notify_interval); 387962306a36Sopenharmony_ci len += scnprintf(pbuffer + len, 388062306a36Sopenharmony_ci LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n"); 388162306a36Sopenharmony_ci return len; 388262306a36Sopenharmony_ci} 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_cistatic int 388562306a36Sopenharmony_cilpfc_idiag_wqs_for_cq(struct lpfc_hba *phba, char *wqtype, char *pbuffer, 388662306a36Sopenharmony_ci int *len, int max_cnt, int cq_id) 388762306a36Sopenharmony_ci{ 388862306a36Sopenharmony_ci struct lpfc_queue *qp; 388962306a36Sopenharmony_ci int qidx; 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { 389262306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[qidx].io_wq; 389362306a36Sopenharmony_ci if (qp->assoc_qid != cq_id) 389462306a36Sopenharmony_ci continue; 389562306a36Sopenharmony_ci *len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len); 389662306a36Sopenharmony_ci if (*len >= max_cnt) 389762306a36Sopenharmony_ci return 1; 389862306a36Sopenharmony_ci } 389962306a36Sopenharmony_ci return 0; 390062306a36Sopenharmony_ci} 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_cistatic int 390362306a36Sopenharmony_ci__lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype, 390462306a36Sopenharmony_ci char *pbuffer, int len) 390562306a36Sopenharmony_ci{ 390662306a36Sopenharmony_ci if (!qp) 390762306a36Sopenharmony_ci return len; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 391062306a36Sopenharmony_ci "\t%s CQ info: ", cqtype); 391162306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 391262306a36Sopenharmony_ci "AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x " 391362306a36Sopenharmony_ci "xabt:x%x wq:x%llx]\n", 391462306a36Sopenharmony_ci qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2, 391562306a36Sopenharmony_ci qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); 391662306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 391762306a36Sopenharmony_ci "\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " 391862306a36Sopenharmony_ci "HST-IDX[%04d], NTFI[%03d], PLMT[%03d]", 391962306a36Sopenharmony_ci qp->queue_id, qp->entry_count, 392062306a36Sopenharmony_ci qp->entry_size, qp->host_index, 392162306a36Sopenharmony_ci qp->notify_interval, qp->max_proc_limit); 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 392462306a36Sopenharmony_ci "\n"); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci return len; 392762306a36Sopenharmony_ci} 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_cistatic int 393062306a36Sopenharmony_ci__lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp, 393162306a36Sopenharmony_ci char *rqtype, char *pbuffer, int len) 393262306a36Sopenharmony_ci{ 393362306a36Sopenharmony_ci if (!qp || !datqp) 393462306a36Sopenharmony_ci return len; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 393762306a36Sopenharmony_ci "\t\t%s RQ info: ", rqtype); 393862306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 393962306a36Sopenharmony_ci "AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x " 394062306a36Sopenharmony_ci "posted:x%x rcv:x%llx]\n", 394162306a36Sopenharmony_ci qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2, 394262306a36Sopenharmony_ci qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); 394362306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 394462306a36Sopenharmony_ci "\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " 394562306a36Sopenharmony_ci "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n", 394662306a36Sopenharmony_ci qp->queue_id, qp->entry_count, qp->entry_size, 394762306a36Sopenharmony_ci qp->host_index, qp->hba_index, qp->notify_interval); 394862306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 394962306a36Sopenharmony_ci "\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " 395062306a36Sopenharmony_ci "HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n", 395162306a36Sopenharmony_ci datqp->queue_id, datqp->entry_count, 395262306a36Sopenharmony_ci datqp->entry_size, datqp->host_index, 395362306a36Sopenharmony_ci datqp->hba_index, datqp->notify_interval); 395462306a36Sopenharmony_ci return len; 395562306a36Sopenharmony_ci} 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_cistatic int 395862306a36Sopenharmony_cilpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer, 395962306a36Sopenharmony_ci int *len, int max_cnt, int eqidx, int eq_id) 396062306a36Sopenharmony_ci{ 396162306a36Sopenharmony_ci struct lpfc_queue *qp; 396262306a36Sopenharmony_ci int rc; 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[eqidx].io_cq; 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci *len = __lpfc_idiag_print_cq(qp, "IO", pbuffer, *len); 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci /* Reset max counter */ 396962306a36Sopenharmony_ci qp->CQ_max_cqe = 0; 397062306a36Sopenharmony_ci 397162306a36Sopenharmony_ci if (*len >= max_cnt) 397262306a36Sopenharmony_ci return 1; 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci rc = lpfc_idiag_wqs_for_cq(phba, "IO", pbuffer, len, 397562306a36Sopenharmony_ci max_cnt, qp->queue_id); 397662306a36Sopenharmony_ci if (rc) 397762306a36Sopenharmony_ci return 1; 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) { 398062306a36Sopenharmony_ci /* NVMET CQset */ 398162306a36Sopenharmony_ci qp = phba->sli4_hba.nvmet_cqset[eqidx]; 398262306a36Sopenharmony_ci *len = __lpfc_idiag_print_cq(qp, "NVMET CQset", pbuffer, *len); 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci /* Reset max counter */ 398562306a36Sopenharmony_ci qp->CQ_max_cqe = 0; 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci if (*len >= max_cnt) 398862306a36Sopenharmony_ci return 1; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci /* RQ header */ 399162306a36Sopenharmony_ci qp = phba->sli4_hba.nvmet_mrq_hdr[eqidx]; 399262306a36Sopenharmony_ci *len = __lpfc_idiag_print_rqpair(qp, 399362306a36Sopenharmony_ci phba->sli4_hba.nvmet_mrq_data[eqidx], 399462306a36Sopenharmony_ci "NVMET MRQ", pbuffer, *len); 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci if (*len >= max_cnt) 399762306a36Sopenharmony_ci return 1; 399862306a36Sopenharmony_ci } 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_ci return 0; 400162306a36Sopenharmony_ci} 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_cistatic int 400462306a36Sopenharmony_ci__lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype, 400562306a36Sopenharmony_ci char *pbuffer, int len) 400662306a36Sopenharmony_ci{ 400762306a36Sopenharmony_ci if (!qp) 400862306a36Sopenharmony_ci return len; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 401162306a36Sopenharmony_ci "\n%s EQ info: EQ-STAT[max:x%x noE:x%x " 401262306a36Sopenharmony_ci "cqe_proc:x%x eqe_proc:x%llx eqd %d]\n", 401362306a36Sopenharmony_ci eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3, 401462306a36Sopenharmony_ci (unsigned long long)qp->q_cnt_4, qp->q_mode); 401562306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 401662306a36Sopenharmony_ci "EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], " 401762306a36Sopenharmony_ci "HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]", 401862306a36Sopenharmony_ci qp->queue_id, qp->entry_count, qp->entry_size, 401962306a36Sopenharmony_ci qp->host_index, qp->notify_interval, 402062306a36Sopenharmony_ci qp->max_proc_limit, qp->chann); 402162306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, 402262306a36Sopenharmony_ci "\n"); 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ci return len; 402562306a36Sopenharmony_ci} 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci/** 402862306a36Sopenharmony_ci * lpfc_idiag_queinfo_read - idiag debugfs read queue information 402962306a36Sopenharmony_ci * @file: The file pointer to read from. 403062306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 403162306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 403262306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 403362306a36Sopenharmony_ci * 403462306a36Sopenharmony_ci * Description: 403562306a36Sopenharmony_ci * This routine reads data from the @phba SLI4 PCI function queue information, 403662306a36Sopenharmony_ci * and copies to user @buf. 403762306a36Sopenharmony_ci * This routine only returns 1 EQs worth of information. It remembers the last 403862306a36Sopenharmony_ci * EQ read and jumps to the next EQ. Thus subsequent calls to queInfo will 403962306a36Sopenharmony_ci * retrieve all EQs allocated for the phba. 404062306a36Sopenharmony_ci * 404162306a36Sopenharmony_ci * Returns: 404262306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 404362306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 404462306a36Sopenharmony_ci **/ 404562306a36Sopenharmony_cistatic ssize_t 404662306a36Sopenharmony_cilpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, 404762306a36Sopenharmony_ci loff_t *ppos) 404862306a36Sopenharmony_ci{ 404962306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 405062306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 405162306a36Sopenharmony_ci char *pbuffer; 405262306a36Sopenharmony_ci int max_cnt, rc, x, len = 0; 405362306a36Sopenharmony_ci struct lpfc_queue *qp = NULL; 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci if (!debug->buffer) 405662306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL); 405762306a36Sopenharmony_ci if (!debug->buffer) 405862306a36Sopenharmony_ci return 0; 405962306a36Sopenharmony_ci pbuffer = debug->buffer; 406062306a36Sopenharmony_ci max_cnt = LPFC_QUE_INFO_GET_BUF_SIZE - 256; 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci if (*ppos) 406362306a36Sopenharmony_ci return 0; 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci /* Fast-path event queue */ 406862306a36Sopenharmony_ci if (phba->sli4_hba.hdwq && phba->cfg_hdw_queue) { 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci x = phba->lpfc_idiag_last_eq; 407162306a36Sopenharmony_ci phba->lpfc_idiag_last_eq++; 407262306a36Sopenharmony_ci if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue) 407362306a36Sopenharmony_ci phba->lpfc_idiag_last_eq = 0; 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci len += scnprintf(pbuffer + len, 407662306a36Sopenharmony_ci LPFC_QUE_INFO_GET_BUF_SIZE - len, 407762306a36Sopenharmony_ci "HDWQ %d out of %d HBA HDWQs\n", 407862306a36Sopenharmony_ci x, phba->cfg_hdw_queue); 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci /* Fast-path EQ */ 408162306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[x].hba_eq; 408262306a36Sopenharmony_ci if (!qp) 408362306a36Sopenharmony_ci goto out; 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci len = __lpfc_idiag_print_eq(qp, "HBA", pbuffer, len); 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci /* Reset max counter */ 408862306a36Sopenharmony_ci qp->EQ_max_eqe = 0; 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci if (len >= max_cnt) 409162306a36Sopenharmony_ci goto too_big; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci /* will dump both fcp and nvme cqs/wqs for the eq */ 409462306a36Sopenharmony_ci rc = lpfc_idiag_cqs_for_eq(phba, pbuffer, &len, 409562306a36Sopenharmony_ci max_cnt, x, qp->queue_id); 409662306a36Sopenharmony_ci if (rc) 409762306a36Sopenharmony_ci goto too_big; 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci /* Only EQ 0 has slow path CQs configured */ 410062306a36Sopenharmony_ci if (x) 410162306a36Sopenharmony_ci goto out; 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci /* Slow-path mailbox CQ */ 410462306a36Sopenharmony_ci qp = phba->sli4_hba.mbx_cq; 410562306a36Sopenharmony_ci len = __lpfc_idiag_print_cq(qp, "MBX", pbuffer, len); 410662306a36Sopenharmony_ci if (len >= max_cnt) 410762306a36Sopenharmony_ci goto too_big; 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci /* Slow-path MBOX MQ */ 411062306a36Sopenharmony_ci qp = phba->sli4_hba.mbx_wq; 411162306a36Sopenharmony_ci len = __lpfc_idiag_print_wq(qp, "MBX", pbuffer, len); 411262306a36Sopenharmony_ci if (len >= max_cnt) 411362306a36Sopenharmony_ci goto too_big; 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ci /* Slow-path ELS response CQ */ 411662306a36Sopenharmony_ci qp = phba->sli4_hba.els_cq; 411762306a36Sopenharmony_ci len = __lpfc_idiag_print_cq(qp, "ELS", pbuffer, len); 411862306a36Sopenharmony_ci /* Reset max counter */ 411962306a36Sopenharmony_ci if (qp) 412062306a36Sopenharmony_ci qp->CQ_max_cqe = 0; 412162306a36Sopenharmony_ci if (len >= max_cnt) 412262306a36Sopenharmony_ci goto too_big; 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci /* Slow-path ELS WQ */ 412562306a36Sopenharmony_ci qp = phba->sli4_hba.els_wq; 412662306a36Sopenharmony_ci len = __lpfc_idiag_print_wq(qp, "ELS", pbuffer, len); 412762306a36Sopenharmony_ci if (len >= max_cnt) 412862306a36Sopenharmony_ci goto too_big; 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci qp = phba->sli4_hba.hdr_rq; 413162306a36Sopenharmony_ci len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq, 413262306a36Sopenharmony_ci "ELS RQpair", pbuffer, len); 413362306a36Sopenharmony_ci if (len >= max_cnt) 413462306a36Sopenharmony_ci goto too_big; 413562306a36Sopenharmony_ci 413662306a36Sopenharmony_ci /* Slow-path NVME LS response CQ */ 413762306a36Sopenharmony_ci qp = phba->sli4_hba.nvmels_cq; 413862306a36Sopenharmony_ci len = __lpfc_idiag_print_cq(qp, "NVME LS", 413962306a36Sopenharmony_ci pbuffer, len); 414062306a36Sopenharmony_ci /* Reset max counter */ 414162306a36Sopenharmony_ci if (qp) 414262306a36Sopenharmony_ci qp->CQ_max_cqe = 0; 414362306a36Sopenharmony_ci if (len >= max_cnt) 414462306a36Sopenharmony_ci goto too_big; 414562306a36Sopenharmony_ci 414662306a36Sopenharmony_ci /* Slow-path NVME LS WQ */ 414762306a36Sopenharmony_ci qp = phba->sli4_hba.nvmels_wq; 414862306a36Sopenharmony_ci len = __lpfc_idiag_print_wq(qp, "NVME LS", 414962306a36Sopenharmony_ci pbuffer, len); 415062306a36Sopenharmony_ci if (len >= max_cnt) 415162306a36Sopenharmony_ci goto too_big; 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ci goto out; 415462306a36Sopenharmony_ci } 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 415762306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 415862306a36Sopenharmony_ci 415962306a36Sopenharmony_citoo_big: 416062306a36Sopenharmony_ci len += scnprintf(pbuffer + len, 416162306a36Sopenharmony_ci LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n"); 416262306a36Sopenharmony_ciout: 416362306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 416462306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 416562306a36Sopenharmony_ci} 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci/** 416862306a36Sopenharmony_ci * lpfc_idiag_que_param_check - queue access command parameter sanity check 416962306a36Sopenharmony_ci * @q: The pointer to queue structure. 417062306a36Sopenharmony_ci * @index: The index into a queue entry. 417162306a36Sopenharmony_ci * @count: The number of queue entries to access. 417262306a36Sopenharmony_ci * 417362306a36Sopenharmony_ci * Description: 417462306a36Sopenharmony_ci * The routine performs sanity check on device queue access method commands. 417562306a36Sopenharmony_ci * 417662306a36Sopenharmony_ci * Returns: 417762306a36Sopenharmony_ci * This function returns -EINVAL when fails the sanity check, otherwise, it 417862306a36Sopenharmony_ci * returns 0. 417962306a36Sopenharmony_ci **/ 418062306a36Sopenharmony_cistatic int 418162306a36Sopenharmony_cilpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) 418262306a36Sopenharmony_ci{ 418362306a36Sopenharmony_ci /* Only support single entry read or browsing */ 418462306a36Sopenharmony_ci if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE)) 418562306a36Sopenharmony_ci return -EINVAL; 418662306a36Sopenharmony_ci if (index > q->entry_count - 1) 418762306a36Sopenharmony_ci return -EINVAL; 418862306a36Sopenharmony_ci return 0; 418962306a36Sopenharmony_ci} 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci/** 419262306a36Sopenharmony_ci * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index 419362306a36Sopenharmony_ci * @pbuffer: The pointer to buffer to copy the read data into. 419462306a36Sopenharmony_ci * @len: Length of the buffer. 419562306a36Sopenharmony_ci * @pque: The pointer to the queue to be read. 419662306a36Sopenharmony_ci * @index: The index into the queue entry. 419762306a36Sopenharmony_ci * 419862306a36Sopenharmony_ci * Description: 419962306a36Sopenharmony_ci * This routine reads out a single entry from the given queue's index location 420062306a36Sopenharmony_ci * and copies it into the buffer provided. 420162306a36Sopenharmony_ci * 420262306a36Sopenharmony_ci * Returns: 420362306a36Sopenharmony_ci * This function returns 0 when it fails, otherwise, it returns the length of 420462306a36Sopenharmony_ci * the data read into the buffer provided. 420562306a36Sopenharmony_ci **/ 420662306a36Sopenharmony_cistatic int 420762306a36Sopenharmony_cilpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, 420862306a36Sopenharmony_ci uint32_t index) 420962306a36Sopenharmony_ci{ 421062306a36Sopenharmony_ci int offset, esize; 421162306a36Sopenharmony_ci uint32_t *pentry; 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci if (!pbuffer || !pque) 421462306a36Sopenharmony_ci return 0; 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci esize = pque->entry_size; 421762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, 421862306a36Sopenharmony_ci "QE-INDEX[%04d]:\n", index); 421962306a36Sopenharmony_ci 422062306a36Sopenharmony_ci offset = 0; 422162306a36Sopenharmony_ci pentry = lpfc_sli4_qe(pque, index); 422262306a36Sopenharmony_ci while (esize > 0) { 422362306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, 422462306a36Sopenharmony_ci "%08x ", *pentry); 422562306a36Sopenharmony_ci pentry++; 422662306a36Sopenharmony_ci offset += sizeof(uint32_t); 422762306a36Sopenharmony_ci esize -= sizeof(uint32_t); 422862306a36Sopenharmony_ci if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) 422962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, 423062306a36Sopenharmony_ci LPFC_QUE_ACC_BUF_SIZE-len, "\n"); 423162306a36Sopenharmony_ci } 423262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci return len; 423562306a36Sopenharmony_ci} 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci/** 423862306a36Sopenharmony_ci * lpfc_idiag_queacc_read - idiag debugfs read port queue 423962306a36Sopenharmony_ci * @file: The file pointer to read from. 424062306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 424162306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 424262306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 424362306a36Sopenharmony_ci * 424462306a36Sopenharmony_ci * Description: 424562306a36Sopenharmony_ci * This routine reads data from the @phba device queue memory according to the 424662306a36Sopenharmony_ci * idiag command, and copies to user @buf. Depending on the queue dump read 424762306a36Sopenharmony_ci * command setup, it does either a single queue entry read or browing through 424862306a36Sopenharmony_ci * all entries of the queue. 424962306a36Sopenharmony_ci * 425062306a36Sopenharmony_ci * Returns: 425162306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 425262306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 425362306a36Sopenharmony_ci **/ 425462306a36Sopenharmony_cistatic ssize_t 425562306a36Sopenharmony_cilpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, 425662306a36Sopenharmony_ci loff_t *ppos) 425762306a36Sopenharmony_ci{ 425862306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 425962306a36Sopenharmony_ci uint32_t last_index, index, count; 426062306a36Sopenharmony_ci struct lpfc_queue *pque = NULL; 426162306a36Sopenharmony_ci char *pbuffer; 426262306a36Sopenharmony_ci int len = 0; 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci /* This is a user read operation */ 426562306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci if (!debug->buffer) 426862306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL); 426962306a36Sopenharmony_ci if (!debug->buffer) 427062306a36Sopenharmony_ci return 0; 427162306a36Sopenharmony_ci pbuffer = debug->buffer; 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci if (*ppos) 427462306a36Sopenharmony_ci return 0; 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { 427762306a36Sopenharmony_ci index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; 427862306a36Sopenharmony_ci count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; 427962306a36Sopenharmony_ci pque = (struct lpfc_queue *)idiag.ptr_private; 428062306a36Sopenharmony_ci } else 428162306a36Sopenharmony_ci return 0; 428262306a36Sopenharmony_ci 428362306a36Sopenharmony_ci /* Browse the queue starting from index */ 428462306a36Sopenharmony_ci if (count == LPFC_QUE_ACC_BROWSE) 428562306a36Sopenharmony_ci goto que_browse; 428662306a36Sopenharmony_ci 428762306a36Sopenharmony_ci /* Read a single entry from the queue */ 428862306a36Sopenharmony_ci len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_cique_browse: 429362306a36Sopenharmony_ci 429462306a36Sopenharmony_ci /* Browse all entries from the queue */ 429562306a36Sopenharmony_ci last_index = idiag.offset.last_rd; 429662306a36Sopenharmony_ci index = last_index; 429762306a36Sopenharmony_ci 429862306a36Sopenharmony_ci while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) { 429962306a36Sopenharmony_ci len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); 430062306a36Sopenharmony_ci index++; 430162306a36Sopenharmony_ci if (index > pque->entry_count - 1) 430262306a36Sopenharmony_ci break; 430362306a36Sopenharmony_ci } 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci /* Set up the offset for next portion of pci cfg read */ 430662306a36Sopenharmony_ci if (index > pque->entry_count - 1) 430762306a36Sopenharmony_ci index = 0; 430862306a36Sopenharmony_ci idiag.offset.last_rd = index; 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 431162306a36Sopenharmony_ci} 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci/** 431462306a36Sopenharmony_ci * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands 431562306a36Sopenharmony_ci * @file: The file pointer to read from. 431662306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 431762306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 431862306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 431962306a36Sopenharmony_ci * 432062306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and then 432162306a36Sopenharmony_ci * perform the syntax check for port queue read (dump) or write (set) command 432262306a36Sopenharmony_ci * accordingly. In the case of port queue read command, it sets up the command 432362306a36Sopenharmony_ci * in the idiag command struct for the following debugfs read operation. In 432462306a36Sopenharmony_ci * the case of port queue write operation, it executes the write operation 432562306a36Sopenharmony_ci * into the port queue entry accordingly. 432662306a36Sopenharmony_ci * 432762306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 432862306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 432962306a36Sopenharmony_ci * space. 433062306a36Sopenharmony_ci **/ 433162306a36Sopenharmony_cistatic ssize_t 433262306a36Sopenharmony_cilpfc_idiag_queacc_write(struct file *file, const char __user *buf, 433362306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 433462306a36Sopenharmony_ci{ 433562306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 433662306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 433762306a36Sopenharmony_ci uint32_t qidx, quetp, queid, index, count, offset, value; 433862306a36Sopenharmony_ci uint32_t *pentry; 433962306a36Sopenharmony_ci struct lpfc_queue *pque, *qp; 434062306a36Sopenharmony_ci int rc; 434162306a36Sopenharmony_ci 434262306a36Sopenharmony_ci /* This is a user write operation */ 434362306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 434662306a36Sopenharmony_ci if (rc < 0) 434762306a36Sopenharmony_ci return rc; 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci /* Get and sanity check on command feilds */ 435062306a36Sopenharmony_ci quetp = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX]; 435162306a36Sopenharmony_ci queid = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX]; 435262306a36Sopenharmony_ci index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; 435362306a36Sopenharmony_ci count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; 435462306a36Sopenharmony_ci offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX]; 435562306a36Sopenharmony_ci value = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX]; 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci /* Sanity check on command line arguments */ 435862306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || 435962306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || 436062306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { 436162306a36Sopenharmony_ci if (rc != LPFC_QUE_ACC_WR_CMD_ARG) 436262306a36Sopenharmony_ci goto error_out; 436362306a36Sopenharmony_ci if (count != 1) 436462306a36Sopenharmony_ci goto error_out; 436562306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { 436662306a36Sopenharmony_ci if (rc != LPFC_QUE_ACC_RD_CMD_ARG) 436762306a36Sopenharmony_ci goto error_out; 436862306a36Sopenharmony_ci } else 436962306a36Sopenharmony_ci goto error_out; 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci switch (quetp) { 437262306a36Sopenharmony_ci case LPFC_IDIAG_EQ: 437362306a36Sopenharmony_ci /* HBA event queue */ 437462306a36Sopenharmony_ci if (phba->sli4_hba.hdwq) { 437562306a36Sopenharmony_ci for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { 437662306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[qidx].hba_eq; 437762306a36Sopenharmony_ci if (qp && qp->queue_id == queid) { 437862306a36Sopenharmony_ci /* Sanity check */ 437962306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check(qp, 438062306a36Sopenharmony_ci index, count); 438162306a36Sopenharmony_ci if (rc) 438262306a36Sopenharmony_ci goto error_out; 438362306a36Sopenharmony_ci idiag.ptr_private = qp; 438462306a36Sopenharmony_ci goto pass_check; 438562306a36Sopenharmony_ci } 438662306a36Sopenharmony_ci } 438762306a36Sopenharmony_ci } 438862306a36Sopenharmony_ci goto error_out; 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_ci case LPFC_IDIAG_CQ: 439162306a36Sopenharmony_ci /* MBX complete queue */ 439262306a36Sopenharmony_ci if (phba->sli4_hba.mbx_cq && 439362306a36Sopenharmony_ci phba->sli4_hba.mbx_cq->queue_id == queid) { 439462306a36Sopenharmony_ci /* Sanity check */ 439562306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 439662306a36Sopenharmony_ci phba->sli4_hba.mbx_cq, index, count); 439762306a36Sopenharmony_ci if (rc) 439862306a36Sopenharmony_ci goto error_out; 439962306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.mbx_cq; 440062306a36Sopenharmony_ci goto pass_check; 440162306a36Sopenharmony_ci } 440262306a36Sopenharmony_ci /* ELS complete queue */ 440362306a36Sopenharmony_ci if (phba->sli4_hba.els_cq && 440462306a36Sopenharmony_ci phba->sli4_hba.els_cq->queue_id == queid) { 440562306a36Sopenharmony_ci /* Sanity check */ 440662306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 440762306a36Sopenharmony_ci phba->sli4_hba.els_cq, index, count); 440862306a36Sopenharmony_ci if (rc) 440962306a36Sopenharmony_ci goto error_out; 441062306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.els_cq; 441162306a36Sopenharmony_ci goto pass_check; 441262306a36Sopenharmony_ci } 441362306a36Sopenharmony_ci /* NVME LS complete queue */ 441462306a36Sopenharmony_ci if (phba->sli4_hba.nvmels_cq && 441562306a36Sopenharmony_ci phba->sli4_hba.nvmels_cq->queue_id == queid) { 441662306a36Sopenharmony_ci /* Sanity check */ 441762306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 441862306a36Sopenharmony_ci phba->sli4_hba.nvmels_cq, index, count); 441962306a36Sopenharmony_ci if (rc) 442062306a36Sopenharmony_ci goto error_out; 442162306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.nvmels_cq; 442262306a36Sopenharmony_ci goto pass_check; 442362306a36Sopenharmony_ci } 442462306a36Sopenharmony_ci /* FCP complete queue */ 442562306a36Sopenharmony_ci if (phba->sli4_hba.hdwq) { 442662306a36Sopenharmony_ci for (qidx = 0; qidx < phba->cfg_hdw_queue; 442762306a36Sopenharmony_ci qidx++) { 442862306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[qidx].io_cq; 442962306a36Sopenharmony_ci if (qp && qp->queue_id == queid) { 443062306a36Sopenharmony_ci /* Sanity check */ 443162306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 443262306a36Sopenharmony_ci qp, index, count); 443362306a36Sopenharmony_ci if (rc) 443462306a36Sopenharmony_ci goto error_out; 443562306a36Sopenharmony_ci idiag.ptr_private = qp; 443662306a36Sopenharmony_ci goto pass_check; 443762306a36Sopenharmony_ci } 443862306a36Sopenharmony_ci } 443962306a36Sopenharmony_ci } 444062306a36Sopenharmony_ci goto error_out; 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci case LPFC_IDIAG_MQ: 444362306a36Sopenharmony_ci /* MBX work queue */ 444462306a36Sopenharmony_ci if (phba->sli4_hba.mbx_wq && 444562306a36Sopenharmony_ci phba->sli4_hba.mbx_wq->queue_id == queid) { 444662306a36Sopenharmony_ci /* Sanity check */ 444762306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 444862306a36Sopenharmony_ci phba->sli4_hba.mbx_wq, index, count); 444962306a36Sopenharmony_ci if (rc) 445062306a36Sopenharmony_ci goto error_out; 445162306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.mbx_wq; 445262306a36Sopenharmony_ci goto pass_check; 445362306a36Sopenharmony_ci } 445462306a36Sopenharmony_ci goto error_out; 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci case LPFC_IDIAG_WQ: 445762306a36Sopenharmony_ci /* ELS work queue */ 445862306a36Sopenharmony_ci if (phba->sli4_hba.els_wq && 445962306a36Sopenharmony_ci phba->sli4_hba.els_wq->queue_id == queid) { 446062306a36Sopenharmony_ci /* Sanity check */ 446162306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 446262306a36Sopenharmony_ci phba->sli4_hba.els_wq, index, count); 446362306a36Sopenharmony_ci if (rc) 446462306a36Sopenharmony_ci goto error_out; 446562306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.els_wq; 446662306a36Sopenharmony_ci goto pass_check; 446762306a36Sopenharmony_ci } 446862306a36Sopenharmony_ci /* NVME LS work queue */ 446962306a36Sopenharmony_ci if (phba->sli4_hba.nvmels_wq && 447062306a36Sopenharmony_ci phba->sli4_hba.nvmels_wq->queue_id == queid) { 447162306a36Sopenharmony_ci /* Sanity check */ 447262306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 447362306a36Sopenharmony_ci phba->sli4_hba.nvmels_wq, index, count); 447462306a36Sopenharmony_ci if (rc) 447562306a36Sopenharmony_ci goto error_out; 447662306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.nvmels_wq; 447762306a36Sopenharmony_ci goto pass_check; 447862306a36Sopenharmony_ci } 447962306a36Sopenharmony_ci 448062306a36Sopenharmony_ci if (phba->sli4_hba.hdwq) { 448162306a36Sopenharmony_ci /* FCP/SCSI work queue */ 448262306a36Sopenharmony_ci for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { 448362306a36Sopenharmony_ci qp = phba->sli4_hba.hdwq[qidx].io_wq; 448462306a36Sopenharmony_ci if (qp && qp->queue_id == queid) { 448562306a36Sopenharmony_ci /* Sanity check */ 448662306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 448762306a36Sopenharmony_ci qp, index, count); 448862306a36Sopenharmony_ci if (rc) 448962306a36Sopenharmony_ci goto error_out; 449062306a36Sopenharmony_ci idiag.ptr_private = qp; 449162306a36Sopenharmony_ci goto pass_check; 449262306a36Sopenharmony_ci } 449362306a36Sopenharmony_ci } 449462306a36Sopenharmony_ci } 449562306a36Sopenharmony_ci goto error_out; 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci case LPFC_IDIAG_RQ: 449862306a36Sopenharmony_ci /* HDR queue */ 449962306a36Sopenharmony_ci if (phba->sli4_hba.hdr_rq && 450062306a36Sopenharmony_ci phba->sli4_hba.hdr_rq->queue_id == queid) { 450162306a36Sopenharmony_ci /* Sanity check */ 450262306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 450362306a36Sopenharmony_ci phba->sli4_hba.hdr_rq, index, count); 450462306a36Sopenharmony_ci if (rc) 450562306a36Sopenharmony_ci goto error_out; 450662306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.hdr_rq; 450762306a36Sopenharmony_ci goto pass_check; 450862306a36Sopenharmony_ci } 450962306a36Sopenharmony_ci /* DAT queue */ 451062306a36Sopenharmony_ci if (phba->sli4_hba.dat_rq && 451162306a36Sopenharmony_ci phba->sli4_hba.dat_rq->queue_id == queid) { 451262306a36Sopenharmony_ci /* Sanity check */ 451362306a36Sopenharmony_ci rc = lpfc_idiag_que_param_check( 451462306a36Sopenharmony_ci phba->sli4_hba.dat_rq, index, count); 451562306a36Sopenharmony_ci if (rc) 451662306a36Sopenharmony_ci goto error_out; 451762306a36Sopenharmony_ci idiag.ptr_private = phba->sli4_hba.dat_rq; 451862306a36Sopenharmony_ci goto pass_check; 451962306a36Sopenharmony_ci } 452062306a36Sopenharmony_ci goto error_out; 452162306a36Sopenharmony_ci default: 452262306a36Sopenharmony_ci goto error_out; 452362306a36Sopenharmony_ci } 452462306a36Sopenharmony_ci 452562306a36Sopenharmony_cipass_check: 452662306a36Sopenharmony_ci 452762306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { 452862306a36Sopenharmony_ci if (count == LPFC_QUE_ACC_BROWSE) 452962306a36Sopenharmony_ci idiag.offset.last_rd = index; 453062306a36Sopenharmony_ci } 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || 453362306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || 453462306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { 453562306a36Sopenharmony_ci /* Additional sanity checks on write operation */ 453662306a36Sopenharmony_ci pque = (struct lpfc_queue *)idiag.ptr_private; 453762306a36Sopenharmony_ci if (offset > pque->entry_size/sizeof(uint32_t) - 1) 453862306a36Sopenharmony_ci goto error_out; 453962306a36Sopenharmony_ci pentry = lpfc_sli4_qe(pque, index); 454062306a36Sopenharmony_ci pentry += offset; 454162306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) 454262306a36Sopenharmony_ci *pentry = value; 454362306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST) 454462306a36Sopenharmony_ci *pentry |= value; 454562306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) 454662306a36Sopenharmony_ci *pentry &= ~value; 454762306a36Sopenharmony_ci } 454862306a36Sopenharmony_ci return nbytes; 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_cierror_out: 455162306a36Sopenharmony_ci /* Clean out command structure on command error out */ 455262306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 455362306a36Sopenharmony_ci return -EINVAL; 455462306a36Sopenharmony_ci} 455562306a36Sopenharmony_ci 455662306a36Sopenharmony_ci/** 455762306a36Sopenharmony_ci * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register 455862306a36Sopenharmony_ci * @phba: The pointer to hba structure. 455962306a36Sopenharmony_ci * @pbuffer: The pointer to the buffer to copy the data to. 456062306a36Sopenharmony_ci * @len: The length of bytes to copied. 456162306a36Sopenharmony_ci * @drbregid: The id to doorbell registers. 456262306a36Sopenharmony_ci * 456362306a36Sopenharmony_ci * Description: 456462306a36Sopenharmony_ci * This routine reads a doorbell register and copies its content to the 456562306a36Sopenharmony_ci * user buffer pointed to by @pbuffer. 456662306a36Sopenharmony_ci * 456762306a36Sopenharmony_ci * Returns: 456862306a36Sopenharmony_ci * This function returns the amount of data that was copied into @pbuffer. 456962306a36Sopenharmony_ci **/ 457062306a36Sopenharmony_cistatic int 457162306a36Sopenharmony_cilpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, 457262306a36Sopenharmony_ci int len, uint32_t drbregid) 457362306a36Sopenharmony_ci{ 457462306a36Sopenharmony_ci 457562306a36Sopenharmony_ci if (!pbuffer) 457662306a36Sopenharmony_ci return 0; 457762306a36Sopenharmony_ci 457862306a36Sopenharmony_ci switch (drbregid) { 457962306a36Sopenharmony_ci case LPFC_DRB_EQ: 458062306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len, 458162306a36Sopenharmony_ci "EQ-DRB-REG: 0x%08x\n", 458262306a36Sopenharmony_ci readl(phba->sli4_hba.EQDBregaddr)); 458362306a36Sopenharmony_ci break; 458462306a36Sopenharmony_ci case LPFC_DRB_CQ: 458562306a36Sopenharmony_ci len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len, 458662306a36Sopenharmony_ci "CQ-DRB-REG: 0x%08x\n", 458762306a36Sopenharmony_ci readl(phba->sli4_hba.CQDBregaddr)); 458862306a36Sopenharmony_ci break; 458962306a36Sopenharmony_ci case LPFC_DRB_MQ: 459062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, 459162306a36Sopenharmony_ci "MQ-DRB-REG: 0x%08x\n", 459262306a36Sopenharmony_ci readl(phba->sli4_hba.MQDBregaddr)); 459362306a36Sopenharmony_ci break; 459462306a36Sopenharmony_ci case LPFC_DRB_WQ: 459562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, 459662306a36Sopenharmony_ci "WQ-DRB-REG: 0x%08x\n", 459762306a36Sopenharmony_ci readl(phba->sli4_hba.WQDBregaddr)); 459862306a36Sopenharmony_ci break; 459962306a36Sopenharmony_ci case LPFC_DRB_RQ: 460062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, 460162306a36Sopenharmony_ci "RQ-DRB-REG: 0x%08x\n", 460262306a36Sopenharmony_ci readl(phba->sli4_hba.RQDBregaddr)); 460362306a36Sopenharmony_ci break; 460462306a36Sopenharmony_ci default: 460562306a36Sopenharmony_ci break; 460662306a36Sopenharmony_ci } 460762306a36Sopenharmony_ci 460862306a36Sopenharmony_ci return len; 460962306a36Sopenharmony_ci} 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_ci/** 461262306a36Sopenharmony_ci * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell 461362306a36Sopenharmony_ci * @file: The file pointer to read from. 461462306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 461562306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 461662306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 461762306a36Sopenharmony_ci * 461862306a36Sopenharmony_ci * Description: 461962306a36Sopenharmony_ci * This routine reads data from the @phba device doorbell register according 462062306a36Sopenharmony_ci * to the idiag command, and copies to user @buf. Depending on the doorbell 462162306a36Sopenharmony_ci * register read command setup, it does either a single doorbell register 462262306a36Sopenharmony_ci * read or dump all doorbell registers. 462362306a36Sopenharmony_ci * 462462306a36Sopenharmony_ci * Returns: 462562306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 462662306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 462762306a36Sopenharmony_ci **/ 462862306a36Sopenharmony_cistatic ssize_t 462962306a36Sopenharmony_cilpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, 463062306a36Sopenharmony_ci loff_t *ppos) 463162306a36Sopenharmony_ci{ 463262306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 463362306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 463462306a36Sopenharmony_ci uint32_t drb_reg_id, i; 463562306a36Sopenharmony_ci char *pbuffer; 463662306a36Sopenharmony_ci int len = 0; 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci /* This is a user read operation */ 463962306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci if (!debug->buffer) 464262306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL); 464362306a36Sopenharmony_ci if (!debug->buffer) 464462306a36Sopenharmony_ci return 0; 464562306a36Sopenharmony_ci pbuffer = debug->buffer; 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci if (*ppos) 464862306a36Sopenharmony_ci return 0; 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) 465162306a36Sopenharmony_ci drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; 465262306a36Sopenharmony_ci else 465362306a36Sopenharmony_ci return 0; 465462306a36Sopenharmony_ci 465562306a36Sopenharmony_ci if (drb_reg_id == LPFC_DRB_ACC_ALL) 465662306a36Sopenharmony_ci for (i = 1; i <= LPFC_DRB_MAX; i++) 465762306a36Sopenharmony_ci len = lpfc_idiag_drbacc_read_reg(phba, 465862306a36Sopenharmony_ci pbuffer, len, i); 465962306a36Sopenharmony_ci else 466062306a36Sopenharmony_ci len = lpfc_idiag_drbacc_read_reg(phba, 466162306a36Sopenharmony_ci pbuffer, len, drb_reg_id); 466262306a36Sopenharmony_ci 466362306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 466462306a36Sopenharmony_ci} 466562306a36Sopenharmony_ci 466662306a36Sopenharmony_ci/** 466762306a36Sopenharmony_ci * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands 466862306a36Sopenharmony_ci * @file: The file pointer to read from. 466962306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 467062306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 467162306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 467262306a36Sopenharmony_ci * 467362306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and then 467462306a36Sopenharmony_ci * perform the syntax check for port doorbell register read (dump) or write 467562306a36Sopenharmony_ci * (set) command accordingly. In the case of port queue read command, it sets 467662306a36Sopenharmony_ci * up the command in the idiag command struct for the following debugfs read 467762306a36Sopenharmony_ci * operation. In the case of port doorbell register write operation, it 467862306a36Sopenharmony_ci * executes the write operation into the port doorbell register accordingly. 467962306a36Sopenharmony_ci * 468062306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 468162306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 468262306a36Sopenharmony_ci * space. 468362306a36Sopenharmony_ci **/ 468462306a36Sopenharmony_cistatic ssize_t 468562306a36Sopenharmony_cilpfc_idiag_drbacc_write(struct file *file, const char __user *buf, 468662306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 468762306a36Sopenharmony_ci{ 468862306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 468962306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 469062306a36Sopenharmony_ci uint32_t drb_reg_id, value, reg_val = 0; 469162306a36Sopenharmony_ci void __iomem *drb_reg; 469262306a36Sopenharmony_ci int rc; 469362306a36Sopenharmony_ci 469462306a36Sopenharmony_ci /* This is a user write operation */ 469562306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 469662306a36Sopenharmony_ci 469762306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 469862306a36Sopenharmony_ci if (rc < 0) 469962306a36Sopenharmony_ci return rc; 470062306a36Sopenharmony_ci 470162306a36Sopenharmony_ci /* Sanity check on command line arguments */ 470262306a36Sopenharmony_ci drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; 470362306a36Sopenharmony_ci value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX]; 470462306a36Sopenharmony_ci 470562306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || 470662306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || 470762306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { 470862306a36Sopenharmony_ci if (rc != LPFC_DRB_ACC_WR_CMD_ARG) 470962306a36Sopenharmony_ci goto error_out; 471062306a36Sopenharmony_ci if (drb_reg_id > LPFC_DRB_MAX) 471162306a36Sopenharmony_ci goto error_out; 471262306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) { 471362306a36Sopenharmony_ci if (rc != LPFC_DRB_ACC_RD_CMD_ARG) 471462306a36Sopenharmony_ci goto error_out; 471562306a36Sopenharmony_ci if ((drb_reg_id > LPFC_DRB_MAX) && 471662306a36Sopenharmony_ci (drb_reg_id != LPFC_DRB_ACC_ALL)) 471762306a36Sopenharmony_ci goto error_out; 471862306a36Sopenharmony_ci } else 471962306a36Sopenharmony_ci goto error_out; 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_ci /* Perform the write access operation */ 472262306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || 472362306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || 472462306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { 472562306a36Sopenharmony_ci switch (drb_reg_id) { 472662306a36Sopenharmony_ci case LPFC_DRB_EQ: 472762306a36Sopenharmony_ci drb_reg = phba->sli4_hba.EQDBregaddr; 472862306a36Sopenharmony_ci break; 472962306a36Sopenharmony_ci case LPFC_DRB_CQ: 473062306a36Sopenharmony_ci drb_reg = phba->sli4_hba.CQDBregaddr; 473162306a36Sopenharmony_ci break; 473262306a36Sopenharmony_ci case LPFC_DRB_MQ: 473362306a36Sopenharmony_ci drb_reg = phba->sli4_hba.MQDBregaddr; 473462306a36Sopenharmony_ci break; 473562306a36Sopenharmony_ci case LPFC_DRB_WQ: 473662306a36Sopenharmony_ci drb_reg = phba->sli4_hba.WQDBregaddr; 473762306a36Sopenharmony_ci break; 473862306a36Sopenharmony_ci case LPFC_DRB_RQ: 473962306a36Sopenharmony_ci drb_reg = phba->sli4_hba.RQDBregaddr; 474062306a36Sopenharmony_ci break; 474162306a36Sopenharmony_ci default: 474262306a36Sopenharmony_ci goto error_out; 474362306a36Sopenharmony_ci } 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR) 474662306a36Sopenharmony_ci reg_val = value; 474762306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) { 474862306a36Sopenharmony_ci reg_val = readl(drb_reg); 474962306a36Sopenharmony_ci reg_val |= value; 475062306a36Sopenharmony_ci } 475162306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { 475262306a36Sopenharmony_ci reg_val = readl(drb_reg); 475362306a36Sopenharmony_ci reg_val &= ~value; 475462306a36Sopenharmony_ci } 475562306a36Sopenharmony_ci writel(reg_val, drb_reg); 475662306a36Sopenharmony_ci readl(drb_reg); /* flush */ 475762306a36Sopenharmony_ci } 475862306a36Sopenharmony_ci return nbytes; 475962306a36Sopenharmony_ci 476062306a36Sopenharmony_cierror_out: 476162306a36Sopenharmony_ci /* Clean out command structure on command error out */ 476262306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 476362306a36Sopenharmony_ci return -EINVAL; 476462306a36Sopenharmony_ci} 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci/** 476762306a36Sopenharmony_ci * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers 476862306a36Sopenharmony_ci * @phba: The pointer to hba structure. 476962306a36Sopenharmony_ci * @pbuffer: The pointer to the buffer to copy the data to. 477062306a36Sopenharmony_ci * @len: The length of bytes to copied. 477162306a36Sopenharmony_ci * @ctlregid: The id to doorbell registers. 477262306a36Sopenharmony_ci * 477362306a36Sopenharmony_ci * Description: 477462306a36Sopenharmony_ci * This routine reads a control register and copies its content to the 477562306a36Sopenharmony_ci * user buffer pointed to by @pbuffer. 477662306a36Sopenharmony_ci * 477762306a36Sopenharmony_ci * Returns: 477862306a36Sopenharmony_ci * This function returns the amount of data that was copied into @pbuffer. 477962306a36Sopenharmony_ci **/ 478062306a36Sopenharmony_cistatic int 478162306a36Sopenharmony_cilpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, 478262306a36Sopenharmony_ci int len, uint32_t ctlregid) 478362306a36Sopenharmony_ci{ 478462306a36Sopenharmony_ci 478562306a36Sopenharmony_ci if (!pbuffer) 478662306a36Sopenharmony_ci return 0; 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci switch (ctlregid) { 478962306a36Sopenharmony_ci case LPFC_CTL_PORT_SEM: 479062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 479162306a36Sopenharmony_ci "Port SemReg: 0x%08x\n", 479262306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 479362306a36Sopenharmony_ci LPFC_CTL_PORT_SEM_OFFSET)); 479462306a36Sopenharmony_ci break; 479562306a36Sopenharmony_ci case LPFC_CTL_PORT_STA: 479662306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 479762306a36Sopenharmony_ci "Port StaReg: 0x%08x\n", 479862306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 479962306a36Sopenharmony_ci LPFC_CTL_PORT_STA_OFFSET)); 480062306a36Sopenharmony_ci break; 480162306a36Sopenharmony_ci case LPFC_CTL_PORT_CTL: 480262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 480362306a36Sopenharmony_ci "Port CtlReg: 0x%08x\n", 480462306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 480562306a36Sopenharmony_ci LPFC_CTL_PORT_CTL_OFFSET)); 480662306a36Sopenharmony_ci break; 480762306a36Sopenharmony_ci case LPFC_CTL_PORT_ER1: 480862306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 480962306a36Sopenharmony_ci "Port Er1Reg: 0x%08x\n", 481062306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 481162306a36Sopenharmony_ci LPFC_CTL_PORT_ER1_OFFSET)); 481262306a36Sopenharmony_ci break; 481362306a36Sopenharmony_ci case LPFC_CTL_PORT_ER2: 481462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 481562306a36Sopenharmony_ci "Port Er2Reg: 0x%08x\n", 481662306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 481762306a36Sopenharmony_ci LPFC_CTL_PORT_ER2_OFFSET)); 481862306a36Sopenharmony_ci break; 481962306a36Sopenharmony_ci case LPFC_CTL_PDEV_CTL: 482062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, 482162306a36Sopenharmony_ci "PDev CtlReg: 0x%08x\n", 482262306a36Sopenharmony_ci readl(phba->sli4_hba.conf_regs_memmap_p + 482362306a36Sopenharmony_ci LPFC_CTL_PDEV_CTL_OFFSET)); 482462306a36Sopenharmony_ci break; 482562306a36Sopenharmony_ci default: 482662306a36Sopenharmony_ci break; 482762306a36Sopenharmony_ci } 482862306a36Sopenharmony_ci return len; 482962306a36Sopenharmony_ci} 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ci/** 483262306a36Sopenharmony_ci * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register 483362306a36Sopenharmony_ci * @file: The file pointer to read from. 483462306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 483562306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 483662306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 483762306a36Sopenharmony_ci * 483862306a36Sopenharmony_ci * Description: 483962306a36Sopenharmony_ci * This routine reads data from the @phba port and device registers according 484062306a36Sopenharmony_ci * to the idiag command, and copies to user @buf. 484162306a36Sopenharmony_ci * 484262306a36Sopenharmony_ci * Returns: 484362306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 484462306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 484562306a36Sopenharmony_ci **/ 484662306a36Sopenharmony_cistatic ssize_t 484762306a36Sopenharmony_cilpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes, 484862306a36Sopenharmony_ci loff_t *ppos) 484962306a36Sopenharmony_ci{ 485062306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 485162306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 485262306a36Sopenharmony_ci uint32_t ctl_reg_id, i; 485362306a36Sopenharmony_ci char *pbuffer; 485462306a36Sopenharmony_ci int len = 0; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci /* This is a user read operation */ 485762306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 485862306a36Sopenharmony_ci 485962306a36Sopenharmony_ci if (!debug->buffer) 486062306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL); 486162306a36Sopenharmony_ci if (!debug->buffer) 486262306a36Sopenharmony_ci return 0; 486362306a36Sopenharmony_ci pbuffer = debug->buffer; 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_ci if (*ppos) 486662306a36Sopenharmony_ci return 0; 486762306a36Sopenharmony_ci 486862306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) 486962306a36Sopenharmony_ci ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; 487062306a36Sopenharmony_ci else 487162306a36Sopenharmony_ci return 0; 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_ci if (ctl_reg_id == LPFC_CTL_ACC_ALL) 487462306a36Sopenharmony_ci for (i = 1; i <= LPFC_CTL_MAX; i++) 487562306a36Sopenharmony_ci len = lpfc_idiag_ctlacc_read_reg(phba, 487662306a36Sopenharmony_ci pbuffer, len, i); 487762306a36Sopenharmony_ci else 487862306a36Sopenharmony_ci len = lpfc_idiag_ctlacc_read_reg(phba, 487962306a36Sopenharmony_ci pbuffer, len, ctl_reg_id); 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 488262306a36Sopenharmony_ci} 488362306a36Sopenharmony_ci 488462306a36Sopenharmony_ci/** 488562306a36Sopenharmony_ci * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands 488662306a36Sopenharmony_ci * @file: The file pointer to read from. 488762306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 488862306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 488962306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 489062306a36Sopenharmony_ci * 489162306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and then 489262306a36Sopenharmony_ci * perform the syntax check for port and device control register read (dump) 489362306a36Sopenharmony_ci * or write (set) command accordingly. 489462306a36Sopenharmony_ci * 489562306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 489662306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 489762306a36Sopenharmony_ci * space. 489862306a36Sopenharmony_ci **/ 489962306a36Sopenharmony_cistatic ssize_t 490062306a36Sopenharmony_cilpfc_idiag_ctlacc_write(struct file *file, const char __user *buf, 490162306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 490262306a36Sopenharmony_ci{ 490362306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 490462306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 490562306a36Sopenharmony_ci uint32_t ctl_reg_id, value, reg_val = 0; 490662306a36Sopenharmony_ci void __iomem *ctl_reg; 490762306a36Sopenharmony_ci int rc; 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_ci /* This is a user write operation */ 491062306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 491162306a36Sopenharmony_ci 491262306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 491362306a36Sopenharmony_ci if (rc < 0) 491462306a36Sopenharmony_ci return rc; 491562306a36Sopenharmony_ci 491662306a36Sopenharmony_ci /* Sanity check on command line arguments */ 491762306a36Sopenharmony_ci ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; 491862306a36Sopenharmony_ci value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX]; 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || 492162306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || 492262306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { 492362306a36Sopenharmony_ci if (rc != LPFC_CTL_ACC_WR_CMD_ARG) 492462306a36Sopenharmony_ci goto error_out; 492562306a36Sopenharmony_ci if (ctl_reg_id > LPFC_CTL_MAX) 492662306a36Sopenharmony_ci goto error_out; 492762306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) { 492862306a36Sopenharmony_ci if (rc != LPFC_CTL_ACC_RD_CMD_ARG) 492962306a36Sopenharmony_ci goto error_out; 493062306a36Sopenharmony_ci if ((ctl_reg_id > LPFC_CTL_MAX) && 493162306a36Sopenharmony_ci (ctl_reg_id != LPFC_CTL_ACC_ALL)) 493262306a36Sopenharmony_ci goto error_out; 493362306a36Sopenharmony_ci } else 493462306a36Sopenharmony_ci goto error_out; 493562306a36Sopenharmony_ci 493662306a36Sopenharmony_ci /* Perform the write access operation */ 493762306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || 493862306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || 493962306a36Sopenharmony_ci idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { 494062306a36Sopenharmony_ci switch (ctl_reg_id) { 494162306a36Sopenharmony_ci case LPFC_CTL_PORT_SEM: 494262306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 494362306a36Sopenharmony_ci LPFC_CTL_PORT_SEM_OFFSET; 494462306a36Sopenharmony_ci break; 494562306a36Sopenharmony_ci case LPFC_CTL_PORT_STA: 494662306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 494762306a36Sopenharmony_ci LPFC_CTL_PORT_STA_OFFSET; 494862306a36Sopenharmony_ci break; 494962306a36Sopenharmony_ci case LPFC_CTL_PORT_CTL: 495062306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 495162306a36Sopenharmony_ci LPFC_CTL_PORT_CTL_OFFSET; 495262306a36Sopenharmony_ci break; 495362306a36Sopenharmony_ci case LPFC_CTL_PORT_ER1: 495462306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 495562306a36Sopenharmony_ci LPFC_CTL_PORT_ER1_OFFSET; 495662306a36Sopenharmony_ci break; 495762306a36Sopenharmony_ci case LPFC_CTL_PORT_ER2: 495862306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 495962306a36Sopenharmony_ci LPFC_CTL_PORT_ER2_OFFSET; 496062306a36Sopenharmony_ci break; 496162306a36Sopenharmony_ci case LPFC_CTL_PDEV_CTL: 496262306a36Sopenharmony_ci ctl_reg = phba->sli4_hba.conf_regs_memmap_p + 496362306a36Sopenharmony_ci LPFC_CTL_PDEV_CTL_OFFSET; 496462306a36Sopenharmony_ci break; 496562306a36Sopenharmony_ci default: 496662306a36Sopenharmony_ci goto error_out; 496762306a36Sopenharmony_ci } 496862306a36Sopenharmony_ci 496962306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR) 497062306a36Sopenharmony_ci reg_val = value; 497162306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) { 497262306a36Sopenharmony_ci reg_val = readl(ctl_reg); 497362306a36Sopenharmony_ci reg_val |= value; 497462306a36Sopenharmony_ci } 497562306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { 497662306a36Sopenharmony_ci reg_val = readl(ctl_reg); 497762306a36Sopenharmony_ci reg_val &= ~value; 497862306a36Sopenharmony_ci } 497962306a36Sopenharmony_ci writel(reg_val, ctl_reg); 498062306a36Sopenharmony_ci readl(ctl_reg); /* flush */ 498162306a36Sopenharmony_ci } 498262306a36Sopenharmony_ci return nbytes; 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_cierror_out: 498562306a36Sopenharmony_ci /* Clean out command structure on command error out */ 498662306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 498762306a36Sopenharmony_ci return -EINVAL; 498862306a36Sopenharmony_ci} 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ci/** 499162306a36Sopenharmony_ci * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup 499262306a36Sopenharmony_ci * @phba: Pointer to HBA context object. 499362306a36Sopenharmony_ci * @pbuffer: Pointer to data buffer. 499462306a36Sopenharmony_ci * 499562306a36Sopenharmony_ci * Description: 499662306a36Sopenharmony_ci * This routine gets the driver mailbox access debugfs setup information. 499762306a36Sopenharmony_ci * 499862306a36Sopenharmony_ci * Returns: 499962306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 500062306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 500162306a36Sopenharmony_ci **/ 500262306a36Sopenharmony_cistatic int 500362306a36Sopenharmony_cilpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) 500462306a36Sopenharmony_ci{ 500562306a36Sopenharmony_ci uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; 500662306a36Sopenharmony_ci int len = 0; 500762306a36Sopenharmony_ci 500862306a36Sopenharmony_ci mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; 500962306a36Sopenharmony_ci mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; 501062306a36Sopenharmony_ci mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; 501162306a36Sopenharmony_ci mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, 501462306a36Sopenharmony_ci "mbx_dump_map: 0x%08x\n", mbx_dump_map); 501562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, 501662306a36Sopenharmony_ci "mbx_dump_cnt: %04d\n", mbx_dump_cnt); 501762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, 501862306a36Sopenharmony_ci "mbx_word_cnt: %04d\n", mbx_word_cnt); 501962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, 502062306a36Sopenharmony_ci "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci return len; 502362306a36Sopenharmony_ci} 502462306a36Sopenharmony_ci 502562306a36Sopenharmony_ci/** 502662306a36Sopenharmony_ci * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access 502762306a36Sopenharmony_ci * @file: The file pointer to read from. 502862306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 502962306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 503062306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 503162306a36Sopenharmony_ci * 503262306a36Sopenharmony_ci * Description: 503362306a36Sopenharmony_ci * This routine reads data from the @phba driver mailbox access debugfs setup 503462306a36Sopenharmony_ci * information. 503562306a36Sopenharmony_ci * 503662306a36Sopenharmony_ci * Returns: 503762306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 503862306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 503962306a36Sopenharmony_ci **/ 504062306a36Sopenharmony_cistatic ssize_t 504162306a36Sopenharmony_cilpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes, 504262306a36Sopenharmony_ci loff_t *ppos) 504362306a36Sopenharmony_ci{ 504462306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 504562306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 504662306a36Sopenharmony_ci char *pbuffer; 504762306a36Sopenharmony_ci int len = 0; 504862306a36Sopenharmony_ci 504962306a36Sopenharmony_ci /* This is a user read operation */ 505062306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 505162306a36Sopenharmony_ci 505262306a36Sopenharmony_ci if (!debug->buffer) 505362306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL); 505462306a36Sopenharmony_ci if (!debug->buffer) 505562306a36Sopenharmony_ci return 0; 505662306a36Sopenharmony_ci pbuffer = debug->buffer; 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci if (*ppos) 505962306a36Sopenharmony_ci return 0; 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) && 506262306a36Sopenharmony_ci (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)) 506362306a36Sopenharmony_ci return 0; 506462306a36Sopenharmony_ci 506562306a36Sopenharmony_ci len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer); 506662306a36Sopenharmony_ci 506762306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 506862306a36Sopenharmony_ci} 506962306a36Sopenharmony_ci 507062306a36Sopenharmony_ci/** 507162306a36Sopenharmony_ci * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands 507262306a36Sopenharmony_ci * @file: The file pointer to read from. 507362306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 507462306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 507562306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 507662306a36Sopenharmony_ci * 507762306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and then 507862306a36Sopenharmony_ci * perform the syntax check for driver mailbox command (dump) and sets up the 507962306a36Sopenharmony_ci * necessary states in the idiag command struct accordingly. 508062306a36Sopenharmony_ci * 508162306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 508262306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 508362306a36Sopenharmony_ci * space. 508462306a36Sopenharmony_ci **/ 508562306a36Sopenharmony_cistatic ssize_t 508662306a36Sopenharmony_cilpfc_idiag_mbxacc_write(struct file *file, const char __user *buf, 508762306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 508862306a36Sopenharmony_ci{ 508962306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 509062306a36Sopenharmony_ci uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; 509162306a36Sopenharmony_ci int rc; 509262306a36Sopenharmony_ci 509362306a36Sopenharmony_ci /* This is a user write operation */ 509462306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 509562306a36Sopenharmony_ci 509662306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 509762306a36Sopenharmony_ci if (rc < 0) 509862306a36Sopenharmony_ci return rc; 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci /* Sanity check on command line arguments */ 510162306a36Sopenharmony_ci mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; 510262306a36Sopenharmony_ci mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; 510362306a36Sopenharmony_ci mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; 510462306a36Sopenharmony_ci mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) { 510762306a36Sopenharmony_ci if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL)) 510862306a36Sopenharmony_ci goto error_out; 510962306a36Sopenharmony_ci if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) && 511062306a36Sopenharmony_ci (mbx_dump_map != LPFC_MBX_DMP_ALL)) 511162306a36Sopenharmony_ci goto error_out; 511262306a36Sopenharmony_ci if (mbx_word_cnt > sizeof(MAILBOX_t)) 511362306a36Sopenharmony_ci goto error_out; 511462306a36Sopenharmony_ci } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) { 511562306a36Sopenharmony_ci if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL)) 511662306a36Sopenharmony_ci goto error_out; 511762306a36Sopenharmony_ci if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) && 511862306a36Sopenharmony_ci (mbx_dump_map != LPFC_MBX_DMP_ALL)) 511962306a36Sopenharmony_ci goto error_out; 512062306a36Sopenharmony_ci if (mbx_word_cnt > (BSG_MBOX_SIZE)/4) 512162306a36Sopenharmony_ci goto error_out; 512262306a36Sopenharmony_ci if (mbx_mbox_cmd != 0x9b) 512362306a36Sopenharmony_ci goto error_out; 512462306a36Sopenharmony_ci } else 512562306a36Sopenharmony_ci goto error_out; 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci if (mbx_word_cnt == 0) 512862306a36Sopenharmony_ci goto error_out; 512962306a36Sopenharmony_ci if (rc != LPFC_MBX_DMP_ARG) 513062306a36Sopenharmony_ci goto error_out; 513162306a36Sopenharmony_ci if (mbx_mbox_cmd & ~0xff) 513262306a36Sopenharmony_ci goto error_out; 513362306a36Sopenharmony_ci 513462306a36Sopenharmony_ci /* condition for stop mailbox dump */ 513562306a36Sopenharmony_ci if (mbx_dump_cnt == 0) 513662306a36Sopenharmony_ci goto reset_out; 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_ci return nbytes; 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_cireset_out: 514162306a36Sopenharmony_ci /* Clean out command structure on command error out */ 514262306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 514362306a36Sopenharmony_ci return nbytes; 514462306a36Sopenharmony_ci 514562306a36Sopenharmony_cierror_out: 514662306a36Sopenharmony_ci /* Clean out command structure on command error out */ 514762306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 514862306a36Sopenharmony_ci return -EINVAL; 514962306a36Sopenharmony_ci} 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_ci/** 515262306a36Sopenharmony_ci * lpfc_idiag_extacc_avail_get - get the available extents information 515362306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 515462306a36Sopenharmony_ci * @pbuffer: pointer to internal buffer. 515562306a36Sopenharmony_ci * @len: length into the internal buffer data has been copied. 515662306a36Sopenharmony_ci * 515762306a36Sopenharmony_ci * Description: 515862306a36Sopenharmony_ci * This routine is to get the available extent information. 515962306a36Sopenharmony_ci * 516062306a36Sopenharmony_ci * Returns: 516162306a36Sopenharmony_ci * overall length of the data read into the internal buffer. 516262306a36Sopenharmony_ci **/ 516362306a36Sopenharmony_cistatic int 516462306a36Sopenharmony_cilpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) 516562306a36Sopenharmony_ci{ 516662306a36Sopenharmony_ci uint16_t ext_cnt = 0, ext_size = 0; 516762306a36Sopenharmony_ci 516862306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 516962306a36Sopenharmony_ci "\nAvailable Extents Information:\n"); 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 517262306a36Sopenharmony_ci "\tPort Available VPI extents: "); 517362306a36Sopenharmony_ci lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, 517462306a36Sopenharmony_ci &ext_cnt, &ext_size); 517562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 517662306a36Sopenharmony_ci "Count %3d, Size %3d\n", ext_cnt, ext_size); 517762306a36Sopenharmony_ci 517862306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 517962306a36Sopenharmony_ci "\tPort Available VFI extents: "); 518062306a36Sopenharmony_ci lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, 518162306a36Sopenharmony_ci &ext_cnt, &ext_size); 518262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 518362306a36Sopenharmony_ci "Count %3d, Size %3d\n", ext_cnt, ext_size); 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 518662306a36Sopenharmony_ci "\tPort Available RPI extents: "); 518762306a36Sopenharmony_ci lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, 518862306a36Sopenharmony_ci &ext_cnt, &ext_size); 518962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 519062306a36Sopenharmony_ci "Count %3d, Size %3d\n", ext_cnt, ext_size); 519162306a36Sopenharmony_ci 519262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 519362306a36Sopenharmony_ci "\tPort Available XRI extents: "); 519462306a36Sopenharmony_ci lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, 519562306a36Sopenharmony_ci &ext_cnt, &ext_size); 519662306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 519762306a36Sopenharmony_ci "Count %3d, Size %3d\n", ext_cnt, ext_size); 519862306a36Sopenharmony_ci 519962306a36Sopenharmony_ci return len; 520062306a36Sopenharmony_ci} 520162306a36Sopenharmony_ci 520262306a36Sopenharmony_ci/** 520362306a36Sopenharmony_ci * lpfc_idiag_extacc_alloc_get - get the allocated extents information 520462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 520562306a36Sopenharmony_ci * @pbuffer: pointer to internal buffer. 520662306a36Sopenharmony_ci * @len: length into the internal buffer data has been copied. 520762306a36Sopenharmony_ci * 520862306a36Sopenharmony_ci * Description: 520962306a36Sopenharmony_ci * This routine is to get the allocated extent information. 521062306a36Sopenharmony_ci * 521162306a36Sopenharmony_ci * Returns: 521262306a36Sopenharmony_ci * overall length of the data read into the internal buffer. 521362306a36Sopenharmony_ci **/ 521462306a36Sopenharmony_cistatic int 521562306a36Sopenharmony_cilpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) 521662306a36Sopenharmony_ci{ 521762306a36Sopenharmony_ci uint16_t ext_cnt, ext_size; 521862306a36Sopenharmony_ci int rc; 521962306a36Sopenharmony_ci 522062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 522162306a36Sopenharmony_ci "\nAllocated Extents Information:\n"); 522262306a36Sopenharmony_ci 522362306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 522462306a36Sopenharmony_ci "\tHost Allocated VPI extents: "); 522562306a36Sopenharmony_ci rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, 522662306a36Sopenharmony_ci &ext_cnt, &ext_size); 522762306a36Sopenharmony_ci if (!rc) 522862306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 522962306a36Sopenharmony_ci "Port %d Extent %3d, Size %3d\n", 523062306a36Sopenharmony_ci phba->brd_no, ext_cnt, ext_size); 523162306a36Sopenharmony_ci else 523262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 523362306a36Sopenharmony_ci "N/A\n"); 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 523662306a36Sopenharmony_ci "\tHost Allocated VFI extents: "); 523762306a36Sopenharmony_ci rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, 523862306a36Sopenharmony_ci &ext_cnt, &ext_size); 523962306a36Sopenharmony_ci if (!rc) 524062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 524162306a36Sopenharmony_ci "Port %d Extent %3d, Size %3d\n", 524262306a36Sopenharmony_ci phba->brd_no, ext_cnt, ext_size); 524362306a36Sopenharmony_ci else 524462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 524562306a36Sopenharmony_ci "N/A\n"); 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 524862306a36Sopenharmony_ci "\tHost Allocated RPI extents: "); 524962306a36Sopenharmony_ci rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, 525062306a36Sopenharmony_ci &ext_cnt, &ext_size); 525162306a36Sopenharmony_ci if (!rc) 525262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 525362306a36Sopenharmony_ci "Port %d Extent %3d, Size %3d\n", 525462306a36Sopenharmony_ci phba->brd_no, ext_cnt, ext_size); 525562306a36Sopenharmony_ci else 525662306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 525762306a36Sopenharmony_ci "N/A\n"); 525862306a36Sopenharmony_ci 525962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 526062306a36Sopenharmony_ci "\tHost Allocated XRI extents: "); 526162306a36Sopenharmony_ci rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, 526262306a36Sopenharmony_ci &ext_cnt, &ext_size); 526362306a36Sopenharmony_ci if (!rc) 526462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 526562306a36Sopenharmony_ci "Port %d Extent %3d, Size %3d\n", 526662306a36Sopenharmony_ci phba->brd_no, ext_cnt, ext_size); 526762306a36Sopenharmony_ci else 526862306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 526962306a36Sopenharmony_ci "N/A\n"); 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci return len; 527262306a36Sopenharmony_ci} 527362306a36Sopenharmony_ci 527462306a36Sopenharmony_ci/** 527562306a36Sopenharmony_ci * lpfc_idiag_extacc_drivr_get - get driver extent information 527662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 527762306a36Sopenharmony_ci * @pbuffer: pointer to internal buffer. 527862306a36Sopenharmony_ci * @len: length into the internal buffer data has been copied. 527962306a36Sopenharmony_ci * 528062306a36Sopenharmony_ci * Description: 528162306a36Sopenharmony_ci * This routine is to get the driver extent information. 528262306a36Sopenharmony_ci * 528362306a36Sopenharmony_ci * Returns: 528462306a36Sopenharmony_ci * overall length of the data read into the internal buffer. 528562306a36Sopenharmony_ci **/ 528662306a36Sopenharmony_cistatic int 528762306a36Sopenharmony_cilpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) 528862306a36Sopenharmony_ci{ 528962306a36Sopenharmony_ci struct lpfc_rsrc_blks *rsrc_blks; 529062306a36Sopenharmony_ci int index; 529162306a36Sopenharmony_ci 529262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 529362306a36Sopenharmony_ci "\nDriver Extents Information:\n"); 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 529662306a36Sopenharmony_ci "\tVPI extents:\n"); 529762306a36Sopenharmony_ci index = 0; 529862306a36Sopenharmony_ci list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { 529962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 530062306a36Sopenharmony_ci "\t\tBlock %3d: Start %4d, Count %4d\n", 530162306a36Sopenharmony_ci index, rsrc_blks->rsrc_start, 530262306a36Sopenharmony_ci rsrc_blks->rsrc_size); 530362306a36Sopenharmony_ci index++; 530462306a36Sopenharmony_ci } 530562306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 530662306a36Sopenharmony_ci "\tVFI extents:\n"); 530762306a36Sopenharmony_ci index = 0; 530862306a36Sopenharmony_ci list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, 530962306a36Sopenharmony_ci list) { 531062306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 531162306a36Sopenharmony_ci "\t\tBlock %3d: Start %4d, Count %4d\n", 531262306a36Sopenharmony_ci index, rsrc_blks->rsrc_start, 531362306a36Sopenharmony_ci rsrc_blks->rsrc_size); 531462306a36Sopenharmony_ci index++; 531562306a36Sopenharmony_ci } 531662306a36Sopenharmony_ci 531762306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 531862306a36Sopenharmony_ci "\tRPI extents:\n"); 531962306a36Sopenharmony_ci index = 0; 532062306a36Sopenharmony_ci list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, 532162306a36Sopenharmony_ci list) { 532262306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 532362306a36Sopenharmony_ci "\t\tBlock %3d: Start %4d, Count %4d\n", 532462306a36Sopenharmony_ci index, rsrc_blks->rsrc_start, 532562306a36Sopenharmony_ci rsrc_blks->rsrc_size); 532662306a36Sopenharmony_ci index++; 532762306a36Sopenharmony_ci } 532862306a36Sopenharmony_ci 532962306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 533062306a36Sopenharmony_ci "\tXRI extents:\n"); 533162306a36Sopenharmony_ci index = 0; 533262306a36Sopenharmony_ci list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, 533362306a36Sopenharmony_ci list) { 533462306a36Sopenharmony_ci len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, 533562306a36Sopenharmony_ci "\t\tBlock %3d: Start %4d, Count %4d\n", 533662306a36Sopenharmony_ci index, rsrc_blks->rsrc_start, 533762306a36Sopenharmony_ci rsrc_blks->rsrc_size); 533862306a36Sopenharmony_ci index++; 533962306a36Sopenharmony_ci } 534062306a36Sopenharmony_ci 534162306a36Sopenharmony_ci return len; 534262306a36Sopenharmony_ci} 534362306a36Sopenharmony_ci 534462306a36Sopenharmony_ci/** 534562306a36Sopenharmony_ci * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands 534662306a36Sopenharmony_ci * @file: The file pointer to read from. 534762306a36Sopenharmony_ci * @buf: The buffer to copy the user data from. 534862306a36Sopenharmony_ci * @nbytes: The number of bytes to get. 534962306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 535062306a36Sopenharmony_ci * 535162306a36Sopenharmony_ci * This routine get the debugfs idiag command struct from user space and then 535262306a36Sopenharmony_ci * perform the syntax check for extent information access commands and sets 535362306a36Sopenharmony_ci * up the necessary states in the idiag command struct accordingly. 535462306a36Sopenharmony_ci * 535562306a36Sopenharmony_ci * It returns the @nbytges passing in from debugfs user space when successful. 535662306a36Sopenharmony_ci * In case of error conditions, it returns proper error code back to the user 535762306a36Sopenharmony_ci * space. 535862306a36Sopenharmony_ci **/ 535962306a36Sopenharmony_cistatic ssize_t 536062306a36Sopenharmony_cilpfc_idiag_extacc_write(struct file *file, const char __user *buf, 536162306a36Sopenharmony_ci size_t nbytes, loff_t *ppos) 536262306a36Sopenharmony_ci{ 536362306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 536462306a36Sopenharmony_ci uint32_t ext_map; 536562306a36Sopenharmony_ci int rc; 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci /* This is a user write operation */ 536862306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_WR; 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_ci rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); 537162306a36Sopenharmony_ci if (rc < 0) 537262306a36Sopenharmony_ci return rc; 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_ci ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; 537562306a36Sopenharmony_ci 537662306a36Sopenharmony_ci if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) 537762306a36Sopenharmony_ci goto error_out; 537862306a36Sopenharmony_ci if (rc != LPFC_EXT_ACC_CMD_ARG) 537962306a36Sopenharmony_ci goto error_out; 538062306a36Sopenharmony_ci if (!(ext_map & LPFC_EXT_ACC_ALL)) 538162306a36Sopenharmony_ci goto error_out; 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci return nbytes; 538462306a36Sopenharmony_cierror_out: 538562306a36Sopenharmony_ci /* Clean out command structure on command error out */ 538662306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 538762306a36Sopenharmony_ci return -EINVAL; 538862306a36Sopenharmony_ci} 538962306a36Sopenharmony_ci 539062306a36Sopenharmony_ci/** 539162306a36Sopenharmony_ci * lpfc_idiag_extacc_read - idiag debugfs read access to extent information 539262306a36Sopenharmony_ci * @file: The file pointer to read from. 539362306a36Sopenharmony_ci * @buf: The buffer to copy the data to. 539462306a36Sopenharmony_ci * @nbytes: The number of bytes to read. 539562306a36Sopenharmony_ci * @ppos: The position in the file to start reading from. 539662306a36Sopenharmony_ci * 539762306a36Sopenharmony_ci * Description: 539862306a36Sopenharmony_ci * This routine reads data from the proper extent information according to 539962306a36Sopenharmony_ci * the idiag command, and copies to user @buf. 540062306a36Sopenharmony_ci * 540162306a36Sopenharmony_ci * Returns: 540262306a36Sopenharmony_ci * This function returns the amount of data that was read (this could be less 540362306a36Sopenharmony_ci * than @nbytes if the end of the file was reached) or a negative error value. 540462306a36Sopenharmony_ci **/ 540562306a36Sopenharmony_cistatic ssize_t 540662306a36Sopenharmony_cilpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, 540762306a36Sopenharmony_ci loff_t *ppos) 540862306a36Sopenharmony_ci{ 540962306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 541062306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 541162306a36Sopenharmony_ci char *pbuffer; 541262306a36Sopenharmony_ci uint32_t ext_map; 541362306a36Sopenharmony_ci int len = 0; 541462306a36Sopenharmony_ci 541562306a36Sopenharmony_ci /* This is a user read operation */ 541662306a36Sopenharmony_ci debug->op = LPFC_IDIAG_OP_RD; 541762306a36Sopenharmony_ci 541862306a36Sopenharmony_ci if (!debug->buffer) 541962306a36Sopenharmony_ci debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL); 542062306a36Sopenharmony_ci if (!debug->buffer) 542162306a36Sopenharmony_ci return 0; 542262306a36Sopenharmony_ci pbuffer = debug->buffer; 542362306a36Sopenharmony_ci if (*ppos) 542462306a36Sopenharmony_ci return 0; 542562306a36Sopenharmony_ci if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) 542662306a36Sopenharmony_ci return 0; 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_ci ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; 542962306a36Sopenharmony_ci if (ext_map & LPFC_EXT_ACC_AVAIL) 543062306a36Sopenharmony_ci len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len); 543162306a36Sopenharmony_ci if (ext_map & LPFC_EXT_ACC_ALLOC) 543262306a36Sopenharmony_ci len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len); 543362306a36Sopenharmony_ci if (ext_map & LPFC_EXT_ACC_DRIVR) 543462306a36Sopenharmony_ci len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len); 543562306a36Sopenharmony_ci 543662306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); 543762306a36Sopenharmony_ci} 543862306a36Sopenharmony_ci 543962306a36Sopenharmony_cistatic int 544062306a36Sopenharmony_cilpfc_cgn_buffer_open(struct inode *inode, struct file *file) 544162306a36Sopenharmony_ci{ 544262306a36Sopenharmony_ci struct lpfc_debug *debug; 544362306a36Sopenharmony_ci int rc = -ENOMEM; 544462306a36Sopenharmony_ci 544562306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 544662306a36Sopenharmony_ci if (!debug) 544762306a36Sopenharmony_ci goto out; 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_ci debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE); 545062306a36Sopenharmony_ci if (!debug->buffer) { 545162306a36Sopenharmony_ci kfree(debug); 545262306a36Sopenharmony_ci goto out; 545362306a36Sopenharmony_ci } 545462306a36Sopenharmony_ci 545562306a36Sopenharmony_ci debug->i_private = inode->i_private; 545662306a36Sopenharmony_ci file->private_data = debug; 545762306a36Sopenharmony_ci 545862306a36Sopenharmony_ci rc = 0; 545962306a36Sopenharmony_ciout: 546062306a36Sopenharmony_ci return rc; 546162306a36Sopenharmony_ci} 546262306a36Sopenharmony_ci 546362306a36Sopenharmony_cistatic ssize_t 546462306a36Sopenharmony_cilpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes, 546562306a36Sopenharmony_ci loff_t *ppos) 546662306a36Sopenharmony_ci{ 546762306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 546862306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 546962306a36Sopenharmony_ci char *buffer = debug->buffer; 547062306a36Sopenharmony_ci uint32_t *ptr; 547162306a36Sopenharmony_ci int cnt, len = 0; 547262306a36Sopenharmony_ci 547362306a36Sopenharmony_ci if (!phba->sli4_hba.pc_sli4_params.mi_ver || !phba->cgn_i) { 547462306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 547562306a36Sopenharmony_ci "Congestion Mgmt is not supported\n"); 547662306a36Sopenharmony_ci goto out; 547762306a36Sopenharmony_ci } 547862306a36Sopenharmony_ci ptr = (uint32_t *)phba->cgn_i->virt; 547962306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 548062306a36Sopenharmony_ci "Congestion Buffer Header\n"); 548162306a36Sopenharmony_ci /* Dump the first 32 bytes */ 548262306a36Sopenharmony_ci cnt = 32; 548362306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 548462306a36Sopenharmony_ci "000: %08x %08x %08x %08x %08x %08x %08x %08x\n", 548562306a36Sopenharmony_ci *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), 548662306a36Sopenharmony_ci *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7)); 548762306a36Sopenharmony_ci ptr += 8; 548862306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 548962306a36Sopenharmony_ci "Congestion Buffer Data\n"); 549062306a36Sopenharmony_ci while (cnt < sizeof(struct lpfc_cgn_info)) { 549162306a36Sopenharmony_ci if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { 549262306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 549362306a36Sopenharmony_ci "Truncated . . .\n"); 549462306a36Sopenharmony_ci goto out; 549562306a36Sopenharmony_ci } 549662306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 549762306a36Sopenharmony_ci "%03x: %08x %08x %08x %08x " 549862306a36Sopenharmony_ci "%08x %08x %08x %08x\n", 549962306a36Sopenharmony_ci cnt, *ptr, *(ptr + 1), *(ptr + 2), 550062306a36Sopenharmony_ci *(ptr + 3), *(ptr + 4), *(ptr + 5), 550162306a36Sopenharmony_ci *(ptr + 6), *(ptr + 7)); 550262306a36Sopenharmony_ci cnt += 32; 550362306a36Sopenharmony_ci ptr += 8; 550462306a36Sopenharmony_ci } 550562306a36Sopenharmony_ci if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { 550662306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 550762306a36Sopenharmony_ci "Truncated . . .\n"); 550862306a36Sopenharmony_ci goto out; 550962306a36Sopenharmony_ci } 551062306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 551162306a36Sopenharmony_ci "Parameter Data\n"); 551262306a36Sopenharmony_ci ptr = (uint32_t *)&phba->cgn_p; 551362306a36Sopenharmony_ci len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, 551462306a36Sopenharmony_ci "%08x %08x %08x %08x\n", 551562306a36Sopenharmony_ci *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3)); 551662306a36Sopenharmony_ciout: 551762306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, buffer, len); 551862306a36Sopenharmony_ci} 551962306a36Sopenharmony_ci 552062306a36Sopenharmony_cistatic int 552162306a36Sopenharmony_cilpfc_cgn_buffer_release(struct inode *inode, struct file *file) 552262306a36Sopenharmony_ci{ 552362306a36Sopenharmony_ci struct lpfc_debug *debug = file->private_data; 552462306a36Sopenharmony_ci 552562306a36Sopenharmony_ci vfree(debug->buffer); 552662306a36Sopenharmony_ci kfree(debug); 552762306a36Sopenharmony_ci 552862306a36Sopenharmony_ci return 0; 552962306a36Sopenharmony_ci} 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_cistatic int 553262306a36Sopenharmony_cilpfc_rx_monitor_open(struct inode *inode, struct file *file) 553362306a36Sopenharmony_ci{ 553462306a36Sopenharmony_ci struct lpfc_rx_monitor_debug *debug; 553562306a36Sopenharmony_ci int rc = -ENOMEM; 553662306a36Sopenharmony_ci 553762306a36Sopenharmony_ci debug = kmalloc(sizeof(*debug), GFP_KERNEL); 553862306a36Sopenharmony_ci if (!debug) 553962306a36Sopenharmony_ci goto out; 554062306a36Sopenharmony_ci 554162306a36Sopenharmony_ci debug->buffer = vmalloc(MAX_DEBUGFS_RX_INFO_SIZE); 554262306a36Sopenharmony_ci if (!debug->buffer) { 554362306a36Sopenharmony_ci kfree(debug); 554462306a36Sopenharmony_ci goto out; 554562306a36Sopenharmony_ci } 554662306a36Sopenharmony_ci 554762306a36Sopenharmony_ci debug->i_private = inode->i_private; 554862306a36Sopenharmony_ci file->private_data = debug; 554962306a36Sopenharmony_ci 555062306a36Sopenharmony_ci rc = 0; 555162306a36Sopenharmony_ciout: 555262306a36Sopenharmony_ci return rc; 555362306a36Sopenharmony_ci} 555462306a36Sopenharmony_ci 555562306a36Sopenharmony_cistatic ssize_t 555662306a36Sopenharmony_cilpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes, 555762306a36Sopenharmony_ci loff_t *ppos) 555862306a36Sopenharmony_ci{ 555962306a36Sopenharmony_ci struct lpfc_rx_monitor_debug *debug = file->private_data; 556062306a36Sopenharmony_ci struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; 556162306a36Sopenharmony_ci char *buffer = debug->buffer; 556262306a36Sopenharmony_ci 556362306a36Sopenharmony_ci if (!phba->rx_monitor) { 556462306a36Sopenharmony_ci scnprintf(buffer, MAX_DEBUGFS_RX_INFO_SIZE, 556562306a36Sopenharmony_ci "Rx Monitor Info is empty.\n"); 556662306a36Sopenharmony_ci } else { 556762306a36Sopenharmony_ci lpfc_rx_monitor_report(phba, phba->rx_monitor, buffer, 556862306a36Sopenharmony_ci MAX_DEBUGFS_RX_INFO_SIZE, 556962306a36Sopenharmony_ci LPFC_MAX_RXMONITOR_ENTRY); 557062306a36Sopenharmony_ci } 557162306a36Sopenharmony_ci 557262306a36Sopenharmony_ci return simple_read_from_buffer(buf, nbytes, ppos, buffer, 557362306a36Sopenharmony_ci strlen(buffer)); 557462306a36Sopenharmony_ci} 557562306a36Sopenharmony_ci 557662306a36Sopenharmony_cistatic int 557762306a36Sopenharmony_cilpfc_rx_monitor_release(struct inode *inode, struct file *file) 557862306a36Sopenharmony_ci{ 557962306a36Sopenharmony_ci struct lpfc_rx_monitor_debug *debug = file->private_data; 558062306a36Sopenharmony_ci 558162306a36Sopenharmony_ci vfree(debug->buffer); 558262306a36Sopenharmony_ci kfree(debug); 558362306a36Sopenharmony_ci 558462306a36Sopenharmony_ci return 0; 558562306a36Sopenharmony_ci} 558662306a36Sopenharmony_ci 558762306a36Sopenharmony_ci#undef lpfc_debugfs_op_disc_trc 558862306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_disc_trc = { 558962306a36Sopenharmony_ci .owner = THIS_MODULE, 559062306a36Sopenharmony_ci .open = lpfc_debugfs_disc_trc_open, 559162306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 559262306a36Sopenharmony_ci .read = lpfc_debugfs_read, 559362306a36Sopenharmony_ci .release = lpfc_debugfs_release, 559462306a36Sopenharmony_ci}; 559562306a36Sopenharmony_ci 559662306a36Sopenharmony_ci#undef lpfc_debugfs_op_nodelist 559762306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_nodelist = { 559862306a36Sopenharmony_ci .owner = THIS_MODULE, 559962306a36Sopenharmony_ci .open = lpfc_debugfs_nodelist_open, 560062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 560162306a36Sopenharmony_ci .read = lpfc_debugfs_read, 560262306a36Sopenharmony_ci .release = lpfc_debugfs_release, 560362306a36Sopenharmony_ci}; 560462306a36Sopenharmony_ci 560562306a36Sopenharmony_ci#undef lpfc_debugfs_op_multixripools 560662306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_multixripools = { 560762306a36Sopenharmony_ci .owner = THIS_MODULE, 560862306a36Sopenharmony_ci .open = lpfc_debugfs_multixripools_open, 560962306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 561062306a36Sopenharmony_ci .read = lpfc_debugfs_read, 561162306a36Sopenharmony_ci .write = lpfc_debugfs_multixripools_write, 561262306a36Sopenharmony_ci .release = lpfc_debugfs_release, 561362306a36Sopenharmony_ci}; 561462306a36Sopenharmony_ci 561562306a36Sopenharmony_ci#undef lpfc_debugfs_op_hbqinfo 561662306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_hbqinfo = { 561762306a36Sopenharmony_ci .owner = THIS_MODULE, 561862306a36Sopenharmony_ci .open = lpfc_debugfs_hbqinfo_open, 561962306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 562062306a36Sopenharmony_ci .read = lpfc_debugfs_read, 562162306a36Sopenharmony_ci .release = lpfc_debugfs_release, 562262306a36Sopenharmony_ci}; 562362306a36Sopenharmony_ci 562462306a36Sopenharmony_ci#ifdef LPFC_HDWQ_LOCK_STAT 562562306a36Sopenharmony_ci#undef lpfc_debugfs_op_lockstat 562662306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_lockstat = { 562762306a36Sopenharmony_ci .owner = THIS_MODULE, 562862306a36Sopenharmony_ci .open = lpfc_debugfs_lockstat_open, 562962306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 563062306a36Sopenharmony_ci .read = lpfc_debugfs_read, 563162306a36Sopenharmony_ci .write = lpfc_debugfs_lockstat_write, 563262306a36Sopenharmony_ci .release = lpfc_debugfs_release, 563362306a36Sopenharmony_ci}; 563462306a36Sopenharmony_ci#endif 563562306a36Sopenharmony_ci 563662306a36Sopenharmony_ci#undef lpfc_debugfs_ras_log 563762306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_ras_log = { 563862306a36Sopenharmony_ci .owner = THIS_MODULE, 563962306a36Sopenharmony_ci .open = lpfc_debugfs_ras_log_open, 564062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 564162306a36Sopenharmony_ci .read = lpfc_debugfs_read, 564262306a36Sopenharmony_ci .release = lpfc_debugfs_ras_log_release, 564362306a36Sopenharmony_ci}; 564462306a36Sopenharmony_ci 564562306a36Sopenharmony_ci#undef lpfc_debugfs_op_dumpHBASlim 564662306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_dumpHBASlim = { 564762306a36Sopenharmony_ci .owner = THIS_MODULE, 564862306a36Sopenharmony_ci .open = lpfc_debugfs_dumpHBASlim_open, 564962306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 565062306a36Sopenharmony_ci .read = lpfc_debugfs_read, 565162306a36Sopenharmony_ci .release = lpfc_debugfs_release, 565262306a36Sopenharmony_ci}; 565362306a36Sopenharmony_ci 565462306a36Sopenharmony_ci#undef lpfc_debugfs_op_dumpHostSlim 565562306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_dumpHostSlim = { 565662306a36Sopenharmony_ci .owner = THIS_MODULE, 565762306a36Sopenharmony_ci .open = lpfc_debugfs_dumpHostSlim_open, 565862306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 565962306a36Sopenharmony_ci .read = lpfc_debugfs_read, 566062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 566162306a36Sopenharmony_ci}; 566262306a36Sopenharmony_ci 566362306a36Sopenharmony_ci#undef lpfc_debugfs_op_nvmestat 566462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_nvmestat = { 566562306a36Sopenharmony_ci .owner = THIS_MODULE, 566662306a36Sopenharmony_ci .open = lpfc_debugfs_nvmestat_open, 566762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 566862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 566962306a36Sopenharmony_ci .write = lpfc_debugfs_nvmestat_write, 567062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 567162306a36Sopenharmony_ci}; 567262306a36Sopenharmony_ci 567362306a36Sopenharmony_ci#undef lpfc_debugfs_op_scsistat 567462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_scsistat = { 567562306a36Sopenharmony_ci .owner = THIS_MODULE, 567662306a36Sopenharmony_ci .open = lpfc_debugfs_scsistat_open, 567762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 567862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 567962306a36Sopenharmony_ci .write = lpfc_debugfs_scsistat_write, 568062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 568162306a36Sopenharmony_ci}; 568262306a36Sopenharmony_ci 568362306a36Sopenharmony_ci#undef lpfc_debugfs_op_ioktime 568462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_ioktime = { 568562306a36Sopenharmony_ci .owner = THIS_MODULE, 568662306a36Sopenharmony_ci .open = lpfc_debugfs_ioktime_open, 568762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 568862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 568962306a36Sopenharmony_ci .write = lpfc_debugfs_ioktime_write, 569062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 569162306a36Sopenharmony_ci}; 569262306a36Sopenharmony_ci 569362306a36Sopenharmony_ci#undef lpfc_debugfs_op_nvmeio_trc 569462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_nvmeio_trc = { 569562306a36Sopenharmony_ci .owner = THIS_MODULE, 569662306a36Sopenharmony_ci .open = lpfc_debugfs_nvmeio_trc_open, 569762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 569862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 569962306a36Sopenharmony_ci .write = lpfc_debugfs_nvmeio_trc_write, 570062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 570162306a36Sopenharmony_ci}; 570262306a36Sopenharmony_ci 570362306a36Sopenharmony_ci#undef lpfc_debugfs_op_hdwqstat 570462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_hdwqstat = { 570562306a36Sopenharmony_ci .owner = THIS_MODULE, 570662306a36Sopenharmony_ci .open = lpfc_debugfs_hdwqstat_open, 570762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 570862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 570962306a36Sopenharmony_ci .write = lpfc_debugfs_hdwqstat_write, 571062306a36Sopenharmony_ci .release = lpfc_debugfs_release, 571162306a36Sopenharmony_ci}; 571262306a36Sopenharmony_ci 571362306a36Sopenharmony_ci#undef lpfc_debugfs_op_dif_err 571462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_dif_err = { 571562306a36Sopenharmony_ci .owner = THIS_MODULE, 571662306a36Sopenharmony_ci .open = simple_open, 571762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 571862306a36Sopenharmony_ci .read = lpfc_debugfs_dif_err_read, 571962306a36Sopenharmony_ci .write = lpfc_debugfs_dif_err_write, 572062306a36Sopenharmony_ci .release = lpfc_debugfs_dif_err_release, 572162306a36Sopenharmony_ci}; 572262306a36Sopenharmony_ci 572362306a36Sopenharmony_ci#undef lpfc_debugfs_op_slow_ring_trc 572462306a36Sopenharmony_cistatic const struct file_operations lpfc_debugfs_op_slow_ring_trc = { 572562306a36Sopenharmony_ci .owner = THIS_MODULE, 572662306a36Sopenharmony_ci .open = lpfc_debugfs_slow_ring_trc_open, 572762306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 572862306a36Sopenharmony_ci .read = lpfc_debugfs_read, 572962306a36Sopenharmony_ci .release = lpfc_debugfs_release, 573062306a36Sopenharmony_ci}; 573162306a36Sopenharmony_ci 573262306a36Sopenharmony_cistatic struct dentry *lpfc_debugfs_root = NULL; 573362306a36Sopenharmony_cistatic atomic_t lpfc_debugfs_hba_count; 573462306a36Sopenharmony_ci 573562306a36Sopenharmony_ci/* 573662306a36Sopenharmony_ci * File operations for the iDiag debugfs 573762306a36Sopenharmony_ci */ 573862306a36Sopenharmony_ci#undef lpfc_idiag_op_pciCfg 573962306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_pciCfg = { 574062306a36Sopenharmony_ci .owner = THIS_MODULE, 574162306a36Sopenharmony_ci .open = lpfc_idiag_open, 574262306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 574362306a36Sopenharmony_ci .read = lpfc_idiag_pcicfg_read, 574462306a36Sopenharmony_ci .write = lpfc_idiag_pcicfg_write, 574562306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 574662306a36Sopenharmony_ci}; 574762306a36Sopenharmony_ci 574862306a36Sopenharmony_ci#undef lpfc_idiag_op_barAcc 574962306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_barAcc = { 575062306a36Sopenharmony_ci .owner = THIS_MODULE, 575162306a36Sopenharmony_ci .open = lpfc_idiag_open, 575262306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 575362306a36Sopenharmony_ci .read = lpfc_idiag_baracc_read, 575462306a36Sopenharmony_ci .write = lpfc_idiag_baracc_write, 575562306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 575662306a36Sopenharmony_ci}; 575762306a36Sopenharmony_ci 575862306a36Sopenharmony_ci#undef lpfc_idiag_op_queInfo 575962306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_queInfo = { 576062306a36Sopenharmony_ci .owner = THIS_MODULE, 576162306a36Sopenharmony_ci .open = lpfc_idiag_open, 576262306a36Sopenharmony_ci .read = lpfc_idiag_queinfo_read, 576362306a36Sopenharmony_ci .release = lpfc_idiag_release, 576462306a36Sopenharmony_ci}; 576562306a36Sopenharmony_ci 576662306a36Sopenharmony_ci#undef lpfc_idiag_op_queAcc 576762306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_queAcc = { 576862306a36Sopenharmony_ci .owner = THIS_MODULE, 576962306a36Sopenharmony_ci .open = lpfc_idiag_open, 577062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 577162306a36Sopenharmony_ci .read = lpfc_idiag_queacc_read, 577262306a36Sopenharmony_ci .write = lpfc_idiag_queacc_write, 577362306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 577462306a36Sopenharmony_ci}; 577562306a36Sopenharmony_ci 577662306a36Sopenharmony_ci#undef lpfc_idiag_op_drbAcc 577762306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_drbAcc = { 577862306a36Sopenharmony_ci .owner = THIS_MODULE, 577962306a36Sopenharmony_ci .open = lpfc_idiag_open, 578062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 578162306a36Sopenharmony_ci .read = lpfc_idiag_drbacc_read, 578262306a36Sopenharmony_ci .write = lpfc_idiag_drbacc_write, 578362306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 578462306a36Sopenharmony_ci}; 578562306a36Sopenharmony_ci 578662306a36Sopenharmony_ci#undef lpfc_idiag_op_ctlAcc 578762306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_ctlAcc = { 578862306a36Sopenharmony_ci .owner = THIS_MODULE, 578962306a36Sopenharmony_ci .open = lpfc_idiag_open, 579062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 579162306a36Sopenharmony_ci .read = lpfc_idiag_ctlacc_read, 579262306a36Sopenharmony_ci .write = lpfc_idiag_ctlacc_write, 579362306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 579462306a36Sopenharmony_ci}; 579562306a36Sopenharmony_ci 579662306a36Sopenharmony_ci#undef lpfc_idiag_op_mbxAcc 579762306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_mbxAcc = { 579862306a36Sopenharmony_ci .owner = THIS_MODULE, 579962306a36Sopenharmony_ci .open = lpfc_idiag_open, 580062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 580162306a36Sopenharmony_ci .read = lpfc_idiag_mbxacc_read, 580262306a36Sopenharmony_ci .write = lpfc_idiag_mbxacc_write, 580362306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 580462306a36Sopenharmony_ci}; 580562306a36Sopenharmony_ci 580662306a36Sopenharmony_ci#undef lpfc_idiag_op_extAcc 580762306a36Sopenharmony_cistatic const struct file_operations lpfc_idiag_op_extAcc = { 580862306a36Sopenharmony_ci .owner = THIS_MODULE, 580962306a36Sopenharmony_ci .open = lpfc_idiag_open, 581062306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 581162306a36Sopenharmony_ci .read = lpfc_idiag_extacc_read, 581262306a36Sopenharmony_ci .write = lpfc_idiag_extacc_write, 581362306a36Sopenharmony_ci .release = lpfc_idiag_cmd_release, 581462306a36Sopenharmony_ci}; 581562306a36Sopenharmony_ci#undef lpfc_cgn_buffer_op 581662306a36Sopenharmony_cistatic const struct file_operations lpfc_cgn_buffer_op = { 581762306a36Sopenharmony_ci .owner = THIS_MODULE, 581862306a36Sopenharmony_ci .open = lpfc_cgn_buffer_open, 581962306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 582062306a36Sopenharmony_ci .read = lpfc_cgn_buffer_read, 582162306a36Sopenharmony_ci .release = lpfc_cgn_buffer_release, 582262306a36Sopenharmony_ci}; 582362306a36Sopenharmony_ci 582462306a36Sopenharmony_ci#undef lpfc_rx_monitor_op 582562306a36Sopenharmony_cistatic const struct file_operations lpfc_rx_monitor_op = { 582662306a36Sopenharmony_ci .owner = THIS_MODULE, 582762306a36Sopenharmony_ci .open = lpfc_rx_monitor_open, 582862306a36Sopenharmony_ci .llseek = lpfc_debugfs_lseek, 582962306a36Sopenharmony_ci .read = lpfc_rx_monitor_read, 583062306a36Sopenharmony_ci .release = lpfc_rx_monitor_release, 583162306a36Sopenharmony_ci}; 583262306a36Sopenharmony_ci#endif 583362306a36Sopenharmony_ci 583462306a36Sopenharmony_ci/* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command 583562306a36Sopenharmony_ci * @phba: Pointer to HBA context object. 583662306a36Sopenharmony_ci * @dmabuf: Pointer to a DMA buffer descriptor. 583762306a36Sopenharmony_ci * 583862306a36Sopenharmony_ci * Description: 583962306a36Sopenharmony_ci * This routine dump a bsg pass-through non-embedded mailbox command with 584062306a36Sopenharmony_ci * external buffer. 584162306a36Sopenharmony_ci **/ 584262306a36Sopenharmony_civoid 584362306a36Sopenharmony_cilpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, 584462306a36Sopenharmony_ci enum mbox_type mbox_tp, enum dma_type dma_tp, 584562306a36Sopenharmony_ci enum sta_type sta_tp, 584662306a36Sopenharmony_ci struct lpfc_dmabuf *dmabuf, uint32_t ext_buf) 584762306a36Sopenharmony_ci{ 584862306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 584962306a36Sopenharmony_ci uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt; 585062306a36Sopenharmony_ci char line_buf[LPFC_MBX_ACC_LBUF_SZ]; 585162306a36Sopenharmony_ci int len = 0; 585262306a36Sopenharmony_ci uint32_t do_dump = 0; 585362306a36Sopenharmony_ci uint32_t *pword; 585462306a36Sopenharmony_ci uint32_t i; 585562306a36Sopenharmony_ci 585662306a36Sopenharmony_ci if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP) 585762306a36Sopenharmony_ci return; 585862306a36Sopenharmony_ci 585962306a36Sopenharmony_ci mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; 586062306a36Sopenharmony_ci mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; 586162306a36Sopenharmony_ci mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; 586262306a36Sopenharmony_ci mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; 586362306a36Sopenharmony_ci 586462306a36Sopenharmony_ci if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) || 586562306a36Sopenharmony_ci (*mbx_dump_cnt == 0) || 586662306a36Sopenharmony_ci (*mbx_word_cnt == 0)) 586762306a36Sopenharmony_ci return; 586862306a36Sopenharmony_ci 586962306a36Sopenharmony_ci if (*mbx_mbox_cmd != 0x9B) 587062306a36Sopenharmony_ci return; 587162306a36Sopenharmony_ci 587262306a36Sopenharmony_ci if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) { 587362306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) { 587462306a36Sopenharmony_ci do_dump |= LPFC_BSG_DMP_MBX_RD_MBX; 587562306a36Sopenharmony_ci pr_err("\nRead mbox command (x%x), " 587662306a36Sopenharmony_ci "nemb:0x%x, extbuf_cnt:%d:\n", 587762306a36Sopenharmony_ci sta_tp, nemb_tp, ext_buf); 587862306a36Sopenharmony_ci } 587962306a36Sopenharmony_ci } 588062306a36Sopenharmony_ci if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) { 588162306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) { 588262306a36Sopenharmony_ci do_dump |= LPFC_BSG_DMP_MBX_RD_BUF; 588362306a36Sopenharmony_ci pr_err("\nRead mbox buffer (x%x), " 588462306a36Sopenharmony_ci "nemb:0x%x, extbuf_seq:%d:\n", 588562306a36Sopenharmony_ci sta_tp, nemb_tp, ext_buf); 588662306a36Sopenharmony_ci } 588762306a36Sopenharmony_ci } 588862306a36Sopenharmony_ci if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) { 588962306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) { 589062306a36Sopenharmony_ci do_dump |= LPFC_BSG_DMP_MBX_WR_MBX; 589162306a36Sopenharmony_ci pr_err("\nWrite mbox command (x%x), " 589262306a36Sopenharmony_ci "nemb:0x%x, extbuf_cnt:%d:\n", 589362306a36Sopenharmony_ci sta_tp, nemb_tp, ext_buf); 589462306a36Sopenharmony_ci } 589562306a36Sopenharmony_ci } 589662306a36Sopenharmony_ci if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) { 589762306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) { 589862306a36Sopenharmony_ci do_dump |= LPFC_BSG_DMP_MBX_WR_BUF; 589962306a36Sopenharmony_ci pr_err("\nWrite mbox buffer (x%x), " 590062306a36Sopenharmony_ci "nemb:0x%x, extbuf_seq:%d:\n", 590162306a36Sopenharmony_ci sta_tp, nemb_tp, ext_buf); 590262306a36Sopenharmony_ci } 590362306a36Sopenharmony_ci } 590462306a36Sopenharmony_ci 590562306a36Sopenharmony_ci /* dump buffer content */ 590662306a36Sopenharmony_ci if (do_dump) { 590762306a36Sopenharmony_ci pword = (uint32_t *)dmabuf->virt; 590862306a36Sopenharmony_ci for (i = 0; i < *mbx_word_cnt; i++) { 590962306a36Sopenharmony_ci if (!(i % 8)) { 591062306a36Sopenharmony_ci if (i != 0) 591162306a36Sopenharmony_ci pr_err("%s\n", line_buf); 591262306a36Sopenharmony_ci len = 0; 591362306a36Sopenharmony_ci len += scnprintf(line_buf+len, 591462306a36Sopenharmony_ci LPFC_MBX_ACC_LBUF_SZ-len, 591562306a36Sopenharmony_ci "%03d: ", i); 591662306a36Sopenharmony_ci } 591762306a36Sopenharmony_ci len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, 591862306a36Sopenharmony_ci "%08x ", (uint32_t)*pword); 591962306a36Sopenharmony_ci pword++; 592062306a36Sopenharmony_ci } 592162306a36Sopenharmony_ci if ((i - 1) % 8) 592262306a36Sopenharmony_ci pr_err("%s\n", line_buf); 592362306a36Sopenharmony_ci (*mbx_dump_cnt)--; 592462306a36Sopenharmony_ci } 592562306a36Sopenharmony_ci 592662306a36Sopenharmony_ci /* Clean out command structure on reaching dump count */ 592762306a36Sopenharmony_ci if (*mbx_dump_cnt == 0) 592862306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 592962306a36Sopenharmony_ci return; 593062306a36Sopenharmony_ci#endif 593162306a36Sopenharmony_ci} 593262306a36Sopenharmony_ci 593362306a36Sopenharmony_ci/* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command 593462306a36Sopenharmony_ci * @phba: Pointer to HBA context object. 593562306a36Sopenharmony_ci * @dmabuf: Pointer to a DMA buffer descriptor. 593662306a36Sopenharmony_ci * 593762306a36Sopenharmony_ci * Description: 593862306a36Sopenharmony_ci * This routine dump a pass-through non-embedded mailbox command from issue 593962306a36Sopenharmony_ci * mailbox command. 594062306a36Sopenharmony_ci **/ 594162306a36Sopenharmony_civoid 594262306a36Sopenharmony_cilpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) 594362306a36Sopenharmony_ci{ 594462306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 594562306a36Sopenharmony_ci uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd; 594662306a36Sopenharmony_ci char line_buf[LPFC_MBX_ACC_LBUF_SZ]; 594762306a36Sopenharmony_ci int len = 0; 594862306a36Sopenharmony_ci uint32_t *pword; 594962306a36Sopenharmony_ci uint8_t *pbyte; 595062306a36Sopenharmony_ci uint32_t i, j; 595162306a36Sopenharmony_ci 595262306a36Sopenharmony_ci if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) 595362306a36Sopenharmony_ci return; 595462306a36Sopenharmony_ci 595562306a36Sopenharmony_ci mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; 595662306a36Sopenharmony_ci mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; 595762306a36Sopenharmony_ci mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; 595862306a36Sopenharmony_ci mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; 595962306a36Sopenharmony_ci 596062306a36Sopenharmony_ci if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) || 596162306a36Sopenharmony_ci (*mbx_dump_cnt == 0) || 596262306a36Sopenharmony_ci (*mbx_word_cnt == 0)) 596362306a36Sopenharmony_ci return; 596462306a36Sopenharmony_ci 596562306a36Sopenharmony_ci if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) && 596662306a36Sopenharmony_ci (*mbx_mbox_cmd != pmbox->mbxCommand)) 596762306a36Sopenharmony_ci return; 596862306a36Sopenharmony_ci 596962306a36Sopenharmony_ci /* dump buffer content */ 597062306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) { 597162306a36Sopenharmony_ci pr_err("Mailbox command:0x%x dump by word:\n", 597262306a36Sopenharmony_ci pmbox->mbxCommand); 597362306a36Sopenharmony_ci pword = (uint32_t *)pmbox; 597462306a36Sopenharmony_ci for (i = 0; i < *mbx_word_cnt; i++) { 597562306a36Sopenharmony_ci if (!(i % 8)) { 597662306a36Sopenharmony_ci if (i != 0) 597762306a36Sopenharmony_ci pr_err("%s\n", line_buf); 597862306a36Sopenharmony_ci len = 0; 597962306a36Sopenharmony_ci memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); 598062306a36Sopenharmony_ci len += scnprintf(line_buf+len, 598162306a36Sopenharmony_ci LPFC_MBX_ACC_LBUF_SZ-len, 598262306a36Sopenharmony_ci "%03d: ", i); 598362306a36Sopenharmony_ci } 598462306a36Sopenharmony_ci len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, 598562306a36Sopenharmony_ci "%08x ", 598662306a36Sopenharmony_ci ((uint32_t)*pword) & 0xffffffff); 598762306a36Sopenharmony_ci pword++; 598862306a36Sopenharmony_ci } 598962306a36Sopenharmony_ci if ((i - 1) % 8) 599062306a36Sopenharmony_ci pr_err("%s\n", line_buf); 599162306a36Sopenharmony_ci pr_err("\n"); 599262306a36Sopenharmony_ci } 599362306a36Sopenharmony_ci if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) { 599462306a36Sopenharmony_ci pr_err("Mailbox command:0x%x dump by byte:\n", 599562306a36Sopenharmony_ci pmbox->mbxCommand); 599662306a36Sopenharmony_ci pbyte = (uint8_t *)pmbox; 599762306a36Sopenharmony_ci for (i = 0; i < *mbx_word_cnt; i++) { 599862306a36Sopenharmony_ci if (!(i % 8)) { 599962306a36Sopenharmony_ci if (i != 0) 600062306a36Sopenharmony_ci pr_err("%s\n", line_buf); 600162306a36Sopenharmony_ci len = 0; 600262306a36Sopenharmony_ci memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); 600362306a36Sopenharmony_ci len += scnprintf(line_buf+len, 600462306a36Sopenharmony_ci LPFC_MBX_ACC_LBUF_SZ-len, 600562306a36Sopenharmony_ci "%03d: ", i); 600662306a36Sopenharmony_ci } 600762306a36Sopenharmony_ci for (j = 0; j < 4; j++) { 600862306a36Sopenharmony_ci len += scnprintf(line_buf+len, 600962306a36Sopenharmony_ci LPFC_MBX_ACC_LBUF_SZ-len, 601062306a36Sopenharmony_ci "%02x", 601162306a36Sopenharmony_ci ((uint8_t)*pbyte) & 0xff); 601262306a36Sopenharmony_ci pbyte++; 601362306a36Sopenharmony_ci } 601462306a36Sopenharmony_ci len += scnprintf(line_buf+len, 601562306a36Sopenharmony_ci LPFC_MBX_ACC_LBUF_SZ-len, " "); 601662306a36Sopenharmony_ci } 601762306a36Sopenharmony_ci if ((i - 1) % 8) 601862306a36Sopenharmony_ci pr_err("%s\n", line_buf); 601962306a36Sopenharmony_ci pr_err("\n"); 602062306a36Sopenharmony_ci } 602162306a36Sopenharmony_ci (*mbx_dump_cnt)--; 602262306a36Sopenharmony_ci 602362306a36Sopenharmony_ci /* Clean out command structure on reaching dump count */ 602462306a36Sopenharmony_ci if (*mbx_dump_cnt == 0) 602562306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 602662306a36Sopenharmony_ci return; 602762306a36Sopenharmony_ci#endif 602862306a36Sopenharmony_ci} 602962306a36Sopenharmony_ci 603062306a36Sopenharmony_ci/** 603162306a36Sopenharmony_ci * lpfc_debugfs_initialize - Initialize debugfs for a vport 603262306a36Sopenharmony_ci * @vport: The vport pointer to initialize. 603362306a36Sopenharmony_ci * 603462306a36Sopenharmony_ci * Description: 603562306a36Sopenharmony_ci * When Debugfs is configured this routine sets up the lpfc debugfs file system. 603662306a36Sopenharmony_ci * If not already created, this routine will create the lpfc directory, and 603762306a36Sopenharmony_ci * lpfcX directory (for this HBA), and vportX directory for this vport. It will 603862306a36Sopenharmony_ci * also create each file used to access lpfc specific debugfs information. 603962306a36Sopenharmony_ci **/ 604062306a36Sopenharmony_ciinline void 604162306a36Sopenharmony_cilpfc_debugfs_initialize(struct lpfc_vport *vport) 604262306a36Sopenharmony_ci{ 604362306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 604462306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 604562306a36Sopenharmony_ci char name[64]; 604662306a36Sopenharmony_ci uint32_t num, i; 604762306a36Sopenharmony_ci bool pport_setup = false; 604862306a36Sopenharmony_ci 604962306a36Sopenharmony_ci if (!lpfc_debugfs_enable) 605062306a36Sopenharmony_ci return; 605162306a36Sopenharmony_ci 605262306a36Sopenharmony_ci /* Setup lpfc root directory */ 605362306a36Sopenharmony_ci if (!lpfc_debugfs_root) { 605462306a36Sopenharmony_ci lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL); 605562306a36Sopenharmony_ci atomic_set(&lpfc_debugfs_hba_count, 0); 605662306a36Sopenharmony_ci } 605762306a36Sopenharmony_ci if (!lpfc_debugfs_start_time) 605862306a36Sopenharmony_ci lpfc_debugfs_start_time = jiffies; 605962306a36Sopenharmony_ci 606062306a36Sopenharmony_ci /* Setup funcX directory for specific HBA PCI function */ 606162306a36Sopenharmony_ci snprintf(name, sizeof(name), "fn%d", phba->brd_no); 606262306a36Sopenharmony_ci if (!phba->hba_debugfs_root) { 606362306a36Sopenharmony_ci pport_setup = true; 606462306a36Sopenharmony_ci phba->hba_debugfs_root = 606562306a36Sopenharmony_ci debugfs_create_dir(name, lpfc_debugfs_root); 606662306a36Sopenharmony_ci atomic_inc(&lpfc_debugfs_hba_count); 606762306a36Sopenharmony_ci atomic_set(&phba->debugfs_vport_count, 0); 606862306a36Sopenharmony_ci 606962306a36Sopenharmony_ci /* Multi-XRI pools */ 607062306a36Sopenharmony_ci snprintf(name, sizeof(name), "multixripools"); 607162306a36Sopenharmony_ci phba->debug_multixri_pools = 607262306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG | 0644, 607362306a36Sopenharmony_ci phba->hba_debugfs_root, 607462306a36Sopenharmony_ci phba, 607562306a36Sopenharmony_ci &lpfc_debugfs_op_multixripools); 607662306a36Sopenharmony_ci if (IS_ERR(phba->debug_multixri_pools)) { 607762306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 607862306a36Sopenharmony_ci "0527 Cannot create debugfs multixripools\n"); 607962306a36Sopenharmony_ci goto debug_failed; 608062306a36Sopenharmony_ci } 608162306a36Sopenharmony_ci 608262306a36Sopenharmony_ci /* Congestion Info Buffer */ 608362306a36Sopenharmony_ci scnprintf(name, sizeof(name), "cgn_buffer"); 608462306a36Sopenharmony_ci phba->debug_cgn_buffer = 608562306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG | 0644, 608662306a36Sopenharmony_ci phba->hba_debugfs_root, 608762306a36Sopenharmony_ci phba, &lpfc_cgn_buffer_op); 608862306a36Sopenharmony_ci if (IS_ERR(phba->debug_cgn_buffer)) { 608962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 609062306a36Sopenharmony_ci "6527 Cannot create debugfs " 609162306a36Sopenharmony_ci "cgn_buffer\n"); 609262306a36Sopenharmony_ci goto debug_failed; 609362306a36Sopenharmony_ci } 609462306a36Sopenharmony_ci 609562306a36Sopenharmony_ci /* RX Monitor */ 609662306a36Sopenharmony_ci scnprintf(name, sizeof(name), "rx_monitor"); 609762306a36Sopenharmony_ci phba->debug_rx_monitor = 609862306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG | 0644, 609962306a36Sopenharmony_ci phba->hba_debugfs_root, 610062306a36Sopenharmony_ci phba, &lpfc_rx_monitor_op); 610162306a36Sopenharmony_ci if (IS_ERR(phba->debug_rx_monitor)) { 610262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 610362306a36Sopenharmony_ci "6528 Cannot create debugfs " 610462306a36Sopenharmony_ci "rx_monitor\n"); 610562306a36Sopenharmony_ci goto debug_failed; 610662306a36Sopenharmony_ci } 610762306a36Sopenharmony_ci 610862306a36Sopenharmony_ci /* RAS log */ 610962306a36Sopenharmony_ci snprintf(name, sizeof(name), "ras_log"); 611062306a36Sopenharmony_ci phba->debug_ras_log = 611162306a36Sopenharmony_ci debugfs_create_file(name, 0644, 611262306a36Sopenharmony_ci phba->hba_debugfs_root, 611362306a36Sopenharmony_ci phba, &lpfc_debugfs_ras_log); 611462306a36Sopenharmony_ci if (IS_ERR(phba->debug_ras_log)) { 611562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 611662306a36Sopenharmony_ci "6148 Cannot create debugfs" 611762306a36Sopenharmony_ci " ras_log\n"); 611862306a36Sopenharmony_ci goto debug_failed; 611962306a36Sopenharmony_ci } 612062306a36Sopenharmony_ci 612162306a36Sopenharmony_ci /* Setup hbqinfo */ 612262306a36Sopenharmony_ci snprintf(name, sizeof(name), "hbqinfo"); 612362306a36Sopenharmony_ci phba->debug_hbqinfo = 612462306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG | 0644, 612562306a36Sopenharmony_ci phba->hba_debugfs_root, 612662306a36Sopenharmony_ci phba, &lpfc_debugfs_op_hbqinfo); 612762306a36Sopenharmony_ci 612862306a36Sopenharmony_ci#ifdef LPFC_HDWQ_LOCK_STAT 612962306a36Sopenharmony_ci /* Setup lockstat */ 613062306a36Sopenharmony_ci snprintf(name, sizeof(name), "lockstat"); 613162306a36Sopenharmony_ci phba->debug_lockstat = 613262306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG | 0644, 613362306a36Sopenharmony_ci phba->hba_debugfs_root, 613462306a36Sopenharmony_ci phba, &lpfc_debugfs_op_lockstat); 613562306a36Sopenharmony_ci if (IS_ERR(phba->debug_lockstat)) { 613662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 613762306a36Sopenharmony_ci "4610 Can't create debugfs lockstat\n"); 613862306a36Sopenharmony_ci goto debug_failed; 613962306a36Sopenharmony_ci } 614062306a36Sopenharmony_ci#endif 614162306a36Sopenharmony_ci 614262306a36Sopenharmony_ci /* Setup dumpHBASlim */ 614362306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) { 614462306a36Sopenharmony_ci snprintf(name, sizeof(name), "dumpHBASlim"); 614562306a36Sopenharmony_ci phba->debug_dumpHBASlim = 614662306a36Sopenharmony_ci debugfs_create_file(name, 614762306a36Sopenharmony_ci S_IFREG|S_IRUGO|S_IWUSR, 614862306a36Sopenharmony_ci phba->hba_debugfs_root, 614962306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dumpHBASlim); 615062306a36Sopenharmony_ci } else 615162306a36Sopenharmony_ci phba->debug_dumpHBASlim = NULL; 615262306a36Sopenharmony_ci 615362306a36Sopenharmony_ci /* Setup dumpHostSlim */ 615462306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) { 615562306a36Sopenharmony_ci snprintf(name, sizeof(name), "dumpHostSlim"); 615662306a36Sopenharmony_ci phba->debug_dumpHostSlim = 615762306a36Sopenharmony_ci debugfs_create_file(name, 615862306a36Sopenharmony_ci S_IFREG|S_IRUGO|S_IWUSR, 615962306a36Sopenharmony_ci phba->hba_debugfs_root, 616062306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dumpHostSlim); 616162306a36Sopenharmony_ci } else 616262306a36Sopenharmony_ci phba->debug_dumpHostSlim = NULL; 616362306a36Sopenharmony_ci 616462306a36Sopenharmony_ci /* Setup DIF Error Injections */ 616562306a36Sopenharmony_ci snprintf(name, sizeof(name), "InjErrLBA"); 616662306a36Sopenharmony_ci phba->debug_InjErrLBA = 616762306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 616862306a36Sopenharmony_ci phba->hba_debugfs_root, 616962306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 617062306a36Sopenharmony_ci phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; 617162306a36Sopenharmony_ci 617262306a36Sopenharmony_ci snprintf(name, sizeof(name), "InjErrNPortID"); 617362306a36Sopenharmony_ci phba->debug_InjErrNPortID = 617462306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 617562306a36Sopenharmony_ci phba->hba_debugfs_root, 617662306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 617762306a36Sopenharmony_ci 617862306a36Sopenharmony_ci snprintf(name, sizeof(name), "InjErrWWPN"); 617962306a36Sopenharmony_ci phba->debug_InjErrWWPN = 618062306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 618162306a36Sopenharmony_ci phba->hba_debugfs_root, 618262306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 618362306a36Sopenharmony_ci 618462306a36Sopenharmony_ci snprintf(name, sizeof(name), "writeGuardInjErr"); 618562306a36Sopenharmony_ci phba->debug_writeGuard = 618662306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 618762306a36Sopenharmony_ci phba->hba_debugfs_root, 618862306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 618962306a36Sopenharmony_ci 619062306a36Sopenharmony_ci snprintf(name, sizeof(name), "writeAppInjErr"); 619162306a36Sopenharmony_ci phba->debug_writeApp = 619262306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 619362306a36Sopenharmony_ci phba->hba_debugfs_root, 619462306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 619562306a36Sopenharmony_ci 619662306a36Sopenharmony_ci snprintf(name, sizeof(name), "writeRefInjErr"); 619762306a36Sopenharmony_ci phba->debug_writeRef = 619862306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 619962306a36Sopenharmony_ci phba->hba_debugfs_root, 620062306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 620162306a36Sopenharmony_ci 620262306a36Sopenharmony_ci snprintf(name, sizeof(name), "readGuardInjErr"); 620362306a36Sopenharmony_ci phba->debug_readGuard = 620462306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 620562306a36Sopenharmony_ci phba->hba_debugfs_root, 620662306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 620762306a36Sopenharmony_ci 620862306a36Sopenharmony_ci snprintf(name, sizeof(name), "readAppInjErr"); 620962306a36Sopenharmony_ci phba->debug_readApp = 621062306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 621162306a36Sopenharmony_ci phba->hba_debugfs_root, 621262306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 621362306a36Sopenharmony_ci 621462306a36Sopenharmony_ci snprintf(name, sizeof(name), "readRefInjErr"); 621562306a36Sopenharmony_ci phba->debug_readRef = 621662306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 621762306a36Sopenharmony_ci phba->hba_debugfs_root, 621862306a36Sopenharmony_ci phba, &lpfc_debugfs_op_dif_err); 621962306a36Sopenharmony_ci 622062306a36Sopenharmony_ci /* Setup slow ring trace */ 622162306a36Sopenharmony_ci if (lpfc_debugfs_max_slow_ring_trc) { 622262306a36Sopenharmony_ci num = lpfc_debugfs_max_slow_ring_trc - 1; 622362306a36Sopenharmony_ci if (num & lpfc_debugfs_max_slow_ring_trc) { 622462306a36Sopenharmony_ci /* Change to be a power of 2 */ 622562306a36Sopenharmony_ci num = lpfc_debugfs_max_slow_ring_trc; 622662306a36Sopenharmony_ci i = 0; 622762306a36Sopenharmony_ci while (num > 1) { 622862306a36Sopenharmony_ci num = num >> 1; 622962306a36Sopenharmony_ci i++; 623062306a36Sopenharmony_ci } 623162306a36Sopenharmony_ci lpfc_debugfs_max_slow_ring_trc = (1 << i); 623262306a36Sopenharmony_ci pr_err("lpfc_debugfs_max_disc_trc changed to " 623362306a36Sopenharmony_ci "%d\n", lpfc_debugfs_max_disc_trc); 623462306a36Sopenharmony_ci } 623562306a36Sopenharmony_ci } 623662306a36Sopenharmony_ci 623762306a36Sopenharmony_ci snprintf(name, sizeof(name), "slow_ring_trace"); 623862306a36Sopenharmony_ci phba->debug_slow_ring_trc = 623962306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 624062306a36Sopenharmony_ci phba->hba_debugfs_root, 624162306a36Sopenharmony_ci phba, &lpfc_debugfs_op_slow_ring_trc); 624262306a36Sopenharmony_ci if (!phba->slow_ring_trc) { 624362306a36Sopenharmony_ci phba->slow_ring_trc = kcalloc( 624462306a36Sopenharmony_ci lpfc_debugfs_max_slow_ring_trc, 624562306a36Sopenharmony_ci sizeof(struct lpfc_debugfs_trc), 624662306a36Sopenharmony_ci GFP_KERNEL); 624762306a36Sopenharmony_ci if (!phba->slow_ring_trc) { 624862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 624962306a36Sopenharmony_ci "0416 Cannot create debugfs " 625062306a36Sopenharmony_ci "slow_ring buffer\n"); 625162306a36Sopenharmony_ci goto debug_failed; 625262306a36Sopenharmony_ci } 625362306a36Sopenharmony_ci atomic_set(&phba->slow_ring_trc_cnt, 0); 625462306a36Sopenharmony_ci } 625562306a36Sopenharmony_ci 625662306a36Sopenharmony_ci snprintf(name, sizeof(name), "nvmeio_trc"); 625762306a36Sopenharmony_ci phba->debug_nvmeio_trc = 625862306a36Sopenharmony_ci debugfs_create_file(name, 0644, 625962306a36Sopenharmony_ci phba->hba_debugfs_root, 626062306a36Sopenharmony_ci phba, &lpfc_debugfs_op_nvmeio_trc); 626162306a36Sopenharmony_ci 626262306a36Sopenharmony_ci atomic_set(&phba->nvmeio_trc_cnt, 0); 626362306a36Sopenharmony_ci if (lpfc_debugfs_max_nvmeio_trc) { 626462306a36Sopenharmony_ci num = lpfc_debugfs_max_nvmeio_trc - 1; 626562306a36Sopenharmony_ci if (num & lpfc_debugfs_max_disc_trc) { 626662306a36Sopenharmony_ci /* Change to be a power of 2 */ 626762306a36Sopenharmony_ci num = lpfc_debugfs_max_nvmeio_trc; 626862306a36Sopenharmony_ci i = 0; 626962306a36Sopenharmony_ci while (num > 1) { 627062306a36Sopenharmony_ci num = num >> 1; 627162306a36Sopenharmony_ci i++; 627262306a36Sopenharmony_ci } 627362306a36Sopenharmony_ci lpfc_debugfs_max_nvmeio_trc = (1 << i); 627462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 627562306a36Sopenharmony_ci "0575 lpfc_debugfs_max_nvmeio_trc " 627662306a36Sopenharmony_ci "changed to %d\n", 627762306a36Sopenharmony_ci lpfc_debugfs_max_nvmeio_trc); 627862306a36Sopenharmony_ci } 627962306a36Sopenharmony_ci phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc; 628062306a36Sopenharmony_ci 628162306a36Sopenharmony_ci /* Allocate trace buffer and initialize */ 628262306a36Sopenharmony_ci phba->nvmeio_trc = kzalloc( 628362306a36Sopenharmony_ci (sizeof(struct lpfc_debugfs_nvmeio_trc) * 628462306a36Sopenharmony_ci phba->nvmeio_trc_size), GFP_KERNEL); 628562306a36Sopenharmony_ci 628662306a36Sopenharmony_ci if (!phba->nvmeio_trc) { 628762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 628862306a36Sopenharmony_ci "0576 Cannot create debugfs " 628962306a36Sopenharmony_ci "nvmeio_trc buffer\n"); 629062306a36Sopenharmony_ci goto nvmeio_off; 629162306a36Sopenharmony_ci } 629262306a36Sopenharmony_ci phba->nvmeio_trc_on = 1; 629362306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 629462306a36Sopenharmony_ci phba->nvmeio_trc = NULL; 629562306a36Sopenharmony_ci } else { 629662306a36Sopenharmony_cinvmeio_off: 629762306a36Sopenharmony_ci phba->nvmeio_trc_size = 0; 629862306a36Sopenharmony_ci phba->nvmeio_trc_on = 0; 629962306a36Sopenharmony_ci phba->nvmeio_trc_output_idx = 0; 630062306a36Sopenharmony_ci phba->nvmeio_trc = NULL; 630162306a36Sopenharmony_ci } 630262306a36Sopenharmony_ci } 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci snprintf(name, sizeof(name), "vport%d", vport->vpi); 630562306a36Sopenharmony_ci if (!vport->vport_debugfs_root) { 630662306a36Sopenharmony_ci vport->vport_debugfs_root = 630762306a36Sopenharmony_ci debugfs_create_dir(name, phba->hba_debugfs_root); 630862306a36Sopenharmony_ci atomic_inc(&phba->debugfs_vport_count); 630962306a36Sopenharmony_ci } 631062306a36Sopenharmony_ci 631162306a36Sopenharmony_ci if (lpfc_debugfs_max_disc_trc) { 631262306a36Sopenharmony_ci num = lpfc_debugfs_max_disc_trc - 1; 631362306a36Sopenharmony_ci if (num & lpfc_debugfs_max_disc_trc) { 631462306a36Sopenharmony_ci /* Change to be a power of 2 */ 631562306a36Sopenharmony_ci num = lpfc_debugfs_max_disc_trc; 631662306a36Sopenharmony_ci i = 0; 631762306a36Sopenharmony_ci while (num > 1) { 631862306a36Sopenharmony_ci num = num >> 1; 631962306a36Sopenharmony_ci i++; 632062306a36Sopenharmony_ci } 632162306a36Sopenharmony_ci lpfc_debugfs_max_disc_trc = (1 << i); 632262306a36Sopenharmony_ci pr_err("lpfc_debugfs_max_disc_trc changed to %d\n", 632362306a36Sopenharmony_ci lpfc_debugfs_max_disc_trc); 632462306a36Sopenharmony_ci } 632562306a36Sopenharmony_ci } 632662306a36Sopenharmony_ci 632762306a36Sopenharmony_ci vport->disc_trc = kzalloc( 632862306a36Sopenharmony_ci (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc), 632962306a36Sopenharmony_ci GFP_KERNEL); 633062306a36Sopenharmony_ci 633162306a36Sopenharmony_ci if (!vport->disc_trc) { 633262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 633362306a36Sopenharmony_ci "0418 Cannot create debugfs disc trace " 633462306a36Sopenharmony_ci "buffer\n"); 633562306a36Sopenharmony_ci goto debug_failed; 633662306a36Sopenharmony_ci } 633762306a36Sopenharmony_ci atomic_set(&vport->disc_trc_cnt, 0); 633862306a36Sopenharmony_ci 633962306a36Sopenharmony_ci snprintf(name, sizeof(name), "discovery_trace"); 634062306a36Sopenharmony_ci vport->debug_disc_trc = 634162306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 634262306a36Sopenharmony_ci vport->vport_debugfs_root, 634362306a36Sopenharmony_ci vport, &lpfc_debugfs_op_disc_trc); 634462306a36Sopenharmony_ci snprintf(name, sizeof(name), "nodelist"); 634562306a36Sopenharmony_ci vport->debug_nodelist = 634662306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 634762306a36Sopenharmony_ci vport->vport_debugfs_root, 634862306a36Sopenharmony_ci vport, &lpfc_debugfs_op_nodelist); 634962306a36Sopenharmony_ci 635062306a36Sopenharmony_ci snprintf(name, sizeof(name), "nvmestat"); 635162306a36Sopenharmony_ci vport->debug_nvmestat = 635262306a36Sopenharmony_ci debugfs_create_file(name, 0644, 635362306a36Sopenharmony_ci vport->vport_debugfs_root, 635462306a36Sopenharmony_ci vport, &lpfc_debugfs_op_nvmestat); 635562306a36Sopenharmony_ci 635662306a36Sopenharmony_ci snprintf(name, sizeof(name), "scsistat"); 635762306a36Sopenharmony_ci vport->debug_scsistat = 635862306a36Sopenharmony_ci debugfs_create_file(name, 0644, 635962306a36Sopenharmony_ci vport->vport_debugfs_root, 636062306a36Sopenharmony_ci vport, &lpfc_debugfs_op_scsistat); 636162306a36Sopenharmony_ci if (IS_ERR(vport->debug_scsistat)) { 636262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 636362306a36Sopenharmony_ci "4611 Cannot create debugfs scsistat\n"); 636462306a36Sopenharmony_ci goto debug_failed; 636562306a36Sopenharmony_ci } 636662306a36Sopenharmony_ci 636762306a36Sopenharmony_ci snprintf(name, sizeof(name), "ioktime"); 636862306a36Sopenharmony_ci vport->debug_ioktime = 636962306a36Sopenharmony_ci debugfs_create_file(name, 0644, 637062306a36Sopenharmony_ci vport->vport_debugfs_root, 637162306a36Sopenharmony_ci vport, &lpfc_debugfs_op_ioktime); 637262306a36Sopenharmony_ci if (IS_ERR(vport->debug_ioktime)) { 637362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, 637462306a36Sopenharmony_ci "0815 Cannot create debugfs ioktime\n"); 637562306a36Sopenharmony_ci goto debug_failed; 637662306a36Sopenharmony_ci } 637762306a36Sopenharmony_ci 637862306a36Sopenharmony_ci snprintf(name, sizeof(name), "hdwqstat"); 637962306a36Sopenharmony_ci vport->debug_hdwqstat = 638062306a36Sopenharmony_ci debugfs_create_file(name, 0644, 638162306a36Sopenharmony_ci vport->vport_debugfs_root, 638262306a36Sopenharmony_ci vport, &lpfc_debugfs_op_hdwqstat); 638362306a36Sopenharmony_ci 638462306a36Sopenharmony_ci /* 638562306a36Sopenharmony_ci * The following section is for additional directories/files for the 638662306a36Sopenharmony_ci * physical port. 638762306a36Sopenharmony_ci */ 638862306a36Sopenharmony_ci 638962306a36Sopenharmony_ci if (!pport_setup) 639062306a36Sopenharmony_ci goto debug_failed; 639162306a36Sopenharmony_ci 639262306a36Sopenharmony_ci /* 639362306a36Sopenharmony_ci * iDiag debugfs root entry points for SLI4 device only 639462306a36Sopenharmony_ci */ 639562306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) 639662306a36Sopenharmony_ci goto debug_failed; 639762306a36Sopenharmony_ci 639862306a36Sopenharmony_ci snprintf(name, sizeof(name), "iDiag"); 639962306a36Sopenharmony_ci if (!phba->idiag_root) { 640062306a36Sopenharmony_ci phba->idiag_root = 640162306a36Sopenharmony_ci debugfs_create_dir(name, phba->hba_debugfs_root); 640262306a36Sopenharmony_ci /* Initialize iDiag data structure */ 640362306a36Sopenharmony_ci memset(&idiag, 0, sizeof(idiag)); 640462306a36Sopenharmony_ci } 640562306a36Sopenharmony_ci 640662306a36Sopenharmony_ci /* iDiag read PCI config space */ 640762306a36Sopenharmony_ci snprintf(name, sizeof(name), "pciCfg"); 640862306a36Sopenharmony_ci if (!phba->idiag_pci_cfg) { 640962306a36Sopenharmony_ci phba->idiag_pci_cfg = 641062306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 641162306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_pciCfg); 641262306a36Sopenharmony_ci idiag.offset.last_rd = 0; 641362306a36Sopenharmony_ci } 641462306a36Sopenharmony_ci 641562306a36Sopenharmony_ci /* iDiag PCI BAR access */ 641662306a36Sopenharmony_ci snprintf(name, sizeof(name), "barAcc"); 641762306a36Sopenharmony_ci if (!phba->idiag_bar_acc) { 641862306a36Sopenharmony_ci phba->idiag_bar_acc = 641962306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 642062306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_barAcc); 642162306a36Sopenharmony_ci idiag.offset.last_rd = 0; 642262306a36Sopenharmony_ci } 642362306a36Sopenharmony_ci 642462306a36Sopenharmony_ci /* iDiag get PCI function queue information */ 642562306a36Sopenharmony_ci snprintf(name, sizeof(name), "queInfo"); 642662306a36Sopenharmony_ci if (!phba->idiag_que_info) { 642762306a36Sopenharmony_ci phba->idiag_que_info = 642862306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO, 642962306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_queInfo); 643062306a36Sopenharmony_ci } 643162306a36Sopenharmony_ci 643262306a36Sopenharmony_ci /* iDiag access PCI function queue */ 643362306a36Sopenharmony_ci snprintf(name, sizeof(name), "queAcc"); 643462306a36Sopenharmony_ci if (!phba->idiag_que_acc) { 643562306a36Sopenharmony_ci phba->idiag_que_acc = 643662306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 643762306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_queAcc); 643862306a36Sopenharmony_ci } 643962306a36Sopenharmony_ci 644062306a36Sopenharmony_ci /* iDiag access PCI function doorbell registers */ 644162306a36Sopenharmony_ci snprintf(name, sizeof(name), "drbAcc"); 644262306a36Sopenharmony_ci if (!phba->idiag_drb_acc) { 644362306a36Sopenharmony_ci phba->idiag_drb_acc = 644462306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 644562306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); 644662306a36Sopenharmony_ci } 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_ci /* iDiag access PCI function control registers */ 644962306a36Sopenharmony_ci snprintf(name, sizeof(name), "ctlAcc"); 645062306a36Sopenharmony_ci if (!phba->idiag_ctl_acc) { 645162306a36Sopenharmony_ci phba->idiag_ctl_acc = 645262306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 645362306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); 645462306a36Sopenharmony_ci } 645562306a36Sopenharmony_ci 645662306a36Sopenharmony_ci /* iDiag access mbox commands */ 645762306a36Sopenharmony_ci snprintf(name, sizeof(name), "mbxAcc"); 645862306a36Sopenharmony_ci if (!phba->idiag_mbx_acc) { 645962306a36Sopenharmony_ci phba->idiag_mbx_acc = 646062306a36Sopenharmony_ci debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, 646162306a36Sopenharmony_ci phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); 646262306a36Sopenharmony_ci } 646362306a36Sopenharmony_ci 646462306a36Sopenharmony_ci /* iDiag extents access commands */ 646562306a36Sopenharmony_ci if (phba->sli4_hba.extents_in_use) { 646662306a36Sopenharmony_ci snprintf(name, sizeof(name), "extAcc"); 646762306a36Sopenharmony_ci if (!phba->idiag_ext_acc) { 646862306a36Sopenharmony_ci phba->idiag_ext_acc = 646962306a36Sopenharmony_ci debugfs_create_file(name, 647062306a36Sopenharmony_ci S_IFREG|S_IRUGO|S_IWUSR, 647162306a36Sopenharmony_ci phba->idiag_root, phba, 647262306a36Sopenharmony_ci &lpfc_idiag_op_extAcc); 647362306a36Sopenharmony_ci } 647462306a36Sopenharmony_ci } 647562306a36Sopenharmony_ci 647662306a36Sopenharmony_cidebug_failed: 647762306a36Sopenharmony_ci return; 647862306a36Sopenharmony_ci#endif 647962306a36Sopenharmony_ci} 648062306a36Sopenharmony_ci 648162306a36Sopenharmony_ci/** 648262306a36Sopenharmony_ci * lpfc_debugfs_terminate - Tear down debugfs infrastructure for this vport 648362306a36Sopenharmony_ci * @vport: The vport pointer to remove from debugfs. 648462306a36Sopenharmony_ci * 648562306a36Sopenharmony_ci * Description: 648662306a36Sopenharmony_ci * When Debugfs is configured this routine removes debugfs file system elements 648762306a36Sopenharmony_ci * that are specific to this vport. It also checks to see if there are any 648862306a36Sopenharmony_ci * users left for the debugfs directories associated with the HBA and driver. If 648962306a36Sopenharmony_ci * this is the last user of the HBA directory or driver directory then it will 649062306a36Sopenharmony_ci * remove those from the debugfs infrastructure as well. 649162306a36Sopenharmony_ci **/ 649262306a36Sopenharmony_ciinline void 649362306a36Sopenharmony_cilpfc_debugfs_terminate(struct lpfc_vport *vport) 649462306a36Sopenharmony_ci{ 649562306a36Sopenharmony_ci#ifdef CONFIG_SCSI_LPFC_DEBUG_FS 649662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 649762306a36Sopenharmony_ci 649862306a36Sopenharmony_ci kfree(vport->disc_trc); 649962306a36Sopenharmony_ci vport->disc_trc = NULL; 650062306a36Sopenharmony_ci 650162306a36Sopenharmony_ci debugfs_remove(vport->debug_disc_trc); /* discovery_trace */ 650262306a36Sopenharmony_ci vport->debug_disc_trc = NULL; 650362306a36Sopenharmony_ci 650462306a36Sopenharmony_ci debugfs_remove(vport->debug_nodelist); /* nodelist */ 650562306a36Sopenharmony_ci vport->debug_nodelist = NULL; 650662306a36Sopenharmony_ci 650762306a36Sopenharmony_ci debugfs_remove(vport->debug_nvmestat); /* nvmestat */ 650862306a36Sopenharmony_ci vport->debug_nvmestat = NULL; 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci debugfs_remove(vport->debug_scsistat); /* scsistat */ 651162306a36Sopenharmony_ci vport->debug_scsistat = NULL; 651262306a36Sopenharmony_ci 651362306a36Sopenharmony_ci debugfs_remove(vport->debug_ioktime); /* ioktime */ 651462306a36Sopenharmony_ci vport->debug_ioktime = NULL; 651562306a36Sopenharmony_ci 651662306a36Sopenharmony_ci debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */ 651762306a36Sopenharmony_ci vport->debug_hdwqstat = NULL; 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_ci if (vport->vport_debugfs_root) { 652062306a36Sopenharmony_ci debugfs_remove(vport->vport_debugfs_root); /* vportX */ 652162306a36Sopenharmony_ci vport->vport_debugfs_root = NULL; 652262306a36Sopenharmony_ci atomic_dec(&phba->debugfs_vport_count); 652362306a36Sopenharmony_ci } 652462306a36Sopenharmony_ci 652562306a36Sopenharmony_ci if (atomic_read(&phba->debugfs_vport_count) == 0) { 652662306a36Sopenharmony_ci 652762306a36Sopenharmony_ci debugfs_remove(phba->debug_multixri_pools); /* multixripools*/ 652862306a36Sopenharmony_ci phba->debug_multixri_pools = NULL; 652962306a36Sopenharmony_ci 653062306a36Sopenharmony_ci debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ 653162306a36Sopenharmony_ci phba->debug_hbqinfo = NULL; 653262306a36Sopenharmony_ci 653362306a36Sopenharmony_ci debugfs_remove(phba->debug_cgn_buffer); 653462306a36Sopenharmony_ci phba->debug_cgn_buffer = NULL; 653562306a36Sopenharmony_ci 653662306a36Sopenharmony_ci debugfs_remove(phba->debug_rx_monitor); 653762306a36Sopenharmony_ci phba->debug_rx_monitor = NULL; 653862306a36Sopenharmony_ci 653962306a36Sopenharmony_ci debugfs_remove(phba->debug_ras_log); 654062306a36Sopenharmony_ci phba->debug_ras_log = NULL; 654162306a36Sopenharmony_ci 654262306a36Sopenharmony_ci#ifdef LPFC_HDWQ_LOCK_STAT 654362306a36Sopenharmony_ci debugfs_remove(phba->debug_lockstat); /* lockstat */ 654462306a36Sopenharmony_ci phba->debug_lockstat = NULL; 654562306a36Sopenharmony_ci#endif 654662306a36Sopenharmony_ci debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ 654762306a36Sopenharmony_ci phba->debug_dumpHBASlim = NULL; 654862306a36Sopenharmony_ci 654962306a36Sopenharmony_ci debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ 655062306a36Sopenharmony_ci phba->debug_dumpHostSlim = NULL; 655162306a36Sopenharmony_ci 655262306a36Sopenharmony_ci debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ 655362306a36Sopenharmony_ci phba->debug_InjErrLBA = NULL; 655462306a36Sopenharmony_ci 655562306a36Sopenharmony_ci debugfs_remove(phba->debug_InjErrNPortID); 655662306a36Sopenharmony_ci phba->debug_InjErrNPortID = NULL; 655762306a36Sopenharmony_ci 655862306a36Sopenharmony_ci debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */ 655962306a36Sopenharmony_ci phba->debug_InjErrWWPN = NULL; 656062306a36Sopenharmony_ci 656162306a36Sopenharmony_ci debugfs_remove(phba->debug_writeGuard); /* writeGuard */ 656262306a36Sopenharmony_ci phba->debug_writeGuard = NULL; 656362306a36Sopenharmony_ci 656462306a36Sopenharmony_ci debugfs_remove(phba->debug_writeApp); /* writeApp */ 656562306a36Sopenharmony_ci phba->debug_writeApp = NULL; 656662306a36Sopenharmony_ci 656762306a36Sopenharmony_ci debugfs_remove(phba->debug_writeRef); /* writeRef */ 656862306a36Sopenharmony_ci phba->debug_writeRef = NULL; 656962306a36Sopenharmony_ci 657062306a36Sopenharmony_ci debugfs_remove(phba->debug_readGuard); /* readGuard */ 657162306a36Sopenharmony_ci phba->debug_readGuard = NULL; 657262306a36Sopenharmony_ci 657362306a36Sopenharmony_ci debugfs_remove(phba->debug_readApp); /* readApp */ 657462306a36Sopenharmony_ci phba->debug_readApp = NULL; 657562306a36Sopenharmony_ci 657662306a36Sopenharmony_ci debugfs_remove(phba->debug_readRef); /* readRef */ 657762306a36Sopenharmony_ci phba->debug_readRef = NULL; 657862306a36Sopenharmony_ci 657962306a36Sopenharmony_ci kfree(phba->slow_ring_trc); 658062306a36Sopenharmony_ci phba->slow_ring_trc = NULL; 658162306a36Sopenharmony_ci 658262306a36Sopenharmony_ci /* slow_ring_trace */ 658362306a36Sopenharmony_ci debugfs_remove(phba->debug_slow_ring_trc); 658462306a36Sopenharmony_ci phba->debug_slow_ring_trc = NULL; 658562306a36Sopenharmony_ci 658662306a36Sopenharmony_ci debugfs_remove(phba->debug_nvmeio_trc); 658762306a36Sopenharmony_ci phba->debug_nvmeio_trc = NULL; 658862306a36Sopenharmony_ci 658962306a36Sopenharmony_ci kfree(phba->nvmeio_trc); 659062306a36Sopenharmony_ci phba->nvmeio_trc = NULL; 659162306a36Sopenharmony_ci 659262306a36Sopenharmony_ci /* 659362306a36Sopenharmony_ci * iDiag release 659462306a36Sopenharmony_ci */ 659562306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) { 659662306a36Sopenharmony_ci /* iDiag extAcc */ 659762306a36Sopenharmony_ci debugfs_remove(phba->idiag_ext_acc); 659862306a36Sopenharmony_ci phba->idiag_ext_acc = NULL; 659962306a36Sopenharmony_ci 660062306a36Sopenharmony_ci /* iDiag mbxAcc */ 660162306a36Sopenharmony_ci debugfs_remove(phba->idiag_mbx_acc); 660262306a36Sopenharmony_ci phba->idiag_mbx_acc = NULL; 660362306a36Sopenharmony_ci 660462306a36Sopenharmony_ci /* iDiag ctlAcc */ 660562306a36Sopenharmony_ci debugfs_remove(phba->idiag_ctl_acc); 660662306a36Sopenharmony_ci phba->idiag_ctl_acc = NULL; 660762306a36Sopenharmony_ci 660862306a36Sopenharmony_ci /* iDiag drbAcc */ 660962306a36Sopenharmony_ci debugfs_remove(phba->idiag_drb_acc); 661062306a36Sopenharmony_ci phba->idiag_drb_acc = NULL; 661162306a36Sopenharmony_ci 661262306a36Sopenharmony_ci /* iDiag queAcc */ 661362306a36Sopenharmony_ci debugfs_remove(phba->idiag_que_acc); 661462306a36Sopenharmony_ci phba->idiag_que_acc = NULL; 661562306a36Sopenharmony_ci 661662306a36Sopenharmony_ci /* iDiag queInfo */ 661762306a36Sopenharmony_ci debugfs_remove(phba->idiag_que_info); 661862306a36Sopenharmony_ci phba->idiag_que_info = NULL; 661962306a36Sopenharmony_ci 662062306a36Sopenharmony_ci /* iDiag barAcc */ 662162306a36Sopenharmony_ci debugfs_remove(phba->idiag_bar_acc); 662262306a36Sopenharmony_ci phba->idiag_bar_acc = NULL; 662362306a36Sopenharmony_ci 662462306a36Sopenharmony_ci /* iDiag pciCfg */ 662562306a36Sopenharmony_ci debugfs_remove(phba->idiag_pci_cfg); 662662306a36Sopenharmony_ci phba->idiag_pci_cfg = NULL; 662762306a36Sopenharmony_ci 662862306a36Sopenharmony_ci /* Finally remove the iDiag debugfs root */ 662962306a36Sopenharmony_ci debugfs_remove(phba->idiag_root); 663062306a36Sopenharmony_ci phba->idiag_root = NULL; 663162306a36Sopenharmony_ci } 663262306a36Sopenharmony_ci 663362306a36Sopenharmony_ci if (phba->hba_debugfs_root) { 663462306a36Sopenharmony_ci debugfs_remove(phba->hba_debugfs_root); /* fnX */ 663562306a36Sopenharmony_ci phba->hba_debugfs_root = NULL; 663662306a36Sopenharmony_ci atomic_dec(&lpfc_debugfs_hba_count); 663762306a36Sopenharmony_ci } 663862306a36Sopenharmony_ci 663962306a36Sopenharmony_ci if (atomic_read(&lpfc_debugfs_hba_count) == 0) { 664062306a36Sopenharmony_ci debugfs_remove(lpfc_debugfs_root); /* lpfc */ 664162306a36Sopenharmony_ci lpfc_debugfs_root = NULL; 664262306a36Sopenharmony_ci } 664362306a36Sopenharmony_ci } 664462306a36Sopenharmony_ci#endif 664562306a36Sopenharmony_ci return; 664662306a36Sopenharmony_ci} 664762306a36Sopenharmony_ci 664862306a36Sopenharmony_ci/* 664962306a36Sopenharmony_ci * Driver debug utility routines outside of debugfs. The debug utility 665062306a36Sopenharmony_ci * routines implemented here is intended to be used in the instrumented 665162306a36Sopenharmony_ci * debug driver for debugging host or port issues. 665262306a36Sopenharmony_ci */ 665362306a36Sopenharmony_ci 665462306a36Sopenharmony_ci/** 665562306a36Sopenharmony_ci * lpfc_debug_dump_all_queues - dump all the queues with a hba 665662306a36Sopenharmony_ci * @phba: Pointer to HBA context object. 665762306a36Sopenharmony_ci * 665862306a36Sopenharmony_ci * This function dumps entries of all the queues asociated with the @phba. 665962306a36Sopenharmony_ci **/ 666062306a36Sopenharmony_civoid 666162306a36Sopenharmony_cilpfc_debug_dump_all_queues(struct lpfc_hba *phba) 666262306a36Sopenharmony_ci{ 666362306a36Sopenharmony_ci int idx; 666462306a36Sopenharmony_ci 666562306a36Sopenharmony_ci /* 666662306a36Sopenharmony_ci * Dump Work Queues (WQs) 666762306a36Sopenharmony_ci */ 666862306a36Sopenharmony_ci lpfc_debug_dump_wq(phba, DUMP_MBX, 0); 666962306a36Sopenharmony_ci lpfc_debug_dump_wq(phba, DUMP_ELS, 0); 667062306a36Sopenharmony_ci lpfc_debug_dump_wq(phba, DUMP_NVMELS, 0); 667162306a36Sopenharmony_ci 667262306a36Sopenharmony_ci for (idx = 0; idx < phba->cfg_hdw_queue; idx++) 667362306a36Sopenharmony_ci lpfc_debug_dump_wq(phba, DUMP_IO, idx); 667462306a36Sopenharmony_ci 667562306a36Sopenharmony_ci lpfc_debug_dump_hdr_rq(phba); 667662306a36Sopenharmony_ci lpfc_debug_dump_dat_rq(phba); 667762306a36Sopenharmony_ci /* 667862306a36Sopenharmony_ci * Dump Complete Queues (CQs) 667962306a36Sopenharmony_ci */ 668062306a36Sopenharmony_ci lpfc_debug_dump_cq(phba, DUMP_MBX, 0); 668162306a36Sopenharmony_ci lpfc_debug_dump_cq(phba, DUMP_ELS, 0); 668262306a36Sopenharmony_ci lpfc_debug_dump_cq(phba, DUMP_NVMELS, 0); 668362306a36Sopenharmony_ci 668462306a36Sopenharmony_ci for (idx = 0; idx < phba->cfg_hdw_queue; idx++) 668562306a36Sopenharmony_ci lpfc_debug_dump_cq(phba, DUMP_IO, idx); 668662306a36Sopenharmony_ci 668762306a36Sopenharmony_ci /* 668862306a36Sopenharmony_ci * Dump Event Queues (EQs) 668962306a36Sopenharmony_ci */ 669062306a36Sopenharmony_ci for (idx = 0; idx < phba->cfg_hdw_queue; idx++) 669162306a36Sopenharmony_ci lpfc_debug_dump_hba_eq(phba, idx); 669262306a36Sopenharmony_ci} 6693