lpfc_attr.c
来自「linux 内核源代码」· C语言 代码 · 共 2,217 行 · 第 1/5 页
C
2,217 行
/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2004-2007 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/delay.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"#include "lpfc_vport.h"#define LPFC_DEF_DEVLOSS_TMO 30#define LPFC_MIN_DEVLOSS_TMO 1#define LPFC_MAX_DEVLOSS_TMO 255static 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_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 *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);}static ssize_tlpfc_modeldesc_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);}static ssize_tlpfc_modelname_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);}static ssize_tlpfc_programtype_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);}static ssize_tlpfc_vportnum_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);}static ssize_tlpfc_fwrev_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; char fwrev[32]; lpfc_decode_firmware_rev(phba, fwrev, 1); return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev);}static ssize_tlpfc_hdw_show(struct class_device *cdev, char *buf){ char hdw[9]; struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; 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 *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);}static ssize_tlpfc_state_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; int len = 0; switch (phba->link_state) { case LPFC_LINK_UNKNOWN: case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n"); switch (vport->port_state) { len += snprintf(buf + len, PAGE_SIZE-len, "initializing\n"); break; case LPFC_LOCAL_CFG_LINK: len += snprintf(buf + len, PAGE_SIZE-len, "Configuring Link\n"); break; case LPFC_FDISC: 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: len += snprintf(buf + len, PAGE_SIZE - len, "Discovery\n"); break; case LPFC_VPORT_READY: len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n"); break; case LPFC_VPORT_FAILED: len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n"); break; case LPFC_VPORT_UNKNOWN: len += snprintf(buf + len, PAGE_SIZE - len, "Unknown\n"); break; } if (phba->fc_topology == TOPOLOGY_LOOP) { if (vport->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 (vport->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 *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; return snprintf(buf, PAGE_SIZE, "%d\n", vport->fc_map_cnt + vport->fc_unmap_cnt);}static intlpfc_issue_lip(struct Scsi_Host *shost){ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; if ((vport->fc_flag & FC_OFFLINE_MODE) || (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || (vport->port_state != LPFC_VPORT_READY)) return -EPERM; pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); if (!pmboxq) return -ENOMEM; memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); pmboxq->mb.mbxCommand = MBX_DOWN_LINK; pmboxq->mb.mbxOwner = OWN_HOST; mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) { 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); } lpfc_set_loopback_flag(phba); if (mbxstatus != MBX_TIMEOUT) mempool_free(pmboxq, phba->mbox_mem_pool); if (mbxstatus == MBXERR_ERROR) return -EIO; return 0;}static intlpfc_do_offline(struct lpfc_hba *phba, uint32_t type){ struct completion online_compl; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; int status = 0; int cnt = 0; int i; init_completion(&online_compl); lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_OFFLINE_PREP); wait_for_completion(&online_compl); if (status != 0) return -EIO; psli = &phba->sli; for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; /* The linkdown event takes 30 seconds to timeout. */ while (pring->txcmplq_cnt) { msleep(10); if (cnt++ > 3000) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0466 Outstanding IO when " "bringing Adapter offline\n"); break; } } } init_completion(&online_compl); lpfc_workq_post_event(phba, &status, &online_compl, type); wait_for_completion(&online_compl); if (status != 0) return -EIO; return 0;}static intlpfc_selective_reset(struct lpfc_hba *phba){ struct completion online_compl; int status = 0; status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); if (status != 0) return status; init_completion(&online_compl); lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); wait_for_completion(&online_compl); if (status != 0) return -EIO; return 0;}static ssize_tlpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; int status = -EINVAL; if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) status = lpfc_selective_reset(phba); if (status == 0) return strlen(buf); else return status;}static ssize_tlpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);}static ssize_tlpfc_board_mode_show(struct class_device *cdev, char *buf){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; char * state; if (phba->link_state == LPFC_HBA_ERROR) state = "error"; else if (phba->link_state == LPFC_WARM_START) state = "warm start"; else if (phba->link_state == LPFC_INIT_START) state = "offline"; else state = "online"; return snprintf(buf, PAGE_SIZE, "%s\n", state);}static ssize_tlpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count){ struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct completion online_compl; int status=0; init_completion(&online_compl); if(strncmp(buf, "online", sizeof("online") - 1) == 0) { lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); wait_for_completion(&online_compl); } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); else if (strncmp(buf, "error", sizeof("error") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_KILL); else return -EINVAL; if (!status) return strlen(buf); else return -EIO;}static intlpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, uint32_t *axri, uint32_t *mrpi, uint32_t *arpi, uint32_t *mvpi, uint32_t *avpi){ struct lpfc_sli *psli = &phba->sli; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc = 0; /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?