[SCSI] lpfc 8.2.7 : Rework the worker thread
authorJames Smart <James.Smart@Emulex.Com>
Sun, 15 Jun 2008 02:52:53 +0000 (22:52 -0400)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Sat, 12 Jul 2008 13:22:28 +0000 (08:22 -0500)
Rework of the worker thread to make it more efficient.
Make a finer-grain notfication of pending work so less time is
spent checking conditions. Also made other general cleanups.

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c

index ec0b0f6e5e1a950ea9f4436b4888f184471f9af0..e3e5b540e36c3353f420b1fd227bf2372209a2ff 100644 (file)
@@ -59,6 +59,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 +428,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 +489,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 +638,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 */
index 153afae567b5876d36f1a6978fa2fb8c03609e57..5442ce33615a04f7f8862377939504a2be1edcd0 100644 (file)
@@ -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
index d418c7c1251ee541b2d7a211282d9046d3813f33..5d69dee85a8d743c8b91867cd4fa06029864ea15 100644 (file)
@@ -1813,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;
 }
@@ -3802,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;
 }
 
@@ -4769,18 +4766,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
index f3dc19dfac5b92e95272fac3cbaadddcb4b076e8..ba4873c9e2c36f71085140c5b9938f1876af02f2 100644 (file)
@@ -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;
 }
 
@@ -2636,21 +2590,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;
 }
 
index 6fcddda58512fbc967baf2b2344e006e9d1baf35..53cedbafffba40def66ee40f9222da452ca06217 100644 (file)
@@ -551,18 +551,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;
 }
 
@@ -2104,6 +2104,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);
index 3926affaf7275c4df532ccd6f37cdc54a20bc700..1e88b7a8a4510f9a97d24c2d2faf472b0c8ad57d 100644 (file)
@@ -50,6 +50,7 @@ void
 lpfc_adjust_queue_depth(struct lpfc_hba *phba)
 {
        unsigned long flags;
+       uint32_t evt_posted;
 
        spin_lock_irqsave(&phba->hbalock, flags);
        atomic_inc(&phba->num_rsrc_err);
@@ -65,17 +66,13 @@ lpfc_adjust_queue_depth(struct lpfc_hba *phba)
        spin_unlock_irqrestore(&phba->hbalock, flags);
 
        spin_lock_irqsave(&phba->pport->work_port_lock, flags);
-       if ((phba->pport->work_port_events &
-               WORKER_RAMP_DOWN_QUEUE) == 0) {
+       evt_posted = phba->pport->work_port_events & WORKER_RAMP_DOWN_QUEUE;
+       if (!evt_posted)
                phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE;
-       }
        spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
 
-       spin_lock_irqsave(&phba->hbalock, flags);
-       if (phba->work_wait)
-               wake_up(phba->work_wait);
-       spin_unlock_irqrestore(&phba->hbalock, flags);
-
+       if (!evt_posted)
+               lpfc_worker_wake_up(phba);
        return;
 }
 
@@ -89,6 +86,7 @@ lpfc_rampup_queue_depth(struct lpfc_vport  *vport,
 {
        unsigned long flags;
        struct lpfc_hba *phba = vport->phba;
+       uint32_t evt_posted;
        atomic_inc(&phba->num_cmd_success);
 
        if (vport->cfg_lun_queue_depth <= sdev->queue_depth)
@@ -103,16 +101,14 @@ lpfc_rampup_queue_depth(struct lpfc_vport  *vport,
        spin_unlock_irqrestore(&phba->hbalock, flags);
 
        spin_lock_irqsave(&phba->pport->work_port_lock, flags);
-       if ((phba->pport->work_port_events &
-               WORKER_RAMP_UP_QUEUE) == 0) {
+       evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE;
+       if (!evt_posted)
                phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
-       }
        spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
 
-       spin_lock_irqsave(&phba->hbalock, flags);
-       if (phba->work_wait)
-               wake_up(phba->work_wait);
-       spin_unlock_irqrestore(&phba->hbalock, flags);
+       if (!evt_posted)
+               lpfc_worker_wake_up(phba);
+       return;
 }
 
 void
index 70a0a9eab21106a70cba3bef3589a1ee3261db29..3dba3a967ed1f46b1caf6522aeb38ea0f6120fa8 100644 (file)
@@ -324,9 +324,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                        phba->work_ha |= HA_ERATT;
                        phba->work_hs = HS_FFER3;
 
-                       /* hbalock should already be held */
-                       if (phba->work_wait)
-                               lpfc_worker_wake_up(phba);
+                       lpfc_worker_wake_up(phba);
 
                        return NULL;
                }
@@ -1309,9 +1307,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        phba->work_ha |= HA_ERATT;
        phba->work_hs = HS_FFER3;
 
-       /* hbalock should already be held */
-       if (phba->work_wait)
-               lpfc_worker_wake_up(phba);
+       lpfc_worker_wake_up(phba);
 
        return;
 }
@@ -2611,12 +2607,9 @@ lpfc_mbox_timeout(unsigned long ptr)
                phba->pport->work_port_events |= WORKER_MBOX_TMO;
        spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
 
-       if (!tmo_posted) {
-               spin_lock_irqsave(&phba->hbalock, iflag);
-               if (phba->work_wait)
-                       lpfc_worker_wake_up(phba);
-               spin_unlock_irqrestore(&phba->hbalock, iflag);
-       }
+       if (!tmo_posted)
+               lpfc_worker_wake_up(phba);
+       return;
 }
 
 void
@@ -3374,8 +3367,12 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
                prev_pring_flag = pring->flag;
-               if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+               /* Only slow rings */
+               if (pring->ringno == LPFC_ELS_RING) {
                        pring->flag |= LPFC_DEFERRED_RING_EVENT;
+                       /* Set the lpfc data pending flag */
+                       set_bit(LPFC_DATA_READY, &phba->data_flags);
+               }
                /*
                 * Error everything on the txq since these iocbs have not been
                 * given to the FW yet.
@@ -3434,8 +3431,12 @@ 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];
-               if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+               /* Only slow rings */
+               if (pring->ringno == LPFC_ELS_RING) {
                        pring->flag |= LPFC_DEFERRED_RING_EVENT;
+                       /* Set the lpfc data pending flag */
+                       set_bit(LPFC_DATA_READY, &phba->data_flags);
+               }
 
                /*
                 * Error everything on the txq since these iocbs have not been
@@ -4159,7 +4160,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                                                "pwork:x%x hawork:x%x wait:x%x",
                                                phba->work_ha, work_ha_copy,
                                                (uint32_t)((unsigned long)
-                                               phba->work_wait));
+                                               &phba->work_waitq));
 
                                        control &=
                                            ~(HC_R0INT_ENA << LPFC_ELS_RING);
@@ -4172,7 +4173,7 @@ lpfc_intr_handler(int irq, void *dev_id)
                                                "x%x hawork:x%x wait:x%x",
                                                phba->work_ha, work_ha_copy,
                                                (uint32_t)((unsigned long)
-                                               phba->work_wait));
+                                               &phba->work_waitq));
                                }
                                spin_unlock(&phba->hbalock);
                        }
@@ -4297,9 +4298,8 @@ send_current_mbox:
 
                spin_lock(&phba->hbalock);
                phba->work_ha |= work_ha_copy;
-               if (phba->work_wait)
-                       lpfc_worker_wake_up(phba);
                spin_unlock(&phba->hbalock);
+               lpfc_worker_wake_up(phba);
        }
 
        ha_copy &= ~(phba->work_ha_mask);