diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-17 09:50:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-17 09:50:44 -0700 |
commit | aa2638a210ab0d7c6702cd54315365785fce326c (patch) | |
tree | ccc6a99248a1e914fbb90a466b76c98e4f083bc6 /drivers/scsi/lpfc | |
parent | b069e8ed4d5054b1fcd31a98bb2053bde645202f (diff) | |
parent | ea4431906d86686e541de527915ccbe556761b16 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6:
[SCSI] aic79xx: make driver respect nvram for IU and QAS settings
[SCSI] don't attach ULD to Dell Universal Xport
[SCSI] lpfc 8.3.3 : Update driver version to 8.3.3
[SCSI] lpfc 8.3.3 : Add support for Target Reset handler entrypoint
[SCSI] lpfc 8.3.3 : Fix a couple of spin_lock and memory issues and a crash
[SCSI] lpfc 8.3.3 : FC/FCOE discovery fixes
[SCSI] lpfc 8.3.3 : Fix various SLI-3 vs SLI-4 differences
[SCSI] qla2xxx: Resolve a performance issue in interrupt
[SCSI] cnic, bnx2i: Fix build failure when CONFIG_PCI is not set.
[SCSI] nsp_cs: time_out reaches -1
[SCSI] qla2xxx: fix printk format warnings
[SCSI] ncr53c8xx: div reaches -1
[SCSI] compat: don't perform unneeded copy in sg_io code
[SCSI] zfcp: Update FC pass-through support
[SCSI] zfcp: Add FC pass-through support
[SCSI] FC Pass Thru support
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 27 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 35 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 34 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 661 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 264 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 2 |
16 files changed, 610 insertions, 448 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 54056984909..1877d981183 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -457,10 +457,6 @@ struct lpfc_hba { void (*lpfc_scsi_prep_cmnd) (struct lpfc_vport *, struct lpfc_scsi_buf *, struct lpfc_nodelist *); - int (*lpfc_scsi_prep_task_mgmt_cmd) - (struct lpfc_vport *, struct lpfc_scsi_buf *, - unsigned int, uint8_t); - /* IOCB interface function jump table entries */ int (*__lpfc_sli_issue_iocb) (struct lpfc_hba *, uint32_t, diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d73e677201f..fc07be5fbce 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3113,6 +3113,9 @@ sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if ((off + count) > FF_REG_AREA_SIZE) return -ERANGE; @@ -3163,6 +3166,9 @@ sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if (off > FF_REG_AREA_SIZE) return -ERANGE; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 1dbccfd3d02..0e532f072eb 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1732,7 +1732,9 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) uint32_t *ptr, str[4]; uint8_t *fwname; - if (vp->rev.rBit) { + if (phba->sli_rev == LPFC_SLI_REV4) + sprintf(fwrevision, "%s", vp->rev.opFwName); + else if (vp->rev.rBit) { if (psli->sli_flag & LPFC_SLI_ACTIVE) rev = vp->rev.sli2FwRev; else diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 6bdeb14878a..f72fdf23bf1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -168,6 +168,19 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (elsiocb == NULL) return NULL; + /* + * If this command is for fabric controller and HBA running + * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. + */ + if ((did == Fabric_DID) && + bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) && + ((elscmd == ELS_CMD_FLOGI) || + (elscmd == ELS_CMD_FDISC) || + (elscmd == ELS_CMD_LOGO))) + elsiocb->iocb_flag |= LPFC_FIP_ELS; + else + elsiocb->iocb_flag &= ~LPFC_FIP_ELS; + icmd = &elsiocb->iocb; /* fill in BDEs for command */ @@ -6108,9 +6121,17 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, icmd->un.elsreq64.myID = 0; icmd->un.elsreq64.fl = 1; - /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ - icmd->ulpCt_h = 1; - icmd->ulpCt_l = 0; + if (phba->sli_rev == LPFC_SLI_REV4) { + /* FDISC needs to be 1 for WQE VPI */ + elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1; + elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ; + /* Set the ulpContext to the vpi */ + elsiocb->iocb.ulpContext = vport->vpi + phba->vpi_base; + } else { + /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ + icmd->ulpCt_h = 1; + icmd->ulpCt_l = 0; + } pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FDISC; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 35c41ae75be..ed46b24a338 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1197,6 +1197,11 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, { struct lpfc_fcf_conn_entry *conn_entry; + /* If FCF not available return 0 */ + if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || + !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)) + return 0; + if (!phba->cfg_enable_fip) { *boot_flag = 0; *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, @@ -1216,6 +1221,14 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, *boot_flag = 0; *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record); + + /* + * When there are no FCF connect entries, use driver's default + * addressing mode - FPMA. + */ + if (*addr_mode & LPFC_FCF_FPMA) + *addr_mode = LPFC_FCF_FPMA; + *vlan_id = 0xFFFF; return 1; } @@ -1241,6 +1254,14 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, } /* + * If connection record does not support any addressing mode, + * skip the FCF record. + */ + if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record) + & (LPFC_FCF_FPMA | LPFC_FCF_SPMA))) + continue; + + /* * Check if the connection record specifies a required * addressing mode. */ @@ -1272,6 +1293,11 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, else *boot_flag = 0; + /* + * If user did not specify any addressing mode, or if the + * prefered addressing mode specified by user is not supported + * by FCF, allow fabric to pick the addressing mode. + */ *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record); /* @@ -1297,12 +1323,6 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, !(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && (*addr_mode & LPFC_FCF_FPMA)) *addr_mode = LPFC_FCF_FPMA; - /* - * If user did not specify any addressing mode, use FPMA if - * possible else use SPMA. - */ - else if (*addr_mode & LPFC_FCF_FPMA) - *addr_mode = LPFC_FCF_FPMA; if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) *vlan_id = conn_entry->conn_rec.vlan_tag; @@ -1864,7 +1884,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport->fc_flag &= ~FC_BYPASSED_MODE; spin_unlock_irq(shost->host_lock); - if (((phba->fc_eventTag + 1) < la->eventTag) || + if ((phba->fc_eventTag < la->eventTag) || (phba->fc_eventTag == la->eventTag)) { phba->fc_stat.LinkMultiEvent++; if (la->attType == AT_LINK_UP) @@ -2925,6 +2945,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_no_rpi(phba, ndlp); ndlp->nlp_rpi = 0; ndlp->nlp_flag &= ~NLP_RPI_VALID; + ndlp->nlp_flag &= ~NLP_NPR_ADISC; return 1; } return 0; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 02aa016b93e..8a3a026667e 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1183,7 +1183,6 @@ typedef struct { #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 #define PCI_VENDOR_ID_SERVERENGINE 0x19a2 #define PCI_DEVICE_ID_TIGERSHARK 0x0704 -#define PCI_DEVICE_ID_TIGERSHARK_S 0x0705 #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 39c34b3ad29..2995d128f07 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -422,9 +422,9 @@ struct lpfc_wqe_generic{ #define lpfc_wqe_gen_pri_WORD word10 uint32_t word11; #define lpfc_wqe_gen_cq_id_SHIFT 16 -#define lpfc_wqe_gen_cq_id_MASK 0x000003FF +#define lpfc_wqe_gen_cq_id_MASK 0x0000FFFF #define lpfc_wqe_gen_cq_id_WORD word11 -#define LPFC_WQE_CQ_ID_DEFAULT 0x3ff +#define LPFC_WQE_CQ_ID_DEFAULT 0xffff #define lpfc_wqe_gen_wqec_SHIFT 7 #define lpfc_wqe_gen_wqec_MASK 0x00000001 #define lpfc_wqe_gen_wqec_WORD word11 @@ -1128,7 +1128,7 @@ struct fcf_record { #define lpfc_fcf_record_mac_5_WORD word4 #define lpfc_fcf_record_fcf_avail_SHIFT 16 #define lpfc_fcf_record_fcf_avail_MASK 0x000000FF -#define lpfc_fcf_record_fc_avail_WORD word4 +#define lpfc_fcf_record_fcf_avail_WORD word4 #define lpfc_fcf_record_mac_addr_prov_SHIFT 24 #define lpfc_fcf_record_mac_addr_prov_MASK 0x000000FF #define lpfc_fcf_record_mac_addr_prov_WORD word4 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2f5907f92ee..fc67cc65c63 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -428,7 +428,8 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Reset the DFT_HBA_Q_DEPTH to the max xri */ if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) phba->cfg_hba_queue_depth = - mb->un.varRdConfig.max_xri + 1; + (mb->un.varRdConfig.max_xri + 1) - + lpfc_sli4_get_els_iocb_cnt(phba); phba->lmt = mb->un.varRdConfig.lmt; @@ -1646,10 +1647,6 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) oneConnect = 1; m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"}; break; - case PCI_DEVICE_ID_TIGERSHARK_S: - oneConnect = 1; - m = (typeof(m)) {"OCe10100-F-S", max_speed, "PCIe"}; - break; default: m = (typeof(m)){ NULL }; break; @@ -3543,6 +3540,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) /* Free the allocated rpi headers. */ lpfc_sli4_remove_rpi_hdrs(phba); + lpfc_sli4_remove_rpis(phba); /* Free the ELS sgl list */ lpfc_free_active_sgl(phba); @@ -7184,16 +7182,19 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) { int max_xri = phba->sli4_hba.max_cfg_param.max_xri; - if (max_xri <= 100) - return 4; - else if (max_xri <= 256) - return 8; - else if (max_xri <= 512) - return 16; - else if (max_xri <= 1024) - return 32; - else - return 48; + if (phba->sli_rev == LPFC_SLI_REV4) { + if (max_xri <= 100) + return 4; + else if (max_xri <= 256) + return 8; + else if (max_xri <= 512) + return 16; + else if (max_xri <= 1024) + return 32; + else + return 48; + } else + return 0; } /** @@ -7642,7 +7643,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) switch (dev_id) { case PCI_DEVICE_ID_TIGERSHARK: - case PCI_DEVICE_ID_TIGERSHARK_S: rc = lpfc_pci_probe_one_s4(pdev, pid); break; default: @@ -7941,8 +7941,6 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK_S, - PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index b9b451c0901..3423571dd1b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1631,6 +1631,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, /* In case of malloc fails, proceed with whatever we have */ if (!viraddr) break; + memset(viraddr, 0, PAGE_SIZE); mbox->sge_array->addr[pagen] = viraddr; /* Keep the first page for later sub-header construction */ if (pagen == 0) @@ -1715,8 +1716,10 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) /* Set up host requested features. */ bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1); - /* Virtual fabrics and FIPs are not supported yet. */ - bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0); + if (phba->cfg_enable_fip) + bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0); + else + bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 1); /* Enable DIF (block guard) only if configured to do so. */ if (phba->cfg_enable_bg) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 09f659f77bb..3e74136f1ed 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -497,7 +497,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); else lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if ((ndlp->nlp_type & NLP_FABRIC) && + if ((ndlp->nlp_DID == Fabric_DID) && vport->port_type == LPFC_NPIV_PORT) { lpfc_linkdown_port(vport); mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7991ba1980a..da59c4f0168 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -116,6 +116,27 @@ lpfc_debug_save_dif(struct scsi_cmnd *cmnd) } /** + * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. + * @phba: Pointer to HBA object. + * @lpfc_cmd: lpfc scsi command object pointer. + * + * This function is called from the lpfc_prep_task_mgmt_cmd function to + * set the last bit in the response sge entry. + **/ +static void +lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, + struct lpfc_scsi_buf *lpfc_cmd) +{ + struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; + if (sgl) { + sgl += 1; + sgl->word2 = le32_to_cpu(sgl->word2); + bf_set(lpfc_sli4_sge_last, sgl, 1); + sgl->word2 = cpu_to_le32(sgl->word2); + } +} + +/** * lpfc_update_stats - Update statistical data for the command completion * @phba: Pointer to HBA object. * @lpfc_cmd: lpfc scsi command object pointer. @@ -1978,7 +1999,7 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, } /** - * lpfc_scsi_unprep_dma_buf_s3 - Un-map DMA mapping of SG-list for SLI3 dev + * lpfc_scsi_unprep_dma_buf - Un-map DMA mapping of SG-list for dev * @phba: The HBA for which this call is being executed. * @psb: The scsi buffer which is going to be un-mapped. * @@ -1986,7 +2007,7 @@ lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, * field of @lpfc_cmd for device with SLI-3 interface spec. **/ static void -lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) +lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) { /* * There are only two special cases to consider. (1) the scsi command @@ -2003,36 +2024,6 @@ lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) } /** - * lpfc_scsi_unprep_dma_buf_s4 - Un-map DMA mapping of SG-list for SLI4 dev - * @phba: The Hba for which this call is being executed. - * @psb: The scsi buffer which is going to be un-mapped. - * - * This routine does DMA un-mapping of scatter gather list of scsi command - * field of @lpfc_cmd for device with SLI-4 interface spec. If we have to - * remove the sgl for this scsi buffer then we will do it here. For now - * we should be able to just call the sli3 unprep routine. - **/ -static void -lpfc_scsi_unprep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - lpfc_scsi_unprep_dma_buf_s3(phba, psb); -} - -/** - * lpfc_scsi_unprep_dma_buf - Wrapper function for unmap DMA mapping of SG-list - * @phba: The Hba for which this call is being executed. - * @psb: The scsi buffer which is going to be un-mapped. - * - * This routine does DMA un-mapping of scatter gather list of scsi command - * field of @lpfc_cmd for device with SLI-4 interface spec. - **/ -static void -lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - phba->lpfc_scsi_unprep_dma_buf(phba, psb); -} - -/** * lpfc_handler_fcp_err - FCP response handler * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. @@ -2461,7 +2452,7 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) } /** - * lpfc_scsi_prep_cmnd_s3 - Convert scsi cmnd to FCP infor unit for SLI3 dev + * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: The scsi command which needs to send. * @pnode: Pointer to lpfc_nodelist. @@ -2470,7 +2461,7 @@ lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) * to transfer for device with SLI3 interface spec. **/ static void -lpfc_scsi_prep_cmnd_s3(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, +lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_nodelist *pnode) { struct lpfc_hba *phba = vport->phba; @@ -2558,46 +2549,7 @@ lpfc_scsi_prep_cmnd_s3(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } /** - * lpfc_scsi_prep_cmnd_s4 - Convert scsi cmnd to FCP infor unit for SLI4 dev - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: The scsi command which needs to send. - * @pnode: Pointer to lpfc_nodelist. - * - * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer for device with SLI4 interface spec. - **/ -static void -lpfc_scsi_prep_cmnd_s4(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_nodelist *pnode) -{ - /* - * The prep cmnd routines do not touch the sgl or its - * entries. We may not have to do anything different. - * I will leave this function in place until we can - * run some IO through the driver and determine if changes - * are needed. - */ - return lpfc_scsi_prep_cmnd_s3(vport, lpfc_cmd, pnode); -} - -/** - * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: The scsi command which needs to send. - * @pnode: Pointer to lpfc_nodelist. - * - * This routine wraps the actual convert SCSI cmnd function pointer from - * the lpfc_hba struct. - **/ -static inline void -lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_nodelist *pnode) -{ - vport->phba->lpfc_scsi_prep_cmnd(vport, lpfc_cmd, pnode); -} - -/** - * lpfc_scsi_prep_task_mgmt_cmnd_s3 - Convert SLI3 scsi TM cmd to FCP info unit + * lpfc_scsi_prep_task_mgmt_cmnd - Convert SLI3 scsi TM cmd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. * @lun: Logical unit number. @@ -2611,7 +2563,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, * 1 - Success **/ static int -lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport, +lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, unsigned int lun, uint8_t task_mgmt_cmd) @@ -2653,68 +2605,13 @@ lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport, * The driver will provide the timeout mechanism. */ piocb->ulpTimeout = 0; - } else { + } else piocb->ulpTimeout = lpfc_cmd->timeout; - } - - return 1; -} - -/** - * lpfc_scsi_prep_task_mgmt_cmnd_s4 - Convert SLI4 scsi TM cmd to FCP info unit - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. - * @lun: Logical unit number. - * @task_mgmt_cmd: SCSI task management command. - * - * This routine creates FCP information unit corresponding to @task_mgmt_cmd - * for device with SLI-4 interface spec. - * - * Return codes: - * 0 - Error - * 1 - Success - **/ -static int -lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport, - struct lpfc_scsi_buf *lpfc_cmd, - unsigned int lun, - uint8_t task_mgmt_cmd) -{ - /* - * The prep cmnd routines do not touch the sgl or its - * entries. We may not have to do anything different. - * I will leave this function in place until we can - * run some IO through the driver and determine if changes - * are needed. - */ - return lpfc_scsi_prep_task_mgmt_cmd_s3(vport, lpfc_cmd, lun, - task_mgmt_cmd); -} -/** - * lpfc_scsi_prep_task_mgmt_cmnd - Wrapper func convert scsi TM cmd to FCP info - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. - * @lun: Logical unit number. - * @task_mgmt_cmd: SCSI task management command. - * - * This routine wraps the actual convert SCSI TM to FCP information unit - * function pointer from the lpfc_hba struct. - * - * Return codes: - * 0 - Error - * 1 - Success - **/ -static inline int -lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, - struct lpfc_scsi_buf *lpfc_cmd, - unsigned int lun, - uint8_t task_mgmt_cmd) -{ - struct lpfc_hba *phba = vport->phba; + if (vport->phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd); - return phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, - task_mgmt_cmd); + return 1; } /** @@ -2730,23 +2627,19 @@ int lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) { + phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf; + phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd; + phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf; + switch (dev_grp) { case LPFC_PCI_DEV_LP: phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3; phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3; - phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s3; - phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s3; - phba->lpfc_scsi_prep_task_mgmt_cmd = - lpfc_scsi_prep_task_mgmt_cmd_s3; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; break; case LPFC_PCI_DEV_OC: phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4; phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; - phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd_s4; - phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf_s4; - phba->lpfc_scsi_prep_task_mgmt_cmd = - lpfc_scsi_prep_task_mgmt_cmd_s4; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; break; default: @@ -2783,72 +2676,6 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, } /** - * lpfc_scsi_tgt_reset - Target reset handler - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure - * @vport: The virtual port for which this call is being executed. - * @tgt_id: Target ID. - * @lun: Lun number. - * @rdata: Pointer to lpfc_rport_data. - * - * This routine issues a TARGET RESET iocb to reset a target with @tgt_id ID. - * - * Return Code: - * 0x2003 - Error - * 0x2002 - Success. - **/ -static int -lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, - unsigned tgt_id, unsigned int lun, - struct lpfc_rport_data *rdata) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *iocbqrsp; - int ret; - int status; - - if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) - return FAILED; - - lpfc_cmd->rdata = rdata; - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, - FCP_TARGET_RESET); - if (!status) - return FAILED; - - iocbq = &lpfc_cmd->cur_iocbq; - iocbqrsp = lpfc_sli_get_iocbq(phba); - - if (!iocbqrsp) - return FAILED; - - /* Issue Target Reset to TGT <num> */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", - tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); - status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, - iocbq, iocbqrsp, lpfc_cmd->timeout); - if (status != IOCB_SUCCESS) { - if (status == IOCB_TIMEDOUT) { - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; - ret = TIMEOUT_ERROR; - } else - ret = FAILED; - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - } else { - ret = SUCCESS; - lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; - lpfc_cmd->status = iocbqrsp->iocb.ulpStatus; - if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && - (lpfc_cmd->result & IOERR_DRVR_MASK)) - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - } - - lpfc_sli_release_iocbq(phba, iocbqrsp); - return ret; -} - -/** * lpfc_info - Info entry point of scsi_host_template data structure * @host: The scsi host for which this call is being executed. * @@ -3228,156 +3055,334 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) return ret; } +static char * +lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) +{ + switch (task_mgmt_cmd) { + case FCP_ABORT_TASK_SET: + return "ABORT_TASK_SET"; + case FCP_CLEAR_TASK_SET: + return "FCP_CLEAR_TASK_SET"; + case FCP_BUS_RESET: + return "FCP_BUS_RESET"; + case FCP_LUN_RESET: + return "FCP_LUN_RESET"; + case FCP_TARGET_RESET: + return "FCP_TARGET_RESET"; + case FCP_CLEAR_ACA: + return "FCP_CLEAR_ACA"; + case FCP_TERMINATE_TASK: + return "FCP_TERMINATE_TASK"; + default: + return "unknown"; + } +} + /** - * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point - * @cmnd: Pointer to scsi_cmnd data structure. + * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler + * @vport: The virtual port for which this call is being executed. + * @rdata: Pointer to remote port local data + * @tgt_id: Target ID of remote device. + * @lun_id: Lun number for the TMF + * @task_mgmt_cmd: type of TMF to send * - * This routine does a device reset by sending a TARGET_RESET task management - * command. + * This routine builds and sends a TMF (SCSI Task Mgmt Function) to + * a remote port. * - * Return code : - * 0x2003 - Error - * 0x2002 - Success + * Return Code: + * 0x2003 - Error + * 0x2002 - Success. **/ static int -lpfc_device_reset_handler(struct scsi_cmnd *cmnd) +lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, + unsigned tgt_id, unsigned int lun_id, + uint8_t task_mgmt_cmd) { - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_scsi_buf *lpfc_cmd; - struct lpfc_iocbq *iocbq, *iocbqrsp; - struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode = rdata->pnode; - unsigned long later; - int ret = SUCCESS; + struct lpfc_iocbq *iocbq; + struct lpfc_iocbq *iocbqrsp; + int ret; int status; - int cnt; - struct lpfc_scsi_event_header scsi_event; - lpfc_block_error_handler(cmnd); - /* - * If target is not in a MAPPED state, delay the reset until - * target is rediscovered or devloss timeout expires. - */ - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies)) { - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return FAILED; - if (pnode->nlp_state == NLP_STE_MAPPED_NODE) - break; - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - rdata = cmnd->device->hostdata; - if (!rdata) - break; - pnode = rdata->pnode; - } - - scsi_event.event_type = FC_REG_SCSI_EVENT; - scsi_event.subcategory = LPFC_EVENT_TGTRESET; - scsi_event.lun = 0; - memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); - - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(scsi_event), - (char *)&scsi_event, - LPFC_NL_VENDOR_ID); - - if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0721 LUN Reset rport " - "failure: msec x%x rdata x%p\n", - jiffies_to_msecs(jiffies - later), rdata); + if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) return FAILED; - } + lpfc_cmd = lpfc_get_scsi_buf(phba); if (lpfc_cmd == NULL) return FAILED; lpfc_cmd->timeout = 60; lpfc_cmd->rdata = rdata; - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, - cmnd->device->lun, - FCP_TARGET_RESET); + status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, + task_mgmt_cmd); if (!status) { lpfc_release_scsi_buf(phba, lpfc_cmd); return FAILED; } - iocbq = &lpfc_cmd->cur_iocbq; - /* get a buffer for this IOCB command response */ + iocbq = &lpfc_cmd->cur_iocbq; iocbqrsp = lpfc_sli_get_iocbq(phba); if (iocbqrsp == NULL) { lpfc_release_scsi_buf(phba, lpfc_cmd); return FAILED; } + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0703 Issue target reset to TGT %d LUN %d " - "rpi x%x nlp_flag x%x\n", cmnd->device->id, - cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); + "0702 Issue %s to TGT %d LUN %d " + "rpi x%x nlp_flag x%x\n", + lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, + rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); + status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, iocbq, iocbqrsp, lpfc_cmd->timeout); - if (status == IOCB_TIMEDOUT) { - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; - ret = TIMEOUT_ERROR; - } else { - if (status != IOCB_SUCCESS) + if (status != IOCB_SUCCESS) { + if (status == IOCB_TIMEDOUT) { + iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; + ret = TIMEOUT_ERROR; + } else ret = FAILED; - lpfc_release_scsi_buf(phba, lpfc_cmd); - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0713 SCSI layer issued device reset (%d, %d) " - "return x%x status x%x result x%x\n", - cmnd->device->id, cmnd->device->lun, ret, - iocbqrsp->iocb.ulpStatus, + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0727 TMF %s to TGT %d LUN %d failed (%d, %d)\n", + lpfc_taskmgmt_name(task_mgmt_cmd), + tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, iocbqrsp->iocb.un.ulpWord[4]); + } else + ret = SUCCESS; + lpfc_sli_release_iocbq(phba, iocbqrsp); - cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, - LPFC_CTX_TGT); + + if (ret != TIMEOUT_ERROR) + lpfc_release_scsi_buf(phba, lpfc_cmd); + + return ret; +} + +/** + * lpfc_chk_tgt_mapped - + * @vport: The virtual port to check on + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine delays until the scsi target (aka rport) for the + * command exists (is present and logged in) or we declare it non-existent. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) +{ + struct lpfc_rport_data *rdata = cmnd->device->hostdata; + struct lpfc_nodelist *pnode = rdata->pnode; + unsigned long later; + + /* + * If target is not in a MAPPED state, delay until + * target is rediscovered or devloss timeout expires. + */ + later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; + while (time_after(later, jiffies)) { + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + return FAILED; + if (pnode->nlp_state == NLP_STE_MAPPED_NODE) + return SUCCESS; + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); + rdata = cmnd->device->hostdata; + if (!rdata) + return FAILED; + pnode = rdata->pnode; + } + if (!pnode || !NLP_CHK_NODE_ACT(pnode) || + (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + return FAILED; + return SUCCESS; +} + +/** + * lpfc_reset_flush_io_context - + * @vport: The virtual port (scsi_host) for the flush context + * @tgt_id: If aborting by Target contect - specifies the target id + * @lun_id: If aborting by Lun context - specifies the lun id + * @context: specifies the context level to flush at. + * + * After a reset condition via TMF, we need to flush orphaned i/o + * contexts from the adapter. This routine aborts any contexts + * outstanding, then waits for their completions. The wait is + * bounded by devloss_tmo though. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, + uint64_t lun_id, lpfc_ctx_cmd context) +{ + struct lpfc_hba *phba = vport->phba; + unsigned long later; + int cnt; + + cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); if (cnt) lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - cmnd->device->id, cmnd->device->lun, - LPFC_CTX_TGT); + tgt_id, lun_id, context); later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; while (time_after(later, jiffies) && cnt) { schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, - cmnd->device->lun, LPFC_CTX_TGT); + cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); } if (cnt) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0719 device reset I/O flush failure: " - "cnt x%x\n", cnt); - ret = FAILED; + "0724 I/O flush failure for context %s : cnt x%x\n", + ((context == LPFC_CTX_LUN) ? "LUN" : + ((context == LPFC_CTX_TGT) ? "TGT" : + ((context == LPFC_CTX_HOST) ? "HOST" : "Unknown"))), + cnt); + return FAILED; } - return ret; + return SUCCESS; +} + +/** + * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does a device reset by sending a LUN_RESET task management + * command. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_device_reset_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_rport_data *rdata = cmnd->device->hostdata; + struct lpfc_nodelist *pnode = rdata->pnode; + unsigned tgt_id = cmnd->device->id; + unsigned int lun_id = cmnd->device->lun; + struct lpfc_scsi_event_header scsi_event; + int status; + + lpfc_block_error_handler(cmnd); + + status = lpfc_chk_tgt_mapped(vport, cmnd); + if (status == FAILED) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0721 Device Reset rport failure: rdata x%p\n", rdata); + return FAILED; + } + + scsi_event.event_type = FC_REG_SCSI_EVENT; + scsi_event.subcategory = LPFC_EVENT_LUNRESET; + scsi_event.lun = lun_id; + memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); + memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); + + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); + + status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, + FCP_LUN_RESET); + + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0713 SCSI layer issued Device Reset (%d, %d) " + "return x%x\n", tgt_id, lun_id, status); + + /* + * We have to clean up i/o as : they may be orphaned by the TMF; + * or if the TMF failed, they may be in an indeterminate state. + * So, continue on. + * We will report success if all the i/o aborts successfully. + */ + status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_LUN); + return status; +} + +/** + * lpfc_target_reset_handler - scsi_host_template eh_target_reset entry point + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does a target reset by sending a TARGET_RESET task management + * command. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_target_reset_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_rport_data *rdata = cmnd->device->hostdata; + struct lpfc_nodelist *pnode = rdata->pnode; + unsigned tgt_id = cmnd->device->id; + unsigned int lun_id = cmnd->device->lun; + struct lpfc_scsi_event_header scsi_event; + int status; + + lpfc_block_error_handler(cmnd); + + status = lpfc_chk_tgt_mapped(vport, cmnd); + if (status == FAILED) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0722 Target Reset rport failure: rdata x%p\n", rdata); + return FAILED; + } + + scsi_event.event_type = FC_REG_SCSI_EVENT; + scsi_event.subcategory = LPFC_EVENT_TGTRESET; + scsi_event.lun = 0; + memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); + memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); + + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); + + status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, + FCP_TARGET_RESET); + + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0723 SCSI layer issued Target Reset (%d, %d) " + "return x%x\n", tgt_id, lun_id, status); + + /* + * We have to clean up i/o as : they may be orphaned by the TMF; + * or if the TMF failed, they may be in an indeterminate state. + * So, continue on. + * We will report success if all the i/o aborts successfully. + */ + status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_TGT); + return status; } /** * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point * @cmnd: Pointer to scsi_cmnd data structure. * - * This routine does target reset to all target on @cmnd->device->host. + * This routine does target reset to all targets on @cmnd->device->host. + * This emulates Parallel SCSI Bus Reset Semantics. * - * Return Code: - * 0x2003 - Error - * 0x2002 - Success + * Return code : + * 0x2003 - Error + * 0x2002 - Success **/ static int lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - int match; - int ret = SUCCESS, status = SUCCESS, i; - int cnt; - struct lpfc_scsi_buf * lpfc_cmd; - unsigned long later; struct lpfc_scsi_event_header scsi_event; + int match; + int ret = SUCCESS, status, i; scsi_event.event_type = FC_REG_SCSI_EVENT; scsi_event.subcategory = LPFC_EVENT_BUSRESET; @@ -3385,13 +3390,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(scsi_event), - (char *)&scsi_event, - LPFC_NL_VENDOR_ID); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); lpfc_block_error_handler(cmnd); + /* * Since the driver manages a single bus device, reset all * targets known to the driver. Should any target reset @@ -3414,16 +3417,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) spin_unlock_irq(shost->host_lock); if (!match) continue; - lpfc_cmd = lpfc_get_scsi_buf(phba); - if (lpfc_cmd) { - lpfc_cmd->timeout = 60; - status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, - cmnd->device->lun, - ndlp->rport->dd_data); - if (status != TIMEOUT_ERROR) - lpfc_release_scsi_buf(phba, lpfc_cmd); - } - if (!lpfc_cmd || status != SUCCESS) { + + status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data, + i, 0, FCP_TARGET_RESET); + + if (status != SUCCESS) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0700 Bus Reset on target %d failed\n", i); @@ -3431,25 +3429,16 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) } } /* - * All outstanding txcmplq I/Os should have been aborted by - * the targets. Unfortunately, some targets do not abide by - * this forcing the driver to double check. + * We have to clean up i/o as : they may be orphaned by the TMFs + * above; or if any of the TMFs failed, they may be in an + * indeterminate state. + * We will report success if all the i/o aborts successfully. */ - cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); - if (cnt) - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - 0, 0, LPFC_CTX_HOST); - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies) && cnt) { - schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); - } - if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0715 Bus Reset I/O flush failure: " - "cnt x%x left x%x\n", cnt, i); + + status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); + if (status != SUCCESS) ret = FAILED; - } + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); return ret; @@ -3582,7 +3571,8 @@ struct scsi_host_template lpfc_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler= lpfc_device_reset_handler, + .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, @@ -3602,7 +3592,8 @@ struct scsi_host_template lpfc_vport_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler= lpfc_device_reset_handler, + .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ff04daf18f4..acc43b061ba 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4139,8 +4139,11 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, return -EIO; } data_length = mqe->un.mb_words[5]; - if (data_length > DMP_FCOEPARAM_RGN_SIZE) + if (data_length > DMP_FCOEPARAM_RGN_SIZE) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); return -EIO; + } lpfc_parse_fcoe_conf(phba, mp->virt, data_length); lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -4211,27 +4214,6 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, return -EIO; } - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0380 Mailbox cmd x%x Status x%x " - "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 x%x x%x " - "CQ: x%x x%x x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - bf_get(lpfc_mqe_command, mqe), - bf_get(lpfc_mqe_status, mqe), - mqe->un.mb_words[0], mqe->un.mb_words[1], - mqe->un.mb_words[2], mqe->un.mb_words[3], - mqe->un.mb_words[4], mqe->un.mb_words[5], - mqe->un.mb_words[6], mqe->un.mb_words[7], - mqe->un.mb_words[8], mqe->un.mb_words[9], - mqe->un.mb_words[10], mqe->un.mb_words[11], - mqe->un.mb_words[12], mqe->un.mb_words[13], - mqe->un.mb_words[14], mqe->un.mb_words[15], - mqe->un.mb_words[16], mqe->un.mb_words[50], - mboxq->mcqe.word0, - mboxq->mcqe.mcqe_tag0, mboxq->mcqe.mcqe_tag1, - mboxq->mcqe.trailer); - /* * The available vpd length cannot be bigger than the * DMA buffer passed to the port. Catch the less than @@ -4337,21 +4319,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_vpd; mqe = &mboxq->u.mqe; - if ((bf_get(lpfc_mbx_rd_rev_sli_lvl, - &mqe->un.read_rev) != LPFC_SLI_REV4) || - (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev) == 0)) { + phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev); + if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) + phba->hba_flag |= HBA_FCOE_SUPPORT; + if (phba->sli_rev != LPFC_SLI_REV4 || + !(phba->hba_flag & HBA_FCOE_SUPPORT)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " "FCoE enabled %d\n", - bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev), - bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)); + phba->sli_rev, phba->hba_flag & HBA_FCOE_SUPPORT); rc = -EIO; goto out_free_vpd; } - /* Single threaded at this point, no need for lock */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= HBA_FCOE_SUPPORT; - spin_unlock_irq(&phba->hbalock); /* * Evaluate the read rev and vpd data. Populate the driver * state with the results. If this routine fails, the failure @@ -4365,8 +4344,32 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = 0; } - /* By now, we should determine the SLI revision, hard code for now */ - phba->sli_rev = LPFC_SLI_REV4; + /* Save information as VPD data */ + phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev; + phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev; + phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev; + phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high, + &mqe->un.read_rev); + phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low, + &mqe->un.read_rev); + phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high, + &mqe->un.read_rev); + phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low, + &mqe->un.read_rev); + phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev; + memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16); + phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev; + memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16); + phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev; + memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "(%d):0380 READ_REV Status x%x " + "fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n", + mboxq->vport ? mboxq->vport->vpi : 0, + bf_get(lpfc_mqe_status, mqe), + phba->vpd.rev.opFwName, + phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, + phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); /* * Discover the port's supported feature set and match it against the @@ -4491,8 +4494,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_free_vpd; } - /* Temporary initialization of lpfc_fip_flag to non-fip */ - bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0); + if (phba->cfg_enable_fip) + bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 1); + else + bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0); /* Set up all the queues to the device */ rc = lpfc_sli4_queue_setup(phba); @@ -5030,6 +5035,92 @@ out_not_finished: } /** + * lpfc_sli4_async_mbox_block - Block posting SLI4 asynchronous mailbox command + * @phba: Pointer to HBA context object. + * + * The function blocks the posting of SLI4 asynchronous mailbox commands from + * the driver internal pending mailbox queue. It will then try to wait out the + * possible outstanding mailbox command before return. + * + * Returns: + * 0 - the outstanding mailbox command completed; otherwise, the wait for + * the outstanding mailbox command timed out. + **/ +static int +lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + uint8_t actcmd = MBX_HEARTBEAT; + int rc = 0; + unsigned long timeout; + + /* Mark the asynchronous mailbox command posting as blocked */ + spin_lock_irq(&phba->hbalock); + psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; + if (phba->sli.mbox_active) + actcmd = phba->sli.mbox_active->u.mb.mbxCommand; + spin_unlock_irq(&phba->hbalock); + /* Determine how long we might wait for the active mailbox + * command to be gracefully completed by firmware. + */ + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) + + jiffies; + /* Wait for the outstnading mailbox command to complete */ + while (phba->sli.mbox_active) { + /* Check active mailbox complete status every 2ms */ + msleep(2); + if (time_after(jiffies, timeout)) { + /* Timeout, marked the outstanding cmd not complete */ + rc = 1; + break; + } + } + + /* Can not cleanly block async mailbox command, fails it */ + if (rc) { + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + } + return rc; +} + +/** + * lpfc_sli4_async_mbox_unblock - Block posting SLI4 async mailbox command + * @phba: Pointer to HBA context object. + * + * The function unblocks and resume posting of SLI4 asynchronous mailbox + * commands from the driver internal pending mailbox queue. It makes sure + * that there is no outstanding mailbox command before resuming posting + * asynchronous mailbox commands. If, for any reason, there is outstanding + * mailbox command, it will try to wait it out before resuming asynchronous + * mailbox command posting. + **/ +static void +lpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + + spin_lock_irq(&phba->hbalock); + if (!(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { + /* Asynchronous mailbox posting is not blocked, do nothing */ + spin_unlock_irq(&phba->hbalock); + return; + } + + /* Outstanding synchronous mailbox command is guaranteed to be done, + * successful or timeout, after timing-out the outstanding mailbox + * command shall always be removed, so just unblock posting async + * mailbox command and resume + */ + psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; + spin_unlock_irq(&phba->hbalock); + + /* wake up worker thread to post asynchronlous mailbox command */ + lpfc_worker_wake_up(phba); +} + +/** * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox * @phba: Pointer to HBA context object. * @mboxq: Pointer to mailbox object. @@ -5204,14 +5295,35 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, psli->sli_flag, flag); return rc; } else if (flag == MBX_POLL) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2542 Mailbox command x%x (x%x) " - "cannot issue Data: x%x x%x\n", + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "(%d):2542 Try to issue mailbox command " + "x%x (x%x) synchronously ahead of async" + "mailbox command queue: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli4_mbox_opcode_get(phba, mboxq), psli->sli_flag, flag); - return -EIO; + /* Try to block the asynchronous mailbox posting */ + rc = lpfc_sli4_async_mbox_block(phba); + if (!rc) { + /* Successfully blocked, now issue sync mbox cmd */ + rc = lpfc_sli4_post_sync_mbox(phba, mboxq); + if (rc != MBX_SUCCESS) + lpfc_printf_log(phba, KERN_ERR, + LOG_MBOX | LOG_SLI, + "(%d):2597 Mailbox command " + "x%x (x%x) cannot issue " + "Data: x%x x%x\n", + mboxq->vport ? + mboxq->vport->vpi : 0, + mboxq->u.mb.mbxCommand, + lpfc_sli4_mbox_opcode_get(phba, + mboxq), + psli->sli_flag, flag); + /* Unblock the async mailbox posting afterward */ + lpfc_sli4_async_mbox_unblock(phba); + } + return rc; } /* Now, interrupt mode asynchrous mailbox command */ @@ -5749,18 +5861,13 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags); /* The fcp commands will set command type */ - if ((!(iocbq->iocb_flag & LPFC_IO_FCP)) && (!fip)) - command_type = ELS_COMMAND_NON_FIP; - else if (!(iocbq->iocb_flag & LPFC_IO_FCP)) - command_type = ELS_COMMAND_FIP; - else if (iocbq->iocb_flag & LPFC_IO_FCP) + if (iocbq->iocb_flag & LPFC_IO_FCP) command_type = FCP_COMMAND; - else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2019 Invalid cmd 0x%x\n", - iocbq->iocb.ulpCommand); - return IOCB_ERROR; - } + else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS)) + command_type = ELS_COMMAND_FIP; + else + command_type = ELS_COMMAND_NON_FIP; + /* Some of the fields are in the right position already */ memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); abort_tag = (uint32_t) iocbq->iotag; @@ -5814,11 +5921,6 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(lpfc_wqe_gen_context, &wqe->generic, iocbq->iocb.ulpContext); - if (iocbq->vport->fc_myDID != 0) { - bf_set(els_req64_sid, &wqe->els_req, - iocbq->vport->fc_myDID); - bf_set(els_req64_sp, &wqe->els_req, 1); - } bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct); bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); /* CCP CCPE PV PRI in word10 were set in the memcpy */ @@ -5877,14 +5979,19 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * is set and we are sending our 2nd or greater command on * this exchange. */ + /* Always open the exchange */ + bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); - /* ALLOW read & write to fall through to ICMD64 */ + wqe->words[10] &= 0xffff0000; /* zero out ebde count */ + bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU); + break; case CMD_FCP_ICMND64_CR: /* Always open the exchange */ bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); + wqe->words[4] = 0; wqe->words[10] &= 0xffff0000; /* zero out ebde count */ - bf_set(lpfc_wqe_gen_pu, &wqe->generic, iocbq->iocb.ulpPU); + bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); break; case CMD_GEN_REQUEST64_CR: /* word3 command length is described as byte offset to the @@ -7247,6 +7354,32 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, } /** + * lpfc_chk_iocb_flg - Test IOCB flag with lock held. + * @phba: Pointer to HBA context object.. + * @piocbq: Pointer to command iocb. + * @flag: Flag to test. + * + * This routine grabs the hbalock and then test the iocb_flag to + * see if the passed in flag is set. + * Returns: + * 1 if flag is set. + * 0 if flag is not set. + **/ +static int +lpfc_chk_iocb_flg(struct lpfc_hba *phba, + struct lpfc_iocbq *piocbq, uint32_t flag) +{ + unsigned long iflags; + int ret; + + spin_lock_irqsave(&phba->hbalock, iflags); + ret = piocbq->iocb_flag & flag; + spin_unlock_irqrestore(&phba->hbalock, iflags); + return ret; + +} + +/** * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands * @phba: Pointer to HBA context object.. * @pring: Pointer to sli ring. @@ -7313,7 +7446,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, if (retval == IOCB_SUCCESS) { timeout_req = timeout * HZ; timeleft = wait_event_timeout(done_q, - piocb->iocb_flag & LPFC_IO_WAKE, + lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); if (piocb->iocb_flag & LPFC_IO_WAKE) { @@ -7498,20 +7631,16 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) if ((HS_FFER1 & phba->work_hs) && ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | HS_FFER6 | HS_FFER7) & phba->work_hs)) { - spin_lock_irq(&phba->hbalock); phba->hba_flag |= DEFER_ERATT; - spin_unlock_irq(&phba->hbalock); /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); readl(phba->HCregaddr); } /* Set the driver HA work bitmap */ - spin_lock_irq(&phba->hbalock); phba->work_ha |= HA_ERATT; /* Indicate polling handles this ERATT */ phba->hba_flag |= HBA_ERATT_HANDLED; - spin_unlock_irq(&phba->hbalock); return 1; } return 0; @@ -7557,12 +7686,10 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) return 0; phba->work_status[0] = uerr_sta_lo; phba->work_status[1] = uerr_sta_hi; - spin_lock_irq(&phba->hbalock); /* Set the driver HA work bitmap */ phba->work_ha |= HA_ERATT; /* Indicate polling handles this ERATT */ phba->hba_flag |= HBA_ERATT_HANDLED; - spin_unlock_irq(&phba->hbalock); return 1; } } @@ -9245,6 +9372,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, kfree(dmabuf); goto out_fail; } + memset(dmabuf->virt, 0, PAGE_SIZE); dmabuf->buffer_tag = x; list_add_tail(&dmabuf->list, &queue->page_list); /* initialize queue's entry array */ @@ -9667,7 +9795,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, /* link the wq onto the parent cq child list */ list_add_tail(&wq->list, &cq->child_list); out: - if (rc == MBX_TIMEOUT) + if (rc != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -11020,10 +11148,7 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) rpi_page->start_rpi); hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys); hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); @@ -11363,6 +11488,7 @@ lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba, bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]); bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]); bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1); + bf_set(lpfc_fcf_record_fcf_avail, fcf_record, 1); bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index); bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record, LPFC_FCF_FPMA | LPFC_FCF_SPMA); diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 7d37eb7459b..3c53316cf6d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -56,6 +56,7 @@ struct lpfc_iocbq { #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ +#define LPFC_FIP_ELS 0x40 uint8_t abort_count; uint8_t rsvd2; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 5196b46608d..3b276b47d18 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -229,7 +229,7 @@ struct lpfc_bmbx { #define LPFC_EQE_DEF_COUNT 1024 #define LPFC_CQE_DEF_COUNT 256 -#define LPFC_WQE_DEF_COUNT 64 +#define LPFC_WQE_DEF_COUNT 256 #define LPFC_MQE_DEF_COUNT 16 #define LPFC_RQE_DEF_COUNT 512 diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 6b8a148f0a5..41094e02304 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.3.2" +#define LPFC_DRIVER_VERSION "8.3.3" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index a6313ee84ac..e0b49922193 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -695,8 +695,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) } vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - goto skip_logo; if (!lpfc_issue_els_npiv_logo(vport, ndlp)) while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) timeout = schedule_timeout(timeout); |