[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"
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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