[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:
James Smart 2007-06-17 19:56:38 -05:00 committed by James Bottomley
parent ed95768429
commit 92d7f7b0cd
20 changed files with 5039 additions and 1781 deletions

View File

@ -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

View File

@ -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 */

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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...) \

View File

@ -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)
{

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,508 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of version 2 of the GNU General *
* Public License as published by the Free Software Foundation. *
* This program is distributed in the hope that it will be useful. *
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
* DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
* TO BE LEGALLY INVALID. See the GNU General Public License for *
* more details, a copy of which can be found in the file COPYING *
* included with this package. *
*******************************************************************/
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_version.h"
#include "lpfc_vport.h"
inline void lpfc_vport_set_state(struct lpfc_vport *vport,
enum fc_vport_state new_state)
{
struct fc_vport *fc_vport = vport->fc_vport;
if (fc_vport) {
/*
* When the transport defines fc_vport_set state we will replace
* this code with the following line
*/
/* fc_vport_set_state(fc_vport, new_state); */
if (new_state != FC_VPORT_INITIALIZING)
fc_vport->vport_last_state = fc_vport->vport_state;
fc_vport->vport_state = new_state;
}
/* for all the error states we will set the invternal state to FAILED */
switch (new_state) {
case FC_VPORT_NO_FABRIC_SUPP:
case FC_VPORT_NO_FABRIC_RSCS:
case FC_VPORT_FABRIC_LOGOUT:
case FC_VPORT_FABRIC_REJ_WWN:
case FC_VPORT_FAILED:
vport->port_state = LPFC_VPORT_FAILED;
break;
case FC_VPORT_LINKDOWN:
vport->port_state = LPFC_VPORT_UNKNOWN;
break;
default:
/* do nothing */
break;
}
}
static int
lpfc_alloc_vpi(struct lpfc_hba *phba)
{
int vpi;
spin_lock_irq(&phba->hbalock);
vpi = find_next_zero_bit(phba->vpi_bmask, phba->max_vpi, 1);
if (vpi > phba->max_vpi)
vpi = 0;
else
set_bit(vpi, phba->vpi_bmask);
spin_unlock_irq(&phba->hbalock);
return vpi;
}
static void
lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
{
spin_lock_irq(&phba->hbalock);
clear_bit(vpi, phba->vpi_bmask);
spin_unlock_irq(&phba->hbalock);
}
static int
lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_dmabuf *mp;
int rc;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
return -ENOMEM;
}
mb = &pmb->mb;
lpfc_read_sparam(phba, pmb, vport->vpi);
/*
* Grab buffer pointer and clear context1 so we can use
* lpfc_sli_issue_box_wait
*/
mp = (struct lpfc_dmabuf *) pmb->context1;
pmb->context1 = NULL;
pmb->vport = vport;
rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
"%d (%d):1818 VPort failed init, mbxCmd x%x "
"READ_SPARM mbxStatus x%x, rc = x%x\n",
phba->brd_no, vport->vpi,
mb->mbxCommand, mb->mbxStatus, rc);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
return 0;
}
static int
lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn,
const char *name_type)
{
/* ensure that IEEE format 1 addresses
* contain zeros in bits 59-48
*/
if (!((wwn->u.wwn[0] >> 4) == 1 &&
((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0)))
return 1;
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
"%02x:%02x:%02x:%02x\n",
phba->brd_no, name_type,
wwn->u.wwn[0], wwn->u.wwn[1],
wwn->u.wwn[2], wwn->u.wwn[3],
wwn->u.wwn[4], wwn->u.wwn[5],
wwn->u.wwn[6], wwn->u.wwn[7]);
return 0;
}
static int
lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
{
struct lpfc_vport *vport;
list_for_each_entry(vport, &phba->port_list, listentry) {
if (vport == new_vport)
continue;
/* If they match, return not unique */
if (memcmp(&vport->fc_sparam.portName,
&new_vport->fc_sparam.portName,
sizeof(struct lpfc_name)) == 0)
return 0;
}
return 1;
}
int
lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
{
struct lpfc_nodelist *ndlp;
struct lpfc_vport *pport =
(struct lpfc_vport *) fc_vport->shost->hostdata;
struct lpfc_hba *phba = pport->phba;
struct lpfc_vport *vport = NULL;
int instance;
int vpi;
int rc = VPORT_ERROR;
if ((phba->sli_rev < 3) ||
!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1808 Create VPORT failed: "
"NPIV is not enabled: SLImode:%d\n",
phba->brd_no, phba->sli_rev);
rc = VPORT_INVAL;
goto error_out;
}
vpi = lpfc_alloc_vpi(phba);
if (vpi == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1809 Create VPORT failed: "
"Max VPORTs (%d) exceeded\n",
phba->brd_no, phba->max_vpi);
rc = VPORT_NORESOURCES;
goto error_out;
}
/* Assign an unused board number */
if ((instance = lpfc_get_instance()) < 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1810 Create VPORT failed: Cannot get "
"instance number\n", phba->brd_no);
lpfc_free_vpi(phba, vpi);
rc = VPORT_NORESOURCES;
goto error_out;
}
vport = lpfc_create_port(phba, instance, fc_vport);
if (!vport) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1811 Create VPORT failed: vpi x%x\n",
phba->brd_no, vpi);
lpfc_free_vpi(phba, vpi);
rc = VPORT_NORESOURCES;
goto error_out;
}
vport->vpi = vpi;
if (lpfc_vport_sparm(phba, vport)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1813 Create VPORT failed: vpi:%d "
"Cannot get sparam\n",
phba->brd_no, vpi);
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_NORESOURCES;
goto error_out;
}
memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
if (fc_vport->node_name != 0)
u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
if (fc_vport->port_name != 0)
u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
!lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1821 Create VPORT failed: vpi:%d "
"Invalid WWN format\n",
phba->brd_no, vpi);
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_INVAL;
goto error_out;
}
if (!lpfc_unique_wwpn(phba, vport)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1823 Create VPORT failed: vpi:%d "
"Duplicate WWN on HBA\n",
phba->brd_no, vpi);
lpfc_free_vpi(phba, vpi);
destroy_port(vport);
rc = VPORT_INVAL;
goto error_out;
}
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
if ((phba->link_state < LPFC_LINK_UP) ||
(phba->fc_topology == TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
goto out;
}
if (disable) {
rc = VPORT_OK;
goto out;
}
/* Use the Physical nodes Fabric NDLP to determine if the link is
* up and ready to FDISC.
*/
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
}
rc = VPORT_OK;
out:
lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
error_out:
return rc;
}
int
disable_vport(struct fc_vport *fc_vport)
{
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
long timeout;
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (ndlp && phba->link_state >= LPFC_LINK_UP) {
vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_issue_els_npiv_logo(vport, ndlp))
while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
timeout = schedule_timeout(timeout);
}
lpfc_sli_host_down(vport);
/* Mark all nodes for discovery so we can remove them by
* calling lpfc_cleanup_rpis(vport, 1)
*/
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue;
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
}
lpfc_cleanup_rpis(vport, 1);
lpfc_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport);
lpfc_unreg_default_rpis(vport);
/*
* Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
* scsi_host_put() to release the vport.
*/
lpfc_mbx_unreg_vpi(vport);
lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
return VPORT_OK;
}
int
enable_vport(struct fc_vport *fc_vport)
{
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL;
if ((phba->link_state < LPFC_LINK_UP) ||
(phba->fc_topology == TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
return VPORT_OK;
}
vport->load_flag |= FC_LOADING;
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
/* Use the Physical nodes Fabric NDLP to determine if the link is
* up and ready to FDISC.
*/
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
}
return VPORT_OK;
}
int
lpfc_vport_disable(struct fc_vport *fc_vport, bool disable)
{
if (disable)
return disable_vport(fc_vport);
else
return enable_vport(fc_vport);
}
int
lpfc_vport_delete(struct fc_vport *fc_vport)
{
struct lpfc_nodelist *ndlp = NULL;
struct lpfc_nodelist *next_ndlp;
struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
long timeout;
int rc = VPORT_ERROR;
/*
* This is a bit of a mess. We want to ensure the shost doesn't get
* torn down until we're done with the embedded lpfc_vport structure.
*
* Beyond holding a reference for this function, we also need a
* reference for outstanding I/O requests we schedule during delete
* processing. But once we scsi_remove_host() we can no longer obtain
* a reference through scsi_host_get().
*
* So we take two references here. We release one reference at the
* bottom of the function -- after delinking the vport. And we
* release the other at the completion of the unreg_vpi that get's
* initiated after we've disposed of all other resources associated
* with the port.
*/
if (!scsi_host_get(shost) || !scsi_host_get(shost))
return VPORT_INVAL;
if (vport->port_type == LPFC_PHYSICAL_PORT) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1812 vport_delete failed: Cannot delete "
"physical host\n", phba->brd_no);
goto out;
}
vport->load_flag |= FC_UNLOADING;
kfree(vport->vname);
fc_remove_host(lpfc_shost_from_vport(vport));
scsi_remove_host(lpfc_shost_from_vport(vport));
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
phba->link_state >= LPFC_LINK_UP) {
/* First look for the Fabric ndlp */
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, allocate one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
goto skip_logo;
lpfc_nlp_init(vport, ndlp, Fabric_DID);
} else {
lpfc_dequeue_node(vport, ndlp);
}
vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_issue_els_npiv_logo(vport, ndlp))
while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
timeout = schedule_timeout(timeout);
}
skip_logo:
lpfc_sli_host_down(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);
}
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
/* free any ndlp's in unused state */
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
lpfc_drop_node(vport, ndlp);
}
lpfc_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport);
lpfc_unreg_default_rpis(vport);
/*
* Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
* scsi_host_put() to release the vport.
*/
lpfc_mbx_unreg_vpi(vport);
lpfc_free_vpi(phba, vport->vpi);
vport->work_port_events = 0;
spin_lock_irq(&phba->hbalock);
list_del_init(&vport->listentry);
spin_unlock_irq(&phba->hbalock);
rc = VPORT_OK;
out:
scsi_host_put(shost);
return rc;
}
EXPORT_SYMBOL(lpfc_vport_create);
EXPORT_SYMBOL(lpfc_vport_delete);

View File

@ -0,0 +1,113 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of version 2 of the GNU General *
* Public License as published by the Free Software Foundation. *
* This program is distributed in the hope that it will be useful. *
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
* DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
* TO BE LEGALLY INVALID. See the GNU General Public License for *
* more details, a copy of which can be found in the file COPYING *
* included with this package. *
*******************************************************************/
#ifndef _H_LPFC_VPORT
#define _H_LPFC_VPORT
/* API version values (each will be an individual bit) */
#define VPORT_API_VERSION_1 0x01
/* Values returned via lpfc_vport_getinfo() */
struct vport_info {
uint32_t api_versions;
uint8_t linktype;
#define VPORT_TYPE_PHYSICAL 0
#define VPORT_TYPE_VIRTUAL 1
uint8_t state;
#define VPORT_STATE_OFFLINE 0
#define VPORT_STATE_ACTIVE 1
#define VPORT_STATE_FAILED 2
uint8_t fail_reason;
uint8_t prev_fail_reason;
#define VPORT_FAIL_UNKNOWN 0
#define VPORT_FAIL_LINKDOWN 1
#define VPORT_FAIL_FAB_UNSUPPORTED 2
#define VPORT_FAIL_FAB_NORESOURCES 3
#define VPORT_FAIL_FAB_LOGOUT 4
#define VPORT_FAIL_ADAP_NORESOURCES 5
uint8_t node_name[8]; /* WWNN */
uint8_t port_name[8]; /* WWPN */
struct Scsi_Host *shost;
/* Following values are valid only on physical links */
uint32_t vports_max;
uint32_t vports_inuse;
uint32_t rpi_max;
uint32_t rpi_inuse;
#define VPORT_CNT_INVALID 0xFFFFFFFF
};
/* data used in link creation */
struct vport_data {
uint32_t api_version;
uint32_t options;
#define VPORT_OPT_AUTORETRY 0x01
uint8_t node_name[8]; /* WWNN */
uint8_t port_name[8]; /* WWPN */
/*
* Upon successful creation, vport_shost will point to the new Scsi_Host
* structure for the new virtual link.
*/
struct Scsi_Host *vport_shost;
};
/* API function return codes */
#define VPORT_OK 0
#define VPORT_ERROR -1
#define VPORT_INVAL -2
#define VPORT_NOMEM -3
#define VPORT_NORESOURCES -4
int lpfc_vport_create(struct fc_vport *, bool);
int lpfc_vport_delete(struct fc_vport *);
int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
/*
* queuecommand VPORT-specific return codes. Specified in the host byte code.
* Returned when the virtual link has failed or is not active.
*/
#define DID_VPORT_ERROR 0x0f
#define VPORT_INFO 0x1
#define VPORT_CREATE 0x2
#define VPORT_DELETE 0x4
struct vport_cmd_tag {
uint32_t cmd;
struct vport_data cdata;
struct vport_info cinfo;
void *vport;
int vport_num;
};
void lpfc_vport_set_state(struct lpfc_vport *vport,
enum fc_vport_state new_state);
#endif /* H_LPFC_VPORT */