lpfc_attr.c

来自「底层驱动开发」· C语言 代码 · 共 1,289 行 · 第 1/3 页

C
1,289
字号
/******************************************************************* * This file is part of the Emulex Linux Device Driver for         * * Fibre Channel Host Bus Adapters.                                * * Copyright (C) 2004-2005 Emulex.  All rights reserved.           * * EMULEX and SLI are trademarks of Emulex.                        * * www.emulex.com                                                  * * Portions Copyright (C) 2004-2005 Christoph Hellwig              * *                                                                 * * 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/ctype.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <scsi/scsi.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.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_version.h"#include "lpfc_compat.h"#include "lpfc_crtn.h"static voidlpfc_jedec_to_ascii(int incr, char hdw[]){	int i, j;	for (i = 0; i < 8; i++) {		j = (incr & 0xf);		if (j <= 9)			hdw[7 - i] = 0x30 +  j;		 else			hdw[7 - i] = 0x61 + j - 10;		incr = (incr >> 4);	}	hdw[8] = 0;	return;}static ssize_tlpfc_drvr_version_show(struct class_device *cdev, char *buf){	return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");}static ssize_tmanagement_version_show(struct class_device *cdev, char *buf){	return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n");}static ssize_tlpfc_info_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host));}static ssize_tlpfc_serialnum_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);}static ssize_tlpfc_modeldesc_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);}static ssize_tlpfc_modelname_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);}static ssize_tlpfc_programtype_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);}static ssize_tlpfc_portnum_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);}static ssize_tlpfc_fwrev_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	char fwrev[32];	lpfc_decode_firmware_rev(phba, fwrev, 1);	return snprintf(buf, PAGE_SIZE, "%s\n",fwrev);}static ssize_tlpfc_hdw_show(struct class_device *cdev, char *buf){	char hdw[9];	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	lpfc_vpd_t *vp = &phba->vpd;	lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);	return snprintf(buf, PAGE_SIZE, "%s\n", hdw);}static ssize_tlpfc_option_rom_version_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);}static ssize_tlpfc_state_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	int len = 0;	switch (phba->hba_state) {	case LPFC_INIT_START:	case LPFC_INIT_MBX_CMDS:	case LPFC_LINK_DOWN:		len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");		break;	case LPFC_LINK_UP:	case LPFC_LOCAL_CFG_LINK:		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n");		break;	case LPFC_FLOGI:	case LPFC_FABRIC_CFG_LINK:	case LPFC_NS_REG:	case LPFC_NS_QRY:	case LPFC_BUILD_DISC_LIST:	case LPFC_DISC_AUTH:	case LPFC_CLEAR_LA:		len += snprintf(buf + len, PAGE_SIZE-len,				"Link Up - Discovery\n");		break;	case LPFC_HBA_READY:		len += snprintf(buf + len, PAGE_SIZE-len,				"Link Up - Ready:\n");		if (phba->fc_topology == TOPOLOGY_LOOP) {			if (phba->fc_flag & FC_PUBLIC_LOOP)				len += snprintf(buf + len, PAGE_SIZE-len,						"   Public Loop\n");			else				len += snprintf(buf + len, PAGE_SIZE-len,						"   Private Loop\n");		} else {			if (phba->fc_flag & FC_FABRIC)				len += snprintf(buf + len, PAGE_SIZE-len,						"   Fabric\n");			else				len += snprintf(buf + len, PAGE_SIZE-len,						"   Point-2-Point\n");		}	}	return len;}static ssize_tlpfc_num_discovered_ports_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt +							phba->fc_unmap_cnt);}static ssize_tlpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0];	int val = 0;	LPFC_MBOXQ_t *pmboxq;	int mbxstatus = MBXERR_ERROR;	if ((sscanf(buf, "%d", &val) != 1) ||	    (val != 1))		return -EINVAL;	if ((phba->fc_flag & FC_OFFLINE_MODE) ||	    (phba->hba_state != LPFC_HBA_READY))		return -EPERM;	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);	if (!pmboxq)		return -ENOMEM;	memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));	lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);	mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);	if (mbxstatus == MBX_TIMEOUT)		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;	else		mempool_free( pmboxq, phba->mbox_mem_pool);	if (mbxstatus == MBXERR_ERROR)		return -EIO;	return strlen(buf);}static ssize_tlpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);}static ssize_tlpfc_board_online_show(struct class_device *cdev, char *buf){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	if (!phba) return 0;	if (phba->fc_flag & FC_OFFLINE_MODE)		return snprintf(buf, PAGE_SIZE, "0\n");	else		return snprintf(buf, PAGE_SIZE, "1\n");}static ssize_tlpfc_board_online_store(struct class_device *cdev, const char *buf,								size_t count){	struct Scsi_Host *host = class_to_shost(cdev);	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];	struct completion online_compl;	int val=0, status=0;	if (sscanf(buf, "%d", &val) != 1)		return 0;	init_completion(&online_compl);	if (val)		lpfc_workq_post_event(phba, &status, &online_compl,							LPFC_EVT_ONLINE);	else		lpfc_workq_post_event(phba, &status, &online_compl,							LPFC_EVT_OFFLINE);	wait_for_completion(&online_compl);	if (!status)		return strlen(buf);	else		return 0;}#define lpfc_param_show(attr)	\static ssize_t \lpfc_##attr##_show(struct class_device *cdev, char *buf) \{ \	struct Scsi_Host *host = class_to_shost(cdev);\	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\	int val = 0;\	if (phba){\		val = phba->cfg_##attr;\		return snprintf(buf, PAGE_SIZE, "%d\n",\				phba->cfg_##attr);\	}\	return 0;\}#define lpfc_param_store(attr, minval, maxval)	\static ssize_t \lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \{ \	struct Scsi_Host *host = class_to_shost(cdev);\	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\	int val = 0;\	if (!isdigit(buf[0]))\		return -EINVAL;\	if (sscanf(buf, "0x%x", &val) != 1)\		if (sscanf(buf, "%d", &val) != 1)\			return -EINVAL;\	if (phba){\		if (val >= minval && val <= maxval) {\			phba->cfg_##attr = val;\			return strlen(buf);\		}\	}\	return 0;\}#define LPFC_ATTR_R_NOINIT(name, desc) \extern int lpfc_##name;\module_param(lpfc_##name, int, 0);\MODULE_PARM_DESC(lpfc_##name, desc);\lpfc_param_show(name)\static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \static int lpfc_##name = defval;\module_param(lpfc_##name, int, 0);\MODULE_PARM_DESC(lpfc_##name, desc);\lpfc_param_show(name)\static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \static int lpfc_##name = defval;\module_param(lpfc_##name, int, 0);\MODULE_PARM_DESC(lpfc_##name, desc);\lpfc_param_show(name)\lpfc_param_store(name, minval, maxval)\static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\			 lpfc_##name##_show, lpfc_##name##_store)static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL);static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL);static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL);static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL);static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);static CLASS_DEVICE_ATTR(option_rom_version, S_IRUGO,					lpfc_option_rom_version_show, NULL);static CLASS_DEVICE_ATTR(num_discovered_ports, S_IRUGO,					lpfc_num_discovered_ports_show, NULL);static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,			 NULL);static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,			 NULL);static CLASS_DEVICE_ATTR(issue_lip, S_IWUSR, NULL, lpfc_issue_lip);static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,			 lpfc_board_online_show, lpfc_board_online_store);/*# lpfc_log_verbose: Only turn this flag on if you are willing to risk being# deluged with LOTS of information.# You can set a bit mask to record specific types of verbose messages:## LOG_ELS                       0x1        ELS events# LOG_DISCOVERY                 0x2        Link discovery events# LOG_MBOX                      0x4        Mailbox events# LOG_INIT                      0x8        Initialization events# LOG_LINK_EVENT                0x10       Link events# LOG_IP                        0x20       IP traffic history# LOG_FCP                       0x40       FCP traffic history# LOG_NODE                      0x80       Node table events# LOG_MISC                      0x400      Miscellaneous events# LOG_SLI                       0x800      SLI events# LOG_CHK_COND                  0x1000     FCP Check condition flag# LOG_LIBDFC                    0x2000     LIBDFC events# LOG_ALL_MSG                   0xffff     LOG all messages*/LPFC_ATTR_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask");/*# lun_queue_depth:  This parameter is used to limit the number of outstanding# commands per FCP LUN. Value range is [1,128]. Default value is 30.*/LPFC_ATTR_R(lun_queue_depth, 30, 1, 128,	    "Max number of FCP commands we can queue to a specific LUN");/*# Some disk devices have a "select ID" or "select Target" capability.# From a protocol standpoint "select ID" usually means select the# Fibre channel "ALPA".  In the FC-AL Profile there is an "informative# annex" which contains a table that maps a "select ID" (a number# between 0 and 7F) to an ALPA.  By default, for compatibility with# older drivers, the lpfc driver scans this table from low ALPA to high# ALPA.## Turning on the scan-down variable (on  = 1, off = 0) will# cause the lpfc driver to use an inverted table, effectively# scanning ALPAs from high to low. Value range is [0,1]. Default value is 1.## (Note: This "select ID" functionality is a LOOP ONLY characteristic# and will not work across a fabric. Also this parameter will take# effect only in the case when ALPA map is not available.)*/LPFC_ATTR_R(scan_down, 1, 0, 1,	     "Start scanning for devices from highest ALPA to lowest");/*# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear# until the timer expires. Value range is [0,255]. Default value is 20.# NOTE: this MUST be less then the SCSI Layer command timeout - 1.*/LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,	     "Seconds driver will hold I/O waiting for a device to come back");/*# lpfc_topology:  link topology for init link#            0x0  = attempt loop mode then point-to-point

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?