Commit 858c9f6c authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc: bug fixes

 Following the NPIV support, the following changes have been accumulated
 in the testing and qualification of the driver:

 - Fix affinity of ELS ring to slow/deferred event processing
 - Fix Ring attention masks
 - Defer dev_loss_tmo timeout handling to worker thread
 - Consolidate link down error classification for better error checking
 - Remove unused/deprecated nlp_initiator_tmr timer
 - Fix for async scan - move adapter init code back into pci_probe_one
   context. Fix async scan interfaces.
 - Expand validation of ability to create vports
 - Extract VPI resource cnt from firmware
 - Tuning of Login/Reject policies to better deal with overwhelmned targets
 - Misc ELS and discovery fixes
 - Export the npiv_enable attribute to sysfs
 - Mailbox handling fix
 - Add debugfs support
 - A few other small misc fixes:
    - wrong return values, double-frees, bad locking
 - Added adapter failure heartbeat
Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 92d7f7b0
...@@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o ...@@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.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 lpfc_vport.o lpfc_debugfs.o
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
struct lpfc_sli2_slim; struct lpfc_sli2_slim;
#define LPFC_MAX_TARGET 256 /* max number of targets supported */ #define LPFC_MAX_TARGET 256 /* max number of targets supported */
#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els #define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
requests */ requests */
...@@ -45,6 +44,9 @@ struct lpfc_sli2_slim; ...@@ -45,6 +44,9 @@ struct lpfc_sli2_slim;
/* Number of exchanges reserved for discovery to complete */ /* Number of exchanges reserved for discovery to complete */
#define LPFC_DISC_IOCB_BUFF_COUNT 20 #define LPFC_DISC_IOCB_BUFF_COUNT 20
#define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */
#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */
/* Define macros for 64 bit support */ /* Define macros for 64 bit support */
#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
...@@ -308,13 +310,15 @@ struct lpfc_vport { ...@@ -308,13 +310,15 @@ struct lpfc_vport {
spinlock_t work_port_lock; spinlock_t work_port_lock;
uint32_t work_port_events; /* Timeout to be handled */ uint32_t work_port_events; /* Timeout to be handled */
#define WORKER_DISC_TMO 0x1 /* Discovery timeout */ #define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* ELS timeout */ #define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
#define WORKER_MBOX_TMO 0x4 /* MBOX timeout */ #define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
#define WORKER_FDMI_TMO 0x8 /* FDMI timeout */
#define WORKER_FABRIC_BLOCK_TMO 0x10 /* fabric block timout */ #define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
#define WORKER_RAMP_DOWN_QUEUE 0x20 /* Decrease Q depth */ #define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
#define WORKER_RAMP_UP_QUEUE 0x40 /* Increase Q depth */ #define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timout */
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
struct timer_list fc_fdmitmo; struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc; struct timer_list els_tmofunc;
...@@ -326,6 +330,14 @@ struct lpfc_vport { ...@@ -326,6 +330,14 @@ struct lpfc_vport {
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
char *vname; /* Application assigned name */ char *vname; /* Application assigned name */
struct fc_vport *fc_vport; struct fc_vport *fc_vport;
#ifdef CONFIG_LPFC_DEBUG_FS
struct dentry *debug_disc_trc;
struct dentry *debug_nodelist;
struct dentry *vport_debugfs_root;
struct lpfc_disc_trc *disc_trc;
atomic_t disc_trc_cnt;
#endif
}; };
struct hbq_s { struct hbq_s {
...@@ -408,6 +420,7 @@ struct lpfc_hba { ...@@ -408,6 +420,7 @@ struct lpfc_hba {
uint32_t cfg_hba_queue_depth; uint32_t cfg_hba_queue_depth;
uint32_t cfg_peer_port_login; uint32_t cfg_peer_port_login;
uint32_t cfg_vport_restrict_login; uint32_t cfg_vport_restrict_login;
uint32_t cfg_npiv_enable;
uint32_t cfg_fcp_class; uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc; uint32_t cfg_use_adisc;
uint32_t cfg_ack0; uint32_t cfg_ack0;
...@@ -513,10 +526,10 @@ struct lpfc_hba { ...@@ -513,10 +526,10 @@ struct lpfc_hba {
mempool_t *nlp_mem_pool; mempool_t *nlp_mem_pool;
struct fc_host_statistics link_stats; struct fc_host_statistics link_stats;
struct list_head port_list; struct list_head port_list;
struct lpfc_vport *pport; /* physical lpfc_vport pointer */ struct lpfc_vport *pport; /* physical lpfc_vport pointer */
uint16_t max_vpi; /* Maximum virtual nports */ uint16_t max_vpi; /* Maximum virtual nports */
uint16_t vpi_cnt; /* Nport count */
#define LPFC_MAX_VPI 100 /* Max number of VPorts supported */ #define LPFC_MAX_VPI 100 /* Max number of VPorts supported */
unsigned long *vpi_bmask; /* vpi allocation table */ unsigned long *vpi_bmask; /* vpi allocation table */
...@@ -531,6 +544,15 @@ struct lpfc_hba { ...@@ -531,6 +544,15 @@ struct lpfc_hba {
unsigned long last_rsrc_error_time; unsigned long last_rsrc_error_time;
unsigned long last_ramp_down_time; unsigned long last_ramp_down_time;
unsigned long last_ramp_up_time; unsigned long last_ramp_up_time;
#ifdef CONFIG_LPFC_DEBUG_FS
struct dentry *hba_debugfs_root;
atomic_t debugfs_vport_count;
#endif
/* Fields used for heart beat. */
unsigned long last_completion_time;
struct timer_list hb_tmofunc;
uint8_t hb_outstanding;
}; };
static inline struct Scsi_Host * static inline struct Scsi_Host *
......
...@@ -282,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *shost) ...@@ -282,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
} }
lpfc_set_loopback_flag(phba); lpfc_set_loopback_flag(phba);
if (mbxstatus == MBX_TIMEOUT) if (mbxstatus != 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);
if (mbxstatus == MBXERR_ERROR) if (mbxstatus == MBXERR_ERROR)
...@@ -439,30 +437,11 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) ...@@ -439,30 +437,11 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
return -EIO; 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 int
lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, lpfc_get_hba_info(struct lpfc_hba *phba,
uint32_t *axri, uint32_t *mrpi, uint32_t *arpi) uint32_t *mxri, uint32_t *axri,
uint32_t *mrpi, uint32_t *arpi,
uint32_t *mvpi, uint32_t *avpi)
{ {
struct lpfc_sli *psli = &phba->sli; struct lpfc_sli *psli = &phba->sli;
LPFC_MBOXQ_t *pmboxq; LPFC_MBOXQ_t *pmboxq;
...@@ -498,9 +477,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, ...@@ -498,9 +477,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) 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 0; return 0;
} }
...@@ -513,6 +490,10 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, ...@@ -513,6 +490,10 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
*mxri = pmb->un.varRdConfig.max_xri; *mxri = pmb->un.varRdConfig.max_xri;
if (axri) if (axri)
*axri = pmb->un.varRdConfig.avail_xri; *axri = pmb->un.varRdConfig.avail_xri;
if (mvpi)
*mvpi = pmb->un.varRdConfig.max_vpi;
if (avpi)
*avpi = pmb->un.varRdConfig.avail_vpi;
mempool_free(pmboxq, phba->mbox_mem_pool); mempool_free(pmboxq, phba->mbox_mem_pool);
return 1; return 1;
...@@ -526,7 +507,7 @@ lpfc_max_rpi_show(struct class_device *cdev, char *buf) ...@@ -526,7 +507,7 @@ lpfc_max_rpi_show(struct class_device *cdev, char *buf)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
uint32_t cnt; uint32_t cnt;
if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL)) if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
return snprintf(buf, PAGE_SIZE, "%d\n", cnt); return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
return snprintf(buf, PAGE_SIZE, "Unknown\n"); return snprintf(buf, PAGE_SIZE, "Unknown\n");
} }
...@@ -539,7 +520,7 @@ lpfc_used_rpi_show(struct class_device *cdev, char *buf) ...@@ -539,7 +520,7 @@ lpfc_used_rpi_show(struct class_device *cdev, char *buf)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
uint32_t cnt, acnt; uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt)) if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
return snprintf(buf, PAGE_SIZE, "Unknown\n"); return snprintf(buf, PAGE_SIZE, "Unknown\n");
} }
...@@ -552,7 +533,7 @@ lpfc_max_xri_show(struct class_device *cdev, char *buf) ...@@ -552,7 +533,7 @@ lpfc_max_xri_show(struct class_device *cdev, char *buf)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
uint32_t cnt; uint32_t cnt;
if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL)) if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
return snprintf(buf, PAGE_SIZE, "%d\n", cnt); return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
return snprintf(buf, PAGE_SIZE, "Unknown\n"); return snprintf(buf, PAGE_SIZE, "Unknown\n");
} }
...@@ -565,7 +546,33 @@ lpfc_used_xri_show(struct class_device *cdev, char *buf) ...@@ -565,7 +546,33 @@ lpfc_used_xri_show(struct class_device *cdev, char *buf)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
uint32_t cnt, acnt; uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL)) if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
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;
uint32_t cnt;
if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
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;
uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
return snprintf(buf, PAGE_SIZE, "Unknown\n"); return snprintf(buf, PAGE_SIZE, "Unknown\n");
} }
...@@ -995,9 +1002,7 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" ...@@ -995,9 +1002,7 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
" 2 - select SLI-2 even on SLI-3 capable HBAs," " 2 - select SLI-2 even on SLI-3 capable HBAs,"
" 3 - select SLI-3"); " 3 - select SLI-3");
int lpfc_npiv_enable = 0; LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
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 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
...@@ -1052,6 +1057,24 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val) ...@@ -1052,6 +1057,24 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
return -EINVAL; return -EINVAL;
} }
static void
lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
struct Scsi_Host *shost;
struct lpfc_nodelist *ndlp;
list_for_each_entry(vport, &phba->port_list, listentry) {
shost = lpfc_shost_from_vport(vport);
spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
if (ndlp->rport)
ndlp->rport->dev_loss_tmo =
phba->cfg_devloss_tmo;
spin_unlock_irq(shost->host_lock);
}
}
static int static int
lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val) lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
{ {
...@@ -1067,6 +1090,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val) ...@@ -1067,6 +1090,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
phba->cfg_nodev_tmo = val; phba->cfg_nodev_tmo = val;
phba->cfg_devloss_tmo = val; phba->cfg_devloss_tmo = val;
lpfc_update_rport_devloss_tmo(phba);
return 0; return 0;
} }
...@@ -1102,6 +1126,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val) ...@@ -1102,6 +1126,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
phba->cfg_nodev_tmo = val; phba->cfg_nodev_tmo = val;
phba->cfg_devloss_tmo = val; phba->cfg_devloss_tmo = val;
phba->dev_loss_tmo_changed = 1; phba->dev_loss_tmo_changed = 1;
lpfc_update_rport_devloss_tmo(phba);
return 0; return 0;
} }
...@@ -1358,6 +1383,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = { ...@@ -1358,6 +1383,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
&class_device_attr_lpfc_multi_ring_type, &class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on, &class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns, &class_device_attr_lpfc_max_luns,
&class_device_attr_lpfc_npiv_enable,
&class_device_attr_nport_evt_cnt, &class_device_attr_nport_evt_cnt,
&class_device_attr_management_version, &class_device_attr_management_version,
&class_device_attr_board_mode, &class_device_attr_board_mode,
...@@ -1641,8 +1667,6 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) ...@@ -1641,8 +1667,6 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) { if (rc == MBX_TIMEOUT) {
phba->sysfs_mbox.mbox->mbox_cmpl =
lpfc_sli_def_mbox_cmpl;
phba->sysfs_mbox.mbox = NULL; phba->sysfs_mbox.mbox = NULL;
} }
sysfs_mbox_idle(phba); sysfs_mbox_idle(phba);
...@@ -1886,9 +1910,7 @@ lpfc_get_stats(struct Scsi_Host *shost) ...@@ -1886,9 +1910,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) 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; return NULL;
} }
...@@ -1913,9 +1935,7 @@ lpfc_get_stats(struct Scsi_Host *shost) ...@@ -1913,9 +1935,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) 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; return NULL;
} }
...@@ -1993,9 +2013,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) ...@@ -1993,9 +2013,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) 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; return;
} }
...@@ -2013,9 +2031,7 @@ lpfc_reset_stats(struct Scsi_Host *shost) ...@@ -2013,9 +2031,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) { if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) 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; return;
} }
...@@ -2253,6 +2269,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) ...@@ -2253,6 +2269,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_max_luns_init(phba, lpfc_max_luns); lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo); lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
lpfc_peer_port_login_init(phba, lpfc_peer_port_login); lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login); lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
lpfc_use_msi_init(phba, lpfc_use_msi); lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo); lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
......
...@@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param); ...@@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
struct fc_rport; struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
struct lpfc_dmabuf *mp); struct lpfc_dmabuf *mp);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
...@@ -45,6 +46,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); ...@@ -45,6 +46,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
...@@ -85,6 +87,7 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); ...@@ -85,6 +87,7 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t); struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *); int lpfc_initial_flogi(struct lpfc_vport *);
int lpfc_initial_fdisc(struct lpfc_vport *); int lpfc_initial_fdisc(struct lpfc_vport *);
...@@ -96,10 +99,11 @@ int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); ...@@ -96,10 +99,11 @@ 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_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); 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_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t); struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *); struct lpfc_nodelist *, LPFC_MBOXQ_t *);
int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *, int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
struct lpfc_nodelist *); struct lpfc_nodelist *);
int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *, int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
...@@ -107,6 +111,7 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *, ...@@ -107,6 +111,7 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long); void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *); struct lpfc_iocbq *);
int lpfc_els_handle_rscn(struct lpfc_vport *); int lpfc_els_handle_rscn(struct lpfc_vport *);
...@@ -117,6 +122,8 @@ int lpfc_els_disc_adisc(struct lpfc_vport *); ...@@ -117,6 +122,8 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *); int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long); void lpfc_els_timeout(unsigned long);
void lpfc_els_timeout_handler(struct lpfc_vport *); void lpfc_els_timeout_handler(struct lpfc_vport *);
void lpfc_hb_timeout(unsigned long);
void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *); struct lpfc_iocbq *);
...@@ -238,7 +245,6 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); ...@@ -238,7 +245,6 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
/* Function prototypes. */ /* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *); const char* lpfc_info(struct Scsi_Host *);
void lpfc_scan_start(struct Scsi_Host *);
int lpfc_scan_finished(struct Scsi_Host *, unsigned long); int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
void lpfc_get_cfgparam(struct lpfc_hba *); void lpfc_get_cfgparam(struct lpfc_hba *);
...@@ -249,7 +255,6 @@ extern struct scsi_host_template lpfc_template; ...@@ -249,7 +255,6 @@ extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode; extern int lpfc_sli_mode;
extern int lpfc_npiv_enable;
int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *); void lpfc_terminate_rport_io(struct fc_rport *);
...@@ -262,6 +267,11 @@ void destroy_port(struct lpfc_vport *); ...@@ -262,6 +267,11 @@ void destroy_port(struct lpfc_vport *);
int lpfc_get_instance(void); int lpfc_get_instance(void);
void lpfc_host_attrib_init(struct Scsi_Host *); void lpfc_host_attrib_init(struct Scsi_Host *);
extern void lpfc_debugfs_initialize(struct lpfc_vport *);
extern void lpfc_debugfs_terminate(struct lpfc_vport *);
extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
uint32_t, uint32_t);
/* Interface exported by fabric iocb scheduler */ /* Interface exported by fabric iocb scheduler */
int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
void lpfc_fabric_abort_vport(struct lpfc_vport *); void lpfc_fabric_abort_vport(struct lpfc_vport *);
......
This diff is collapsed.
This diff is collapsed.
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
* 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_DEBUG_FS
#define _H_LPFC_DEBUG_FS
#ifdef CONFIG_LPFC_DEBUG_FS
struct lpfc_disc_trc {
char *fmt;
uint32_t data1;
uint32_t data2;
uint32_t data3;
uint32_t seq_cnt;
unsigned long jif;
};
#endif
/* Mask for discovery_trace */
#define LPFC_DISC_TRC_ELS_CMD 0x1 /* Trace ELS commands */
#define LPFC_DISC_TRC_ELS_RSP 0x2 /* Trace ELS response */
#define LPFC_DISC_TRC_ELS_UNSOL 0x4 /* Trace ELS rcv'ed */
#define LPFC_DISC_TRC_ELS_ALL 0x7 /* Trace ELS */
#define LPFC_DISC_TRC_MBOX_VPORT 0x8 /* Trace vport MBOXs */
#define LPFC_DISC_TRC_MBOX 0x10 /* Trace other MBOXs */
#define LPFC_DISC_TRC_MBOX_ALL 0x18 /* Trace all MBOXs */
#define LPFC_DISC_TRC_CT 0x20 /* Trace disc CT requests */
#define LPFC_DISC_TRC_DSM 0x40 /* Trace DSM events */
#define LPFC_DISC_TRC_RPORT 0x80 /* Trace rport events */
#define LPFC_DISC_TRC_NODE 0x100 /* Trace ndlp state changes */
#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general
* discovery */
#endif /* H_LPFC_DEBUG_FS */
...@@ -36,6 +36,7 @@ enum lpfc_work_type { ...@@ -36,6 +36,7 @@ enum lpfc_work_type {
LPFC_EVT_WARM_START, LPFC_EVT_WARM_START,
LPFC_EVT_KILL, LPFC_EVT_KILL,
LPFC_EVT_ELS_RETRY, LPFC_EVT_ELS_RETRY,
LPFC_EVT_DEV_LOSS_DELAY,
LPFC_EVT_DEV_LOSS, LPFC_EVT_DEV_LOSS,
}; };
...@@ -74,7 +75,6 @@ struct lpfc_nodelist { ...@@ -74,7 +75,6 @@ struct lpfc_nodelist {
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ 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 struct fc_rport *rport; /* Corresponding FC transport
port structure */ port structure */
struct lpfc_vport *vport; struct lpfc_vport *vport;
...@@ -101,6 +101,7 @@ struct lpfc_nodelist { ...@@ -101,6 +101,7 @@ struct lpfc_nodelist {
ACC */ ACC */
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from #define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */ NPR list */
#define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
......
This diff is collapsed.
This diff is collapsed.
...@@ -1278,6 +1278,7 @@ typedef struct { /* FireFly BIU registers */ ...@@ -1278,6 +1278,7 @@ typedef struct { /* FireFly BIU registers */
#define MBX_KILL_BOARD 0x24 #define MBX_KILL_BOARD 0x24
#define MBX_CONFIG_FARP 0x25 #define MBX_CONFIG_FARP 0x25
#define MBX_BEACON 0x2A #define MBX_BEACON 0x2A
#define MBX_HEARTBEAT 0x31
#define MBX_CONFIG_HBQ 0x7C #define MBX_CONFIG_HBQ 0x7C
#define MBX_LOAD_AREA 0x81 #define MBX_LOAD_AREA 0x81
...@@ -1777,8 +1778,6 @@ typedef struct { ...@@ -1777,8 +1778,6 @@ typedef struct {
#define LMT_4Gb 0x040 #define LMT_4Gb 0x040
#define LMT_8Gb 0x080 #define LMT_8Gb 0x080
#define LMT_10Gb 0x100 #define LMT_10Gb 0x100
uint32_t rsvd2; uint32_t rsvd2;
uint32_t rsvd3; uint32_t rsvd3;
uint32_t max_xri; uint32_t max_xri;
...@@ -1787,7 +1786,10 @@ typedef struct { ...@@ -1787,7 +1786,10 @@ typedef struct {
uint32_t avail_xri; uint32_t avail_xri;
uint32_t avail_iocb; uint32_t avail_iocb;
uint32_t avail_rpi; uint32_t avail_rpi;
uint32_t default_rpi; uint32_t max_vpi;
uint32_t rsvd4;
uint32_t rsvd5;
uint32_t avail_vpi;
} READ_CONFIG_VAR; } READ_CONFIG_VAR;
/* Structure for MB Command READ_RCONFIG (12) */ /* Structure for MB Command READ_RCONFIG (12) */
...@@ -3171,3 +3173,16 @@ lpfc_is_LC_HBA(unsigned short device) ...@@ -3171,3 +3173,16 @@ lpfc_is_LC_HBA(unsigned short device)
else else
return 0; return 0;
} }
/*
* Determine if an IOCB failed because of a link event or firmware reset.
*/
static inline int
lpfc_error_lost_link(IOCB_t *iocbp)
{
return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT &&
(iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED ||
iocbp->un.ulpWord[4] == IOERR_LINK_DOWN ||
iocbp->un.ulpWord[4] == IOERR_SLI_DOWN));
}
...@@ -391,6 +391,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) ...@@ -391,6 +391,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
*/ */
timeout = phba->fc_ratov << 1; timeout = phba->fc_ratov << 1;
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
phba->hb_outstanding = 0;
phba->last_completion_time = jiffies;
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
...@@ -485,6 +488,119 @@ lpfc_hba_down_post(struct lpfc_hba *phba) ...@@ -485,6 +488,119 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
return 0; return 0;
} }
/* HBA heart beat timeout handler */
void
lpfc_hb_timeout(unsigned long ptr)
{
struct lpfc_hba *phba;
unsigned long iflag;
phba = (struct lpfc_hba *)ptr;
spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
if (!(phba->pport->work_port_events & WORKER_HB_TMO))
phba->pport->work_port_events |= WORKER_HB_TMO;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
if (phba->work_wait)
wake_up(phba->work_wait);
return;
}
static void
lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
{
unsigned long drvr_flag;
spin_lock_irqsave(&phba->hbalock, drvr_flag);
phba->hb_outstanding = 0;
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
mempool_free(pmboxq, phba->mbox_mem_pool);
if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
!(phba->link_state == LPFC_HBA_ERROR) &&
!(phba->pport->fc_flag & FC_UNLOADING))
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
return;
}
void
lpfc_hb_timeout_handler(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *pmboxq;
int retval;
struct lpfc_sli *psli = &phba->sli;
if ((phba->link_state == LPFC_HBA_ERROR) ||
(phba->pport->fc_flag & FC_UNLOADING) ||
(phba->pport->fc_flag & FC_OFFLINE_MODE))
return;
spin_lock_irq(&phba->pport->work_port_lock);
/* If the timer is already canceled do nothing */
if (!(phba->pport->work_port_events & WORKER_HB_TMO)) {
spin_unlock_irq(&phba->pport->work_port_lock);
return;
}
if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ,
jiffies)) {
spin_unlock_irq(&phba->pport->work_port_lock);
if (!phba->hb_outstanding)
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
else
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
return;
}
spin_unlock_irq(&phba->pport->work_port_lock);
/* If there is no heart beat outstanding, issue a heartbeat command */
if (!phba->hb_outstanding) {
pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
if (!pmboxq) {
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
return;
}
lpfc_heart_beat(phba, pmboxq);
pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
pmboxq->vport = phba->pport;
retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool);
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
return;
}
mod_timer(&phba->hb_tmofunc,
jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
phba->hb_outstanding = 1;
return;
} else {
/*
* If heart beat timeout called with hb_outstanding set we
* need to take the HBA offline.
*/
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0459 Adapter heartbeat failure, taking "
"this port offline.\n", phba->brd_no);
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);
phba->link_state = LPFC_HBA_ERROR;
lpfc_hba_down_post(phba);
}
}
/************************************************************************/ /************************************************************************/
/* */ /* */
/* lpfc_handle_eratt */ /* lpfc_handle_eratt */
...@@ -1190,9 +1306,6 @@ lpfc_cleanup(struct lpfc_vport *vport) ...@@ -1190,9 +1306,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_can_disctmo(vport); lpfc_can_disctmo(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
INIT_LIST_HEAD(&vport->fc_nodes);
return; return;
} }
...@@ -1238,6 +1351,8 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba) ...@@ -1238,6 +1351,8 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
lpfc_stop_vport_timers(vport); lpfc_stop_vport_timers(vport);
del_timer_sync(&phba->sli.mbox_tmo); del_timer_sync(&phba->sli.mbox_tmo);
del_timer_sync(&phba->fabric_block_timer); del_timer_sync(&phba->fabric_block_timer);
phba->hb_outstanding = 0;
del_timer_sync(&phba->hb_tmofunc);
return; return;
} }
...@@ -1474,8 +1589,8 @@ destroy_port(struct lpfc_vport *vport) ...@@ -1474,8 +1589,8 @@ destroy_port(struct lpfc_vport *vport)
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
kfree(vport->vname); kfree(vport->vname);
lpfc_free_sysfs_attr(vport);
lpfc_debugfs_terminate(vport);
fc_remove_host(shost); fc_remove_host(shost);
scsi_remove_host(shost); scsi_remove_host(shost);
...@@ -1500,50 +1615,29 @@ lpfc_get_instance(void) ...@@ -1500,50 +1615,29 @@ lpfc_get_instance(void)
return instance; return instance;
} }
static void /*
lpfc_remove_device(struct lpfc_vport *vport) * Note: there is no scan_start function as adapter initialization
{ * will have asynchronously kicked off the link initialization.
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); */
lpfc_free_sysfs_attr(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_UNLOADING;
spin_unlock_irq(shost->host_lock);
fc_remove_host(shost);
scsi_remove_host(shost);
}
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_sli_hba_setup(phba))
goto error;
/*
* hba setup may have changed the hba_queue_depth so we need to adjust
* the value of can_queue.
*/
shost->can_queue = phba->cfg_hba_queue_depth - 10;
return;
error:
lpfc_remove_device(vport);
}
int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
{ {
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
int stat = 0;
spin_lock_irq(shost->host_lock);
if (vport->fc_flag & FC_UNLOADING) {
stat = 1;
goto finished;
}
if (time >= 30 * HZ) { if (time >= 30 * HZ) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"%d:0461 Scanning longer than 30 " "%d:0461 Scanning longer than 30 "
"seconds. Continuing initialization\n", "seconds. Continuing initialization\n",
phba->brd_no); phba->brd_no);
stat = 1;
goto finished; goto finished;
} }
if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) { if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
...@@ -1551,21 +1645,24 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) ...@@ -1551,21 +1645,24 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
"%d:0465 Link down longer than 15 " "%d:0465 Link down longer than 15 "
"seconds. Continuing initialization\n", "seconds. Continuing initialization\n",
phba->brd_no); phba->brd_no);
stat = 1;
goto finished; goto finished;
} }
if (vport->port_state != LPFC_VPORT_READY) if (vport->port_state != LPFC_VPORT_READY)
return 0; goto finished;
if (vport->num_disc_nodes || vport->fc_prli_sent) if (vport->num_disc_nodes || vport->fc_prli_sent)
return 0; goto finished;
if (vport->fc_map_cnt == 0 && time < 2 * HZ) if (vport->fc_map_cnt == 0 && time < 2 * HZ)
return 0; goto finished;
if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0) if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0)
return 0; goto finished;
stat = 1;
finished: finished:
lpfc_host_attrib_init(shost); spin_unlock_irq(shost->host_lock);
return 1; return stat;
} }
void lpfc_host_attrib_init(struct Scsi_Host *shost) void lpfc_host_attrib_init(struct Scsi_Host *shost)
...@@ -1656,7 +1753,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -1656,7 +1753,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Initialize timers used by driver */ /* Initialize timers used by driver */
init_timer(&phba->fc_estabtmo); init_timer(&phba->fc_estabtmo);
phba->fc_estabtmo.function = lpfc_establish_link_tmo; phba->fc_estabtmo.function = lpfc_establish_link_tmo;
phba->fc_estabtmo.data = (unsigned long) phba; phba->fc_estabtmo.data = (unsigned long)phba;
init_timer(&phba->hb_tmofunc);
phba->hb_tmofunc.function = lpfc_hb_timeout;
phba->hb_tmofunc.data = (unsigned long)phba;
psli = &phba->sli; psli = &phba->sli;
init_timer(&psli->mbox_tmo); init_timer(&psli->mbox_tmo);
psli->mbox_tmo.function = lpfc_mbox_timeout; psli->mbox_tmo.function = lpfc_mbox_timeout;
...@@ -1791,6 +1893,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -1791,6 +1893,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
shost = lpfc_shost_from_vport(vport); shost = lpfc_shost_from_vport(vport);
phba->pport = vport; phba->pport = vport;
lpfc_debugfs_initialize(vport);
pci_set_drvdata(pdev, shost); pci_set_drvdata(pdev, shost);
...@@ -1820,15 +1923,32 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -1820,15 +1923,32 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (lpfc_alloc_sysfs_attr(vport)) if (lpfc_alloc_sysfs_attr(vport))
goto out_free_irq; goto out_free_irq;
scsi_scan_host(shost); if (lpfc_sli_hba_setup(phba))
goto out_remove_device;
/*
* hba setup may have changed the hba_queue_depth so we need to adjust
* the value of can_queue.
*/
shost->can_queue = phba->cfg_hba_queue_depth - 10;
lpfc_host_attrib_init(shost);
if (phba->cfg_poll & DISABLE_FCP_RING_INT) { if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
lpfc_poll_start_timer(phba); lpfc_poll_start_timer(phba);
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
} }
scsi_scan_host(shost);
return 0; return 0;
out_remove_device:
lpfc_free_sysfs_attr(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_UNLOADING;
spin_unlock_irq(shost->host_lock);
out_free_irq: out_free_irq:
lpfc_stop_phba_timers(phba); lpfc_stop_phba_timers(phba);
phba->pport->work_port_events = 0; phba->pport->work_port_events = 0;
...@@ -1865,6 +1985,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -1865,6 +1985,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
pci_disable_device(pdev); pci_disable_device(pdev);
out: out:
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
if (shost)
scsi_host_put(shost);
return error; return error;
} }
...@@ -1878,6 +2000,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -1878,6 +2000,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
list_for_each_entry(port_iterator, &phba->port_list, listentry) list_for_each_entry(port_iterator, &phba->port_list, listentry)
port_iterator->load_flag |= FC_UNLOADING; port_iterator->load_flag |= FC_UNLOADING;
kfree(vport->vname);
lpfc_free_sysfs_attr(vport);
fc_remove_host(shost);
scsi_remove_host(shost);
/* /*
* Bring down the SLI Layer. This step disable all interrupts, * Bring down the SLI Layer. This step disable all interrupts,
* clears the rings, discards all mailbox commands, and resets * clears the rings, discards all mailbox commands, and resets
...@@ -1887,6 +2015,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -1887,6 +2015,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
lpfc_sli_brdrestart(phba); lpfc_sli_brdrestart(phba);
lpfc_stop_phba_timers(phba); lpfc_stop_phba_timers(phba);
spin_lock_irq(&phba->hbalock);
list_del_init(&vport->listentry);
spin_unlock_irq(&phba->hbalock);
lpfc_debugfs_terminate(vport);
lpfc_cleanup(vport);
kthread_stop(phba->worker_thread); kthread_stop(phba->worker_thread);
...@@ -1894,9 +2029,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -1894,9 +2029,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
free_irq(phba->pcidev->irq, phba); free_irq(phba->pcidev->irq, phba);
pci_disable_msi(phba->pcidev); pci_disable_msi(phba->pcidev);
destroy_port(vport);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
scsi_host_put(shost);
/* /*
* Call scsi_free before mem_free since scsi bufs are released to their * Call scsi_free before mem_free since scsi bufs are released to their
......
...@@ -81,6 +81,22 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ...@@ -81,6 +81,22 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
return; return;
} }
/**********************************************/
/* lpfc_heart_beat Issue a HEART_BEAT */
/* mailbox command */
/**********************************************/
void
lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->mbxCommand = MBX_HEARTBEAT;
mb->mbxOwner = OWN_HOST;
return;
}
/**********************************************/ /**********************************************/
/* lpfc_read_la Issue a READ LA */ /* lpfc_read_la Issue a READ LA */
/* mailbox command */ /* mailbox command */
...@@ -676,7 +692,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -676,7 +692,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */ mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
if (phba->max_vpi && lpfc_npiv_enable && if (phba->max_vpi && phba->cfg_npiv_enable &&
phba->vpd.sli3Feat.cmv) { phba->vpd.sli3Feat.cmv) {
mb->un.varCfgPort.max_vpi = phba->max_vpi; mb->un.varCfgPort.max_vpi = phba->max_vpi;
mb->un.varCfgPort.cmv = 1; mb->un.varCfgPort.cmv = 1;
......
...@@ -88,7 +88,8 @@ lpfc_mem_alloc(struct lpfc_hba * phba) ...@@ -88,7 +88,8 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
if (!phba->lpfc_hbq_pool) if (!phba->lpfc_hbq_pool)
goto fail_free_nlp_mem_pool; goto fail_free_nlp_mem_pool;
longs = (phba->max_vpi + BITS_PER_LONG - 1) / BITS_PER_LONG; /* vpi zero is reserved for the physical port so add 1 to max */
longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL); phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
if (!phba->vpi_bmask) if (!phba->vpi_bmask)
goto fail_free_hbq_pool; goto fail_free_hbq_pool;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "lpfc_logmsg.h" #include "lpfc_logmsg.h"
#include "lpfc_crtn.h" #include "lpfc_crtn.h"
#include "lpfc_vport.h" #include "lpfc_vport.h"
#include "lpfc_debugfs.h"
/* Called to verify a rcv'ed ADISC was intended for us. */ /* Called to verify a rcv'ed ADISC was intended for us. */
...@@ -204,11 +205,9 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) ...@@ -204,11 +205,9 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
/* First check the txq */ /* First check the txq */
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
/* Check to see if iocb matches the nport we are looking /* Check to see if iocb matches the nport we are looking for */
for */
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
/* It matches, so deque and call compl with an /* It matches, so deque and call compl with anp error */
error */
list_move_tail(&iocb->list, &completions); list_move_tail(&iocb->list, &completions);
pring->txq_cnt--; pring->txq_cnt--;
} }
...@@ -216,8 +215,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) ...@@ -216,8 +215,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
/* Next check the txcmplq */ /* Next check the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
/* Check to see if iocb matches the nport we are looking /* Check to see if iocb matches the nport we are looking for */
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); lpfc_sli_issue_abort_iotag(phba, pring, iocb);
} }
...@@ -282,7 +280,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -282,7 +280,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
ndlp); ndlp, NULL);
return 0; return 0;
} }
} }
...@@ -293,7 +291,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -293,7 +291,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Reject this request because invalid parameters */ /* Reject this request because invalid parameters */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
return 0; return 0;
} }
icmd = &cmdiocb->iocb; icmd = &cmdiocb->iocb;
...@@ -392,13 +391,30 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -392,13 +391,30 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_els_abort(phba, ndlp); lpfc_els_abort(phba, ndlp);
} }
if ((vport->port_type == LPFC_NPIV_PORT &&
phba->cfg_vport_restrict_login)) {
/* In order to preserve RPIs, we want to cleanup
* the default RPI the firmware created to rcv
* this ELS request. The only way to do this is
* to register, then unregister the RPI.
*/
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
spin_unlock_irq(shost->host_lock);
stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
ndlp, mbox);
return 1;
}
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
return 1; return 1;
out: out:
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0; return 0;
} }
...@@ -445,7 +461,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -445,7 +461,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0; stat.un.b.vendorUnique = 0;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
/* 1 sec timeout */ /* 1 sec timeout */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
...@@ -535,6 +551,11 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -535,6 +551,11 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
roles |= FC_RPORT_ROLE_FCP_INITIATOR; roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (ndlp->nlp_type & NLP_FCP_TARGET) if (ndlp->nlp_type & NLP_FCP_TARGET)
roles |= FC_RPORT_ROLE_FCP_TARGET; roles |= FC_RPORT_ROLE_FCP_TARGET;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
"rport rolechg: role:x%x did:x%x flg:x%x",
roles, ndlp->nlp_DID, ndlp->nlp_flag);
fc_remote_port_rolechg(rport, roles); fc_remote_port_rolechg(rport, roles);
} }
} }
...@@ -657,7 +678,8 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -657,7 +678,8 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ours */ ours */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
} else { } else {
lpfc_rcv_plogi(vport, ndlp, cmdiocb); lpfc_rcv_plogi(vport, ndlp, cmdiocb);
} /* If our portname was less */ } /* If our portname was less */
...@@ -675,7 +697,7 @@ lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -675,7 +697,7 @@ lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
memset(&stat, 0, sizeof (struct ls_rjt)); memset(&stat, 0, sizeof (struct ls_rjt));
stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1335,6 +1357,10 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1335,6 +1357,10 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
irsp = &rspiocb->iocb; irsp = &rspiocb->iocb;
if (irsp->ulpStatus) { if (irsp->ulpStatus) {
if ((vport->port_type == LPFC_NPIV_PORT) &&
phba->cfg_vport_restrict_login) {
goto out;
}
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
...@@ -1355,6 +1381,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1355,6 +1381,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!(ndlp->nlp_type & NLP_FCP_TARGET) && if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
(vport->port_type == LPFC_NPIV_PORT) && (vport->port_type == LPFC_NPIV_PORT) &&
phba->cfg_vport_restrict_login) { phba->cfg_vport_restrict_login) {
out:
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_TARGET_REMOVE; ndlp->nlp_flag |= NLP_TARGET_REMOVE;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
...@@ -1606,7 +1633,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1606,7 +1633,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Ignore PLOGI if we have an outstanding LOGO */ /* Ignore PLOGI if we have an outstanding LOGO */
if (ndlp->nlp_flag & NLP_LOGO_SND) { if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) {
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1638,7 +1665,7 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1638,7 +1665,7 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
memset(&stat, 0, sizeof (struct ls_rjt)); memset(&stat, 0, sizeof (struct ls_rjt));
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp); lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
if (ndlp->nlp_flag & NLP_NPR_ADISC) { if (ndlp->nlp_flag & NLP_NPR_ADISC) {
...@@ -2035,6 +2062,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -2035,6 +2062,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->brd_no, vport->vpi, phba->brd_no, vport->vpi,
evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag); evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM in: evt:%d ste:%d did:x%x",
evt, cur_state, ndlp->nlp_DID);
func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt]; func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
rc = (func) (vport, ndlp, arg, evt); rc = (func) (vport, ndlp, arg, evt);
...@@ -2045,6 +2076,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -2045,6 +2076,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->brd_no, vport->vpi, phba->brd_no, vport->vpi,
rc, ndlp->nlp_DID, ndlp->nlp_flag); rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM out: ste:%d did:x%x flg:x%x",
rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
return rc; return rc;
......
...@@ -1532,7 +1532,6 @@ struct scsi_host_template lpfc_template = { ...@@ -1532,7 +1532,6 @@ struct scsi_host_template lpfc_template = {
.slave_configure = lpfc_slave_configure, .slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy, .slave_destroy = lpfc_slave_destroy,
.scan_finished = lpfc_scan_finished, .scan_finished = lpfc_scan_finished,
.scan_start = lpfc_scan_start,
.this_id = -1, .this_id = -1,
.sg_tablesize = LPFC_SG_SEG_CNT, .sg_tablesize = LPFC_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN, .cmd_per_lun = LPFC_CMD_PER_LUN,
......
This diff is collapsed.
...@@ -73,7 +73,8 @@ struct lpfc_iocbq { ...@@ -73,7 +73,8 @@ struct lpfc_iocbq {
#define IOCB_ERROR 2 #define IOCB_ERROR 2
#define IOCB_TIMEDOUT 3 #define IOCB_TIMEDOUT 3
#define LPFC_MBX_WAKE 1 #define LPFC_MBX_WAKE 1
#define LPFC_MBX_IMED_UNREG 2
typedef struct lpfcMboxq { typedef struct lpfcMboxq {
/* MBOXQs are used in single linked lists */ /* MBOXQs are used in single linked lists */
......
...@@ -82,7 +82,8 @@ lpfc_alloc_vpi(struct lpfc_hba *phba) ...@@ -82,7 +82,8 @@ lpfc_alloc_vpi(struct lpfc_hba *phba)
int vpi; int vpi;
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
vpi = find_next_zero_bit(phba->vpi_bmask, phba->max_vpi, 1); /* Start at bit 1 because vpi zero is reserved for the physical port */
vpi = find_next_zero_bit(phba->vpi_bmask, (phba->max_vpi + 1), 1);
if (vpi > phba->max_vpi) if (vpi > phba->max_vpi)
vpi = 0; vpi = 0;
else else
...@@ -131,7 +132,8 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) ...@@ -131,7 +132,8 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
mb->mbxCommand, mb->mbxStatus, rc); mb->mbxCommand, mb->mbxStatus, rc);
lpfc_mbuf_free(phba, mp->virt, mp->phys); lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp); kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool); if (rc != MBX_TIMEOUT)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO; return -EIO;
} }
...@@ -241,6 +243,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) ...@@ -241,6 +243,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
} }
vport->vpi = vpi; vport->vpi = vpi;
lpfc_debugfs_initialize(vport);
if (lpfc_vport_sparm(phba, vport)) { if (lpfc_vport_sparm(phba, vport)) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"%d:1813 Create VPORT failed: vpi:%d " "%d:1813 Create VPORT failed: vpi:%d "
...@@ -306,8 +310,16 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) ...@@ -306,8 +310,16 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*/ */
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
lpfc_set_disctmo(vport); if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
lpfc_initial_fdisc(vport); lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"%d (%d):0262 No NPIV Fabric "
"support\n",
phba->brd_no, vport->vpi);
}
} else { } else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_vport_set_state(vport, FC_VPORT_FAILED);
} }
...@@ -383,8 +395,16 @@ enable_vport(struct fc_vport *fc_vport) ...@@ -383,8 +395,16 @@ enable_vport(struct fc_vport *fc_vport)
*/ */
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
lpfc_set_disctmo(vport); if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
lpfc_initial_fdisc(vport); lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport);
} else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"%d (%d):0264 No NPIV Fabric "
"support\n",
phba->brd_no, vport->vpi);
}
} else { } else {
lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_vport_set_state(vport, FC_VPORT_FAILED);
} }
...@@ -441,6 +461,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -441,6 +461,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
vport->load_flag |= FC_UNLOADING; vport->load_flag |= FC_UNLOADING;
kfree(vport->vname); kfree(vport->vname);
lpfc_debugfs_terminate(vport);
fc_remove_host(lpfc_shost_from_vport(vport)); fc_remove_host(lpfc_shost_from_vport(vport));
scsi_remove_host(lpfc_shost_from_vport(vport)); scsi_remove_host(lpfc_shost_from_vport(vport));
...@@ -476,12 +497,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -476,12 +497,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
NLP_EVT_DEVICE_RM); 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_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport); lpfc_unreg_all_rpis(vport);
lpfc_unreg_default_rpis(vport); lpfc_unreg_default_rpis(vport);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment