You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
[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: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
committed by
James Bottomley
parent
92d7f7b0cd
commit
858c9f6c19
@@ -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_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 @@
|
||||
|
||||
struct lpfc_sli2_slim;
|
||||
|
||||
|
||||
#define LPFC_MAX_TARGET 256 /* max number of targets supported */
|
||||
#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
|
||||
requests */
|
||||
@@ -45,6 +44,9 @@ struct lpfc_sli2_slim;
|
||||
/* Number of exchanges reserved for discovery to complete */
|
||||
#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 putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
|
||||
#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
|
||||
@@ -308,13 +310,15 @@ struct lpfc_vport {
|
||||
|
||||
spinlock_t work_port_lock;
|
||||
uint32_t work_port_events; /* Timeout to be handled */
|
||||
#define WORKER_DISC_TMO 0x1 /* Discovery timeout */
|
||||
#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 */
|
||||
#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
|
||||
#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
|
||||
#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
|
||||
|
||||
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
|
||||
#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
|
||||
#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 els_tmofunc;
|
||||
@@ -326,6 +330,14 @@ struct lpfc_vport {
|
||||
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
|
||||
char *vname; /* Application assigned name */
|
||||
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 {
|
||||
@@ -408,6 +420,7 @@ struct lpfc_hba {
|
||||
uint32_t cfg_hba_queue_depth;
|
||||
uint32_t cfg_peer_port_login;
|
||||
uint32_t cfg_vport_restrict_login;
|
||||
uint32_t cfg_npiv_enable;
|
||||
uint32_t cfg_fcp_class;
|
||||
uint32_t cfg_use_adisc;
|
||||
uint32_t cfg_ack0;
|
||||
@@ -513,10 +526,10 @@ struct lpfc_hba {
|
||||
mempool_t *nlp_mem_pool;
|
||||
|
||||
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 */
|
||||
|
||||
@@ -531,6 +544,15 @@ struct lpfc_hba {
|
||||
unsigned long last_rsrc_error_time;
|
||||
unsigned long last_ramp_down_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 *
|
||||
|
||||
@@ -282,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
|
||||
}
|
||||
|
||||
lpfc_set_loopback_flag(phba);
|
||||
if (mbxstatus == MBX_TIMEOUT)
|
||||
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
else
|
||||
if (mbxstatus != MBX_TIMEOUT)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
|
||||
if (mbxstatus == MBXERR_ERROR)
|
||||
@@ -439,30 +437,11 @@ 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)
|
||||
lpfc_get_hba_info(struct lpfc_hba *phba,
|
||||
uint32_t *mxri, uint32_t *axri,
|
||||
uint32_t *mrpi, uint32_t *arpi,
|
||||
uint32_t *mvpi, uint32_t *avpi)
|
||||
{
|
||||
struct lpfc_sli *psli = &phba->sli;
|
||||
LPFC_MBOXQ_t *pmboxq;
|
||||
@@ -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);
|
||||
|
||||
if (rc != MBX_SUCCESS) {
|
||||
if (rc == MBX_TIMEOUT)
|
||||
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
else
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return 0;
|
||||
}
|
||||
@@ -513,6 +490,10 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
|
||||
*mxri = pmb->un.varRdConfig.max_xri;
|
||||
if (axri)
|
||||
*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);
|
||||
return 1;
|
||||
@@ -526,7 +507,7 @@ lpfc_max_rpi_show(struct class_device *cdev, char *buf)
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
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, "Unknown\n");
|
||||
}
|
||||
@@ -539,7 +520,7 @@ lpfc_used_rpi_show(struct class_device *cdev, char *buf)
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
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, "Unknown\n");
|
||||
}
|
||||
@@ -552,7 +533,7 @@ lpfc_max_xri_show(struct class_device *cdev, char *buf)
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
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, "Unknown\n");
|
||||
}
|
||||
@@ -565,7 +546,33 @@ lpfc_used_xri_show(struct class_device *cdev, char *buf)
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
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, "Unknown\n");
|
||||
}
|
||||
@@ -995,9 +1002,7 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
|
||||
" 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_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
|
||||
|
||||
/*
|
||||
# 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)
|
||||
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
|
||||
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) {
|
||||
phba->cfg_nodev_tmo = val;
|
||||
phba->cfg_devloss_tmo = val;
|
||||
lpfc_update_rport_devloss_tmo(phba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1102,6 +1126,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
|
||||
phba->cfg_nodev_tmo = val;
|
||||
phba->cfg_devloss_tmo = val;
|
||||
phba->dev_loss_tmo_changed = 1;
|
||||
lpfc_update_rport_devloss_tmo(phba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1358,6 +1383,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
|
||||
&class_device_attr_lpfc_multi_ring_type,
|
||||
&class_device_attr_lpfc_fdmi_on,
|
||||
&class_device_attr_lpfc_max_luns,
|
||||
&class_device_attr_lpfc_npiv_enable,
|
||||
&class_device_attr_nport_evt_cnt,
|
||||
&class_device_attr_management_version,
|
||||
&class_device_attr_board_mode,
|
||||
@@ -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_TIMEOUT) {
|
||||
phba->sysfs_mbox.mbox->mbox_cmpl =
|
||||
lpfc_sli_def_mbox_cmpl;
|
||||
phba->sysfs_mbox.mbox = NULL;
|
||||
}
|
||||
sysfs_mbox_idle(phba);
|
||||
@@ -1886,9 +1910,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
|
||||
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
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1913,9 +1935,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
|
||||
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
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1993,9 +2013,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
|
||||
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
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return;
|
||||
}
|
||||
@@ -2013,9 +2031,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
|
||||
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
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free( pmboxq, phba->mbox_mem_pool);
|
||||
return;
|
||||
}
|
||||
@@ -2253,6 +2269,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
|
||||
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_npiv_enable_init(phba, lpfc_npiv_enable);
|
||||
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);
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
|
||||
struct fc_rport;
|
||||
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_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,
|
||||
struct lpfc_dmabuf *mp);
|
||||
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 *);
|
||||
|
||||
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_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_ns_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 *);
|
||||
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 *);
|
||||
int lpfc_els_chk_latt(struct lpfc_vport *);
|
||||
int lpfc_els_abort_flogi(struct lpfc_hba *);
|
||||
int lpfc_initial_flogi(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);
|
||||
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_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
|
||||
int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
|
||||
struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
|
||||
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 *,
|
||||
struct lpfc_nodelist *);
|
||||
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_els_retry_delay(unsigned long);
|
||||
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 *,
|
||||
struct lpfc_iocbq *);
|
||||
int lpfc_els_handle_rscn(struct lpfc_vport *);
|
||||
@@ -117,6 +122,8 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
|
||||
int lpfc_els_disc_plogi(struct lpfc_vport *);
|
||||
void lpfc_els_timeout(unsigned long);
|
||||
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 *,
|
||||
struct lpfc_iocbq *);
|
||||
@@ -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 *);
|
||||
/* Function prototypes. */
|
||||
const char* lpfc_info(struct Scsi_Host *);
|
||||
void lpfc_scan_start(struct Scsi_Host *);
|
||||
int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
|
||||
|
||||
void lpfc_get_cfgparam(struct lpfc_hba *);
|
||||
@@ -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_vport_transport_functions;
|
||||
extern int lpfc_sli_mode;
|
||||
extern int lpfc_npiv_enable;
|
||||
|
||||
int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
|
||||
void lpfc_terminate_rport_io(struct fc_rport *);
|
||||
@@ -262,6 +267,11 @@ void destroy_port(struct lpfc_vport *);
|
||||
int lpfc_get_instance(void);
|
||||
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 */
|
||||
int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
|
||||
void lpfc_fabric_abort_vport(struct lpfc_vport *);
|
||||
|
||||
+164
-53
@@ -41,6 +41,7 @@
|
||||
#include "lpfc_crtn.h"
|
||||
#include "lpfc_version.h"
|
||||
#include "lpfc_vport.h"
|
||||
#include "lpfc_debugfs.h"
|
||||
|
||||
#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
|
||||
* incapable of reporting */
|
||||
@@ -251,6 +252,32 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
|
||||
return mlist;
|
||||
}
|
||||
|
||||
int
|
||||
lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
|
||||
{
|
||||
struct lpfc_dmabuf *buf_ptr;
|
||||
|
||||
if (ctiocb->context1) {
|
||||
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
|
||||
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
|
||||
kfree(buf_ptr);
|
||||
ctiocb->context1 = NULL;
|
||||
}
|
||||
if (ctiocb->context2) {
|
||||
lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
|
||||
ctiocb->context2 = NULL;
|
||||
}
|
||||
|
||||
if (ctiocb->context3) {
|
||||
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
|
||||
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
|
||||
kfree(buf_ptr);
|
||||
ctiocb->context1 = NULL;
|
||||
}
|
||||
lpfc_sli_release_iocbq(phba, ctiocb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
|
||||
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
|
||||
@@ -428,6 +455,13 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
|
||||
(!phba->cfg_vport_restrict_login)) {
|
||||
ndlp = lpfc_setup_disc_node(vport, Did);
|
||||
if (ndlp) {
|
||||
lpfc_debugfs_disc_trc(vport,
|
||||
LPFC_DISC_TRC_CT,
|
||||
"Parse GID_FTrsp: "
|
||||
"did:x%x flg:x%x x%x",
|
||||
Did, ndlp->nlp_flag,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_printf_log(phba, KERN_INFO,
|
||||
LOG_DISCOVERY,
|
||||
"%d (%d):0238 Process "
|
||||
@@ -439,6 +473,13 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
|
||||
vport->fc_flag,
|
||||
vport->fc_rscn_id_cnt);
|
||||
} else {
|
||||
lpfc_debugfs_disc_trc(vport,
|
||||
LPFC_DISC_TRC_CT,
|
||||
"Skip1 GID_FTrsp: "
|
||||
"did:x%x flg:x%x cnt:%d",
|
||||
Did, vport->fc_flag,
|
||||
vport->fc_rscn_id_cnt);
|
||||
|
||||
lpfc_printf_log(phba, KERN_INFO,
|
||||
LOG_DISCOVERY,
|
||||
"%d (%d):0239 Skip x%x "
|
||||
@@ -453,12 +494,26 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
|
||||
} else {
|
||||
if (!(vport->fc_flag & FC_RSCN_MODE) ||
|
||||
(lpfc_rscn_payload_check(vport, Did))) {
|
||||
lpfc_debugfs_disc_trc(vport,
|
||||
LPFC_DISC_TRC_CT,
|
||||
"Query GID_FTrsp: "
|
||||
"did:x%x flg:x%x cnt:%d",
|
||||
Did, vport->fc_flag,
|
||||
vport->fc_rscn_id_cnt);
|
||||
|
||||
if (lpfc_ns_cmd(vport,
|
||||
SLI_CTNS_GFF_ID,
|
||||
0, Did) == 0)
|
||||
vport->num_disc_nodes++;
|
||||
}
|
||||
else {
|
||||
lpfc_debugfs_disc_trc(vport,
|
||||
LPFC_DISC_TRC_CT,
|
||||
"Skip2 GID_FTrsp: "
|
||||
"did:x%x flg:x%x cnt:%d",
|
||||
Did, vport->fc_flag,
|
||||
vport->fc_rscn_id_cnt);
|
||||
|
||||
lpfc_printf_log(phba, KERN_INFO,
|
||||
LOG_DISCOVERY,
|
||||
"%d (%d):0245 Skip x%x "
|
||||
@@ -492,7 +547,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
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_sli_ct_request *CTrsp;
|
||||
int rc;
|
||||
@@ -500,31 +554,39 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
||||
cmdiocb->context_un.rsp_iocb = rspiocb;
|
||||
|
||||
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
|
||||
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
||||
bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
|
||||
irsp = &rspiocb->iocb;
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"GID_FT cmpl: status:x%x/x%x rtry:%d",
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
|
||||
|
||||
/* 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 err1;
|
||||
|
||||
if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
|
||||
"%d (%d):0216 Link event during NS query\n",
|
||||
phba->brd_no, vport->vpi);
|
||||
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (irsp->ulpStatus) {
|
||||
/* Check for retry */
|
||||
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
|
||||
vport->fc_ns_retry++;
|
||||
if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
|
||||
(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
|
||||
vport->fc_ns_retry++;
|
||||
/* CT command is being retried */
|
||||
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",
|
||||
@@ -553,6 +615,13 @@ err1:
|
||||
(uint32_t) CTrsp->ReasonCode,
|
||||
(uint32_t) CTrsp->Explanation,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
||||
(uint32_t) CTrsp->ReasonCode,
|
||||
(uint32_t) CTrsp->Explanation);
|
||||
|
||||
} else {
|
||||
/* NameServer Rsp Error */
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
||||
@@ -563,6 +632,12 @@ err1:
|
||||
(uint32_t) CTrsp->ReasonCode,
|
||||
(uint32_t) CTrsp->Explanation,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
||||
(uint32_t) CTrsp->ReasonCode,
|
||||
(uint32_t) CTrsp->Explanation);
|
||||
}
|
||||
}
|
||||
/* Link up / RSCN discovery */
|
||||
@@ -586,12 +661,7 @@ err1:
|
||||
lpfc_disc_start(vport);
|
||||
}
|
||||
out:
|
||||
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);
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -602,7 +672,6 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
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;
|
||||
@@ -613,6 +682,10 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
|
||||
did = be32_to_cpu(did);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"GFF_ID cmpl: status:x%x/x%x did:x%x",
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4], did);
|
||||
|
||||
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
||||
/* Good status, continue checking */
|
||||
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
||||
@@ -632,6 +705,15 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
||||
"%d (%d):0267 NameServer GFF Rsp"
|
||||
" x%x Error (%d %d) Data: x%x x%x\n",
|
||||
phba->brd_no, vport->vpi, did,
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4],
|
||||
vport->fc_flag, vport->fc_rscn_id_cnt)
|
||||
}
|
||||
|
||||
/* This is a target port, unregistered port, or the GFF_ID failed */
|
||||
ndlp = lpfc_setup_disc_node(vport, did);
|
||||
if (ndlp) {
|
||||
@@ -670,13 +752,7 @@ out:
|
||||
}
|
||||
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);
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -686,37 +762,45 @@ 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;
|
||||
uint32_t latt;
|
||||
|
||||
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
||||
cmdiocb->context_un.rsp_iocb = rspiocb;
|
||||
|
||||
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
|
||||
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
||||
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;
|
||||
|
||||
/* NS request completes status <ulpStatus> CmdRsp <CmdRsp> */
|
||||
latt = lpfc_els_chk_latt(vport);
|
||||
|
||||
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
|
||||
"%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, vport->vpi,
|
||||
cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4],
|
||||
"%d (%d):0209 RFT request completes, latt %d, "
|
||||
"ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
|
||||
phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
|
||||
CTrsp->CommandResponse.bits.CmdRsp,
|
||||
cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"CT cmd cmpl: status:x%x/x%x cmd:x%x",
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
|
||||
|
||||
if (irsp->ulpStatus) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
||||
"%d (%d):0268 NS cmd %x Error (%d %d)\n",
|
||||
phba->brd_no, vport->vpi, cmdcode,
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4]);
|
||||
|
||||
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
|
||||
((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
|
||||
(irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
|
||||
@@ -736,12 +820,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
}
|
||||
|
||||
out:
|
||||
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);
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -840,31 +919,42 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
|
||||
struct lpfc_iocbq *) = NULL;
|
||||
uint32_t rsp_size = 1024;
|
||||
size_t size;
|
||||
int rc = 0;
|
||||
|
||||
ndlp = lpfc_findnode_did(vport, NameServer_DID);
|
||||
if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
|
||||
return 1;
|
||||
if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
|
||||
rc=1;
|
||||
goto ns_cmd_exit;
|
||||
}
|
||||
|
||||
/* fill in BDEs for command */
|
||||
/* Allocate buffer for command payload */
|
||||
mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!mp)
|
||||
if (!mp) {
|
||||
rc=2;
|
||||
goto ns_cmd_exit;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&mp->list);
|
||||
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
||||
if (!mp->virt)
|
||||
if (!mp->virt) {
|
||||
rc=3;
|
||||
goto ns_cmd_free_mp;
|
||||
}
|
||||
|
||||
/* Allocate buffer for Buffer ptr list */
|
||||
bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!bmp)
|
||||
if (!bmp) {
|
||||
rc=4;
|
||||
goto ns_cmd_free_mpvirt;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&bmp->list);
|
||||
bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
|
||||
if (!bmp->virt)
|
||||
if (!bmp->virt) {
|
||||
rc=5;
|
||||
goto ns_cmd_free_bmp;
|
||||
}
|
||||
|
||||
/* NameServer Req */
|
||||
lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
|
||||
@@ -970,10 +1060,15 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
|
||||
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
|
||||
/* On success, The cmpl function will free the buffers */
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"Issue CT cmd: cmd:x%x did:x%x",
|
||||
cmdcode, ndlp->nlp_DID, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc=6;
|
||||
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
|
||||
ns_cmd_free_bmp:
|
||||
kfree(bmp);
|
||||
@@ -982,6 +1077,10 @@ ns_cmd_free_mpvirt:
|
||||
ns_cmd_free_mp:
|
||||
kfree(mp);
|
||||
ns_cmd_exit:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
||||
"%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
|
||||
phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
|
||||
vport->fc_rscn_id_cnt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -989,7 +1088,6 @@ static void
|
||||
lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
struct lpfc_iocbq * rspiocb)
|
||||
{
|
||||
struct lpfc_dmabuf *bmp = cmdiocb->context3;
|
||||
struct lpfc_dmabuf *inp = cmdiocb->context1;
|
||||
struct lpfc_dmabuf *outp = cmdiocb->context2;
|
||||
struct lpfc_sli_ct_request *CTrsp = outp->virt;
|
||||
@@ -998,6 +1096,25 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
||||
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
||||
struct lpfc_vport *vport = cmdiocb->vport;
|
||||
IOCB_t *irsp = &rspiocb->iocb;
|
||||
uint32_t latt;
|
||||
|
||||
latt = lpfc_els_chk_latt(vport);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"FDMI cmpl: status:x%x/x%x latt:%d",
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
|
||||
|
||||
if (latt || irsp->ulpStatus) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
|
||||
"%d (%d):0229 FDMI cmd %04x failed, latt = %d "
|
||||
"ulpStatus: x%x, rid x%x\n",
|
||||
phba->brd_no, vport->vpi,
|
||||
be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
|
||||
irsp->un.ulpWord[4]);
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
||||
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
||||
@@ -1024,13 +1141,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************
|
||||
* 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 {
|
||||
LPFC_EVT_WARM_START,
|
||||
LPFC_EVT_KILL,
|
||||
LPFC_EVT_ELS_RETRY,
|
||||
LPFC_EVT_DEV_LOSS_DELAY,
|
||||
LPFC_EVT_DEV_LOSS,
|
||||
};
|
||||
|
||||
@@ -74,7 +75,6 @@ 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;
|
||||
@@ -101,6 +101,7 @@ struct lpfc_nodelist {
|
||||
ACC */
|
||||
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
|
||||
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_TARGET_REMOVE 0x10000000 /* Target remove in process */
|
||||
|
||||
|
||||
+318
-92
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1278,6 +1278,7 @@ typedef struct { /* FireFly BIU registers */
|
||||
#define MBX_KILL_BOARD 0x24
|
||||
#define MBX_CONFIG_FARP 0x25
|
||||
#define MBX_BEACON 0x2A
|
||||
#define MBX_HEARTBEAT 0x31
|
||||
|
||||
#define MBX_CONFIG_HBQ 0x7C
|
||||
#define MBX_LOAD_AREA 0x81
|
||||
@@ -1777,8 +1778,6 @@ typedef struct {
|
||||
#define LMT_4Gb 0x040
|
||||
#define LMT_8Gb 0x080
|
||||
#define LMT_10Gb 0x100
|
||||
|
||||
|
||||
uint32_t rsvd2;
|
||||
uint32_t rsvd3;
|
||||
uint32_t max_xri;
|
||||
@@ -1787,7 +1786,10 @@ typedef struct {
|
||||
uint32_t avail_xri;
|
||||
uint32_t avail_iocb;
|
||||
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;
|
||||
|
||||
/* Structure for MB Command READ_RCONFIG (12) */
|
||||
@@ -3171,3 +3173,16 @@ lpfc_is_LC_HBA(unsigned short device)
|
||||
else
|
||||
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));
|
||||
}
|
||||
|
||||
+181
-47
@@ -391,6 +391,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
|
||||
*/
|
||||
timeout = phba->fc_ratov << 1;
|
||||
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);
|
||||
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
@@ -485,6 +488,119 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
|
||||
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 */
|
||||
@@ -1190,9 +1306,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
|
||||
lpfc_can_disctmo(vport);
|
||||
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
|
||||
lpfc_nlp_put(ndlp);
|
||||
|
||||
INIT_LIST_HEAD(&vport->fc_nodes);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1238,6 +1351,8 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
|
||||
lpfc_stop_vport_timers(vport);
|
||||
del_timer_sync(&phba->sli.mbox_tmo);
|
||||
del_timer_sync(&phba->fabric_block_timer);
|
||||
phba->hb_outstanding = 0;
|
||||
del_timer_sync(&phba->hb_tmofunc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1474,8 +1589,8 @@ destroy_port(struct lpfc_vport *vport)
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
|
||||
kfree(vport->vname);
|
||||
lpfc_free_sysfs_attr(vport);
|
||||
|
||||
lpfc_debugfs_terminate(vport);
|
||||
fc_remove_host(shost);
|
||||
scsi_remove_host(shost);
|
||||
|
||||
@@ -1500,50 +1615,29 @@ lpfc_get_instance(void)
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void
|
||||
lpfc_remove_device(struct lpfc_vport *vport)
|
||||
{
|
||||
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);
|
||||
}
|
||||
/*
|
||||
* Note: there is no scan_start function as adapter initialization
|
||||
* will have asynchronously kicked off the link initialization.
|
||||
*/
|
||||
|
||||
int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||
{
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||
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) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||
"%d:0461 Scanning longer than 30 "
|
||||
"seconds. Continuing initialization\n",
|
||||
phba->brd_no);
|
||||
stat = 1;
|
||||
goto finished;
|
||||
}
|
||||
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)
|
||||
"%d:0465 Link down longer than 15 "
|
||||
"seconds. Continuing initialization\n",
|
||||
phba->brd_no);
|
||||
stat = 1;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if (vport->port_state != LPFC_VPORT_READY)
|
||||
return 0;
|
||||
goto finished;
|
||||
if (vport->num_disc_nodes || vport->fc_prli_sent)
|
||||
return 0;
|
||||
goto finished;
|
||||
if (vport->fc_map_cnt == 0 && time < 2 * HZ)
|
||||
return 0;
|
||||
goto finished;
|
||||
if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0)
|
||||
return 0;
|
||||
goto finished;
|
||||
|
||||
stat = 1;
|
||||
|
||||
finished:
|
||||
lpfc_host_attrib_init(shost);
|
||||
return 1;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
return stat;
|
||||
}
|
||||
|
||||
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)
|
||||
/* Initialize timers used by driver */
|
||||
init_timer(&phba->fc_estabtmo);
|
||||
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;
|
||||
init_timer(&psli->mbox_tmo);
|
||||
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)
|
||||
|
||||
shost = lpfc_shost_from_vport(vport);
|
||||
phba->pport = vport;
|
||||
lpfc_debugfs_initialize(vport);
|
||||
|
||||
pci_set_drvdata(pdev, shost);
|
||||
|
||||
@@ -1820,15 +1923,32 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
||||
if (lpfc_alloc_sysfs_attr(vport))
|
||||
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) {
|
||||
spin_lock_irq(shost->host_lock);
|
||||
lpfc_poll_start_timer(phba);
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
}
|
||||
|
||||
scsi_scan_host(shost);
|
||||
|
||||
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:
|
||||
lpfc_stop_phba_timers(phba);
|
||||
phba->pport->work_port_events = 0;
|
||||
@@ -1865,6 +1985,8 @@ out_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
out:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
if (shost)
|
||||
scsi_host_put(shost);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1878,6 +2000,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
|
||||
list_for_each_entry(port_iterator, &phba->port_list, listentry)
|
||||
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,
|
||||
* clears the rings, discards all mailbox commands, and resets
|
||||
@@ -1887,6 +2015,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
|
||||
lpfc_sli_brdrestart(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);
|
||||
|
||||
@@ -1894,9 +2029,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
|
||||
free_irq(phba->pcidev->irq, phba);
|
||||
pci_disable_msi(phba->pcidev);
|
||||
|
||||
destroy_port(vport);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
scsi_host_put(shost);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
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 */
|
||||
/* mailbox command */
|
||||
@@ -676,7 +692,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
||||
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 &&
|
||||
if (phba->max_vpi && phba->cfg_npiv_enable &&
|
||||
phba->vpd.sli3Feat.cmv) {
|
||||
mb->un.varCfgPort.max_vpi = phba->max_vpi;
|
||||
mb->un.varCfgPort.cmv = 1;
|
||||
|
||||
@@ -88,7 +88,8 @@ 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;
|
||||
/* 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);
|
||||
if (!phba->vpi_bmask)
|
||||
goto fail_free_hbq_pool;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "lpfc_logmsg.h"
|
||||
#include "lpfc_crtn.h"
|
||||
#include "lpfc_vport.h"
|
||||
#include "lpfc_debugfs.h"
|
||||
|
||||
|
||||
/* 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)
|
||||
/* First check the txq */
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
|
||||
/* Check to see if iocb matches the nport we are looking
|
||||
for */
|
||||
/* Check to see if iocb matches the nport we are looking for */
|
||||
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
|
||||
/* It matches, so deque and call compl with an
|
||||
error */
|
||||
/* It matches, so deque and call compl with anp error */
|
||||
list_move_tail(&iocb->list, &completions);
|
||||
pring->txq_cnt--;
|
||||
}
|
||||
@@ -216,8 +215,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
|
||||
|
||||
/* Next check the txcmplq */
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
|
||||
/* Check to see if iocb matches the nport we are looking
|
||||
for */
|
||||
/* Check to see if iocb matches the nport we are looking for */
|
||||
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
|
||||
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
|
||||
}
|
||||
@@ -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.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
|
||||
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
|
||||
ndlp);
|
||||
ndlp, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -293,7 +291,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
/* Reject this request because invalid parameters */
|
||||
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
|
||||
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;
|
||||
}
|
||||
icmd = &cmdiocb->iocb;
|
||||
@@ -392,13 +391,30 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *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);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
|
||||
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 */
|
||||
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
|
||||
@@ -535,6 +551,11 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
if (ndlp->nlp_type & NLP_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);
|
||||
}
|
||||
}
|
||||
@@ -657,7 +678,8 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
ours */
|
||||
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
|
||||
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 {
|
||||
lpfc_rcv_plogi(vport, ndlp, cmdiocb);
|
||||
} /* If our portname was less */
|
||||
@@ -675,7 +697,7 @@ lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
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);
|
||||
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
|
||||
return ndlp->nlp_state;
|
||||
}
|
||||
|
||||
@@ -1335,6 +1357,10 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
|
||||
irsp = &rspiocb->iocb;
|
||||
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;
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
|
||||
return ndlp->nlp_state;
|
||||
@@ -1355,6 +1381,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
|
||||
(vport->port_type == LPFC_NPIV_PORT) &&
|
||||
phba->cfg_vport_restrict_login) {
|
||||
out:
|
||||
spin_lock_irq(shost->host_lock);
|
||||
ndlp->nlp_flag |= NLP_TARGET_REMOVE;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
@@ -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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -1638,7 +1665,7 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
memset(&stat, 0, sizeof (struct ls_rjt));
|
||||
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
|
||||
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_NPR_ADISC) {
|
||||
@@ -2035,6 +2062,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
phba->brd_no, vport->vpi,
|
||||
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];
|
||||
rc = (func) (vport, ndlp, arg, evt);
|
||||
|
||||
@@ -2045,6 +2076,10 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
phba->brd_no, vport->vpi,
|
||||
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);
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -1532,7 +1532,6 @@ struct scsi_host_template lpfc_template = {
|
||||
.slave_configure = lpfc_slave_configure,
|
||||
.slave_destroy = lpfc_slave_destroy,
|
||||
.scan_finished = lpfc_scan_finished,
|
||||
.scan_start = lpfc_scan_start,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = LPFC_SG_SEG_CNT,
|
||||
.cmd_per_lun = LPFC_CMD_PER_LUN,
|
||||
|
||||
+153
-55
@@ -38,6 +38,7 @@
|
||||
#include "lpfc_crtn.h"
|
||||
#include "lpfc_logmsg.h"
|
||||
#include "lpfc_compat.h"
|
||||
#include "lpfc_debugfs.h"
|
||||
|
||||
/*
|
||||
* Define macro to log: Mailbox command x%x cannot issue Data
|
||||
@@ -269,20 +270,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||
static struct lpfc_iocbq *
|
||||
lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
|
||||
{
|
||||
struct list_head *dlp;
|
||||
struct lpfc_iocbq *cmd_iocb;
|
||||
|
||||
dlp = &pring->txq;
|
||||
cmd_iocb = NULL;
|
||||
list_remove_head((&pring->txq), cmd_iocb,
|
||||
struct lpfc_iocbq,
|
||||
list);
|
||||
if (cmd_iocb) {
|
||||
/* If the first ptr is not equal to the list header,
|
||||
* deque the IOCBQ_t and return it.
|
||||
*/
|
||||
list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
|
||||
if (cmd_iocb != NULL)
|
||||
pring->txq_cnt--;
|
||||
}
|
||||
return cmd_iocb;
|
||||
}
|
||||
|
||||
@@ -736,6 +728,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
|
||||
case MBX_LOAD_EXP_ROM:
|
||||
case MBX_REG_VPI:
|
||||
case MBX_UNREG_VPI:
|
||||
case MBX_HEARTBEAT:
|
||||
ret = mbxCommand;
|
||||
break;
|
||||
default:
|
||||
@@ -748,15 +741,18 @@ static void
|
||||
lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
||||
{
|
||||
wait_queue_head_t *pdone_q;
|
||||
unsigned long drvr_flag;
|
||||
|
||||
/*
|
||||
* If pdone_q is empty, the driver thread gave up waiting and
|
||||
* continued running.
|
||||
*/
|
||||
pmboxq->mbox_flag |= LPFC_MBX_WAKE;
|
||||
spin_lock_irqsave(&phba->hbalock, drvr_flag);
|
||||
pdone_q = (wait_queue_head_t *) pmboxq->context1;
|
||||
if (pdone_q)
|
||||
wake_up_interruptible(pdone_q);
|
||||
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -817,6 +813,25 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
|
||||
|
||||
pmbox = &pmb->mb;
|
||||
|
||||
if (pmbox->mbxCommand != MBX_HEARTBEAT) {
|
||||
if (pmb->vport) {
|
||||
lpfc_debugfs_disc_trc(pmb->vport,
|
||||
LPFC_DISC_TRC_MBOX_VPORT,
|
||||
"MBOX cmpl vport: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)pmbox->mbxCommand,
|
||||
pmbox->un.varWords[0],
|
||||
pmbox->un.varWords[1]);
|
||||
}
|
||||
else {
|
||||
lpfc_debugfs_disc_trc(phba->pport,
|
||||
LPFC_DISC_TRC_MBOX,
|
||||
"MBOX cmpl: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)pmbox->mbxCommand,
|
||||
pmbox->un.varWords[0],
|
||||
pmbox->un.varWords[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if unknown mbox command completion.
|
||||
*/
|
||||
@@ -1309,6 +1324,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
|
||||
* network byte order and pci byte orders are different.
|
||||
*/
|
||||
entry = lpfc_resp_iocb(phba, pring);
|
||||
phba->last_completion_time = jiffies;
|
||||
|
||||
if (++pring->rspidx >= portRspMax)
|
||||
pring->rspidx = 0;
|
||||
@@ -1511,6 +1527,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
|
||||
*/
|
||||
entry = lpfc_resp_iocb(phba, pring);
|
||||
|
||||
phba->last_completion_time = jiffies;
|
||||
rspiocbp = __lpfc_sli_get_iocbq(phba);
|
||||
if (rspiocbp == NULL) {
|
||||
printk(KERN_ERR "%s: out of buffers! Failing "
|
||||
@@ -2304,7 +2321,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
|
||||
|
||||
switch (lpfc_sli_mode) {
|
||||
case 2:
|
||||
if (lpfc_npiv_enable) {
|
||||
if (phba->cfg_npiv_enable) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
|
||||
"%d:1824 NPIV enabled: Override lpfc_sli_mode "
|
||||
"parameter (%d) to auto (0).\n",
|
||||
@@ -2573,6 +2590,21 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
|
||||
psli->slistat.mbox_busy++;
|
||||
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
|
||||
|
||||
if (pmbox->vport) {
|
||||
lpfc_debugfs_disc_trc(pmbox->vport,
|
||||
LPFC_DISC_TRC_MBOX_VPORT,
|
||||
"MBOX Bsy vport: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)mb->mbxCommand,
|
||||
mb->un.varWords[0], mb->un.varWords[1]);
|
||||
}
|
||||
else {
|
||||
lpfc_debugfs_disc_trc(phba->pport,
|
||||
LPFC_DISC_TRC_MBOX,
|
||||
"MBOX Bsy: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)mb->mbxCommand,
|
||||
mb->un.varWords[0], mb->un.varWords[1]);
|
||||
}
|
||||
|
||||
return MBX_BUSY;
|
||||
}
|
||||
|
||||
@@ -2618,6 +2650,23 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
|
||||
mb->mbxCommand, phba->pport->port_state,
|
||||
psli->sli_flag, flag);
|
||||
|
||||
if (mb->mbxCommand != MBX_HEARTBEAT) {
|
||||
if (pmbox->vport) {
|
||||
lpfc_debugfs_disc_trc(pmbox->vport,
|
||||
LPFC_DISC_TRC_MBOX_VPORT,
|
||||
"MBOX Send vport: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)mb->mbxCommand,
|
||||
mb->un.varWords[0], mb->un.varWords[1]);
|
||||
}
|
||||
else {
|
||||
lpfc_debugfs_disc_trc(phba->pport,
|
||||
LPFC_DISC_TRC_MBOX,
|
||||
"MBOX Send: cmd:x%x mb:x%x x%x",
|
||||
(uint32_t)mb->mbxCommand,
|
||||
mb->un.varWords[0], mb->un.varWords[1]);
|
||||
}
|
||||
}
|
||||
|
||||
psli->slistat.mbox_cmd++;
|
||||
evtctr = psli->slistat.mbox_event;
|
||||
|
||||
@@ -2760,14 +2809,13 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
|
||||
/*
|
||||
* Caller needs to hold lock.
|
||||
*/
|
||||
static int
|
||||
static void
|
||||
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||
struct lpfc_iocbq *piocb)
|
||||
{
|
||||
/* Insert the caller's iocb in the txq tail for later processing. */
|
||||
list_add_tail(&piocb->list, &pring->txq);
|
||||
pring->txq_cnt++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lpfc_iocbq *
|
||||
@@ -3074,11 +3122,11 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
|
||||
int
|
||||
lpfc_sli_host_down(struct lpfc_vport *vport)
|
||||
{
|
||||
LIST_HEAD(completions);
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_sli *psli = &phba->sli;
|
||||
struct lpfc_sli_ring *pring;
|
||||
struct lpfc_iocbq *iocb, *next_iocb;
|
||||
IOCB_t *icmd = NULL;
|
||||
int i;
|
||||
unsigned long flags = 0;
|
||||
uint16_t prev_pring_flag;
|
||||
@@ -3086,31 +3134,20 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
|
||||
lpfc_cleanup_discovery_resources(vport);
|
||||
|
||||
spin_lock_irqsave(&phba->hbalock, flags);
|
||||
|
||||
for (i = 0; i < psli->num_rings; i++) {
|
||||
pring = &psli->ring[i];
|
||||
prev_pring_flag = pring->flag;
|
||||
pring->flag |= LPFC_DEFERRED_RING_EVENT;
|
||||
|
||||
if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
|
||||
pring->flag |= LPFC_DEFERRED_RING_EVENT;
|
||||
/*
|
||||
* Error everything on the txq since these iocbs have not been
|
||||
* given to the FW yet.
|
||||
*/
|
||||
|
||||
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
|
||||
if (iocb->vport != vport)
|
||||
continue;
|
||||
list_del_init(&iocb->list);
|
||||
list_move_tail(&iocb->list, &completions);
|
||||
pring->txq_cnt--;
|
||||
if (iocb->iocb_cmpl) {
|
||||
icmd = &iocb->iocb;
|
||||
icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
|
||||
icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
(iocb->iocb_cmpl) (phba, iocb, iocb);
|
||||
spin_lock_irqsave(&phba->hbalock, flags);
|
||||
} else
|
||||
lpfc_sli_release_iocbq(phba, iocb);
|
||||
}
|
||||
|
||||
/* Next issue ABTS for everything on the txcmplq */
|
||||
@@ -3126,6 +3163,17 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
|
||||
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
|
||||
while (!list_empty(&completions)) {
|
||||
list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
|
||||
|
||||
if (!iocb->iocb_cmpl)
|
||||
lpfc_sli_release_iocbq(phba, iocb);
|
||||
else {
|
||||
iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
|
||||
iocb->iocb.un.ulpWord[4] = IOERR_SLI_DOWN;
|
||||
(iocb->iocb_cmpl) (phba, iocb, iocb);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3148,7 +3196,8 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
|
||||
spin_lock_irqsave(&phba->hbalock, flags);
|
||||
for (i = 0; i < psli->num_rings; i++) {
|
||||
pring = &psli->ring[i];
|
||||
pring->flag |= LPFC_DEFERRED_RING_EVENT;
|
||||
if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
|
||||
pring->flag |= LPFC_DEFERRED_RING_EVENT;
|
||||
|
||||
/*
|
||||
* Error everything on the txq since these iocbs have not been
|
||||
@@ -3326,8 +3375,10 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
"x%x x%x x%x\n",
|
||||
phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
|
||||
irsp->un.ulpWord[4], irsp->ulpTimeout);
|
||||
|
||||
lpfc_els_free_iocb(phba, cmdiocb);
|
||||
if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
|
||||
lpfc_ct_free_iocb(phba, cmdiocb);
|
||||
else
|
||||
lpfc_els_free_iocb(phba, cmdiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3352,10 +3403,11 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||
(cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
|
||||
return 0;
|
||||
|
||||
/* If we're unloading, don't abort the iocb, but change the callback so
|
||||
* that nothing happens when it finishes.
|
||||
/* If we're unloading, don't abort iocb on the ELS ring, but change the
|
||||
* callback so that nothing happens when it finishes.
|
||||
*/
|
||||
if (vport->load_flag & FC_UNLOADING) {
|
||||
if ((vport->load_flag & FC_UNLOADING) &&
|
||||
(pring->ringno == LPFC_ELS_RING)) {
|
||||
if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
|
||||
cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
|
||||
else
|
||||
@@ -3540,9 +3592,9 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
|
||||
&rspiocbq->iocb, sizeof(IOCB_t));
|
||||
|
||||
pdone_q = cmdiocbq->context_un.wait_queue;
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
if (pdone_q)
|
||||
wake_up(pdone_q);
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3638,6 +3690,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
|
||||
{
|
||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
|
||||
int retval;
|
||||
unsigned long flag;
|
||||
|
||||
/* The caller must leave context1 empty. */
|
||||
if (pmboxq->context1 != 0)
|
||||
@@ -3656,6 +3709,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
|
||||
pmboxq->mbox_flag & LPFC_MBX_WAKE,
|
||||
timeout * HZ);
|
||||
|
||||
spin_lock_irqsave(&phba->hbalock, flag);
|
||||
pmboxq->context1 = NULL;
|
||||
/*
|
||||
* if LPFC_MBX_WAKE flag is set the mailbox is completed
|
||||
@@ -3663,8 +3717,11 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
|
||||
*/
|
||||
if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
|
||||
retval = MBX_SUCCESS;
|
||||
else
|
||||
else {
|
||||
retval = MBX_TIMEOUT;
|
||||
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
}
|
||||
spin_unlock_irqrestore(&phba->hbalock, flag);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -3712,6 +3769,9 @@ lpfc_intr_handler(int irq, void *dev_id)
|
||||
uint32_t control;
|
||||
|
||||
MAILBOX_t *mbox, *pmbox;
|
||||
struct lpfc_vport *vport;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
struct lpfc_dmabuf *mp;
|
||||
LPFC_MBOXQ_t *pmb;
|
||||
int rc;
|
||||
|
||||
@@ -3780,18 +3840,23 @@ lpfc_intr_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
|
||||
for (i = 0; i < phba->sli.num_rings; i++) {
|
||||
if (work_ha_copy & (HA_RXATT << (4*i))) {
|
||||
/*
|
||||
* Turn off Slow Rings interrupts
|
||||
*/
|
||||
spin_lock(&phba->hbalock);
|
||||
control = readl(phba->HCregaddr);
|
||||
control &= ~(HC_R0INT_ENA << i);
|
||||
/*
|
||||
* Turn off Slow Rings interrupts, LPFC_ELS_RING is
|
||||
* the only slow ring.
|
||||
*/
|
||||
status = (work_ha_copy &
|
||||
(HA_RXMASK << (4*LPFC_ELS_RING)));
|
||||
status >>= (4*LPFC_ELS_RING);
|
||||
if (status & HA_RXMASK) {
|
||||
spin_lock(&phba->hbalock);
|
||||
control = readl(phba->HCregaddr);
|
||||
if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
|
||||
control &=
|
||||
~(HC_R0INT_ENA << LPFC_ELS_RING);
|
||||
writel(control, phba->HCregaddr);
|
||||
readl(phba->HCregaddr); /* flush */
|
||||
spin_unlock(&phba->hbalock);
|
||||
}
|
||||
spin_unlock(&phba->hbalock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3819,6 +3884,7 @@ lpfc_intr_handler(int irq, void *dev_id)
|
||||
pmb = phba->sli.mbox_active;
|
||||
pmbox = &pmb->mb;
|
||||
mbox = &phba->slim2p->mbx;
|
||||
vport = pmb->vport;
|
||||
|
||||
/* First check out the status word */
|
||||
lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
|
||||
@@ -3833,22 +3899,54 @@ lpfc_intr_handler(int irq, void *dev_id)
|
||||
"Interrupt mbxCommand x%x "
|
||||
"mbxStatus x%x\n",
|
||||
phba->brd_no,
|
||||
(pmb->vport
|
||||
? pmb->vport->vpi
|
||||
: 0),
|
||||
(vport
|
||||
? vport->vpi : 0),
|
||||
pmbox->mbxCommand,
|
||||
pmbox->mbxStatus);
|
||||
}
|
||||
phba->last_completion_time = jiffies;
|
||||
del_timer_sync(&phba->sli.mbox_tmo);
|
||||
|
||||
spin_lock(&phba->pport->work_port_lock);
|
||||
phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
|
||||
spin_unlock(&phba->pport->work_port_lock);
|
||||
phba->sli.mbox_active = NULL;
|
||||
if (pmb->mbox_cmpl) {
|
||||
lpfc_sli_pcimem_bcopy(mbox, pmbox,
|
||||
MAILBOX_CMD_SIZE);
|
||||
}
|
||||
if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
|
||||
pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
|
||||
|
||||
lpfc_debugfs_disc_trc(vport,
|
||||
LPFC_DISC_TRC_MBOX_VPORT,
|
||||
"MBOX dflt rpi: : status:x%x rpi:x%x",
|
||||
(uint32_t)pmbox->mbxStatus,
|
||||
pmbox->un.varWords[0], 0);
|
||||
|
||||
if ( !pmbox->mbxStatus) {
|
||||
mp = (struct lpfc_dmabuf *)
|
||||
(pmb->context1);
|
||||
ndlp = (struct lpfc_nodelist *)
|
||||
pmb->context2;
|
||||
|
||||
/* Reg_LOGIN of dflt RPI was successful.
|
||||
* new lets get rid of the RPI using the
|
||||
* same mbox buffer.
|
||||
*/
|
||||
lpfc_unreg_login(phba, vport->vpi,
|
||||
pmbox->un.varWords[0], pmb);
|
||||
pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
|
||||
pmb->context1 = mp;
|
||||
pmb->context2 = ndlp;
|
||||
pmb->vport = vport;
|
||||
spin_lock(&phba->hbalock);
|
||||
phba->sli.sli_flag &=
|
||||
~LPFC_SLI_MBOX_ACTIVE;
|
||||
spin_unlock(&phba->hbalock);
|
||||
goto send_current_mbox;
|
||||
}
|
||||
}
|
||||
spin_lock(&phba->pport->work_port_lock);
|
||||
phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
|
||||
spin_unlock(&phba->pport->work_port_lock);
|
||||
lpfc_mbox_cmpl_put(phba, pmb);
|
||||
}
|
||||
if ((work_ha_copy & HA_MBATT) &&
|
||||
@@ -3858,7 +3956,7 @@ send_next_mbox:
|
||||
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
|
||||
pmb = lpfc_mbox_get(phba);
|
||||
spin_unlock(&phba->hbalock);
|
||||
|
||||
send_current_mbox:
|
||||
/* Process next mailbox command if there is one */
|
||||
if (pmb != NULL) {
|
||||
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
|
||||
@@ -3891,7 +3989,7 @@ send_next_mbox:
|
||||
*/
|
||||
status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
|
||||
status >>= (4*LPFC_FCP_RING);
|
||||
if (status & HA_RXATT)
|
||||
if (status & HA_RXMASK)
|
||||
lpfc_sli_handle_fast_ring_event(phba,
|
||||
&phba->sli.ring[LPFC_FCP_RING],
|
||||
status);
|
||||
@@ -3904,7 +4002,7 @@ send_next_mbox:
|
||||
*/
|
||||
status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
|
||||
status >>= (4*LPFC_EXTRA_RING);
|
||||
if (status & HA_RXATT) {
|
||||
if (status & HA_RXMASK) {
|
||||
lpfc_sli_handle_fast_ring_event(phba,
|
||||
&phba->sli.ring[LPFC_EXTRA_RING],
|
||||
status);
|
||||
|
||||
@@ -73,7 +73,8 @@ struct lpfc_iocbq {
|
||||
#define IOCB_ERROR 2
|
||||
#define IOCB_TIMEDOUT 3
|
||||
|
||||
#define LPFC_MBX_WAKE 1
|
||||
#define LPFC_MBX_WAKE 1
|
||||
#define LPFC_MBX_IMED_UNREG 2
|
||||
|
||||
typedef struct lpfcMboxq {
|
||||
/* MBOXQs are used in single linked lists */
|
||||
|
||||
@@ -82,7 +82,8 @@ 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);
|
||||
/* 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)
|
||||
vpi = 0;
|
||||
else
|
||||
@@ -131,7 +132,8 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
|
||||
mb->mbxCommand, mb->mbxStatus, rc);
|
||||
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
||||
kfree(mp);
|
||||
mempool_free(pmb, phba->mbox_mem_pool);
|
||||
if (rc != MBX_TIMEOUT)
|
||||
mempool_free(pmb, phba->mbox_mem_pool);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -241,6 +243,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
|
||||
}
|
||||
|
||||
vport->vpi = vpi;
|
||||
lpfc_debugfs_initialize(vport);
|
||||
|
||||
if (lpfc_vport_sparm(phba, vport)) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
|
||||
"%d:1813 Create VPORT failed: vpi:%d "
|
||||
@@ -306,8 +310,16 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
|
||||
*/
|
||||
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);
|
||||
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
|
||||
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 {
|
||||
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
||||
}
|
||||
@@ -383,8 +395,16 @@ enable_vport(struct fc_vport *fc_vport)
|
||||
*/
|
||||
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);
|
||||
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
|
||||
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 {
|
||||
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
||||
}
|
||||
@@ -441,6 +461,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
|
||||
vport->load_flag |= FC_UNLOADING;
|
||||
|
||||
kfree(vport->vname);
|
||||
lpfc_debugfs_terminate(vport);
|
||||
fc_remove_host(lpfc_shost_from_vport(vport));
|
||||
scsi_remove_host(lpfc_shost_from_vport(vport));
|
||||
|
||||
@@ -476,12 +497,6 @@ skip_logo:
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user