📄 lpfc_attr.c
字号:
/******************************************************************* * 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 intlpfc_issue_lip(struct Scsi_Host *host){ struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; 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 0;}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->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 -EINVAL; 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 -EIO;}#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;\ val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ phba->cfg_##attr);\}#define lpfc_param_hex_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;\ val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%#x\n",\ phba->cfg_##attr);\}#define lpfc_param_init(attr, default, minval, maxval) \static int \lpfc_##attr##_init(struct lpfc_hba *phba, int val) \{ \ if (val >= minval && val <= maxval) {\ phba->cfg_##attr = val;\ return 0;\ }\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ "%d:0449 lpfc_"#attr" attribute cannot be set to %d, "\ "allowed range is ["#minval", "#maxval"]\n", \ phba->brd_no, val); \ phba->cfg_##attr = default;\ return -EINVAL;\}#define lpfc_param_set(attr, default, minval, maxval) \static int \lpfc_##attr##_set(struct lpfc_hba *phba, int val) \{ \ if (val >= minval && val <= maxval) {\ phba->cfg_##attr = val;\ return 0;\ }\ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ "%d:0450 lpfc_"#attr" attribute cannot be set to %d, "\ "allowed range is ["#minval", "#maxval"]\n", \ phba->brd_no, val); \ return -EINVAL;\}#define lpfc_param_store(attr) \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, "%i", &val) != 1)\ return -EINVAL;\ if (lpfc_##attr##_set(phba, val) == 0) \ return strlen(buf);\ else \ return -EINVAL;\}#define LPFC_ATTR(name, defval, minval, maxval, desc) \static int lpfc_##name = defval;\module_param(lpfc_##name, int, 0);\MODULE_PARM_DESC(lpfc_##name, desc);\lpfc_param_init(name, defval, minval, maxval)#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)\lpfc_param_init(name, defval, minval, maxval)\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_init(name, defval, minval, maxval)\lpfc_param_set(name, defval, minval, maxval)\lpfc_param_store(name)\static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ lpfc_##name##_show, lpfc_##name##_store)#define LPFC_ATTR_HEX_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_hex_show(name)\lpfc_param_init(name, defval, minval, maxval)\static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)#define LPFC_ATTR_HEX_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_hex_show(name)\lpfc_param_init(name, defval, minval, maxval)\lpfc_param_set(name, defval, minval, maxval)\lpfc_param_store(name)\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(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_HEX_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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -