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
This commit is contained in:
@@ -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,
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
@@ -1240,6 +1253,14 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 }
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -115,6 +115,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.
|
||||
@@ -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
|
||||
@@ -2002,36 +2023,6 @@ lpfc_scsi_unprep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
|
||||
psb->pCmd->sc_data_direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -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,70 +2605,15 @@ 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;
|
||||
}
|
||||
|
||||
if (vport->phba->sli_rev == LPFC_SLI_REV4)
|
||||
lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd);
|
||||
|
||||
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;
|
||||
|
||||
return phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
|
||||
task_mgmt_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table
|
||||
* @phba: The hba struct for which this call is being executed.
|
||||
@@ -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:
|
||||
@@ -2782,72 +2675,6 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,11 +3055,201 @@ 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_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 builds and sends a TMF (SCSI Task Mgmt Function) to
|
||||
* a remote port.
|
||||
*
|
||||
* Return Code:
|
||||
* 0x2003 - Error
|
||||
* 0x2002 - Success.
|
||||
**/
|
||||
static int
|
||||
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 lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_scsi_buf *lpfc_cmd;
|
||||
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 = 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, lun_id,
|
||||
task_mgmt_cmd);
|
||||
if (!status) {
|
||||
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
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,
|
||||
"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_SUCCESS) {
|
||||
if (status == IOCB_TIMEDOUT) {
|
||||
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
|
||||
ret = TIMEOUT_ERROR;
|
||||
} else
|
||||
ret = FAILED;
|
||||
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);
|
||||
|
||||
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],
|
||||
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, tgt_id, lun_id, context);
|
||||
}
|
||||
if (cnt) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||
"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 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 TARGET_RESET task management
|
||||
* This routine does a device reset by sending a LUN_RESET task management
|
||||
* command.
|
||||
*
|
||||
* Return code :
|
||||
@@ -3244,33 +3261,79 @@ 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_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;
|
||||
int status;
|
||||
int cnt;
|
||||
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);
|
||||
|
||||
/*
|
||||
* If target is not in a MAPPED state, delay the reset until
|
||||
* target is rediscovered or devloss timeout expires.
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
@@ -3279,105 +3342,47 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
|
||||
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);
|
||||
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);
|
||||
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_send_taskmgmt(vport, rdata, tgt_id, lun_id,
|
||||
FCP_TARGET_RESET);
|
||||
|
||||
status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd,
|
||||
cmnd->device->lun,
|
||||
FCP_TARGET_RESET);
|
||||
if (!status) {
|
||||
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
||||
return FAILED;
|
||||
}
|
||||
iocbq = &lpfc_cmd->cur_iocbq;
|
||||
|
||||
/* get a buffer for this IOCB command response */
|
||||
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);
|
||||
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)
|
||||
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,
|
||||
iocbqrsp->iocb.un.ulpWord[4]);
|
||||
lpfc_sli_release_iocbq(phba, iocbqrsp);
|
||||
cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun,
|
||||
LPFC_CTX_TGT);
|
||||
if (cnt)
|
||||
lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
|
||||
cmnd->device->id, cmnd->device->lun,
|
||||
LPFC_CTX_TGT);
|
||||
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);
|
||||
}
|
||||
if (cnt) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||
"0719 device reset I/O flush failure: "
|
||||
"cnt x%x\n", cnt);
|
||||
ret = FAILED;
|
||||
}
|
||||
return ret;
|
||||
"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,
|
||||
|
@@ -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);
|
||||
@@ -5029,6 +5034,92 @@ out_not_finished:
|
||||
return MBX_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.
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/* ALLOW read & write to fall through to ICMD64 */
|
||||
case CMD_FCP_ICMND64_CR:
|
||||
/* Always open the exchange */
|
||||
bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
|
||||
|
||||
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, 0);
|
||||
break;
|
||||
case CMD_GEN_REQUEST64_CR:
|
||||
/* word3 command length is described as byte offset to the
|
||||
@@ -7246,6 +7353,32 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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..
|
||||
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user