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