]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
[SCSI] lpfc: Fix for "command completion for iotax x?? not found"
authorJames Bottomley <jejb@mulgrave.(none)>
Sat, 29 Oct 2005 15:28:33 +0000 (10:28 -0500)
committerJames Bottomley <jejb@mulgrave.(none)>
Sat, 29 Oct 2005 15:28:33 +0000 (10:28 -0500)
From: James Smart <James.Smart@emulex.com>

There were scenarios where the error handlers could reuse an iotag
value of an active io.  Remove all possibility of this by
pre-assigning iotag resources to command resources.

Signed-off-by: James Smart <James.Smart@emulex.com>
Rejections fixed up and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/lpfc/lpfc_crtn.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_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h

index ffc58f9a5a5994e5c692adc705d196bb3f92f1db..25f2650f098ca73ac583f7ac36ce4b79188dfd23 100644 (file)
@@ -143,6 +143,8 @@ LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
 int lpfc_mem_alloc(struct lpfc_hba *);
 void lpfc_mem_free(struct lpfc_hba *);
 
+void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
 int lpfc_sli_hba_setup(struct lpfc_hba *);
 int lpfc_sli_hba_down(struct lpfc_hba *);
 int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
index 1280f0e54636806df9b36bfea2f927678731ed60..40c34a30a94a441f9c88ce57eae8eaa38d86fe07 100644 (file)
@@ -235,7 +235,6 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
 
        if (geniocb == NULL)
                return 1;
-       memset(geniocb, 0, sizeof (struct lpfc_iocbq));
 
        icmd = &geniocb->iocb;
        icmd->un.genreq64.bdl.ulpIoTag32 = 0;
@@ -279,7 +278,7 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
        geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
        spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) {
-               list_add_tail(&geniocb->list, lpfc_iocb_list);
+               lpfc_sli_release_iocbq(phba, geniocb);
                spin_unlock_irq(phba->host->host_lock);
                return 1;
        }
@@ -487,7 +486,7 @@ out:
        kfree(inp);
        kfree(bmp);
        spin_lock_irq(phba->host->host_lock);
-       list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
        spin_unlock_irq(phba->host->host_lock);
        return;
 }
@@ -526,7 +525,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        kfree(inp);
        kfree(bmp);
        spin_lock_irq(phba->host->host_lock);
-       list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
        spin_unlock_irq(phba->host->host_lock);
        return;
 }
@@ -735,7 +734,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
        kfree(inp);
        kfree(bmp);
        spin_lock_irq(phba->host->host_lock);
-       list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
        spin_unlock_irq(phba->host->host_lock);
        return;
 }
index 63caf7fe97254b0084c74808669a53443d1297a4..e931ae6e7464dca23ad5cc14967f29c6a3e6cf24 100644 (file)
@@ -122,7 +122,6 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
 
        if (elsiocb == NULL)
                return NULL;
-       memset(elsiocb, 0, sizeof (struct lpfc_iocbq));
        icmd = &elsiocb->iocb;
 
        /* fill in BDEs for command */
@@ -133,7 +132,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
                if (pcmd)
                        kfree(pcmd);
 
-               list_add_tail(&elsiocb->list, lpfc_iocb_list);
+               spin_lock_irq(phba->host->host_lock);
+               lpfc_sli_release_iocbq(phba, elsiocb);
+               spin_unlock_irq(phba->host->host_lock);
                return NULL;
        }
 
@@ -150,7 +151,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
                                kfree(prsp);
                        lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
                        kfree(pcmd);
-                       list_add_tail(&elsiocb->list, lpfc_iocb_list);
+                       spin_lock_irq(phba->host->host_lock);
+                       lpfc_sli_release_iocbq(phba, elsiocb);
+                       spin_unlock_irq(phba->host->host_lock);
                        return NULL;
                }
                INIT_LIST_HEAD(&prsp->list);
@@ -164,7 +167,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
            pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                             &pbuflist->phys);
        if (pbuflist == 0 || pbuflist->virt == 0) {
-               list_add_tail(&elsiocb->list, lpfc_iocb_list);
+               spin_lock_irq(phba->host->host_lock);
+               lpfc_sli_release_iocbq(phba, elsiocb);
+               spin_unlock_irq(phba->host->host_lock);
                lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
                lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
                kfree(pcmd);
@@ -596,10 +601,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
                                        spin_unlock_irq(phba->host->host_lock);
                                        (iocb->iocb_cmpl) (phba, iocb, iocb);
                                        spin_lock_irq(phba->host->host_lock);
-                               } else {
-                                       list_add_tail(&iocb->list,
-                                                     &phba->lpfc_iocb_list);
-                               }
+                               } else
+                                       lpfc_sli_release_iocbq(phba, iocb);
                        }
                }
        }
@@ -1713,7 +1716,7 @@ lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
                kfree(buf_ptr);
        }
        spin_lock_irq(phba->host->host_lock);
-       list_add_tail(&elsiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, elsiocb);
        spin_unlock_irq(phba->host->host_lock);
        return 0;
 }
@@ -2929,9 +2932,8 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                        spin_unlock_irq(phba->host->host_lock);
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
                        spin_lock_irq(phba->host->host_lock);
-               } else {
-                       list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
-               }
+               } else
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
        if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
                phba->els_tmofunc.expires = jiffies + HZ * timeout;
@@ -2996,7 +2998,7 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                        spin_lock_irq(phba->host->host_lock);
                }
                else
-                       list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3033,7 +3035,7 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                        spin_lock_irq(phba->host->host_lock);
                }
                else
-                       list_add_tail(&piocb->list, &phba->lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
        spin_unlock_irq(phba->host->host_lock);
        return;
index cd06d4c471ac18089700f5f15685272342f09c0d..259eeb161b82ce0e3ac55f706150c653f39a5bbe 100644 (file)
@@ -1445,10 +1445,9 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                                                                   iocb, iocb);
                                                spin_lock_irq(phba->host->
                                                              host_lock);
-                                       } else {
-                                               list_add_tail(&iocb->list,
-                                                       &phba->lpfc_iocb_list);
-                                       }
+                                       } else
+                                               lpfc_sli_release_iocbq(phba,
+                                                                      iocb);
                                }
                        }
                        spin_unlock_irq(phba->host->host_lock);
index e591611f98e21a490e8701ad1a61bf6ebda4ac0a..59e244f04c328c24d355812ca229d8473a0253ef 100644 (file)
@@ -886,7 +886,6 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                        pring->missbufcnt = cnt;
                        return cnt;
                }
-               memset(iocb, 0, sizeof (struct lpfc_iocbq));
                icmd = &iocb->iocb;
 
                /* 2 buffers can be posted per command */
@@ -899,7 +898,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                        if (mp1)
                                kfree(mp1);
                        spin_lock_irq(phba->host->host_lock);
-                       list_add_tail(&iocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, iocb);
                        spin_unlock_irq(phba->host->host_lock);
                        pring->missbufcnt = cnt;
                        return cnt;
@@ -918,7 +917,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                                lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
                                kfree(mp1);
                                spin_lock_irq(phba->host->host_lock);
-                               list_add_tail(&iocb->list, lpfc_iocb_list);
+                               lpfc_sli_release_iocbq(phba, iocb);
                                spin_unlock_irq(phba->host->host_lock);
                                pring->missbufcnt = cnt;
                                return cnt;
@@ -955,7 +954,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
                                kfree(mp2);
                                cnt++;
                        }
-                       list_add_tail(&iocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, iocb);
                        pring->missbufcnt = cnt;
                        spin_unlock_irq(phba->host->host_lock);
                        return cnt;
@@ -1328,6 +1327,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        unsigned long bar0map_len, bar2map_len;
        int error = -ENODEV, retval;
        int i;
+       uint16_t iotag;
 
        if (pci_enable_device(pdev))
                goto out;
@@ -1452,6 +1452,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                }
 
                memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
+               iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
+               if (iotag == 0) {
+                       kfree (iocbq_entry);
+                       printk(KERN_ERR "%s: failed to allocate IOTAG. "
+                              "Unloading driver.\n",
+                               __FUNCTION__);
+                       error = -ENOMEM;
+                       goto out_free_iocbq;
+               }
                spin_lock_irq(phba->host->host_lock);
                list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
                phba->total_iocbq_bufs++;
index 9a58de876d40e0853178a4753714db6a12af2a74..507a6af56f42d51ad52687a2f15889aca267729a 100644 (file)
@@ -187,10 +187,8 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
                                        spin_unlock_irq(phba->host->host_lock);
                                        (iocb->iocb_cmpl) (phba, iocb, iocb);
                                        spin_lock_irq(phba->host->host_lock);
-                               } else {
-                                       list_add_tail(&iocb->list,
-                                                       &phba->lpfc_iocb_list);
-                               }
+                               } else
+                                       lpfc_sli_release_iocbq(phba, iocb);
                                break;
                        }
                }
@@ -232,10 +230,8 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
                                        spin_unlock_irq(phba->host->host_lock);
                                        (iocb->iocb_cmpl) (phba, iocb, iocb);
                                        spin_lock_irq(phba->host->host_lock);
-                               } else {
-                                       list_add_tail(&iocb->list,
-                                                       &phba->lpfc_iocb_list);
-                               }
+                               } else
+                                       lpfc_sli_release_iocbq(phba, iocb);
                                break;
                        }
                }
index c55ab1a630e5ddf24c32f72edf2b526c3538e0a2..51c6b677490cfac5676443f19d2dae22a67ed37c 100644 (file)
@@ -56,6 +56,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
        struct ulp_bde64 *bpl;
        IOCB_t *iocb;
        dma_addr_t pdma_phys;
+       uint16_t iotag;
 
        psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
        if (!psb)
@@ -79,6 +80,15 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
        /* Initialize virtual ptrs to dma_buf region. */
        memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
 
+       /* Allocate iotag for psb->cur_iocbq. */
+       iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
+       if (iotag == 0) {
+               pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+                             psb->data, psb->dma_handle);
+               kfree (psb);
+               return NULL;
+       }
+
        psb->fcp_cmnd = psb->data;
        psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
        psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) +
@@ -626,7 +636,6 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
        list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list);
        if (!iocbqrsp)
                return FAILED;
-       memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq));
 
        iocbq->iocb_flag |= LPFC_IO_POLL;
        ret = lpfc_sli_issue_iocb_wait_high_priority(phba,
@@ -655,8 +664,7 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
                            lpfc_cmd->pCmd->device->id,
                            lpfc_cmd->pCmd->device->lun, 0, LPFC_CTX_TGT);
 
-       /* Return response IOCB to free list. */
-       list_add_tail(&iocbqrsp->list, lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, iocbqrsp);
        return ret;
 }
 
@@ -818,9 +826,8 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd)
 
                list_del_init(&iocb->list);
                pring->txq_cnt--;
-               if (!iocb->iocb_cmpl) {
-                       list_add_tail(&iocb->list, lpfc_iocb_list);
-               }
+               if (!iocb->iocb_cmpl)
+                       lpfc_sli_release_iocbq(phba, iocb);
                else {
                        cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
                        cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
@@ -834,8 +841,6 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd)
        if (abtsiocb == NULL)
                return FAILED;
 
-       memset(abtsiocb, 0, sizeof (struct lpfc_iocbq));
-
        /*
         * The scsi command was not in the txq.  Check the txcmplq and if it is
         * found, send an abort to the FW.
@@ -861,7 +866,7 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd)
                abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
                if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) ==
                                                                IOCB_ERROR) {
-                       list_add_tail(&abtsiocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, abtsiocb);
                        ret = IOCB_ERROR;
                        break;
                }
@@ -964,8 +969,6 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
        if (iocbqrsp == NULL)
                goto out_free_scsi_buf;
 
-       memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq));
-
        iocbq->iocb_flag |= LPFC_IO_POLL;
        iocbq->iocb_cmpl = lpfc_sli_wake_iocb_high_priority;
 
@@ -1011,7 +1014,7 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
                        phba->brd_no, cnt);
        }
 
-       list_add_tail(&iocbqrsp->list, lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, iocbqrsp);
 
 out_free_scsi_buf:
        lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
index 71ff2b6a642f4d458cd2adec2368f3c961191a65..a8097e6c9dceb80e3749a829c837ef12d13d7d0a 100644 (file)
@@ -65,6 +65,18 @@ typedef enum _lpfc_iocb_type {
        LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
+void
+lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
+{
+       size_t start_clean = (size_t)(&((struct lpfc_iocbq *)NULL)->iocb);
+
+       /*
+        * Clean all volatile data fields, preserve iotag and node struct.
+        */
+       memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
+       list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
+}
+
 /*
  * Translate the iocb command to an iocb command type used to decide the final
  * disposition of each completed IOCB.
@@ -265,41 +277,69 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        return iocb;
 }
 
-static uint32_t
-lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+uint16_t
+lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
 {
-       uint32_t search_start;
+       struct lpfc_iocbq ** new_arr;
+       struct lpfc_iocbq ** old_arr;
+       size_t new_len;
+       struct lpfc_sli *psli = &phba->sli;
+       uint16_t iotag;
 
-       if (pring->fast_lookup == NULL) {
-               pring->iotag_ctr++;
-               if (pring->iotag_ctr >= pring->iotag_max)
-                       pring->iotag_ctr = 1;
-               return pring->iotag_ctr;
+       spin_lock_irq(phba->host->host_lock);
+       iotag = psli->last_iotag;
+       if(++iotag < psli->iocbq_lookup_len) {
+               psli->last_iotag = iotag;
+               psli->iocbq_lookup[iotag] = iocbq;
+               spin_unlock_irq(phba->host->host_lock);
+               iocbq->iotag = iotag;
+               return iotag;
+       }
+       else if (psli->iocbq_lookup_len < (0xffff
+                                          - LPFC_IOCBQ_LOOKUP_INCREMENT)) {
+               new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT;
+               spin_unlock_irq(phba->host->host_lock);
+               new_arr = kmalloc(new_len * sizeof (struct lpfc_iocbq *),
+                                 GFP_KERNEL);
+               if (new_arr) {
+                       memset((char *)new_arr, 0,
+                              new_len * sizeof (struct lpfc_iocbq *));
+                       spin_lock_irq(phba->host->host_lock);
+                       old_arr = psli->iocbq_lookup;
+                       if (new_len <= psli->iocbq_lookup_len) {
+                               /* highly unprobable case */
+                               kfree(new_arr);
+                               iotag = psli->last_iotag;
+                               if(++iotag < psli->iocbq_lookup_len) {
+                                       psli->last_iotag = iotag;
+                                       psli->iocbq_lookup[iotag] = iocbq;
+                                       spin_unlock_irq(phba->host->host_lock);
+                                       iocbq->iotag = iotag;
+                                       return iotag;
+                               }
+                               spin_unlock_irq(phba->host->host_lock);
+                               return 0;
+                       }
+                       if (psli->iocbq_lookup)
+                               memcpy(new_arr, old_arr,
+                                      ((psli->last_iotag  + 1) *
+                                       sizeof (struct lpfc_iocbq *)));
+                       psli->iocbq_lookup = new_arr;
+                       psli->iocbq_lookup_len = new_len;
+                       psli->last_iotag = iotag;
+                       psli->iocbq_lookup[iotag] = iocbq;
+                       spin_unlock_irq(phba->host->host_lock);
+                       iocbq->iotag = iotag;
+                       kfree(old_arr);
+                       return iotag;
+               }
        }
 
-       search_start = pring->iotag_ctr;
-
-       do {
-               pring->iotag_ctr++;
-               if (pring->iotag_ctr >= pring->fast_iotag)
-                       pring->iotag_ctr = 1;
-
-               if (*(pring->fast_lookup + pring->iotag_ctr) == NULL)
-                       return pring->iotag_ctr;
-
-       } while (pring->iotag_ctr != search_start);
+       lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
+                       "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
+                       phba->brd_no, psli->last_iotag);
 
-       /*
-        * Outstanding I/O count for ring <ringno> is at max <fast_iotag>
-        */
-       lpfc_printf_log(phba,
-               KERN_ERR,
-               LOG_SLI,
-               "%d:0318 Outstanding I/O count for ring %d is at max x%x\n",
-               phba->brd_no,
-               pring->ringno,
-               pring->fast_iotag);
-       return (0);
+       return 0;
 }
 
 static void
@@ -307,10 +347,9 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
 {
        /*
-        * Allocate and set up an iotag
+        * Set up an iotag
         */
-       nextiocb->iocb.ulpIoTag =
-               lpfc_sli_next_iotag(phba, &phba->sli.ring[phba->sli.fcp_ring]);
+       nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0;
 
        /*
         * Issue iocb command to adapter
@@ -326,9 +365,8 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
         */
        if (nextiocb->iocb_cmpl)
                lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
-       else {
-               list_add_tail(&nextiocb->list, &phba->lpfc_iocb_list);
-       }
+       else
+               lpfc_sli_release_iocbq(phba, nextiocb);
 
        /*
         * Let the HBA know what IOCB slot will be the next one the
@@ -752,80 +790,28 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 }
 
 static struct lpfc_iocbq *
-lpfc_sli_txcmpl_ring_search_slow(struct lpfc_sli_ring * pring,
-                                struct lpfc_iocbq * prspiocb)
+lpfc_sli_iocbq_lookup(struct lpfc_hba * phba,
+                     struct lpfc_sli_ring * pring,
+                     struct lpfc_iocbq * prspiocb)
 {
-       IOCB_t *icmd = NULL;
-       IOCB_t *irsp = NULL;
-       struct lpfc_iocbq *cmd_iocb;
-       struct lpfc_iocbq *iocb, *next_iocb;
-       uint16_t iotag;
-
-       irsp = &prspiocb->iocb;
-       iotag = irsp->ulpIoTag;
-       cmd_iocb = NULL;
-
-       /* Search through txcmpl from the begining */
-       list_for_each_entry_safe(iocb, next_iocb, &(pring->txcmplq), list) {
-               icmd = &iocb->iocb;
-               if (iotag == icmd->ulpIoTag) {
-                       /* Found a match.  */
-                       cmd_iocb = iocb;
-                       list_del(&iocb->list);
-                       pring->txcmplq_cnt--;
-                       break;
-               }
-       }
-
-       return (cmd_iocb);
-}
-
-static struct lpfc_iocbq *
-lpfc_sli_txcmpl_ring_iotag_lookup(struct lpfc_hba * phba,
-                       struct lpfc_sli_ring * pring,
-                       struct lpfc_iocbq * prspiocb)
-{
-       IOCB_t *irsp = NULL;
        struct lpfc_iocbq *cmd_iocb = NULL;
        uint16_t iotag;
 
-       if (unlikely(pring->fast_lookup == NULL))
-               return NULL;
-
-       /* Use fast lookup based on iotag for completion */
-       irsp = &prspiocb->iocb;
-       iotag = irsp->ulpIoTag;
-       if (iotag < pring->fast_iotag) {
-               cmd_iocb = *(pring->fast_lookup + iotag);
-               *(pring->fast_lookup + iotag) = NULL;
-               if (cmd_iocb) {
-                       list_del(&cmd_iocb->list);
-                       pring->txcmplq_cnt--;
-                       return cmd_iocb;
-               } else {
-                       /*
-                        * This is clearly an error.  A ring that uses iotags
-                        * should never have a interrupt for a completion that
-                        * is not on the ring.  Return NULL and log a error.
-                        */
-                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                               "%d:0327 Rsp ring %d error -  command "
-                               "completion for iotag x%x not found\n",
-                               phba->brd_no, pring->ringno, iotag);
-                       return NULL;
-               }
+       iotag = prspiocb->iocb.ulpIoTag;
+
+       if (iotag != 0 && iotag <= phba->sli.last_iotag) {
+               cmd_iocb = phba->sli.iocbq_lookup[iotag];
+               list_del(&cmd_iocb->list);
+               pring->txcmplq_cnt--;
+               return cmd_iocb;
        }
 
-       /*
-        * Rsp ring <ringno> get: iotag <iotag> greater then
-        * configured max <fast_iotag> wd0 <irsp>.  This is an
-        * error.  Just return NULL.
-        */
        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                       "%d:0317 Rsp ring %d get: iotag x%x greater then "
-                       "configured max x%x wd0 x%x\n",
-                       phba->brd_no, pring->ringno, iotag, pring->fast_iotag,
-                       *(((uint32_t *) irsp) + 7));
+                       "%d:0317 iotag x%x is out off "
+                       "range: max iotag x%x wd0 x%x\n",
+                       phba->brd_no, iotag,
+                       phba->sli.last_iotag,
+                       *(((uint32_t *) &prspiocb->iocb) + 7));
        return NULL;
 }
 
@@ -839,7 +825,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
 
        /* Based on the iotag field, get the cmd IOCB from the txcmplq */
        spin_lock_irqsave(phba->host->host_lock, iflag);
-       cmdiocbp = lpfc_sli_txcmpl_ring_search_slow(pring, saveq);
+       cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
        if (cmdiocbp) {
                if (cmdiocbp->iocb_cmpl) {
                        /*
@@ -861,9 +847,8 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
                                (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
                                spin_lock_irqsave(phba->host->host_lock, iflag);
                        }
-               } else {
-                       list_add_tail(&cmdiocbp->list, &phba->lpfc_iocb_list);
-               }
+               } else
+                       lpfc_sli_release_iocbq(phba, cmdiocbp);
        } else {
                /*
                 * Unknown initiating command based on the response iotag.
@@ -990,9 +975,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                                break;
                        }
 
-                       cmdiocbq = lpfc_sli_txcmpl_ring_iotag_lookup(phba,
-                                                               pring,
-                                                               &rspiocbq);
+                       cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
+                                                        &rspiocbq);
                        if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
                                spin_unlock_irqrestore(
                                       phba->host->host_lock, iflag);
@@ -1213,8 +1197,8 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                        } else if (type == LPFC_ABORT_IOCB) {
                                if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
                                    ((cmdiocbp =
-                                     lpfc_sli_txcmpl_ring_search_slow(pring,
-                                               saveq)))) {
+                                     lpfc_sli_iocbq_lookup(phba, pring,
+                                                           saveq)))) {
                                        /* Call the specified completion
                                           routine */
                                        if (cmdiocbp->iocb_cmpl) {
@@ -1226,10 +1210,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                                                spin_lock_irqsave(
                                                          phba->host->host_lock,
                                                          iflag);
-                                       } else {
-                                               list_add_tail(&cmdiocbp->list,
-                                                               lpfc_iocb_list);
-                                       }
+                                       } else
+                                               lpfc_sli_release_iocbq(phba,
+                                                                     cmdiocbp);
                                }
                        } else if (type == LPFC_UNKNOWN_IOCB) {
                                if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
@@ -1264,12 +1247,12 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
                                                                 next_iocb,
                                                                 &saveq->list,
                                                                 list) {
-                                               list_add_tail(&rspiocbp->list,
-                                                             lpfc_iocb_list);
+                                               lpfc_sli_release_iocbq(phba,
+                                                                    rspiocbp);
                                        }
                                }
 
-                               list_add_tail(&saveq->list, lpfc_iocb_list);
+                               lpfc_sli_release_iocbq(phba, saveq);
                        }
                }
 
@@ -1314,7 +1297,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
        struct lpfc_iocbq *iocb, *next_iocb;
        IOCB_t *icmd = NULL, *cmd = NULL;
        int errcnt;
-       uint16_t iotag;
 
        errcnt = 0;
 
@@ -1331,9 +1313,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                        spin_unlock_irq(phba->host->host_lock);
                        (iocb->iocb_cmpl) (phba, iocb, iocb);
                        spin_lock_irq(phba->host->host_lock);
-               } else {
-                       list_add_tail(&iocb->list, &phba->lpfc_iocb_list);
-               }
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
        pring->txq_cnt = 0;
        INIT_LIST_HEAD(&(pring->txq));
@@ -1343,13 +1324,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                cmd = &iocb->iocb;
 
                /*
-                * Imediate abort of IOCB, clear fast_lookup entry,
-                * if any, deque and call compl
+                * Imediate abort of IOCB, deque and call compl
                 */
-               iotag = cmd->ulpIoTag;
-               if (iotag && pring->fast_lookup &&
-                   (iotag < pring->fast_iotag))
-                       pring->fast_lookup[iotag] = NULL;
 
                list_del_init(&iocb->list);
                pring->txcmplq_cnt--;
@@ -1360,9 +1336,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
                        spin_unlock_irq(phba->host->host_lock);
                        (iocb->iocb_cmpl) (phba, iocb, iocb);
                        spin_lock_irq(phba->host->host_lock);
-               } else {
-                       list_add_tail(&iocb->list, &phba->lpfc_iocb_list);
-               }
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
 
        INIT_LIST_HEAD(&pring->txcmplq);
@@ -2147,6 +2122,10 @@ lpfc_sli_setup(struct lpfc_hba *phba)
        psli->next_ring = LPFC_FCP_NEXT_RING;
        psli->ip_ring = LPFC_IP_RING;
 
+       psli->iocbq_lookup = NULL;
+       psli->iocbq_lookup_len = 0;
+       psli->last_iotag = 0;
+
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
                switch (i) {
@@ -2222,7 +2201,7 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
 {
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
-       int i, cnt;
+       int i;
 
        psli = &phba->sli;
        spin_lock_irq(phba->host->host_lock);
@@ -2238,19 +2217,6 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
                INIT_LIST_HEAD(&pring->txcmplq);
                INIT_LIST_HEAD(&pring->iocb_continueq);
                INIT_LIST_HEAD(&pring->postbufq);
-               cnt = pring->fast_iotag;
-               spin_unlock_irq(phba->host->host_lock);
-               if (cnt) {
-                       pring->fast_lookup =
-                               kmalloc(cnt * sizeof (struct lpfc_iocbq *),
-                                       GFP_KERNEL);
-                       if (pring->fast_lookup == 0) {
-                               return (0);
-                       }
-                       memset((char *)pring->fast_lookup, 0,
-                              cnt * sizeof (struct lpfc_iocbq *));
-               }
-               spin_lock_irq(phba->host->host_lock);
        }
        spin_unlock_irq(phba->host->host_lock);
        return (1);
@@ -2292,10 +2258,8 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
                                                       flags);
                                (iocb->iocb_cmpl) (phba, iocb, iocb);
                                spin_lock_irqsave(phba->host->host_lock, flags);
-                       } else {
-                               list_add_tail(&iocb->list,
-                                             &phba->lpfc_iocb_list);
-                       }
+                       } else
+                               lpfc_sli_release_iocbq(phba, iocb);
                }
 
                INIT_LIST_HEAD(&(pring->txq));
@@ -2436,7 +2400,7 @@ lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                kfree(buf_ptr);
        }
 
-       list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
        return;
 }
 
@@ -2454,7 +2418,6 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
        list_remove_head(lpfc_iocb_list, abtsiocbp, struct lpfc_iocbq, list);
        if (abtsiocbp == NULL)
                return 0;
-       memset(abtsiocbp, 0, sizeof (struct lpfc_iocbq));
 
        iabt = &abtsiocbp->iocb;
        icmd = &cmdiocb->iocb;
@@ -2473,7 +2436,7 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
                abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
                break;
        default:
-               list_add_tail(&abtsiocbp->list, lpfc_iocb_list);
+               lpfc_sli_release_iocbq(phba, abtsiocbp);
                return 0;
        }
 
@@ -2485,7 +2448,7 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
        iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
 
        if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
-               list_add_tail(&abtsiocbp->list, lpfc_iocb_list);
+               lpfc_sli_release_iocbq(phba, abtsiocbp);
                return 0;
        }
 
@@ -2563,7 +2526,7 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                           struct lpfc_iocbq * rspiocb)
 {
        spin_lock_irq(phba->host->host_lock);
-       list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
        spin_unlock_irq(phba->host->host_lock);
        return;
 }
@@ -2604,7 +2567,6 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        errcnt++;
                        continue;
                }
-               memset(abtsiocb, 0, sizeof (struct lpfc_iocbq));
 
                abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
                abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
@@ -2621,7 +2583,7 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
                ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0);
                if (ret_val == IOCB_ERROR) {
-                       list_add_tail(&abtsiocb->list, lpfc_iocb_list);
+                       lpfc_sli_release_iocbq(phba, abtsiocb);
                        errcnt++;
                        continue;
                }
@@ -2635,8 +2597,9 @@ lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba,
                                 struct lpfc_iocbq * queue1,
                                 struct lpfc_iocbq * queue2)
 {
-       if (queue1->context2 && queue2)
-               memcpy(queue1->context2, queue2, sizeof (struct lpfc_iocbq));
+       struct lpfc_iocbq *save_iocbq = queue1->context2;
+       if (save_iocbq && queue2)
+               memcpy(&save_iocbq->iocb, &queue2->iocb, sizeof(queue2->iocb));
 
        /* The waiter is looking for LPFC_IO_HIPRI bit to be set
           as a signal to wake up */
index 2d5b0670415c4d5e08d81a6d84367137b19befac..5d8911de4faa5db33c53251a4fc980f09d2a31e2 100644 (file)
@@ -33,6 +33,9 @@ typedef enum _lpfc_ctx_cmd {
 struct lpfc_iocbq {
        /* lpfc_iocbqs are used in double linked lists */
        struct list_head list;
+       uint16_t iotag;         /* pre-assigned IO tag */
+       uint16_t rsvd1;
+
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
        uint8_t iocb_flag;
@@ -200,6 +203,11 @@ struct lpfc_sli {
                                           cmd */
 
        uint32_t *MBhostaddr;   /* virtual address for mbox cmds */
+
+#define LPFC_IOCBQ_LOOKUP_INCREMENT  1024
+       struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */
+       size_t iocbq_lookup_len;           /* current lengs of the array */
+       uint16_t  last_iotag;              /* last allocated IOTAG */
 };
 
 /* Given a pointer to the start of the ring, and the slot number of