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