aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h21
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c22
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c181
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c120
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c34
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c145
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c232
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c49
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c16
12 files changed, 328 insertions, 500 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ec0b0f6e5e1..e0e018d1265 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -33,6 +33,7 @@ struct lpfc_sli2_slim;
#define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
+#define LPFC_VNAME_LEN 100 /* vport symbolic name length */
/*
* Following time intervals are used of adjusting SCSI device
@@ -59,6 +60,9 @@ struct lpfc_sli2_slim;
#define MAX_HBAEVT 32
+/* lpfc wait event data ready flag */
+#define LPFC_DATA_READY (1<<0)
+
enum lpfc_polling_flags {
ENABLE_FCP_RING_POLLING = 0x1,
DISABLE_FCP_RING_INT = 0x2
@@ -425,9 +429,6 @@ struct lpfc_hba {
uint16_t pci_cfg_value;
- uint8_t work_found;
-#define LPFC_MAX_WORKER_ITERATION 4
-
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
@@ -489,8 +490,9 @@ struct lpfc_hba {
uint32_t work_hs; /* HS stored in case of ERRAT */
uint32_t work_status[2]; /* Extra status from SLIM */
- wait_queue_head_t *work_wait;
+ wait_queue_head_t work_waitq;
struct task_struct *worker_thread;
+ long data_flags;
uint32_t hbq_in_use; /* HBQs in use flag */
struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */
@@ -637,6 +639,17 @@ lpfc_is_link_up(struct lpfc_hba *phba)
phba->link_state == LPFC_HBA_READY;
}
+static inline void
+lpfc_worker_wake_up(struct lpfc_hba *phba)
+{
+ /* Set the lpfc data pending flag */
+ set_bit(LPFC_DATA_READY, &phba->data_flags);
+
+ /* Wake up worker thread */
+ wake_up(&phba->work_waitq);
+ return;
+}
+
#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
#define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature
event */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 960baaf11fb..37bfa0bd1da 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1995,8 +1995,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
/* Don't allow mailbox commands to be sent when blocked
* or when in the middle of discovery
*/
- if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO ||
- vport->fc_flag & FC_NDISC_ACTIVE) {
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
sysfs_mbox_idle(phba);
spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 7c9f8317d97..1b8245213b8 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -142,7 +142,7 @@ int lpfc_config_port_post(struct lpfc_hba *);
int lpfc_hba_down_prep(struct lpfc_hba *);
int lpfc_hba_down_post(struct lpfc_hba *);
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
-int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
+int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int);
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
int lpfc_online(struct lpfc_hba *);
void lpfc_unblock_mgmt_io(struct lpfc_hba *);
@@ -263,6 +263,7 @@ extern int lpfc_sli_mode;
extern int lpfc_enable_npiv;
int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
+int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 153afae567b..7fc74cf5823 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -101,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* Not enough posted buffers; Try posting more buffers */
phba->fc_stat.NoRcvBuf++;
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
- lpfc_post_buffer(phba, pring, 2, 1);
+ lpfc_post_buffer(phba, pring, 2);
return;
}
@@ -151,7 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
list_del(&iocbq->list);
lpfc_sli_release_iocbq(phba, iocbq);
- lpfc_post_buffer(phba, pring, i, 1);
+ lpfc_post_buffer(phba, pring, i);
}
}
}
@@ -990,7 +990,7 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return;
}
-static int
+int
lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
size_t size)
{
@@ -1679,20 +1679,18 @@ lpfc_fdmi_tmo(unsigned long ptr)
{
struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
struct lpfc_hba *phba = vport->phba;
+ uint32_t tmo_posted;
unsigned long iflag;
spin_lock_irqsave(&vport->work_port_lock, iflag);
- if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
+ tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
+ if (!tmo_posted)
vport->work_port_events |= WORKER_FDMI_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
- spin_lock_irqsave(&phba->hbalock, iflag);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(&phba->hbalock, iflag);
- }
- else
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+ return;
}
void
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 886c5f1b11d..f54e0f7eaee 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1754,29 +1754,34 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_work_evt *evtp;
+ if (!(nlp->nlp_flag & NLP_DELAY_TMO))
+ return;
spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(shost->host_lock);
del_timer_sync(&nlp->nlp_delayfunc);
nlp->nlp_last_elscmd = 0;
-
if (!list_empty(&nlp->els_retry_evt.evt_listp)) {
list_del_init(&nlp->els_retry_evt.evt_listp);
/* Decrement nlp reference count held for the delayed retry */
evtp = &nlp->els_retry_evt;
lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1);
}
-
if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
if (vport->num_disc_nodes) {
- /* Check to see if there are more
- * PLOGIs to be sent
- */
- lpfc_more_plogi(vport);
-
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* Check if there are more ADISCs to be sent */
+ lpfc_more_adisc(vport);
+ if ((vport->num_disc_nodes == 0) &&
+ (vport->fc_npr_cnt))
+ lpfc_els_disc_plogi(vport);
+ } else {
+ /* Check if there are more PLOGIs to be sent */
+ lpfc_more_plogi(vport);
+ }
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
@@ -1798,10 +1803,6 @@ lpfc_els_retry_delay(unsigned long ptr)
unsigned long flags;
struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
- ndlp = (struct lpfc_nodelist *) ptr;
- phba = ndlp->vport->phba;
- evtp = &ndlp->els_retry_evt;
-
spin_lock_irqsave(&phba->hbalock, flags);
if (!list_empty(&evtp->evt_listp)) {
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -1812,11 +1813,11 @@ lpfc_els_retry_delay(unsigned long ptr)
* count until the queued work is done
*/
evtp->evt_arg1 = lpfc_nlp_get(ndlp);
- evtp->evt = LPFC_EVT_ELS_RETRY;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
+ if (evtp->evt_arg1) {
+ evtp->evt = LPFC_EVT_ELS_RETRY;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
lpfc_worker_wake_up(phba);
-
+ }
spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
@@ -2761,10 +2762,11 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
npr = (PRLI *) pcmd;
vpd = &phba->vpd;
/*
- * If our firmware version is 3.20 or later,
- * set the following bits for FC-TAPE support.
+ * If the remote port is a target and our firmware version is 3.20 or
+ * later, set the following bits for FC-TAPE support.
*/
- if (vpd->rev.feaLevelHigh >= 0x02) {
+ if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
+ (vpd->rev.feaLevelHigh >= 0x02)) {
npr->ConfmComplAllowed = 1;
npr->Retry = 1;
npr->TaskRetryIdReq = 1;
@@ -3056,27 +3058,16 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL;
- /* Look at all nodes effected by pending RSCNs and move
- * them to NPR state.
- */
-
+ /* Move all affected nodes by pending RSCNs to NPR state. */
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp) ||
- ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
- lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
+ (ndlp->nlp_state == NLP_STE_UNUSED_NODE) ||
+ !lpfc_rscn_payload_check(vport, ndlp->nlp_DID))
continue;
-
lpfc_disc_state_machine(vport, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
-
- /*
- * Make sure NLP_DELAY_TMO is NOT running after a device
- * recovery event.
- */
- if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ NLP_EVT_DEVICE_RECOVERY);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
-
return 0;
}
@@ -3781,91 +3772,27 @@ static int
lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *fan_ndlp)
{
- struct lpfc_dmabuf *pcmd;
+ struct lpfc_hba *phba = vport->phba;
uint32_t *lp;
- IOCB_t *icmd;
- uint32_t cmd, did;
FAN *fp;
- struct lpfc_nodelist *ndlp, *next_ndlp;
- struct lpfc_hba *phba = vport->phba;
-
- /* FAN received */
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "0265 FAN received\n");
- icmd = &cmdiocb->iocb;
- did = icmd->un.elsreq64.remoteID;
- pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
- lp = (uint32_t *)pcmd->virt;
-
- cmd = *lp++;
- fp = (FAN *) lp;
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n");
+ lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+ fp = (FAN *) ++lp;
/* FAN received; Fan does not have a reply sequence */
-
- if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
+ if ((vport == phba->pport) &&
+ (vport->port_state == LPFC_LOCAL_CFG_LINK)) {
if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
- sizeof(struct lpfc_name)) != 0) ||
+ sizeof(struct lpfc_name))) ||
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
- sizeof(struct lpfc_name)) != 0)) {
- /*
- * This node has switched fabrics. FLOGI is required
- * Clean up the old rpi's
- */
-
- list_for_each_entry_safe(ndlp, next_ndlp,
- &vport->fc_nodes, nlp_listp) {
- if (!NLP_CHK_NODE_ACT(ndlp))
- continue;
- if (ndlp->nlp_state != NLP_STE_NPR_NODE)
- continue;
- if (ndlp->nlp_type & NLP_FABRIC) {
- /*
- * Clean up old Fabric, Nameserver and
- * other NLP_FABRIC logins
- */
- lpfc_drop_node(vport, ndlp);
-
- } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- /* Fail outstanding I/O now since this
- * device is marked for PLOGI
- */
- lpfc_unreg_rpi(vport, ndlp);
- }
- }
-
+ sizeof(struct lpfc_name)))) {
+ /* This port has switched fabrics. FLOGI is required */
lpfc_initial_flogi(vport);
- return 0;
- }
- /* Discovery not needed,
- * move the nodes to their original state.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
- nlp_listp) {
- if (!NLP_CHK_NODE_ACT(ndlp))
- continue;
- if (ndlp->nlp_state != NLP_STE_NPR_NODE)
- continue;
-
- switch (ndlp->nlp_prev_state) {
- case NLP_STE_UNMAPPED_NODE:
- ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(vport, ndlp,
- NLP_STE_UNMAPPED_NODE);
- break;
-
- case NLP_STE_MAPPED_NODE:
- ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(vport, ndlp,
- NLP_STE_MAPPED_NODE);
- break;
-
- default:
- break;
- }
+ } else {
+ /* FAN verified - skip FLOGI */
+ vport->fc_myDID = vport->fc_prevDID;
+ lpfc_issue_fabric_reglogin(vport);
}
-
- /* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(vport);
}
return 0;
}
@@ -3875,20 +3802,17 @@ lpfc_els_timeout(unsigned long ptr)
{
struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
struct lpfc_hba *phba = vport->phba;
+ uint32_t tmo_posted;
unsigned long iflag;
spin_lock_irqsave(&vport->work_port_lock, iflag);
- if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
+ tmo_posted = vport->work_port_events & WORKER_ELS_TMO;
+ if (!tmo_posted)
vport->work_port_events |= WORKER_ELS_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
- spin_lock_irqsave(&phba->hbalock, iflag);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(&phba->hbalock, iflag);
- }
- else
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
return;
}
@@ -3933,9 +3857,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
els_command == ELS_CMD_FDISC)
continue;
- if (vport != piocb->vport)
- continue;
-
if (piocb->drvrTimeout > 0) {
if (piocb->drvrTimeout >= timeout)
piocb->drvrTimeout -= timeout;
@@ -4089,7 +4010,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
cmd = *payload;
if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
- lpfc_post_buffer(phba, pring, 1, 1);
+ lpfc_post_buffer(phba, pring, 1);
did = icmd->un.rcvels.remoteID;
if (icmd->ulpStatus) {
@@ -4398,7 +4319,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
phba->fc_stat.NoRcvBuf++;
/* Not enough posted buffers; Try posting more buffers */
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
- lpfc_post_buffer(phba, pring, 0, 1);
+ lpfc_post_buffer(phba, pring, 0);
return;
}
@@ -4842,18 +4763,16 @@ lpfc_fabric_block_timeout(unsigned long ptr)
struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
unsigned long iflags;
uint32_t tmo_posted;
+
spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
if (!tmo_posted)
phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
- if (!tmo_posted) {
- spin_lock_irqsave(&phba->hbalock, iflags);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- }
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+ return;
}
static void
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 7cb68feb04f..a98d11bf357 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -153,11 +153,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
* count until this queued work is done
*/
evtp->evt_arg1 = lpfc_nlp_get(ndlp);
- evtp->evt = LPFC_EVT_DEV_LOSS;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
- wake_up(phba->work_wait);
-
+ if (evtp->evt_arg1) {
+ evtp->evt = LPFC_EVT_DEV_LOSS;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ lpfc_worker_wake_up(phba);
+ }
spin_unlock_irq(&phba->hbalock);
return;
@@ -276,14 +276,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
}
-
-void
-lpfc_worker_wake_up(struct lpfc_hba *phba)
-{
- wake_up(phba->work_wait);
- return;
-}
-
static void
lpfc_work_list_done(struct lpfc_hba *phba)
{
@@ -429,6 +421,8 @@ lpfc_work_done(struct lpfc_hba *phba)
|| (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
if (pring->flag & LPFC_STOP_IOCB_EVENT) {
pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ /* Set the lpfc data pending flag */
+ set_bit(LPFC_DATA_READY, &phba->data_flags);
} else {
pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
lpfc_sli_handle_slow_ring_event(phba, pring,
@@ -459,69 +453,29 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_work_list_done(phba);
}
-static int
-check_work_wait_done(struct lpfc_hba *phba)
-{
- struct lpfc_vport *vport;
- struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
- int rc = 0;
-
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry(vport, &phba->port_list, listentry) {
- if (vport->work_port_events) {
- rc = 1;
- break;
- }
- }
- if (rc || phba->work_ha || (!list_empty(&phba->work_list)) ||
- kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) {
- rc = 1;
- phba->work_found++;
- } else
- phba->work_found = 0;
- spin_unlock_irq(&phba->hbalock);
- return rc;
-}
-
-
int
lpfc_do_work(void *p)
{
struct lpfc_hba *phba = p;
int rc;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq);
set_user_nice(current, -20);
- phba->work_wait = &work_waitq;
- phba->work_found = 0;
+ phba->data_flags = 0;
while (1) {
-
- rc = wait_event_interruptible(work_waitq,
- check_work_wait_done(phba));
-
+ /* wait and check worker queue activities */
+ rc = wait_event_interruptible(phba->work_waitq,
+ (test_and_clear_bit(LPFC_DATA_READY,
+ &phba->data_flags)
+ || kthread_should_stop()));
BUG_ON(rc);
if (kthread_should_stop())
break;
+ /* Attend pending lpfc data processing */
lpfc_work_done(phba);
-
- /* If there is alot of slow ring work, like during link up
- * check_work_wait_done() may cause this thread to not give
- * up the CPU for very long periods of time. This may cause
- * soft lockups or other problems. To avoid these situations
- * give up the CPU here after LPFC_MAX_WORKER_ITERATION
- * consecutive iterations.
- */
- if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) {
- phba->work_found = 0;
- schedule();
- }
}
- spin_lock_irq(&phba->hbalock);
- phba->work_wait = NULL;
- spin_unlock_irq(&phba->hbalock);
return 0;
}
@@ -551,10 +505,10 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
spin_lock_irqsave(&phba->hbalock, flags);
list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
spin_unlock_irqrestore(&phba->hbalock, flags);
+ lpfc_worker_wake_up(phba);
+
return 1;
}
@@ -963,6 +917,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
if (phba->fc_topology == TOPOLOGY_LOOP) {
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+ if (phba->cfg_enable_npiv)
+ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+ "1309 Link Up Event npiv not supported in loop "
+ "topology\n");
/* Get Loop Map information */
if (la->il)
vport->fc_flag |= FC_LBIT;
@@ -1087,6 +1045,8 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ /* Unblock ELS traffic */
+ phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
/* Check for error */
if (mb->mbxStatus) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
@@ -1650,7 +1610,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_DID, old_state, state);
if (old_state == NLP_STE_NPR_NODE &&
- (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
state != NLP_STE_NPR_NODE)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (old_state == NLP_STE_UNMAPPED_NODE) {
@@ -1687,8 +1646,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
spin_lock_irq(shost->host_lock);
@@ -1701,8 +1659,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
static void
lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
@@ -2121,10 +2078,8 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
ndlp->nlp_last_elscmd = 0;
del_timer_sync(&ndlp->nlp_delayfunc);
- if (!list_empty(&ndlp->els_retry_evt.evt_listp))
- list_del_init(&ndlp->els_retry_evt.evt_listp);
- if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
- list_del_init(&ndlp->dev_loss_evt.evt_listp);
+ list_del_init(&ndlp->els_retry_evt.evt_listp);
+ list_del_init(&ndlp->dev_loss_evt.evt_listp);
lpfc_unreg_rpi(vport, ndlp);
@@ -2144,10 +2099,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
LPFC_MBOXQ_t *mbox;
int rc;
- if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
- }
-
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
@@ -2317,8 +2269,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
/* Since this node is marked for discovery,
* delay timeout is not needed.
*/
- if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
} else
ndlp = NULL;
} else {
@@ -2643,21 +2594,20 @@ lpfc_disc_timeout(unsigned long ptr)
{
struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
struct lpfc_hba *phba = vport->phba;
+ uint32_t tmo_posted;
unsigned long flags = 0;
if (unlikely(!phba))
return;
- if ((vport->work_port_events & WORKER_DISC_TMO) == 0) {
- spin_lock_irqsave(&vport->work_port_lock, flags);
+ spin_lock_irqsave(&vport->work_port_lock, flags);
+ tmo_posted = vport->work_port_events & WORKER_DISC_TMO;
+ if (!tmo_posted)
vport->work_port_events |= WORKER_DISC_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, flags);
+ spin_unlock_irqrestore(&vport->work_port_lock, flags);
- spin_lock_irqsave(&phba->hbalock, flags);
- if (phba->work_wait)
- lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(&phba->hbalock, flags);
- }
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index fa757b251f8..5b6e5395c8e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -145,8 +145,10 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
return -ERESTART;
}
- if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp)
+ if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) {
+ mempool_free(pmb, phba->mbox_mem_pool);
return -EINVAL;
+ }
/* Save information as VPD data */
vp->rev.rBit = 1;
@@ -551,18 +553,18 @@ static void
lpfc_hb_timeout(unsigned long ptr)
{
struct lpfc_hba *phba;
+ uint32_t tmo_posted;
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))
+ tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO;
+ if (!tmo_posted)
phba->pport->work_port_events |= WORKER_HB_TMO;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
- spin_lock_irqsave(&phba->hbalock, iflag);
- if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
return;
}
@@ -851,6 +853,8 @@ lpfc_handle_latt(struct lpfc_hba *phba)
lpfc_read_la(phba, pmb, mp);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
pmb->vport = vport;
+ /* Block ELS IOCBs until we have processed this mbox command */
+ phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT;
rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
rc = 4;
@@ -866,6 +870,7 @@ lpfc_handle_latt(struct lpfc_hba *phba)
return;
lpfc_handle_latt_free_mbuf:
+ phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
lpfc_handle_latt_free_mp:
kfree(mp);
@@ -1194,8 +1199,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
/* Returns the number of buffers NOT posted. */
/**************************************************/
int
-lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
- int type)
+lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt)
{
IOCB_t *icmd;
struct lpfc_iocbq *iocb;
@@ -1295,7 +1299,7 @@ lpfc_post_rcv_buf(struct lpfc_hba *phba)
struct lpfc_sli *psli = &phba->sli;
/* Ring 0, ELS / CT buffers */
- lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0, 1);
+ lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0);
/* Ring 2 - FCP no buffers needed */
return 0;
@@ -1454,6 +1458,15 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);
+
+ /* nlp_type zero is not defined, nlp_flag zero also not defined,
+ * nlp_state is unused, this happens when
+ * an initiator has logged
+ * into us so cleanup this ndlp.
+ */
+ if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) &&
+ (ndlp->nlp_state == 0))
+ lpfc_nlp_put(ndlp);
}
/* At this point, ALL ndlp's should be gone
@@ -2101,6 +2114,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT);
phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
+ /* Initialize the wait queue head for the kernel thread */
+ init_waitqueue_head(&phba->work_waitq);
+
/* Startup the kernel thread for this host adapter. */
phba->worker_thread = kthread_run(lpfc_do_work, phba,
"lpfc_worker_%d", phba->brd_no);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index d08c4c89074..6688a8689b5 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -235,10 +235,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
(iocb->iocb_cmpl) (phba, iocb, iocb);
}
}
-
- /* If we are delaying issuing an ELS command, cancel it */
- if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
+ lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0;
}
@@ -249,7 +246,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
- struct lpfc_work_evt *evtp;
uint32_t *lp;
IOCB_t *icmd;
struct serv_parm *sp;
@@ -425,73 +421,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp, mbox);
return 1;
}
-
- /* If the remote NPort logs into us, before we can initiate
- * discovery to them, cleanup the NPort from discovery accordingly.
- */
- if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
- spin_lock_irq(shost->host_lock);
- ndlp->nlp_flag &= ~NLP_DELAY_TMO;
- spin_unlock_irq(shost->host_lock);
- del_timer_sync(&ndlp->nlp_delayfunc);
- ndlp->nlp_last_elscmd = 0;
-
- if (!list_empty(&ndlp->els_retry_evt.evt_listp)) {
- list_del_init(&ndlp->els_retry_evt.evt_listp);
- /* Decrement ndlp reference count held for the
- * delayed retry
- */
- evtp = &ndlp->els_retry_evt;
- lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1);
- }
-
- if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- spin_lock_irq(shost->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(shost->host_lock);
-
- if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
- (vport->num_disc_nodes)) {
- /* Check to see if there are more
- * ADISCs to be sent
- */
- lpfc_more_adisc(vport);
-
- if ((vport->num_disc_nodes == 0) &&
- (vport->fc_npr_cnt))
- lpfc_els_disc_plogi(vport);
-
- if (vport->num_disc_nodes == 0) {
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(shost->host_lock);
- lpfc_can_disctmo(vport);
- lpfc_end_rscn(vport);
- }
- }
- }
- } else if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) &&
- (ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (vport->num_disc_nodes)) {
- spin_lock_irq(shost->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(shost->host_lock);
- /* Check to see if there are more
- * PLOGIs to be sent
- */
- lpfc_more_plogi(vport);
- if (vport->num_disc_nodes == 0) {
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(shost->host_lock);
- lpfc_can_disctmo(vport);
- lpfc_end_rscn(vport);
- }
- }
-
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
return 1;
-
out:
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
@@ -574,7 +505,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
else
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
- if (!(ndlp->nlp_type & NLP_FABRIC) ||
+ if ((!(ndlp->nlp_type & NLP_FABRIC) &&
+ ((ndlp->nlp_type & NLP_FCP_TARGET) ||
+ !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
/* Only try to re-login if this is NOT a Fabric Node */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
@@ -751,6 +684,7 @@ static uint32_t
lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb = arg;
struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -776,7 +710,22 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
} else {
- lpfc_rcv_plogi(vport, ndlp, cmdiocb);
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) &&
+ (ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+ (vport->num_disc_nodes)) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
+ /* Check if there are more PLOGIs to be sent */
+ lpfc_more_plogi(vport);
+ if (vport->num_disc_nodes == 0) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ lpfc_end_rscn(vport);
+ }
+ }
} /* If our portname was less */
return ndlp->nlp_state;
@@ -1040,6 +989,7 @@ static uint32_t
lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
@@ -1048,9 +998,28 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,