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 + -
显示快捷键?