From ed957684294618602b48f1950b0c9bbcb036583f Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:37 -0500 Subject: [SCSI] lpfc: NPIV: add SLI-3 interface NPIV support is only available via new adapter interface extensions, termed SLI-3. This interface changes some of the basic behaviors such as command and response ring element sizes and data structures, as well as a change in buffer posting. Note: the new firmware extensions are found only on our mid-range and enterprise 4Gig adapters - so NPIV support is available only on these newer adapters. The latest firmware can be downloaded from the Emulex support page. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 35 +- drivers/scsi/lpfc/lpfc_crtn.h | 14 + drivers/scsi/lpfc/lpfc_ct.c | 183 ++++++---- drivers/scsi/lpfc/lpfc_els.c | 273 ++++++++------- drivers/scsi/lpfc/lpfc_hbadisc.c | 79 ++--- drivers/scsi/lpfc/lpfc_hw.h | 397 +++++++++++++++++++-- drivers/scsi/lpfc/lpfc_init.c | 68 ++-- drivers/scsi/lpfc/lpfc_mbox.c | 176 +++++++++- drivers/scsi/lpfc/lpfc_mem.c | 29 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 36 +- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 698 ++++++++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_sli.h | 25 ++ drivers/scsi/lpfc/lpfc_version.h | 2 +- 14 files changed, 1522 insertions(+), 495 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8d718964f28..74f4d18842c 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -63,6 +63,11 @@ struct lpfc_dma_pool { uint32_t current_count; }; +struct hbq_dmabuf { + struct lpfc_dmabuf dbuf; + uint32_t tag; +}; + /* Priority bit. Set value to exceed low water mark in lpfc_mem. */ #define MEM_PRI 0x100 @@ -276,8 +281,25 @@ struct lpfc_vport { }; + +struct hbq_s { + uint16_t entry_count; /* Current number of HBQ slots */ + uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ + uint32_t hbqPutIdx; /* HBQ slot to use */ + uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ +}; + +#define MAX_HBQS 16 + struct lpfc_hba { struct lpfc_sli sli; + uint32_t sli_rev; /* SLI2 or SLI3 */ + uint32_t sli3_options; /* Mask of enabled SLI3 options */ +#define LPFC_SLI3_ENABLED 0x01 +#define LPFC_SLI3_HBQ_ENABLED 0x02 +#define LPFC_SLI3_INB_ENABLED 0x04 + uint32_t iocb_cmd_size; + uint32_t iocb_rsp_size; enum hba_state link_state; uint32_t link_flag; /* link state flags */ @@ -286,8 +308,6 @@ struct lpfc_hba { /* INIT_LINK mailbox command */ #define LS_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */ - uint32_t pgpOffset; /* PGP offset within host memory */ - struct lpfc_sli2_slim *slim2p; struct lpfc_dmabuf hbqslimp; @@ -371,6 +391,12 @@ struct lpfc_hba { wait_queue_head_t *work_wait; struct task_struct *worker_thread; + struct hbq_dmabuf *hbq_buffer_pool; + uint32_t hbq_buffer_count; + uint32_t hbq_buff_count; /* Current hbq buffers */ + uint32_t hbq_count; /* Count of configured HBQs */ + struct hbq_s hbqs[MAX_HBQS]; /* local copy of hbq indicies */ + unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ void __iomem *slim_memmap_p; /* Kernel memory mapped address for @@ -385,6 +411,10 @@ struct lpfc_hba { reg */ void __iomem *HCregaddr; /* virtual address for host ctl reg */ + struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */ + uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */ + uint32_t __iomem *hbq_get; /* Address in SLIM to HBQ get ptrs */ + int brd_no; /* FC board number */ char SerialNumber[32]; /* adapter Serial Number */ @@ -425,6 +455,7 @@ struct lpfc_hba { /* pci_mem_pools */ struct pci_pool *lpfc_scsi_dma_buf_pool; struct pci_pool *lpfc_mbuf_pool; + struct pci_pool *lpfc_hbq_pool; struct lpfc_dma_pool lpfc_mbuf_safety_pool; mempool_t *mbox_mem_pool; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 0081cffd928..77693072705 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -138,6 +138,10 @@ void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); int lpfc_mbox_tmo_val(struct lpfc_hba *, int); +void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t , + LPFC_MBOXQ_t *); +struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t); + int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); @@ -172,6 +176,12 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); +int lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *); +void lpfc_sli_hbqbuf_free(struct lpfc_hba *, void *, dma_addr_t); +void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); +struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t); +void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); +int lpfc_sli_hbq_size(void); int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, @@ -198,6 +208,9 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb); +void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *); +void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t); + void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *); void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); @@ -213,6 +226,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); extern struct class_device_attribute *lpfc_hba_attrs[]; extern struct scsi_host_template lpfc_template; extern struct fc_function_template lpfc_transport_functions; +extern int lpfc_sli_mode; void lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp); void lpfc_terminate_rport_io(struct fc_rport *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index dc25a53524c..e8ed5d7ccf9 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -58,25 +58,66 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION; /* * lpfc_ct_unsol_event */ +static void +lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_dmabuf *mp, uint32_t size) +{ + if (!mp) { + printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, " + "piocbq = %p, status = x%x, mp = %p, size = %d\n", + __FUNCTION__, __LINE__, + piocbq, piocbq->iocb.ulpStatus, mp, size); + } + + printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, " + "buffer = %p, size = %d, status = x%x\n", + __FUNCTION__, __LINE__, + piocbq, mp, size, + piocbq->iocb.ulpStatus); +} + +static void +lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct hbq_dmabuf *sp, uint32_t size) +{ + struct lpfc_dmabuf *mp = NULL; + + mp = sp ? &sp->dbuf : NULL; + if (!mp) { + printk(KERN_ERR "%s (%d): Unsolited CT, no " + "HBQ buffer, piocbq = %p, status = x%x\n", + __FUNCTION__, __LINE__, + piocbq, piocbq->iocb.ulpStatus); + } else { + lpfc_ct_unsol_buffer(phba, piocbq, mp, size); + printk(KERN_ERR "%s (%d): Ignoring unsolicted CT " + "piocbq = %p, buffer = %p, size = %d, " + "status = x%x\n", + __FUNCTION__, __LINE__, + piocbq, mp, size, piocbq->iocb.ulpStatus); + } +} + void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) { - - struct lpfc_iocbq *next_piocbq; - struct lpfc_dmabuf *pmbuf = NULL; - struct lpfc_dmabuf *matp = NULL, *next_matp; - uint32_t ctx = 0, size = 0, cnt = 0; + struct lpfc_dmabuf *mp = NULL; + struct hbq_dmabuf *sp = NULL; IOCB_t *icmd = &piocbq->iocb; - IOCB_t *save_icmd = icmd; - int i, go_exit = 0; - struct list_head head; + int i; + struct lpfc_iocbq *iocbq; + dma_addr_t paddr; + uint32_t size; if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { /* Not enough posted buffers; Try posting more buffers */ phba->fc_stat.NoRcvBuf++; - lpfc_post_buffer(phba, pring, 0, 1); + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + lpfc_sli_hbqbuf_fill_hbq(phba); + else + lpfc_post_buffer(phba, pring, 0, 1); return; } @@ -86,62 +127,62 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (icmd->ulpBdeCount == 0) return; - INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); - - list_for_each_entry_safe(piocbq, next_piocbq, &head, list) { - icmd = &piocbq->iocb; - if (ctx == 0) - ctx = (uint32_t) (icmd->ulpContext); - if (icmd->ulpBdeCount == 0) - continue; - - for (i = 0; i < icmd->ulpBdeCount; i++) { - matp = lpfc_sli_ringpostbuf_get(phba, pring, - getPaddr(icmd->un. - cont64[i]. - addrHigh, - icmd->un. - cont64[i]. - addrLow)); - if (!matp) { - /* Insert lpfc log message here */ - lpfc_post_buffer(phba, pring, cnt, 1); - go_exit = 1; - goto ct_unsol_event_exit_piocbq; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + list_for_each_entry(iocbq, &piocbq->list, list) { + icmd = &iocbq->iocb; + if (icmd->ulpBdeCount == 0) { + printk(KERN_ERR "%s (%d): Unsolited CT, no " + "BDE, iocbq = %p, status = x%x\n", + __FUNCTION__, __LINE__, + iocbq, iocbq->iocb.ulpStatus); + continue; } - /* Typically for Unsolicited CT requests */ - if (!pmbuf) { - pmbuf = matp; - INIT_LIST_HEAD(&pmbuf->list); - } else - list_add_tail(&matp->list, &pmbuf->list); + size = icmd->un.cont64[0].tus.f.bdeSize; + sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]); + if (sp) + phba->hbq_buff_count--; + lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, size); + lpfc_sli_free_hbq(phba, sp); + if (icmd->ulpBdeCount == 2) { + sp = lpfc_sli_hbqbuf_find(phba, + icmd->un.ulpWord[15]); + if (sp) + phba->hbq_buff_count--; + lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, + size); + lpfc_sli_free_hbq(phba, sp); + } - size += icmd->un.cont64[i].tus.f.bdeSize; - cnt++; } + lpfc_sli_hbqbuf_fill_hbq(phba); + } else { + struct lpfc_iocbq *next; + + list_for_each_entry_safe(iocbq, next, &piocbq->list, list) { + icmd = &iocbq->iocb; + if (icmd->ulpBdeCount == 0) { + printk(KERN_ERR "%s (%d): Unsolited CT, no " + "BDE, iocbq = %p, status = x%x\n", + __FUNCTION__, __LINE__, + iocbq, iocbq->iocb.ulpStatus); + continue; + } - icmd->ulpBdeCount = 0; - } - - lpfc_post_buffer(phba, pring, cnt, 1); - if (save_icmd->ulpStatus) { - go_exit = 1; - } - -ct_unsol_event_exit_piocbq: - list_del(&head); - if (pmbuf) { - list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) { - lpfc_mbuf_free(phba, matp->virt, matp->phys); - list_del(&matp->list); - kfree(matp); + for (i = 0; i < icmd->ulpBdeCount; i++) { + paddr = getPaddr(icmd->un.cont64[i].addrHigh, + icmd->un.cont64[i].addrLow); + mp = lpfc_sli_ringpostbuf_get(phba, pring, + paddr); + size = icmd->un.cont64[i].tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, piocbq, mp, size); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + list_del(&iocbq->list); + lpfc_sli_release_iocbq(phba, iocbq); } - lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys); - kfree(pmbuf); } - return; } static void @@ -364,9 +405,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) vport->fc_flag, vport->fc_rscn_id_cnt); } else { - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0239 Skip x%x NameServer " "Rsp Data: x%x x%x x%x\n", phba->brd_no, @@ -717,12 +756,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp = lpfc_findnode_did(vport, FDMI_DID); if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* FDMI rsp failed */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, - "%d:0220 FDMI rsp failed Data: x%x\n", - phba->brd_no, - be16_to_cpu(fdmi_cmd)); + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "%d:0220 FDMI rsp failed Data: x%x\n", + phba->brd_no, be16_to_cpu(fdmi_cmd)); } switch (be16_to_cpu(fdmi_cmd)) { @@ -791,9 +827,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) INIT_LIST_HEAD(&bmp->list); /* FDMI request */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0218 FDMI Request Data: x%x x%x x%x\n", phba->brd_no, vport->fc_flag, vport->port_state, cmdcode); @@ -1120,12 +1154,9 @@ fdmi_cmd_free_mp: kfree(mp); fdmi_cmd_exit: /* Issue FDMI request failed */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0244 Issue FDMI request failed Data: x%x\n", - phba->brd_no, - cmdcode); + phba->brd_no, cmdcode); return 1; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0af33bead30..d48247b3b65 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -45,9 +45,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; uint32_t ha_copy; - int rc; if (vport->port_state >= LPFC_VPORT_READY || phba->link_state == LPFC_LINK_DOWN) @@ -76,20 +74,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) spin_unlock_irq(shost->host_lock); if (phba->link_state != LPFC_CLEAR_LA) { - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { - phba->link_state = LPFC_CLEAR_LA; - lpfc_clear_la(phba, mbox); - mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - mbox->vport = vport; - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - phba->link_state = LPFC_HBA_ERROR; - } - } + lpfc_issue_clear_la(phba, vport); } return 1; @@ -153,8 +138,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, /* Allocate buffer for Buffer ptr list */ pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); if (pbuflist) - pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &pbuflist->phys); + pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, + &pbuflist->phys); if (pbuflist == 0 || pbuflist->virt == 0) { lpfc_sli_release_iocbq(phba, elsiocb); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); @@ -289,6 +274,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, vport->port_state = LPFC_FABRIC_CFG_LINK; lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); if (rc == MBX_NOT_FINISHED) @@ -364,6 +350,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); if (rc == MBX_NOT_FINISHED) { @@ -714,8 +701,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp) + + if (!ndlp) { goto out; + } /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. @@ -1110,9 +1099,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* If we get here, there is nothing left to wait for */ if (vport->port_state < LPFC_VPORT_READY && phba->link_state != LPFC_CLEAR_LA) { - if (vport->port_type == LPFC_PHYSICAL_PORT) { + if (vport->port_type == LPFC_PHYSICAL_PORT) lpfc_issue_clear_la(phba, vport); - } } else { lpfc_rscn_disc(vport); } @@ -1420,6 +1408,27 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 0; } +static void +lpfc_end_rscn(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (vport->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while we were + * processing this one. + */ + if (vport->fc_rscn_id_cnt || + (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) + lpfc_els_handle_rscn(vport); + else { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(shost->host_lock); + } + } +} + void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { @@ -1449,24 +1458,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) vport->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs - * came in while we were - * processing this one. - */ - if (!vport->fc_rscn_id_cnt && - !(vport->fc_flag & - FC_RSCN_DISCOVERY)) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq( - shost->host_lock); - } - else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } } } @@ -1689,6 +1681,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 0; } + if ((vport->load_flag & FC_UNLOADING) != 0) + retry = 0; + if (retry) { /* Retry ELS command to remote NPORT */ @@ -2141,9 +2136,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, cmdsize = sizeof (uint32_t) + sizeof (PRLI); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, - (ELS_CMD_ACC | - (ELS_CMD_PRLI & ~ELS_RSP_MASK))); + ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); if (!elsiocb) return 1; @@ -2361,8 +2354,12 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport) for (i = 0; i < vport->fc_rscn_id_cnt; i++) { mp = vport->fc_rscn_id_list[i]; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys); + else { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } vport->fc_rscn_id_list[i] = NULL; } spin_lock_irq(shost->host_lock); @@ -2486,9 +2483,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, cmd &= ELS_CMD_MASK; /* RSCN received */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0214 RSCN received Data: x%x x%x x%x x%x\n", phba->brd_no, vport->fc_flag, payload_len, *lp, vport->fc_rscn_id_cnt); @@ -2581,9 +2576,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) lpfc_set_disctmo(vport); /* RSCN processed */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n", phba->brd_no, vport->fc_flag, 0, vport->fc_rscn_id_cnt, @@ -2683,6 +2676,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, phba->cfg_link_speed); mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); lpfc_set_loopback_flag(phba); @@ -2837,10 +2831,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; phba->fc_stat.elsXmitACC++; - - if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) lpfc_els_free_iocb(phba, elsiocb); - } return; } @@ -3015,9 +3007,7 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, fp = (FARP *) lp; /* FARP-REQ received from DID */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0601 FARP-REQ received from DID x%x\n", phba->brd_no, did); @@ -3077,12 +3067,9 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, cmd = *lp++; /* FARP-RSP received from DID */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0600 FARP-RSP received from DID x%x\n", phba->brd_no, did); - /* ACCEPT the Farp resp request */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); @@ -3102,8 +3089,9 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_hba *phba = vport->phba; /* FAN received */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n", - phba->brd_no); + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "%d:0265 FAN received\n", + phba->brd_no); icmd = &cmdiocb->iocb; did = icmd->un.elsreq64.remoteID; @@ -3332,79 +3320,40 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) return; } -void -lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *elsiocb) +static void +lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_vport *vport, struct lpfc_dmabuf *mp, + struct lpfc_iocbq *elsiocb) { - struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *mp = NULL; - uint32_t *lp; - IOCB_t *icmd; struct ls_rjt stat; + uint32_t *lp; uint32_t cmd, did, newnode, rjt_err = 0; - uint32_t drop_cmd = 0; /* by default do NOT drop received cmd */ - struct lpfc_vport *vport = NULL; - - psli = &phba->sli; - icmd = &elsiocb->iocb; + IOCB_t *icmd = &elsiocb->iocb; - if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { - phba->fc_stat.NoRcvBuf++; - /* Not enough posted buffers; Try posting more buffers */ - lpfc_post_buffer(phba, pring, 0, 1); - return; - } - - /* If there are no BDEs associated with this IOCB, - * there is nothing to do. - */ - if (icmd->ulpBdeCount == 0) - return; - - /* type of ELS cmd is first 32bit word in packet */ - mp = lpfc_sli_ringpostbuf_get(phba, pring, - getPaddr(icmd->un.cont64[0].addrHigh, - icmd->un.cont64[0].addrLow)); - if (mp == 0) { - drop_cmd = 1; + if (!vport || !mp) goto dropit; - } - - vport = phba->pport; newnode = 0; lp = (uint32_t *) mp->virt; cmd = *lp++; - lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1); + if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) + lpfc_post_buffer(phba, pring, 1, 1); - if (icmd->ulpStatus) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - drop_cmd = 1; + if (icmd->ulpStatus) goto dropit; - } /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - drop_cmd = 1; + if (lpfc_els_chk_latt(vport)) goto dropit; - } did = icmd->un.rcvels.remoteID; ndlp = lpfc_findnode_did(vport, did); if (!ndlp) { /* Cannot find existing Fabric ndlp, so allocate a new one */ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - drop_cmd = 1; + if (!ndlp) goto dropit; - } lpfc_nlp_init(vport, ndlp, did); newnode = 1; @@ -3428,7 +3377,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0112 ELS command x%x received from NPORT x%x " "Data: x%x\n", phba->brd_no, cmd, did, - vport->port_state); + vport->port_state); switch (cmd) { case ELS_CMD_PLOGI: @@ -3537,8 +3486,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* Unknown ELS command received from NPORT */ lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "%d:0115 Unknown ELS command x%x received from " - "NPORT x%x\n", phba->brd_no, cmd, did); + "%d:0115 Unknown ELS command x%x " + "received from NPORT x%x\n", + phba->brd_no, cmd, did); if (newnode) lpfc_drop_node(vport, ndlp); break; @@ -3553,20 +3503,89 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp); } + return; + +dropit: + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "%d:0111 Dropping received ELS cmd " + "Data: x%x x%x x%x\n", + phba->brd_no, + icmd->ulpStatus, icmd->un.ulpWord[4], + icmd->ulpTimeout); + phba->fc_stat.elsRcvDrop++; +} + + +void +lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *elsiocb) +{ + struct lpfc_vport *vport = phba->pport; + struct lpfc_dmabuf *mp = NULL; + IOCB_t *icmd = &elsiocb->iocb; + struct hbq_dmabuf *sp = NULL; + dma_addr_t paddr; + + if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + phba->fc_stat.NoRcvBuf++; + /* Not enough posted buffers; Try posting more buffers */ + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + lpfc_sli_hbqbuf_fill_hbq(phba); + else + lpfc_post_buffer(phba, pring, 0, 1); + return; + } + + /* If there are no BDEs associated with this IOCB, + * there is nothing to do. + */ + if (icmd->ulpBdeCount == 0) + return; + + /* type of ELS cmd is first 32bit word in packet */ + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + paddr = getPaddr(icmd->un.cont64[0].addrHigh, + icmd->un.cont64[0].addrLow); + sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]); + if (sp) + phba->hbq_buff_count--; + mp = sp ? &sp->dbuf : NULL; + } else { + paddr = getPaddr(icmd->un.cont64[0].addrHigh, + icmd->un.cont64[0].addrLow); + mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr); + } + + lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb); + lpfc_nlp_put(elsiocb->context1); elsiocb->context1 = NULL; if (elsiocb->context2) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + lpfc_sli_free_hbq(phba, sp); + else { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } } -dropit: - /* check if need to drop received ELS cmd */ - if (drop_cmd == 1) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "%d:0111 Dropping received ELS cmd " - "Data: x%x x%x x%x\n", phba->brd_no, - icmd->ulpStatus, icmd->un.ulpWord[4], - icmd->ulpTimeout); - phba->fc_stat.elsRcvDrop++; + + /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */ + if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 && + icmd->ulpBdeCount == 2) { + sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]); + if (sp) + phba->hbq_buff_count--; + mp = sp ? &sp->dbuf : NULL; + lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb); + /* free mp if we are done with it */ + if (elsiocb->context2) { + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) + lpfc_sli_free_hbq(phba, sp); + else { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + } } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dee875ee616..20b2a4905da 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -232,9 +232,9 @@ static void lpfc_work_done(struct lpfc_hba *phba) { struct lpfc_sli_ring *pring; - int i; uint32_t ha_copy, control, work_port_events; struct lpfc_vport *vport; + int i; spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; @@ -303,9 +303,9 @@ check_work_wait_done(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; int rc = 0; - if (!vport) return 0; + spin_lock_irq(&phba->hbalock); if (phba->work_ha || @@ -354,6 +354,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, uint32_t evt) { struct lpfc_work_evt *evtp; + unsigned long flags; /* * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will @@ -367,11 +368,11 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, flags); list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); return 1; } @@ -401,6 +402,7 @@ lpfc_linkdown(struct lpfc_hba *phba) mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_unreg_did(phba, 0xffffffff, mb); + mb->vport = vport; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { @@ -433,6 +435,7 @@ lpfc_linkdown(struct lpfc_hba *phba) if (mb) { lpfc_config_link(phba, mb); mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; + mb->vport = vport; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { @@ -550,15 +553,11 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); } - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; out: /* Device Discovery completes */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0225 Device Discovery completes\n", phba->brd_no); @@ -632,8 +631,6 @@ out: phba->brd_no, vport->port_state); lpfc_clear_la(phba, pmb); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -643,8 +640,6 @@ out: psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } return; @@ -702,8 +697,6 @@ out: struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; lpfc_clear_la(phba, pmb); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)) @@ -713,8 +706,6 @@ out: extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } } else { @@ -875,12 +866,9 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if (mb->mbxStatus) { - lpfc_printf_log(phba, - KERN_INFO, - LOG_LINK_EVENT, + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "%d:1307 READ_LA mbox error x%x state x%x\n", - phba->brd_no, - mb->mbxStatus, vport->port_state); + phba->brd_no, mb->mbxStatus, vport->port_state); lpfc_mbx_issue_link_down(phba); phba->link_state = LPFC_HBA_ERROR; goto lpfc_mbx_cmpl_read_la_free_mbuf; @@ -955,7 +943,6 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - pmb->context1 = NULL; /* Good status, call state machine */ @@ -1553,6 +1540,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox); + mbox->vport = vport; mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -1925,8 +1913,6 @@ lpfc_disc_start(struct lpfc_vport *vport) if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { if (vport->port_type == LPFC_PHYSICAL_PORT) { /* If we get here, there is nothing to ADISC */ - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); lpfc_issue_clear_la(phba, vport); } else if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { @@ -1940,8 +1926,6 @@ lpfc_disc_start(struct lpfc_vport *vport) vport->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(shost->host_lock); } - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } } else { @@ -2095,13 +2079,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) if (!(vport->fc_flag & FC_DISC_TMO)) return; - spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_DISC_TMO; spin_unlock_irq(shost->host_lock); - printk(KERN_ERR "%s (%d): link_state = %d, port_state = %d\n", - __FUNCTION__, __LINE__, phba->link_state, vport->port_state); switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: @@ -2109,9 +2090,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) * FAN */ /* FAN timeout */ - lpfc_printf_log(phba, - KERN_WARNING, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY, "%d:0221 FAN timeout\n", phba->brd_no); @@ -2138,9 +2117,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0222 Initial FLOGI timeout\n", phba->brd_no); @@ -2203,8 +2180,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, @@ -2230,6 +2205,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) lpfc_init_link(phba, initlinkmbox, phba->cfg_topology, phba->cfg_link_speed); initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; + initlinkmbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, initlinkmbox, (MBX_NOWAIT | MBX_STOP_IOCB)); lpfc_set_loopback_flag(phba); @@ -2240,9 +2216,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_DISC_AUTH: /* Node Authentication timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0227 Node Authentication timeout\n", phba->brd_no); lpfc_disc_flush_list(vport); @@ -2259,8 +2233,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, @@ -2273,9 +2245,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_VPORT_READY: if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0231 RSCN timeout Data: x%x x%x\n", phba->brd_no, vport->fc_ns_retry, LPFC_MAX_NS_RETRY); @@ -2291,13 +2261,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_STATE_UNKNOWN: case LPFC_NS_REG: case LPFC_BUILD_DISC_LIST: - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0229 Unexpected discovery timeout, vport " "State x%x\n", - vport->port_state, - phba->brd_no); + vport->port_state, phba->brd_no); break; } @@ -2305,9 +2272,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) switch (phba->link_state) { case LPFC_CLEAR_LA: /* CLEAR LA timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0228 CLEAR LA timeout\n", phba->brd_no); clrlaerr = 1; @@ -2320,9 +2285,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_LINK_DOWN: case LPFC_LINK_UP: case LPFC_HBA_ERROR: - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0230 Unexpected timeout, hba link " "state x%x\n", phba->brd_no, phba->link_state); @@ -2335,8 +2298,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c4be6dc00c4..430416805e8 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -59,6 +59,11 @@ #define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24 #define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32 +#define SLI2_IOCB_CMD_SIZE 32 +#define SLI2_IOCB_RSP_SIZE 32 +#define SLI3_IOCB_CMD_SIZE 128 +#define SLI3_IOCB_RSP_SIZE 64 + /* Common Transport structures and definitions */ union CtRevisionId { @@ -1255,6 +1260,7 @@ typedef struct { /* FireFly BIU registers */ #define MBX_CONFIG_FARP 0x25 #define MBX_BEACON 0x2A +#define MBX_CONFIG_HBQ 0x7C #define MBX_LOAD_AREA 0x81 #define MBX_RUN_BIU_DIAG64 0x84 #define MBX_CONFIG_PORT 0x88 @@ -1334,6 +1340,10 @@ typedef struct { /* FireFly BIU registers */ #define CMD_FCP_TRECEIVE64_CX 0xA1 #define CMD_FCP_TRSP64_CX 0xA3 +#define CMD_IOCB_RCV_SEQ64_CX 0xB5 +#define CMD_IOCB_RCV_ELS64_CX 0xB7 +#define CMD_IOCB_RCV_CONT64_CX 0xBB + #define CMD_GEN_REQUEST64_CR 0xC2 #define CMD_GEN_REQUEST64_CX 0xC3 @@ -1560,6 +1570,7 @@ typedef struct { #define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */ #define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */ #define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */ +#define FLAGS_UNREG_LOGIN_ALL 0x08 /* UNREG_LOGIN all on link down */ #define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */ #define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ @@ -1817,6 +1828,13 @@ typedef struct { structure */ struct ulp_bde64 sp64; } un; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t rsvd3; + uint16_t vpi; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint16_t vpi; + uint16_t rsvd3; +#endif } READ_SPARM_VAR; /* Structure for MB Command READ_STATUS (14) */ @@ -1917,11 +1935,17 @@ typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint32_t cv:1; uint32_t rr:1; - uint32_t rsvd1:29; + uint32_t rsvd2:2; + uint32_t v3req:1; + uint32_t v3rsp:1; + uint32_t rsvd1:25; uint32_t rv:1; #else /* __LITTLE_ENDIAN_BITFIELD */ uint32_t rv:1; - uint32_t rsvd1:29; + uint32_t rsvd1:25; + uint32_t v3rsp:1; + uint32_t v3req:1; + uint32_t rsvd2:2; uint32_t rr:1; uint32_t cv:1; #endif @@ -1971,8 +1995,8 @@ typedef struct { uint8_t sli1FwName[16]; uint32_t sli2FwRev; uint8_t sli2FwName[16]; - uint32_t rsvd2; - uint32_t RandomData[7]; + uint32_t sli3Feat; + uint32_t RandomData[6]; } READ_REV_VAR; /* Structure for MB Command READ_LINK_STAT (18) */ @@ -2012,6 +2036,14 @@ typedef struct { struct ulp_bde64 sp64; } un; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t rsvd6; + uint16_t vpi; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint16_t vpi; + uint16_t rsvd6; +#endif + } REG_LOGIN_VAR; /* Word 30 contents for REG_LOGIN */ @@ -2036,9 +2068,21 @@ typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint16_t rsvd1; uint16_t rpi; + uint32_t rsvd2; + uint32_t rsvd3; + uint32_t rsvd4; + uint32_t rsvd5; + uint16_t rsvd6; + uint16_t vpi; #else /* __LITTLE_ENDIAN_BITFIELD */ uint16_t rpi; uint16_t rsvd1; + uint32_t rsvd2; + uint32_t rsvd3; + uint32_t rsvd4; + uint32_t rsvd5; + uint16_t vpi; + uint16_t rsvd6; #endif } UNREG_LOGIN_VAR; @@ -2046,6 +2090,17 @@ typedef struct { typedef struct { uint32_t did; + uint32_t rsvd2; + uint32_t rsvd3; + uint32_t rsvd4; + uint32_t rsvd5; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t rsvd6; + uint16_t vpi; +#else + uint16_t vpi; + uint16_t rsvd6; +#endif } UNREG_D_ID_VAR; /* Structure for MB Command READ_LA (21) */ @@ -2177,13 +2232,240 @@ typedef struct { #define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ #define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ +struct hbq_mask { +#ifdef __BIG_ENDIAN_BITFIELD + uint8_t tmatch; + uint8_t tmask; + uint8_t rctlmatch; + uint8_t rctlmask; +#else /* __LITTLE_ENDIAN */ + uint8_t rctlmask; + uint8_t rctlmatch; + uint8_t tmask; + uint8_t tmatch; +#endif +}; + + +/* Structure for MB Command CONFIG_HBQ (7c) */ + +struct config_hbq_var { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd1 :7; + uint32_t recvNotify :1; /* Receive Notification */ + uint32_t numMask :8; /* # Mask Entries */ + uint32_t profile :8; /* Selection Profile */ + uint32_t rsvd2 :8; +#else /* __LITTLE_ENDIAN */ + uint32_t rsvd2 :8; + uint32_t profile :8; /* Selection Profile */ + uint32_t numMask :8; /* # Mask Entries */ + uint32_t recvNotify :1; /* Receive Notification */ + uint32_t rsvd1 :7; +#endif + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t hbqId :16; + uint32_t rsvd3 :12; + uint32_t ringMask :4; +#else /* __LITTLE_ENDIAN */ + uint32_t ringMask :4; + uint32_t rsvd3 :12; + uint32_t hbqId :16; +#endif + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t entry_count :16; + uint32_t rsvd4 :8; + uint32_t headerLen :8; +#else /* __LITTLE_ENDIAN */ + uint32_t headerLen :8; + uint32_t rsvd4 :8; + uint32_t entry_count :16; +#endif + + uint32_t hbqaddrLow; + uint32_t hbqaddrHigh; + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd5 :31; + uint32_t logEntry :1; +#else /* __LITTLE_ENDIAN */ + uint32_t logEntry :1; + uint32_t rsvd5 :31; +#endif + + uint32_t rsvd6; /* w7 */ + uint32_t rsvd7; /* w8 */ + uint32_t rsvd8; /* w9 */ + + struct hbq_mask hbqMasks[6]; + + + union { + uint32_t allprofiles[12]; + + struct { + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t seqlenoff :16; + uint32_t maxlen :16; + #else /* __LITTLE_ENDIAN */ + uint32_t maxlen :16; + uint32_t seqlenoff :16; + #endif + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd1 :28; + uint32_t seqlenbcnt :4; + #else /* __LITTLE_ENDIAN */ + uint32_t seqlenbcnt :4; + uint32_t rsvd1 :28; + #endif + uint32_t rsvd[10]; + } profile2; + + struct { + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t seqlenoff :16; + uint32_t maxlen :16; + #else /* __LITTLE_ENDIAN */ + uint32_t maxlen :16; + uint32_t seqlenoff :16; + #endif + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t cmdcodeoff :28; + uint32_t rsvd1 :12; + uint32_t seqlenbcnt :4; + #else /* __LITTLE_ENDIAN */ + uint32_t seqlenbcnt :4; + uint32_t rsvd1 :12; + uint32_t cmdcodeoff :28; + #endif + uint32_t cmdmatch[8]; + + uint32_t rsvd[2]; + } profile3; + + struct { + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t seqlenoff :16; + uint32_t maxlen :16; + #else /* __LITTLE_ENDIAN */ + uint32_t maxlen :16; + uint32_t seqlenoff :16; + #endif + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t cmdcodeoff :28; + uint32_t rsvd1 :12; + uint32_t seqlenbcnt :4; + #else /* __LITTLE_ENDIAN */ + uint32_t seqlenbcnt :4; + uint32_t rsvd1 :12; + uint32_t cmdcodeoff :28; + #endif + uint32_t cmdmatch[8]; + + uint32_t rsvd[2]; + } profile5; + + } profiles; + +}; + + /* Structure for MB Command CONFIG_PORT (0x88) */ typedef struct { - uint32_t pcbLen; +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t cBE : 1; + uint32_t cET : 1; + uint32_t cHpcb : 1; + uint32_t cMA : 1; + uint32_t sli_mode : 4; + uint32_t pcbLen : 24; /* bit 23:0 of memory based port + * config block */ +#else /* __LITTLE_ENDIAN */ + uint32_t pcbLen : 24; /* bit 23:0 of memory based port + * config block */ + uint32_t sli_mode : 4; + uint32_t cMA : 1; + uint32_t cHpcb : 1; + uint32_t cET : 1; + uint32_t cBE : 1; +#endif + uint32_t pcbLow; /* bit 31:0 of memory based port config block */ uint32_t pcbHigh; /* bit 63:32 of memory based port config block */ - uint32_t hbainit[5]; + uint32_t hbainit[6]; + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd : 24; /* Reserved */ + uint32_t cmv : 1; /* Configure Max VPIs */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ + uint32_t chbs : 1; /* Cofigure Host Backing store */ + uint32_t cinb : 1; /* Enable Interrupt Notification Block */ + uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ + uint32_t cmx : 1; /* Configure Max XRIs */ + uint32_t cmr : 1; /* Configure Max RPIs */ +#else /* __LITTLE_ENDIAN */ + uint32_t cmr : 1; /* Configure Max RPIs */ + uint32_t cmx : 1; /* Configure Max XRIs */ + uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ + uint32_t cinb : 1; /* Enable Interrupt Notification Block */ + uint32_t chbs : 1; /* Cofigure Host Backing store */ + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t cmv : 1; /* Configure Max VPIs */ + uint32_t rsvd : 24; /* Reserved */ +#endif +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd2 : 24; /* Reserved */ + uint32_t gmv : 1; /* Grant Max VPIs */ + uint32_t gcrp : 1; /* Grant Command Ring Polling */ + uint32_t gsah : 1; /* Grant Synchronous Abort Handling */ + uint32_t ghbs : 1; /* Grant Host Backing Store */ + uint32_t ginb : 1; /* Grant Interrupt Notification Block */ + uint32_t gerbm : 1; /* Grant ERBM Request */ + uint32_t gmx : 1; /* Grant Max XRIs */ + uint32_t gmr : 1; /* Grant Max RPIs */ +#else /* __LITTLE_ENDIAN */ + uint32_t gmr : 1; /* Grant Max RPIs */ + uint32_t gmx : 1; /* Grant Max XRIs */ + uint32_t gerbm : 1; /* Grant ERBM Request */ + uint32_t ginb : 1; /* Grant Interrupt Notification Block */ + uint32_t ghbs : 1; /* Grant Host Backing Store */ + uint32_t gsah : 1; /* Grant Synchronous Abort Handling */ + uint32_t gcrp : 1; /* Grant Command Ring Polling */ + uint32_t gmv : 1; /* Grant Max VPIs */ + uint32_t rsvd2 : 24; /* Reserved */ +#endif + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t max_rpi : 16; /* Max RPIs Port should configure */ + uint32_t max_xri : 16; /* Max XRIs Port should configure */ +#else /* __LITTLE_ENDIAN */ + uint32_t max_xri : 16; /* Max XRIs Port should configure */ + uint32_t max_rpi : 16; /* Max RPIs Port should configure */ +#endif + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ + uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */ +#else /* __LITTLE_ENDIAN */ + uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */ + uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ +#endif + + uint32_t rsvd4; /* Reserved */ + +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd5 : 16; /* Reserved */ + uint32_t max_vpi : 16; /* Max number of virt N-Ports */ +#else /* __LITTLE_ENDIAN */ + uint32_t max_vpi : 16; /* Max number of virt N-Ports */ + uint32_t rsvd5 : 16; /* Reserved */ +#endif + } CONFIG_PORT_VAR; /* SLI-2 Port Control Block */ @@ -2261,33 +2543,38 @@ typedef struct { #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) typedef union { - uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; - LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */ - READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */ - WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */ + uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ + * feature/max ring number + */ + LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */ + READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */ + WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */ BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */ INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */ DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */ - CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */ - PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */ + CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */ + PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */ CONFIG_RING_VAR varCfgRing; /* cmd = 9 (CONFIG_RING) */ RESET_RING_VAR varRstRing; /* cmd = 10 (RESET_RING) */ READ_CONFIG_VAR varRdConfig; /* cmd = 11 (READ_CONFIG) */ READ_RCONF_VAR varRdRConfig; /* cmd = 12 (READ_RCONFIG) */ READ_SPARM_VAR varRdSparm; /* cmd = 13 (READ_SPARM(64)) */ READ_STATUS_VAR varRdStatus; /* cmd = 14 (READ_STATUS) */ - READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */ - READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */ - READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */ - READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */ + READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */ + READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */ + READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */ + READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */ REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */ UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */ - READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */ + READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */ CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */ - DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */ - UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */ - CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) NEW_FEATURE */ - CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ + DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */ + UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */ + CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) + * NEW_FEATURE + */ + struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */ + CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ } MAILVARIANTS; /* @@ -2304,16 +2591,30 @@ struct lpfc_pgp { __le32 rspPutInx; }; -typedef struct _SLI2_DESC { - struct lpfc_hgp host[MAX_RINGS]; +struct sli2_desc { uint32_t unused1[16]; + struct lpfc_hgp host[MAX_RINGS]; + struct lpfc_pgp port[MAX_RINGS]; +}; + +struct sli3_desc { + struct lpfc_hgp host[MAX_RINGS]; + uint32_t reserved[8]; + uint32_t hbq_put[16]; +}; + +struct sli3_pgp { struct lpfc_pgp port[MAX_RINGS]; -} SLI2_DESC; + uint32_t hbq_get[16]; +}; typedef union { - SLI2_DESC s2; + struct sli2_desc s2; + struct sli3_desc s3; + struct sli3_pgp s3_pgp; } SLI_VAR; + typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint16_t mbxStatus; @@ -2617,6 +2918,23 @@ typedef struct { uint32_t fcpt_Length; /* transfer ready for IWRITE */ } FCPT_FIELDS64; +/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) + or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ + +struct rcv_sli3 { + uint32_t word8Rsvd; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t vpi; + uint16_t word9Rsvd; +#else /* __LITTLE_ENDIAN */ + uint16_t word9Rsvd; + uint16_t vpi; +#endif + uint32_t word10Rsvd; + uint32_t acc_len; /* accumulated length */ + struct ulp_bde64 bde2; +}; + typedef struct _IOCB { /* IOCB structure */ union { GENERIC_RSP grsp; /* Generic response */ @@ -2631,8 +2949,8 @@ typedef struct _IOCB { /* IOCB structure */ /* SLI-2 structures */ - struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation - bde_64s */ + struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation + * bde_64s */ ELS_REQUEST64 elsreq64; /* ELS_REQUEST template */ GEN_REQUEST64 genreq64; /* GEN_REQUEST template */ RCV_ELS_REQ64 rcvels64; /* RCV_ELS_REQ template */ @@ -2693,7 +3011,16 @@ typedef struct _IOCB { /* IOCB structure */ uint32_t ulpXS:1; uint32_t ulpTimeout:8; #endif + union { + struct rcv_sli3 rcvsli3; /* words 8 - 15 */ + uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ + } unsli3; + +#define ulpCt_h ulpXS +#define ulpCt_l ulpFCP2Rcvy +#define IOCB_FCP 1 /* IOCB is used for FCP ELS cmds-ulpRsvByte */ +#define IOCB_IP 2 /* IOCB is used for IP ELS cmds */ #define PARM_UNUSED 0 /* PU field (Word 4) not used */ #define PARM_REL_OFF 1 /* PU field (Word 4) = R. O. */ #define PARM_READ_CHECK 2 /* PU field (Word 4) = Data Transfer Length */ @@ -2724,21 +3051,33 @@ typedef struct _IOCB { /* IOCB structure */ } IOCB_t; +/* Structure used for a single HBQ entry */ +struct lpfc_hbq_entry { + struct ulp_bde64 bde; + uint32_t buffer_tag; +}; + #define SLI1_SLIM_SIZE (4 * 1024) /* Up to 498 IOCBs will fit into 16k * 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384 */ -#define SLI2_SLIM_SIZE (16 * 1024) +#define SLI2_SLIM_SIZE (64 * 1024) /* Maximum IOCBs that will fit in SLI2 slim */ #define MAX_SLI2_IOCB 498 +#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ + (sizeof(MAILBOX_t) + sizeof(PCB_t))) + +/* HBQ entries are 4 words each = 4k */ +#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \ + lpfc_sli_hbq_count()) struct lpfc_sli2_slim { MAILBOX_t mbx; PCB_t pcb; - IOCB_t IOCBs[MAX_SLI2_IOCB]; + IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE]; }; /* diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e11c4cda0f3..e50c5ad252f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -49,6 +49,12 @@ static int lpfc_post_rcv_buf(struct lpfc_hba *); static struct scsi_transport_template *lpfc_transport_template = NULL; static DEFINE_IDR(lpfc_hba_index); +int lpfc_sli_mode = 0; +module_param(lpfc_sli_mode, int, 0); +MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" + " 0 - auto (SLI-3 if supported)," + " 2 - select SLI-2 even on SLI-3 capable HBAs," + " 3 - select SLI-3"); /************************************************************************/ @@ -102,9 +108,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "%d:0324 Config Port initialization " "error, mbxCmd x%x READ_NVPARM, " "mbxStatus x%x\n", @@ -123,9 +127,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) lpfc_read_rev(phba, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0439 Adapter failed to init, mbxCmd x%x " "READ_REV, mbxStatus x%x\n", phba->brd_no, @@ -148,6 +150,9 @@ lpfc_config_port_prep(struct lpfc_hba *phba) return -ERESTART; } + if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) + return -EINVAL; + /* Save information as VPD data */ vp->rev.rBit = 1; vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev; @@ -236,10 +241,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Get login parameters for NID. */ lpfc_read_sparam(phba, pmb); + pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0448 Adapter failed init, mbxCmd x%x " "READ_SPARM mbxStatus x%x\n", phba->brd_no, @@ -296,10 +300,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) } lpfc_read_config(phba, pmb); + pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0453 Adapter failed to init, mbxCmd x%x " "READ_CONFIG, mbxStatus x%x\n", phba->brd_no, @@ -331,9 +334,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) || ((phba->cfg_link_speed == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb))) { /* Reset link speed to auto */ - lpfc_printf_log(phba, - KERN_WARNING, - LOG_LINK_EVENT, + lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT, "%d:1302 Invalid speed for this board: " "Reset link speed to auto: x%x\n", phba->brd_no, @@ -352,7 +353,8 @@ lpfc_config_port_post(struct lpfc_hba *phba) psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT; /* Post receive buffers for desired rings */ - lpfc_post_rcv_buf(phba); + if (phba->sli_rev != 3) + lpfc_post_rcv_buf(phba); /* Enable appropriate host interrupts */ spin_lock_irq(&phba->hbalock); @@ -383,12 +385,11 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); lpfc_set_loopback_flag(phba); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0454 Adapter failed to init, mbxCmd x%x " "INIT_LINK, mbxStatus x%x\n", phba->brd_no, @@ -630,9 +631,7 @@ lpfc_handle_latt_err_exit: /* The other case is an error from issue_mbox */ if (rc == -ENOMEM) - lpfc_printf_log(phba, - KERN_WARNING, - LOG_MBOX, + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "%d:0300 READ_LA: no buffers\n", phba->brd_no); @@ -658,9 +657,7 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) return 0; /* Vital Product */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0455 Vital Product Data: x%x x%x x%x x%x\n", phba->brd_no, (uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2], @@ -1221,9 +1218,7 @@ lpfc_online(struct lpfc_hba *phba) if (!(vport->fc_flag & FC_OFFLINE_MODE)) return 0; - lpfc_printf_log(phba, - KERN_WARNING, - LOG_INIT, + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "%d:0458 Bring Adapter online\n", phba->brd_no); @@ -1633,13 +1628,22 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) memset(phba->slim2p, 0, SLI2_SLIM_SIZE); + phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev, + lpfc_sli_hbq_size(), + &phba->hbqslimp.phys, + GFP_KERNEL); + if (!phba->hbqslimp.virt) + goto out_free_slim; + + memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); + /* Initialize the SLI Layer to run with lpfc HBAs. */ lpfc_sli_setup(phba); lpfc_sli_queue_setup(phba); error = lpfc_mem_alloc(phba); if (error) - goto out_free_slim; + goto out_free_hbqslimp; /* Initialize and populate the iocb list per host. */ INIT_LIST_HEAD(&phba->lpfc_iocb_list); @@ -1753,6 +1757,9 @@ out_free_iocbq: phba->total_iocbq_bufs--; } lpfc_mem_free(phba); +out_free_hbqslimp: + dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt, + phba->hbqslimp.phys); out_free_slim: dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p, phba->slim2p_mapping); @@ -1811,6 +1818,9 @@ lpfc_pci_remove_one(struct pci_dev *pdev) lpfc_scsi_free(phba); lpfc_mem_free(phba); + dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt, + phba->hbqslimp.phys); + /* Free resources associated with SLI2 interface */ dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p, phba->slim2p_mapping); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 86757ec5305..977799c2b2c 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -232,6 +232,7 @@ lpfc_init_link(struct lpfc_hba * phba, mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; mb->mbxOwner = OWN_HOST; mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; + mb->un.varInitLnk.link_flags |= FLAGS_UNREG_LOGIN_ALL; return; } @@ -418,6 +419,10 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; + pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE: + SLI2_IOCB_CMD_SIZE; + pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE: + SLI2_IOCB_RSP_SIZE; /* A ring MUST have both cmd and rsp entries defined to be valid */ if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { @@ -432,8 +437,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) continue; } /* Command ring setup for ring */ - pring->cmdringaddr = - (void *)&phba->slim2p->IOCBs[iocbCnt]; + pring->cmdringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; pcbp->rdsc[i].cmdEntries = pring->numCiocb; offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - @@ -444,8 +448,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) iocbCnt += pring->numCiocb; /* Response ring setup for ring */ - pring->rspringaddr = - (void *)&phba->slim2p->IOCBs[iocbCnt]; + pring->rspringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; pcbp->rdsc[i].rspEntries = pring->numRiocb; offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - @@ -463,11 +466,103 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) MAILBOX_t *mb = &pmb->mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); mb->un.varRdRev.cv = 1; + mb->un.varRdRev.v3req = 1; /* Request SLI3 info */ mb->mbxCommand = MBX_READ_REV; mb->mbxOwner = OWN_HOST; return; } +static void +lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +{ + hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt; + hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen; + hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff; +} + +static void +lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +{ + hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt; + hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen; + hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff; + hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff; + memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch, + sizeof(hbqmb->profiles.profile3.cmdmatch)); +} + +static void +lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +{ + hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt; + hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen; + hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff; + hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff; + memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch, + sizeof(hbqmb->profiles.profile5.cmdmatch)); +} + +void +lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc, + uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb) +{ + int i; + MAILBOX_t *mb = &pmb->mb; + struct config_hbq_var *hbqmb = &mb->un.varCfgHbq; + + memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); + hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */ + hbqmb->recvNotify = hbq_desc->rn; /* Receive + * Notification */ + hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks + * # in words 0-19 */ + hbqmb->profile = hbq_desc->profile; /* Selection profile: + * 0 = all, + * 7 = logentry */ + hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring + * e.g. Ring0=b0001, + * ring2=b0100 */ + hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4 + * or 5 */ + hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this + * HBQ will be used + * for LogEntry + * buffers */ + hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) + + hbq_entry_index * sizeof(struct lpfc_hbq_entry); + hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys); + + mb->mbxCommand = MBX_CONFIG_HBQ; + mb->mbxOwner = OWN_HOST; + + /* Copy info for profiles 2,3,5. Other + * profiles this area is reserved + */ + if (hbq_desc->profile == 2) + lpfc_build_hbq_profile2(hbqmb, hbq_desc); + else if (hbq_desc->profile == 3) + lpfc_build_hbq_profile3(hbqmb, hbq_desc); + else if (hbq_desc->profile == 5) + lpfc_build_hbq_profile5(hbqmb, hbq_desc); + + /* Return if no rctl / type masks for this HBQ */ + if (!hbq_desc->mask_count) + return; + + /* Otherwise we setup specific rctl / type masks for this HBQ */ + for (i = 0; i < hbq_desc->mask_count; i++) { + hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch; + hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask; + hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch; + hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask; + } + + return; +} + void lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) { @@ -512,13 +607,14 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) void lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { + MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr; MAILBOX_t *mb = &pmb->mb; dma_addr_t pdma_addr; uint32_t bar_low, bar_high; size_t offset; struct lpfc_hgp hgp; - void __iomem *to_slim; int i; + uint32_t pgp_offset; memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb->mbxCommand = MBX_CONFIG_PORT; @@ -531,12 +627,21 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); + /* If HBA supports SLI=3 ask for it */ + + mb->un.varCfgPort.sli_mode = phba->sli_rev; + if (phba->sli_rev == 3) { + mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ + mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */ + } + /* Now setup pcb */ phba->slim2p->pcb.type = TYPE_NATIVE_SLI2; phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2; /* Setup Mailbox pointers */ - phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t); + phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) + + sizeof(struct sli2_desc); offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p; pdma_addr = phba->slim2p_mapping + offset; phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr); @@ -564,29 +669,70 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low); pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high); + /* + * Set up HGP - Port Memory + * + * The port expects the host get/put pointers to reside in memory + * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes) + * area of SLIM. In SLI-2 mode, there's an additional 16 reserved + * words (0x40 bytes). This area is not reserved if HBQs are + * configured in SLI-3. + * + * CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80 + * RR0Get 0xc4 0x84 + * CR1Put 0xc8 0x88 + * RR1Get 0xcc 0x8c + * CR2Put 0xd0 0x90 + * RR2Get 0xd4 0x94 + * CR3Put 0xd8 0x98 + * RR3Get 0xdc 0x9c + * + * Reserved 0xa0-0xbf + * If HBQs configured: + * HBQ 0 Put ptr 0xc0 + * HBQ 1 Put ptr 0xc4 + * HBQ 2 Put ptr 0xc8 + * ...... + * HBQ(M-1)Put Pointer 0xc0+(M-1)*4 + * + */ + + if (phba->sli_rev == 3) { + phba->host_gp = &mb_slim->us.s3.host[0]; + phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; + } else { + phba->host_gp = &mb_slim->us.s2.host[0]; + phba->hbq_put = NULL; + } /* mask off BAR0's flag bits 0 - 3 */ phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + - (SLIMOFF*sizeof(uint32_t)); + (void __iomem *) phba->host_gp - + (void __iomem *)phba->MBslimaddr; if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) phba->slim2p->pcb.hgpAddrHigh = bar_high; else phba->slim2p->pcb.hgpAddrHigh = 0; /* write HGP data to SLIM at the required longword offset */ memset(&hgp, 0, sizeof(struct lpfc_hgp)); - to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t)); for (i=0; i < phba->sli.num_rings; i++) { - lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp)); - to_slim += sizeof (struct lpfc_hgp); + lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, + sizeof(*phba->host_gp)); } /* Setup Port Group ring pointer */ - offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - - (uint8_t *)phba->slim2p; - pdma_addr = phba->slim2p_mapping + offset; + if (phba->sli_rev == 3) + pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port - + (uint8_t *)phba->slim2p; + else + pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - + (uint8_t *)phba->slim2p; + + pdma_addr = phba->slim2p_mapping + pgp_offset; phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr); phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr); + phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0]; /* Use callback routine to setp rings in the pcb */ lpfc_config_pcb_setup(phba); @@ -603,10 +749,6 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* Swap PCB if needed */ lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb, sizeof (PCB_t)); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "%d:0405 Service Level Interface (SLI) 2 selected\n", - phba->brd_no); } void diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 3aa1dff1544..435dc2ec935 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -82,8 +82,16 @@ lpfc_mem_alloc(struct lpfc_hba * phba) if (!phba->nlp_mem_pool) goto fail_free_mbox_pool; + phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev, + LPFC_BPL_SIZE, 8, 0); + if (!phba->lpfc_hbq_pool) + goto fail_free_nlp_mem_pool; + return 0; + fail_free_nlp_mem_pool: + mempool_destroy(phba->nlp_mem_pool); + phba->nlp_mem_pool = NULL; fail_free_mbox_pool: mempool_destroy(phba->mbox_mem_pool); phba->mbox_mem_pool = NULL; @@ -111,6 +119,8 @@ lpfc_mem_free(struct lpfc_hba * phba) struct lpfc_dmabuf *mp; int i; + lpfc_sli_hbqbuf_free_all(phba); + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); @@ -140,12 +150,14 @@ lpfc_mem_free(struct lpfc_hba * phba) pool->elements[i].phys); kfree(pool->elements); + pci_pool_destroy(phba->lpfc_hbq_pool); mempool_destroy(phba->nlp_mem_pool); mempool_destroy(phba->mbox_mem_pool); pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); pci_pool_destroy(phba->lpfc_mbuf_pool); + phba->lpfc_hbq_pool = NULL; phba->nlp_mem_pool = NULL; phba->mbox_mem_pool = NULL; phba->lpfc_scsi_dma_buf_pool = NULL; @@ -201,3 +213,20 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) spin_unlock_irqrestore(&phba->hbalock, iflags); return; } + + +void * +lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) +{ + void *ret; + ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle); + return ret; +} + +void +lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma) +{ + pci_pool_free(phba->lpfc_hbq_pool, virt, dma); + return; +} + diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index e6452b88d95..b1727481a1e 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -255,9 +255,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Start discovery - this should just do CLEAR_LA */ lpfc_disc_start(vport); - } else { + } else lpfc_initial_flogi(vport); - } } else { stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; @@ -279,19 +278,16 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, icmd = &cmdiocb->iocb; /* PLOGI chkparm OK */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", phba->brd_no, ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); - if (phba->cfg_fcp_class == 2 && sp->cls2.classValid) { + if (phba->cfg_fcp_class == 2 && sp->cls2.classValid) ndlp->nlp_fcp_info |= CLASS2; - } else { + else ndlp->nlp_fcp_info |= CLASS3; - } ndlp->nlp_class_sup = 0; if (sp->cls1.classValid) @@ -327,6 +323,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, goto out; lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) { @@ -544,9 +541,7 @@ static uint32_t lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - lpfc_printf_log(vport->phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY, "%d:0253 Illegal State Transition: node x%x event x%x, " "state x%x Data: x%x x%x\n", vport->phba->brd_no, @@ -728,9 +723,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, goto out; /* PLOGI chkparm OK */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0121 PLOGI chkparm OK " "Data: x%x x%x x%x x%x\n", phba->brd_no, @@ -1105,9 +1098,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, if (mb->mbxStatus) { /* RegLogin failed */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0246 RegLogin failed Data: x%x x%x x%x\n", phba->brd_no, did, mb->mbxStatus, vport->port_state); @@ -1470,15 +1461,12 @@ static uint32_t lpfc_rcv_prlo_mapped_node(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 = (struct lpfc_iocbq *) arg; /* flush the target */ - spin_lock_irq(shost->host_lock); lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); - spin_unlock_irq(shost->host_lock); /* Treat like rcv logo */ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); @@ -1926,9 +1914,7 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, cur_state = ndlp->nlp_state; /* DSM in event on NPort in state */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0211 DSM in event x%x on NPort x%x in state %d " "Data: x%x\n", phba->brd_no, @@ -1938,9 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rc = (func) (vport, ndlp, arg, evt); /* DSM out state on NPort */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0212 DSM out state %d on NPort x%x Data: x%x\n", phba->brd_no, rc, ndlp->nlp_DID, ndlp->nlp_flag); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 6db7ad83cc3..90c88733a4f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -840,7 +840,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = ScsiResult(DID_BUS_BUSY, 0); goto out_fail_command; } - lpfc_cmd = lpfc_get_scsi_buf (phba); + lpfc_cmd = lpfc_get_scsi_buf(phba); if (lpfc_cmd == NULL) { lpfc_printf_log(phba, KERN_INFO, LOG_FCP, "%d:0707 driver's buffer pool is empty, " diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1edac15eed4..6e0b42bcebe 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -65,6 +65,25 @@ typedef enum _lpfc_iocb_type { LPFC_ABORT_IOCB } lpfc_iocb_type; +/* + * SLI-2/SLI-3 provide different sized iocbs. Given a pointer to the start of + * the ring, and the slot number of the desired iocb entry, calc a pointer to + * that entry. + */ +static inline IOCB_t * +lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) +{ + return (IOCB_t *) (((char *) pring->cmdringaddr) + + pring->cmdidx * phba->iocb_cmd_size); +} + +static inline IOCB_t * +lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) +{ + return (IOCB_t *) (((char *) pring->rspringaddr) + + pring->rspidx * phba->iocb_rsp_size); +} + static struct lpfc_iocbq * __lpfc_sli_get_iocbq(struct lpfc_hba *phba) { @@ -180,6 +199,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_RCV_ELS_REQ_CX: case CMD_RCV_SEQUENCE64_CX: case CMD_RCV_ELS_REQ64_CX: + case CMD_IOCB_RCV_SEQ64_CX: + case CMD_IOCB_RCV_ELS64_CX: + case CMD_IOCB_RCV_CONT64_CX: type = LPFC_UNSOL_IOCB; break; default: @@ -191,14 +213,19 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) } static int -lpfc_sli_ring_map(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +lpfc_sli_ring_map(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; - MAILBOX_t *pmbox = &pmb->mb; - int i, rc; + LPFC_MBOXQ_t *pmb; + MAILBOX_t *pmbox; + int i, rc, ret = 0; + pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) + return -ENOMEM; + pmbox = &pmb->mb; + phba->link_state = LPFC_INIT_MBX_CMDS; for (i = 0; i < psli->num_rings; i++) { - phba->link_state = LPFC_INIT_MBX_CMDS; lpfc_config_ring(phba, i, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { @@ -213,10 +240,12 @@ lpfc_sli_ring_map(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmbox->mbxStatus, i); phba->link_state = LPFC_HBA_ERROR; - return -ENXIO; + ret = -ENXIO; + break; } } - return 0; + mempool_free(pmb, phba->mbox_mem_pool); + return ret; } static int @@ -255,9 +284,10 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) static IOCB_t * lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; + struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : + &phba->slim2p->mbx.us.s2.port[pring->ringno]; uint32_t max_cmd_idx = pring->numCiocb; - IOCB_t *iocb = NULL; if ((pring->next_cmdidx == pring->cmdidx) && (++pring->next_cmdidx >= max_cmd_idx)) @@ -291,9 +321,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return NULL; } - iocb = IOCB_ENTRY(pring->cmdringaddr, pring->cmdidx); - - return iocb; + return lpfc_cmd_iocb(phba, pring); } uint16_t @@ -390,8 +418,7 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * driver will put a command into. */ pring->cmdidx = pring->next_cmdidx; - writel(pring->cmdidx, phba->MBslimaddr - + (SLIMOFF + (pring->ringno * 2)) * 4); + writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); } static void @@ -462,7 +489,9 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) static void lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno) { - struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[ringno]; + struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[ringno] : + &phba->slim2p->mbx.us.s2.port[ringno]; unsigned long iflags; /* If the ring is active, flag it */ @@ -481,6 +510,168 @@ lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno) spin_unlock_irqrestore(&phba->hbalock, iflags); } +struct lpfc_hbq_entry * +lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) +{ + struct hbq_s *hbqp = &phba->hbqs[hbqno]; + + if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx && + ++hbqp->next_hbqPutIdx >= hbqp->entry_count) + hbqp->next_hbqPutIdx = 0; + + if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) { + uint32_t raw_index = readl(&phba->hbq_get[hbqno]); + uint32_t getidx = le32_to_cpu(raw_index); + + hbqp->local_hbqGetIdx = getidx; + + if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) { + lpfc_printf_log(phba, KERN_ERR, + LOG_SLI, + "%d:1802 HBQ %d: local_hbqGetIdx " + "%u is > than hbqp->entry_count %u\n", + phba->brd_no, hbqno, + hbqp->local_hbqGetIdx, + hbqp->entry_count); + + phba->link_state = LPFC_HBA_ERROR; + return NULL; + } + + if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx) + return NULL; + } + + return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx; +} + +void +lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) +{ + uint32_t i; + + if (!phba->hbq_buffer_pool) + return; + /* Return all memory used by all HBQs */ + for (i = 0; i < phba->hbq_buffer_count; i++) { + lpfc_hbq_free(phba, phba->hbq_buffer_pool[i].dbuf.virt, + phba->hbq_buffer_pool[i].dbuf.phys); + } + kfree(phba->hbq_buffer_pool); + phba->hbq_buffer_pool = NULL; +} + +static void +lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, + struct hbq_dmabuf *hbq_buf_desc) +{ + struct lpfc_hbq_entry *hbqe; + + /* Get next HBQ entry slot to use */ + hbqe = lpfc_sli_next_hbq_slot(phba, hbqno); + if (hbqe) { + struct hbq_s *hbqp = &phba->hbqs[hbqno]; + + hbqe->bde.addrHigh = putPaddrHigh(hbq_buf_desc->dbuf.phys); + hbqe->bde.addrLow = putPaddrLow(hbq_buf_desc->dbuf.phys); + hbqe->bde.tus.f.bdeSize = FCELSSIZE; + hbqe->bde.tus.f.bdeFlags = 0; + hbqe->buffer_tag = hbq_buf_desc->tag; + /* Sync SLIM */ + hbqp->hbqPutIdx = hbqp->next_hbqPutIdx; + writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno); + /* flush */ + readl(phba->hbq_put + hbqno); + phba->hbq_buff_count++; + } +} + +static void +lpfc_sli_fill_hbq(struct lpfc_hba *phba, uint32_t hbqno, uint32_t buffer_index) +{ + struct hbq_dmabuf *hbq_buf_desc; + uint32_t i; + + for (i = 0; i < phba->hbqs[hbqno].entry_count; i++) { + /* Search hbqbufq, from the begining, + * looking for an unused entry + */ + phba->hbq_buffer_pool[buffer_index + i].tag |= hbqno << 16; + hbq_buf_desc = phba->hbq_buffer_pool + buffer_index + i; + lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf_desc); + } +} + +int +lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *phba) +{ + return 0; +} + +static int +lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba) +{ + uint32_t buffer_index = 0; + uint32_t hbqno; + + /* Populate HBQ entries */ + for (hbqno = 0; hbqno < phba->hbq_count; ++hbqno) { + /* Find ring associated with HBQ */ + + lpfc_sli_fill_hbq(phba, hbqno, buffer_index); + buffer_index += phba->hbqs[hbqno].entry_count; + } + return 0; +} + +struct hbq_dmabuf * +lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) +{ + if ((tag & 0xffff) < phba->hbq_buffer_count) + return phba->hbq_buffer_pool + (tag & 0xffff); + + lpfc_printf_log(phba, KERN_ERR, + LOG_SLI, + "%d:1803 Bad hbq tag. Data: x%x x%x\n", + phba->brd_no, tag, + phba->hbq_buffer_count); + return NULL; +} + +void +lpfc_sli_hbqbuf_free(struct lpfc_hba *phba, void *virt, dma_addr_t phys) +{ + uint32_t i, hbqno; + + for (i = 0; i < phba->hbq_buffer_count; i++) { + /* Search hbqbufq, from the begining, looking for a match on + phys */ + if (phba->hbq_buffer_pool[i].dbuf.phys == phys) { + hbqno = phba->hbq_buffer_pool[i].tag >> 16; + lpfc_sli_hbq_to_firmware(phba, hbqno, + phba->hbq_buffer_pool + i); + return; + } + } + + lpfc_printf_log(phba, KERN_ERR, + LOG_SLI, + "%d:1804 Cannot find virtual addr for " + "mapped buf. Data x%llx\n", + phba->brd_no, (unsigned long long) phys); +} + +void +lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp) +{ + uint32_t hbqno; + + if (sp) { + hbqno = sp->tag >> 16; + lpfc_sli_hbq_to_firmware(phba, hbqno, sp); + } +} + static int lpfc_sli_chk_mbx_command(uint8_t mbxCommand) { @@ -757,7 +948,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, match = 0; irsp = &(saveq->iocb); if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) - || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)) { + || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) + || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX) + || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) { Rctl = FC_ELS_REQ; Type = FC_ELS_DATA; } else { @@ -769,7 +962,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* Firmware Workaround */ if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) && - (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX)) { + (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX || + irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { Rctl = FC_ELS_REQ; Type = FC_ELS_DATA; w5p->hcsw.Rctl = Rctl; @@ -906,7 +1100,10 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, static void lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; + struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : + &phba->slim2p->mbx.us.s2.port[pring->ringno]; + /* * Ring handler: portRspPut is bigger then * rsp ring @@ -945,14 +1142,15 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) uint32_t portRspPut, portRspMax; int type; uint32_t rsp_cmpl = 0; - void __iomem *to_slim; uint32_t ha_copy; unsigned long iflags; pring->stats.iocb_event++; - /* The driver assumes SLI-2 mode */ - pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; + pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : + &phba->slim2p->mbx.us.s2.port[pring->ringno]; + /* * The next available response entry should never exceed the maximum @@ -967,9 +1165,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) rmb(); while (pring->rspidx != portRspPut) { - - entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); - + entry = lpfc_resp_iocb(phba, pring); if (++pring->rspidx >= portRspMax) pring->rspidx = 0; @@ -1050,9 +1246,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) * been updated, sync the pgp->rspPutInx and fetch the new port * response put pointer. */ - to_slim = phba->MBslimaddr + - (SLIMOFF + (pring->ringno * 2) + 1) * 4; - writeb(pring->rspidx, to_slim); + writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); if (pring->rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); @@ -1096,7 +1290,9 @@ static int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) { - struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; + struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : + &phba->slim2p->mbx.us.s2.port[pring->ringno]; IOCB_t *irsp = NULL; IOCB_t *entry = NULL; struct lpfc_iocbq *cmdiocbq = NULL; @@ -1107,7 +1303,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, lpfc_iocb_type type; unsigned long iflag; uint32_t rsp_cmpl = 0; - void __iomem *to_slim; spin_lock_irqsave(&phba->hbalock, iflag); pring->stats.iocb_event++; @@ -1131,14 +1326,14 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * structure. The copy involves a byte-swap since the * network byte order and pci byte orders are different. */ - entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); + entry = lpfc_resp_iocb(phba, pring); if (++pring->rspidx >= portRspMax) pring->rspidx = 0; lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, - sizeof(IOCB_t)); + phba->iocb_rsp_size); INIT_LIST_HEAD(&(rspiocbq.list)); irsp = &rspiocbq.iocb; @@ -1222,9 +1417,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * been updated, sync the pgp->rspPutInx and fetch the new port * response put pointer. */ - to_slim = phba->MBslimaddr + - (SLIMOFF + (pring->ringno * 2) + 1) * 4; - writel(pring->rspidx, to_slim); + writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); if (pring->rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); @@ -1258,7 +1451,9 @@ int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) { - struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; + struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? + &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : + &phba->slim2p->mbx.us.s2.port[pring->ringno]; IOCB_t *entry; IOCB_t *irsp = NULL; struct lpfc_iocbq *rspiocbp = NULL; @@ -1271,7 +1466,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, uint32_t portRspPut, portRspMax; int rc = 1; unsigned long iflag; - void __iomem *to_slim; spin_lock_irqsave(&phba->hbalock, iflag); pring->stats.iocb_event++; @@ -1287,9 +1481,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, * Ring handler: portRspPut is bigger then * rsp ring */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0303 Ring %d handler: portRspPut %d " "is bigger then rsp ring %d\n", phba->brd_no, @@ -1319,7 +1511,8 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, * the ulpLe field is set, the entire Command has been * received. */ - entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); + entry = lpfc_resp_iocb(phba, pring); + rspiocbp = __lpfc_sli_get_iocbq(phba); if (rspiocbp == NULL) { printk(KERN_ERR "%s: out of buffers! Failing " @@ -1327,15 +1520,14 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, break; } - lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof(IOCB_t)); + lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, + phba->iocb_rsp_size); irsp = &rspiocbp->iocb; if (++pring->rspidx >= portRspMax) pring->rspidx = 0; - to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) - + 1) * 4; - writel(pring->rspidx, to_slim); + writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); if (list_empty(&(pring->iocb_continueq))) { list_add(&rspiocbp->list, &(pring->iocb_continueq)); @@ -1361,21 +1553,31 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, if (irsp->ulpStatus) { /* Rsp ring error: IOCB */ - lpfc_printf_log(phba, - KERN_WARNING, - LOG_SLI, - "%d:0328 Rsp Ring %d error: IOCB Data: " - "x%x x%x x%x x%x x%x x%x x%x x%x\n", - phba->brd_no, - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7)); + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "%d:0328 Rsp Ring %d error: " + "IOCB Data: " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x " + "x%x x%x x%x x%x\n", + phba->brd_no, + pring->ringno, + irsp->un.ulpWord[0], + irsp->un.ulpWord[1], + irsp->un.ulpWord[2], + irsp->un.ulpWord[3], + irsp->un.ulpWord[4], + irsp->un.ulpWord[5], + *(((uint32_t *) irsp) + 6), + *(((uint32_t *) irsp) + 7), + *(((uint32_t *) irsp) + 8), + *(((uint32_t *) irsp) + 9), + *(((uint32_t *) irsp) + 10), + *(((uint32_t *) irsp) + 11), + *(((uint32_t *) irsp) + 12), + *(((uint32_t *) irsp) + 13), + *(((uint32_t *) irsp) + 14), + *(((uint32_t *) irsp) + 15)); } /* @@ -1659,13 +1861,9 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) psli = &phba->sli; /* Kill HBA */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "%d:0329 Kill HBA Data: x%x x%x\n", - phba->brd_no, - phba->pport->port_state, - psli->sli_flag); + phba->brd_no, phba->pport->port_state, psli->sli_flag); if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) == 0) @@ -1857,13 +2055,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (i++ >= 20) { /* Adapter failed to init, timeout, status reg */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0436 Adapter failed to init, " "timeout, status reg x%x\n", - phba->brd_no, - status); + phba->brd_no, status); phba->link_state = LPFC_HBA_ERROR; return -ETIMEDOUT; } @@ -1873,9 +2068,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0437 Adapter failed to init, " "chipset, status reg x%x\n", phba->brd_no, @@ -1905,9 +2098,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (status & HS_FFERM) { /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0438 Adapter failed to init, chipset, " "status reg x%x\n", phba->brd_no, @@ -1926,8 +2117,145 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) return 0; } +static struct hbq_dmabuf * +lpfc_alloc_hbq_buffers(struct lpfc_hba *phba, int count) +{ + struct hbq_dmabuf *hbq_buffer_pool; + int i; + + hbq_buffer_pool = kmalloc(count * sizeof(struct hbq_dmabuf), + GFP_KERNEL); + if (!hbq_buffer_pool) + goto out; + + for (i = 0; i < count; ++i) { + hbq_buffer_pool[i].dbuf.virt = + lpfc_hbq_alloc(phba, MEM_PRI, + &hbq_buffer_pool[i].dbuf.phys); + if (hbq_buffer_pool[i].dbuf.virt == NULL) + goto alloc_failed; + hbq_buffer_pool[i].tag = i; + } + goto out; + +alloc_failed: + while (--i >= 0) + lpfc_hbq_free(phba, hbq_buffer_pool[i].dbuf.virt, + hbq_buffer_pool[i].dbuf.phys); + kfree(hbq_buffer_pool); + hbq_buffer_pool = NULL; + +out: + phba->hbq_buffer_pool = hbq_buffer_pool; + return hbq_buffer_pool; +} + +static struct lpfc_hbq_init lpfc_els_hbq = { + .rn = 1, + .entry_count = 1200, + .mask_count = 0, + .profile = 0, + .ring_mask = 1 << LPFC_ELS_RING, +}; + +static struct lpfc_hbq_init *lpfc_hbq_definitions[] = { + &lpfc_els_hbq, +}; + +static int +lpfc_sli_hbq_count(void) +{ + return ARRAY_SIZE(lpfc_hbq_definitions); +} + +static int +lpfc_sli_hbq_entry_count(void) +{ + int hbq_count = lpfc_sli_hbq_count(); + int count = 0; + int i; + + for (i = 0; i < hbq_count; ++i) + count += lpfc_hbq_definitions[i]->entry_count; + return count; +} + int -lpfc_sli_hba_setup(struct lpfc_hba *phba) +lpfc_sli_hbq_size(void) +{ + return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry); +} + +static int +lpfc_sli_hbq_setup(struct lpfc_hba *phba) +{ + int hbq_count = lpfc_sli_hbq_count(); + LPFC_MBOXQ_t *pmb; + MAILBOX_t *pmbox; + uint32_t hbqno; + uint32_t hbq_entry_index; + uint32_t hbq_buffer_count; + + /* count hbq buffers */ + hbq_buffer_count = lpfc_sli_hbq_entry_count(); + if (!lpfc_alloc_hbq_buffers(phba, hbq_buffer_count)) + return -ENOMEM; + + phba->hbq_buffer_count = hbq_buffer_count; + + /* Get a Mailbox buffer to setup mailbox + * commands for HBA initialization + */ + pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + + if (!pmb) + return -ENOMEM; + + pmbox = &pmb->mb; + + /* Initialize the struct lpfc_sli_hbq structure for each hbq */ + phba->link_state = LPFC_INIT_MBX_CMDS; + + hbq_entry_index = 0; + for (hbqno = 0; hbqno < hbq_count; ++hbqno) { + phba->hbqs[hbqno].next_hbqPutIdx = 0; + phba->hbqs[hbqno].hbqPutIdx = 0; + phba->hbqs[hbqno].local_hbqGetIdx = 0; + phba->hbqs[hbqno].entry_count = + lpfc_hbq_definitions[hbqno]->entry_count; + lpfc_config_hbq(phba, lpfc_hbq_definitions[hbqno], + hbq_entry_index, pmb); + hbq_entry_index += phba->hbqs[hbqno].entry_count; + + if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { + /* Adapter failed to init, mbxCmd CFG_RING, + mbxStatus , ring */ + + lpfc_printf_log(phba, KERN_ERR, + LOG_SLI, + "%d:1805 Adapter failed to init. " + "Data: x%x x%x x%x\n", + phba->brd_no, pmbox->mbxCommand, + pmbox->mbxStatus, hbqno); + + phba->link_state = LPFC_HBA_ERROR; + mempool_free(pmb, phba->mbox_mem_pool); + /* Free all HBQ memory */ + lpfc_sli_hbqbuf_free_all(phba); + return ENXIO; + } + } + phba->hbq_count = hbq_count; + + /* Initially populate or replenish the HBQs */ + lpfc_sli_hbqbuf_fill_hbqs(phba); + mempool_free(pmb, phba->mbox_mem_pool); + + return 0; +} + +static int +lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode) { LPFC_MBOXQ_t *pmb; uint32_t resetcount = 0, rc = 0, done = 0; @@ -1938,6 +2266,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) return -ENOMEM; } + phba->sli_rev = sli_mode; while (resetcount < 2 && !done) { spin_lock_irq(&phba->hbalock); phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE; @@ -1954,14 +2283,14 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); resetcount++; - /* Call pre CONFIG_PORT mailbox command initialization. A value of 0 - * means the call was successful. Any other nonzero value is a failure, - * but if ERESTART is returned, the driver may reset the HBA and try - * again. - */ + /* Call pre CONFIG_PORT mailbox command initialization. A + * value of 0 means the call was successful. Any other + * nonzero value is a failure, but if ERESTART is returned, + * the driver may reset the HBA and try again. + */ rc = lpfc_config_port_prep(phba); if (rc == -ERESTART) { - phba->pport->port_state = 0; + phba->link_state = LPFC_LINK_UNKNOWN; continue; } else if (rc) { break; @@ -1970,39 +2299,116 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) phba->link_state = LPFC_INIT_MBX_CMDS; lpfc_config_port(phba, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc == MBX_SUCCESS) - done = 1; - else { + if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "%d:0442 Adapter failed to init, mbxCmd x%x " - "CONFIG_PORT, mbxStatus x%x Data: x%x\n", - phba->brd_no, pmb->mb.mbxCommand, - pmb->mb.mbxStatus, 0); + "%d:0442 Adapter failed to init, " + "mbxCmd x%x CONFIG_PORT, mbxStatus " + "x%x Data: x%x\n", + phba->brd_no, pmb->mb.mbxCommand, + pmb->mb.mbxStatus, 0); spin_lock_irq(&phba->hbalock); phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); rc = -ENXIO; + } else { + done = 1; + /* DBG: Do we need max_vpi, reg_vpi for that matter + phba->max_vpi = 0; + */ } } - if (!done) + + if (!done) { + rc = -EINVAL; + goto do_prep_failed; + } + + if ((pmb->mb.un.varCfgPort.sli_mode == 3) && + (!pmb->mb.un.varCfgPort.cMA)) { + rc = -ENXIO; + goto do_prep_failed; + } + return rc; + + do_prep_failed: + mempool_free(pmb, phba->mbox_mem_pool); + return rc; +} + +int +lpfc_sli_hba_setup(struct lpfc_hba *phba) +{ + uint32_t rc; + int mode = 3; + + switch (lpfc_sli_mode) { + case 2: + mode = 2; + break; + case 0: + case 3: + break; + default: + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "%d:1819 Unrecognized lpfc_sli_mode " + "parameter: %d.\n", + phba->brd_no, lpfc_sli_mode); + + break; + } + + rc = lpfc_do_config_port(phba, mode); + if (rc && lpfc_sli_mode == 3) + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "%d:1820 Unable to select SLI-3. " + "Not supported by adapter.\n", + phba->brd_no); + if (rc && mode != 2) + rc = lpfc_do_config_port(phba, 2); + if (rc) goto lpfc_sli_hba_setup_error; - rc = lpfc_sli_ring_map(phba, pmb); + if (phba->sli_rev == 3) { + phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE; + phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE; + phba->sli3_options |= LPFC_SLI3_ENABLED; + phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; + + } else { + phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE; + phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE; + phba->sli3_options = 0x0; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "%d:0444 Firmware in SLI %x mode.\n", + phba->brd_no, phba->sli_rev); + rc = lpfc_sli_ring_map(phba); if (rc) goto lpfc_sli_hba_setup_error; + /* Init HBQs */ + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + rc = lpfc_sli_hbq_setup(phba); + if (rc) + goto lpfc_sli_hba_setup_error; + } + phba->sli.sli_flag |= LPFC_PROCESS_LA; rc = lpfc_config_port_post(phba); if (rc) goto lpfc_sli_hba_setup_error; - goto lpfc_sli_hba_setup_exit; -lpfc_sli_hba_setup_error: + return rc; + + lpfc_sli_hba_setup_error: phba->link_state = LPFC_HBA_ERROR; -lpfc_sli_hba_setup_exit: - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "%d:0445 Firmware initialization failed\n", + phba->brd_no); return rc; } @@ -2027,7 +2433,7 @@ lpfc_mbox_timeout(unsigned long ptr) uint32_t tmo_posted; spin_lock_irqsave(&phba->pport->work_port_lock, iflag); - tmo_posted = (phba->pport->work_port_events & WORKER_MBOX_TMO) == 0; + tmo_posted = (phba->pport->work_port_events & WORKER_MBOX_TMO); if (!tmo_posted) phba->pport->work_port_events |= WORKER_MBOX_TMO; spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); @@ -2051,9 +2457,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) } /* Mbox cmd timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "%d:0310 Mailbox command x%x timeout Data: x%x x%x x%p\n", phba->brd_no, mb->mbxCommand, @@ -2105,13 +2509,25 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) volatile uint32_t word0, ldata; void __iomem *to_slim; + if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl && + pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) { + if(!pmbox->vport) { + lpfc_printf_log(phba, KERN_ERR, + LOG_MBOX, + "%d:1806 Mbox x%x failed. No vport\n", + phba->brd_no, + pmbox->mb.mbxCommand); + dump_stack(); + return MBXERR_ERROR; + } + } + /* If the PCI channel is in offline state, do not post mbox. */ if (unlikely(pci_channel_offline(phba->pcidev))) return MBX_NOT_FINISHED; spin_lock_irqsave(&phba->hbalock, drvr_flag); psli = &phba->sli; - mb = &pmbox->mb; status = MBX_SUCCESS; @@ -2172,15 +2588,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) lpfc_mbox_put(phba, pmbox); /* Mbox cmd issue - BUSY */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "%d:0308 Mbox cmd issue - BUSY Data: x%x x%x x%x x%x\n", phba->brd_no, - mb->mbxCommand, - phba->pport->port_state, - psli->sli_flag, - flag); + mb->mbxCommand, phba->pport->port_state, + psli->sli_flag, flag); psli->slistat.mbox_busy++; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); @@ -2223,15 +2635,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) } /* Mailbox cmd issue */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "%d:0309 Mailbox cmd x%x issue Data: x%x x%x x%x\n", phba->brd_no, - mb->mbxCommand, - phba->pport->port_state, - psli->sli_flag, - flag); + mb->mbxCommand, phba->pport->port_state, + psli->sli_flag, flag); psli->slistat.mbox_cmd++; evtctr = psli->slistat.mbox_event; @@ -2526,7 +2934,7 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) int lpfc_sli_setup(struct lpfc_hba *phba) { - int i, totiocb = 0; + int i, totiocbsize = 0; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; @@ -2551,9 +2959,15 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sizeCiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_CMD_SIZE : + SLI2_IOCB_CMD_SIZE; + pring->sizeRiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_RSP_SIZE : + SLI2_IOCB_RSP_SIZE; pring->iotag_ctr = 0; pring->iotag_max = - (phba->cfg_hba_queue_depth * 2); + (phba->cfg_hba_queue_depth * 2); pring->fast_iotag = pring->iotag_max; pring->num_mask = 0; break; @@ -2561,6 +2975,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) /* numCiocb and numRiocb are used in config_port */ pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; + pring->sizeCiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_CMD_SIZE : + SLI2_IOCB_CMD_SIZE; + pring->sizeRiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_RSP_SIZE : + SLI2_IOCB_RSP_SIZE; pring->iotag_max = phba->cfg_hba_queue_depth; pring->num_mask = 0; break; @@ -2568,6 +2988,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) /* numCiocb and numRiocb are used in config_port */ pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; + pring->sizeCiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_CMD_SIZE : + SLI2_IOCB_CMD_SIZE; + pring->sizeRiocb = (phba->sli_rev == 3) ? + SLI3_IOCB_RSP_SIZE : + SLI2_IOCB_RSP_SIZE; pring->fast_iotag = 0; pring->iotag_ctr = 0; pring->iotag_max = 4096; @@ -2576,36 +3002,38 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->prt[0].rctl = FC_ELS_REQ; pring->prt[0].type = FC_ELS_DATA; pring->prt[0].lpfc_sli_rcv_unsol_event = - lpfc_els_unsol_event; + lpfc_els_unsol_event; pring->prt[1].profile = 0; /* Mask 1 */ pring->prt[1].rctl = FC_ELS_RSP; pring->prt[1].type = FC_ELS_DATA; pring->prt[1].lpfc_sli_rcv_unsol_event = - lpfc_els_unsol_event; + lpfc_els_unsol_event; pring->prt[2].profile = 0; /* Mask 2 */ /* NameServer Inquiry */ pring->prt[2].rctl = FC_UNSOL_CTL; /* NameServer */ pring->prt[2].type = FC_COMMON_TRANSPORT_ULP; pring->prt[2].lpfc_sli_rcv_unsol_event = - lpfc_ct_unsol_event; + lpfc_ct_unsol_event; pring->prt[3].profile = 0; /* Mask 3 */ /* NameServer response */ pring->prt[3].rctl = FC_SOL_CTL; /* NameServer */ pring->prt[3].type = FC_COMMON_TRANSPORT_ULP; pring->prt[3].lpfc_sli_rcv_unsol_event = - lpfc_ct_unsol_event; + lpfc_ct_unsol_event; break; } - totiocb += (pring->numCiocb + pring->numRiocb); + totiocbsize += (pring->numCiocb * pring->sizeCiocb) + + (pring->numRiocb * pring->sizeRiocb); } - if (totiocb > MAX_SLI2_IOCB) { + if (totiocbsize > MAX_SLIM_IOCB_SIZE) { /* Too many cmd / rsp ring entries in SLI2 SLIM */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0462 Too many cmd / rsp ring entries in " - "SLI2 SLIM Data: x%x x%x\n", - phba->brd_no, totiocb, MAX_SLI2_IOCB); + "SLI2 SLIM Data: x%x x%lx\n", + phba->brd_no, totiocbsize, + (unsigned long) MAX_SLIM_IOCB_SIZE); } if (phba->cfg_multi_ring_support == 2) lpfc_extra_ring_setup(phba); @@ -2689,6 +3117,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) phba->pport->work_port_events &= ~WORKER_MBOX_TMO; spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); + spin_lock_irqsave(&phba->hbalock, flags); pmb = psli->mbox_active; if (pmb) { psli->mbox_active = NULL; @@ -2708,6 +3137,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) } INIT_LIST_HEAD(&psli->mboxq); + /* Free all HBQ memory */ + lpfc_sli_hbqbuf_free_all(phba); + return 1; } @@ -3075,11 +3507,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0); if (retval == IOCB_SUCCESS) { timeout_req = timeout * HZ; - spin_unlock_irq(&phba->hbalock); timeleft = wait_event_timeout(done_q, piocb->iocb_flag & LPFC_IO_WAKE, timeout_req); - spin_lock_irq(&phba->hbalock); if (piocb->iocb_flag & LPFC_IO_WAKE) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3164,13 +3594,25 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) { struct lpfc_vport *vport = phba->pport; int i = 0; + uint32_t ha_copy; while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) { if (i++ > LPFC_MBOX_TMO * 1000) return 1; - if (lpfc_sli_handle_mb_event(phba) == 0) - i = 0; + /* + * Call lpfc_sli_handle_mb_event only if a mailbox cmd + * did finish. This way we won't get the misleading + * "Stray Mailbox Interrupt" message. + */ + spin_lock_irq(&phba->hbalock); + ha_copy = phba->work_ha; + phba->work_ha &= ~HA_MBATT; + spin_unlock_irq(&phba->hbalock); + + if (ha_copy & HA_MBATT) + if (lpfc_sli_handle_mb_event(phba) == 0) + i = 0; msleep(1); } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 0e857e51a2c..190d55a69b2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -138,6 +138,8 @@ struct lpfc_sli_ring { uint8_t ringno; /* ring number */ uint16_t numCiocb; /* number of command iocb's per ring */ uint16_t numRiocb; /* number of rsp iocb's per ring */ + uint16_t sizeCiocb; /* Size of command iocb's in this ring */ + uint16_t sizeRiocb; /* Size of response iocb's in this ring */ uint32_t fast_iotag; /* max fastlookup based iotag */ uint32_t iotag_ctr; /* keeps track of the next iotag to use */ @@ -168,6 +170,29 @@ struct lpfc_sli_ring { struct lpfc_sli_ring *); }; +/* Structure used for configuring rings to a specific profile or rctl / type */ +struct lpfc_hbq_init { + uint32_t rn; /* Receive buffer notification */ + uint32_t entry_count; /* # of entries in HBQ */ + uint32_t headerLen; /* 0 if not profile 4 or 5 */ + uint32_t logEntry; /* Set to 1 if this HBQ used for LogEntry */ + uint32_t profile; /* Selection profile 0=all, 7=logentry */ + uint32_t ring_mask; /* Binds HBQ to a ring e.g. Ring0=b0001, + * ring2=b0100 */ + uint32_t hbq_index; /* index of this hbq in ring .HBQs[] */ + + uint32_t seqlenoff; + uint32_t maxlen; + uint32_t seqlenbcnt; + uint32_t cmdcodeoff; + uint32_t cmdmatch[8]; + uint32_t mask_count; /* number of mask entries in prt array */ + struct hbq_mask hbqMasks[6]; +} ; + +#define LPFC_MAX_HBQ 16 + + /* Structure used to hold SLI statistical counters and info */ struct lpfc_sli_stat { uint64_t mbox_stat_err; /* Mbox cmds completed status error */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 0a793735144..fd10fa16980 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.12_psplit" +#define LPFC_DRIVER_VERSION "8.1.12_sli3" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.3