diff options
author | James Bottomley <jejb@mulgrave.(none)> | 2005-10-29 10:28:33 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-10-29 10:28:33 -0500 |
commit | 604a3e3042eb89ffaa4f735ef9208281aae786c7 (patch) | |
tree | 54c4ad58274b0bb79386c6c57b4849bfb92d4118 /drivers/scsi | |
parent | 21568f5387636fe2bfb9ee42383d76de11ed99c7 (diff) | |
download | linux-604a3e3042eb89ffaa4f735ef9208281aae786c7.tar.gz linux-604a3e3042eb89ffaa4f735ef9208281aae786c7.tar.bz2 linux-604a3e3042eb89ffaa4f735ef9208281aae786c7.zip |
[SCSI] lpfc: Fix for "command completion for iotax x?? not found"
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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 30 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 17 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 12 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 27 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 281 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 8 |
9 files changed, 187 insertions, 206 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index ffc58f9a5a59..25f2650f098c 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -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); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 1280f0e54636..40c34a30a94a 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -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; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 63caf7fe9725..e931ae6e7464 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -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; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index cd06d4c471ac..259eeb161b82 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -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); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e591611f98e2..59e244f04c32 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -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++; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 9a58de876d40..507a6af56f42 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -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; } } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c55ab1a630e5..51c6b677490c 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -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, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 71ff2b6a642f..a8097e6c9dce 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -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 */ diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 2d5b0670415c..5d8911de4faa 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -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 |