[SCSI] lpfc: NPIV: add NPIV support on top of SLI-3
NPIV support is added to the driver. It utilizes the interfaces of the fc transport for the creation and deletion of vports. Within the driver, a new Scsi_Host is created for each NPIV instance, and is paired with a new instance of a FC port. This allows N FC Port elements to share a single Adapter. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
		
							parent
							
								
									ed95768429
								
							
						
					
					
						commit
						92d7f7b0cd
					
				| @ -1,7 +1,7 @@ | ||||
| #/*******************************************************************
 | ||||
| # * This file is part of the Emulex Linux Device Driver for         *
 | ||||
| # * Fibre Channel Host Bus Adapters.                                *
 | ||||
| # * Copyright (C) 2004-2005 Emulex.  All rights reserved.           *
 | ||||
| # * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
 | ||||
| # * EMULEX and SLI are trademarks of Emulex.                        *
 | ||||
| # * www.emulex.com                                                  *
 | ||||
| # *                                                                 *
 | ||||
| @ -27,4 +27,5 @@ endif | ||||
| obj-$(CONFIG_SCSI_LPFC) := lpfc.o | ||||
| 
 | ||||
| lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
 | ||||
| 	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o | ||||
| 	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
 | ||||
| 	lpfc_vport.o | ||||
|  | ||||
| @ -34,6 +34,17 @@ struct lpfc_sli2_slim; | ||||
| #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */ | ||||
| #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Following time intervals are used of adjusting SCSI device | ||||
|  * queue depths when there are driver resource error or Firmware | ||||
|  * resource error. | ||||
|  */ | ||||
| #define QUEUE_RAMP_DOWN_INTERVAL	(1 * HZ)   /* 1 Second */ | ||||
| #define QUEUE_RAMP_UP_INTERVAL		(300 * HZ) /* 5 minutes */ | ||||
| 
 | ||||
| /* Number of exchanges reserved for discovery to complete */ | ||||
| #define LPFC_DISC_IOCB_BUFF_COUNT 20 | ||||
| 
 | ||||
| /* Define macros for 64 bit support */ | ||||
| #define putPaddrLow(addr)    ((uint32_t) (0xffffffff & (u64)(addr))) | ||||
| #define putPaddrHigh(addr)   ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) | ||||
| @ -97,6 +108,29 @@ typedef struct lpfc_vpd { | ||||
| 		uint32_t sli2FwRev; | ||||
| 		uint8_t sli2FwName[16]; | ||||
| 	} rev; | ||||
| 	struct { | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 		uint32_t rsvd2  :24;  /* Reserved                             */ | ||||
| 		uint32_t cmv	: 1;  /* Configure Max VPIs                   */ | ||||
| 		uint32_t ccrp   : 1;  /* Config Command Ring Polling          */ | ||||
| 		uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */ | ||||
| 		uint32_t chbs   : 1;  /* Cofigure Host Backing store          */ | ||||
| 		uint32_t cinb   : 1;  /* Enable Interrupt Notification Block  */ | ||||
| 		uint32_t cerbm	: 1;  /* Configure Enhanced Receive Buf Mgmt  */ | ||||
| 		uint32_t cmx	: 1;  /* Configure Max XRIs                   */ | ||||
| 		uint32_t cmr	: 1;  /* Configure Max RPIs                   */ | ||||
| #else	/*  __LITTLE_ENDIAN */ | ||||
| 		uint32_t cmr	: 1;  /* Configure Max RPIs                   */ | ||||
| 		uint32_t cmx	: 1;  /* Configure Max XRIs                   */ | ||||
| 		uint32_t cerbm	: 1;  /* Configure Enhanced Receive Buf Mgmt  */ | ||||
| 		uint32_t cinb   : 1;  /* Enable Interrupt Notification Block  */ | ||||
| 		uint32_t chbs   : 1;  /* Cofigure Host Backing store          */ | ||||
| 		uint32_t csah   : 1;  /* Configure Synchronous Abort Handling */ | ||||
| 		uint32_t ccrp   : 1;  /* Config Command Ring Polling          */ | ||||
| 		uint32_t cmv	: 1;  /* Configure Max VPIs                   */ | ||||
| 		uint32_t rsvd2  :24;  /* Reserved                             */ | ||||
| #endif | ||||
| 	} sli3Feat; | ||||
| } lpfc_vpd_t; | ||||
| 
 | ||||
| struct lpfc_scsi_buf; | ||||
| @ -129,6 +163,7 @@ struct lpfc_stats { | ||||
| 	uint32_t elsRcvRPS; | ||||
| 	uint32_t elsRcvRPL; | ||||
| 	uint32_t elsXmitFLOGI; | ||||
| 	uint32_t elsXmitFDISC; | ||||
| 	uint32_t elsXmitPLOGI; | ||||
| 	uint32_t elsXmitPRLI; | ||||
| 	uint32_t elsXmitADISC; | ||||
| @ -174,18 +209,21 @@ struct lpfc_sysfs_mbox { | ||||
| 
 | ||||
| struct lpfc_hba; | ||||
| 
 | ||||
| 
 | ||||
| enum discovery_state { | ||||
| 	LPFC_STATE_UNKNOWN   =  0,    /* HBA state is unknown */ | ||||
| 	LPFC_LOCAL_CFG_LINK  =  6,    /* local NPORT Id configured */ | ||||
| 	LPFC_FLOGI           =  7,    /* FLOGI sent to Fabric */ | ||||
| 	LPFC_FABRIC_CFG_LINK =  8,    /* Fabric assigned NPORT Id
 | ||||
| 				       * configured */ | ||||
| 	LPFC_NS_REG          =  9,    /* Register with NameServer */ | ||||
| 	LPFC_NS_QRY          =  10,   /* Query NameServer for NPort ID list */ | ||||
| 	LPFC_BUILD_DISC_LIST =  11,   /* Build ADISC and PLOGI lists for
 | ||||
| 				       * device authentication / discovery */ | ||||
| 	LPFC_DISC_AUTH       =  12,   /* Processing ADISC list */ | ||||
| 	LPFC_VPORT_READY     =  32, | ||||
| 	LPFC_VPORT_UNKNOWN     =  0,    /* vport state is unknown */ | ||||
| 	LPFC_VPORT_FAILED      =  1,    /* vport has failed */ | ||||
| 	LPFC_LOCAL_CFG_LINK    =  6,    /* local NPORT Id configured */ | ||||
| 	LPFC_FLOGI             =  7,    /* FLOGI sent to Fabric */ | ||||
| 	LPFC_FDISC             =  8,    /* FDISC sent for vport */ | ||||
| 	LPFC_FABRIC_CFG_LINK   =  9,    /* Fabric assigned NPORT Id
 | ||||
| 				         * configured */ | ||||
| 	LPFC_NS_REG            =  10,   /* Register with NameServer */ | ||||
| 	LPFC_NS_QRY            =  11,   /* Query NameServer for NPort ID list */ | ||||
| 	LPFC_BUILD_DISC_LIST   =  12,   /* Build ADISC and PLOGI lists for
 | ||||
| 				         * device authentication / discovery */ | ||||
| 	LPFC_DISC_AUTH         =  13,   /* Processing ADISC list */ | ||||
| 	LPFC_VPORT_READY       =  32, | ||||
| }; | ||||
| 
 | ||||
| enum hba_state { | ||||
| @ -195,8 +233,9 @@ enum hba_state { | ||||
| 	LPFC_INIT_MBX_CMDS   =   3,   /* Initialize HBA with mbox commands */ | ||||
| 	LPFC_LINK_DOWN       =   4,   /* HBA initialized, link is down */ | ||||
| 	LPFC_LINK_UP         =   5,   /* Link is up  - issue READ_LA */ | ||||
| 	LPFC_CLEAR_LA        =  13,   /* authentication cmplt - issue
 | ||||
| 	LPFC_CLEAR_LA        =   6,   /* authentication cmplt - issue
 | ||||
| 				       * CLEAR_LA */ | ||||
| 	LPFC_HBA_READY       =  32, | ||||
| 	LPFC_HBA_ERROR       =  -1 | ||||
| }; | ||||
| 
 | ||||
| @ -209,26 +248,30 @@ struct lpfc_vport { | ||||
| #define LPFC_FABRIC_PORT 3 | ||||
| 	enum discovery_state port_state; | ||||
| 
 | ||||
| 	uint16_t vpi; | ||||
| 
 | ||||
| 	uint32_t fc_flag;	/* FC flags */ | ||||
| /* Several of these flags are HBA centric and should be moved to
 | ||||
|  * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP) | ||||
|  */ | ||||
| #define FC_PT2PT                0x1	/* pt2pt with no fabric */ | ||||
| #define FC_PT2PT_PLOGI          0x2	/* pt2pt initiate PLOGI */ | ||||
| #define FC_DISC_TMO             0x4	/* Discovery timer running */ | ||||
| #define FC_PUBLIC_LOOP          0x8	/* Public loop */ | ||||
| #define FC_LBIT                 0x10	/* LOGIN bit in loopinit set */ | ||||
| #define FC_RSCN_MODE            0x20	/* RSCN cmd rcv'ed */ | ||||
| #define FC_NLP_MORE             0x40	/* More node to process in node tbl */ | ||||
| #define FC_OFFLINE_MODE         0x80	/* Interface is offline for diag */ | ||||
| #define FC_FABRIC               0x100	/* We are fabric attached */ | ||||
| #define FC_ESTABLISH_LINK       0x200	/* Reestablish Link */ | ||||
| #define FC_RSCN_DISCOVERY       0x400	/* Authenticate all devices after RSCN*/ | ||||
| #define FC_SCSI_SCAN_TMO        0x4000	/* scsi scan timer running */ | ||||
| #define FC_ABORT_DISCOVERY      0x8000	/* we want to abort discovery */ | ||||
| #define FC_NDISC_ACTIVE         0x10000	/* NPort discovery active */ | ||||
| #define FC_BYPASSED_MODE        0x20000	/* NPort is in bypassed mode */ | ||||
| #define FC_PT2PT                0x1	 /* pt2pt with no fabric */ | ||||
| #define FC_PT2PT_PLOGI          0x2	 /* pt2pt initiate PLOGI */ | ||||
| #define FC_DISC_TMO             0x4	 /* Discovery timer running */ | ||||
| #define FC_PUBLIC_LOOP          0x8	 /* Public loop */ | ||||
| #define FC_LBIT                 0x10	 /* LOGIN bit in loopinit set */ | ||||
| #define FC_RSCN_MODE            0x20	 /* RSCN cmd rcv'ed */ | ||||
| #define FC_NLP_MORE             0x40	 /* More node to process in node tbl */ | ||||
| #define FC_OFFLINE_MODE         0x80	 /* Interface is offline for diag */ | ||||
| #define FC_FABRIC               0x100	 /* We are fabric attached */ | ||||
| #define FC_ESTABLISH_LINK       0x200	 /* Reestablish Link */ | ||||
| #define FC_RSCN_DISCOVERY       0x400	 /* Auth all devices after RSCN */ | ||||
| #define FC_SCSI_SCAN_TMO        0x4000	 /* scsi scan timer running */ | ||||
| #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */ | ||||
| #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */ | ||||
| #define FC_BYPASSED_MODE        0x20000	 /* NPort is in bypassed mode */ | ||||
| #define FC_RFF_NOT_SUPPORTED    0x40000	 /* RFF_ID was rejected by switch */ | ||||
| #define FC_VPORT_NEEDS_REG_VPI	0x80000  /* Needs to have its vpi registered */ | ||||
| #define FC_RSCN_DEFERRED	0x100000 /* A deferred RSCN being processed */ | ||||
| 
 | ||||
| 	struct list_head fc_nodes; | ||||
| 
 | ||||
| @ -269,6 +312,9 @@ struct lpfc_vport { | ||||
| #define WORKER_ELS_TMO                 0x2	/* ELS timeout */ | ||||
| #define WORKER_MBOX_TMO                0x4	/* MBOX timeout */ | ||||
| #define WORKER_FDMI_TMO                0x8	/* FDMI timeout */ | ||||
| #define WORKER_FABRIC_BLOCK_TMO        0x10	/* fabric block timout */ | ||||
| #define WORKER_RAMP_DOWN_QUEUE    0x20	/* Decrease Q depth */ | ||||
| #define WORKER_RAMP_UP_QUEUE      0x40	/* Increase Q depth */ | ||||
| 
 | ||||
| 	struct timer_list fc_fdmitmo; | ||||
| 	struct timer_list els_tmofunc; | ||||
| @ -278,10 +324,10 @@ struct lpfc_vport { | ||||
| 	uint8_t load_flag; | ||||
| #define FC_LOADING		0x1	/* HBA in process of loading drvr */ | ||||
| #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */ | ||||
| 
 | ||||
| 	char  *vname;		        /* Application assigned name */ | ||||
| 	struct fc_vport *fc_vport; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct hbq_s { | ||||
| 	uint16_t entry_count;	  /* Current number of HBQ slots */ | ||||
| 	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */ | ||||
| @ -289,33 +335,38 @@ struct hbq_s { | ||||
| 	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ | ||||
| }; | ||||
| 
 | ||||
| #define MAX_HBQS  16 | ||||
| #define LPFC_MAX_HBQS  16 | ||||
| /* this matches the possition in the lpfc_hbq_defs array */ | ||||
| #define LPFC_ELS_HBQ	0 | ||||
| 
 | ||||
| struct lpfc_hba { | ||||
| 	struct lpfc_sli sli; | ||||
| 	uint32_t sli_rev;		/* SLI2 or SLI3 */ | ||||
| 	uint32_t sli3_options;		/* Mask of enabled SLI3 options */ | ||||
| #define LPFC_SLI3_ENABLED	0x01 | ||||
| #define LPFC_SLI3_HBQ_ENABLED	0x02 | ||||
| #define LPFC_SLI3_INB_ENABLED	0x04 | ||||
| #define LPFC_SLI3_ENABLED 	 0x01 | ||||
| #define LPFC_SLI3_HBQ_ENABLED	 0x02 | ||||
| #define LPFC_SLI3_NPIV_ENABLED	 0x04 | ||||
| #define LPFC_SLI3_VPORT_TEARDOWN 0x08 | ||||
| 	uint32_t iocb_cmd_size; | ||||
| 	uint32_t iocb_rsp_size; | ||||
| 
 | ||||
| 	enum hba_state link_state; | ||||
| 	uint32_t link_flag;	/* link state flags */ | ||||
| #define LS_LOOPBACK_MODE        0x40000	/* NPort is in Loopback mode */ | ||||
| #define LS_LOOPBACK_MODE      0x1 	/* NPort is in Loopback mode */ | ||||
| 					/* This flag is set while issuing */ | ||||
| 					/* INIT_LINK mailbox command */ | ||||
| #define LS_IGNORE_ERATT         0x80000	/* intr handler should ignore ERATT */ | ||||
| #define LS_NPIV_FAB_SUPPORTED 0x2	/* Fabric supports NPIV */ | ||||
| #define LS_IGNORE_ERATT       0x3	/* intr handler should ignore ERATT */ | ||||
| 
 | ||||
| 	struct lpfc_sli2_slim *slim2p; | ||||
| 	struct lpfc_dmabuf hbqslimp; | ||||
| 
 | ||||
| 	dma_addr_t slim2p_mapping; | ||||
| 
 | ||||
| 
 | ||||
| 	uint16_t pci_cfg_value; | ||||
| 
 | ||||
| 	uint8_t work_found; | ||||
| #define LPFC_MAX_WORKER_ITERATION  4 | ||||
| 
 | ||||
| 	uint8_t fc_linkspeed;	/* Link speed after last READ_LA */ | ||||
| 
 | ||||
| @ -325,7 +376,7 @@ struct lpfc_hba { | ||||
| 	struct timer_list fc_estabtmo;	/* link establishment timer */ | ||||
| 	/* These fields used to be binfo */ | ||||
| 	uint32_t fc_pref_DID;	/* preferred D_ID */ | ||||
| 	uint8_t fc_pref_ALPA;	/* preferred AL_PA */ | ||||
| 	uint8_t  fc_pref_ALPA;	/* preferred AL_PA */ | ||||
| 	uint32_t fc_edtov;	/* E_D_TOV timer value */ | ||||
| 	uint32_t fc_arbtov;	/* ARB_TOV timer value */ | ||||
| 	uint32_t fc_ratov;	/* R_A_TOV timer value */ | ||||
| @ -355,6 +406,8 @@ struct lpfc_hba { | ||||
| 	uint32_t cfg_nodev_tmo; | ||||
| 	uint32_t cfg_devloss_tmo; | ||||
| 	uint32_t cfg_hba_queue_depth; | ||||
| 	uint32_t cfg_peer_port_login; | ||||
| 	uint32_t cfg_vport_restrict_login; | ||||
| 	uint32_t cfg_fcp_class; | ||||
| 	uint32_t cfg_use_adisc; | ||||
| 	uint32_t cfg_ack0; | ||||
| @ -391,11 +444,9 @@ struct lpfc_hba { | ||||
| 	wait_queue_head_t    *work_wait; | ||||
| 	struct task_struct   *worker_thread; | ||||
| 
 | ||||
| 	struct   hbq_dmabuf *hbq_buffer_pool; | ||||
| 	uint32_t hbq_buffer_count; | ||||
| 	uint32_t hbq_buff_count; 	/* Current hbq buffers */ | ||||
| 	struct list_head hbq_buffer_list; | ||||
| 	uint32_t hbq_count;	        /* Count of configured HBQs */ | ||||
| 	struct hbq_s hbqs[MAX_HBQS];    /* local copy of hbq indicies  */ | ||||
| 	struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */ | ||||
| 
 | ||||
| 	unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */ | ||||
| 	unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */ | ||||
| @ -413,7 +464,7 @@ struct lpfc_hba { | ||||
| 
 | ||||
| 	struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */ | ||||
| 	uint32_t __iomem  *hbq_put;     /* Address in SLIM to HBQ put ptrs */ | ||||
| 	uint32_t __iomem  *hbq_get;     /* Address in SLIM to HBQ get ptrs */ | ||||
| 	uint32_t          *hbq_get;     /* Host mem address of HBQ get ptrs */ | ||||
| 
 | ||||
| 	int brd_no;			/* FC board number */ | ||||
| 
 | ||||
| @ -464,6 +515,22 @@ struct lpfc_hba { | ||||
| 	struct fc_host_statistics link_stats; | ||||
| 	struct list_head port_list; | ||||
| 	struct lpfc_vport *pport; /* physical lpfc_vport pointer */ | ||||
| 	uint16_t max_vpi;	/* Maximum virtual nports */ | ||||
| 	uint16_t vpi_cnt;	/* Nport count */ | ||||
| #define LPFC_MAX_VPI 100  /* Max number of VPorts supported */ | ||||
| 	unsigned long *vpi_bmask; /* vpi allocation table */ | ||||
| 
 | ||||
| 	/* Data structure used by fabric iocb scheduler */ | ||||
| 	struct list_head fabric_iocb_list; | ||||
| 	atomic_t fabric_iocb_count; | ||||
| 	struct timer_list fabric_block_timer; | ||||
| 	unsigned long bit_flags; | ||||
| #define	FABRIC_COMANDS_BLOCKED	0 | ||||
| 	atomic_t num_rsrc_err; | ||||
| 	atomic_t num_cmd_success; | ||||
| 	unsigned long last_rsrc_error_time; | ||||
| 	unsigned long last_ramp_down_time; | ||||
| 	unsigned long last_ramp_up_time; | ||||
| }; | ||||
| 
 | ||||
| static inline struct Scsi_Host * | ||||
| @ -485,10 +552,9 @@ static inline int | ||||
| lpfc_is_link_up(struct lpfc_hba *phba) | ||||
| { | ||||
| 	return  phba->link_state == LPFC_LINK_UP || | ||||
| 		phba->link_state == LPFC_CLEAR_LA; | ||||
| 		phba->link_state == LPFC_CLEAR_LA || | ||||
| 		phba->link_state == LPFC_HBA_READY; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #define FC_REG_DUMP_EVENT	0x10	/* Register for Dump events */ | ||||
| 
 | ||||
|  | ||||
| @ -39,6 +39,7 @@ | ||||
| #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 | ||||
| @ -139,7 +140,7 @@ lpfc_fwrev_show(struct class_device *cdev, char *buf) | ||||
| 	char fwrev[32]; | ||||
| 
 | ||||
| 	lpfc_decode_firmware_rev(phba, fwrev, 1); | ||||
| 	return snprintf(buf, PAGE_SIZE, "%s\n",fwrev); | ||||
| 	return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| @ -178,10 +179,11 @@ lpfc_state_show(struct class_device *cdev, char *buf) | ||||
| 	case LPFC_INIT_MBX_CMDS: | ||||
| 	case LPFC_LINK_DOWN: | ||||
| 	case LPFC_HBA_ERROR: | ||||
| 		len += snprintf(buf + len, PAGE_SIZE-len, "Link Down"); | ||||
| 		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) { | ||||
| @ -190,8 +192,9 @@ lpfc_state_show(struct class_device *cdev, char *buf) | ||||
| 			break; | ||||
| 		case LPFC_LOCAL_CFG_LINK: | ||||
| 			len += snprintf(buf + len, PAGE_SIZE-len, | ||||
| 					"configuring\n"); | ||||
| 					"Configuring Link\n"); | ||||
| 			break; | ||||
| 		case LPFC_FDISC: | ||||
| 		case LPFC_FLOGI: | ||||
| 		case LPFC_FABRIC_CFG_LINK: | ||||
| 		case LPFC_NS_REG: | ||||
| @ -205,7 +208,11 @@ lpfc_state_show(struct class_device *cdev, char *buf) | ||||
| 			len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n"); | ||||
| 			break; | ||||
| 
 | ||||
| 		case LPFC_STATE_UNKNOWN: | ||||
| 		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; | ||||
| @ -432,6 +439,151 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) | ||||
| 		return -EIO; | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_max_vpi_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->max_vpi); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_used_vpi_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; | ||||
| 
 | ||||
| 	/* Don't count the physical port */ | ||||
| 	return snprintf(buf, PAGE_SIZE, "%d\n", phba->vpi_cnt-1); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, | ||||
| 	uint32_t *axri, uint32_t *mrpi, uint32_t *arpi) | ||||
| { | ||||
| 	struct lpfc_sli   *psli = &phba->sli; | ||||
| 	LPFC_MBOXQ_t *pmboxq; | ||||
| 	MAILBOX_t *pmb; | ||||
| 	int rc = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * prevent udev from issuing mailbox commands until the port is | ||||
| 	 * configured. | ||||
| 	 */ | ||||
| 	if (phba->link_state < LPFC_LINK_DOWN || | ||||
| 	    !phba->mbox_mem_pool || | ||||
| 	    (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||||
| 	if (!pmboxq) | ||||
| 		return 0; | ||||
| 	memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); | ||||
| 
 | ||||
| 	pmb = &pmboxq->mb; | ||||
| 	pmb->mbxCommand = MBX_READ_CONFIG; | ||||
| 	pmb->mbxOwner = OWN_HOST; | ||||
| 	pmboxq->context1 = NULL; | ||||
| 
 | ||||
| 	if ((phba->pport->fc_flag & FC_OFFLINE_MODE) || | ||||
| 		(!(psli->sli_flag & LPFC_SLI2_ACTIVE))) | ||||
| 		rc = MBX_NOT_FINISHED; | ||||
| 	else | ||||
| 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); | ||||
| 
 | ||||
| 	if (rc != MBX_SUCCESS) { | ||||
| 		if (rc == MBX_TIMEOUT) | ||||
| 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||||
| 		else | ||||
| 			mempool_free(pmboxq, phba->mbox_mem_pool); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mrpi) | ||||
| 		*mrpi = pmb->un.varRdConfig.max_rpi; | ||||
| 	if (arpi) | ||||
| 		*arpi = pmb->un.varRdConfig.avail_rpi; | ||||
| 	if (mxri) | ||||
| 		*mxri = pmb->un.varRdConfig.max_xri; | ||||
| 	if (axri) | ||||
| 		*axri = pmb->un.varRdConfig.avail_xri; | ||||
| 
 | ||||
| 	mempool_free(pmboxq, phba->mbox_mem_pool); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_max_rpi_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; | ||||
| 	uint32_t cnt; | ||||
| 
 | ||||
| 	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL)) | ||||
| 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt); | ||||
| 	return snprintf(buf, PAGE_SIZE, "Unknown\n"); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_used_rpi_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; | ||||
| 	uint32_t cnt, acnt; | ||||
| 
 | ||||
| 	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt)) | ||||
| 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); | ||||
| 	return snprintf(buf, PAGE_SIZE, "Unknown\n"); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_max_xri_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; | ||||
| 	uint32_t cnt; | ||||
| 
 | ||||
| 	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL)) | ||||
| 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt); | ||||
| 	return snprintf(buf, PAGE_SIZE, "Unknown\n"); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_used_xri_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; | ||||
| 	uint32_t cnt, acnt; | ||||
| 
 | ||||
| 	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL)) | ||||
| 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); | ||||
| 	return snprintf(buf, PAGE_SIZE, "Unknown\n"); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_npiv_info_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; | ||||
| 
 | ||||
| 	if (!(phba->max_vpi)) | ||||
| 		return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n"); | ||||
| 	if (vport->port_type == LPFC_PHYSICAL_PORT) | ||||
| 		return snprintf(buf, PAGE_SIZE, "NPIV Physical\n"); | ||||
| 	return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| lpfc_poll_show(struct class_device *cdev, char *buf) | ||||
| { | ||||
| @ -640,6 +792,13 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, | ||||
| static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, | ||||
| 			 lpfc_board_mode_show, lpfc_board_mode_store); | ||||
| static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); | ||||
| static CLASS_DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(max_rpi, S_IRUGO, lpfc_max_rpi_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); | ||||
| static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); | ||||
| 
 | ||||
| 
 | ||||
| static char *lpfc_soft_wwn_key = "C99G71SL8032A"; | ||||
| @ -829,6 +988,17 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:" | ||||
| static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR, | ||||
| 			 lpfc_poll_show, lpfc_poll_store); | ||||
| 
 | ||||
| int  lpfc_sli_mode = 0; | ||||
| module_param(lpfc_sli_mode, int, 0); | ||||
| MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" | ||||
| 		 " 0 - auto (SLI-3 if supported)," | ||||
| 		 " 2 - select SLI-2 even on SLI-3 capable HBAs," | ||||
| 		 " 3 - select SLI-3"); | ||||
| 
 | ||||
| int  lpfc_npiv_enable = 0; | ||||
| module_param(lpfc_npiv_enable, int, 0); | ||||
| MODULE_PARM_DESC(lpfc_npiv_enable, "Enable NPIV functionality"); | ||||
| 
 | ||||
| /*
 | ||||
| # 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 30. | ||||
| @ -984,6 +1154,33 @@ LPFC_ATTR_R(lun_queue_depth, 30, 1, 128, | ||||
| LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192, | ||||
| 	    "Max number of FCP commands we can queue to a lpfc HBA"); | ||||
| 
 | ||||
| /*
 | ||||
| # peer_port_login:  This parameter allows/prevents logins | ||||
| # between peer ports hosted on the same physical port. | ||||
| # When this parameter is set 0 peer ports of same physical port | ||||
| # are not allowed to login to each other. | ||||
| # When this parameter is set 1 peer ports of same physical port | ||||
| # are allowed to login to each other. | ||||
| # Default value of this parameter is 0. | ||||
| */ | ||||
| LPFC_ATTR_R(peer_port_login, 0, 0, 1, | ||||
| 	    "Allow peer ports on the same physical port to login to each " | ||||
| 	    "other."); | ||||
| 
 | ||||
| /*
 | ||||
| # vport_restrict_login:  This parameter allows/prevents logins | ||||
| # between Virtual Ports and remote initiators. | ||||
| # When this parameter is not set (0) Virtual Ports will accept PLOGIs from | ||||
| # other initiators and will attempt to PLOGI all remote ports. | ||||
| # When this parameter is set (1) Virtual Ports will reject PLOGIs from | ||||
| # remote ports and will not attempt to PLOGI to other initiators. | ||||
| # This parameter does not restrict to the physical port. | ||||
| # This parameter does not restrict logins to Fabric resident remote ports. | ||||
| # Default value of this parameter is 1. | ||||
| */ | ||||
| LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1, | ||||
| 	    "Restrict virtual ports login to remote initiators."); | ||||
| 
 | ||||
| /*
 | ||||
| # Some disk devices have a "select ID" or "select Target" capability. | ||||
| # From a protocol standpoint "select ID" usually means select the | ||||
| @ -1127,6 +1324,7 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, | ||||
| LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct class_device_attribute *lpfc_hba_attrs[] = { | ||||
| 	&class_device_attr_info, | ||||
| 	&class_device_attr_serialnum, | ||||
| @ -1143,6 +1341,8 @@ struct class_device_attribute *lpfc_hba_attrs[] = { | ||||
| 	&class_device_attr_lpfc_log_verbose, | ||||
| 	&class_device_attr_lpfc_lun_queue_depth, | ||||
| 	&class_device_attr_lpfc_hba_queue_depth, | ||||
| 	&class_device_attr_lpfc_peer_port_login, | ||||
| 	&class_device_attr_lpfc_vport_restrict_login, | ||||
| 	&class_device_attr_lpfc_nodev_tmo, | ||||
| 	&class_device_attr_lpfc_devloss_tmo, | ||||
| 	&class_device_attr_lpfc_fcp_class, | ||||
| @ -1161,6 +1361,13 @@ struct class_device_attribute *lpfc_hba_attrs[] = { | ||||
| 	&class_device_attr_nport_evt_cnt, | ||||
| 	&class_device_attr_management_version, | ||||
| 	&class_device_attr_board_mode, | ||||
| 	&class_device_attr_max_vpi, | ||||
| 	&class_device_attr_used_vpi, | ||||
| 	&class_device_attr_max_rpi, | ||||
| 	&class_device_attr_used_rpi, | ||||
| 	&class_device_attr_max_xri, | ||||
| 	&class_device_attr_used_xri, | ||||
| 	&class_device_attr_npiv_info, | ||||
| 	&class_device_attr_issue_reset, | ||||
| 	&class_device_attr_lpfc_poll, | ||||
| 	&class_device_attr_lpfc_poll_tmo, | ||||
| @ -1299,7 +1506,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||||
| 	} else { | ||||
| 		if (phba->sysfs_mbox.state  != SMBOX_WRITING || | ||||
| 		    phba->sysfs_mbox.offset != off           || | ||||
| 		    phba->sysfs_mbox.mbox   == NULL ) { | ||||
| 		    phba->sysfs_mbox.mbox   == NULL) { | ||||
| 			sysfs_mbox_idle(phba); | ||||
| 			spin_unlock_irq(&phba->hbalock); | ||||
| 			return -EAGAIN; | ||||
| @ -1406,6 +1613,8 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||||
| 			return -EPERM; | ||||
| 		} | ||||
| 
 | ||||
| 		phba->sysfs_mbox.mbox->vport = vport; | ||||
| 
 | ||||
| 		if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { | ||||
| 			sysfs_mbox_idle(phba); | ||||
| 			spin_unlock_irq(&phba->hbalock); | ||||
| @ -1480,12 +1689,12 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) | ||||
| 	int error; | ||||
| 
 | ||||
| 	error = sysfs_create_bin_file(&shost->shost_classdev.kobj, | ||||
| 							&sysfs_ctlreg_attr); | ||||
| 				      &sysfs_ctlreg_attr); | ||||
| 	if (error) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	error = sysfs_create_bin_file(&shost->shost_classdev.kobj, | ||||
| 							&sysfs_mbox_attr); | ||||
| 				      &sysfs_mbox_attr); | ||||
| 	if (error) | ||||
| 		goto out_remove_ctlreg_attr; | ||||
| 
 | ||||
| @ -1527,7 +1736,9 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) | ||||
| 
 | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 
 | ||||
| 	if (lpfc_is_link_up(phba)) { | ||||
| 	if (vport->port_type == LPFC_NPIV_PORT) { | ||||
| 		fc_host_port_type(shost) = FC_PORTTYPE_NPIV; | ||||
| 	} else if (lpfc_is_link_up(phba)) { | ||||
| 		if (phba->fc_topology == TOPOLOGY_LOOP) { | ||||
| 			if (vport->fc_flag & FC_PUBLIC_LOOP) | ||||
| 				fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | ||||
| @ -1563,6 +1774,7 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) | ||||
| 			break; | ||||
| 		case LPFC_LINK_UP: | ||||
| 		case LPFC_CLEAR_LA: | ||||
| 		case LPFC_HBA_READY: | ||||
| 			/* Links up, beyond this port_type reports state */ | ||||
| 			fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||||
| 			break; | ||||
| @ -1644,13 +1856,14 @@ lpfc_get_stats(struct Scsi_Host *shost) | ||||
| 	unsigned long seconds; | ||||
| 	int rc = 0; | ||||
| 
 | ||||
| 				/* prevent udev from issuing mailbox commands
 | ||||
| 				 * until the port is configured. | ||||
| 				 */ | ||||
| 	/*
 | ||||
| 	 * prevent udev from issuing mailbox commands until the port is | ||||
| 	 * configured. | ||||
| 	 */ | ||||
| 	if (phba->link_state < LPFC_LINK_DOWN || | ||||
| 	    !phba->mbox_mem_pool || | ||||
| 	    (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0) | ||||
| 			return NULL; | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) | ||||
| 		return NULL; | ||||
| @ -1664,6 +1877,7 @@ lpfc_get_stats(struct Scsi_Host *shost) | ||||
| 	pmb->mbxCommand = MBX_READ_STATUS; | ||||
| 	pmb->mbxOwner = OWN_HOST; | ||||
| 	pmboxq->context1 = NULL; | ||||
| 	pmboxq->vport = vport; | ||||
| 
 | ||||
| 	if ((vport->fc_flag & FC_OFFLINE_MODE) || | ||||
| 		(!(psli->sli_flag & LPFC_SLI2_ACTIVE))) | ||||
| @ -1690,6 +1904,7 @@ lpfc_get_stats(struct Scsi_Host *shost) | ||||
| 	pmb->mbxCommand = MBX_READ_LNK_STAT; | ||||
| 	pmb->mbxOwner = OWN_HOST; | ||||
| 	pmboxq->context1 = NULL; | ||||
| 	pmboxq->vport = vport; | ||||
| 
 | ||||
| 	if ((vport->fc_flag & FC_OFFLINE_MODE) || | ||||
| 	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) | ||||
| @ -1701,7 +1916,7 @@ lpfc_get_stats(struct Scsi_Host *shost) | ||||
| 		if (rc == MBX_TIMEOUT) | ||||
| 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||||
| 		else | ||||
| 			mempool_free( pmboxq, phba->mbox_mem_pool); | ||||
| 			mempool_free(pmboxq, phba->mbox_mem_pool); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| @ -1769,6 +1984,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) | ||||
| 	pmb->mbxOwner = OWN_HOST; | ||||
| 	pmb->un.varWords[0] = 0x1; /* reset request */ | ||||
| 	pmboxq->context1 = NULL; | ||||
| 	pmboxq->vport = vport; | ||||
| 
 | ||||
| 	if ((vport->fc_flag & FC_OFFLINE_MODE) || | ||||
| 		(!(psli->sli_flag & LPFC_SLI2_ACTIVE))) | ||||
| @ -1788,6 +2004,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) | ||||
| 	pmb->mbxCommand = MBX_READ_LNK_STAT; | ||||
| 	pmb->mbxOwner = OWN_HOST; | ||||
| 	pmboxq->context1 = NULL; | ||||
| 	pmboxq->vport = vport; | ||||
| 
 | ||||
| 	if ((vport->fc_flag & FC_OFFLINE_MODE) || | ||||
| 	    (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) | ||||
| @ -1950,6 +2167,69 @@ struct fc_function_template lpfc_transport_functions = { | ||||
| 	.issue_fc_host_lip = lpfc_issue_lip, | ||||
| 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, | ||||
| 	.terminate_rport_io = lpfc_terminate_rport_io, | ||||
| 
 | ||||
| 	.vport_create = lpfc_vport_create, | ||||
| 	.vport_delete = lpfc_vport_delete, | ||||
| 	.dd_fcvport_size = sizeof(struct lpfc_vport *), | ||||
| }; | ||||
| 
 | ||||
| struct fc_function_template lpfc_vport_transport_functions = { | ||||
| 	/* fixed attributes the driver supports */ | ||||
| 	.show_host_node_name = 1, | ||||
| 	.show_host_port_name = 1, | ||||
| 	.show_host_supported_classes = 1, | ||||
| 	.show_host_supported_fc4s = 1, | ||||
| 	.show_host_supported_speeds = 1, | ||||
| 	.show_host_maxframe_size = 1, | ||||
| 
 | ||||
| 	/* dynamic attributes the driver supports */ | ||||
| 	.get_host_port_id = lpfc_get_host_port_id, | ||||
| 	.show_host_port_id = 1, | ||||
| 
 | ||||
| 	.get_host_port_type = lpfc_get_host_port_type, | ||||
| 	.show_host_port_type = 1, | ||||
| 
 | ||||
| 	.get_host_port_state = lpfc_get_host_port_state, | ||||
| 	.show_host_port_state = 1, | ||||
| 
 | ||||
| 	/* active_fc4s is shown but doesn't change (thus no get function) */ | ||||
| 	.show_host_active_fc4s = 1, | ||||
| 
 | ||||
| 	.get_host_speed = lpfc_get_host_speed, | ||||
| 	.show_host_speed = 1, | ||||
| 
 | ||||
| 	.get_host_fabric_name = lpfc_get_host_fabric_name, | ||||
| 	.show_host_fabric_name = 1, | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The LPFC driver treats linkdown handling as target loss events | ||||
| 	 * so there are no sysfs handlers for link_down_tmo. | ||||
| 	 */ | ||||
| 
 | ||||
| 	.get_fc_host_stats = lpfc_get_stats, | ||||
| 	.reset_fc_host_stats = lpfc_reset_stats, | ||||
| 
 | ||||
| 	.dd_fcrport_size = sizeof(struct lpfc_rport_data), | ||||
| 	.show_rport_maxframe_size = 1, | ||||
| 	.show_rport_supported_classes = 1, | ||||
| 
 | ||||
| 	.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo, | ||||
| 	.show_rport_dev_loss_tmo = 1, | ||||
| 
 | ||||
| 	.get_starget_port_id  = lpfc_get_starget_port_id, | ||||
| 	.show_starget_port_id = 1, | ||||
| 
 | ||||
| 	.get_starget_node_name = lpfc_get_starget_node_name, | ||||
| 	.show_starget_node_name = 1, | ||||
| 
 | ||||
| 	.get_starget_port_name = lpfc_get_starget_port_name, | ||||
| 	.show_starget_port_name = 1, | ||||
| 
 | ||||
| 	.issue_fc_host_lip = lpfc_issue_lip, | ||||
| 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, | ||||
| 	.terminate_rport_io = lpfc_terminate_rport_io, | ||||
| 
 | ||||
| 	.vport_disable = lpfc_vport_disable, | ||||
| }; | ||||
| 
 | ||||
| void | ||||
| @ -1972,6 +2252,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) | ||||
| 	lpfc_discovery_threads_init(phba, lpfc_discovery_threads); | ||||
| 	lpfc_max_luns_init(phba, lpfc_max_luns); | ||||
| 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo); | ||||
| 	lpfc_peer_port_login_init(phba, lpfc_peer_port_login); | ||||
| 	lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login); | ||||
| 	lpfc_use_msi_init(phba, lpfc_use_msi); | ||||
| 	lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo); | ||||
| 	lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo); | ||||
|  | ||||
| @ -28,15 +28,18 @@ int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, | ||||
| void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport); | ||||
| void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); | ||||
| void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *, | ||||
| 		   uint32_t); | ||||
| void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *); | ||||
| void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *); | ||||
| int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, | ||||
| 		   LPFC_MBOXQ_t *, uint32_t); | ||||
| void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); | ||||
| void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); | ||||
| void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); | ||||
| void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); | ||||
| void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); | ||||
| 
 | ||||
| void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); | ||||
| int lpfc_linkdown(struct lpfc_hba *); | ||||
| void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| 
 | ||||
| @ -51,6 +54,10 @@ void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); | ||||
| void lpfc_set_disctmo(struct lpfc_vport *); | ||||
| int  lpfc_can_disctmo(struct lpfc_vport *); | ||||
| int  lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *); | ||||
| void lpfc_unreg_all_rpis(struct lpfc_vport *); | ||||
| void lpfc_unreg_default_rpis(struct lpfc_vport *); | ||||
| void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *); | ||||
| 
 | ||||
| int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, | ||||
| 			struct lpfc_iocbq *, struct lpfc_nodelist *); | ||||
| void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t); | ||||
| @ -60,25 +67,33 @@ struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); | ||||
| void lpfc_disc_list_loopmap(struct lpfc_vport *); | ||||
| void lpfc_disc_start(struct lpfc_vport *); | ||||
| void lpfc_disc_flush_list(struct lpfc_vport *); | ||||
| void lpfc_cleanup_discovery_resources(struct lpfc_vport *); | ||||
| void lpfc_disc_timeout(unsigned long); | ||||
| 
 | ||||
| struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); | ||||
| struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); | ||||
| 
 | ||||
| void lpfc_worker_wake_up(struct lpfc_hba *); | ||||
| int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); | ||||
| int lpfc_do_work(void *); | ||||
| int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, | ||||
| 			    uint32_t); | ||||
| 
 | ||||
| void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, | ||||
| 			struct lpfc_nodelist *); | ||||
| void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); | ||||
| int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, | ||||
| 		     struct serv_parm *, uint32_t); | ||||
| int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp); | ||||
| int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); | ||||
| int lpfc_els_abort_flogi(struct lpfc_hba *); | ||||
| int lpfc_initial_flogi(struct lpfc_vport *); | ||||
| int lpfc_initial_fdisc(struct lpfc_vport *); | ||||
| int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); | ||||
| int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t); | ||||
| int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); | ||||
| int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); | ||||
| int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); | ||||
| int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); | ||||
| int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); | ||||
| int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); | ||||
| int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, | ||||
| @ -95,7 +110,7 @@ void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); | ||||
| void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, | ||||
| 			  struct lpfc_iocbq *); | ||||
| int lpfc_els_handle_rscn(struct lpfc_vport *); | ||||
| int lpfc_els_flush_rscn(struct lpfc_vport *); | ||||
| void lpfc_els_flush_rscn(struct lpfc_vport *); | ||||
| int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t); | ||||
| void lpfc_els_flush_cmd(struct lpfc_vport *); | ||||
| int lpfc_els_disc_adisc(struct lpfc_vport *); | ||||
| @ -105,7 +120,7 @@ void lpfc_els_timeout_handler(struct lpfc_vport *); | ||||
| 
 | ||||
| void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, | ||||
| 			 struct lpfc_iocbq *); | ||||
| int lpfc_ns_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); | ||||
| int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); | ||||
| int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); | ||||
| void lpfc_fdmi_tmo(unsigned long); | ||||
| void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport); | ||||
| @ -136,6 +151,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); | ||||
| void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); | ||||
| int lpfc_mbox_tmo_val(struct lpfc_hba *, int); | ||||
| 
 | ||||
| void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t , | ||||
| @ -144,6 +160,7 @@ struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t); | ||||
| 
 | ||||
| int lpfc_mem_alloc(struct lpfc_hba *); | ||||
| void lpfc_mem_free(struct lpfc_hba *); | ||||
| void lpfc_stop_vport_timers(struct lpfc_vport *); | ||||
| 
 | ||||
| void lpfc_poll_timeout(unsigned long ptr); | ||||
| void lpfc_poll_start_timer(struct lpfc_hba * phba); | ||||
| @ -176,11 +193,10 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, | ||||
| struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, | ||||
| 					     struct lpfc_sli_ring *, | ||||
| 					     dma_addr_t); | ||||
| int lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *); | ||||
| void lpfc_sli_hbqbuf_free(struct lpfc_hba *, void *, dma_addr_t); | ||||
| int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t); | ||||
| int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); | ||||
| void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); | ||||
| struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t); | ||||
| void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); | ||||
| int lpfc_sli_hbq_size(void); | ||||
| int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, | ||||
| 			       struct lpfc_iocbq *); | ||||
| @ -192,12 +208,15 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, | ||||
| void lpfc_mbox_timeout(unsigned long); | ||||
| void lpfc_mbox_timeout_handler(struct lpfc_hba *); | ||||
| 
 | ||||
| struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter, | ||||
| 				       void *); | ||||
| struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *); | ||||
| struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); | ||||
| struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, | ||||
| 					 struct lpfc_name *); | ||||
| 
 | ||||
| int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, | ||||
| 			 uint32_t timeout); | ||||
| 			     uint32_t timeout); | ||||
| 
 | ||||
| int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, | ||||
| 			     struct lpfc_sli_ring * pring, | ||||
| @ -210,11 +229,13 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, | ||||
| 
 | ||||
| void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *); | ||||
| void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t); | ||||
| void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); | ||||
| 
 | ||||
| void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *); | ||||
| void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); | ||||
| void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); | ||||
| 
 | ||||
| void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); | ||||
| /* Function prototypes. */ | ||||
| const char* lpfc_info(struct Scsi_Host *); | ||||
| void lpfc_scan_start(struct Scsi_Host *); | ||||
| @ -226,14 +247,34 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); | ||||
| extern struct class_device_attribute *lpfc_hba_attrs[]; | ||||
| extern struct scsi_host_template lpfc_template; | ||||
| extern struct fc_function_template lpfc_transport_functions; | ||||
| extern struct fc_function_template lpfc_vport_transport_functions; | ||||
| extern int lpfc_sli_mode; | ||||
| extern int lpfc_npiv_enable; | ||||
| 
 | ||||
| void lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp); | ||||
| int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); | ||||
| void lpfc_terminate_rport_io(struct fc_rport *); | ||||
| void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); | ||||
| 
 | ||||
| struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int); | ||||
| void lpfc_post_hba_setup_vport_init(struct lpfc_vport *); | ||||
| struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *); | ||||
| int  lpfc_vport_disable(struct fc_vport *fc_vport, bool disable); | ||||
| void lpfc_mbx_unreg_vpi(struct lpfc_vport *); | ||||
| void destroy_port(struct lpfc_vport *); | ||||
| int lpfc_get_instance(void); | ||||
| void lpfc_host_attrib_init(struct Scsi_Host *); | ||||
| 
 | ||||
| /* Interface exported by fabric iocb scheduler */ | ||||
| int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *); | ||||
| void lpfc_fabric_abort_vport(struct lpfc_vport *); | ||||
| void lpfc_fabric_abort_nport(struct lpfc_nodelist *); | ||||
| void lpfc_fabric_abort_hba(struct lpfc_hba *); | ||||
| void lpfc_fabric_abort_flogi(struct lpfc_hba *); | ||||
| void lpfc_fabric_block_timeout(unsigned long); | ||||
| void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); | ||||
| void lpfc_adjust_queue_depth(struct lpfc_hba *); | ||||
| void lpfc_ramp_down_queue_handler(struct lpfc_hba *); | ||||
| void lpfc_ramp_up_queue_handler(struct lpfc_hba *); | ||||
| 
 | ||||
| #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) | ||||
| #define HBA_EVENT_RSCN                   5 | ||||
| #define HBA_EVENT_LINK_UP                2 | ||||
| #define HBA_EVENT_LINK_DOWN              3 | ||||
|  | ||||
| @ -40,6 +40,7 @@ | ||||
| #include "lpfc_logmsg.h" | ||||
| #include "lpfc_crtn.h" | ||||
| #include "lpfc_version.h" | ||||
| #include "lpfc_vport.h" | ||||
| 
 | ||||
| #define HBA_PORTSPEED_UNKNOWN               0	/* Unknown - transceiver | ||||
| 						 * incapable of reporting */ | ||||
| @ -74,15 +75,13 @@ lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | ||||
| 	       __FUNCTION__, __LINE__, | ||||
| 	       piocbq, mp, size, | ||||
| 	       piocbq->iocb.ulpStatus); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | ||||
| 			  struct hbq_dmabuf *sp, uint32_t size) | ||||
| 			  struct lpfc_dmabuf *mp, uint32_t size) | ||||
| { | ||||
| 	struct lpfc_dmabuf *mp = NULL; | ||||
| 
 | ||||
| 	mp = sp ? &sp->dbuf : NULL; | ||||
| 	if (!mp) { | ||||
| 		printk(KERN_ERR "%s (%d): Unsolited CT, no " | ||||
| 		       "HBQ buffer, piocbq = %p, status = x%x\n", | ||||
| @ -102,21 +101,26 @@ void | ||||
| lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | ||||
| 		    struct lpfc_iocbq *piocbq) | ||||
| { | ||||
| 
 | ||||
| 	struct lpfc_dmabuf *mp = NULL; | ||||
| 	struct hbq_dmabuf  *sp = NULL; | ||||
| 	IOCB_t *icmd = &piocbq->iocb; | ||||
| 	int i; | ||||
| 	struct lpfc_iocbq *iocbq; | ||||
| 	dma_addr_t paddr; | ||||
| 	uint32_t size; | ||||
| 	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; | ||||
| 	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; | ||||
| 
 | ||||
| 	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||||
| 	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||||
| 	piocbq->context2 = NULL; | ||||
| 	piocbq->context3 = NULL; | ||||
| 
 | ||||
| 	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { | ||||
| 		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); | ||||
| 	} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||||
| 		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||||
| 		/* Not enough posted buffers; Try posting more buffers */ | ||||
| 		phba->fc_stat.NoRcvBuf++; | ||||
| 		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) | ||||
| 			lpfc_sli_hbqbuf_fill_hbq(phba); | ||||
| 		else | ||||
| 		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | ||||
| 			lpfc_post_buffer(phba, pring, 0, 1); | ||||
| 		return; | ||||
| 	} | ||||
| @ -139,23 +143,14 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | ||||
| 			} | ||||
| 
 | ||||
| 			size  = icmd->un.cont64[0].tus.f.bdeSize; | ||||
| 			sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]); | ||||
| 			if (sp) | ||||
| 				phba->hbq_buff_count--; | ||||
| 			lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, size); | ||||
| 			lpfc_sli_free_hbq(phba, sp); | ||||
| 			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size); | ||||
| 			lpfc_in_buf_free(phba, bdeBuf1); | ||||
| 			if (icmd->ulpBdeCount == 2) { | ||||
| 				sp = lpfc_sli_hbqbuf_find(phba, | ||||
| 							  icmd->un.ulpWord[15]); | ||||
| 				if (sp) | ||||
| 					phba->hbq_buff_count--; | ||||
| 				lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, | ||||
| 				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2, | ||||
| 							  size); | ||||
| 				lpfc_sli_free_hbq(phba, sp); | ||||
| 				lpfc_in_buf_free(phba, bdeBuf2); | ||||
| 			} | ||||
| 
 | ||||
| 		} | ||||
| 		lpfc_sli_hbqbuf_fill_hbq(phba); | ||||
| 	} else { | ||||
| 		struct lpfc_iocbq  *next; | ||||
| 
 | ||||
| @ -176,8 +171,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | ||||
| 							      paddr); | ||||
| 				size = icmd->un.cont64[i].tus.f.bdeSize; | ||||
| 				lpfc_ct_unsol_buffer(phba, piocbq, mp, size); | ||||
| 				lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 				kfree(mp); | ||||
| 				lpfc_in_buf_free(phba, mp); | ||||
| 			} | ||||
| 			list_del(&iocbq->list); | ||||
| 			lpfc_sli_release_iocbq(phba, iocbq); | ||||
| @ -222,7 +216,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, | ||||
| 
 | ||||
| 		INIT_LIST_HEAD(&mp->list); | ||||
| 
 | ||||
| 		if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT)) | ||||
| 		if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) || | ||||
| 		    cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID)) | ||||
| 			mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); | ||||
| 		else | ||||
| 			mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); | ||||
| @ -242,8 +237,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, | ||||
| 
 | ||||
| 		bpl->tus.f.bdeFlags = BUFF_USE_RCV; | ||||
| 		/* build buffer ptr list for IOCB */ | ||||
| 		bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||||
| 		bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||||
| 		bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); | ||||
| 		bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); | ||||
| 		bpl->tus.f.bdeSize = (uint16_t) cnt; | ||||
| 		bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||||
| 		bpl++; | ||||
| @ -262,13 +257,14 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, | ||||
| 	     void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||||
| 		     struct lpfc_iocbq *), | ||||
| 	     struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry, | ||||
| 	     uint32_t tmo) | ||||
| 	     uint32_t tmo, uint8_t retry) | ||||
| { | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 	struct lpfc_sli  *psli = &phba->sli; | ||||
| 	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; | ||||
| 	IOCB_t *icmd; | ||||
| 	struct lpfc_iocbq *geniocb; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	/* Allocate buffer for  command iocb */ | ||||
| 	geniocb = lpfc_sli_get_iocbq(phba); | ||||
| @ -311,15 +307,25 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, | ||||
| 	icmd->ulpClass = CLASS3; | ||||
| 	icmd->ulpContext = ndlp->nlp_rpi; | ||||
| 
 | ||||
| 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { | ||||
| 		/* For GEN_REQUEST64_CR, use the RPI */ | ||||
| 		icmd->ulpCt_h = 0; | ||||
| 		icmd->ulpCt_l = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Issue GEN REQ IOCB for NPORT <did> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||||
| 			"%d:0119 Issue GEN REQ IOCB for NPORT x%x " | ||||
| 			"Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5], | ||||
| 			icmd->ulpIoTag, vport->port_state); | ||||
| 			"%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x " | ||||
| 			"Data: x%x x%x\n", phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, icmd->ulpIoTag, | ||||
| 			vport->port_state); | ||||
| 	geniocb->iocb_cmpl = cmpl; | ||||
| 	geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; | ||||
| 	geniocb->vport = vport; | ||||
| 	if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) { | ||||
| 	geniocb->retry = retry; | ||||
| 	rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0); | ||||
| 
 | ||||
| 	if (rc == IOCB_ERROR) { | ||||
| 		lpfc_sli_release_iocbq(phba, geniocb); | ||||
| 		return 1; | ||||
| 	} | ||||
| @ -332,7 +338,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, | ||||
| 	    struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp, | ||||
| 	    void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||||
| 			  struct lpfc_iocbq *), | ||||
| 	    uint32_t rsp_size) | ||||
| 	    uint32_t rsp_size, uint8_t retry) | ||||
| { | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 	struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt; | ||||
| @ -349,7 +355,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0, | ||||
| 			      cnt+1, 0); | ||||
| 			      cnt+1, 0, retry); | ||||
| 	if (status) { | ||||
| 		lpfc_free_ct_rsp(phba, outmp); | ||||
| 		return -ENOMEM; | ||||
| @ -357,10 +363,23 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct lpfc_vport * | ||||
| lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { | ||||
| 
 | ||||
| 	struct lpfc_vport *vport_curr; | ||||
| 
 | ||||
| 	list_for_each_entry(vport_curr, &phba->port_list, listentry) { | ||||
| 		if ((vport_curr->fc_myDID) && | ||||
| 			(vport_curr->fc_myDID == did)) | ||||
| 			return vport_curr; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | ||||
| { | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 	struct lpfc_sli_ct_request *Response = | ||||
| 		(struct lpfc_sli_ct_request *) mp->virt; | ||||
| @ -372,6 +391,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | ||||
| 	struct list_head head; | ||||
| 
 | ||||
| 	lpfc_set_disctmo(vport); | ||||
| 	vport->num_disc_nodes = 0; | ||||
| 
 | ||||
| 
 | ||||
| 	list_add_tail(&head, &mp->list); | ||||
| @ -392,25 +412,64 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | ||||
| 			/* Get next DID from NameServer List */ | ||||
| 			CTentry = *ctptr++; | ||||
| 			Did = ((be32_to_cpu(CTentry)) & Mask_DID); | ||||
| 
 | ||||
| 			ndlp = NULL; | ||||
| 			/* Check for rscn processing or not */ | ||||
| 			if (Did != vport->fc_myDID) | ||||
| 				ndlp = lpfc_setup_disc_node(vport, Did); | ||||
| 			if (ndlp) { | ||||
| 				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 						"%d:0238 Process x%x NameServer" | ||||
| 						" Rsp Data: x%x x%x x%x\n", | ||||
| 						phba->brd_no, | ||||
| 						Did, ndlp->nlp_flag, | ||||
| 						vport->fc_flag, | ||||
| 						vport->fc_rscn_id_cnt); | ||||
| 			} else { | ||||
| 				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 						"%d:0239 Skip x%x NameServer " | ||||
| 						"Rsp Data: x%x x%x x%x\n", | ||||
| 						phba->brd_no, | ||||
| 						Did, Size, vport->fc_flag, | ||||
| 						vport->fc_rscn_id_cnt); | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * Check for rscn processing or not | ||||
| 			 * To conserve rpi's, filter out addresses for other | ||||
| 			 * vports on the same physical HBAs. | ||||
| 			 */ | ||||
| 			if ((Did != vport->fc_myDID) && | ||||
| 			    ((lpfc_find_vport_by_did(phba, Did) == NULL) || | ||||
| 			     phba->cfg_peer_port_login)) { | ||||
| 				if ((vport->port_type != LPFC_NPIV_PORT) || | ||||
| 				    (vport->fc_flag & FC_RFF_NOT_SUPPORTED) || | ||||
| 				    (!phba->cfg_vport_restrict_login)) { | ||||
| 					ndlp = lpfc_setup_disc_node(vport, Did); | ||||
| 					if (ndlp) { | ||||
| 						lpfc_printf_log(phba, KERN_INFO, | ||||
| 							LOG_DISCOVERY, | ||||
| 							"%d (%d):0238 Process " | ||||
| 							"x%x NameServer Rsp" | ||||
| 							"Data: x%x x%x x%x\n", | ||||
| 							phba->brd_no, | ||||
| 							vport->vpi, Did, | ||||
| 							ndlp->nlp_flag, | ||||
| 							vport->fc_flag, | ||||
| 							vport->fc_rscn_id_cnt); | ||||
| 					} else { | ||||
| 						lpfc_printf_log(phba, KERN_INFO, | ||||
| 							LOG_DISCOVERY, | ||||
| 							"%d (%d):0239 Skip x%x " | ||||
| 							"NameServer Rsp Data: " | ||||
| 							"x%x x%x\n", | ||||
| 							phba->brd_no, | ||||
| 							vport->vpi, Did, | ||||
| 							vport->fc_flag, | ||||
| 							vport->fc_rscn_id_cnt); | ||||
| 					} | ||||
| 
 | ||||
| 				} else { | ||||
| 					if (!(vport->fc_flag & FC_RSCN_MODE) || | ||||
| 					(lpfc_rscn_payload_check(vport, Did))) { | ||||
| 						if (lpfc_ns_cmd(vport, | ||||
| 							SLI_CTNS_GFF_ID, | ||||
| 							0, Did) == 0) | ||||
| 							vport->num_disc_nodes++; | ||||
| 					} | ||||
| 					else { | ||||
| 						lpfc_printf_log(phba, KERN_INFO, | ||||
| 							LOG_DISCOVERY, | ||||
| 							"%d (%d):0245 Skip x%x " | ||||
| 							"NameServer Rsp Data: " | ||||
| 							"x%x x%x\n", | ||||
| 							phba->brd_no, | ||||
| 							vport->vpi, Did, | ||||
| 							vport->fc_flag, | ||||
| 							vport->fc_rscn_id_cnt); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY))) | ||||
| 				goto nsout1; | ||||
| @ -422,34 +481,19 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | ||||
| 
 | ||||
| nsout1: | ||||
| 	list_del(&head); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The driver has cycled through all Nports in the RSCN payload. | ||||
| 	 * Complete the handling by cleaning up and marking the | ||||
| 	 * current driver state. | ||||
| 	 */ | ||||
| 	if (vport->port_state == LPFC_VPORT_READY) { | ||||
| 		lpfc_els_flush_rscn(vport); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		vport->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */ | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	struct lpfc_vport *vport = cmdiocb->vport; | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	IOCB_t *irsp; | ||||
| 	struct lpfc_dmabuf *bmp; | ||||
| 	struct lpfc_dmabuf *inp; | ||||
| 	struct lpfc_dmabuf *outp; | ||||
| 	struct lpfc_nodelist *ndlp; | ||||
| 	struct lpfc_sli_ct_request *CTrsp; | ||||
| 	int rc; | ||||
| 
 | ||||
| @ -460,33 +504,41 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 	outp = (struct lpfc_dmabuf *) cmdiocb->context2; | ||||
| 	bmp = (struct lpfc_dmabuf *) cmdiocb->context3; | ||||
| 
 | ||||
| 	/* Don't bother processing response if vport is being torn down. */ | ||||
| 	if (vport->load_flag & FC_UNLOADING) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	irsp = &rspiocb->iocb; | ||||
| 	if (irsp->ulpStatus) { | ||||
| 		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||||
| 			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || | ||||
| 			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) | ||||
| 			goto out; | ||||
| 			goto err1; | ||||
| 
 | ||||
| 		/* Check for retry */ | ||||
| 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { | ||||
| 			vport->fc_ns_retry++; | ||||
| 			/* CT command is being retried */ | ||||
| 			ndlp = lpfc_findnode_did(vport, NameServer_DID); | ||||
| 			if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||||
| 				rc = lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT); | ||||
| 				if (rc == 0) | ||||
| 					goto out; | ||||
| 				} | ||||
| 			} | ||||
| 			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, | ||||
| 					 vport->fc_ns_retry, 0); | ||||
| 			if (rc == 0) | ||||
| 				goto out; | ||||
| 		} | ||||
| err1: | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||||
| 			"%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n", | ||||
| 			phba->brd_no, vport->vpi, irsp->ulpStatus, | ||||
| 			vport->fc_ns_retry); | ||||
| 	} else { | ||||
| 		/* Good status, continue checking */ | ||||
| 		CTrsp = (struct lpfc_sli_ct_request *) outp->virt; | ||||
| 		if (CTrsp->CommandResponse.bits.CmdRsp == | ||||
| 		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { | ||||
| 			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 					"%d:0208 NameServer Rsp " | ||||
| 					"%d (%d):0208 NameServer Rsp " | ||||
| 					"Data: x%x\n", | ||||
| 					phba->brd_no, | ||||
| 					phba->brd_no, vport->vpi, | ||||
| 					vport->fc_flag); | ||||
| 			lpfc_ns_rsp(vport, outp, | ||||
| 				    (uint32_t) (irsp->un.genreq64.bdl.bdeSize)); | ||||
| @ -494,21 +546,19 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			   be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { | ||||
| 			/* NameServer Rsp Error */ | ||||
| 			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 					"%d:0240 NameServer Rsp Error " | ||||
| 					"%d (%d):0240 NameServer Rsp Error " | ||||
| 					"Data: x%x x%x x%x x%x\n", | ||||
| 					phba->brd_no, | ||||
| 					phba->brd_no, vport->vpi, | ||||
| 					CTrsp->CommandResponse.bits.CmdRsp, | ||||
| 					(uint32_t) CTrsp->ReasonCode, | ||||
| 					(uint32_t) CTrsp->Explanation, | ||||
| 					vport->fc_flag); | ||||
| 		} else { | ||||
| 			/* NameServer Rsp Error */ | ||||
| 			lpfc_printf_log(phba, | ||||
| 					KERN_INFO, | ||||
| 					LOG_DISCOVERY, | ||||
| 					"%d:0241 NameServer Rsp Error " | ||||
| 			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, | ||||
| 					"%d (%d):0241 NameServer Rsp Error " | ||||
| 					"Data: x%x x%x x%x x%x\n", | ||||
| 					phba->brd_no, | ||||
| 					phba->brd_no, vport->vpi, | ||||
| 					CTrsp->CommandResponse.bits.CmdRsp, | ||||
| 					(uint32_t) CTrsp->ReasonCode, | ||||
| 					(uint32_t) CTrsp->Explanation, | ||||
| @ -516,7 +566,25 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 		} | ||||
| 	} | ||||
| 	/* Link up / RSCN discovery */ | ||||
| 	lpfc_disc_start(vport); | ||||
| 	if (vport->num_disc_nodes == 0) { | ||||
| 		/*
 | ||||
| 		 * The driver has cycled through all Nports in the RSCN payload. | ||||
| 		 * Complete the handling by cleaning up and marking the | ||||
| 		 * current driver state. | ||||
| 		 */ | ||||
| 		if (vport->port_state >= LPFC_DISC_AUTH) { | ||||
| 			if (vport->fc_flag & FC_RSCN_MODE) { | ||||
| 				lpfc_els_flush_rscn(vport); | ||||
| 				spin_lock_irq(shost->host_lock); | ||||
| 				vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ | ||||
| 				spin_unlock_irq(shost->host_lock); | ||||
| 			} | ||||
| 			else | ||||
| 				lpfc_els_flush_rscn(vport); | ||||
| 		} | ||||
| 
 | ||||
| 		lpfc_disc_start(vport); | ||||
| 	} | ||||
| out: | ||||
| 	lpfc_free_ct_rsp(phba, outp); | ||||
| 	lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||||
| @ -527,15 +595,104 @@ out: | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	struct lpfc_vport *vport = cmdiocb->vport; | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	IOCB_t *irsp = &rspiocb->iocb; | ||||
| 	struct lpfc_dmabuf *bmp = (struct lpfc_dmabuf *) cmdiocb->context3; | ||||
| 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; | ||||
| 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; | ||||
| 	struct lpfc_sli_ct_request *CTrsp; | ||||
| 	int did; | ||||
| 	uint8_t fbits; | ||||
| 	struct lpfc_nodelist *ndlp; | ||||
| 
 | ||||
| 	did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId; | ||||
| 	did = be32_to_cpu(did); | ||||
| 
 | ||||
| 	if (irsp->ulpStatus == IOSTAT_SUCCESS) { | ||||
| 		/* Good status, continue checking */ | ||||
| 		CTrsp = (struct lpfc_sli_ct_request *) outp->virt; | ||||
| 		fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET]; | ||||
| 
 | ||||
| 		if (CTrsp->CommandResponse.bits.CmdRsp == | ||||
| 		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { | ||||
| 			if ((fbits & FC4_FEATURE_INIT) && | ||||
| 			    !(fbits & FC4_FEATURE_TARGET)) { | ||||
| 				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 						"%d (%d):0245 Skip x%x GFF " | ||||
| 						"NameServer Rsp Data: (init) " | ||||
| 						"x%x x%x\n", phba->brd_no, | ||||
| 						vport->vpi, did, fbits, | ||||
| 						vport->fc_rscn_id_cnt); | ||||
| 				goto out; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	/* This is a target port, unregistered port, or the GFF_ID failed */ | ||||
| 	ndlp = lpfc_setup_disc_node(vport, did); | ||||
| 	if (ndlp) { | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 				"%d (%d):0242 Process x%x GFF " | ||||
| 				"NameServer Rsp Data: x%x x%x x%x\n", | ||||
| 				phba->brd_no, vport->vpi, | ||||
| 				did, ndlp->nlp_flag, vport->fc_flag, | ||||
| 				vport->fc_rscn_id_cnt); | ||||
| 	} else { | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 				"%d (%d):0243 Skip x%x GFF " | ||||
| 				"NameServer Rsp Data: x%x x%x\n", | ||||
| 				phba->brd_no, vport->vpi, did, | ||||
| 				vport->fc_flag,	vport->fc_rscn_id_cnt); | ||||
| 	} | ||||
| out: | ||||
| 	/* Link up / RSCN discovery */ | ||||
| 	if (vport->num_disc_nodes) | ||||
| 		vport->num_disc_nodes--; | ||||
| 	if (vport->num_disc_nodes == 0) { | ||||
| 		/*
 | ||||
| 		 * The driver has cycled through all Nports in the RSCN payload. | ||||
| 		 * Complete the handling by cleaning up and marking the | ||||
| 		 * current driver state. | ||||
| 		 */ | ||||
| 		if (vport->port_state >= LPFC_DISC_AUTH) { | ||||
| 			if (vport->fc_flag & FC_RSCN_MODE) { | ||||
| 				lpfc_els_flush_rscn(vport); | ||||
| 				spin_lock_irq(shost->host_lock); | ||||
| 				vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ | ||||
| 				spin_unlock_irq(shost->host_lock); | ||||
| 			} | ||||
| 			else | ||||
| 				lpfc_els_flush_rscn(vport); | ||||
| 		} | ||||
| 		lpfc_disc_start(vport); | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_free_ct_rsp(phba, outp); | ||||
| 	lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||||
| 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||||
| 	kfree(inp); | ||||
| 	kfree(bmp); | ||||
| 	lpfc_sli_release_iocbq(phba, cmdiocb); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	struct lpfc_vport *vport = cmdiocb->vport; | ||||
| 	struct lpfc_dmabuf *bmp; | ||||
| 	struct lpfc_dmabuf *inp; | ||||
| 	struct lpfc_dmabuf *outp; | ||||
| 	IOCB_t *irsp; | ||||
| 	struct lpfc_sli_ct_request *CTrsp; | ||||
| 	int cmdcode, rc; | ||||
| 	uint8_t retry; | ||||
| 
 | ||||
| 	/* we pass cmdiocb to state machine which needs rspiocb as well */ | ||||
| 	cmdiocb->context_un.rsp_iocb = rspiocb; | ||||
| @ -545,16 +702,40 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 	bmp = (struct lpfc_dmabuf *) cmdiocb->context3; | ||||
| 	irsp = &rspiocb->iocb; | ||||
| 
 | ||||
| 	cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)-> | ||||
| 					CommandResponse.bits.CmdRsp); | ||||
| 	CTrsp = (struct lpfc_sli_ct_request *) outp->virt; | ||||
| 
 | ||||
| 	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */ | ||||
| 	/* NS request completes status <ulpStatus> CmdRsp <CmdRsp> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 			"%d:0209 RFT request completes ulpStatus x%x " | ||||
| 			"%d (%d):0209 NS request %x completes " | ||||
| 			"ulpStatus x%x / x%x " | ||||
| 			"CmdRsp x%x, Context x%x, Tag x%x\n", | ||||
| 			phba->brd_no, irsp->ulpStatus, | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4], | ||||
| 			CTrsp->CommandResponse.bits.CmdRsp, | ||||
| 			cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag); | ||||
| 
 | ||||
| 	if (irsp->ulpStatus) { | ||||
| 		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||||
| 			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || | ||||
| 			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		retry = cmdiocb->retry; | ||||
| 		if (retry >= LPFC_MAX_NS_RETRY) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		retry++; | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 				"%d (%d):0216 Retrying NS cmd %x\n", | ||||
| 				phba->brd_no, vport->vpi, cmdcode); | ||||
| 		rc = lpfc_ns_cmd(vport, cmdcode, retry, 0); | ||||
| 		if (rc == 0) | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	lpfc_free_ct_rsp(phba, outp); | ||||
| 	lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||||
| 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||||
| @ -572,6 +753,14 @@ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			 struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			 struct lpfc_iocbq *rspiocb) | ||||
| @ -581,23 +770,54 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||||
| 			 struct lpfc_iocbq * rspiocb) | ||||
| lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 			struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	IOCB_t *irsp = &rspiocb->iocb; | ||||
| 	struct lpfc_vport *vport = cmdiocb->vport; | ||||
| 
 | ||||
| 	if (irsp->ulpStatus != IOSTAT_SUCCESS) | ||||
| 	    vport->fc_flag |= FC_RFF_NOT_SUPPORTED; | ||||
| 
 | ||||
| 	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp) | ||||
| int | ||||
| lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, | ||||
| 	size_t size) | ||||
| { | ||||
| 	int n; | ||||
| 	uint8_t *wwn = vport->phba->wwpn; | ||||
| 
 | ||||
| 	n = snprintf(symbol, size, | ||||
| 		     "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", | ||||
| 		     wwn[0], wwn[1], wwn[2], wwn[3], | ||||
| 		     wwn[4], wwn[5], wwn[6], wwn[7]); | ||||
| 
 | ||||
| 	if (vport->port_type == LPFC_PHYSICAL_PORT) | ||||
| 		return n; | ||||
| 
 | ||||
| 	if (n < size) | ||||
| 		n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi); | ||||
| 
 | ||||
| 	if (n < size && vport->vname) | ||||
| 		n += snprintf(symbol + n, size - n, " VName-%s", vport->vname); | ||||
| 	return n; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol, | ||||
| 	size_t size) | ||||
| { | ||||
| 	char fwrev[16]; | ||||
| 	int n; | ||||
| 
 | ||||
| 	lpfc_decode_firmware_rev(phba, fwrev, 0); | ||||
| 	lpfc_decode_firmware_rev(vport->phba, fwrev, 0); | ||||
| 
 | ||||
| 	sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, | ||||
| 		fwrev, lpfc_release_version); | ||||
| 	return; | ||||
| 	n = snprintf(symbol, size, "Emulex %s FV%s DV%s", | ||||
| 		vport->phba->ModelName, fwrev, lpfc_release_version); | ||||
| 	return n; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -608,8 +828,10 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp) | ||||
|  *       LI_CTNS_RFT_ID | ||||
|  */ | ||||
| int | ||||
| lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, | ||||
| 	    uint8_t retry, uint32_t context) | ||||
| { | ||||
| 	struct lpfc_nodelist * ndlp; | ||||
| 	struct lpfc_hba *phba = vport->phba; | ||||
| 	struct lpfc_dmabuf *mp, *bmp; | ||||
| 	struct lpfc_sli_ct_request *CtReq; | ||||
| @ -617,6 +839,11 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| 	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||||
| 		      struct lpfc_iocbq *) = NULL; | ||||
| 	uint32_t rsp_size = 1024; | ||||
| 	size_t   size; | ||||
| 
 | ||||
| 	ndlp = lpfc_findnode_did(vport, NameServer_DID); | ||||
| 	if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	/* fill in BDEs for command */ | ||||
| 	/* Allocate buffer for command payload */ | ||||
| @ -640,24 +867,26 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| 		goto ns_cmd_free_bmp; | ||||
| 
 | ||||
| 	/* NameServer Req */ | ||||
| 	lpfc_printf_log(phba, | ||||
| 			KERN_INFO, | ||||
| 			LOG_DISCOVERY, | ||||
| 			"%d:0236 NameServer Req Data: x%x x%x x%x\n", | ||||
| 			phba->brd_no, cmdcode, vport->fc_flag, | ||||
| 	lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY, | ||||
| 			"%d (%d):0236 NameServer Req Data: x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, cmdcode, vport->fc_flag, | ||||
| 			vport->fc_rscn_id_cnt); | ||||
| 
 | ||||
| 	bpl = (struct ulp_bde64 *) bmp->virt; | ||||
| 	memset(bpl, 0, sizeof(struct ulp_bde64)); | ||||
| 	bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||||
| 	bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||||
| 	bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); | ||||
| 	bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); | ||||
| 	bpl->tus.f.bdeFlags = 0; | ||||
| 	if (cmdcode == SLI_CTNS_GID_FT) | ||||
| 		bpl->tus.f.bdeSize = GID_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_GFF_ID) | ||||
| 		bpl->tus.f.bdeSize = GFF_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_RFT_ID) | ||||
| 		bpl->tus.f.bdeSize = RFT_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_RNN_ID) | ||||
| 		bpl->tus.f.bdeSize = RNN_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_RSPN_ID) | ||||
| 		bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_RSNN_NN) | ||||
| 		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; | ||||
| 	else if (cmdcode == SLI_CTNS_RFF_ID) | ||||
| @ -678,13 +907,20 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_GID_FT); | ||||
| 		CtReq->un.gid.Fc4Type = SLI_CTPT_FCP; | ||||
| 		if (vport->port_state < LPFC_VPORT_READY) | ||||
| 		if (vport->port_state < LPFC_NS_QRY) | ||||
| 			vport->port_state = LPFC_NS_QRY; | ||||
| 		lpfc_set_disctmo(vport); | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_gid_ft; | ||||
| 		rsp_size = FC_MAX_NS_RSP; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SLI_CTNS_GFF_ID: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 			be16_to_cpu(SLI_CTNS_GFF_ID); | ||||
| 		CtReq->un.gff.PortId = be32_to_cpu(context); | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_gff_id; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SLI_CTNS_RFT_ID: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_RFT_ID); | ||||
| @ -693,17 +929,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rft_id; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SLI_CTNS_RFF_ID: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 			be16_to_cpu(SLI_CTNS_RFF_ID); | ||||
| 		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID); | ||||
| 		CtReq->un.rff.feature_res = 0; | ||||
| 		CtReq->un.rff.feature_tgt = 0; | ||||
| 		CtReq->un.rff.type_code = FC_FCP_DATA; | ||||
| 		CtReq->un.rff.feature_init = 1; | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rff_id; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SLI_CTNS_RNN_ID: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_RNN_ID); | ||||
| @ -713,18 +938,39 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode) | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rnn_id; | ||||
| 		break; | ||||
| 
 | ||||
| 	case SLI_CTNS_RSPN_ID: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_RSPN_ID); | ||||
| 		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID); | ||||
| 		size = sizeof(CtReq->un.rspn.symbname); | ||||
| 		CtReq->un.rspn.len = | ||||
| 			lpfc_vport_symbolic_port_name(vport, | ||||
| 			CtReq->un.rspn.symbname, size); | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rspn_id; | ||||
| 		break; | ||||
| 	case SLI_CTNS_RSNN_NN: | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_RSNN_NN); | ||||
| 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename, | ||||
| 		       sizeof (struct lpfc_name)); | ||||
| 		lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname); | ||||
| 		CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname); | ||||
| 		size = sizeof(CtReq->un.rsnn.symbname); | ||||
| 		CtReq->un.rsnn.len = | ||||
| 			lpfc_vport_symbolic_node_name(vport, | ||||
| 			CtReq->un.rsnn.symbname, size); | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; | ||||
| 		break; | ||||
| 	case SLI_CTNS_RFF_ID: | ||||
| 		vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED; | ||||
| 		CtReq->CommandResponse.bits.CmdRsp = | ||||
| 		    be16_to_cpu(SLI_CTNS_RFF_ID); | ||||
| 		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);; | ||||
| 		CtReq->un.rff.fbits = FC4_FEATURE_INIT; | ||||
| 		CtReq->un.rff.type_code = FC_FCP_DATA; | ||||
| 		cmpl = lpfc_cmpl_ct_cmd_rff_id; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size)) | ||||
| 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) | ||||
| 		/* On success, The cmpl function will free the buffers */ | ||||
| 		return 0; | ||||
| 
 | ||||
| @ -757,8 +1003,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { | ||||
| 		/* FDMI rsp failed */ | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 				"%d:0220 FDMI rsp failed Data: x%x\n", | ||||
| 				phba->brd_no, be16_to_cpu(fdmi_cmd)); | ||||
| 			        "%d (%d):0220 FDMI rsp failed Data: x%x\n", | ||||
| 			        phba->brd_no, vport->vpi, | ||||
| 				be16_to_cpu(fdmi_cmd)); | ||||
| 	} | ||||
| 
 | ||||
| 	switch (be16_to_cpu(fdmi_cmd)) { | ||||
| @ -828,9 +1075,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) | ||||
| 
 | ||||
| 	/* FDMI request */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 		        "%d:0218 FDMI Request Data: x%x x%x x%x\n", | ||||
| 		        phba->brd_no, | ||||
| 			vport->fc_flag, vport->port_state, cmdcode); | ||||
| 			"%d (%d):0218 FDMI Request Data: x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, vport->fc_flag, | ||||
| 			vport->port_state, cmdcode); | ||||
| 
 | ||||
| 	CtReq = (struct lpfc_sli_ct_request *) mp->virt; | ||||
| 
 | ||||
| @ -1134,15 +1381,15 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) | ||||
| 	} | ||||
| 
 | ||||
| 	bpl = (struct ulp_bde64 *) bmp->virt; | ||||
| 	bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||||
| 	bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||||
| 	bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); | ||||
| 	bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); | ||||
| 	bpl->tus.f.bdeFlags = 0; | ||||
| 	bpl->tus.f.bdeSize = size; | ||||
| 	bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||||
| 
 | ||||
| 	cmpl = lpfc_cmpl_ct_cmd_fdmi; | ||||
| 
 | ||||
| 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP)) | ||||
| 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||||
| @ -1155,8 +1402,8 @@ fdmi_cmd_free_mp: | ||||
| fdmi_cmd_exit: | ||||
| 	/* Issue FDMI request failed */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 		        "%d:0244 Issue FDMI request failed Data: x%x\n", | ||||
| 		        phba->brd_no, cmdcode); | ||||
| 		        "%d (%d):0244 Issue FDMI request failed Data: x%x\n", | ||||
| 		        phba->brd_no, vport->vpi, cmdcode); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| @ -1170,10 +1417,15 @@ lpfc_fdmi_tmo(unsigned long ptr) | ||||
| 	spin_lock_irqsave(&vport->work_port_lock, iflag); | ||||
| 	if (!(vport->work_port_events & WORKER_FDMI_TMO)) { | ||||
| 		vport->work_port_events |= WORKER_FDMI_TMO; | ||||
| 		spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||||
| 
 | ||||
| 		spin_lock_irqsave(&phba->hbalock, iflag); | ||||
| 		if (phba->work_wait) | ||||
| 			wake_up(phba->work_wait); | ||||
| 			lpfc_worker_wake_up(phba); | ||||
| 		spin_unlock_irqrestore(&phba->hbalock, iflag); | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||||
| 	else | ||||
| 		spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  | ||||
| @ -36,13 +36,14 @@ enum lpfc_work_type { | ||||
| 	LPFC_EVT_WARM_START, | ||||
| 	LPFC_EVT_KILL, | ||||
| 	LPFC_EVT_ELS_RETRY, | ||||
| 	LPFC_EVT_DEV_LOSS, | ||||
| }; | ||||
| 
 | ||||
| /* structure used to queue event to the discovery tasklet */ | ||||
| struct lpfc_work_evt { | ||||
| 	struct list_head      evt_listp; | ||||
| 	void                * evt_arg1; | ||||
| 	void                * evt_arg2; | ||||
| 	void                 *evt_arg1; | ||||
| 	void                 *evt_arg2; | ||||
| 	enum lpfc_work_type   evt; | ||||
| }; | ||||
| 
 | ||||
| @ -73,10 +74,12 @@ struct lpfc_nodelist { | ||||
| #define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */ | ||||
| 
 | ||||
| 	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */ | ||||
| 	struct timer_list   nlp_initiator_tmr;	/* Used with dev_loss */ | ||||
| 	struct fc_rport *rport;			/* Corresponding FC transport
 | ||||
| 						   port structure */ | ||||
| 	struct lpfc_vport *vport; | ||||
| 	struct lpfc_work_evt els_retry_evt; | ||||
| 	struct lpfc_work_evt dev_loss_evt; | ||||
| 	unsigned long last_ramp_up_time;        /* jiffy of last ramp up */ | ||||
| 	unsigned long last_q_full_time;		/* jiffy of last queue full */ | ||||
| 	struct kref     kref; | ||||
| @ -99,6 +102,7 @@ struct lpfc_nodelist { | ||||
| #define NLP_NPR_ADISC      0x2000000	/* Issue ADISC when dq'ed from | ||||
| 					   NPR list */ | ||||
| #define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */ | ||||
| #define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */ | ||||
| 
 | ||||
| /* There are 4 different double linked lists nodelist entries can reside on.
 | ||||
|  * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -64,6 +64,7 @@ | ||||
| #define SLI3_IOCB_CMD_SIZE	128 | ||||
| #define SLI3_IOCB_RSP_SIZE	64 | ||||
| 
 | ||||
| 
 | ||||
| /* Common Transport structures and definitions */ | ||||
| 
 | ||||
| union CtRevisionId { | ||||
| @ -84,6 +85,9 @@ union CtCommandResponse { | ||||
| 	uint32_t word; | ||||
| }; | ||||
| 
 | ||||
| #define FC4_FEATURE_INIT 0x2 | ||||
| #define FC4_FEATURE_TARGET 0x1 | ||||
| 
 | ||||
| struct lpfc_sli_ct_request { | ||||
| 	/* Structure is in Big Endian format */ | ||||
| 	union CtRevisionId RevisionId; | ||||
| @ -126,20 +130,6 @@ struct lpfc_sli_ct_request { | ||||
| 
 | ||||
| 			uint32_t rsvd[7]; | ||||
| 		} rft; | ||||
| 		struct rff { | ||||
| 			uint32_t PortId; | ||||
| 			uint8_t reserved[2]; | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 			uint8_t feature_res:6; | ||||
| 			uint8_t feature_init:1; | ||||
| 			uint8_t feature_tgt:1; | ||||
| #else  /*  __LITTLE_ENDIAN_BITFIELD */ | ||||
| 			uint8_t feature_tgt:1; | ||||
| 			uint8_t feature_init:1; | ||||
| 			uint8_t feature_res:6; | ||||
| #endif | ||||
| 			uint8_t type_code;     /* type=8 for FCP */ | ||||
| 		} rff; | ||||
| 		struct rnn { | ||||
| 			uint32_t PortId;	/* For RNN_ID requests */ | ||||
| 			uint8_t wwnn[8]; | ||||
| @ -149,15 +139,42 @@ struct lpfc_sli_ct_request { | ||||
| 			uint8_t len; | ||||
| 			uint8_t symbname[255]; | ||||
| 		} rsnn; | ||||
| 		struct rspn {	/* For RSPN_ID requests */ | ||||
| 			uint32_t PortId; | ||||
| 			uint8_t len; | ||||
| 			uint8_t symbname[255]; | ||||
| 		} rspn; | ||||
| 		struct gff { | ||||
| 			uint32_t PortId; | ||||
| 		} gff; | ||||
| 		struct gff_acc { | ||||
| 			uint8_t fbits[128]; | ||||
| 		} gff_acc; | ||||
| #define FCP_TYPE_FEATURE_OFFSET 4 | ||||
| 		struct rff { | ||||
| 			uint32_t PortId; | ||||
| 			uint8_t reserved[2]; | ||||
| 			uint8_t fbits; | ||||
| 			uint8_t type_code;     /* type=8 for FCP */ | ||||
| 		} rff; | ||||
| 	} un; | ||||
| }; | ||||
| 
 | ||||
| #define  SLI_CT_REVISION        1 | ||||
| #define  GID_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 260) | ||||
| #define  RFT_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 228) | ||||
| #define  RFF_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 235) | ||||
| #define  RNN_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 252) | ||||
| #define  RSNN_REQUEST_SZ        (sizeof(struct lpfc_sli_ct_request)) | ||||
| #define  GID_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct gid)) | ||||
| #define  GFF_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct gff)) | ||||
| #define  RFT_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct rft)) | ||||
| #define  RFF_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct rff)) | ||||
| #define  RNN_REQUEST_SZ   (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct rnn)) | ||||
| #define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct rsnn)) | ||||
| #define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \ | ||||
| 			   sizeof(struct rspn)) | ||||
| 
 | ||||
| /*
 | ||||
|  * FsType Definitions | ||||
| @ -232,6 +249,7 @@ struct lpfc_sli_ct_request { | ||||
| #define  SLI_CTNS_GFT_ID      0x0117 | ||||
| #define  SLI_CTNS_GSPN_ID     0x0118 | ||||
| #define  SLI_CTNS_GPT_ID      0x011A | ||||
| #define  SLI_CTNS_GFF_ID      0x011F | ||||
| #define  SLI_CTNS_GID_PN      0x0121 | ||||
| #define  SLI_CTNS_GID_NN      0x0131 | ||||
| #define  SLI_CTNS_GIP_NN      0x0135 | ||||
| @ -245,9 +263,9 @@ struct lpfc_sli_ct_request { | ||||
| #define  SLI_CTNS_RNN_ID      0x0213 | ||||
| #define  SLI_CTNS_RCS_ID      0x0214 | ||||
| #define  SLI_CTNS_RFT_ID      0x0217 | ||||
| #define  SLI_CTNS_RFF_ID      0x021F | ||||
| #define  SLI_CTNS_RSPN_ID     0x0218 | ||||
| #define  SLI_CTNS_RPT_ID      0x021A | ||||
| #define  SLI_CTNS_RFF_ID      0x021F | ||||
| #define  SLI_CTNS_RIP_NN      0x0235 | ||||
| #define  SLI_CTNS_RIPA_NN     0x0236 | ||||
| #define  SLI_CTNS_RSNN_NN     0x0239 | ||||
| @ -316,8 +334,9 @@ struct csp { | ||||
| 	uint8_t bbCreditlsb;	/* FC Word 0, byte 3 */ | ||||
| 
 | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */ | ||||
| 	uint16_t response_multiple_Nport:1;	/* FC Word 1, bit 29 */ | ||||
| 	uint16_t request_multiple_Nport:1;	/* FC Word 1, bit 31 */ | ||||
| 	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */ | ||||
| 	uint16_t response_multiple_NPort:1;	/* FC Word 1, bit 29 */ | ||||
| 	uint16_t fPort:1;	/* FC Word 1, bit 28 */ | ||||
| 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */ | ||||
| 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */ | ||||
| @ -336,9 +355,9 @@ struct csp { | ||||
| 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */ | ||||
| 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */ | ||||
| 	uint16_t fPort:1;	/* FC Word 1, bit 28 */ | ||||
| 	uint16_t word1Reserved2:1;	/* FC Word 1, bit 29 */ | ||||
| 	uint16_t response_multiple_NPort:1;	/* FC Word 1, bit 29 */ | ||||
| 	uint16_t randomOffset:1;	/* FC Word 1, bit 30 */ | ||||
| 	uint16_t increasingOffset:1;	/* FC Word 1, bit 31 */ | ||||
| 	uint16_t request_multiple_Nport:1;	/* FC Word 1, bit 31 */ | ||||
| 
 | ||||
| 	uint16_t payloadlength:1;	/* FC Word 1, bit 16 */ | ||||
| 	uint16_t contIncSeqCnt:1;	/* FC Word 1, bit 17 */ | ||||
| @ -1268,6 +1287,10 @@ typedef struct {		/* FireFly BIU registers */ | ||||
| #define MBX_READ_RPI64      0x8F | ||||
| #define MBX_REG_LOGIN64     0x93 | ||||
| #define MBX_READ_LA64       0x95 | ||||
| #define MBX_REG_VPI	    0x96 | ||||
| #define MBX_UNREG_VPI	    0x97 | ||||
| #define MBX_REG_VNPID	    0x96 | ||||
| #define MBX_UNREG_VNPID	    0x97 | ||||
| 
 | ||||
| #define MBX_FLASH_WR_ULA    0x98 | ||||
| #define MBX_SET_DEBUG       0x99 | ||||
| @ -1570,7 +1593,7 @@ typedef struct { | ||||
| #define FLAGS_TOPOLOGY_MODE_PT_PT    0x02 /* Attempt pt-pt only */ | ||||
| #define FLAGS_TOPOLOGY_MODE_LOOP     0x04 /* Attempt loop only */ | ||||
| #define FLAGS_TOPOLOGY_MODE_PT_LOOP  0x06 /* Attempt pt-pt then loop */ | ||||
| #define FLAGS_UNREG_LOGIN_ALL        0x08 /* UNREG_LOGIN all on link down */ | ||||
| #define	FLAGS_UNREG_LOGIN_ALL	     0x08 /* UNREG_LOGIN all on link down */ | ||||
| #define FLAGS_LIRP_LILP              0x80 /* LIRP / LILP is disabled */ | ||||
| 
 | ||||
| #define FLAGS_TOPOLOGY_FAILOVER      0x0400	/* Bit 10 */ | ||||
| @ -2086,6 +2109,45 @@ typedef struct { | ||||
| #endif | ||||
| } UNREG_LOGIN_VAR; | ||||
| 
 | ||||
| /* Structure for MB Command REG_VPI (0x96) */ | ||||
| typedef struct { | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 	uint32_t rsvd1; | ||||
| 	uint32_t rsvd2:8; | ||||
| 	uint32_t sid:24; | ||||
| 	uint32_t rsvd3; | ||||
| 	uint32_t rsvd4; | ||||
| 	uint32_t rsvd5; | ||||
| 	uint16_t rsvd6; | ||||
| 	uint16_t vpi; | ||||
| #else	/*  __LITTLE_ENDIAN */ | ||||
| 	uint32_t rsvd1; | ||||
| 	uint32_t sid:24; | ||||
| 	uint32_t rsvd2:8; | ||||
| 	uint32_t rsvd3; | ||||
| 	uint32_t rsvd4; | ||||
| 	uint32_t rsvd5; | ||||
| 	uint16_t vpi; | ||||
| 	uint16_t rsvd6; | ||||
| #endif | ||||
| } REG_VPI_VAR; | ||||
| 
 | ||||
| /* Structure for MB Command UNREG_VPI (0x97) */ | ||||
| typedef struct { | ||||
| 	uint32_t rsvd1; | ||||
| 	uint32_t rsvd2; | ||||
| 	uint32_t rsvd3; | ||||
| 	uint32_t rsvd4; | ||||
| 	uint32_t rsvd5; | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 	uint16_t rsvd6; | ||||
| 	uint16_t vpi; | ||||
| #else	/*  __LITTLE_ENDIAN */ | ||||
| 	uint16_t vpi; | ||||
| 	uint16_t rsvd6; | ||||
| #endif | ||||
| } UNREG_VPI_VAR; | ||||
| 
 | ||||
| /* Structure for MB Command UNREG_D_ID (0x23) */ | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -2549,8 +2611,8 @@ typedef union { | ||||
| 	LOAD_SM_VAR varLdSM;		/* cmd =  1 (LOAD_SM)        */ | ||||
| 	READ_NV_VAR varRDnvp;		/* cmd =  2 (READ_NVPARMS)   */ | ||||
| 	WRITE_NV_VAR varWTnvp;		/* cmd =  3 (WRITE_NVPARMS)  */ | ||||
| 	BIU_DIAG_VAR varBIUdiag;	/* cmd =  4 (RUN_BIU_DIAG)   */ | ||||
| 	INIT_LINK_VAR varInitLnk;	/* cmd =  5 (INIT_LINK)      */ | ||||
| 	BIU_DIAG_VAR varBIUdiag; 	/* cmd =  4 (RUN_BIU_DIAG)   */ | ||||
| 	INIT_LINK_VAR varInitLnk; 	/* cmd =  5 (INIT_LINK)      */ | ||||
| 	DOWN_LINK_VAR varDwnLnk;	/* cmd =  6 (DOWN_LINK)      */ | ||||
| 	CONFIG_LINK varCfgLnk;		/* cmd =  7 (CONFIG_LINK)    */ | ||||
| 	PART_SLIM_VAR varSlim;		/* cmd =  8 (PART_SLIM)      */ | ||||
| @ -2575,6 +2637,8 @@ typedef union { | ||||
| 					 */ | ||||
| 	struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ)  */ | ||||
| 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */ | ||||
| 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */ | ||||
| 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */ | ||||
| } MAILVARIANTS; | ||||
| 
 | ||||
| /*
 | ||||
| @ -2614,7 +2678,6 @@ typedef union { | ||||
| 	struct sli3_pgp  s3_pgp; | ||||
| } SLI_VAR; | ||||
| 
 | ||||
| 
 | ||||
| typedef struct { | ||||
| #ifdef __BIG_ENDIAN_BITFIELD | ||||
| 	uint16_t mbxStatus; | ||||
| @ -2935,6 +2998,8 @@ struct rcv_sli3 { | ||||
| 	struct ulp_bde64 bde2; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| typedef struct _IOCB {	/* IOCB structure */ | ||||
| 	union { | ||||
| 		GENERIC_RSP grsp;	/* Generic response */ | ||||
| @ -3011,6 +3076,7 @@ typedef struct _IOCB {	/* IOCB structure */ | ||||
| 	uint32_t ulpXS:1; | ||||
| 	uint32_t ulpTimeout:8; | ||||
| #endif | ||||
| 
 | ||||
| 	union { | ||||
| 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */ | ||||
| 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ | ||||
| @ -3024,6 +3090,7 @@ typedef struct _IOCB {	/* IOCB structure */ | ||||
| #define PARM_UNUSED        0	/* PU field (Word 4) not used */ | ||||
| #define PARM_REL_OFF       1	/* PU field (Word 4) = R. O. */ | ||||
| #define PARM_READ_CHECK    2	/* PU field (Word 4) = Data Transfer Length */ | ||||
| #define PARM_NPIV_DID	   3 | ||||
| #define CLASS1             0	/* Class 1 */ | ||||
| #define CLASS2             1	/* Class 2 */ | ||||
| #define CLASS3             2	/* Class 3 */ | ||||
| @ -3044,7 +3111,7 @@ typedef struct _IOCB {	/* IOCB structure */ | ||||
| #define IOSTAT_RSVD2           0xC | ||||
| #define IOSTAT_RSVD3           0xD | ||||
| #define IOSTAT_RSVD4           0xE | ||||
| #define IOSTAT_RSVD5           0xF | ||||
| #define IOSTAT_NEED_BUFFER     0xF | ||||
| #define IOSTAT_DRIVER_REJECT   0x10   /* ulpStatus  - Driver defined */ | ||||
| #define IOSTAT_DEFAULT         0xF    /* Same as rsvd5 for now */ | ||||
| #define IOSTAT_CNT             0x11 | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include <linux/kthread.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/ctype.h> | ||||
| 
 | ||||
| #include <scsi/scsi.h> | ||||
| #include <scsi/scsi_device.h> | ||||
| @ -40,21 +41,18 @@ | ||||
| #include "lpfc.h" | ||||
| #include "lpfc_logmsg.h" | ||||
| #include "lpfc_crtn.h" | ||||
| #include "lpfc_vport.h" | ||||
| #include "lpfc_version.h" | ||||
| #include "lpfc_vport.h" | ||||
| 
 | ||||
| static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); | ||||
| static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); | ||||
| static int lpfc_post_rcv_buf(struct lpfc_hba *); | ||||
| 
 | ||||
| static struct scsi_transport_template *lpfc_transport_template = NULL; | ||||
| static struct scsi_transport_template *lpfc_vport_transport_template = NULL; | ||||
| static DEFINE_IDR(lpfc_hba_index); | ||||
| 
 | ||||
| int lpfc_sli_mode = 0; | ||||
| module_param(lpfc_sli_mode, int, 0); | ||||
| MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" | ||||
| 		 " 0 - auto (SLI-3 if supported)," | ||||
| 		 " 2 - select SLI-2 even on SLI-3 capable HBAs," | ||||
| 		 " 3 - select SLI-3"); | ||||
| 
 | ||||
| 
 | ||||
| /************************************************************************/ | ||||
| @ -123,6 +121,8 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | ||||
| 		       sizeof(phba->wwpn)); | ||||
| 	} | ||||
| 
 | ||||
| 	phba->sli3_options = 0x0; | ||||
| 
 | ||||
| 	/* Setup and issue mailbox READ REV command */ | ||||
| 	lpfc_read_rev(phba, pmb); | ||||
| 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); | ||||
| @ -136,6 +136,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | ||||
| 		return -ERESTART; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The value of rr must be 1 since the driver set the cv field to 1. | ||||
| 	 * This setting requires the FW to set all revision fields. | ||||
| @ -155,6 +156,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | ||||
| 
 | ||||
| 	/* Save information as VPD data */ | ||||
| 	vp->rev.rBit = 1; | ||||
| 	memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t)); | ||||
| 	vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev; | ||||
| 	memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16); | ||||
| 	vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev; | ||||
| @ -170,6 +172,13 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | ||||
| 	vp->rev.postKernRev = mb->un.varRdRev.postKernRev; | ||||
| 	vp->rev.opFwRev = mb->un.varRdRev.opFwRev; | ||||
| 
 | ||||
| 	/* If the sli feature level is less then 9, we must
 | ||||
| 	 * tear down all RPIs and VPIs on link down if NPIV | ||||
| 	 * is enabled. | ||||
| 	 */ | ||||
| 	if (vp->rev.feaLevelHigh < 9) | ||||
| 		phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN; | ||||
| 
 | ||||
| 	if (lpfc_is_LC_HBA(phba->pcidev->device)) | ||||
| 		memcpy(phba->RandomData, (char *)&mb->un.varWords[24], | ||||
| 						sizeof (phba->RandomData)); | ||||
| @ -197,7 +206,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | ||||
| 		if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) | ||||
| 			mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; | ||||
| 		lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset, | ||||
| 							mb->un.varDmp.word_cnt); | ||||
| 				      mb->un.varDmp.word_cnt); | ||||
| 		offset += mb->un.varDmp.word_cnt; | ||||
| 	} while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); | ||||
| 	lpfc_parse_vpd(phba, lpfc_vpd_data, offset); | ||||
| @ -240,7 +249,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) | ||||
| 	mb = &pmb->mb; | ||||
| 
 | ||||
| 	/* Get login parameters for NID.  */ | ||||
| 	lpfc_read_sparam(phba, pmb); | ||||
| 	lpfc_read_sparam(phba, pmb, 0); | ||||
| 	pmb->vport = vport; | ||||
| 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||||
| @ -431,10 +440,9 @@ lpfc_hba_down_prep(struct lpfc_hba *phba) | ||||
| 	writel(0, phba->HCregaddr); | ||||
| 	readl(phba->HCregaddr); /* flush */ | ||||
| 
 | ||||
| 				/* Cleanup potential discovery resources */ | ||||
| 	lpfc_els_flush_rscn(vport); | ||||
| 	lpfc_els_flush_cmd(vport); | ||||
| 	lpfc_disc_flush_list(vport); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		lpfc_cleanup_discovery_resources(vport); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -456,13 +464,17 @@ lpfc_hba_down_post(struct lpfc_hba *phba) | ||||
| 	struct lpfc_dmabuf *mp, *next_mp; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* Cleanup preposted buffers on the ELS ring */ | ||||
| 	pring = &psli->ring[LPFC_ELS_RING]; | ||||
| 	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { | ||||
| 		list_del(&mp->list); | ||||
| 		pring->postbufq_cnt--; | ||||
| 		lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 		kfree(mp); | ||||
| 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) | ||||
| 		lpfc_sli_hbqbuf_free_all(phba); | ||||
| 	else { | ||||
| 		/* Cleanup preposted buffers on the ELS ring */ | ||||
| 		pring = &psli->ring[LPFC_ELS_RING]; | ||||
| 		list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { | ||||
| 			list_del(&mp->list); | ||||
| 			pring->postbufq_cnt--; | ||||
| 			lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 			kfree(mp); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < psli->num_rings; i++) { | ||||
| @ -485,10 +497,11 @@ void | ||||
| lpfc_handle_eratt(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_sli   *psli = &phba->sli; | ||||
| 	struct lpfc_sli_ring  *pring; | ||||
| 	struct lpfc_vport *port_iterator; | ||||
| 	uint32_t event_data; | ||||
| 	struct Scsi_Host  *shost; | ||||
| 
 | ||||
| 	/* If the pci channel is offline, ignore possible errors,
 | ||||
| 	 * since we cannot communicate with the pci card anyway. */ | ||||
| @ -503,10 +516,17 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | ||||
| 				"Data: x%x x%x x%x\n", | ||||
| 				phba->brd_no, phba->work_hs, | ||||
| 				phba->work_status[0], phba->work_status[1]); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		vport->fc_flag |= FC_ESTABLISH_LINK; | ||||
| 		list_for_each_entry(port_iterator, &phba->port_list, | ||||
| 				    listentry) { | ||||
| 			shost = lpfc_shost_from_vport(port_iterator); | ||||
| 
 | ||||
| 			spin_lock_irq(shost->host_lock); | ||||
| 			port_iterator->fc_flag |= FC_ESTABLISH_LINK; | ||||
| 			spin_unlock_irq(shost->host_lock); | ||||
| 		} | ||||
| 		spin_lock_irq(&phba->hbalock); | ||||
| 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 		spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		* Firmware stops when it triggled erratt with HS_FFER6. | ||||
| @ -543,11 +563,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | ||||
| 				phba->work_status[0], phba->work_status[1]); | ||||
| 
 | ||||
| 		event_data = FC_REG_DUMP_EVENT; | ||||
| 		shost = lpfc_shost_from_vport(vport); | ||||
| 		fc_host_post_vendor_event(shost, fc_get_event_number(), | ||||
| 				sizeof(event_data), (char *) &event_data, | ||||
| 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); | ||||
| 
 | ||||
| 		spin_lock_irq(&phba->hbalock); | ||||
| 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | ||||
| 		spin_unlock_irq(&phba->hbalock); | ||||
| 		lpfc_offline_prep(phba); | ||||
| 		lpfc_offline(phba); | ||||
| 		lpfc_unblock_mgmt_io(phba); | ||||
| @ -569,6 +592,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct lpfc_sli   *psli = &phba->sli; | ||||
| 	struct lpfc_vport *port_iterator; | ||||
| 	LPFC_MBOXQ_t *pmb; | ||||
| 	volatile uint32_t control; | ||||
| 	struct lpfc_dmabuf *mp; | ||||
| @ -589,7 +613,8 @@ lpfc_handle_latt(struct lpfc_hba *phba) | ||||
| 	rc = -EIO; | ||||
| 
 | ||||
| 	/* Cleanup any outstanding ELS commands */ | ||||
| 	lpfc_els_flush_cmd(vport); | ||||
| 	list_for_each_entry(port_iterator, &phba->port_list, listentry) | ||||
| 		lpfc_els_flush_cmd(port_iterator); | ||||
| 
 | ||||
| 	psli->slistat.link_event++; | ||||
| 	lpfc_read_la(phba, pmb, mp); | ||||
| @ -1023,9 +1048,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt, | ||||
| 			return cnt; | ||||
| 		} | ||||
| 		lpfc_sli_ringpostbuf_put(phba, pring, mp1); | ||||
| 		if (mp2) { | ||||
| 		if (mp2) | ||||
| 			lpfc_sli_ringpostbuf_put(phba, pring, mp2); | ||||
| 		} | ||||
| 	} | ||||
| 	pring->missbufcnt = 0; | ||||
| 	return 0; | ||||
| @ -1175,34 +1199,45 @@ lpfc_cleanup(struct lpfc_vport *vport) | ||||
| static void | ||||
| lpfc_establish_link_tmo(unsigned long ptr) | ||||
| { | ||||
| 	struct lpfc_hba   *phba = (struct lpfc_hba *)ptr; | ||||
| 	struct lpfc_hba   *phba = (struct lpfc_hba *) ptr; | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport); | ||||
| 	unsigned long iflag; | ||||
| 
 | ||||
| 
 | ||||
| 	/* Re-establishing Link, timer expired */ | ||||
| 	lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | ||||
| 			"%d:1300 Re-establishing Link, timer expired " | ||||
| 			"Data: x%x x%x\n", | ||||
| 			phba->brd_no, vport->fc_flag, | ||||
| 			vport->port_state); | ||||
| 	spin_lock_irqsave(shost->host_lock, iflag); | ||||
| 	vport->fc_flag &= ~FC_ESTABLISH_LINK; | ||||
| 	spin_unlock_irqrestore(shost->host_lock, iflag); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 
 | ||||
| 		spin_lock_irqsave(shost->host_lock, iflag); | ||||
| 		vport->fc_flag &= ~FC_ESTABLISH_LINK; | ||||
| 		spin_unlock_irqrestore(shost->host_lock, iflag); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_stop_vport_timers(struct lpfc_vport *vport) | ||||
| { | ||||
| 	del_timer_sync(&vport->els_tmofunc); | ||||
| 	del_timer_sync(&vport->fc_fdmitmo); | ||||
| 	lpfc_can_disctmo(vport); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_stop_timer(struct lpfc_hba *phba) | ||||
| lpfc_stop_phba_timers(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct lpfc_vport *vport; | ||||
| 
 | ||||
| 	del_timer_sync(&phba->fcp_poll_timer); | ||||
| 	del_timer_sync(&phba->fc_estabtmo); | ||||
| 	del_timer_sync(&vport->els_tmofunc); | ||||
| 	del_timer_sync(&vport->fc_fdmitmo); | ||||
| 	del_timer_sync(&vport->fc_disctmo); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) | ||||
| 		lpfc_stop_vport_timers(vport); | ||||
| 	del_timer_sync(&phba->sli.mbox_tmo); | ||||
| 	del_timer_sync(&phba->fabric_block_timer); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| @ -1210,7 +1245,6 @@ int | ||||
| lpfc_online(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport); | ||||
| 
 | ||||
| 	if (!phba) | ||||
| 		return 0; | ||||
| @ -1234,9 +1268,14 @@ lpfc_online(struct lpfc_hba *phba) | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	vport->fc_flag &= ~FC_OFFLINE_MODE; | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		struct Scsi_Host  *shost = lpfc_shost_from_vport(vport); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		vport->fc_flag &= ~FC_OFFLINE_MODE; | ||||
| 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) | ||||
| 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_unblock_mgmt_io(phba); | ||||
| 	return 0; | ||||
| @ -1288,31 +1327,37 @@ lpfc_offline(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport = phba->pport; | ||||
| 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport); | ||||
| 	unsigned long iflag; | ||||
| 	struct lpfc_vport *port_iterator; | ||||
| 
 | ||||
| 	if (vport->fc_flag & FC_OFFLINE_MODE) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* stop all timers associated with this hba */ | ||||
| 	lpfc_stop_timer(phba); | ||||
| 	lpfc_stop_phba_timers(phba); | ||||
| 	list_for_each_entry(port_iterator, &phba->port_list, listentry) { | ||||
| 		port_iterator->work_port_events = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_printf_log(phba, | ||||
| 		       KERN_WARNING, | ||||
| 		       LOG_INIT, | ||||
| 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, | ||||
| 		       "%d:0460 Bring Adapter offline\n", | ||||
| 		       phba->brd_no); | ||||
| 
 | ||||
| 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
 | ||||
| 	   now.  */ | ||||
| 	lpfc_sli_hba_down(phba); | ||||
| 	lpfc_cleanup(vport); | ||||
| 	spin_lock_irqsave(shost->host_lock, iflag); | ||||
| 	spin_lock(&phba->hbalock); | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	phba->work_ha = 0; | ||||
| 	vport->work_port_events = 0; | ||||
| 	vport->fc_flag |= FC_OFFLINE_MODE; | ||||
| 	spin_unlock(&phba->hbalock); | ||||
| 	spin_unlock_irqrestore(shost->host_lock, iflag); | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	list_for_each_entry(port_iterator, &phba->port_list, listentry) { | ||||
| 		shost = lpfc_shost_from_vport(port_iterator); | ||||
| 
 | ||||
| 		lpfc_cleanup(port_iterator); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		vport->work_port_events = 0; | ||||
| 		vport->fc_flag |= FC_OFFLINE_MODE; | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /******************************************************************************
 | ||||
| @ -1332,7 +1377,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) | ||||
| 	list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { | ||||
| 		list_del(&sb->list); | ||||
| 		pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data, | ||||
| 								sb->dma_handle); | ||||
| 			      sb->dma_handle); | ||||
| 		kfree(sb); | ||||
| 		phba->total_scsi_bufs--; | ||||
| 	} | ||||
| @ -1349,8 +1394,9 @@ lpfc_scsi_free(struct lpfc_hba *phba) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct lpfc_vport * | ||||
| lpfc_create_port(struct lpfc_hba *phba, int instance) | ||||
| lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport) | ||||
| { | ||||
| 	struct lpfc_vport *vport; | ||||
| 	struct Scsi_Host  *shost; | ||||
| @ -1364,6 +1410,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance) | ||||
| 	vport->phba = phba; | ||||
| 
 | ||||
| 	vport->load_flag |= FC_LOADING; | ||||
| 	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | ||||
| 
 | ||||
| 	shost->unique_id = instance; | ||||
| 	shost->max_id = LPFC_MAX_TARGET; | ||||
| @ -1376,7 +1423,13 @@ lpfc_create_port(struct lpfc_hba *phba, int instance) | ||||
| 	 * max xri value determined in hba setup. | ||||
| 	 */ | ||||
| 	shost->can_queue = phba->cfg_hba_queue_depth - 10; | ||||
| 	shost->transportt = lpfc_transport_template; | ||||
| 	if (fc_vport != NULL) { | ||||
| 		shost->transportt = lpfc_vport_transport_template; | ||||
| 		vport->port_type = LPFC_NPIV_PORT; | ||||
| 	} else { | ||||
| 		shost->transportt = lpfc_transport_template; | ||||
| 		vport->port_type = LPFC_PHYSICAL_PORT; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Initialize all internally managed lists. */ | ||||
| 	INIT_LIST_HEAD(&vport->fc_nodes); | ||||
| @ -1384,22 +1437,28 @@ lpfc_create_port(struct lpfc_hba *phba, int instance) | ||||
| 
 | ||||
| 	init_timer(&vport->fc_disctmo); | ||||
| 	vport->fc_disctmo.function = lpfc_disc_timeout; | ||||
| 	vport->fc_disctmo.data = (unsigned long) vport; | ||||
| 	vport->fc_disctmo.data = (unsigned long)vport; | ||||
| 
 | ||||
| 	init_timer(&vport->fc_fdmitmo); | ||||
| 	vport->fc_fdmitmo.function = lpfc_fdmi_tmo; | ||||
| 	vport->fc_fdmitmo.data = (unsigned long) vport; | ||||
| 	vport->fc_fdmitmo.data = (unsigned long)vport; | ||||
| 
 | ||||
| 	init_timer(&vport->els_tmofunc); | ||||
| 	vport->els_tmofunc.function = lpfc_els_timeout; | ||||
| 	vport->els_tmofunc.data = (unsigned long) vport; | ||||
| 	vport->els_tmofunc.data = (unsigned long)vport; | ||||
| 
 | ||||
| 	error = scsi_add_host(shost, &phba->pcidev->dev); | ||||
| 	if (fc_vport != NULL) { | ||||
| 		error = scsi_add_host(shost, &fc_vport->dev); | ||||
| 	} else { | ||||
| 		error = scsi_add_host(shost, &phba->pcidev->dev); | ||||
| 	} | ||||
| 	if (error) | ||||
| 		goto out_put_shost; | ||||
| 
 | ||||
| 	if (!shost->shost_classdev.kobj.dentry) | ||||
| 		goto out_put_shost; | ||||
| 
 | ||||
| 	list_add_tail(&vport->listentry, &phba->port_list); | ||||
| 	scsi_scan_host(shost); | ||||
| 	return vport; | ||||
| 
 | ||||
| out_put_shost: | ||||
| @ -1411,19 +1470,40 @@ out: | ||||
| void | ||||
| destroy_port(struct lpfc_vport *vport) | ||||
| { | ||||
| 	lpfc_cleanup(vport); | ||||
| 	list_del(&vport->listentry); | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 
 | ||||
| 	kfree(vport->vname); | ||||
| 	lpfc_free_sysfs_attr(vport); | ||||
| 	fc_remove_host(lpfc_shost_from_vport(vport)); | ||||
| 	scsi_remove_host(lpfc_shost_from_vport(vport)); | ||||
| 
 | ||||
| 	fc_remove_host(shost); | ||||
| 	scsi_remove_host(shost); | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	list_del_init(&vport->listentry); | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 	lpfc_cleanup(vport); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_get_instance(void) | ||||
| { | ||||
| 	int instance = 0; | ||||
| 
 | ||||
| 	/* Assign an unused number */ | ||||
| 	if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL)) | ||||
| 		return -1; | ||||
| 	if (idr_get_new(&lpfc_hba_index, NULL, &instance)) | ||||
| 		return -1; | ||||
| 	return instance; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_remove_device(struct lpfc_vport *vport) | ||||
| { | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba  = vport->phba; | ||||
| 
 | ||||
| 	lpfc_free_sysfs_attr(vport); | ||||
| 
 | ||||
| @ -1433,8 +1513,6 @@ lpfc_remove_device(struct lpfc_vport *vport) | ||||
| 
 | ||||
| 	fc_remove_host(shost); | ||||
| 	scsi_remove_host(shost); | ||||
| 
 | ||||
| 	kthread_stop(phba->worker_thread); | ||||
| } | ||||
| 
 | ||||
| void lpfc_scan_start(struct Scsi_Host *shost) | ||||
| @ -1442,7 +1520,7 @@ void lpfc_scan_start(struct Scsi_Host *shost) | ||||
| 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 
 | ||||
| 	if (lpfc_alloc_sysfs_attr(vport)) | ||||
| 	if (lpfc_sli_hba_setup(phba)) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -1486,6 +1564,14 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) | ||||
| 		return 0; | ||||
| 
 | ||||
| finished: | ||||
| 	lpfc_host_attrib_init(shost); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| void lpfc_host_attrib_init(struct Scsi_Host *shost) | ||||
| { | ||||
| 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 	/*
 | ||||
| 	 * Set fixed host attributes.  Must done after lpfc_sli_hba_setup(). | ||||
| 	 */ | ||||
| @ -1499,7 +1585,8 @@ finished: | ||||
| 	fc_host_supported_fc4s(shost)[2] = 1; | ||||
| 	fc_host_supported_fc4s(shost)[7] = 1; | ||||
| 
 | ||||
| 	lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost)); | ||||
| 	lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost), | ||||
| 				 sizeof fc_host_symbolic_name(shost)); | ||||
| 
 | ||||
| 	fc_host_supported_speeds(shost) = 0; | ||||
| 	if (phba->lmt & LMT_10Gb) | ||||
| @ -1521,11 +1608,10 @@ finished: | ||||
| 	fc_host_active_fc4s(shost)[2] = 1; | ||||
| 	fc_host_active_fc4s(shost)[7] = 1; | ||||
| 
 | ||||
| 	fc_host_max_npiv_vports(shost) = phba->max_vpi; | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	vport->fc_flag &= ~FC_LOADING; | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int __devinit | ||||
| @ -1555,20 +1641,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 	phba->pcidev = pdev; | ||||
| 
 | ||||
| 	/* Assign an unused board number */ | ||||
| 	if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL)) | ||||
| 		goto out_free_phba; | ||||
| 
 | ||||
| 	error = idr_get_new(&lpfc_hba_index, NULL, &phba->brd_no); | ||||
| 	if (error) | ||||
| 	if ((phba->brd_no = lpfc_get_instance()) < 0) | ||||
| 		goto out_free_phba; | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&phba->port_list); | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&phba->hbq_buffer_list); | ||||
| 	/*
 | ||||
| 	 * Get all the module params for configuring this host and then | ||||
| 	 * establish the host. | ||||
| 	 */ | ||||
| 	lpfc_get_cfgparam(phba); | ||||
| 	phba->max_vpi = LPFC_MAX_VPI; | ||||
| 
 | ||||
| 	/* Initialize timers used by driver */ | ||||
| 	init_timer(&phba->fc_estabtmo); | ||||
| @ -1581,6 +1664,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 	init_timer(&phba->fcp_poll_timer); | ||||
| 	phba->fcp_poll_timer.function = lpfc_poll_timeout; | ||||
| 	phba->fcp_poll_timer.data = (unsigned long) phba; | ||||
| 	init_timer(&phba->fabric_block_timer); | ||||
| 	phba->fabric_block_timer.function = lpfc_fabric_block_timeout; | ||||
| 	phba->fabric_block_timer.data = (unsigned long) phba; | ||||
| 
 | ||||
| 	pci_set_master(pdev); | ||||
| 	retval = pci_set_mwi(pdev); | ||||
| @ -1696,15 +1782,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 	spin_lock_init(&phba->scsi_buf_list_lock); | ||||
| 	INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list); | ||||
| 
 | ||||
| 	vport = lpfc_create_port(phba, phba->brd_no); | ||||
| 	/* Initialize list of fabric iocbs */ | ||||
| 	INIT_LIST_HEAD(&phba->fabric_iocb_list); | ||||
| 
 | ||||
| 	vport = lpfc_create_port(phba, phba->brd_no, NULL); | ||||
| 	if (!vport) | ||||
| 		goto out_kthread_stop; | ||||
| 
 | ||||
| 	shost = lpfc_shost_from_vport(vport); | ||||
| 	vport->port_type = LPFC_PHYSICAL_PORT; | ||||
| 	phba->pport = vport; | ||||
| 
 | ||||
| 	pci_set_drvdata(pdev, lpfc_shost_from_vport(vport)); | ||||
| 	pci_set_drvdata(pdev, shost); | ||||
| 
 | ||||
| 	if (phba->cfg_use_msi) { | ||||
| 		error = pci_enable_msi(phba->pcidev); | ||||
| @ -1720,7 +1808,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||||
| 			"%d:0451 Enable interrupt handler failed\n", | ||||
| 			phba->brd_no); | ||||
| 		goto out_destroy_port; | ||||
| 		goto out_disable_msi; | ||||
| 	} | ||||
| 
 | ||||
| 	phba->MBslimaddr = phba->slim_memmap_p; | ||||
| @ -1729,10 +1817,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; | ||||
| 	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; | ||||
| 
 | ||||
| 	error = lpfc_sli_hba_setup(phba); | ||||
| 	if (error) | ||||
| 	if (lpfc_alloc_sysfs_attr(vport)) | ||||
| 		goto out_free_irq; | ||||
| 
 | ||||
| 	scsi_scan_host(shost); | ||||
| 	if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		lpfc_poll_start_timer(phba); | ||||
| @ -1742,11 +1830,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | ||||
| 	return 0; | ||||
| 
 | ||||
| out_free_irq: | ||||
| 	lpfc_stop_timer(phba); | ||||
| 	lpfc_stop_phba_timers(phba); | ||||
| 	phba->pport->work_port_events = 0; | ||||
| 	free_irq(phba->pcidev->irq, phba); | ||||
| out_disable_msi: | ||||
| 	pci_disable_msi(phba->pcidev); | ||||
| out_destroy_port: | ||||
| 	destroy_port(vport); | ||||
| out_kthread_stop: | ||||
| 	kthread_stop(phba->worker_thread); | ||||
| @ -1786,9 +1874,9 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | ||||
| 	struct Scsi_Host  *shost = pci_get_drvdata(pdev); | ||||
| 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 
 | ||||
| 	vport->load_flag |= FC_UNLOADING; | ||||
| 	lpfc_remove_device(vport); | ||||
| 	struct lpfc_vport *port_iterator; | ||||
| 	list_for_each_entry(port_iterator, &phba->port_list, listentry) | ||||
| 		port_iterator->load_flag |= FC_UNLOADING; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Bring down the SLI Layer. This step disable all interrupts, | ||||
| @ -1798,7 +1886,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | ||||
| 	lpfc_sli_hba_down(phba); | ||||
| 	lpfc_sli_brdrestart(phba); | ||||
| 
 | ||||
| 	lpfc_stop_timer(phba); | ||||
| 	lpfc_stop_phba_timers(phba); | ||||
| 
 | ||||
| 	kthread_stop(phba->worker_thread); | ||||
| 
 | ||||
| @ -1806,7 +1894,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | ||||
| 	free_irq(phba->pcidev->irq, phba); | ||||
| 	pci_disable_msi(phba->pcidev); | ||||
| 
 | ||||
| 	vport->work_port_events = 0; | ||||
| 	destroy_port(vport); | ||||
| 
 | ||||
| 	pci_set_drvdata(pdev, NULL); | ||||
| @ -1892,13 +1979,14 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) | ||||
| 	pci_set_master(pdev); | ||||
| 
 | ||||
| 	/* Re-establishing Link */ | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	phba->pport->fc_flag |= FC_ESTABLISH_LINK; | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	spin_lock_irq(host->host_lock); | ||||
| 	psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | ||||
| 	phba->pport->fc_flag |= FC_ESTABLISH_LINK; | ||||
| 	spin_unlock_irq(host->host_lock); | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Take device offline; this will perform cleanup */ | ||||
| 	lpfc_offline(phba); | ||||
| @ -2020,11 +2108,15 @@ lpfc_init(void) | ||||
| 
 | ||||
| 	lpfc_transport_template = | ||||
| 				fc_attach_transport(&lpfc_transport_functions); | ||||
| 	if (!lpfc_transport_template) | ||||
| 	lpfc_vport_transport_template = | ||||
| 			fc_attach_transport(&lpfc_vport_transport_functions); | ||||
| 	if (!lpfc_transport_template || !lpfc_vport_transport_template) | ||||
| 		return -ENOMEM; | ||||
| 	error = pci_register_driver(&lpfc_driver); | ||||
| 	if (error) | ||||
| 	if (error) { | ||||
| 		fc_release_transport(lpfc_transport_template); | ||||
| 		fc_release_transport(lpfc_vport_transport_template); | ||||
| 	} | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
| @ -2034,6 +2126,7 @@ lpfc_exit(void) | ||||
| { | ||||
| 	pci_unregister_driver(&lpfc_driver); | ||||
| 	fc_release_transport(lpfc_transport_template); | ||||
| 	fc_release_transport(lpfc_vport_transport_template); | ||||
| } | ||||
| 
 | ||||
| module_init(lpfc_init); | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| #define LOG_SLI                       0x800	/* SLI events */ | ||||
| #define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */ | ||||
| #define LOG_LIBDFC                    0x2000	/* Libdfc events */ | ||||
| #define LOG_VPORT                     0x4000	/* NPIV events */ | ||||
| #define LOG_ALL_MSG                   0xffff	/* LOG all messages */ | ||||
| 
 | ||||
| #define lpfc_printf_log(phba, level, mask, fmt, arg...) \ | ||||
|  | ||||
| @ -106,7 +106,7 @@ lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp) | ||||
| 	 */ | ||||
| 	pmb->context1 = (uint8_t *) mp; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 	return 0; | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| /**********************************************/ | ||||
| @ -209,7 +209,7 @@ lpfc_init_link(struct lpfc_hba * phba, | ||||
| 	 */ | ||||
| 	vpd = &phba->vpd; | ||||
| 	if (vpd->rev.feaLevelHigh >= 0x02){ | ||||
| 		switch (linkspeed){ | ||||
| 		switch(linkspeed){ | ||||
| 			case LINK_SPEED_1G: | ||||
| 			case LINK_SPEED_2G: | ||||
| 			case LINK_SPEED_4G: | ||||
| @ -232,7 +232,6 @@ lpfc_init_link(struct lpfc_hba * phba, | ||||
| 	mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 	mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; | ||||
| 	mb->un.varInitLnk.link_flags |= FLAGS_UNREG_LOGIN_ALL; | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| @ -241,7 +240,7 @@ lpfc_init_link(struct lpfc_hba * phba, | ||||
| /*                    mailbox command         */ | ||||
| /**********************************************/ | ||||
| int | ||||
| lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) | ||||
| { | ||||
| 	struct lpfc_dmabuf *mp; | ||||
| 	MAILBOX_t *mb; | ||||
| @ -265,18 +264,19 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| 			        LOG_MBOX, | ||||
| 			        "%d:0301 READ_SPARAM: no buffers\n", | ||||
| 			        phba->brd_no); | ||||
| 		return 1; | ||||
| 		return (1); | ||||
| 	} | ||||
| 	INIT_LIST_HEAD(&mp->list); | ||||
| 	mb->mbxCommand = MBX_READ_SPARM64; | ||||
| 	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); | ||||
| 	mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys); | ||||
| 	mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys); | ||||
| 	mb->un.varRdSparm.vpi = vpi; | ||||
| 
 | ||||
| 	/* save address for completion */ | ||||
| 	pmb->context1 = mp; | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| /********************************************/ | ||||
| @ -284,7 +284,8 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| /*                  mailbox command         */ | ||||
| /********************************************/ | ||||
| void | ||||
| lpfc_unreg_did(struct lpfc_hba *phba, uint32_t did, LPFC_MBOXQ_t *pmb) | ||||
| lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did, | ||||
| 	       LPFC_MBOXQ_t * pmb) | ||||
| { | ||||
| 	MAILBOX_t *mb; | ||||
| 
 | ||||
| @ -292,6 +293,7 @@ lpfc_unreg_did(struct lpfc_hba *phba, uint32_t did, LPFC_MBOXQ_t *pmb) | ||||
| 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | ||||
| 
 | ||||
| 	mb->un.varUnregDID.did = did; | ||||
| 	mb->un.varUnregDID.vpi = vpi; | ||||
| 
 | ||||
| 	mb->mbxCommand = MBX_UNREG_D_ID; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| @ -337,8 +339,8 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| /*                  mailbox command         */ | ||||
| /********************************************/ | ||||
| int | ||||
| lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param, | ||||
| 	       LPFC_MBOXQ_t *pmb, uint32_t flag) | ||||
| lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, | ||||
| 	       uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag) | ||||
| { | ||||
| 	MAILBOX_t *mb = &pmb->mb; | ||||
| 	uint8_t *sparam; | ||||
| @ -347,6 +349,7 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param, | ||||
| 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | ||||
| 
 | ||||
| 	mb->un.varRegLogin.rpi = 0; | ||||
| 	mb->un.varRegLogin.vpi = vpi; | ||||
| 	mb->un.varRegLogin.did = did; | ||||
| 	mb->un.varWords[30] = flag;	/* Set flag to issue action on cmpl */ | ||||
| 
 | ||||
| @ -358,13 +361,11 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param, | ||||
| 		kfree(mp); | ||||
| 		mb->mbxCommand = MBX_REG_LOGIN64; | ||||
| 		/* REG_LOGIN: no buffers */ | ||||
| 		lpfc_printf_log(phba, | ||||
| 			       KERN_WARNING, | ||||
| 			       LOG_MBOX, | ||||
| 			       "%d:0302 REG_LOGIN: no buffers Data x%x x%x\n", | ||||
| 			       phba->brd_no, | ||||
| 			       (uint32_t) did, (uint32_t) flag); | ||||
| 		return 1; | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, | ||||
| 				"%d (%d):0302 REG_LOGIN: no buffers, DID x%x, " | ||||
| 				"flag x%x\n", | ||||
| 				phba->brd_no, vpi, did, flag); | ||||
| 		return (1); | ||||
| 	} | ||||
| 	INIT_LIST_HEAD(&mp->list); | ||||
| 	sparam = mp->virt; | ||||
| @ -380,7 +381,7 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param, | ||||
| 	mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys); | ||||
| 	mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys); | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return (0); | ||||
| } | ||||
| 
 | ||||
| /**********************************************/ | ||||
| @ -388,7 +389,8 @@ lpfc_reg_login(struct lpfc_hba *phba, uint32_t did, uint8_t *param, | ||||
| /*                    mailbox command         */ | ||||
| /**********************************************/ | ||||
| void | ||||
| lpfc_unreg_login(struct lpfc_hba *phba, uint32_t rpi, LPFC_MBOXQ_t * pmb) | ||||
| lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi, | ||||
| 		 LPFC_MBOXQ_t * pmb) | ||||
| { | ||||
| 	MAILBOX_t *mb; | ||||
| 
 | ||||
| @ -397,12 +399,52 @@ lpfc_unreg_login(struct lpfc_hba *phba, uint32_t rpi, LPFC_MBOXQ_t * pmb) | ||||
| 
 | ||||
| 	mb->un.varUnregLogin.rpi = (uint16_t) rpi; | ||||
| 	mb->un.varUnregLogin.rsvd1 = 0; | ||||
| 	mb->un.varUnregLogin.vpi = vpi; | ||||
| 
 | ||||
| 	mb->mbxCommand = MBX_UNREG_LOGIN; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| /**************************************************/ | ||||
| /*  lpfc_reg_vpi   Issue a REG_VPI                */ | ||||
| /*                    mailbox command             */ | ||||
| /**************************************************/ | ||||
| void | ||||
| lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid, | ||||
| 	     LPFC_MBOXQ_t *pmb) | ||||
| { | ||||
| 	MAILBOX_t *mb = &pmb->mb; | ||||
| 
 | ||||
| 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | ||||
| 
 | ||||
| 	mb->un.varRegVpi.vpi = vpi; | ||||
| 	mb->un.varRegVpi.sid = sid; | ||||
| 
 | ||||
| 	mb->mbxCommand = MBX_REG_VPI; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 	return; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /**************************************************/ | ||||
| /*  lpfc_unreg_vpi   Issue a UNREG_VNPI           */ | ||||
| /*                    mailbox command             */ | ||||
| /**************************************************/ | ||||
| void | ||||
| lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb) | ||||
| { | ||||
| 	MAILBOX_t *mb = &pmb->mb; | ||||
| 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | ||||
| 
 | ||||
| 	mb->un.varUnregVpi.vpi = vpi; | ||||
| 
 | ||||
| 	mb->mbxCommand = MBX_UNREG_VPI; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 	return; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_config_pcb_setup(struct lpfc_hba * phba) | ||||
| { | ||||
| @ -420,9 +462,9 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) | ||||
| 		pring = &psli->ring[i]; | ||||
| 
 | ||||
| 		pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE: | ||||
| 			SLI2_IOCB_CMD_SIZE; | ||||
| 							SLI2_IOCB_CMD_SIZE; | ||||
| 		pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE: | ||||
| 			SLI2_IOCB_RSP_SIZE; | ||||
| 							SLI2_IOCB_RSP_SIZE; | ||||
| 		/* A ring MUST have both cmd and rsp entries defined to be
 | ||||
| 		   valid */ | ||||
| 		if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { | ||||
| @ -437,18 +479,18 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) | ||||
| 			continue; | ||||
| 		} | ||||
| 		/* Command ring setup for ring */ | ||||
| 		pring->cmdringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; | ||||
| 		pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt]; | ||||
| 		pcbp->rdsc[i].cmdEntries = pring->numCiocb; | ||||
| 
 | ||||
| 		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - | ||||
| 			 (uint8_t *)phba->slim2p; | ||||
| 		offset = (uint8_t *) &phba->slim2p->IOCBs[iocbCnt] - | ||||
| 			 (uint8_t *) phba->slim2p; | ||||
| 		pdma_addr = phba->slim2p_mapping + offset; | ||||
| 		pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr); | ||||
| 		pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr); | ||||
| 		iocbCnt += pring->numCiocb; | ||||
| 
 | ||||
| 		/* Response ring setup for ring */ | ||||
| 		pring->rspringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; | ||||
| 		pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt]; | ||||
| 
 | ||||
| 		pcbp->rdsc[i].rspEntries = pring->numRiocb; | ||||
| 		offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - | ||||
| @ -519,7 +561,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc, | ||||
| 						       * Notification */ | ||||
| 	hbqmb->numMask    = hbq_desc->mask_count;     /* # R_CTL/TYPE masks
 | ||||
| 						       * # in words 0-19 */ | ||||
| 	hbqmb->profile    = hbq_desc->profile;        /* Selection profile:
 | ||||
| 	hbqmb->profile    = hbq_desc->profile;	      /* Selection profile:
 | ||||
| 						       * 0 = all, | ||||
| 						       * 7 = logentry */ | ||||
| 	hbqmb->ringMask   = hbq_desc->ring_mask;      /* Binds HBQ to a ring
 | ||||
| @ -538,9 +580,9 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc, | ||||
| 	mb->mbxCommand = MBX_CONFIG_HBQ; | ||||
| 	mb->mbxOwner = OWN_HOST; | ||||
| 
 | ||||
| 	/* Copy info for profiles 2,3,5. Other
 | ||||
| 	 * profiles this area is reserved | ||||
| 	 */ | ||||
| 				/* Copy info for profiles 2,3,5. Other
 | ||||
| 				 * profiles this area is reserved | ||||
| 				 */ | ||||
| 	if (hbq_desc->profile == 2) | ||||
| 		lpfc_build_hbq_profile2(hbqmb, hbq_desc); | ||||
| 	else if (hbq_desc->profile == 3) | ||||
| @ -563,6 +605,8 @@ lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc, | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) | ||||
| { | ||||
| @ -605,7 +649,7 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | ||||
| { | ||||
| 	MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr; | ||||
| 	MAILBOX_t *mb = &pmb->mb; | ||||
| @ -629,11 +673,19 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| 
 | ||||
| 	/* If HBA supports SLI=3 ask for it */ | ||||
| 
 | ||||
| 	mb->un.varCfgPort.sli_mode = phba->sli_rev; | ||||
| 	if (phba->sli_rev == 3) { | ||||
| 	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { | ||||
| 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ | ||||
| 		mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */ | ||||
| 	} | ||||
| 		if (phba->max_vpi && lpfc_npiv_enable && | ||||
| 		    phba->vpd.sli3Feat.cmv) { | ||||
| 			mb->un.varCfgPort.max_vpi = phba->max_vpi; | ||||
| 			mb->un.varCfgPort.cmv = 1; | ||||
| 			phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; | ||||
| 		} else | ||||
| 			mb->un.varCfgPort.max_vpi = phba->max_vpi = 0; | ||||
| 	} else | ||||
| 		phba->sli_rev = 2; | ||||
| 	mb->un.varCfgPort.sli_mode = phba->sli_rev; | ||||
| 
 | ||||
| 	/* Now setup pcb */ | ||||
| 	phba->slim2p->pcb.type = TYPE_NATIVE_SLI2; | ||||
| @ -748,7 +800,7 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | ||||
| 
 | ||||
| 	/* Swap PCB if needed */ | ||||
| 	lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb, | ||||
| 								sizeof (PCB_t)); | ||||
| 			      sizeof(PCB_t)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| @ -783,13 +835,22 @@ lpfc_mbox_get(struct lpfc_hba * phba) | ||||
| 	struct lpfc_sli *psli = &phba->sli; | ||||
| 
 | ||||
| 	list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list); | ||||
| 	if (mbq) { | ||||
| 	if (mbq) | ||||
| 		psli->mboxq_cnt--; | ||||
| 	} | ||||
| 
 | ||||
| 	return mbq; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) | ||||
| { | ||||
| 	/* This function expects to be called from interupt context */ | ||||
| 	spin_lock(&phba->hbalock); | ||||
| 	list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); | ||||
| 	spin_unlock(&phba->hbalock); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) | ||||
| { | ||||
|  | ||||
| @ -44,6 +44,7 @@ int | ||||
| lpfc_mem_alloc(struct lpfc_hba * phba) | ||||
| { | ||||
| 	struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; | ||||
| 	int longs; | ||||
| 	int i; | ||||
| 
 | ||||
| 	phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool", | ||||
| @ -87,8 +88,15 @@ lpfc_mem_alloc(struct lpfc_hba * phba) | ||||
| 	if (!phba->lpfc_hbq_pool) | ||||
| 		goto fail_free_nlp_mem_pool; | ||||
| 
 | ||||
| 	longs = (phba->max_vpi + BITS_PER_LONG - 1) / BITS_PER_LONG; | ||||
| 	phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); | ||||
| 	if (!phba->vpi_bmask) | ||||
| 		goto fail_free_hbq_pool; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
|  fail_free_hbq_pool: | ||||
| 	lpfc_sli_hbqbuf_free_all(phba); | ||||
|  fail_free_nlp_mem_pool: | ||||
| 	mempool_destroy(phba->nlp_mem_pool); | ||||
| 	phba->nlp_mem_pool = NULL; | ||||
| @ -119,9 +127,9 @@ lpfc_mem_free(struct lpfc_hba * phba) | ||||
| 	struct lpfc_dmabuf   *mp; | ||||
| 	int i; | ||||
| 
 | ||||
| 	kfree(phba->vpi_bmask); | ||||
| 	lpfc_sli_hbqbuf_free_all(phba); | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { | ||||
| 		mp = (struct lpfc_dmabuf *) (mbox->context1); | ||||
| 		if (mp) { | ||||
| @ -131,9 +139,17 @@ lpfc_mem_free(struct lpfc_hba * phba) | ||||
| 		list_del(&mbox->list); | ||||
| 		mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 	} | ||||
| 	list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) { | ||||
| 		mp = (struct lpfc_dmabuf *) (mbox->context1); | ||||
| 		if (mp) { | ||||
| 			lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 			kfree(mp); | ||||
| 		} | ||||
| 		list_del(&mbox->list); | ||||
| 		mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 	} | ||||
| 
 | ||||
| 	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	if (psli->mbox_active) { | ||||
| 		mbox = psli->mbox_active; | ||||
| 		mp = (struct lpfc_dmabuf *) (mbox->context1); | ||||
| @ -163,7 +179,7 @@ lpfc_mem_free(struct lpfc_hba * phba) | ||||
| 	phba->lpfc_scsi_dma_buf_pool = NULL; | ||||
| 	phba->lpfc_mbuf_pool = NULL; | ||||
| 
 | ||||
| 	/* Free the iocb lookup array */ | ||||
| 				/* Free the iocb lookup array */ | ||||
| 	kfree(psli->iocbq_lookup); | ||||
| 	psli->iocbq_lookup = NULL; | ||||
| 
 | ||||
| @ -179,7 +195,7 @@ lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) | ||||
| 	ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->hbalock, iflags); | ||||
| 	if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) { | ||||
| 	if (!ret && (mem_flags & MEM_PRI) && pool->current_count) { | ||||
| 		pool->current_count--; | ||||
| 		ret = pool->elements[pool->current_count].virt; | ||||
| 		*handle = pool->elements[pool->current_count].phys; | ||||
| @ -214,7 +230,6 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void * | ||||
| lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) | ||||
| { | ||||
| @ -230,3 +245,24 @@ lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma) | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) | ||||
| { | ||||
| 	struct hbq_dmabuf *hbq_entry; | ||||
| 
 | ||||
| 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | ||||
| 		hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); | ||||
| 		if (hbq_entry->tag == -1) { | ||||
| 			lpfc_hbq_free(phba, hbq_entry->dbuf.virt, | ||||
| 				      hbq_entry->dbuf.phys); | ||||
| 			kfree(hbq_entry); | ||||
| 		} else { | ||||
| 			lpfc_sli_free_hbq(phba, hbq_entry); | ||||
| 		} | ||||
| 	} else { | ||||
| 		lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 		kfree(mp); | ||||
| 	} | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /*******************************************************************
 | ||||
|  /*******************************************************************
 | ||||
|  * This file is part of the Emulex Linux Device Driver for         * | ||||
|  * Fibre Channel Host Bus Adapters.                                * | ||||
|  * Copyright (C) 2004-2007 Emulex.  All rights reserved.           * | ||||
| @ -35,6 +35,7 @@ | ||||
| #include "lpfc.h" | ||||
| #include "lpfc_logmsg.h" | ||||
| #include "lpfc_crtn.h" | ||||
| #include "lpfc_vport.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Called to verify a rcv'ed ADISC was intended for us. */ | ||||
| @ -74,12 +75,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 				hsp->cls1.rcvDataSizeLsb; | ||||
| 		ssp_value = (sp->cls1.rcvDataSizeMsb << 8) | | ||||
| 				sp->cls1.rcvDataSizeLsb; | ||||
| 		if (!ssp_value) | ||||
| 			goto bad_service_param; | ||||
| 		if (ssp_value > hsp_value) { | ||||
| 			sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb; | ||||
| 			sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb; | ||||
| 		} | ||||
| 	} else if (class == CLASS1) { | ||||
| 		return 0; | ||||
| 		goto bad_service_param; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sp->cls2.classValid) { | ||||
| @ -87,12 +90,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 				hsp->cls2.rcvDataSizeLsb; | ||||
| 		ssp_value = (sp->cls2.rcvDataSizeMsb << 8) | | ||||
| 				sp->cls2.rcvDataSizeLsb; | ||||
| 		if (!ssp_value) | ||||
| 			goto bad_service_param; | ||||
| 		if (ssp_value > hsp_value) { | ||||
| 			sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb; | ||||
| 			sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb; | ||||
| 		} | ||||
| 	} else if (class == CLASS2) { | ||||
| 		return 0; | ||||
| 		goto bad_service_param; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sp->cls3.classValid) { | ||||
| @ -100,12 +105,14 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 				hsp->cls3.rcvDataSizeLsb; | ||||
| 		ssp_value = (sp->cls3.rcvDataSizeMsb << 8) | | ||||
| 				sp->cls3.rcvDataSizeLsb; | ||||
| 		if (!ssp_value) | ||||
| 			goto bad_service_param; | ||||
| 		if (ssp_value > hsp_value) { | ||||
| 			sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb; | ||||
| 			sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb; | ||||
| 		} | ||||
| 	} else if (class == CLASS3) { | ||||
| 		return 0; | ||||
| 		goto bad_service_param; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -124,11 +131,22 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name)); | ||||
| 	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name)); | ||||
| 	return 1; | ||||
| bad_service_param: | ||||
| 	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY, | ||||
| 			"%d (%d):0207 Device %x " | ||||
| 			"(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent " | ||||
| 			"invalid service parameters.  Ignoring device.\n", | ||||
| 			vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID, | ||||
| 			sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1], | ||||
| 			sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3], | ||||
| 			sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5], | ||||
| 			sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void * | ||||
| lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | ||||
| 		      struct lpfc_iocbq *rspiocb) | ||||
| 			struct lpfc_iocbq *rspiocb) | ||||
| { | ||||
| 	struct lpfc_dmabuf *pcmd, *prsp; | ||||
| 	uint32_t *lp; | ||||
| @ -176,10 +194,12 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | ||||
| 
 | ||||
| 	/* Abort outstanding I/O on NPort <nlp_DID> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 			"%d:0205 Abort outstanding I/O on NPort x%x " | ||||
| 			"%d (%d):0205 Abort outstanding I/O on NPort x%x " | ||||
| 			"Data: x%x x%x x%x\n", | ||||
| 			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, | ||||
| 			ndlp->nlp_state, ndlp->nlp_rpi); | ||||
| 			phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID, | ||||
| 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||||
| 
 | ||||
| 	lpfc_fabric_abort_nport(ndlp); | ||||
| 
 | ||||
| 	/* First check the txq */ | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| @ -198,15 +218,16 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | ||||
| 	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { | ||||
| 		/* Check to see if iocb matches the nport we are looking
 | ||||
| 		   for */ | ||||
| 		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) | ||||
| 		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { | ||||
| 			lpfc_sli_issue_abort_iotag(phba, pring, iocb); | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 	while (!list_empty(&completions)) { | ||||
| 		iocb = list_get_first(&completions, struct lpfc_iocbq, list); | ||||
| 		cmd = &iocb->iocb; | ||||
| 		list_del(&iocb->list); | ||||
| 		list_del_init(&iocb->list); | ||||
| 
 | ||||
| 		if (!iocb->iocb_cmpl) | ||||
| 			lpfc_sli_release_iocbq(phba, iocb); | ||||
| @ -225,7 +246,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | ||||
| 
 | ||||
| static int | ||||
| lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		      struct lpfc_iocbq *cmdiocb) | ||||
| 	       struct lpfc_iocbq *cmdiocb) | ||||
| { | ||||
| 	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba    *phba = vport->phba; | ||||
| @ -244,7 +265,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		 * the FLOGI and resend it first. | ||||
| 		 */ | ||||
| 		if (vport->fc_flag & FC_PT2PT) { | ||||
| 			lpfc_els_abort_flogi(phba); | ||||
| 			 lpfc_els_abort_flogi(phba); | ||||
| 		        if (!(vport->fc_flag & FC_PT2PT_PLOGI)) { | ||||
| 				/* If the other side is supposed to initiate
 | ||||
| 				 * the PLOGI anyway, just ACC it now and | ||||
| @ -279,8 +300,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 	/* PLOGI chkparm OK */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||||
| 			"%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, | ||||
| 			"%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, | ||||
| 			ndlp->nlp_rpi); | ||||
| 
 | ||||
| @ -314,8 +335,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((vport->fc_flag & FC_PT2PT) | ||||
| 	    && !(vport->fc_flag & FC_PT2PT_PLOGI)) { | ||||
| 	if ((vport->fc_flag & FC_PT2PT) && | ||||
| 	    !(vport->fc_flag & FC_PT2PT_PLOGI)) { | ||||
| 		/* rcv'ed PLOGI decides what our NPortId will be */ | ||||
| 		vport->fc_myDID = icmd->un.rcvels.parmRo; | ||||
| 		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||||
| @ -327,7 +348,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		rc = lpfc_sli_issue_mbox | ||||
| 			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); | ||||
| 		if (rc == MBX_NOT_FINISHED) { | ||||
| 			mempool_free( mbox, phba->mbox_mem_pool); | ||||
| 			mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| @ -337,8 +358,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 	if (!mbox) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	rc = lpfc_reg_login(phba, icmd->un.rcvels.remoteID, (uint8_t *) sp, | ||||
| 			    mbox, 0); | ||||
| 	rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID, | ||||
| 			    (uint8_t *) sp, mbox, 0); | ||||
| 	if (rc) { | ||||
| 		mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 		goto out; | ||||
| @ -415,7 +436,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp); | ||||
| 		} else { | ||||
| 			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, | ||||
| 				NULL, 0); | ||||
| 					 NULL, 0); | ||||
| 		} | ||||
| 		return 1; | ||||
| 	} | ||||
| @ -457,7 +478,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | ||||
| 
 | ||||
| 	if (!(ndlp->nlp_type & NLP_FABRIC) || | ||||
| 		(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { | ||||
| 	    (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { | ||||
| 		/* Only try to re-login if this is NOT a Fabric Node */ | ||||
| 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| @ -499,8 +520,7 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); | ||||
| 	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; | ||||
| 	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && | ||||
| 	    (npr->prliType == PRLI_FCP_TYPE)) { | ||||
| 	if (npr->prliType == PRLI_FCP_TYPE) { | ||||
| 		if (npr->initiatorFunc) | ||||
| 			ndlp->nlp_type |= NLP_FCP_INITIATOR; | ||||
| 		if (npr->targetFunc) | ||||
| @ -526,15 +546,16 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 
 | ||||
| 	/* Check config parameter use-adisc or FCP-2 */ | ||||
| 	if (phba->cfg_use_adisc == 0 && | ||||
| 	    (vport->fc_flag & FC_RSCN_MODE) == 0 && | ||||
| 	    (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) == 0) | ||||
| 			return 0; | ||||
| 
 | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag |= NLP_NPR_ADISC; | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 	return 1; | ||||
| 	if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || | ||||
| 	    ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		ndlp->nlp_flag |= NLP_NPR_ADISC; | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	ndlp->nlp_flag &= ~NLP_NPR_ADISC; | ||||
| 	lpfc_unreg_rpi(vport, ndlp); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static uint32_t | ||||
| @ -542,9 +563,9 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		  void *arg, uint32_t evt) | ||||
| { | ||||
| 	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY, | ||||
| 			"%d:0253 Illegal State Transition: node x%x event x%x, " | ||||
| 			"state x%x Data: x%x x%x\n", | ||||
| 			vport->phba->brd_no, | ||||
| 			"%d (%d):0253 Illegal State Transition: node x%x " | ||||
| 			"event x%x, state x%x Data: x%x x%x\n", | ||||
| 			vport->phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, | ||||
| 			ndlp->nlp_flag); | ||||
| 	return ndlp->nlp_state; | ||||
| @ -629,7 +650,7 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 	 */ | ||||
| 	phba->fc_stat.elsLogiCol++; | ||||
| 	port_cmp = memcmp(&vport->fc_portname, &sp->portName, | ||||
| 			  sizeof (struct lpfc_name)); | ||||
| 			  sizeof(struct lpfc_name)); | ||||
| 
 | ||||
| 	if (port_cmp >= 0) { | ||||
| 		/* Reject this request because the remote node will accept
 | ||||
| @ -644,13 +665,27 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| static uint32_t | ||||
| lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 			  void *arg, uint32_t evt) | ||||
| { | ||||
| 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | ||||
| 	struct ls_rjt     stat; | ||||
| 
 | ||||
| 	memset(&stat, 0, sizeof (struct ls_rjt)); | ||||
| 	stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; | ||||
| 	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; | ||||
| 	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| static uint32_t | ||||
| lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 			  void *arg, uint32_t evt) | ||||
| { | ||||
| 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | ||||
| 
 | ||||
| 	/* software abort outstanding PLOGI */ | ||||
| 				/* software abort outstanding PLOGI */ | ||||
| 	lpfc_els_abort(vport->phba, ndlp); | ||||
| 
 | ||||
| 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); | ||||
| @ -724,9 +759,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | ||||
| 
 | ||||
| 	/* PLOGI chkparm OK */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||||
| 			"%d:0121 PLOGI chkparm OK " | ||||
| 			"%d (%d):0121 PLOGI chkparm OK " | ||||
| 			"Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, ndlp->nlp_state, | ||||
| 			ndlp->nlp_flag, ndlp->nlp_rpi); | ||||
| 
 | ||||
| @ -748,13 +783,20 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | ||||
| 		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; | ||||
| 
 | ||||
| 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||||
| 	if (!mbox) | ||||
| 	if (!mbox) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||||
| 			"%d (%d):0133 PLOGI: no memory for reg_login " | ||||
| 			"Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, ndlp->nlp_state, | ||||
| 			ndlp->nlp_flag, ndlp->nlp_rpi); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_unreg_rpi(vport, ndlp); | ||||
| 
 | ||||
| 	if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp, | ||||
| 			   mbox, 0) == 0) { | ||||
| 	if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID, | ||||
| 			   (uint8_t *) sp, mbox, 0) == 0) { | ||||
| 		switch (ndlp->nlp_DID) { | ||||
| 		case NameServer_DID: | ||||
| 			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login; | ||||
| @ -775,16 +817,37 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | ||||
| 			return ndlp->nlp_state; | ||||
| 		} | ||||
| 		lpfc_nlp_put(ndlp); | ||||
| 		mp = (struct lpfc_dmabuf *)mbox->context1; | ||||
| 		mp = (struct lpfc_dmabuf *) mbox->context1; | ||||
| 		lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 		kfree(mp); | ||||
| 		mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||||
| 			"%d (%d):0134 PLOGI: cannot issue reg_login " | ||||
| 			"Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, ndlp->nlp_state, | ||||
| 			ndlp->nlp_flag, ndlp->nlp_rpi); | ||||
| 	} else { | ||||
| 		mempool_free(mbox, phba->mbox_mem_pool); | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||||
| 			"%d (%d):0135 PLOGI: cannot format reg_login " | ||||
| 			"Data: x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			ndlp->nlp_DID, ndlp->nlp_state, | ||||
| 			ndlp->nlp_flag, ndlp->nlp_rpi); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|  out: | ||||
| out: | ||||
| 	if (ndlp->nlp_DID == NameServer_DID) { | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||||
| 			"%d (%d):0261 Cannot Register NameServer login\n", | ||||
| 			phba->brd_no, vport->vpi); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Free this node since the driver cannot login or has the wrong
 | ||||
| 	   sparm */ | ||||
| 	lpfc_drop_node(vport, ndlp); | ||||
| @ -820,12 +883,18 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 
 | ||||
| 	/* Don't do anything that will mess up processing of the
 | ||||
| 	 * previous RSCN. | ||||
| 	 */ | ||||
| 	if (vport->fc_flag & FC_RSCN_DEFERRED) | ||||
| 		return ndlp->nlp_state; | ||||
| 
 | ||||
| 	/* software abort outstanding PLOGI */ | ||||
| 	lpfc_els_abort(phba, ndlp); | ||||
| 
 | ||||
| 	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 
 | ||||
| @ -924,7 +993,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, | ||||
| 	irsp = &rspiocb->iocb; | ||||
| 
 | ||||
| 	if ((irsp->ulpStatus) || | ||||
| 	     (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) { | ||||
| 	    (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) { | ||||
| 		/* 1 sec timeout */ | ||||
| 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| @ -980,6 +1049,12 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 
 | ||||
| 	/* Don't do anything that will mess up processing of the
 | ||||
| 	 * previous RSCN. | ||||
| 	 */ | ||||
| 	if (vport->fc_flag & FC_RSCN_DEFERRED) | ||||
| 		return ndlp->nlp_state; | ||||
| 
 | ||||
| 	/* software abort outstanding ADISC */ | ||||
| 	lpfc_els_abort(phba, ndlp); | ||||
| 
 | ||||
| @ -987,9 +1062,8 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, | ||||
| 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | ||||
| 	ndlp->nlp_flag |= NLP_NPR_ADISC; | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 
 | ||||
| 	lpfc_disc_set_adisc(vport, ndlp); | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| @ -1035,6 +1109,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, | ||||
| 	if ((mb = phba->sli.mbox_active)) { | ||||
| 		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && | ||||
| 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) { | ||||
| 			lpfc_nlp_put(ndlp); | ||||
| 			mb->context2 = NULL; | ||||
| 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||||
| 		} | ||||
| @ -1049,6 +1124,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, | ||||
| 				lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 				kfree(mp); | ||||
| 			} | ||||
| 			lpfc_nlp_put(ndlp); | ||||
| 			list_del(&mb->list); | ||||
| 			mempool_free(mb, phba->mbox_mem_pool); | ||||
| 		} | ||||
| @ -1099,8 +1175,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, | ||||
| 	if (mb->mbxStatus) { | ||||
| 		/* RegLogin failed */ | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, | ||||
| 				"%d:0246 RegLogin failed Data: x%x x%x x%x\n", | ||||
| 				phba->brd_no, | ||||
| 				"%d (%d):0246 RegLogin failed Data: x%x x%x " | ||||
| 				"x%x\n", | ||||
| 				phba->brd_no, vport->vpi, | ||||
| 				did, mb->mbxStatus, vport->port_state); | ||||
| 
 | ||||
| 		/*
 | ||||
| @ -1167,11 +1244,18 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, | ||||
| { | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 
 | ||||
| 	/* Don't do anything that will mess up processing of the
 | ||||
| 	 * previous RSCN. | ||||
| 	 */ | ||||
| 	if (vport->fc_flag & FC_RSCN_DEFERRED) | ||||
| 		return ndlp->nlp_state; | ||||
| 
 | ||||
| 	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; | ||||
| 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 	lpfc_disc_set_adisc(vport, ndlp); | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| @ -1239,6 +1323,7 @@ static uint32_t | ||||
| lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 			  void *arg, uint32_t evt) | ||||
| { | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_iocbq *cmdiocb, *rspiocb; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 	IOCB_t *irsp; | ||||
| @ -1267,29 +1352,45 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 		if (npr->Retry) | ||||
| 			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; | ||||
| 	} | ||||
| 	if (!(ndlp->nlp_type & NLP_FCP_TARGET) && | ||||
| 	    (vport->port_type == LPFC_NPIV_PORT) && | ||||
| 	     phba->cfg_vport_restrict_login) { | ||||
| 		spin_lock_irq(shost->host_lock); | ||||
| 		ndlp->nlp_flag |= NLP_TARGET_REMOVE; | ||||
| 		spin_unlock_irq(shost->host_lock); | ||||
| 		lpfc_issue_els_logo(vport, ndlp, 0); | ||||
| 
 | ||||
| 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; | ||||
| 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | ||||
| 		return ndlp->nlp_state; | ||||
| 	} | ||||
| 
 | ||||
| 	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; | ||||
| 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); | ||||
| 	if (ndlp->nlp_type & NLP_FCP_TARGET) | ||||
| 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); | ||||
| 	else | ||||
| 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| /*! lpfc_device_rm_prli_issue
 | ||||
|   * | ||||
|   * \pre | ||||
|   * \post | ||||
|   * \param   phba | ||||
|   * \param   ndlp | ||||
|   * \param   arg | ||||
|   * \param   evt | ||||
|   * \return  uint32_t | ||||
|   * | ||||
|   * \b Description: | ||||
|   *    This routine is envoked when we a request to remove a nport we are in the | ||||
|   *    process of PRLIing. We should software abort outstanding prli, unreg | ||||
|   *    login, send a logout. We will change node state to UNUSED_NODE, put it | ||||
|   *    in plogi state so it can be freed when LOGO completes. | ||||
|   * | ||||
|   */ | ||||
|  * | ||||
|  * \pre | ||||
|  * \post | ||||
|  * \param   phba | ||||
|  * \param   ndlp | ||||
|  * \param   arg | ||||
|  * \param   evt | ||||
|  * \return  uint32_t | ||||
|  * | ||||
|  * \b Description: | ||||
|  *    This routine is envoked when we a request to remove a nport we are in the | ||||
|  *    process of PRLIing. We should software abort outstanding prli, unreg | ||||
|  *    login, send a logout. We will change node state to UNUSED_NODE, put it | ||||
|  *    on plogi list so it can be freed when LOGO completes. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| static uint32_t | ||||
| lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 			  void *arg, uint32_t evt) | ||||
| @ -1312,21 +1413,21 @@ lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 
 | ||||
| /*! lpfc_device_recov_prli_issue
 | ||||
|   * | ||||
|   * \pre | ||||
|   * \post | ||||
|   * \param   phba | ||||
|   * \param   ndlp | ||||
|   * \param   arg | ||||
|   * \param   evt | ||||
|   * \return  uint32_t | ||||
|   * | ||||
|   * \b Description: | ||||
|   *    The routine is envoked when the state of a device is unknown, like | ||||
|   *    during a link down. We should remove the nodelist entry from the | ||||
|   *    unmapped list, issue a UNREG_LOGIN, do a software abort of the | ||||
|   *    outstanding PRLI command, then free the node entry. | ||||
|   */ | ||||
|  * | ||||
|  * \pre | ||||
|  * \post | ||||
|  * \param   phba | ||||
|  * \param   ndlp | ||||
|  * \param   arg | ||||
|  * \param   evt | ||||
|  * \return  uint32_t | ||||
|  * | ||||
|  * \b Description: | ||||
|  *    The routine is envoked when the state of a device is unknown, like | ||||
|  *    during a link down. We should remove the nodelist entry from the | ||||
|  *    unmapped list, issue a UNREG_LOGIN, do a software abort of the | ||||
|  *    outstanding PRLI command, then free the node entry. | ||||
|  */ | ||||
| static uint32_t | ||||
| lpfc_device_recov_prli_issue(struct lpfc_vport *vport, | ||||
| 			     struct lpfc_nodelist *ndlp, | ||||
| @ -1336,6 +1437,12 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 	struct lpfc_hba  *phba = vport->phba; | ||||
| 
 | ||||
| 	/* Don't do anything that will mess up processing of the
 | ||||
| 	 * previous RSCN. | ||||
| 	 */ | ||||
| 	if (vport->fc_flag & FC_RSCN_DEFERRED) | ||||
| 		return ndlp->nlp_state; | ||||
| 
 | ||||
| 	/* software abort outstanding PRLI */ | ||||
| 	lpfc_els_abort(phba, ndlp); | ||||
| 
 | ||||
| @ -1344,6 +1451,7 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| 	lpfc_disc_set_adisc(vport, ndlp); | ||||
| 	return ndlp->nlp_state; | ||||
| } | ||||
| 
 | ||||
| @ -1466,7 +1574,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 	/* flush the target */ | ||||
| 	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], | ||||
| 			       ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); | ||||
| 			    ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); | ||||
| 
 | ||||
| 	/* Treat like rcv logo */ | ||||
| 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); | ||||
| @ -1573,8 +1681,9 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 	 * here will affect the counting of discovery threads. | ||||
| 	 */ | ||||
| 	if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && | ||||
| 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){ | ||||
| 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { | ||||
| 		if (ndlp->nlp_flag & NLP_NPR_ADISC) { | ||||
| 			ndlp->nlp_flag &= ~NLP_NPR_ADISC; | ||||
| 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | ||||
| 			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); | ||||
| 			lpfc_issue_els_adisc(vport, ndlp, 0); | ||||
| @ -1719,6 +1828,12 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| { | ||||
| 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||||
| 
 | ||||
| 	/* Don't do anything that will mess up processing of the
 | ||||
| 	 * previous RSCN. | ||||
| 	 */ | ||||
| 	if (vport->fc_flag & FC_RSCN_DEFERRED) | ||||
| 		return ndlp->nlp_state; | ||||
| 
 | ||||
| 	spin_lock_irq(shost->host_lock); | ||||
| 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | ||||
| 	spin_unlock_irq(shost->host_lock); | ||||
| @ -1803,7 +1918,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) | ||||
| 	lpfc_disc_illegal,		/* DEVICE_RECOVERY */ | ||||
| 
 | ||||
| 	lpfc_rcv_plogi_plogi_issue,	/* RCV_PLOGI   PLOGI_ISSUE    */ | ||||
| 	lpfc_rcv_els_plogi_issue,	/* RCV_PRLI        */ | ||||
| 	lpfc_rcv_prli_plogi_issue,	/* RCV_PRLI        */ | ||||
| 	lpfc_rcv_logo_plogi_issue,	/* RCV_LOGO        */ | ||||
| 	lpfc_rcv_els_plogi_issue,	/* RCV_ADISC       */ | ||||
| 	lpfc_rcv_els_plogi_issue,	/* RCV_PDISC       */ | ||||
| @ -1915,9 +2030,9 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 			"%d:0211 DSM in event x%x on NPort x%x in state %d " | ||||
| 			"Data: x%x\n", | ||||
| 			phba->brd_no, | ||||
| 			"%d (%d):0211 DSM in event x%x on NPort x%x in " | ||||
| 			"state %d Data: x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag); | ||||
| 
 | ||||
| 	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt]; | ||||
| @ -1925,9 +2040,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||||
| 
 | ||||
| 	/* DSM out state <rc> on NPort <nlp_DID> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||||
| 		       "%d:0212 DSM out state %d on NPort x%x Data: x%x\n", | ||||
| 		       phba->brd_no, | ||||
| 		       rc, ndlp->nlp_DID, ndlp->nlp_flag); | ||||
| 			"%d (%d):0212 DSM out state %d on NPort x%x " | ||||
| 			"Data: x%x\n", | ||||
| 			phba->brd_no, vport->vpi, | ||||
| 			rc, ndlp->nlp_DID, ndlp->nlp_flag); | ||||
| 
 | ||||
| 	lpfc_nlp_put(ndlp); | ||||
| 
 | ||||
|  | ||||
| @ -37,10 +37,159 @@ | ||||
| #include "lpfc.h" | ||||
| #include "lpfc_logmsg.h" | ||||
| #include "lpfc_crtn.h" | ||||
| #include "lpfc_vport.h" | ||||
| 
 | ||||
| #define LPFC_RESET_WAIT  2 | ||||
| #define LPFC_ABORT_WAIT  2 | ||||
| 
 | ||||
| /*
 | ||||
|  * This function is called with no lock held when there is a resource | ||||
|  * error in driver or in firmware. | ||||
|  */ | ||||
| void | ||||
| lpfc_adjust_queue_depth(struct lpfc_hba *phba) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->hbalock, flags); | ||||
| 	atomic_inc(&phba->num_rsrc_err); | ||||
| 	phba->last_rsrc_error_time = jiffies; | ||||
| 
 | ||||
| 	if ((phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL) > jiffies) { | ||||
| 		spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	phba->last_ramp_down_time = jiffies; | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->pport->work_port_lock, flags); | ||||
| 	if ((phba->pport->work_port_events & | ||||
| 		WORKER_RAMP_DOWN_QUEUE) == 0) { | ||||
| 		phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->hbalock, flags); | ||||
| 	if (phba->work_wait) | ||||
| 		wake_up(phba->work_wait); | ||||
| 	spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| 
 | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function is called with no lock held when there is a successful | ||||
|  * SCSI command completion. | ||||
|  */ | ||||
| static inline void | ||||
| lpfc_rampup_queue_depth(struct lpfc_hba *phba, | ||||
| 			struct scsi_device *sdev) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	atomic_inc(&phba->num_cmd_success); | ||||
| 
 | ||||
| 	if (phba->cfg_lun_queue_depth <= sdev->queue_depth) | ||||
| 		return; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->hbalock, flags); | ||||
| 	if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) || | ||||
| 	 ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) { | ||||
| 		spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	phba->last_ramp_up_time = jiffies; | ||||
| 	spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->pport->work_port_lock, flags); | ||||
| 	if ((phba->pport->work_port_events & | ||||
| 		WORKER_RAMP_UP_QUEUE) == 0) { | ||||
| 		phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&phba->hbalock, flags); | ||||
| 	if (phba->work_wait) | ||||
| 		wake_up(phba->work_wait); | ||||
| 	spin_unlock_irqrestore(&phba->hbalock, flags); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport; | ||||
| 	struct Scsi_Host  *host; | ||||
| 	struct scsi_device *sdev; | ||||
| 	unsigned long new_queue_depth; | ||||
| 	unsigned long num_rsrc_err, num_cmd_success; | ||||
| 
 | ||||
| 	num_rsrc_err = atomic_read(&phba->num_rsrc_err); | ||||
| 	num_cmd_success = atomic_read(&phba->num_cmd_success); | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		host = lpfc_shost_from_vport(vport); | ||||
| 		if (!scsi_host_get(host)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 		shost_for_each_device(sdev, host) { | ||||
| 			new_queue_depth = sdev->queue_depth * num_rsrc_err / | ||||
| 			(num_rsrc_err + num_cmd_success); | ||||
| 			if (!new_queue_depth) | ||||
| 				new_queue_depth = sdev->queue_depth - 1; | ||||
| 			else | ||||
| 				new_queue_depth = | ||||
| 					sdev->queue_depth - new_queue_depth; | ||||
| 
 | ||||
| 			if (sdev->ordered_tags) | ||||
| 				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, | ||||
| 					new_queue_depth); | ||||
| 			else | ||||
| 				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, | ||||
| 					new_queue_depth); | ||||
| 		} | ||||
| 		spin_lock_irq(&phba->hbalock); | ||||
| 		scsi_host_put(host); | ||||
| 	} | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	atomic_set(&phba->num_rsrc_err, 0); | ||||
| 	atomic_set(&phba->num_cmd_success, 0); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) | ||||
| { | ||||
| 	struct lpfc_vport *vport; | ||||
| 	struct Scsi_Host  *host; | ||||
| 	struct scsi_device *sdev; | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		host = lpfc_shost_from_vport(vport); | ||||
| 		if (!scsi_host_get(host)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		spin_unlock_irq(&phba->hbalock); | ||||
| 		shost_for_each_device(sdev, host) { | ||||
| 			if (sdev->ordered_tags) | ||||
| 				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, | ||||
| 					sdev->queue_depth+1); | ||||
| 			else | ||||
| 				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, | ||||
| 					sdev->queue_depth+1); | ||||
| 		} | ||||
| 		spin_lock_irq(&phba->hbalock); | ||||
| 		scsi_host_put(host); | ||||
| 	} | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	atomic_set(&phba->num_rsrc_err, 0); | ||||
| 	atomic_set(&phba->num_cmd_success, 0); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This routine allocates a scsi buffer, which contains all the necessary | ||||
|  * information needed to initiate a SCSI I/O.  The non-DMAable buffer region | ||||
| @ -154,7 +303,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) | ||||
| lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) | ||||
| { | ||||
| 	unsigned long iflag = 0; | ||||
| 
 | ||||
| @ -165,13 +314,16 @@ lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) | ||||
| lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) | ||||
| { | ||||
| 	struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; | ||||
| 	struct scatterlist *sgel = NULL; | ||||
| 	struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; | ||||
| 	struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl; | ||||
| 	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; | ||||
| 	uint32_t vpi = (lpfc_cmd->cur_iocbq.vport | ||||
| 			? lpfc_cmd->cur_iocbq.vport->vpi | ||||
| 			: 0); | ||||
| 	dma_addr_t physaddr; | ||||
| 	uint32_t i, num_bde = 0; | ||||
| 	int datadir = scsi_cmnd->sc_data_direction; | ||||
| @ -235,9 +387,9 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) | ||||
| 		dma_error = dma_mapping_error(physaddr); | ||||
| 		if (dma_error) { | ||||
| 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 				"%d:0718 Unable to dma_map_single " | ||||
| 				"request_buffer: x%x\n", | ||||
| 				phba->brd_no, dma_error); | ||||
| 					"%d (%d):0718 Unable to dma_map_single " | ||||
| 					"request_buffer: x%x\n", | ||||
| 					phba->brd_no, vpi, dma_error); | ||||
| 			return 1; | ||||
| 		} | ||||
| 
 | ||||
| @ -299,6 +451,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; | ||||
| 	struct lpfc_hba *phba = vport->phba; | ||||
| 	uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; | ||||
| 	uint32_t vpi = vport->vpi; | ||||
| 	uint32_t resp_info = fcprsp->rspStatus2; | ||||
| 	uint32_t scsi_status = fcprsp->rspStatus3; | ||||
| 	uint32_t *lp; | ||||
| @ -331,9 +484,9 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 		logit = LOG_FCP; | ||||
| 
 | ||||
| 	lpfc_printf_log(phba, KERN_WARNING, logit, | ||||
| 			"%d:0730 FCP command x%x failed: x%x SNS x%x x%x " | ||||
| 			"%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x " | ||||
| 			"Data: x%x x%x x%x x%x x%x\n", | ||||
| 			phba->brd_no, cmnd->cmnd[0], scsi_status, | ||||
| 			phba->brd_no, vpi, cmnd->cmnd[0], scsi_status, | ||||
| 			be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info, | ||||
| 			be32_to_cpu(fcprsp->rspResId), | ||||
| 			be32_to_cpu(fcprsp->rspSnsLen), | ||||
| @ -354,10 +507,11 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 		cmnd->resid = be32_to_cpu(fcprsp->rspResId); | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 				"%d:0716 FCP Read Underrun, expected %d, " | ||||
| 				"residual %d Data: x%x x%x x%x\n", phba->brd_no, | ||||
| 				be32_to_cpu(fcpcmd->fcpDl), cmnd->resid, | ||||
| 				fcpi_parm, cmnd->cmnd[0], cmnd->underflow); | ||||
| 				"%d (%d):0716 FCP Read Underrun, expected %d, " | ||||
| 				"residual %d Data: x%x x%x x%x\n", | ||||
| 				phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl), | ||||
| 				cmnd->resid, fcpi_parm, cmnd->cmnd[0], | ||||
| 				cmnd->underflow); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * If there is an under run check if under run reported by | ||||
| @ -368,12 +522,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 			fcpi_parm && | ||||
| 			(cmnd->resid != fcpi_parm)) { | ||||
| 			lpfc_printf_log(phba, KERN_WARNING, | ||||
| 				LOG_FCP | LOG_FCP_ERROR, | ||||
| 				"%d:0735 FCP Read Check Error and Underrun " | ||||
| 				"Data: x%x x%x x%x x%x\n", phba->brd_no, | ||||
| 				be32_to_cpu(fcpcmd->fcpDl), | ||||
| 				cmnd->resid, | ||||
| 				fcpi_parm, cmnd->cmnd[0]); | ||||
| 					LOG_FCP | LOG_FCP_ERROR, | ||||
| 					"%d (%d):0735 FCP Read Check Error " | ||||
| 					"and Underrun Data: x%x x%x x%x x%x\n", | ||||
| 					phba->brd_no, vpi, | ||||
| 					be32_to_cpu(fcpcmd->fcpDl), | ||||
| 					cmnd->resid, fcpi_parm, cmnd->cmnd[0]); | ||||
| 			cmnd->resid = cmnd->request_bufflen; | ||||
| 			host_status = DID_ERROR; | ||||
| 		} | ||||
| @ -387,19 +541,20 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 		    (scsi_status == SAM_STAT_GOOD) && | ||||
| 		    (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) { | ||||
| 			lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 					"%d:0717 FCP command x%x residual " | ||||
| 					"%d (%d):0717 FCP command x%x residual " | ||||
| 					"underrun converted to error " | ||||
| 					"Data: x%x x%x x%x\n", phba->brd_no, | ||||
| 					cmnd->cmnd[0], cmnd->request_bufflen, | ||||
| 					cmnd->resid, cmnd->underflow); | ||||
| 					"Data: x%x x%x x%x\n", | ||||
| 					phba->brd_no, vpi, cmnd->cmnd[0], | ||||
| 					cmnd->request_bufflen, cmnd->resid, | ||||
| 					cmnd->underflow); | ||||
| 
 | ||||
| 			host_status = DID_ERROR; | ||||
| 		} | ||||
| 	} else if (resp_info & RESID_OVER) { | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 				"%d:0720 FCP command x%x residual " | ||||
| 				"%d (%d):0720 FCP command x%x residual " | ||||
| 				"overrun error. Data: x%x x%x \n", | ||||
| 				phba->brd_no, cmnd->cmnd[0], | ||||
| 				phba->brd_no, vpi, cmnd->cmnd[0], | ||||
| 				cmnd->request_bufflen, cmnd->resid); | ||||
| 		host_status = DID_ERROR; | ||||
| 
 | ||||
| @ -410,11 +565,12 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | ||||
| 	} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm && | ||||
| 			(cmnd->sc_data_direction == DMA_FROM_DEVICE)) { | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, | ||||
| 			"%d:0734 FCP Read Check Error Data: " | ||||
| 			"x%x x%x x%x x%x\n", phba->brd_no, | ||||
| 			be32_to_cpu(fcpcmd->fcpDl), | ||||
| 			be32_to_cpu(fcprsp->rspResId), | ||||
| 			fcpi_parm, cmnd->cmnd[0]); | ||||
| 				"%d (%d):0734 FCP Read Check Error Data: " | ||||
| 				"x%x x%x x%x x%x\n", | ||||
| 				phba->brd_no, vpi, | ||||
| 				be32_to_cpu(fcpcmd->fcpDl), | ||||
| 				be32_to_cpu(fcprsp->rspResId), | ||||
| 				fcpi_parm, cmnd->cmnd[0]); | ||||
| 		host_status = DID_ERROR; | ||||
| 		cmnd->resid = cmnd->request_bufflen; | ||||
| 	} | ||||
| @ -433,6 +589,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata; | ||||
| 	struct lpfc_nodelist *pnode = rdata->pnode; | ||||
| 	struct scsi_cmnd *cmd = lpfc_cmd->pCmd; | ||||
| 	uint32_t vpi = (lpfc_cmd->cur_iocbq.vport | ||||
| 			? lpfc_cmd->cur_iocbq.vport->vpi | ||||
| 			: 0); | ||||
| 	int result; | ||||
| 	struct scsi_device *sdev, *tmp_sdev; | ||||
| 	int depth = 0; | ||||
| @ -448,11 +607,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 			lpfc_cmd->status = IOSTAT_DEFAULT; | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 				"%d:0729 FCP cmd x%x failed <%d/%d> status: " | ||||
| 				"x%x result: x%x Data: x%x x%x\n", | ||||
| 				phba->brd_no, cmd->cmnd[0], cmd->device->id, | ||||
| 				cmd->device->lun, lpfc_cmd->status, | ||||
| 				lpfc_cmd->result, pIocbOut->iocb.ulpContext, | ||||
| 				"%d (%d):0729 FCP cmd x%x failed <%d/%d> " | ||||
| 				"status: x%x result: x%x Data: x%x x%x\n", | ||||
| 				phba->brd_no, vpi, cmd->cmnd[0], | ||||
| 				cmd->device ? cmd->device->id : 0xffff, | ||||
| 				cmd->device ? cmd->device->lun : 0xffff, | ||||
| 				lpfc_cmd->status, lpfc_cmd->result, | ||||
| 				pIocbOut->iocb.ulpContext, | ||||
| 				lpfc_cmd->cur_iocbq.iocb.ulpIoTag); | ||||
| 
 | ||||
| 		switch (lpfc_cmd->status) { | ||||
| @ -464,6 +625,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 		case IOSTAT_FABRIC_BSY: | ||||
| 			cmd->result = ScsiResult(DID_BUS_BUSY, 0); | ||||
| 			break; | ||||
| 		case IOSTAT_LOCAL_REJECT: | ||||
| 			if (lpfc_cmd->result == RJT_UNAVAIL_PERM || | ||||
| 			    lpfc_cmd->result == IOERR_NO_RESOURCES || | ||||
| 			    lpfc_cmd->result == RJT_LOGIN_REQUIRED) { | ||||
| 				cmd->result = ScsiResult(DID_REQUEUE, 0); | ||||
| 			break; | ||||
| 		} /* else: fall through */ | ||||
| 		default: | ||||
| 			cmd->result = ScsiResult(DID_ERROR, 0); | ||||
| 			break; | ||||
| @ -480,9 +648,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 		uint32_t *lp = (uint32_t *)cmd->sense_buffer; | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 				"%d:0710 Iodone <%d/%d> cmd %p, error x%x " | ||||
| 				"SNS x%x x%x Data: x%x x%x\n", | ||||
| 				phba->brd_no, cmd->device->id, | ||||
| 				"%d (%d):0710 Iodone <%d/%d> cmd %p, error " | ||||
| 				"x%x SNS x%x x%x Data: x%x x%x\n", | ||||
| 				phba->brd_no, vpi, cmd->device->id, | ||||
| 				cmd->device->lun, cmd, cmd->result, | ||||
| 				*lp, *(lp + 3), cmd->retries, cmd->resid); | ||||
| 	} | ||||
| @ -497,6 +665,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (!result) | ||||
| 		lpfc_rampup_queue_depth(phba, sdev); | ||||
| 
 | ||||
| 	if (!result && pnode != NULL && | ||||
| 	   ((jiffies - pnode->last_ramp_up_time) > | ||||
| 		LPFC_Q_RAMP_UP_INTERVAL * HZ) && | ||||
| @ -545,8 +717,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | ||||
| 
 | ||||
| 		if (depth) { | ||||
| 			lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 				"%d:0711 detected queue full - lun queue depth " | ||||
| 				" adjusted to %d.\n", phba->brd_no, depth); | ||||
| 					"%d (%d):0711 detected queue full - " | ||||
| 					"lun queue depth  adjusted to %d.\n", | ||||
| 					phba->brd_no, vpi, depth); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -733,10 +906,10 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | ||||
| 
 | ||||
| 	/* Issue Target Reset to TGT <num> */ | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 			"%d:0702 Issue Target Reset to TGT %d " | ||||
| 			"%d (%d):0702 Issue Target Reset to TGT %d " | ||||
| 			"Data: x%x x%x\n", | ||||
| 			phba->brd_no, tgt_id, rdata->pnode->nlp_rpi, | ||||
| 			rdata->pnode->nlp_flag); | ||||
| 			phba->brd_no, vport->vpi, tgt_id, | ||||
| 			rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); | ||||
| 
 | ||||
| 	ret = lpfc_sli_issue_iocb_wait(phba, | ||||
| 				       &phba->sli.ring[phba->sli.fcp_ring], | ||||
| @ -842,9 +1015,12 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) | ||||
| 	} | ||||
| 	lpfc_cmd = lpfc_get_scsi_buf(phba); | ||||
| 	if (lpfc_cmd == NULL) { | ||||
| 		lpfc_adjust_queue_depth(phba); | ||||
| 
 | ||||
| 		lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 				"%d:0707 driver's buffer pool is empty, " | ||||
| 				"IO busied\n", phba->brd_no); | ||||
| 				"%d (%d):0707 driver's buffer pool is empty, " | ||||
| 				"IO busied\n", | ||||
| 				phba->brd_no, vport->vpi); | ||||
| 		goto out_host_busy; | ||||
| 	} | ||||
| 
 | ||||
| @ -865,7 +1041,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) | ||||
| 	lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); | ||||
| 
 | ||||
| 	err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], | ||||
| 				&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); | ||||
| 				  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); | ||||
| 	if (err) | ||||
| 		goto out_host_busy_free_buf; | ||||
| 
 | ||||
| @ -986,18 +1162,19 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) | ||||
| 	if (lpfc_cmd->pCmd == cmnd) { | ||||
| 		ret = FAILED; | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 				"%d:0748 abort handler timed out waiting for " | ||||
| 				"abort to complete: ret %#x, ID %d, LUN %d, " | ||||
| 				"snum %#lx\n", | ||||
| 				phba->brd_no,  ret, cmnd->device->id, | ||||
| 				cmnd->device->lun, cmnd->serial_number); | ||||
| 				"%d (%d):0748 abort handler timed out waiting " | ||||
| 				"for abort to complete: ret %#x, ID %d, " | ||||
| 				"LUN %d, snum %#lx\n", | ||||
| 				phba->brd_no, vport->vpi, ret, | ||||
| 				cmnd->device->id, cmnd->device->lun, | ||||
| 				cmnd->serial_number); | ||||
| 	} | ||||
| 
 | ||||
|  out: | ||||
| 	lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 			"%d:0749 SCSI Layer I/O Abort Request " | ||||
| 			"%d (%d):0749 SCSI Layer I/O Abort Request " | ||||
| 			"Status x%x ID %d LUN %d snum %#lx\n", | ||||
| 			phba->brd_no, ret, cmnd->device->id, | ||||
| 			phba->brd_no, vport->vpi, ret, cmnd->device->id, | ||||
| 			cmnd->device->lun, cmnd->serial_number); | ||||
| 
 | ||||
| 	return ret; | ||||
| @ -1024,7 +1201,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 	 * If target is not in a MAPPED state, delay the reset until | ||||
| 	 * target is rediscovered or devloss timeout expires. | ||||
| 	 */ | ||||
| 	while ( 1 ) { | ||||
| 	while (1) { | ||||
| 		if (!pnode) | ||||
| 			goto out; | ||||
| 
 | ||||
| @ -1035,9 +1212,10 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 			if (!rdata || | ||||
| 				(loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) { | ||||
| 				lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 		   			"%d:0721 LUN Reset rport failure:" | ||||
| 					" cnt x%x rdata x%p\n", | ||||
| 		   			phba->brd_no, loopcnt, rdata); | ||||
| 						"%d (%d):0721 LUN Reset rport " | ||||
| 						"failure: cnt x%x rdata x%p\n", | ||||
| 						phba->brd_no, vport->vpi, | ||||
| 						loopcnt, rdata); | ||||
| 				goto out; | ||||
| 			} | ||||
| 			pnode = rdata->pnode; | ||||
| @ -1068,8 +1246,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 		goto out_free_scsi_buf; | ||||
| 
 | ||||
| 	lpfc_printf_log(phba, KERN_INFO, LOG_FCP, | ||||
| 			"%d:0703 Issue target reset to TGT %d LUN %d rpi x%x " | ||||
| 			"nlp_flag x%x\n", phba->brd_no, cmnd->device->id, | ||||
| 			"%d (%d):0703 Issue target reset to TGT %d LUN %d " | ||||
| 			"rpi x%x nlp_flag x%x\n", | ||||
| 			phba->brd_no, vport->vpi, cmnd->device->id, | ||||
| 			cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); | ||||
| 
 | ||||
| 	iocb_status = lpfc_sli_issue_iocb_wait(phba, | ||||
| @ -1103,7 +1282,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 				    cmnd->device->id, cmnd->device->lun, | ||||
| 				    0, LPFC_CTX_LUN); | ||||
| 	loopcnt = 0; | ||||
| 	while (cnt) { | ||||
| 	while(cnt) { | ||||
| 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | ||||
| 
 | ||||
| 		if (++loopcnt | ||||
| @ -1118,8 +1297,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 
 | ||||
| 	if (cnt) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 			"%d:0719 device reset I/O flush failure: cnt x%x\n", | ||||
| 			phba->brd_no, cnt); | ||||
| 				"%d (%d):0719 device reset I/O flush failure: " | ||||
| 				"cnt x%x\n", | ||||
| 				phba->brd_no, vport->vpi, cnt); | ||||
| 		ret = FAILED; | ||||
| 	} | ||||
| 
 | ||||
| @ -1128,10 +1308,10 @@ out_free_scsi_buf: | ||||
| 		lpfc_release_scsi_buf(phba, lpfc_cmd); | ||||
| 	} | ||||
| 	lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 			"%d:0713 SCSI layer issued device reset (%d, %d) " | ||||
| 			"%d (%d):0713 SCSI layer issued device reset (%d, %d) " | ||||
| 			"return x%x status x%x result x%x\n", | ||||
| 			phba->brd_no, cmnd->device->id, cmnd->device->lun, | ||||
| 			ret, cmd_status, cmd_result); | ||||
| 			phba->brd_no, vport->vpi, cmnd->device->id, | ||||
| 			cmnd->device->lun, ret, cmd_status, cmd_result); | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| @ -1184,8 +1364,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 					  ndlp->rport->dd_data); | ||||
| 		if (ret != SUCCESS) { | ||||
| 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 				"%d:0700 Bus Reset on target %d failed\n", | ||||
| 				phba->brd_no, i); | ||||
| 					"%d (%d):0700 Bus Reset on target %d " | ||||
| 					"failed\n", | ||||
| 					phba->brd_no, vport->vpi, i); | ||||
| 			err_count++; | ||||
| 			break; | ||||
| 		} | ||||
| @ -1210,7 +1391,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], | ||||
| 				    0, 0, 0, LPFC_CTX_HOST); | ||||
| 	loopcnt = 0; | ||||
| 	while (cnt) { | ||||
| 	while(cnt) { | ||||
| 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | ||||
| 
 | ||||
| 		if (++loopcnt | ||||
| @ -1224,16 +1405,15 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | ||||
| 
 | ||||
| 	if (cnt) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 		   "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n", | ||||
| 		   phba->brd_no, cnt, i); | ||||
| 				"%d (%d):0715 Bus Reset I/O flush failure: " | ||||
| 				"cnt x%x left x%x\n", | ||||
| 				phba->brd_no, vport->vpi, cnt, i); | ||||
| 		ret = FAILED; | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_printf_log(phba, | ||||
| 			KERN_ERR, | ||||
| 			LOG_FCP, | ||||
| 			"%d:0714 SCSI layer issued Bus Reset Data: x%x\n", | ||||
| 			phba->brd_no, ret); | ||||
| 	lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 			"%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n", | ||||
| 			phba->brd_no, vport->vpi, ret); | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| @ -1263,17 +1443,24 @@ lpfc_slave_alloc(struct scsi_device *sdev) | ||||
| 	 */ | ||||
| 	total = phba->total_scsi_bufs; | ||||
| 	num_to_alloc = phba->cfg_lun_queue_depth + 2; | ||||
| 	if (total >= phba->cfg_hba_queue_depth) { | ||||
| 
 | ||||
| 	/* Allow some exchanges to be available always to complete discovery */ | ||||
| 	if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) { | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 				"%d:0704 At limitation of %d preallocated " | ||||
| 				"command buffers\n", phba->brd_no, total); | ||||
| 				"%d (%d):0704 At limitation of %d " | ||||
| 				"preallocated command buffers\n", | ||||
| 				phba->brd_no, vport->vpi, total); | ||||
| 		return 0; | ||||
| 	} else if (total + num_to_alloc > phba->cfg_hba_queue_depth) { | ||||
| 
 | ||||
| 	/* Allow some exchanges to be available always to complete discovery */ | ||||
| 	} else if (total + num_to_alloc > | ||||
| 		phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) { | ||||
| 		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, | ||||
| 				"%d:0705 Allocation request of %d command " | ||||
| 				"buffers will exceed max of %d.  Reducing " | ||||
| 				"allocation request to %d.\n", phba->brd_no, | ||||
| 				num_to_alloc, phba->cfg_hba_queue_depth, | ||||
| 				"%d (%d):0705 Allocation request of %d " | ||||
| 				"command buffers will exceed max of %d.  " | ||||
| 				"Reducing allocation request to %d.\n", | ||||
| 				phba->brd_no, vport->vpi, num_to_alloc, | ||||
| 				phba->cfg_hba_queue_depth, | ||||
| 				(phba->cfg_hba_queue_depth - total)); | ||||
| 		num_to_alloc = phba->cfg_hba_queue_depth - total; | ||||
| 	} | ||||
| @ -1282,8 +1469,9 @@ lpfc_slave_alloc(struct scsi_device *sdev) | ||||
| 		scsi_buf = lpfc_new_scsi_buf(vport); | ||||
| 		if (!scsi_buf) { | ||||
| 			lpfc_printf_log(phba, KERN_ERR, LOG_FCP, | ||||
| 					"%d:0706 Failed to allocate command " | ||||
| 					"buffer\n", phba->brd_no); | ||||
| 					"%d (%d):0706 Failed to allocate " | ||||
| 					"command buffer\n", | ||||
| 					phba->brd_no, vport->vpi); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| @ -1331,6 +1519,7 @@ lpfc_slave_destroy(struct scsi_device *sdev) | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct scsi_host_template lpfc_template = { | ||||
| 	.module			= THIS_MODULE, | ||||
| 	.name			= LPFC_DRIVER_NAME, | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -44,6 +44,7 @@ struct lpfc_iocbq { | ||||
| #define LPFC_IO_WAKE		2	/* High Priority Queue signal flag */ | ||||
| #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */ | ||||
| #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */ | ||||
| #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */ | ||||
| 
 | ||||
| 	uint8_t abort_count; | ||||
| 	uint8_t rsvd2; | ||||
| @ -58,6 +59,8 @@ struct lpfc_iocbq { | ||||
| 		struct lpfcMboxq   *mbox; | ||||
| 	} context_un; | ||||
| 
 | ||||
| 	void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||||
| 			   struct lpfc_iocbq *); | ||||
| 	void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||||
| 			   struct lpfc_iocbq *); | ||||
| 
 | ||||
| @ -173,7 +176,7 @@ struct lpfc_sli_ring { | ||||
| /* Structure used for configuring rings to a specific profile or rctl / type */ | ||||
| struct lpfc_hbq_init { | ||||
| 	uint32_t rn;		/* Receive buffer notification */ | ||||
| 	uint32_t entry_count;	/* # of entries in HBQ */ | ||||
| 	uint32_t entry_count;	/* max # of entries in HBQ */ | ||||
| 	uint32_t headerLen;	/* 0 if not profile 4 or 5 */ | ||||
| 	uint32_t logEntry;	/* Set to 1 if this HBQ used for LogEntry */ | ||||
| 	uint32_t profile;	/* Selection profile 0=all, 7=logentry */ | ||||
| @ -188,6 +191,11 @@ struct lpfc_hbq_init { | ||||
| 	uint32_t cmdmatch[8]; | ||||
| 	uint32_t mask_count;	/* number of mask entries in prt array */ | ||||
| 	struct hbq_mask hbqMasks[6]; | ||||
| 
 | ||||
| 	/* Non-config rings fields to keep track of buffer allocations */ | ||||
| 	uint32_t buffer_count;	/* number of buffers allocated */ | ||||
| 	uint32_t init_count;	/* number to allocate when initialized */ | ||||
| 	uint32_t add_count;	/* number to allocate when starved */ | ||||
| } ; | ||||
| 
 | ||||
| #define LPFC_MAX_HBQ 16 | ||||
| @ -238,6 +246,7 @@ struct lpfc_sli { | ||||
| 	uint16_t mboxq_cnt;	/* current length of queue */ | ||||
| 	uint16_t mboxq_max;	/* max length */ | ||||
| 	LPFC_MBOXQ_t *mbox_active;	/* active mboxq information */ | ||||
| 	struct list_head mboxq_cmpl; | ||||
| 
 | ||||
| 	struct timer_list mbox_tmo;	/* Hold clk to timeout active mbox
 | ||||
| 					   cmd */ | ||||
| @ -250,12 +259,6 @@ struct lpfc_sli { | ||||
| 	struct lpfc_lnk_stat lnk_stat_offsets; | ||||
| }; | ||||
| 
 | ||||
| /* Given a pointer to the start of the ring, and the slot number of
 | ||||
|  * the desired iocb entry, calc a pointer to that entry. | ||||
|  * (assume iocb entry size is 32 bytes, or 8 words) | ||||
|  */ | ||||
| #define IOCB_ENTRY(ring,slot) ((IOCB_t *)(((char *)(ring)) + ((slot) * 32))) | ||||
| 
 | ||||
| #define LPFC_MBOX_TMO           30	/* Sec tmo for outstanding mbox | ||||
| 					   command */ | ||||
| #define LPFC_MBOX_TMO_FLASH_CMD 300     /* Sec tmo for outstanding FLASH write | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
|  * included with this package.                                     * | ||||
|  *******************************************************************/ | ||||
| 
 | ||||
| #define LPFC_DRIVER_VERSION "8.1.12_sli3" | ||||
| #define LPFC_DRIVER_VERSION "8.2.0" | ||||
| 
 | ||||
| #define LPFC_DRIVER_NAME "lpfc" | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										508
									
								
								drivers/scsi/lpfc/lpfc_vport.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										508
									
								
								drivers/scsi/lpfc/lpfc_vport.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,508 @@ | ||||
| /*******************************************************************
 | ||||
|  * This file is part of the Emulex Linux Device Driver for         * | ||||
|  * Fibre Channel Host Bus Adapters.                                * | ||||
|  * Copyright (C) 2004-2006 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/blkdev.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/idr.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/kthread.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/spinlock.h> | ||||
| 
 | ||||
| #include <scsi/scsi.h> | ||||
| #include <scsi/scsi_device.h> | ||||
| #include <scsi/scsi_host.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_crtn.h" | ||||
| #include "lpfc_version.h" | ||||
| #include "lpfc_vport.h" | ||||
| 
 | ||||
| inline void lpfc_vport_set_state(struct lpfc_vport *vport, | ||||
| 				 enum fc_vport_state new_state) | ||||
| { | ||||
| 	struct fc_vport *fc_vport = vport->fc_vport; | ||||
| 
 | ||||
| 	if (fc_vport) { | ||||
| 		/*
 | ||||
| 		 * When the transport defines fc_vport_set state we will replace | ||||
| 		 * this code with the following line | ||||
| 		 */ | ||||
| 		/* fc_vport_set_state(fc_vport, new_state); */ | ||||
| 		if (new_state != FC_VPORT_INITIALIZING) | ||||
| 			fc_vport->vport_last_state = fc_vport->vport_state; | ||||
| 		fc_vport->vport_state = new_state; | ||||
| 	} | ||||
| 
 | ||||
| 	/* for all the error states we will set the invternal state to FAILED */ | ||||
| 	switch (new_state) { | ||||
| 	case FC_VPORT_NO_FABRIC_SUPP: | ||||
| 	case FC_VPORT_NO_FABRIC_RSCS: | ||||
| 	case FC_VPORT_FABRIC_LOGOUT: | ||||
| 	case FC_VPORT_FABRIC_REJ_WWN: | ||||
| 	case FC_VPORT_FAILED: | ||||
| 		vport->port_state = LPFC_VPORT_FAILED; | ||||
| 		break; | ||||
| 	case FC_VPORT_LINKDOWN: | ||||
| 		vport->port_state = LPFC_VPORT_UNKNOWN; | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* do nothing */ | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_alloc_vpi(struct lpfc_hba *phba) | ||||
| { | ||||
| 	int  vpi; | ||||
| 
 | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	vpi = find_next_zero_bit(phba->vpi_bmask, phba->max_vpi, 1); | ||||
| 	if (vpi > phba->max_vpi) | ||||
| 		vpi = 0; | ||||
| 	else | ||||
| 		set_bit(vpi, phba->vpi_bmask); | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 	return vpi; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lpfc_free_vpi(struct lpfc_hba *phba, int vpi) | ||||
| { | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	clear_bit(vpi, phba->vpi_bmask); | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) | ||||
| { | ||||
| 	LPFC_MBOXQ_t *pmb; | ||||
| 	MAILBOX_t *mb; | ||||
| 	struct lpfc_dmabuf *mp; | ||||
| 	int  rc; | ||||
| 
 | ||||
| 	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||||
| 	if (!pmb) { | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	mb = &pmb->mb; | ||||
| 
 | ||||
| 	lpfc_read_sparam(phba, pmb, vport->vpi); | ||||
| 	/*
 | ||||
| 	 * Grab buffer pointer and clear context1 so we can use | ||||
| 	 * lpfc_sli_issue_box_wait | ||||
| 	 */ | ||||
| 	mp = (struct lpfc_dmabuf *) pmb->context1; | ||||
| 	pmb->context1 = NULL; | ||||
| 
 | ||||
| 	pmb->vport = vport; | ||||
| 	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); | ||||
| 	if (rc != MBX_SUCCESS) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, | ||||
| 				"%d (%d):1818 VPort failed init, mbxCmd x%x " | ||||
| 				"READ_SPARM mbxStatus x%x, rc = x%x\n", | ||||
| 				phba->brd_no, vport->vpi, | ||||
| 				mb->mbxCommand, mb->mbxStatus, rc); | ||||
| 		lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 		kfree(mp); | ||||
| 		mempool_free(pmb, phba->mbox_mem_pool); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); | ||||
| 	memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, | ||||
| 	       sizeof (struct lpfc_name)); | ||||
| 	memcpy(&vport->fc_portname, &vport->fc_sparam.portName, | ||||
| 	       sizeof (struct lpfc_name)); | ||||
| 
 | ||||
| 	lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||||
| 	kfree(mp); | ||||
| 	mempool_free(pmb, phba->mbox_mem_pool); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn, | ||||
| 		      const char *name_type) | ||||
| { | ||||
| 				/* ensure that IEEE format 1 addresses
 | ||||
| 				 * contain zeros in bits 59-48 | ||||
| 				 */ | ||||
| 	if (!((wwn->u.wwn[0] >> 4) == 1 && | ||||
| 	      ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0))) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 			"%d:1822 Invalid %s: %02x:%02x:%02x:%02x:" | ||||
| 			"%02x:%02x:%02x:%02x\n", | ||||
| 			phba->brd_no, name_type, | ||||
| 			wwn->u.wwn[0], wwn->u.wwn[1], | ||||
| 			wwn->u.wwn[2], wwn->u.wwn[3], | ||||
| 			wwn->u.wwn[4], wwn->u.wwn[5], | ||||
| 			wwn->u.wwn[6], wwn->u.wwn[7]); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) | ||||
| { | ||||
| 	struct lpfc_vport *vport; | ||||
| 
 | ||||
| 	list_for_each_entry(vport, &phba->port_list, listentry) { | ||||
| 		if (vport == new_vport) | ||||
| 			continue; | ||||
| 		/* If they match, return not unique */ | ||||
| 		if (memcmp(&vport->fc_sparam.portName, | ||||
| 			&new_vport->fc_sparam.portName, | ||||
| 			sizeof(struct lpfc_name)) == 0) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | ||||
| { | ||||
| 	struct lpfc_nodelist *ndlp; | ||||
| 	struct lpfc_vport *pport = | ||||
| 		(struct lpfc_vport *) fc_vport->shost->hostdata; | ||||
| 	struct lpfc_hba   *phba = pport->phba; | ||||
| 	struct lpfc_vport *vport = NULL; | ||||
| 	int instance; | ||||
| 	int vpi; | ||||
| 	int rc = VPORT_ERROR; | ||||
| 
 | ||||
| 	if ((phba->sli_rev < 3) || | ||||
| 		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1808 Create VPORT failed: " | ||||
| 				"NPIV is not enabled: SLImode:%d\n", | ||||
| 				phba->brd_no, phba->sli_rev); | ||||
| 		rc = VPORT_INVAL; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	vpi = lpfc_alloc_vpi(phba); | ||||
| 	if (vpi == 0) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1809 Create VPORT failed: " | ||||
| 				"Max VPORTs (%d) exceeded\n", | ||||
| 				phba->brd_no, phba->max_vpi); | ||||
| 		rc = VPORT_NORESOURCES; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/* Assign an unused board number */ | ||||
| 	if ((instance = lpfc_get_instance()) < 0) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1810 Create VPORT failed: Cannot get " | ||||
| 				"instance number\n", phba->brd_no); | ||||
| 		lpfc_free_vpi(phba, vpi); | ||||
| 		rc = VPORT_NORESOURCES; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	vport = lpfc_create_port(phba, instance, fc_vport); | ||||
| 	if (!vport) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1811 Create VPORT failed: vpi x%x\n", | ||||
| 				phba->brd_no, vpi); | ||||
| 		lpfc_free_vpi(phba, vpi); | ||||
| 		rc = VPORT_NORESOURCES; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	vport->vpi = vpi; | ||||
| 	if (lpfc_vport_sparm(phba, vport)) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1813 Create VPORT failed: vpi:%d " | ||||
| 				"Cannot get sparam\n", | ||||
| 				phba->brd_no, vpi); | ||||
| 		lpfc_free_vpi(phba, vpi); | ||||
| 		destroy_port(vport); | ||||
| 		rc = VPORT_NORESOURCES; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); | ||||
| 	memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); | ||||
| 
 | ||||
| 	if (fc_vport->node_name != 0) | ||||
| 		u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); | ||||
| 	if (fc_vport->port_name != 0) | ||||
| 		u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn); | ||||
| 
 | ||||
| 	memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8); | ||||
| 	memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8); | ||||
| 
 | ||||
| 	if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") || | ||||
| 	    !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1821 Create VPORT failed: vpi:%d " | ||||
| 				"Invalid WWN format\n", | ||||
| 				phba->brd_no, vpi); | ||||
| 		lpfc_free_vpi(phba, vpi); | ||||
| 		destroy_port(vport); | ||||
| 		rc = VPORT_INVAL; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!lpfc_unique_wwpn(phba, vport)) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1823 Create VPORT failed: vpi:%d " | ||||
| 				"Duplicate WWN on HBA\n", | ||||
| 				phba->brd_no, vpi); | ||||
| 		lpfc_free_vpi(phba, vpi); | ||||
| 		destroy_port(vport); | ||||
| 		rc = VPORT_INVAL; | ||||
| 		goto error_out; | ||||
| 	} | ||||
| 
 | ||||
| 	*(struct lpfc_vport **)fc_vport->dd_data = vport; | ||||
| 	vport->fc_vport = fc_vport; | ||||
| 
 | ||||
| 	if ((phba->link_state < LPFC_LINK_UP) || | ||||
| 	    (phba->fc_topology == TOPOLOGY_LOOP)) { | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); | ||||
| 		rc = VPORT_OK; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (disable) { | ||||
| 		rc = VPORT_OK; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Use the Physical nodes Fabric NDLP to determine if the link is
 | ||||
| 	 * up and ready to FDISC. | ||||
| 	 */ | ||||
| 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | ||||
| 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||||
| 		lpfc_set_disctmo(vport); | ||||
| 		lpfc_initial_fdisc(vport); | ||||
| 	} else { | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||||
| 	} | ||||
| 	rc = VPORT_OK; | ||||
| 
 | ||||
| out: | ||||
| 	lpfc_host_attrib_init(lpfc_shost_from_vport(vport)); | ||||
| error_out: | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| disable_vport(struct fc_vport *fc_vport) | ||||
| { | ||||
| 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 	struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; | ||||
| 	long timeout; | ||||
| 
 | ||||
| 	ndlp = lpfc_findnode_did(vport, Fabric_DID); | ||||
| 	if (ndlp && phba->link_state >= LPFC_LINK_UP) { | ||||
| 		vport->unreg_vpi_cmpl = VPORT_INVAL; | ||||
| 		timeout = msecs_to_jiffies(phba->fc_ratov * 2000); | ||||
| 		if (!lpfc_issue_els_npiv_logo(vport, ndlp)) | ||||
| 			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) | ||||
| 				timeout = schedule_timeout(timeout); | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_sli_host_down(vport); | ||||
| 
 | ||||
| 	/* Mark all nodes for discovery so we can remove them by
 | ||||
| 	 * calling lpfc_cleanup_rpis(vport, 1) | ||||
| 	 */ | ||||
| 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | ||||
| 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||||
| 			continue; | ||||
| 		lpfc_disc_state_machine(vport, ndlp, NULL, | ||||
| 					NLP_EVT_DEVICE_RECOVERY); | ||||
| 	} | ||||
| 	lpfc_cleanup_rpis(vport, 1); | ||||
| 
 | ||||
| 	lpfc_stop_vport_timers(vport); | ||||
| 	lpfc_unreg_all_rpis(vport); | ||||
| 	lpfc_unreg_default_rpis(vport); | ||||
| 	/*
 | ||||
| 	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the | ||||
| 	 * scsi_host_put() to release the vport. | ||||
| 	 */ | ||||
| 	lpfc_mbx_unreg_vpi(vport); | ||||
| 
 | ||||
| 	lpfc_vport_set_state(vport, FC_VPORT_DISABLED); | ||||
| 	return VPORT_OK; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| enable_vport(struct fc_vport *fc_vport) | ||||
| { | ||||
| 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 	struct lpfc_nodelist *ndlp = NULL; | ||||
| 
 | ||||
| 	if ((phba->link_state < LPFC_LINK_UP) || | ||||
| 	    (phba->fc_topology == TOPOLOGY_LOOP)) { | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); | ||||
| 		return VPORT_OK; | ||||
| 	} | ||||
| 
 | ||||
| 	vport->load_flag |= FC_LOADING; | ||||
| 	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | ||||
| 
 | ||||
| 	/* Use the Physical nodes Fabric NDLP to determine if the link is
 | ||||
| 	 * up and ready to FDISC. | ||||
| 	 */ | ||||
| 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | ||||
| 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||||
| 		lpfc_set_disctmo(vport); | ||||
| 		lpfc_initial_fdisc(vport); | ||||
| 	} else { | ||||
| 		lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||||
| 	} | ||||
| 
 | ||||
| 	return VPORT_OK; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| lpfc_vport_disable(struct fc_vport *fc_vport, bool disable) | ||||
| { | ||||
| 	if (disable) | ||||
| 		return disable_vport(fc_vport); | ||||
| 	else | ||||
| 		return enable_vport(fc_vport); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int | ||||
| lpfc_vport_delete(struct fc_vport *fc_vport) | ||||
| { | ||||
| 	struct lpfc_nodelist *ndlp = NULL; | ||||
| 	struct lpfc_nodelist *next_ndlp; | ||||
| 	struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; | ||||
| 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; | ||||
| 	struct lpfc_hba   *phba = vport->phba; | ||||
| 	long timeout; | ||||
| 	int rc = VPORT_ERROR; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This is a bit of a mess.  We want to ensure the shost doesn't get | ||||
| 	 * torn down until we're done with the embedded lpfc_vport structure. | ||||
| 	 * | ||||
| 	 * Beyond holding a reference for this function, we also need a | ||||
| 	 * reference for outstanding I/O requests we schedule during delete | ||||
| 	 * processing.  But once we scsi_remove_host() we can no longer obtain | ||||
| 	 * a reference through scsi_host_get(). | ||||
| 	 * | ||||
| 	 * So we take two references here.  We release one reference at the | ||||
| 	 * bottom of the function -- after delinking the vport.  And we | ||||
| 	 * release the other at the completion of the unreg_vpi that get's | ||||
| 	 * initiated after we've disposed of all other resources associated | ||||
| 	 * with the port. | ||||
| 	 */ | ||||
| 	if (!scsi_host_get(shost) || !scsi_host_get(shost)) | ||||
| 		return VPORT_INVAL; | ||||
| 
 | ||||
| 	if (vport->port_type == LPFC_PHYSICAL_PORT) { | ||||
| 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||||
| 				"%d:1812 vport_delete failed: Cannot delete " | ||||
| 				"physical host\n", phba->brd_no); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	vport->load_flag |= FC_UNLOADING; | ||||
| 
 | ||||
| 	kfree(vport->vname); | ||||
| 	fc_remove_host(lpfc_shost_from_vport(vport)); | ||||
| 	scsi_remove_host(lpfc_shost_from_vport(vport)); | ||||
| 
 | ||||
| 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | ||||
| 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && | ||||
| 		phba->link_state >= LPFC_LINK_UP) { | ||||
| 
 | ||||
| 		/* First look for the Fabric ndlp */ | ||||
| 		ndlp = lpfc_findnode_did(vport, Fabric_DID); | ||||
| 		if (!ndlp) { | ||||
| 			/* Cannot find existing Fabric ndlp, allocate one */ | ||||
| 			ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||||
| 			if (!ndlp) | ||||
| 				goto skip_logo; | ||||
| 			lpfc_nlp_init(vport, ndlp, Fabric_DID); | ||||
| 		} else { | ||||
| 			lpfc_dequeue_node(vport, ndlp); | ||||
| 		} | ||||
| 		vport->unreg_vpi_cmpl = VPORT_INVAL; | ||||
| 		timeout = msecs_to_jiffies(phba->fc_ratov * 2000); | ||||
| 		if (!lpfc_issue_els_npiv_logo(vport, ndlp)) | ||||
| 			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) | ||||
| 				timeout = schedule_timeout(timeout); | ||||
| 	} | ||||
| 
 | ||||
| skip_logo: | ||||
| 	lpfc_sli_host_down(vport); | ||||
| 
 | ||||
| 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | ||||
| 		lpfc_disc_state_machine(vport, ndlp, NULL, | ||||
| 					     NLP_EVT_DEVICE_RECOVERY); | ||||
| 		lpfc_disc_state_machine(vport, ndlp, NULL, | ||||
| 					     NLP_EVT_DEVICE_RM); | ||||
| 	} | ||||
| 
 | ||||
| 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | ||||
| 		/* free any ndlp's in unused state */ | ||||
| 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||||
| 			lpfc_drop_node(vport, ndlp); | ||||
| 	} | ||||
| 
 | ||||
| 	lpfc_stop_vport_timers(vport); | ||||
| 	lpfc_unreg_all_rpis(vport); | ||||
| 	lpfc_unreg_default_rpis(vport); | ||||
| 	/*
 | ||||
| 	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the | ||||
| 	 * scsi_host_put() to release the vport. | ||||
| 	 */ | ||||
| 	lpfc_mbx_unreg_vpi(vport); | ||||
| 
 | ||||
| 	lpfc_free_vpi(phba, vport->vpi); | ||||
| 	vport->work_port_events = 0; | ||||
| 	spin_lock_irq(&phba->hbalock); | ||||
| 	list_del_init(&vport->listentry); | ||||
| 	spin_unlock_irq(&phba->hbalock); | ||||
| 
 | ||||
| 	rc = VPORT_OK; | ||||
| out: | ||||
| 	scsi_host_put(shost); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| EXPORT_SYMBOL(lpfc_vport_create); | ||||
| EXPORT_SYMBOL(lpfc_vport_delete); | ||||
							
								
								
									
										113
									
								
								drivers/scsi/lpfc/lpfc_vport.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								drivers/scsi/lpfc/lpfc_vport.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | ||||
| /*******************************************************************
 | ||||
|  * This file is part of the Emulex Linux Device Driver for         * | ||||
|  * Fibre Channel Host Bus Adapters.                                * | ||||
|  * Copyright (C) 2004-2006 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.                                     * | ||||
|  *******************************************************************/ | ||||
| 
 | ||||
| #ifndef _H_LPFC_VPORT | ||||
| #define _H_LPFC_VPORT | ||||
| 
 | ||||
| /* API version values (each will be an individual bit) */ | ||||
| #define VPORT_API_VERSION_1	0x01 | ||||
| 
 | ||||
| /* Values returned via lpfc_vport_getinfo() */ | ||||
| struct vport_info { | ||||
| 
 | ||||
| 	uint32_t api_versions; | ||||
| 	uint8_t linktype; | ||||
| #define  VPORT_TYPE_PHYSICAL	0 | ||||
| #define  VPORT_TYPE_VIRTUAL	1 | ||||
| 
 | ||||
| 	uint8_t state; | ||||
| #define  VPORT_STATE_OFFLINE	0 | ||||
| #define  VPORT_STATE_ACTIVE	1 | ||||
| #define  VPORT_STATE_FAILED	2 | ||||
| 
 | ||||
| 	uint8_t fail_reason; | ||||
| 	uint8_t prev_fail_reason; | ||||
| #define  VPORT_FAIL_UNKNOWN	0 | ||||
| #define  VPORT_FAIL_LINKDOWN	1 | ||||
| #define  VPORT_FAIL_FAB_UNSUPPORTED	2 | ||||
| #define  VPORT_FAIL_FAB_NORESOURCES	3 | ||||
| #define  VPORT_FAIL_FAB_LOGOUT	4 | ||||
| #define  VPORT_FAIL_ADAP_NORESOURCES	5 | ||||
| 
 | ||||
| 	uint8_t node_name[8];	/* WWNN */ | ||||
| 	uint8_t port_name[8];	/* WWPN */ | ||||
| 
 | ||||
| 	struct Scsi_Host *shost; | ||||
| 
 | ||||
| /* Following values are valid only on physical links */ | ||||
| 	uint32_t vports_max; | ||||
| 	uint32_t vports_inuse; | ||||
| 	uint32_t rpi_max; | ||||
| 	uint32_t rpi_inuse; | ||||
| #define  VPORT_CNT_INVALID	0xFFFFFFFF | ||||
| }; | ||||
| 
 | ||||
| /* data used  in link creation */ | ||||
| struct vport_data { | ||||
| 	uint32_t api_version; | ||||
| 
 | ||||
| 	uint32_t options; | ||||
| #define  VPORT_OPT_AUTORETRY	0x01 | ||||
| 
 | ||||
| 	uint8_t node_name[8];	/* WWNN */ | ||||
| 	uint8_t port_name[8];	/* WWPN */ | ||||
| 
 | ||||
| /*
 | ||||
|  *  Upon successful creation, vport_shost will point to the new Scsi_Host | ||||
|  *  structure for the new virtual link. | ||||
|  */ | ||||
| 	struct Scsi_Host *vport_shost; | ||||
| }; | ||||
| 
 | ||||
| /* API function return codes */ | ||||
| #define VPORT_OK	0 | ||||
| #define VPORT_ERROR	-1 | ||||
| #define VPORT_INVAL	-2 | ||||
| #define VPORT_NOMEM	-3 | ||||
| #define VPORT_NORESOURCES	-4 | ||||
| 
 | ||||
| int lpfc_vport_create(struct fc_vport *, bool); | ||||
| int lpfc_vport_delete(struct fc_vport *); | ||||
| int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); | ||||
| int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); | ||||
| 
 | ||||
| /*
 | ||||
|  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code. | ||||
|  *  Returned when the virtual link has failed or is not active. | ||||
|  */ | ||||
| #define  DID_VPORT_ERROR	0x0f | ||||
| 
 | ||||
| #define VPORT_INFO	0x1 | ||||
| #define VPORT_CREATE	0x2 | ||||
| #define VPORT_DELETE	0x4 | ||||
| 
 | ||||
| struct vport_cmd_tag { | ||||
| 	uint32_t cmd; | ||||
| 	struct vport_data cdata; | ||||
| 	struct vport_info cinfo; | ||||
| 	void *vport; | ||||
| 	int vport_num; | ||||
| }; | ||||
| 
 | ||||
| void lpfc_vport_set_state(struct lpfc_vport *vport, | ||||
| 			  enum fc_vport_state new_state); | ||||
| 
 | ||||
| #endif /* H_LPFC_VPORT */ | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user