lpfc_debugfs.c
来自「linux 内核源代码」· C语言 代码 · 共 1,003 行 · 第 1/2 页
C
1,003 行
/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of version 2 of the GNU General * * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID. See the GNU General Public License for * * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/kthread.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/ctype.h>#include <linux/version.h>#include <scsi/scsi.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_transport_fc.h>#include "lpfc_hw.h"#include "lpfc_sli.h"#include "lpfc_disc.h"#include "lpfc_scsi.h"#include "lpfc.h"#include "lpfc_logmsg.h"#include "lpfc_crtn.h"#include "lpfc_vport.h"#include "lpfc_version.h"#include "lpfc_debugfs.h"#ifdef CONFIG_LPFC_DEBUG_FS/* debugfs interface * * To access this interface the user should: * # mkdir /debug * # mount -t debugfs none /debug * * The lpfc debugfs directory hierachy is: * lpfc/lpfcX/vportY * where X is the lpfc hba unique_id * where Y is the vport VPI on that hba * * Debugging services available per vport: * discovery_trace * This is an ACSII readable file that contains a trace of the last * lpfc_debugfs_max_disc_trc events that happened on a specific vport. * See lpfc_debugfs.h for different categories of * discovery events. To enable the discovery trace, the following * module parameters must be set: * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for * EACH vport. X MUST also be a power of 2. * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in * lpfc_debugfs.h . */static int lpfc_debugfs_enable = 1;module_param(lpfc_debugfs_enable, int, 0);MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");/* This MUST be a power of 2 */static int lpfc_debugfs_max_disc_trc = 0;module_param(lpfc_debugfs_max_disc_trc, int, 0);MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc, "Set debugfs discovery trace depth");/* This MUST be a power of 2 */static int lpfc_debugfs_max_slow_ring_trc = 0;module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, "Set debugfs slow ring trace depth");static int lpfc_debugfs_mask_disc_trc = 0;module_param(lpfc_debugfs_mask_disc_trc, int, 0);MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, "Set debugfs discovery trace mask");#include <linux/debugfs.h>/* size of output line, for discovery_trace and slow_ring_trace */#define LPFC_DEBUG_TRC_ENTRY_SIZE 100/* nodelist output buffer size */#define LPFC_NODELIST_SIZE 8192#define LPFC_NODELIST_ENTRY_SIZE 120/* dumpslim output buffer size */#define LPFC_DUMPSLIM_SIZE 4096/* hbqinfo output buffer size */#define LPFC_HBQINFO_SIZE 8192struct lpfc_debug { char *buffer; int len;};static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);static unsigned long lpfc_debugfs_start_time = 0L;static intlpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size){ int i, index, len, enable; uint32_t ms; struct lpfc_debugfs_trc *dtp; char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; enable = lpfc_debugfs_enable; lpfc_debugfs_enable = 0; len = 0; index = (atomic_read(&vport->disc_trc_cnt) + 1) & (lpfc_debugfs_max_disc_trc - 1); for (i = index; i < lpfc_debugfs_max_disc_trc; i++) { dtp = vport->disc_trc + i; if (!dtp->fmt) continue; ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); len += snprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { dtp = vport->disc_trc + i; if (!dtp->fmt) continue; ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); len += snprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } lpfc_debugfs_enable = enable; return len;}static intlpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size){ int i, index, len, enable; uint32_t ms; struct lpfc_debugfs_trc *dtp; char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; enable = lpfc_debugfs_enable; lpfc_debugfs_enable = 0; len = 0; index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) & (lpfc_debugfs_max_slow_ring_trc - 1); for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) { dtp = phba->slow_ring_trc + i; if (!dtp->fmt) continue; ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); len += snprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } for (i = 0; i < index; i++) { dtp = phba->slow_ring_trc + i; if (!dtp->fmt) continue; ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); snprintf(buffer, LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", dtp->seq_cnt, ms, dtp->fmt); len += snprintf(buf+len, size-len, buffer, dtp->data1, dtp->data2, dtp->data3); } lpfc_debugfs_enable = enable; return len;}static int lpfc_debugfs_last_hbq = -1;static intlpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size){ int len = 0; int cnt, i, j, found, posted, low; uint32_t phys, raw_index, getidx; struct lpfc_hbq_init *hip; struct hbq_s *hbqs; struct lpfc_hbq_entry *hbqe; struct lpfc_dmabuf *d_buf; struct hbq_dmabuf *hbq_buf; cnt = LPFC_HBQINFO_SIZE; spin_lock_irq(&phba->hbalock); /* toggle between multiple hbqs, if any */ i = lpfc_sli_hbq_count(); if (i > 1) { lpfc_debugfs_last_hbq++; if (lpfc_debugfs_last_hbq >= i) lpfc_debugfs_last_hbq = 0; } else lpfc_debugfs_last_hbq = 0; i = lpfc_debugfs_last_hbq; len += snprintf(buf+len, size-len, "HBQ %d Info\n", i); hbqs = &phba->hbqs[i]; posted = 0; list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) posted++; hip = lpfc_hbq_defs[i]; len += snprintf(buf+len, size-len, "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n", hip->hbq_index, hip->profile, hip->rn, hip->buffer_count, hip->init_count, hip->add_count, posted); raw_index = phba->hbq_get[i]; getidx = le32_to_cpu(raw_index); len += snprintf(buf+len, size-len, "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; for (j=0; j<hbqs->entry_count; j++) { len += snprintf(buf+len, size-len, "%03d: %08x %04x %05x ", j, hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag); i = 0; found = 0; /* First calculate if slot has an associated posted buffer */ low = hbqs->hbqPutIdx - posted; if (low >= 0) { if ((j >= hbqs->hbqPutIdx) || (j < low)) { len += snprintf(buf+len, size-len, "Unused\n"); goto skipit; } } else { if ((j >= hbqs->hbqPutIdx) && (j < (hbqs->entry_count+low))) { len += snprintf(buf+len, size-len, "Unused\n"); goto skipit; } } /* Get the Buffer info for the posted buffer */ list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); if (phys == hbqe->bde.addrLow) { len += snprintf(buf+len, size-len, "Buf%d: %p %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); found = 1; break; } i++; } if (!found) { len += snprintf(buf+len, size-len, "No DMAinfo?\n"); }skipit: hbqe++; if (len > LPFC_HBQINFO_SIZE - 54) break; } spin_unlock_irq(&phba->hbalock); return len;}static intlpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size){ int len = 0; int cnt, i, off; uint32_t word0, word1, word2, word3; uint32_t *ptr; struct lpfc_pgp *pgpp; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; cnt = LPFC_DUMPSLIM_SIZE; off = 0; spin_lock_irq(&phba->hbalock); len += snprintf(buf+len, size-len, "SLIM Mailbox\n"); ptr = (uint32_t *)phba->slim2p; i = sizeof(MAILBOX_t); while (i > 0) { len += snprintf(buf+len, size-len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); ptr += 8; i -= (8 * sizeof(uint32_t)); off += (8 * sizeof(uint32_t)); } len += snprintf(buf+len, size-len, "SLIM PCB\n"); ptr = (uint32_t *)&phba->slim2p->pcb; i = sizeof(PCB_t); while (i > 0) { len += snprintf(buf+len, size-len, "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); ptr += 8; i -= (8 * sizeof(uint32_t)); off += (8 * sizeof(uint32_t)); } pgpp = (struct lpfc_pgp *)&phba->slim2p->mbx.us.s3_pgp.port; pring = &psli->ring[0]; len += snprintf(buf+len, size-len, "Ring 0: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " "RSP PutInx:%d Max:%d\n", pgpp->cmdGetInx, pring->numCiocb, pring->next_cmdidx, pring->local_getidx, pring->flag, pgpp->rspPutInx, pring->numRiocb); pgpp++; pring = &psli->ring[1]; len += snprintf(buf+len, size-len, "Ring 1: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " "RSP PutInx:%d Max:%d\n", pgpp->cmdGetInx, pring->numCiocb, pring->next_cmdidx, pring->local_getidx, pring->flag, pgpp->rspPutInx, pring->numRiocb); pgpp++; pring = &psli->ring[2]; len += snprintf(buf+len, size-len, "Ring 2: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " "RSP PutInx:%d Max:%d\n", pgpp->cmdGetInx, pring->numCiocb, pring->next_cmdidx, pring->local_getidx, pring->flag, pgpp->rspPutInx, pring->numRiocb); pgpp++; pring = &psli->ring[3]; len += snprintf(buf+len, size-len, "Ring 3: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " "RSP PutInx:%d Max:%d\n", pgpp->cmdGetInx, pring->numCiocb, pring->next_cmdidx, pring->local_getidx, pring->flag, pgpp->rspPutInx, pring->numRiocb); ptr = (uint32_t *)&phba->slim2p->mbx.us.s3_pgp.hbq_get; word0 = readl(phba->HAregaddr); word1 = readl(phba->CAregaddr); word2 = readl(phba->HSregaddr); word3 = readl(phba->HCregaddr); len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n", word0, word1, word2, word3); spin_unlock_irq(&phba->hbalock); return len;}static intlpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size){ int len = 0; int cnt; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; unsigned char *statep, *name; cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (!cnt) { len += snprintf(buf+len, size-len, "Missing Nodelist Entries\n"); break; } cnt--; switch (ndlp->nlp_state) { case NLP_STE_UNUSED_NODE: statep = "UNUSED"; break; case NLP_STE_PLOGI_ISSUE: statep = "PLOGI "; break; case NLP_STE_ADISC_ISSUE: statep = "ADISC "; break; case NLP_STE_REG_LOGIN_ISSUE: statep = "REGLOG"; break; case NLP_STE_PRLI_ISSUE: statep = "PRLI "; break; case NLP_STE_UNMAPPED_NODE: statep = "UNMAP "; break; case NLP_STE_MAPPED_NODE: statep = "MAPPED"; break; case NLP_STE_NPR_NODE: statep = "NPR "; break; default: statep = "UNKNOWN"; } len += snprintf(buf+len, size-len, "%s DID:x%06x ", statep, ndlp->nlp_DID); name = (unsigned char *)&ndlp->nlp_portname; len += snprintf(buf+len, size-len, "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7)); name = (unsigned char *)&ndlp->nlp_nodename; len += snprintf(buf+len, size-len, "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7)); len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ", ndlp->nlp_rpi, ndlp->nlp_flag); if (!ndlp->nlp_type) len += snprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) len += snprintf(buf+len, size-len, "FC_NODE "); if (ndlp->nlp_type & NLP_FABRIC) len += snprintf(buf+len, size-len, "FABRIC "); if (ndlp->nlp_type & NLP_FCP_TARGET) len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ", ndlp->nlp_sid); if (ndlp->nlp_type & NLP_FCP_INITIATOR) len += snprintf(buf+len, size-len, "FCP_INITIATOR "); len += snprintf(buf+len, size-len, "refcnt:%x", atomic_read(&ndlp->kref.refcount)); len += snprintf(buf+len, size-len, "\n"); } spin_unlock_irq(shost->host_lock); return len;}#endifinline voidlpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt, uint32_t data1, uint32_t data2, uint32_t data3){#ifdef CONFIG_LPFC_DEBUG_FS struct lpfc_debugfs_trc *dtp; int index; if (!(lpfc_debugfs_mask_disc_trc & mask)) return; if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc || !vport || !vport->disc_trc) return; index = atomic_inc_return(&vport->disc_trc_cnt) & (lpfc_debugfs_max_disc_trc - 1); dtp = vport->disc_trc + index; dtp->fmt = fmt; dtp->data1 = data1; dtp->data2 = data2; dtp->data3 = data3; dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); dtp->jif = jiffies;#endif return;}inline voidlpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt, uint32_t data1, uint32_t data2, uint32_t data3){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?