diff options
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 76 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 16 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 494 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.h | 72 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 186 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 98 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 42 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 839 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 38 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mem.c | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 127 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 144 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 621 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 42 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 63 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 7 |
21 files changed, 1732 insertions, 1187 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a65c05a8d488..a184c2443a64 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -73,6 +73,8 @@ struct lpfc_sli2_slim; #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ +#define LPFC_LOOK_AHEAD_OFF 0 /* Look ahead logic is turned off */ + /* Error Attention event polling interval */ #define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ @@ -684,6 +686,7 @@ struct lpfc_hba { #define LPFC_FCF_FOV 1 /* Fast fcf failover */ #define LPFC_FCF_PRIORITY 2 /* Priority fcf failover */ uint32_t cfg_fcf_failover_policy; + uint32_t cfg_fcp_io_sched; uint32_t cfg_cr_delay; uint32_t cfg_cr_count; uint32_t cfg_multi_ring_support; @@ -695,6 +698,7 @@ struct lpfc_hba { uint32_t cfg_fcp_imax; uint32_t cfg_fcp_wq_count; uint32_t cfg_fcp_eq_count; + uint32_t cfg_fcp_io_channel; uint32_t cfg_sg_seg_cnt; uint32_t cfg_prot_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; @@ -732,7 +736,7 @@ struct lpfc_hba { uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ - uint32_t fcp_qidx; /* next work queue to post work to */ + atomic_t fcp_qidx; /* next work queue to post work to */ unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index adef5bb2100e..b032562aa0d9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3643,18 +3643,25 @@ lpfc_fcp_imax_store(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; int val = 0, i; + /* fcp_imax is only valid for SLI4 */ + if (phba->sli_rev != LPFC_SLI_REV4) + return -EINVAL; + /* Sanity check on user data */ if (!isdigit(buf[0])) return -EINVAL; if (sscanf(buf, "%i", &val) != 1) return -EINVAL; - /* Value range is [636,651042] */ - if (val < LPFC_MIM_IMAX || val > LPFC_DMULT_CONST) + /* + * Value range for the HBA is [5000,5000000] + * The value for each EQ depends on how many EQs are configured. + */ + if (val < LPFC_MIN_IMAX || val > LPFC_MAX_IMAX) return -EINVAL; phba->cfg_fcp_imax = (uint32_t)val; - for (i = 0; i < phba->cfg_fcp_eq_count; i += LPFC_MAX_EQ_DELAY) + for (i = 0; i < phba->cfg_fcp_io_channel; i += LPFC_MAX_EQ_DELAY) lpfc_modify_fcp_eq_delay(phba, i); return strlen(buf); @@ -3662,13 +3669,14 @@ lpfc_fcp_imax_store(struct device *dev, struct device_attribute *attr, /* # lpfc_fcp_imax: The maximum number of fast-path FCP interrupts per second +# for the HBA. # -# Value range is [636,651042]. Default value is 10000. +# Value range is [5,000 to 5,000,000]. Default value is 50,000. */ -static int lpfc_fcp_imax = LPFC_FP_DEF_IMAX; +static int lpfc_fcp_imax = LPFC_DEF_IMAX; module_param(lpfc_fcp_imax, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(lpfc_fcp_imax, - "Set the maximum number of fast-path FCP interrupts per second"); + "Set the maximum number of FCP interrupts per second per HBA"); lpfc_param_show(fcp_imax) /** @@ -3687,14 +3695,19 @@ lpfc_param_show(fcp_imax) static int lpfc_fcp_imax_init(struct lpfc_hba *phba, int val) { - if (val >= LPFC_MIM_IMAX && val <= LPFC_DMULT_CONST) { + if (phba->sli_rev != LPFC_SLI_REV4) { + phba->cfg_fcp_imax = 0; + return 0; + } + + if (val >= LPFC_MIN_IMAX && val <= LPFC_MAX_IMAX) { phba->cfg_fcp_imax = val; return 0; } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3016 fcp_imax: %d out of range, using default\n", val); - phba->cfg_fcp_imax = LPFC_FP_DEF_IMAX; + phba->cfg_fcp_imax = LPFC_DEF_IMAX; return 0; } @@ -3765,6 +3778,16 @@ static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR, LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); /* +# lpfc_fcp_io_sched: Determine scheduling algrithmn for issuing FCP cmds +# range is [0,1]. Default value is 0. +# For [0], FCP commands are issued to Work Queues ina round robin fashion. +# For [1], FCP commands are issued to a Work Queue associated with the +# current CPU. +*/ +LPFC_ATTR_RW(fcp_io_sched, 0, 0, 1, "Determine scheduling algrithmn for " + "issuing commands [0] - Round Robin, [1] - Current CPU"); + +/* # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing # cr_delay (msec) or cr_count outstanding commands. cr_delay can take # value [0,63]. cr_count can take value [1,255]. Default value of cr_delay @@ -3844,21 +3867,33 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " /* # lpfc_fcp_wq_count: Set the number of fast-path FCP work queues +# This parameter is ignored and will eventually be depricated # -# Value range is [1,31]. Default value is 4. +# Value range is [1,7]. Default value is 4. */ -LPFC_ATTR_R(fcp_wq_count, LPFC_FP_WQN_DEF, LPFC_FP_WQN_MIN, LPFC_FP_WQN_MAX, +LPFC_ATTR_R(fcp_wq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN, + LPFC_FCP_IO_CHAN_MAX, "Set the number of fast-path FCP work queues, if possible"); /* -# lpfc_fcp_eq_count: Set the number of fast-path FCP event queues +# lpfc_fcp_eq_count: Set the number of FCP EQ/CQ/WQ IO channels # -# Value range is [1,7]. Default value is 1. +# Value range is [1,7]. Default value is 4. */ -LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX, +LPFC_ATTR_R(fcp_eq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN, + LPFC_FCP_IO_CHAN_MAX, "Set the number of fast-path FCP event queues, if possible"); /* +# lpfc_fcp_io_channel: Set the number of FCP EQ/CQ/WQ IO channels +# +# Value range is [1,7]. Default value is 4. +*/ +LPFC_ATTR_R(fcp_io_channel, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN, + LPFC_FCP_IO_CHAN_MAX, + "Set the number of FCP I/O channels"); + +/* # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. # 0 = HBA resets disabled # 1 = HBA resets enabled (default) @@ -3883,6 +3918,17 @@ LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat."); LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); /* +# lpfc_fcp_look_ahead: Look ahead for completions in FCP start routine +# 0 = disabled (default) +# 1 = enabled +# Value range is [0,1]. Default value is 0. +*/ +unsigned int lpfc_fcp_look_ahead = LPFC_LOOK_AHEAD_OFF; + +module_param(lpfc_fcp_look_ahead, uint, S_IRUGO); +MODULE_PARM_DESC(lpfc_fcp_look_ahead, "Look ahead for completions"); + +/* # lpfc_prot_mask: i # - Bit mask of host protection capabilities used to register with the # SCSI mid-layer @@ -3976,6 +4022,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_topology, &dev_attr_lpfc_scan_down, &dev_attr_lpfc_link_speed, + &dev_attr_lpfc_fcp_io_sched, &dev_attr_lpfc_cr_delay, &dev_attr_lpfc_cr_count, &dev_attr_lpfc_multi_ring_support, @@ -4002,6 +4049,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fcp_imax, &dev_attr_lpfc_fcp_wq_count, &dev_attr_lpfc_fcp_eq_count, + &dev_attr_lpfc_fcp_io_channel, &dev_attr_lpfc_enable_bg, &dev_attr_lpfc_soft_wwnn, &dev_attr_lpfc_soft_wwpn, @@ -4964,6 +5012,7 @@ struct fc_function_template lpfc_vport_transport_functions = { void lpfc_get_cfgparam(struct lpfc_hba *phba) { + lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched); lpfc_cr_delay_init(phba, lpfc_cr_delay); lpfc_cr_count_init(phba, lpfc_cr_count); lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support); @@ -4980,6 +5029,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_fcp_imax_init(phba, lpfc_fcp_imax); lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count); lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count); + lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_enable_bg_init(phba, lpfc_enable_bg); diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 253d9a857346..f7368eb80415 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -195,7 +195,7 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, if (rsp->ulpStatus) { if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { + switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { case IOERR_SEQUENCE_TIMEOUT: rc = -ETIMEDOUT; break; @@ -1234,7 +1234,7 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, if (rsp->ulpStatus) { if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { + switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { case IOERR_SEQUENCE_TIMEOUT: rc = -ETIMEDOUT; break; @@ -1714,6 +1714,8 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) phba->sli4_hba.lnk_info.lnk_no); link_diag_state = &pmboxq->u.mqe.un.link_diag_state; + bf_set(lpfc_mbx_set_diag_state_diag_bit_valid, &link_diag_state->u.req, + LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE); bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, phba->sli4_hba.lnk_info.lnk_no); bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, @@ -4796,7 +4798,7 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, menlo_resp->xri = rsp->ulpContext; if (rsp->ulpStatus) { if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { + switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { case IOERR_SEQUENCE_TIMEOUT: rc = -ETIMEDOUT; break; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 8a2a514a2553..e470c489de07 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -196,8 +196,7 @@ irqreturn_t lpfc_sli_intr_handler(int, void *); irqreturn_t lpfc_sli_sp_intr_handler(int, void *); irqreturn_t lpfc_sli_fp_intr_handler(int, void *); irqreturn_t lpfc_sli4_intr_handler(int, void *); -irqreturn_t lpfc_sli4_sp_intr_handler(int, void *); -irqreturn_t lpfc_sli4_fp_intr_handler(int, void *); +irqreturn_t lpfc_sli4_hba_intr_handler(int, void *); void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -391,6 +390,7 @@ extern spinlock_t pgcnt_lock; extern unsigned int pgcnt; extern unsigned int lpfc_prot_mask; extern unsigned char lpfc_prot_guard; +extern unsigned int lpfc_fcp_look_ahead; /* Interface exported by fabric iocb scheduler */ void lpfc_fabric_abort_nport(struct lpfc_nodelist *); @@ -457,6 +457,8 @@ int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, struct sli4_wcqe_xri_aborted *); +void lpfc_sli_abts_recover_port(struct lpfc_vport *, + struct lpfc_nodelist *); int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 93e96b3c9097..7ffabb7e3afa 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -104,7 +104,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { + ((icmd->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_RCV_BUFFER_WAITING)) { /* Not enough posted buffers; Try posting more buffers */ phba->fc_stat.NoRcvBuf++; if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) @@ -633,7 +634,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || - irsp->un.ulpWord[4] != IOERR_NO_RESOURCES) + (irsp->un.ulpWord[4] && IOERR_PARAM_MASK) != + IOERR_NO_RESOURCES) vport->fc_ns_retry++; /* CT command is being retried */ @@ -783,7 +785,9 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { retry = 1; if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (irsp->un.ulpWord[4]) { + switch ((irsp->un.ulpWord[4] & + IOERR_PARAM_MASK)) { + case IOERR_NO_RESOURCES: /* We don't increment the retry * count for this case. @@ -908,8 +912,10 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]); if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || - (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) + (((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_SLI_DOWN) || + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_SLI_ABORTED))) goto out; retry = cmdiocb->retry; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3217d63ed282..f63f5ff7f274 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -490,9 +490,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) len += snprintf(buf+len, size-len, "Ring %d: CMD GetInx:%d (Max:%d Next:%d " "Local:%d flg:x%x) RSP PutInx:%d Max:%d\n", - i, pgpp->cmdGetInx, pring->numCiocb, - pring->next_cmdidx, pring->local_getidx, - pring->flag, pgpp->rspPutInx, pring->numRiocb); + i, pgpp->cmdGetInx, pring->sli.sli3.numCiocb, + pring->sli.sli3.next_cmdidx, + pring->sli.sli3.local_getidx, + pring->flag, pgpp->rspPutInx, + pring->sli.sli3.numRiocb); } if (phba->sli_rev <= LPFC_SLI_REV3) { @@ -557,6 +559,9 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) case NLP_STE_PRLI_ISSUE: statep = "PRLI "; break; + case NLP_STE_LOGO_ISSUE: + statep = "LOGO "; + break; case NLP_STE_UNMAPPED_NODE: statep = "UNMAP "; break; @@ -581,8 +586,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7)); - len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ", - ndlp->nlp_rpi, ndlp->nlp_flag); + if (ndlp->nlp_flag & NLP_RPI_REGISTERED) + len += snprintf(buf+len, size-len, "RPI:%03d ", + ndlp->nlp_rpi); + else + len += snprintf(buf+len, size-len, "RPI:none "); + len += snprintf(buf+len, size-len, "flag:x%08x ", + ndlp->nlp_flag); if (!ndlp->nlp_type) len += snprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) @@ -1999,207 +2009,298 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, { struct lpfc_debug *debug = file->private_data; struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - int len = 0, fcp_qidx; + int len = 0; char *pbuffer; + int x, cnt; + int max_cnt; + struct lpfc_queue *qp = NULL; + if (!debug->buffer) debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL); if (!debug->buffer) return 0; pbuffer = debug->buffer; + max_cnt = LPFC_QUE_INFO_GET_BUF_SIZE - 128; if (*ppos) return 0; - /* Get slow-path event queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path EQ information:\n"); - if (phba->sli4_hba.sp_eq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tEQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.sp_eq->queue_id, - phba->sli4_hba.sp_eq->entry_count, - phba->sli4_hba.sp_eq->entry_size, - phba->sli4_hba.sp_eq->host_index, - phba->sli4_hba.sp_eq->hba_index); - } + spin_lock_irq(&phba->hbalock); + + /* Fast-path event queue */ + if (phba->sli4_hba.hba_eq && phba->cfg_fcp_io_channel) { + cnt = phba->cfg_fcp_io_channel; + + for (x = 0; x < cnt; x++) { + + /* Fast-path EQ */ + qp = phba->sli4_hba.hba_eq[x]; + if (!qp) + goto proc_cq; + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\nHBA EQ info: " + "EQ-STAT[max:x%x noE:x%x " + "bs:x%x proc:x%llx]\n", + qp->q_cnt_1, qp->q_cnt_2, + qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "EQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, + qp->entry_count, + qp->entry_size, + qp->host_index, + qp->hba_index); + + + /* Reset max counter */ + qp->EQ_max_eqe = 0; + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; +proc_cq: + /* Fast-path FCP CQ */ + qp = phba->sli4_hba.fcp_cq[x]; + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\tFCP CQ info: "); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "AssocEQID[%02d]: " + "CQ STAT[max:x%x relw:x%x " + "xabt:x%x wq:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, qp->q_cnt_2, + qp->q_cnt_3, (unsigned long long)qp->q_cnt_4); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\tCQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, qp->entry_count, + qp->entry_size, qp->host_index, + qp->hba_index); + - /* Get fast-path event queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path EQ information:\n"); - if (phba->sli4_hba.fp_eq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; - fcp_qidx++) { - if (phba->sli4_hba.fp_eq[fcp_qidx]) { + /* Reset max counter */ + qp->CQ_max_cqe = 0; + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; + + /* Fast-path FCP WQ */ + qp = phba->sli4_hba.fcp_wq[x]; + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tFCP WQ info: "); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "AssocCQID[%02d]: " + "WQ-STAT[oflow:x%x posted:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, (unsigned long long)qp->q_cnt_4); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tWQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, + qp->entry_count, + qp->entry_size, + qp->host_index, + qp->hba_index); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; + + if (x) + continue; + + /* Only EQ 0 has slow path CQs configured */ + + /* Slow-path mailbox CQ */ + qp = phba->sli4_hba.mbx_cq; + if (qp) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\tMBX CQ info: "); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "AssocEQID[%02d]: " + "CQ-STAT[mbox:x%x relw:x%x " + "xabt:x%x wq:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, qp->q_cnt_2, + qp->q_cnt_3, + (unsigned long long)qp->q_cnt_4); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tEQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, - phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, - phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, - phba->sli4_hba.fp_eq[fcp_qidx]->host_index, - phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); + "\tCQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, qp->entry_count, + qp->entry_size, qp->host_index, + qp->hba_index); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; } - } - } - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); - - /* Get mailbox complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path MBX CQ information:\n"); - if (phba->sli4_hba.mbx_cq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.mbx_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.mbx_cq->queue_id, - phba->sli4_hba.mbx_cq->entry_count, - phba->sli4_hba.mbx_cq->entry_size, - phba->sli4_hba.mbx_cq->host_index, - phba->sli4_hba.mbx_cq->hba_index); - } - /* Get slow-path complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path ELS CQ information:\n"); - if (phba->sli4_hba.els_cq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.els_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID [%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.els_cq->queue_id, - phba->sli4_hba.els_cq->entry_count, - phba->sli4_hba.els_cq->entry_size, - phba->sli4_hba.els_cq->host_index, - phba->sli4_hba.els_cq->hba_index); - } + /* Slow-path MBOX MQ */ + qp = phba->sli4_hba.mbx_wq; + if (qp) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tMBX MQ info: "); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "AssocCQID[%02d]:\n", + phba->sli4_hba.mbx_wq->assoc_qid); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tWQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, qp->entry_count, + qp->entry_size, qp->host_index, + qp->hba_index); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; + } - /* Get fast-path complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path FCP CQ information:\n"); - fcp_qidx = 0; - if (phba->sli4_hba.fcp_cq) { - do { - if (phba->sli4_hba.fcp_cq[fcp_qidx]) { + /* Slow-path ELS response CQ */ + qp = phba->sli4_hba.els_cq; + if (qp) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); + "\tELS CQ info: "); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, - phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); + "AssocEQID[%02d]: " + "CQ-STAT[max:x%x relw:x%x " + "xabt:x%x wq:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, qp->q_cnt_2, + qp->q_cnt_3, + (unsigned long long)qp->q_cnt_4); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\tCQID [%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, qp->entry_count, + qp->entry_size, qp->host_index, + qp->hba_index); + + /* Reset max counter */ + qp->CQ_max_cqe = 0; + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; } - } while (++fcp_qidx < phba->cfg_fcp_eq_count); - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); - } - /* Get mailbox queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path MBX MQ information:\n"); - if (phba->sli4_hba.mbx_wq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.mbx_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.mbx_wq->queue_id, - phba->sli4_hba.mbx_wq->entry_count, - phba->sli4_hba.mbx_wq->entry_size, - phba->sli4_hba.mbx_wq->host_index, - phba->sli4_hba.mbx_wq->hba_index); - } + /* Slow-path ELS WQ */ + qp = phba->sli4_hba.els_wq; + if (qp) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tELS WQ info: "); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "AssocCQID[%02d]: " + " WQ-STAT[oflow:x%x " + "posted:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, + (unsigned long long)qp->q_cnt_4); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tWQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]", + qp->queue_id, qp->entry_count, + qp->entry_size, qp->host_index, + qp->hba_index); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + if (len >= max_cnt) + goto too_big; + } - /* Get slow-path work queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path ELS WQ information:\n"); - if (phba->sli4_hba.els_wq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.els_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.els_wq->queue_id, - phba->sli4_hba.els_wq->entry_count, - phba->sli4_hba.els_wq->entry_size, - phba->sli4_hba.els_wq->host_index, - phba->sli4_hba.els_wq->hba_index); - } + if (phba->sli4_hba.hdr_rq && phba->sli4_hba.dat_rq) { + /* Slow-path RQ header */ + qp = phba->sli4_hba.hdr_rq; - /* Get fast-path work queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path FCP WQ information:\n"); - if (phba->sli4_hba.fcp_wq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; - fcp_qidx++) { - if (!phba->sli4_hba.fcp_wq[fcp_qidx]) - continue; - len += snprintf(pbuffer+len, + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tRQ info: "); + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, + "AssocCQID[%02d]: " + "RQ-STAT[nopost:x%x nobuf:x%x " + "trunc:x%x rcv:x%llx]\n", + qp->assoc_qid, + qp->q_cnt_1, qp->q_cnt_2, + qp->q_cnt_3, + (unsigned long long)qp->q_cnt_4); + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], WQE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, - phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); + "\t\tHQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]\n", + qp->queue_id, + qp->entry_count, + qp->entry_size, + qp->host_index, + qp->hba_index); + + /* Slow-path RQ data */ + qp = phba->sli4_hba.dat_rq; + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, + "\t\tDQID[%02d], " + "QE-CNT[%04d], QE-SIZE[%04d], " + "HOST-IDX[%04d], PORT-IDX[%04d]\n", + qp->queue_id, + qp->entry_count, + qp->entry_size, + qp->host_index, + qp->hba_index); + + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + } } - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); } - /* Get receive queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path RQ information:\n"); - if (phba->sli4_hba.hdr_rq && phba->sli4_hba.dat_rq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.hdr_rq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tHQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.hdr_rq->queue_id, - phba->sli4_hba.hdr_rq->entry_count, - phba->sli4_hba.hdr_rq->entry_size, - phba->sli4_hba.hdr_rq->host_index, - phba->sli4_hba.hdr_rq->hba_index); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tDQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.dat_rq->queue_id, - phba->sli4_hba.dat_rq->entry_count, - phba->sli4_hba.dat_rq->entry_size, - phba->sli4_hba.dat_rq->host_index, - phba->sli4_hba.dat_rq->hba_index); - } + spin_unlock_irq(&phba->hbalock); + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); + +too_big: + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "Truncated ...\n"); + spin_unlock_irq(&phba->hbalock); return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } @@ -2408,31 +2509,21 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, switch (quetp) { case LPFC_IDIAG_EQ: - /* Slow-path event queue */ - if (phba->sli4_hba.sp_eq && - phba->sli4_hba.sp_eq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.sp_eq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.sp_eq; - goto pass_check; - } - /* Fast-path event queue */ - if (phba->sli4_hba.fp_eq) { - for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { - if (phba->sli4_hba.fp_eq[qidx] && - phba->sli4_hba.fp_eq[qidx]->queue_id == + /* HBA event queue */ + if (phba->sli4_hba.hba_eq) { + for (qidx = 0; qidx < phba->cfg_fcp_io_channel; + qidx++) { + if (phba->sli4_hba.hba_eq[qidx] && + phba->sli4_hba.hba_eq[qidx]->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( - phba->sli4_hba.fp_eq[qidx], + phba->sli4_hba.hba_eq[qidx], index, count); if (rc) goto error_out; idiag.ptr_private = - phba->sli4_hba.fp_eq[qidx]; + phba->sli4_hba.hba_eq[qidx]; goto pass_check; } } @@ -2479,7 +2570,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, phba->sli4_hba.fcp_cq[qidx]; goto pass_check; } - } while (++qidx < phba->cfg_fcp_eq_count); + } while (++qidx < phba->cfg_fcp_io_channel); } goto error_out; break; @@ -2511,7 +2602,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } /* FCP work queue */ if (phba->sli4_hba.fcp_wq) { - for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { + for (qidx = 0; qidx < phba->cfg_fcp_io_channel; + qidx++) { if (!phba->sli4_hba.fcp_wq[qidx]) continue; if (phba->sli4_hba.fcp_wq[qidx]->queue_id == @@ -4490,7 +4582,7 @@ lpfc_debug_dump_all_queues(struct lpfc_hba *phba) lpfc_debug_dump_mbx_wq(phba); lpfc_debug_dump_els_wq(phba); - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_io_channel; fcp_wqidx++) lpfc_debug_dump_fcp_wq(phba, fcp_wqidx); lpfc_debug_dump_hdr_rq(phba); @@ -4501,14 +4593,12 @@ lpfc_debug_dump_all_queues(struct lpfc_hba *phba) lpfc_debug_dump_mbx_cq(phba); lpfc_debug_dump_els_cq(phba); - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_io_channel; fcp_wqidx++) lpfc_debug_dump_fcp_cq(phba, fcp_wqidx); /* * Dump Event Queues (EQs) */ - lpfc_debug_dump_sp_eq(phba); - - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) - lpfc_debug_dump_fcp_eq(phba, fcp_wqidx); + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_io_channel; fcp_wqidx++) + lpfc_debug_dump_hba_eq(phba, fcp_wqidx); } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index afe368fd1b98..8b2b6a3bfc25 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -36,6 +36,9 @@ /* dumpHostSlim output buffer size */ #define LPFC_DUMPHOSTSLIM_SIZE 4096 +/* dumpSLIqinfo output buffer size */ +#define LPFC_DUMPSLIQINFO_SIZE 4096 + /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 @@ -366,7 +369,7 @@ static inline void lpfc_debug_dump_fcp_wq(struct lpfc_hba *phba, int fcp_wqidx) { /* sanity check */ - if (fcp_wqidx >= phba->cfg_fcp_wq_count) + if (fcp_wqidx >= phba->cfg_fcp_io_channel) return; printk(KERN_ERR "FCP WQ: WQ[Idx:%d|Qid:%d]\n", @@ -388,15 +391,15 @@ lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx) int fcp_cqidx, fcp_cqid; /* sanity check */ - if (fcp_wqidx >= phba->cfg_fcp_wq_count) + if (fcp_wqidx >= phba->cfg_fcp_io_channel) return; fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; - for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_io_channel; fcp_cqidx++) if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) break; if (phba->intr_type == MSIX) { - if (fcp_cqidx >= phba->cfg_fcp_eq_count) + if (fcp_cqidx >= phba->cfg_fcp_io_channel) return; } else { if (fcp_cqidx > 0) @@ -410,7 +413,7 @@ lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx) } /** - * lpfc_debug_dump_fcp_eq - dump all entries from a fcp work queue's evt queue + * lpfc_debug_dump_hba_eq - dump all entries from a fcp work queue's evt queue * @phba: Pointer to HBA context object. * @fcp_wqidx: Index to a FCP work queue. * @@ -418,36 +421,30 @@ lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx) * associated to the FCP work queue specified by the @fcp_wqidx. **/ static inline void -lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx) +lpfc_debug_dump_hba_eq(struct lpfc_hba *phba, int fcp_wqidx) { struct lpfc_queue *qdesc; int fcp_eqidx, fcp_eqid; int fcp_cqidx, fcp_cqid; /* sanity check */ - if (fcp_wqidx >= phba->cfg_fcp_wq_count) + if (fcp_wqidx >= phba->cfg_fcp_io_channel) return; fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; - for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_io_channel; fcp_cqidx++) if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) break; if (phba->intr_type == MSIX) { - if (fcp_cqidx >= phba->cfg_fcp_eq_count) + if (fcp_cqidx >= phba->cfg_fcp_io_channel) return; } else { if (fcp_cqidx > 0) return; } - if (phba->cfg_fcp_eq_count == 0) { - fcp_eqidx = -1; - fcp_eqid = phba->sli4_hba.sp_eq->queue_id; - qdesc = phba->sli4_hba.sp_eq; - } else { - fcp_eqidx = fcp_cqidx; - fcp_eqid = phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id; - qdesc = phba->sli4_hba.fp_eq[fcp_eqidx]; - } + fcp_eqidx = fcp_cqidx; + fcp_eqid = phba->sli4_hba.hba_eq[fcp_eqidx]->queue_id; + qdesc = phba->sli4_hba.hba_eq[fcp_eqidx]; printk(KERN_ERR "FCP EQ: WQ[Idx:%d|Qid:%d]->CQ[Idx:%d|Qid:%d]->" "EQ[Idx:%d|Qid:%d]\n", @@ -543,25 +540,6 @@ lpfc_debug_dump_mbx_cq(struct lpfc_hba *phba) } /** - * lpfc_debug_dump_sp_eq - dump all entries from slow-path event queue - * @phba: Pointer to HBA context object. - * - * This function dumps all entries from the slow-path event queue. - **/ -static inline void -lpfc_debug_dump_sp_eq(struct lpfc_hba *phba) -{ - printk(KERN_ERR "SP EQ: WQ[Qid:%d/Qid:%d]->CQ[Qid:%d/Qid:%d]->" - "EQ[Qid:%d]:\n", - phba->sli4_hba.mbx_wq->queue_id, - phba->sli4_hba.els_wq->queue_id, - phba->sli4_hba.mbx_cq->queue_id, - phba->sli4_hba.els_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); - lpfc_debug_dump_q(phba->sli4_hba.sp_eq); -} - -/** * lpfc_debug_dump_wq_by_id - dump all entries from a work queue by queue id * @phba: Pointer to HBA context object. * @qid: Work queue identifier. @@ -574,10 +552,10 @@ lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid) { int wq_idx; - for (wq_idx = 0; wq_idx < phba->cfg_fcp_wq_count; wq_idx++) + for (wq_idx = 0; wq_idx < phba->cfg_fcp_io_channel; wq_idx++) if (phba->sli4_hba.fcp_wq[wq_idx]->queue_id == qid) break; - if (wq_idx < phba->cfg_fcp_wq_count) { + if (wq_idx < phba->cfg_fcp_io_channel) { printk(KERN_ERR "FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[wq_idx]); return; @@ -644,9 +622,9 @@ lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid) do { if (phba->sli4_hba.fcp_cq[cq_idx]->queue_id == qid) break; - } while (++cq_idx < phba->cfg_fcp_eq_count); + } while (++cq_idx < phba->cfg_fcp_io_channel); - if (cq_idx < phba->cfg_fcp_eq_count) { + if (cq_idx < phba->cfg_fcp_io_channel) { printk(KERN_ERR "FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[cq_idx]); return; @@ -677,21 +655,17 @@ lpfc_debug_dump_eq_by_id(struct lpfc_hba *phba, int qid) { int eq_idx; - for (eq_idx = 0; eq_idx < phba->cfg_fcp_eq_count; eq_idx++) { - if (phba->sli4_hba.fp_eq[eq_idx]->queue_id == qid) + for (eq_idx = 0; eq_idx < phba->cfg_fcp_io_channel; eq_idx++) { + if (phba->sli4_hba.hba_eq[eq_idx]->queue_id == qid) break; } - if (eq_idx < phba->cfg_fcp_eq_count) { + if (eq_idx < phba->cfg_fcp_io_channel) { printk(KERN_ERR "FCP EQ[Idx:%d|Qid:%d]\n", eq_idx, qid); - lpfc_debug_dump_q(phba->sli4_hba.fp_eq[eq_idx]); + lpfc_debug_dump_q(phba->sli4_hba.hba_eq[eq_idx]); return; } - if (phba->sli4_hba.sp_eq->queue_id == qid) { - printk(KERN_ERR "SP EQ[|Qid:%d]\n", qid); - lpfc_debug_dump_q(phba->sli4_hba.sp_eq); - } } void lpfc_debug_dump_all_queues(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 1d84b63fccad..af49fb03dbb8 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -145,6 +145,7 @@ struct lpfc_node_rrq { #define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ #define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ #define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ +#define NLP_ISSUE_LOGO 0x00400000 /* waiting to issue a LOGO */ #define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful ACC */ #define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from @@ -201,10 +202,11 @@ struct lpfc_node_rrq { #define NLP_STE_ADISC_ISSUE 0x2 /* ADISC was sent to NL_PORT */ #define NLP_STE_REG_LOGIN_ISSUE 0x3 /* REG_LOGIN was issued for NL_PORT */ #define NLP_STE_PRLI_ISSUE 0x4 /* PRLI was sent to NL_PORT */ -#define NLP_STE_UNMAPPED_NODE 0x5 /* PRLI completed from NL_PORT */ -#define NLP_STE_MAPPED_NODE 0x6 /* Identified as a FCP Target */ -#define NLP_STE_NPR_NODE 0x7 /* NPort disappeared */ -#define NLP_STE_MAX_STATE 0x8 +#define NLP_STE_LOGO_ISSUE 0x5 /* LOGO was sent to NL_PORT */ +#define NLP_STE_UNMAPPED_NODE 0x6 /* PRLI completed from NL_PORT */ +#define NLP_STE_MAPPED_NODE 0x7 /* Identified as a FCP Target */ +#define NLP_STE_NPR_NODE 0x8 /* NPort disappeared */ +#define NLP_STE_MAX_STATE 0x9 #define NLP_STE_FREED_NODE 0xff /* node entry was freed to MEM_NLP */ /* For UNUSED_NODE state, the node has just been allocated. diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index d54ae1999797..cfe533bc9790 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -962,7 +962,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((phba->fcoe_cvl_eventtag_attn == phba->fcoe_cvl_eventtag) && (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)) + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_SLI_ABORTED)) goto stop_rr_fcf_flogi; else phba->fcoe_cvl_eventtag_attn = @@ -1108,8 +1109,10 @@ flogifail: /* Start discovery */ lpfc_disc_start(vport); } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) && - (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) && + (((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + IOERR_SLI_ABORTED) && + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + IOERR_SLI_DOWN))) && (phba->link_state != LPFC_CLEAR_LA)) { /* If FLOGI failed enable link interrupt. */ lpfc_issue_clear_la(phba, vport); @@ -1476,6 +1479,10 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, return ndlp; memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap)); + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3178 PLOGI confirm: ndlp %p x%x: new_ndlp %p\n", + ndlp, ndlp->nlp_DID, new_ndlp); + if (!new_ndlp) { rc = memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)); @@ -1527,6 +1534,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, /* The new_ndlp is replacing ndlp totally, so we need * to put ndlp on UNUSED list and try to free it. */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3179 PLOGI confirm NEW: %x %x\n", + new_ndlp->nlp_DID, keepDID); /* Fix up the rport accordingly */ rport = ndlp->rport; @@ -1559,23 +1569,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, lpfc_drop_node(vport, ndlp); } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3180 PLOGI confirm SWAP: %x %x\n", + new_ndlp->nlp_DID, keepDID); + lpfc_unreg_rpi(vport, ndlp); + /* Two ndlps cannot have the same did */ ndlp->nlp_DID = keepDID; if (phba->sli_rev == LPFC_SLI_REV4) memcpy(&ndlp->active_rrqs.xri_bitmap, &rrq.xri_bitmap, sizeof(ndlp->active_rrqs.xri_bitmap)); + /* Since we are swapping the ndlp passed in with the new one - * and the did has already been swapped, copy over the - * state and names. + * and the did has already been swapped, copy over state. + * The new WWNs are already in new_ndlp since thats what + * we looked it up by in the begining of this routine. */ - memcpy(&new_ndlp->nlp_portname, &ndlp->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(&new_ndlp->nlp_nodename, &ndlp->nlp_nodename, - sizeof(struct lpfc_name)); new_ndlp->nlp_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + + /* Since we are switching over to the new_ndlp, the old + * ndlp should be put in the NPR state, unless we have + * already started re-discovery on it. + */ + if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || + (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + /* Fix up the rport accordingly */ rport = ndlp->rport; if (rport) { @@ -2367,6 +2388,8 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_sli *psli; struct lpfcMboxq *mbox; + unsigned long flags; + uint32_t skip_recovery = 0; psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ @@ -2381,47 +2404,52 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "LOGO cmpl: status:x%x/x%x did:x%x", irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID); + /* LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout, vport->num_disc_nodes); - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) + + if (lpfc_els_chk_latt(vport)) { + skip_recovery = 1; goto out; + } + /* Check to see if link went down during discovery */ if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { /* NLP_EVT_DEVICE_RM should unregister the RPI * which should abort all outstanding IOs. */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_DEVICE_RM); + skip_recovery = 1; goto out; } if (irsp->ulpStatus) { /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) + if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ + skip_recovery = 1; goto out; + } /* LOGO failed */ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "2756 LOGO failure DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) + if (lpfc_error_lost_link(irsp)) { + skip_recovery = 1; goto out; - else - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_LOGO); - } else - /* Good status, call state machine. - * This will unregister the rpi if needed. - */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_LOGO); + } + } + + /* Call state machine. This will unregister the rpi if needed. */ + lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); + out: lpfc_els_free_iocb(phba, cmdiocb); /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */ @@ -2436,9 +2464,30 @@ out: if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); + skip_recovery = 1; } } } + + /* + * If the node is a target, the handling attempts to recover the port. + * For any other port type, the rpi is unregistered as an implicit + * LOGO. + */ + if ((ndlp->nlp_type & NLP_FCP_TARGET) && (skip_recovery == 0)) { + lpfc_cancel_retry_delay_tmo(vport, ndlp); + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irqrestore(shost->host_lock, flags); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3187 LOGO completes to NPort x%x: Start " + "Recovery Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, irsp->ulpStatus, + irsp->un.ulpWord[4], irsp->ulpTimeout, + vport->num_disc_nodes); + lpfc_disc_start(vport); + } return; } @@ -2501,10 +2550,27 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "Issue LOGO: did:x%x", ndlp->nlp_DID, 0, 0); + /* + * If we are issuing a LOGO, we may try to recover the remote NPort + * by issuing a PLOGI later. Even though we issue ELS cmds by the + * VPI, if we have a valid RPI, and that RPI gets unreg'ed while + * that ELS command is in-flight, the HBA returns a IOERR_INVALID_RPI + * for that ELS cmd. To avoid this situation, lets get rid of the + * RPI right now, before any ELS cmds are sent. + */ + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_ISSUE_LOGO; + spin_unlock_irq(shost->host_lock); + if (lpfc_unreg_rpi(vport, ndlp)) { + lpfc_els_free_iocb(phba, elsiocb); + return 0; + } + phba->fc_stat.elsXmitLOGO++; elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_LOGO_SND; + ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; spin_unlock_irq(shost->host_lock); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); @@ -2920,7 +2986,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) case ELS_CMD_LOGO: if (!lpfc_issue_els_logo(vport, ndlp, retry)) { ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE); } break; case ELS_CMD_FDISC: @@ -3007,7 +3073,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } break; case IOSTAT_LOCAL_REJECT: - switch ((irsp->un.ulpWord[4] & 0xff)) { + switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) { case IOERR_LOOP_OPEN_FAILURE: if (cmd == ELS_CMD_FLOGI) { if (PCI_DEVICE_ID_HORNET == @@ -3214,7 +3280,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) && ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) { + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + IOERR_NO_RESOURCES))) { /* Don't reset timer for no resources */ /* If discovery / RSCN timer is running, reset it */ @@ -3273,7 +3340,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return 1; case ELS_CMD_LOGO: ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE); lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry); return 1; } @@ -3533,13 +3600,17 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_put(ndlp); - /* This is the end of the default RPI cleanup logic for this - * ndlp. If no other discovery threads are using this ndlp. - * we should free all resources associated with it. - */ - lpfc_nlp_not_used(ndlp); + if (ndlp) { + if (NLP_CHK_NODE_ACT(ndlp)) { + lpfc_nlp_put(ndlp); + /* This is the end of the default RPI cleanup logic for + * this ndlp. If no other discovery threads are using + * this ndlp, free all resources associated with it. + */ + lpfc_nlp_not_used(ndlp); + } else { + lpfc_drop_node(ndlp->vport, ndlp); + } } return; @@ -6803,7 +6874,8 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT && - (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) { + (icmd->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_RCV_BUFFER_WAITING) { phba->fc_stat.NoRcvBuf++; /* Not enough posted buffers; Try posting more buffers */ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) @@ -7985,3 +8057,47 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, iflag); return; } + +/* lpfc_sli_abts_recover_port - Recover a port that failed a BLS_ABORT req. + * @vport: pointer to virtual port object. + * @ndlp: nodelist pointer for the impacted node. + * + * The driver calls this routine in response to an SLI4 XRI ABORT CQE + * or an SLI3 ASYNC_STATUS_CN event from the port. For either event, + * the driver is required to send a LOGO to the remote node before it + * attempts to recover its login to the remote node. + */ +void +lpfc_sli_abts_recover_port(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +{ + struct Scsi_Host *shost; + struct lpfc_hba *phba; + unsigned long flags = 0; + + shost = lpfc_shost_from_vport(vport); + phba = vport->phba; + if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI, "3093 No rport recovery needed. " + "rport in state 0x%x\n", ndlp->nlp_state); + return; + } + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3094 Start rport recovery on shost id 0x%x " + "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " + "flags 0x%x\n", + shost->host_no, ndlp->nlp_DID, + vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, + ndlp->nlp_flag); + /* + * The rport is not responding. Remove the FCP-2 flag to prevent + * an ADISC in the follow-up recovery code. + */ + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_issue_els_logo(vport, ndlp, 0); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE); +} + diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9b4f92941dce..e9845d2ecf10 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -123,6 +123,10 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) "rport devlosscb: sid:x%x did:x%x flg:x%x", ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3181 dev_loss_callbk x%06x, rport %p flg x%x\n", + ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); + /* Don't defer this if we are in the process of deleting the vport * or unloading the driver. The unload will cleanup the node * appropriately we just need to cleanup the ndlp rport info here. @@ -142,6 +146,15 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) return; + if (ndlp->nlp_type & NLP_FABRIC) { + + /* If the WWPN of the rport and ndlp don't match, ignore it */ + if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) { + put_device(&rport->dev); + return; + } + } + evtp = &ndlp->dev_loss_evt; if (!list_empty(&evtp->evt_listp)) @@ -202,6 +215,10 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) "rport devlosstmo:did:x%x type:x%x id:x%x", ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3182 dev_loss_tmo_handler x%06x, rport %p flg x%x\n", + ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); + /* Don't defer this if we are in the process of deleting the vport * or unloading the driver. The unload will cleanup the node * appropriately we just need to cleanup the ndlp rport info here. @@ -3492,7 +3509,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; struct static_vport_info *vport_info; - int rc = 0, i; + int mbx_wait_rc = 0, i; struct fc_vport_identifiers vport_id; struct fc_vport *new_fc_vport; struct Scsi_Host *shost; @@ -3509,7 +3526,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) " allocate mailbox memory\n"); return; } - + memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb = &pmb->u.mb; vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); @@ -3523,24 +3540,31 @@ lpfc_create_static_vport(struct lpfc_hba *phba) vport_buff = (uint8_t *) vport_info; do { + /* free dma buffer from previous round */ + if (pmb->context1) { + mp = (struct lpfc_dmabuf *)pmb->context1; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } if (lpfc_dump_static_vport(phba, pmb, offset)) goto out; pmb->vport = phba->pport; - rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO); + mbx_wait_rc = lpfc_sli_issue_mbox_wait(phba, pmb, + LPFC_MBOX_TMO); - if ((rc != MBX_SUCCESS) || mb->mbxStatus) { + if ((mbx_wait_rc != MBX_SUCCESS) || mb->mbxStatus) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0544 lpfc_create_static_vport failed to" " issue dump mailbox command ret 0x%x " "status 0x%x\n", - rc, mb->mbxStatus); + mbx_wait_rc, mb->mbxStatus); goto out; } if (phba->sli_rev == LPFC_SLI_REV4) { byte_count = pmb->u.mqe.un.mb_words[5]; - mp = (struct lpfc_dmabuf *) pmb->context2; + mp = (struct lpfc_dmabuf *)pmb->context1; if (byte_count > sizeof(struct static_vport_info) - offset) byte_count = sizeof(struct static_vport_info) @@ -3604,9 +3628,9 @@ lpfc_create_static_vport(struct lpfc_hba *phba) out: kfree(vport_info); - if (rc != MBX_TIMEOUT) { - if (pmb->context2) { - mp = (struct lpfc_dmabuf *) pmb->context2; + if (mbx_wait_rc != MBX_TIMEOUT) { + if (pmb->context1) { + mp = (struct lpfc_dmabuf *)pmb->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } @@ -3834,6 +3858,10 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3183 rport register x%06x, rport %p role x%x\n", + ndlp->nlp_DID, rport, rport_ids.roles); + if ((rport->scsi_target_id != -1) && (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; @@ -3850,6 +3878,10 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) "rport delete: did:x%x flg:x%x type x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3184 rport unregister x%06x, rport %p\n", + ndlp->nlp_DID, rport); + fc_remote_port_delete(rport); return; @@ -3964,6 +3996,7 @@ lpfc_nlp_state_name(char *buffer, size_t size, int state) [NLP_STE_ADISC_ISSUE] = "ADISC", [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN", [NLP_STE_PRLI_ISSUE] = "PRLI", + [NLP_STE_LOGO_ISSUE] = "LOGO", [NLP_STE_UNMAPPED_NODE] = "UNMAPPED", [NLP_STE_MAPPED_NODE] = "MAPPED", [NLP_STE_NPR_NODE] = "NPR", @@ -4330,6 +4363,26 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) return 0; } +/** + * lpfc_nlp_logo_unreg - Unreg mailbox completion handler before LOGO + * @phba: Pointer to HBA context object. + * @pmb: Pointer to mailbox object. + * + * This function will issue an ELS LOGO command after completing + * the UNREG_RPI. + **/ +void +lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + struct lpfc_nodelist *ndlp; + + ndlp = (struct lpfc_nodelist *)(pmb->context1); + if (!ndlp) + return; + lpfc_issue_els_logo(vport, ndlp, 0); +} + /* * Free rpi associated with LPFC_NODELIST entry. * This routine is called from lpfc_freenode(), when we are removing @@ -4354,9 +4407,16 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rpi = ndlp->nlp_rpi; if (phba->sli_rev == LPFC_SLI_REV4) rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + lpfc_unreg_login(phba, vport->vpi, rpi, mbox); mbox->vport = vport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { + mbox->context1 = ndlp; + mbox->mbox_cmpl = lpfc_nlp_logo_unreg; + } else { + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + } + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) mempool_free(mbox, phba->mbox_mem_pool); @@ -4499,9 +4559,13 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_disable_node(vport, ndlp); } + + /* Don't need to clean up REG_LOGIN64 cmds for Default RPI cleanup */ + /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && + !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mb->context2 = NULL; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -4512,6 +4576,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Cleanup REG_LOGIN completions which are not yet processed */ list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) { if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) || + (mb->mbox_flag & LPFC_MBX_IMED_UNREG) || (ndlp != (struct lpfc_nodelist *) mb->context2)) continue; @@ -4521,6 +4586,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && + !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { @@ -4585,7 +4651,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; mbox->vport = vport; - mbox->context2 = NULL; + mbox->context2 = ndlp; rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); @@ -5365,9 +5431,17 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) struct lpfc_nodelist *ndlp; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (filter(ndlp, param)) + if (filter(ndlp, param)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "3185 FIND node filter %p DID " + "Data: x%p x%x x%x\n", + filter, ndlp, ndlp->nlp_DID, + ndlp->nlp_flag); return ndlp; + } } + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "3186 FIND node filter %p NOT FOUND.\n", filter); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 41bb1d2fb625..7398ca862e97 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1188,8 +1188,8 @@ typedef struct { */ /* Number of rings currently used and available. */ -#define MAX_CONFIGURED_RINGS 3 -#define MAX_RINGS 4 +#define MAX_SLI3_CONFIGURED_RINGS 3 +#define MAX_SLI3_RINGS 4 /* IOCB / Mailbox is owned by FireFly */ #define OWN_CHIP 1 @@ -1251,6 +1251,8 @@ typedef struct { #define PCI_VENDOR_ID_SERVERENGINE 0x19a2 #define PCI_DEVICE_ID_TIGERSHARK 0x0704 #define PCI_DEVICE_ID_TOMCAT 0x0714 +#define PCI_DEVICE_ID_SKYHAWK 0x0724 +#define PCI_DEVICE_ID_SKYHAWK_VF 0x072c #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC @@ -1458,6 +1460,7 @@ typedef struct { /* FireFly BIU registers */ #define MBX_UNREG_FCFI 0xA2 #define MBX_INIT_VFI 0xA3 #define MBX_INIT_VPI 0xA4 +#define MBX_ACCESS_VDATA 0xA5 #define MBX_AUTH_PORT 0xF8 #define MBX_SECURITY_MGMT 0xF9 @@ -2991,7 +2994,7 @@ typedef struct _PCB { uint32_t pgpAddrLow; uint32_t pgpAddrHigh; - SLI2_RDSC rdsc[MAX_RINGS]; + SLI2_RDSC rdsc[MAX_SLI3_RINGS]; } PCB_t; /* NEW_FEATURE */ @@ -3101,18 +3104,18 @@ struct lpfc_pgp { struct sli2_desc { uint32_t unused1[16]; - struct lpfc_hgp host[MAX_RINGS]; - struct lpfc_pgp port[MAX_RINGS]; + struct lpfc_hgp host[MAX_SLI3_RINGS]; + struct lpfc_pgp port[MAX_SLI3_RINGS]; }; struct sli3_desc { - struct lpfc_hgp host[MAX_RINGS]; + struct lpfc_hgp host[MAX_SLI3_RINGS]; uint32_t reserved[8]; uint32_t hbq_put[16]; }; struct sli3_pgp { - struct lpfc_pgp port[MAX_RINGS]; + struct lpfc_pgp port[MAX_SLI3_RINGS]; uint32_t hbq_get[16]; }; @@ -3242,6 +3245,7 @@ typedef struct { #define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */ #define IOERR_SLI_BRESET 0x102 #define IOERR_SLI_ABORTED 0x103 +#define IOERR_PARAM_MASK 0x1ff } PARM_ERR; typedef union { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 953603a7a43c..834b699cac76 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -187,11 +187,17 @@ struct lpfc_sli_intf { /* Active interrupt test count */ #define LPFC_ACT_INTR_CNT 4 +/* Algrithmns for scheduling FCP commands to WQs */ +#define LPFC_FCP_SCHED_ROUND_ROBIN 0 +#define LPFC_FCP_SCHED_BY_CPU 1 + /* Delay Multiplier constant */ #define LPFC_DMULT_CONST 651042 -#define LPFC_MIM_IMAX 636 -#define LPFC_FP_DEF_IMAX 10000 -#define LPFC_SP_DEF_IMAX 10000 + +/* Configuration of Interrupts / sec for entire HBA port */ +#define LPFC_MIN_IMAX 5000 +#define LPFC_MAX_IMAX 5000000 +#define LPFC_DEF_IMAX 50000 /* PORT_CAPABILITIES constants. */ #define LPFC_MAX_SUPPORTED_PAGES 8 @@ -338,7 +344,7 @@ struct lpfc_cqe { * Define mask value for xri_aborted and wcqe completed CQE extended status. * Currently, extended status is limited to 9 bits (0x0 -> 0x103) . */ -#define WCQE_PARAM_MASK 0x1FF; +#define WCQE_PARAM_MASK 0x1FF /* completion queue entry for wqe completions */ struct lpfc_wcqe_complete { @@ -880,13 +886,19 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 #define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A #define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D +#define LPFC_MBOX_OPCODE_SET_PHYSICAL_LINK_CONFIG 0x3E +#define LPFC_MBOX_OPCODE_SET_BOOT_CONFIG 0x43 #define LPFC_MBOX_OPCODE_GET_PORT_NAME 0x4D #define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A +#define LPFC_MBOX_OPCODE_GET_VPD_DATA 0x5B +#define LPFC_MBOX_OPCODE_SEND_ACTIVATION 0x73 +#define LPFC_MBOX_OPCODE_RESET_LICENSES 0x74 #define LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO 0x9A #define LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT 0x9B #define LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT 0x9C #define LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT 0x9D #define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0 +#define LPFC_MBOX_OPCODE_GET_PROFILE_CAPACITIES 0xA1 #define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4 #define LPFC_MBOX_OPCODE_SET_PROFILE_CONFIG 0xA5 #define LPFC_MBOX_OPCODE_GET_PROFILE_LIST 0xA6 @@ -1382,6 +1394,11 @@ struct lpfc_mbx_set_link_diag_state { #define lpfc_mbx_set_diag_state_diag_SHIFT 0 #define lpfc_mbx_set_diag_state_diag_MASK 0x00000001 #define lpfc_mbx_set_diag_state_diag_WORD word0 +#define lpfc_mbx_set_diag_state_diag_bit_valid_SHIFT 2 +#define lpfc_mbx_set_diag_state_diag_bit_valid_MASK 0x00000001 +#define lpfc_mbx_set_diag_state_diag_bit_valid_WORD word0 +#define LPFC_DIAG_STATE_DIAG_BIT_VALID_NO_CHANGE 0 +#define LPFC_DIAG_STATE_DIAG_BIT_VALID_CHANGE 1 #define lpfc_mbx_set_diag_state_link_num_SHIFT 16 #define lpfc_mbx_set_diag_state_link_num_MASK 0x0000003F #define lpfc_mbx_set_diag_state_link_num_WORD word0 @@ -2556,7 +2573,7 @@ struct lpfc_mbx_get_sli4_parameters { }; struct lpfc_rscr_desc_generic { -#define LPFC_RSRC_DESC_WSIZE 18 +#define LPFC_RSRC_DESC_WSIZE 22 uint32_t desc[LPFC_RSRC_DESC_WSIZE]; }; @@ -2566,6 +2583,9 @@ struct lpfc_rsrc_desc_pcie { #define lpfc_rsrc_desc_pcie_type_MASK 0x000000ff #define lpfc_rsrc_desc_pcie_type_WORD word0 #define LPFC_RSRC_DESC_TYPE_PCIE 0x40 +#define lpfc_rsrc_desc_pcie_length_SHIFT 8 +#define lpfc_rsrc_desc_pcie_length_MASK 0x000000ff +#define lpfc_rsrc_desc_pcie_length_WORD word0 uint32_t word1; #define lpfc_rsrc_desc_pcie_pfnum_SHIFT 0 #define lpfc_rsrc_desc_pcie_pfnum_MASK 0x000000ff @@ -2593,6 +2613,12 @@ struct lpfc_rsrc_desc_fcfcoe { #define lpfc_rsrc_desc_fcfcoe_type_MASK 0x000000ff #define lpfc_rsrc_desc_fcfcoe_type_WORD word0 #define LPFC_RSRC_DESC_TYPE_FCFCOE 0x43 +#define lpfc_rsrc_desc_fcfcoe_length_SHIFT 8 +#define lpfc_rsrc_desc_fcfcoe_length_MASK 0x000000ff +#define lpfc_rsrc_desc_fcfcoe_length_WORD word0 +#define LPFC_RSRC_DESC_TYPE_FCFCOE_V0_RSVD 0 +#define LPFC_RSRC_DESC_TYPE_FCFCOE_V0_LENGTH 72 +#define LPFC_RSRC_DESC_TYPE_FCFCOE_V1_LENGTH 88 uint32_t word1; #define lpfc_rsrc_desc_fcfcoe_vfnum_SHIFT 0 #define lpfc_rsrc_desc_fcfcoe_vfnum_MASK 0x000000ff @@ -2651,6 +2677,12 @@ struct lpfc_rsrc_desc_fcfcoe { #define lpfc_rsrc_desc_fcfcoe_eq_cnt_SHIFT 16 #define lpfc_rsrc_desc_fcfcoe_eq_cnt_MASK 0x0000ffff #define lpfc_rsrc_desc_fcfcoe_eq_cnt_WORD word13 +/* extended FC/FCoE Resource Descriptor when length = 88 bytes */ + uint32_t bw_min; + uint32_t bw_max; + uint32_t iops_min; + uint32_t iops_max; + uint32_t reserved[4]; }; struct lpfc_func_cfg { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 45c15208be9f..654564fead6c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -480,11 +480,11 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->link_state = LPFC_LINK_DOWN; /* Only process IOCBs on ELS ring till hba_state is READY */ - if (psli->ring[psli->extra_ring].cmdringaddr) + if (psli->ring[psli->extra_ring].sli.sli3.cmdringaddr) psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT; - if (psli->ring[psli->fcp_ring].cmdringaddr) + if (psli->ring[psli->fcp_ring].sli.sli3.cmdringaddr) psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT; - if (psli->ring[psli->next_ring].cmdringaddr) + if (psli->ring[psli->next_ring].sli.sli3.cmdringaddr) psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT; /* Post receive buffers for desired rings */ @@ -2059,6 +2059,11 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) oneConnect = 1; m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; break; + case PCI_DEVICE_ID_SKYHAWK: + case PCI_DEVICE_ID_SKYHAWK_VF: + oneConnect = 1; + m = (typeof(m)){"OCe14000", "PCIe", "FCoE"}; + break; default: m = (typeof(m)){"Unknown", "", ""}; break; @@ -4546,6 +4551,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; } + if (!phba->sli.ring) + phba->sli.ring = (struct lpfc_sli_ring *) + kzalloc(LPFC_SLI3_MAX_RING * + sizeof(struct lpfc_sli_ring), GFP_KERNEL); + if (!phba->sli.ring) + return -ENOMEM; + /* * Since the sg_tablesize is module parameter, the sg_dma_buf_size * used to create the sg_dma_buf_pool must be dynamically calculated. @@ -4690,6 +4702,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Get all the module params for configuring this host */ lpfc_get_cfgparam(phba); phba->max_vpi = LPFC_MAX_VPI; + + /* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */ + phba->cfg_fcp_io_channel = phba->cfg_fcp_eq_count; + /* This will be set to correct value after the read_config mbox */ phba->max_vports = 0; @@ -4705,6 +4721,16 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sges_per_segment = 2; /* + * For SLI4, instead of using ring 0 (LPFC_FCP_RING) for FCP commands + * we will associate a new ring, for each FCP fastpath EQ/CQ/WQ tuple. + */ + if (!phba->sli.ring) + phba->sli.ring = kzalloc( + (LPFC_SLI3_MAX_RING + phba->cfg_fcp_io_channel) * + sizeof(struct lpfc_sli_ring), GFP_KERNEL); + if (!phba->sli.ring) + return -ENOMEM; + /* * Since the sg_tablesize is module parameter, the sg_dma_buf_size * used to create the sg_dma_buf_pool must be dynamically calculated. * 2 segments are added since the IOCB needs a command and response bde. @@ -4909,21 +4935,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_remove_rpi_hdrs; } - /* - * The cfg_fcp_eq_count can be zero whenever there is exactly one - * interrupt vector. This is not an error - */ - if (phba->cfg_fcp_eq_count) { - phba->sli4_hba.fcp_eq_hdl = - kzalloc((sizeof(struct lpfc_fcp_eq_hdl) * - phba->cfg_fcp_eq_count), GFP_KERNEL); - if (!phba->sli4_hba.fcp_eq_hdl) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2572 Failed allocate memory for " - "fast-path per-EQ handle array\n"); - rc = -ENOMEM; - goto out_free_fcf_rr_bmask; - } + phba->sli4_hba.fcp_eq_hdl = + kzalloc((sizeof(struct lpfc_fcp_eq_hdl) * + phba->cfg_fcp_io_channel), GFP_KERNEL); + if (!phba->sli4_hba.fcp_eq_hdl) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2572 Failed allocate memory for " + "fast-path per-EQ handle array\n"); + rc = -ENOMEM; + goto out_free_fcf_rr_bmask; } phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) * @@ -5550,6 +5570,10 @@ lpfc_hba_free(struct lpfc_hba *phba) /* Release the driver assigned board number */ idr_remove(&lpfc_hba_index, phba->brd_no); + /* Free memory allocated with sli rings */ + kfree(phba->sli.ring); + phba->sli.ring = NULL; + kfree(phba); return; } @@ -6275,8 +6299,9 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) uint32_t shdr_status, shdr_add_status; struct lpfc_mbx_get_func_cfg *get_func_cfg; struct lpfc_rsrc_desc_fcfcoe *desc; + char *pdesc_0; uint32_t desc_count; - int length, i, rc = 0; + int length, i, rc = 0, rc2; pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { @@ -6388,18 +6413,17 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG, length, LPFC_SLI4_MBX_EMBED); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); + rc2 = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); shdr = (union lpfc_sli4_cfg_shdr *) &pmb->u.mqe.un.sli4_config.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); - if (rc || shdr_status || shdr_add_status) { + if (rc2 || shdr_status || shdr_add_status) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3026 Mailbox failed , mbxCmd x%x " "GET_FUNCTION_CONFIG, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &pmb->u.mqe), bf_get(lpfc_mqe_status, &pmb->u.mqe)); - rc = -EIO; goto read_cfg_out; } @@ -6407,11 +6431,18 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) get_func_cfg = &pmb->u.mqe.un.get_func_cfg; desc_count = get_func_cfg->func_cfg.rsrc_desc_count; + pdesc_0 = (char *)&get_func_cfg->func_cfg.desc[0]; + desc = (struct lpfc_rsrc_desc_fcfcoe *)pdesc_0; + length = bf_get(lpfc_rsrc_desc_fcfcoe_length, desc); + if (length == LPFC_RSRC_DESC_TYPE_FCFCOE_V0_RSVD) + length = LPFC_RSRC_DESC_TYPE_FCFCOE_V0_LENGTH; + else if (length != LPFC_RSRC_DESC_TYPE_FCFCOE_V1_LENGTH) + goto read_cfg_out; + for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) { - desc = (struct lpfc_rsrc_desc_fcfcoe *) - &get_func_cfg->func_cfg.desc[i]; + desc = (struct lpfc_rsrc_desc_fcfcoe *)(pdesc_0 + length * i); if (LPFC_RSRC_DESC_TYPE_FCFCOE == - bf_get(lpfc_rsrc_desc_pcie_type, desc)) { + bf_get(lpfc_rsrc_desc_fcfcoe_type, desc)) { phba->sli4_hba.iov.pf_number = bf_get(lpfc_rsrc_desc_fcfcoe_pfnum, desc); phba->sli4_hba.iov.vf_number = @@ -6425,13 +6456,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) "3027 GET_FUNCTION_CONFIG: pf_number:%d, " "vf_number:%d\n", phba->sli4_hba.iov.pf_number, phba->sli4_hba.iov.vf_number); - else { + else lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3028 GET_FUNCTION_CONFIG: failed to find " "Resrouce Descriptor:x%x\n", LPFC_RSRC_DESC_TYPE_FCFCOE); - rc = -EIO; - } read_cfg_out: mempool_free(pmb, phba->mbox_mem_pool); @@ -6512,53 +6541,40 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) static int lpfc_sli4_queue_verify(struct lpfc_hba *phba) { - int cfg_fcp_wq_count; - int cfg_fcp_eq_count; + int cfg_fcp_io_channel; + uint32_t cpu; + uint32_t i = 0; + /* - * Sanity check for confiugred queue parameters against the run-time + * Sanity check for configured queue parameters against the run-time * device parameters */ - /* Sanity check on FCP fast-path WQ parameters */ - cfg_fcp_wq_count = phba->cfg_fcp_wq_count; - if (cfg_fcp_wq_count > - (phba->sli4_hba.max_cfg_param.max_wq - LPFC_SP_WQN_DEF)) { - cfg_fcp_wq_count = phba->sli4_hba.max_cfg_param.max_wq - - LPFC_SP_WQN_DEF; - if (cfg_fcp_wq_count < LPFC_FP_WQN_MIN) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2581 Not enough WQs (%d) from " - "the pci function for supporting " - "FCP WQs (%d)\n", - phba->sli4_hba.max_cfg_param.max_wq, - phba->cfg_fcp_wq_count); - goto out_error; - } + /* Sanity check on HBA EQ parameters */ + cfg_fcp_io_channel = phba->cfg_fcp_io_channel; + + /* It doesn't make sense to have more io channels then CPUs */ + for_each_online_cpu(cpu) { + i++; + } + if (i < cfg_fcp_io_channel) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2582 Not enough WQs (%d) from the pci " - "function for supporting the requested " - "FCP WQs (%d), the actual FCP WQs can " - "be supported: %d\n", - phba->sli4_hba.max_cfg_param.max_wq, - phba->cfg_fcp_wq_count, cfg_fcp_wq_count); - } - /* The actual number of FCP work queues adopted */ - phba->cfg_fcp_wq_count = cfg_fcp_wq_count; - - /* Sanity check on FCP fast-path EQ parameters */ - cfg_fcp_eq_count = phba->cfg_fcp_eq_count; - if (cfg_fcp_eq_count > - (phba->sli4_hba.max_cfg_param.max_eq - LPFC_SP_EQN_DEF)) { - cfg_fcp_eq_count = phba->sli4_hba.max_cfg_param.max_eq - - LPFC_SP_EQN_DEF; - if (cfg_fcp_eq_count < LPFC_FP_EQN_MIN) { + "3188 Reducing IO channels to match number of " + "CPUs: from %d to %d\n", cfg_fcp_io_channel, i); + cfg_fcp_io_channel = i; + } + + if (cfg_fcp_io_channel > + phba->sli4_hba.max_cfg_param.max_eq) { + cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq; + if (cfg_fcp_io_channel < LPFC_FCP_IO_CHAN_MIN) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2574 Not enough EQs (%d) from the " "pci function for supporting FCP " "EQs (%d)\n", phba->sli4_hba.max_cfg_param.max_eq, - phba->cfg_fcp_eq_count); + phba->cfg_fcp_io_channel); goto out_error; } lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -6567,22 +6583,16 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) "FCP EQs (%d), the actual FCP EQs can " "be supported: %d\n", phba->sli4_hba.max_cfg_param.max_eq, - phba->cfg_fcp_eq_count, cfg_fcp_eq_count); - } - /* It does not make sense to have more EQs than WQs */ - if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2593 The FCP EQ count(%d) cannot be greater " - "than the FCP WQ count(%d), limiting the " - "FCP EQ count to %d\n", cfg_fcp_eq_count, - phba->cfg_fcp_wq_count, - phba->cfg_fcp_wq_count); - cfg_fcp_eq_count = phba->cfg_fcp_wq_count; + phba->cfg_fcp_io_channel, cfg_fcp_io_channel); } + + /* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */ + /* The actual number of FCP event queues adopted */ - phba->cfg_fcp_eq_count = cfg_fcp_eq_count; - /* The overall number of event queues used */ - phba->sli4_hba.cfg_eqn = phba->cfg_fcp_eq_count + LPFC_SP_EQN_DEF; + phba->cfg_fcp_eq_count = cfg_fcp_io_channel; + phba->cfg_fcp_wq_count = cfg_fcp_io_channel; + phba->cfg_fcp_io_channel = cfg_fcp_io_channel; + phba->sli4_hba.cfg_eqn = cfg_fcp_io_channel; /* Get EQ depth from module parameter, fake the default for now */ phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B; @@ -6615,50 +6625,104 @@ int lpfc_sli4_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; - int fcp_eqidx, fcp_cqidx, fcp_wqidx; + int idx; /* - * Create Event Queues (EQs) + * Create HBA Record arrays. */ + if (!phba->cfg_fcp_io_channel) + return -ERANGE; - /* Create slow path event queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, - phba->sli4_hba.eq_ecount); - if (!qdesc) { + phba->sli4_hba.mq_esize = LPFC_MQE_SIZE; + phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT; + phba->sli4_hba.wq_esize = LPFC_WQE_SIZE; + phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT; + phba->sli4_hba.rq_esize = LPFC_RQE_SIZE; + phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT; + + phba->sli4_hba.hba_eq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_io_channel), GFP_KERNEL); + if (!phba->sli4_hba.hba_eq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2576 Failed allocate memory for " + "fast-path EQ record array\n"); + goto out_error; + } + + phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_io_channel), GFP_KERNEL); + if (!phba->sli4_hba.fcp_cq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0496 Failed allocate slow-path EQ\n"); + "2577 Failed allocate memory for fast-path " + "CQ record array\n"); + goto out_error; + } + + phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) * + phba->cfg_fcp_io_channel), GFP_KERNEL); + if (!phba->sli4_hba.fcp_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2578 Failed allocate memory for fast-path " + "WQ record array\n"); goto out_error; } - phba->sli4_hba.sp_eq = qdesc; /* - * Create fast-path FCP Event Queue(s). The cfg_fcp_eq_count can be - * zero whenever there is exactly one interrupt vector. This is not - * an error. + * Since the first EQ can have multiple CQs associated with it, + * this array is used to quickly see if we have a FCP fast-path + * CQ match. */ - if (phba->cfg_fcp_eq_count) { - phba->sli4_hba.fp_eq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_eq_count), GFP_KERNEL); - if (!phba->sli4_hba.fp_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2576 Failed allocate memory for " - "fast-path EQ record array\n"); - goto out_free_sp_eq; - } + phba->sli4_hba.fcp_cq_map = kzalloc((sizeof(uint16_t) * + phba->cfg_fcp_io_channel), GFP_KERNEL); + if (!phba->sli4_hba.fcp_cq_map) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2545 Failed allocate memory for fast-path " + "CQ map\n"); + goto out_error; } - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { + + /* + * Create HBA Event Queues (EQs). The cfg_fcp_io_channel specifies + * how many EQs to create. + */ + for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) { + + /* Create EQs */ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0497 Failed allocate fast-path EQ\n"); - goto out_free_fp_eq; + "0497 Failed allocate EQ (%d)\n", idx); + goto out_error; } - phba->sli4_hba.fp_eq[fcp_eqidx] = qdesc; + phba->sli4_hba.hba_eq[idx] = qdesc; + + /* Create Fast Path FCP CQs */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0499 Failed allocate fast-path FCP " + "CQ (%d)\n", idx); + goto out_error; + } + phba->sli4_hba.fcp_cq[idx] = qdesc; + + /* Create Fast Path FCP WQs */ + qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + phba->sli4_hba.wq_ecount); + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0503 Failed allocate fast-path FCP " + "WQ (%d)\n", idx); + goto out_error; + } + phba->sli4_hba.fcp_wq[idx] = qdesc; } + /* - * Create Complete Queues (CQs) + * Create Slow Path Completion Queues (CQs) */ /* Create slow-path Mailbox Command Complete Queue */ @@ -6667,7 +6731,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0500 Failed allocate slow-path mailbox CQ\n"); - goto out_free_fp_eq; + goto out_error; } phba->sli4_hba.mbx_cq = qdesc; @@ -6677,59 +6741,29 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0501 Failed allocate slow-path ELS CQ\n"); - goto out_free_mbx_cq; + goto out_error; } phba->sli4_hba.els_cq = qdesc; /* - * Create fast-path FCP Completion Queue(s), one-to-one with FCP EQs. - * If there are no FCP EQs then create exactly one FCP CQ. + * Create Slow Path Work Queues (WQs) */ - if (phba->cfg_fcp_eq_count) - phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_eq_count), - GFP_KERNEL); - else - phba->sli4_hba.fcp_cq = kzalloc(sizeof(struct lpfc_queue *), - GFP_KERNEL); - if (!phba->sli4_hba.fcp_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2577 Failed allocate memory for fast-path " - "CQ record array\n"); - goto out_free_els_cq; - } - fcp_cqidx = 0; - do { - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0499 Failed allocate fast-path FCP " - "CQ (%d)\n", fcp_cqidx); - goto out_free_fcp_cq; - } - phba->sli4_hba.fcp_cq[fcp_cqidx] = qdesc; - } while (++fcp_cqidx < phba->cfg_fcp_eq_count); /* Create Mailbox Command Queue */ - phba->sli4_hba.mq_esize = LPFC_MQE_SIZE; - phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT; qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize, phba->sli4_hba.mq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0505 Failed allocate slow-path MQ\n"); - goto out_free_fcp_cq; + goto out_error; } phba->sli4_hba.mbx_wq = qdesc; /* - * Create all the Work Queues (WQs) + * Create ELS Work Queues */ - phba->sli4_hba.wq_esize = LPFC_WQE_SIZE; - phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT; /* Create slow-path ELS Work Queue */ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, @@ -6737,36 +6771,13 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0504 Failed allocate slow-path ELS WQ\n"); - goto out_free_mbx_wq; + goto out_error; } phba->sli4_hba.els_wq = qdesc; - /* Create fast-path FCP Work Queue(s) */ - phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_wq_count), GFP_KERNEL); - if (!phba->sli4_hba.fcp_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2578 Failed allocate memory for fast-path " - "WQ record array\n"); - goto out_free_els_wq; - } - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0503 Failed allocate fast-path FCP " - "WQ (%d)\n", fcp_wqidx); - goto out_free_fcp_wq; - } - phba->sli4_hba.fcp_wq[fcp_wqidx] = qdesc; - } - /* * Create Receive Queue (RQ) */ - phba->sli4_hba.rq_esize = LPFC_RQE_SIZE; - phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT; /* Create Receive Queue for header */ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, @@ -6774,7 +6785,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0506 Failed allocate receive HRQ\n"); - goto out_free_fcp_wq; + goto out_error; } phba->sli4_hba.hdr_rq = qdesc; @@ -6784,52 +6795,14 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0507 Failed allocate receive DRQ\n"); - goto out_free_hdr_rq; + goto out_error; } phba->sli4_hba.dat_rq = qdesc; return 0; -out_free_hdr_rq: - lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); - phba->sli4_hba.hdr_rq = NULL; -out_free_fcp_wq: - for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_wqidx]); - phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL; - } - kfree(phba->sli4_hba.fcp_wq); - phba->sli4_hba.fcp_wq = NULL; -out_free_els_wq: - lpfc_sli4_queue_free(phba->sli4_hba.els_wq); - phba->sli4_hba.els_wq = NULL; -out_free_mbx_wq: - lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); - phba->sli4_hba.mbx_wq = NULL; -out_free_fcp_cq: - for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_cqidx]); - phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; - } - kfree(phba->sli4_hba.fcp_cq); - phba->sli4_hba.fcp_cq = NULL; -out_free_els_cq: - lpfc_sli4_queue_free(phba->sli4_hba.els_cq); - phba->sli4_hba.els_cq = NULL; -out_free_mbx_cq: - lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); - phba->sli4_hba.mbx_cq = NULL; -out_free_fp_eq: - for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_eqidx]); - phba->sli4_hba.fp_eq[fcp_eqidx] = NULL; - } - kfree(phba->sli4_hba.fp_eq); - phba->sli4_hba.fp_eq = NULL; -out_free_sp_eq: - lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); - phba->sli4_hba.sp_eq = NULL; out_error: + lpfc_sli4_queue_destroy(phba); return -ENOMEM; } @@ -6848,58 +6821,86 @@ out_error: void lpfc_sli4_queue_destroy(struct lpfc_hba *phba) { - int fcp_qidx; + int idx; + + if (phba->sli4_hba.hba_eq != NULL) { + /* Release HBA event queue */ + for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) { + if (phba->sli4_hba.hba_eq[idx] != NULL) { + lpfc_sli4_queue_free( + phba->sli4_hba.hba_eq[idx]); + phba->sli4_hba.hba_eq[idx] = NULL; + } + } + kfree(phba->sli4_hba.hba_eq); + phba->sli4_hba.hba_eq = NULL; + } + + if (phba->sli4_hba.fcp_cq != NULL) { + /* Release FCP completion queue */ + for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) { + if (phba->sli4_hba.fcp_cq[idx] != NULL) { + lpfc_sli4_queue_free( + phba->sli4_hba.fcp_cq[idx]); + phba->sli4_hba.fcp_cq[idx] = NULL; + } + } + kfree(phba->sli4_hba.fcp_cq); + phba->sli4_hba.fcp_cq = NULL; + } + + if (phba->sli4_hba.fcp_wq != NULL) { + /* Release FCP work queue */ + for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) { + if (phba->sli4_hba.fcp_wq[idx] != NULL) { + lpfc_sli4_queue_free( + phba->sli4_hba.fcp_wq[idx]); + phba->sli4_hba.fcp_wq[idx] = NULL; + } + } + kfree(phba->sli4_hba.fcp_wq); + phba->sli4_hba.fcp_wq = NULL; + } + + /* Release FCP CQ mapping array */ + if (phba->sli4_hba.fcp_cq_map != NULL) { + kfree(phba->sli4_hba.fcp_cq_map); + phba->sli4_hba.fcp_cq_map = NULL; + } /* Release mailbox command work queue */ - lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); - phba->sli4_hba.mbx_wq = NULL; + if (phba->sli4_hba.mbx_wq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); + phba->sli4_hba.mbx_wq = NULL; + } /* Release ELS work queue */ - lpfc_sli4_queue_free(phba->sli4_hba.els_wq); - phba->sli4_hba.els_wq = NULL; - - /* Release FCP work queue */ - if (phba->sli4_hba.fcp_wq != NULL) - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; - fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); - kfree(phba->sli4_hba.fcp_wq); - phba->sli4_hba.fcp_wq = NULL; + if (phba->sli4_hba.els_wq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.els_wq); + phba->sli4_hba.els_wq = NULL; + } /* Release unsolicited receive queue */ - lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); - phba->sli4_hba.hdr_rq = NULL; - lpfc_sli4_queue_free(phba->sli4_hba.dat_rq); - phba->sli4_hba.dat_rq = NULL; + if (phba->sli4_hba.hdr_rq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); + phba->sli4_hba.hdr_rq = NULL; + } + if (phba->sli4_hba.dat_rq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.dat_rq); + phba->sli4_hba.dat_rq = NULL; + } /* Release ELS complete queue */ - lpfc_sli4_queue_free(phba->sli4_hba.els_cq); - phba->sli4_hba.els_cq = NULL; + if (phba->sli4_hba.els_cq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.els_cq); + phba->sli4_hba.els_cq = NULL; + } /* Release mailbox command complete queue */ - lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); - phba->sli4_hba.mbx_cq = NULL; - - /* Release FCP response complete queue */ - fcp_qidx = 0; - if (phba->sli4_hba.fcp_cq != NULL) - do - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); - while (++fcp_qidx < phba->cfg_fcp_eq_count); - kfree(phba->sli4_hba.fcp_cq); - phba->sli4_hba.fcp_cq = NULL; - - /* Release fast-path event queue */ - if (phba->sli4_hba.fp_eq != NULL) - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; - fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); - kfree(phba->sli4_hba.fp_eq); - phba->sli4_hba.fp_eq = NULL; - - /* Release slow-path event queue */ - lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); - phba->sli4_hba.sp_eq = NULL; + if (phba->sli4_hba.mbx_cq != NULL) { + lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); + phba->sli4_hba.mbx_cq = NULL; + } return; } @@ -6919,61 +6920,124 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) int lpfc_sli4_queue_setup(struct lpfc_hba *phba) { + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; int rc = -ENOMEM; int fcp_eqidx, fcp_cqidx, fcp_wqidx; int fcp_cq_index = 0; /* - * Set up Event Queues (EQs) + * Set up HBA Event Queues (EQs) */ - /* Set up slow-path event queue */ - if (!phba->sli4_hba.sp_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0520 Slow-path EQ not allocated\n"); - goto out_error; - } - rc = lpfc_eq_create(phba, phba->sli4_hba.sp_eq, - LPFC_SP_DEF_IMAX); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0521 Failed setup of slow-path EQ: " - "rc = 0x%x\n", rc); - goto out_error; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2583 Slow-path EQ setup: queue-id=%d\n", - phba->sli4_hba.sp_eq->queue_id); - - /* Set up fast-path event queue */ - if (phba->cfg_fcp_eq_count && !phba->sli4_hba.fp_eq) { + /* Set up HBA event queue */ + if (phba->cfg_fcp_io_channel && !phba->sli4_hba.hba_eq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3147 Fast-path EQs not allocated\n"); rc = -ENOMEM; - goto out_destroy_sp_eq; + goto out_error; } - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - if (!phba->sli4_hba.fp_eq[fcp_eqidx]) { + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) { + if (!phba->sli4_hba.hba_eq[fcp_eqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0522 Fast-path EQ (%d) not " "allocated\n", fcp_eqidx); rc = -ENOMEM; - goto out_destroy_fp_eq; + goto out_destroy_hba_eq; } - rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx], - phba->cfg_fcp_imax); + rc = lpfc_eq_create(phba, phba->sli4_hba.hba_eq[fcp_eqidx], + (phba->cfg_fcp_imax / phba->cfg_fcp_io_channel)); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0523 Failed setup of fast-path EQ " "(%d), rc = 0x%x\n", fcp_eqidx, rc); - goto out_destroy_fp_eq; + goto out_destroy_hba_eq; } lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2584 Fast-path EQ setup: " + "2584 HBA EQ setup: " "queue[%d]-id=%d\n", fcp_eqidx, - phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id); + phba->sli4_hba.hba_eq[fcp_eqidx]->queue_id); } + /* Set up fast-path FCP Response Complete Queue */ + if (!phba->sli4_hba.fcp_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3148 Fast-path FCP CQ array not " + "allocated\n"); + rc = -ENOMEM; + goto out_destroy_hba_eq; + } + + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_io_channel; fcp_cqidx++) { + if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0526 Fast-path FCP CQ (%d) not " + "allocated\n", fcp_cqidx); + rc = -ENOMEM; + goto out_destroy_fcp_cq; + } + rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx], + phba->sli4_hba.hba_eq[fcp_cqidx], LPFC_WCQ, LPFC_FCP); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0527 Failed setup of fast-path FCP " + "CQ (%d), rc = 0x%x\n", fcp_cqidx, rc); + goto out_destroy_fcp_cq; + } + + /* Setup fcp_cq_map for fast lookup */ + phba->sli4_hba.fcp_cq_map[fcp_cqidx] = + phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2588 FCP CQ setup: cq[%d]-id=%d, " + "parent seq[%d]-id=%d\n", + fcp_cqidx, + phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id, + fcp_cqidx, + phba->sli4_hba.hba_eq[fcp_cqidx]->queue_id); + } + + /* Set up fast-path FCP Work Queue */ + if (!phba->sli4_hba.fcp_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3149 Fast-path FCP WQ array not " + "allocated\n"); + rc = -ENOMEM; + goto out_destroy_fcp_cq; + } + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_io_channel; fcp_wqidx++) { + if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0534 Fast-path FCP WQ (%d) not " + "allocated\n", fcp_wqidx); + rc = -ENOMEM; + goto out_destroy_fcp_wq; + } + rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], + phba->sli4_hba.fcp_cq[fcp_wqidx], + LPFC_FCP); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0535 Failed setup of fast-path FCP " + "WQ (%d), rc = 0x%x\n", fcp_wqidx, rc); + goto out_destroy_fcp_wq; + } + + /* Bind this WQ to the next FCP ring */ + pring = &psli->ring[MAX_SLI3_CONFIGURED_RINGS + fcp_wqidx]; + pring->sli.sli4.wqp = (void *)phba->sli4_hba.fcp_wq[fcp_wqidx]; + phba->sli4_hba.fcp_cq[fcp_wqidx]->pring = pring; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2591 FCP WQ setup: wq[%d]-id=%d, " + "parent cq[%d]-id=%d\n", + fcp_wqidx, + phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cq_index, + phba->sli4_hba.fcp_cq[fcp_wqidx]->queue_id); + } /* * Set up Complete Queues (CQs) */ @@ -6983,20 +7047,20 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0528 Mailbox CQ not allocated\n"); rc = -ENOMEM; - goto out_destroy_fp_eq; + goto out_destroy_fcp_wq; } - rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq, - LPFC_MCQ, LPFC_MBOX); + rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, + phba->sli4_hba.hba_eq[0], LPFC_MCQ, LPFC_MBOX); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0529 Failed setup of slow-path mailbox CQ: " "rc = 0x%x\n", rc); - goto out_destroy_fp_eq; + goto out_destroy_fcp_wq; } lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2585 MBX CQ setup: cq-id=%d, parent eq-id=%d\n", phba->sli4_hba.mbx_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); + phba->sli4_hba.hba_eq[0]->queue_id); /* Set up slow-path ELS Complete Queue */ if (!phba->sli4_hba.els_cq) { @@ -7005,8 +7069,8 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = -ENOMEM; goto out_destroy_mbx_cq; } - rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq, - LPFC_WCQ, LPFC_ELS); + rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, + phba->sli4_hba.hba_eq[0], LPFC_WCQ, LPFC_ELS); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0531 Failed setup of slow-path ELS CQ: " @@ -7016,52 +7080,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2586 ELS CQ setup: cq-id=%d, parent eq-id=%d\n", phba->sli4_hba.els_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); - - /* Set up fast-path FCP Response Complete Queue */ - if (!phba->sli4_hba.fcp_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3148 Fast-path FCP CQ array not " - "allocated\n"); - rc = -ENOMEM; - goto out_destroy_els_cq; - } - fcp_cqidx = 0; - do { - if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0526 Fast-path FCP CQ (%d) not " - "allocated\n", fcp_cqidx); - rc = -ENOMEM; - goto out_destroy_fcp_cq; - } - if (phba->cfg_fcp_eq_count) - rc = lpfc_cq_create(phba, - phba->sli4_hba.fcp_cq[fcp_cqidx], - phba->sli4_hba.fp_eq[fcp_cqidx], - LPFC_WCQ, LPFC_FCP); - else - rc = lpfc_cq_create(phba, - phba->sli4_hba.fcp_cq[fcp_cqidx], - phba->sli4_hba.sp_eq, - LPFC_WCQ, LPFC_FCP); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0527 Failed setup of fast-path FCP " - "CQ (%d), rc = 0x%x\n", fcp_cqidx, rc); - goto out_destroy_fcp_cq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2588 FCP CQ setup: cq[%d]-id=%d, " - "parent %seq[%d]-id=%d\n", - fcp_cqidx, - phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id, - (phba->cfg_fcp_eq_count) ? "" : "sp_", - fcp_cqidx, - (phba->cfg_fcp_eq_count) ? - phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id : - phba->sli4_hba.sp_eq->queue_id); - } while (++fcp_cqidx < phba->cfg_fcp_eq_count); + phba->sli4_hba.hba_eq[0]->queue_id); /* * Set up all the Work Queues (WQs) @@ -7072,7 +7091,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0538 Slow-path MQ not allocated\n"); rc = -ENOMEM; - goto out_destroy_fcp_cq; + goto out_destroy_els_cq; } rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq, phba->sli4_hba.mbx_cq, LPFC_MBOX); @@ -7080,7 +7099,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0539 Failed setup of slow-path MQ: " "rc = 0x%x\n", rc); - goto out_destroy_fcp_cq; + goto out_destroy_els_cq; } lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2589 MBX MQ setup: wq-id=%d, parent cq-id=%d\n", @@ -7102,49 +7121,17 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) "rc = 0x%x\n", rc); goto out_destroy_mbx_wq; } + + /* Bind this WQ to the ELS ring */ + pring = &psli->ring[LPFC_ELS_RING]; + pring->sli.sli4.wqp = (void *)phba->sli4_hba.els_wq; + phba->sli4_hba.els_cq->pring = pring; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2590 ELS WQ setup: wq-id=%d, parent cq-id=%d\n", phba->sli4_hba.els_wq->queue_id, phba->sli4_hba.els_cq->queue_id); - /* Set up fast-path FCP Work Queue */ - if (!phba->sli4_hba.fcp_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3149 Fast-path FCP WQ array not " - "allocated\n"); - rc = -ENOMEM; - goto out_destroy_els_wq; - } - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { - if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0534 Fast-path FCP WQ (%d) not " - "allocated\n", fcp_wqidx); - rc = -ENOMEM; - goto out_destroy_fcp_wq; - } - rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], - phba->sli4_hba.fcp_cq[fcp_cq_index], - LPFC_FCP); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0535 Failed setup of fast-path FCP " - "WQ (%d), rc = 0x%x\n", fcp_wqidx, rc); - goto out_destroy_fcp_wq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2591 FCP WQ setup: wq[%d]-id=%d, " - "parent cq[%d]-id=%d\n", - fcp_wqidx, - phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, - fcp_cq_index, - phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id); - /* Round robin FCP Work Queue's Completion Queue assignment */ - if (phba->cfg_fcp_eq_count) - fcp_cq_index = ((fcp_cq_index + 1) % - phba->cfg_fcp_eq_count); - } - /* * Create Receive Queue (RQ) */ @@ -7152,7 +7139,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0540 Receive Queue not allocated\n"); rc = -ENOMEM; - goto out_destroy_fcp_wq; + goto out_destroy_els_wq; } lpfc_rq_adjust_repost(phba, phba->sli4_hba.hdr_rq, LPFC_ELS_HBQ); @@ -7175,25 +7162,23 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_cq->queue_id); return 0; -out_destroy_fcp_wq: - for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) - lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); out_destroy_els_wq: lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); out_destroy_mbx_wq: lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); -out_destroy_fcp_cq: - for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) - lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); out_destroy_els_cq: lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); out_destroy_mbx_cq: lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); -out_destroy_fp_eq: +out_destroy_fcp_wq: + for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) + lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); +out_destroy_fcp_cq: + for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) + lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); +out_destroy_hba_eq: for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]); -out_destroy_sp_eq: - lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); + lpfc_eq_destroy(phba, phba->sli4_hba.hba_eq[fcp_eqidx]); out_error: return rc; } @@ -7222,27 +7207,27 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) /* Unset unsolicited receive queue */ lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq); /* Unset FCP work queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) - lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]); + if (phba->sli4_hba.fcp_wq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_io_channel; + fcp_qidx++) + lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]); + } /* Unset mailbox command complete queue */ lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); /* Unset ELS complete queue */ lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); /* Unset FCP response complete queue */ if (phba->sli4_hba.fcp_cq) { - fcp_qidx = 0; - do { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_io_channel; + fcp_qidx++) lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); } /* Unset fast-path event queue */ - if (phba->sli4_hba.fp_eq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + if (phba->sli4_hba.hba_eq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_io_channel; fcp_qidx++) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + lpfc_eq_destroy(phba, phba->sli4_hba.hba_eq[fcp_qidx]); } - /* Unset slow-path event queue */ - lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); } /** @@ -7590,10 +7575,11 @@ lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt) /* Set up NOP SLI4_CONFIG mailbox-ioctl command */ length = (sizeof(struct lpfc_mbx_nop) - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_NOP, length, LPFC_SLI4_MBX_EMBED); for (cmdsent = 0; cmdsent < cnt; cmdsent++) { + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_NOP, length, + LPFC_SLI4_MBX_EMBED); if (!phba->sli4_hba.intr_enable) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); else { @@ -8133,33 +8119,22 @@ enable_msix_vectors: "message=%d\n", index, phba->sli4_hba.msix_entries[index].vector, phba->sli4_hba.msix_entries[index].entry); + /* * Assign MSI-X vectors to interrupt handlers */ - if (vectors > 1) - rc = request_irq(phba->sli4_hba.msix_entries[0].vector, - &lpfc_sli4_sp_intr_handler, IRQF_SHARED, - LPFC_SP_DRIVER_HANDLER_NAME, phba); - else - /* All Interrupts need to be handled by one EQ */ - rc = request_irq(phba->sli4_hba.msix_entries[0].vector, - &lpfc_sli4_intr_handler, IRQF_SHARED, - LPFC_DRIVER_NAME, phba); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0485 MSI-X slow-path request_irq failed " - "(%d)\n", rc); - goto msi_fail_out; - } + for (index = 0; index < vectors; index++) { + memset(&phba->sli4_hba.handler_name[index], 0, 16); + sprintf((char *)&phba->sli4_hba.handler_name[index], + LPFC_DRIVER_HANDLER_NAME"%d", index); - /* The rest of the vector(s) are associated to fast-path handler(s) */ - for (index = 1; index < vectors; index++) { - phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; - phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; + phba->sli4_hba.fcp_eq_hdl[index].idx = index; + phba->sli4_hba.fcp_eq_hdl[index].phba = phba; + atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].fcp_eq_in_use, 1); rc = request_irq(phba->sli4_hba.msix_entries[index].vector, - &lpfc_sli4_fp_intr_handler, IRQF_SHARED, - LPFC_FP_DRIVER_HANDLER_NAME, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); + &lpfc_sli4_hba_intr_handler, IRQF_SHARED, + (char *)&phba->sli4_hba.handler_name[index], + &phba->sli4_hba.fcp_eq_hdl[index]); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0486 MSI-X fast-path (%d) " @@ -8173,12 +8148,9 @@ enable_msix_vectors: cfg_fail_out: /* free the irq already requested */ - for (--index; index >= 1; index--) - free_irq(phba->sli4_hba.msix_entries[index - 1].vector, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); - - /* free the irq already requested */ - free_irq(phba->sli4_hba.msix_entries[0].vector, phba); + for (--index; index >= 0; index--) + free_irq(phba->sli4_hba.msix_entries[index].vector, + &phba->sli4_hba.fcp_eq_hdl[index]); msi_fail_out: /* Unconfigure MSI-X capability structure */ @@ -8199,11 +8171,9 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba) int index; /* Free up MSI-X multi-message vectors */ - free_irq(phba->sli4_hba.msix_entries[0].vector, phba); - - for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++) + for (index = 0; index < phba->sli4_hba.msix_vec_nr; index++) free_irq(phba->sli4_hba.msix_entries[index].vector, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); + &phba->sli4_hba.fcp_eq_hdl[index]); /* Disable MSI-X */ pci_disable_msix(phba->pcidev); @@ -8249,7 +8219,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) return rc; } - for (index = 0; index < phba->cfg_fcp_eq_count; index++) { + for (index = 0; index < phba->cfg_fcp_io_channel; index++) { phba->sli4_hba.fcp_eq_hdl[index].idx = index; phba->sli4_hba.fcp_eq_hdl[index].phba = phba; } @@ -8329,10 +8299,12 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) /* Indicate initialization to INTx mode */ phba->intr_type = INTx; intr_mode = 0; - for (index = 0; index < phba->cfg_fcp_eq_count; + for (index = 0; index < phba->cfg_fcp_io_channel; index++) { phba->sli4_hba.fcp_eq_hdl[index].idx = index; phba->sli4_hba.fcp_eq_hdl[index].phba = phba; + atomic_set(&phba->sli4_hba.fcp_eq_hdl[index]. + fcp_eq_in_use, 1); } } } @@ -9449,7 +9421,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) int error; uint32_t cfg_mode, intr_mode; int mcnt; - int adjusted_fcp_eq_count; + int adjusted_fcp_io_channel; const struct firmware *fw; uint8_t file_name[16]; @@ -9552,13 +9524,13 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) } /* Default to single EQ for non-MSI-X */ if (phba->intr_type != MSIX) - adjusted_fcp_eq_count = 0; + adjusted_fcp_io_channel = 1; else if (phba->sli4_hba.msix_vec_nr < - phba->cfg_fcp_eq_count + 1) - adjusted_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1; + phba->cfg_fcp_io_channel) + adjusted_fcp_io_channel = phba->sli4_hba.msix_vec_nr; else - adjusted_fcp_eq_count = phba->cfg_fcp_eq_count; - phba->cfg_fcp_eq_count = adjusted_fcp_eq_count; + adjusted_fcp_io_channel = phba->cfg_fcp_io_channel; + phba->cfg_fcp_io_channel = adjusted_fcp_io_channel; /* Set up SLI-4 HBA */ if (lpfc_sli4_hba_setup(phba)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -9694,6 +9666,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) * buffers are released to their corresponding pools here. */ lpfc_scsi_free(phba); + lpfc_sli4_driver_resource_unset(phba); /* Unmap adapter Control and Doorbell registers */ @@ -10420,6 +10393,10 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 20336f09fb3c..efc9cd9def8b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -92,7 +92,7 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, memset(mp->virt, 0, LPFC_BPL_SIZE); INIT_LIST_HEAD(&mp->list); /* save address for completion */ - pmb->context2 = (uint8_t *) mp; + pmb->context1 = (uint8_t *)mp; mb->un.varWords[3] = putPaddrLow(mp->phys); mb->un.varWords[4] = putPaddrHigh(mp->phys); mb->un.varDmp.sli4_length = sizeof(struct static_vport_info); @@ -950,44 +950,47 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE: + pring->sli.sli3.sizeCiocb = + phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE: + pring->sli.sli3.sizeRiocb = + phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; /* A ring MUST have both cmd and rsp entries defined to be valid */ - if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { + if ((pring->sli.sli3.numCiocb == 0) || + (pring->sli.sli3.numRiocb == 0)) { pcbp->rdsc[i].cmdEntries = 0; pcbp->rdsc[i].rspEntries = 0; pcbp->rdsc[i].cmdAddrHigh = 0; pcbp->rdsc[i].rspAddrHigh = 0; pcbp->rdsc[i].cmdAddrLow = 0; pcbp->rdsc[i].rspAddrLow = 0; - pring->cmdringaddr = NULL; - pring->rspringaddr = NULL; + pring->sli.sli3.cmdringaddr = NULL; + pring->sli.sli3.rspringaddr = NULL; continue; } /* Command ring setup for ring */ - pring->cmdringaddr = (void *)&phba->IOCBs[iocbCnt]; - pcbp->rdsc[i].cmdEntries = pring->numCiocb; + pring->sli.sli3.cmdringaddr = (void *)&phba->IOCBs[iocbCnt]; + pcbp->rdsc[i].cmdEntries = pring->sli.sli3.numCiocb; offset = (uint8_t *) &phba->IOCBs[iocbCnt] - (uint8_t *) phba->slim2p.virt; pdma_addr = phba->slim2p.phys + offset; pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr); pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr); - iocbCnt += pring->numCiocb; + iocbCnt += pring->sli.sli3.numCiocb; /* Response ring setup for ring */ - pring->rspringaddr = (void *) &phba->IOCBs[iocbCnt]; + pring->sli.sli3.rspringaddr = (void *) &phba->IOCBs[iocbCnt]; - pcbp->rdsc[i].rspEntries = pring->numRiocb; + pcbp->rdsc[i].rspEntries = pring->sli.sli3.numRiocb; offset = (uint8_t *)&phba->IOCBs[iocbCnt] - (uint8_t *)phba->slim2p.virt; pdma_addr = phba->slim2p.phys + offset; pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr); pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr); - iocbCnt += pring->numRiocb; + iocbCnt += pring->sli.sli3.numRiocb; } } @@ -1609,12 +1612,15 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) switch (mbox->mbxCommand) { case MBX_WRITE_NV: /* 0x03 */ + case MBX_DUMP_MEMORY: /* 0x17 */ case MBX_UPDATE_CFG: /* 0x1B */ case MBX_DOWN_LOAD: /* 0x1C */ case MBX_DEL_LD_ENTRY: /* 0x1D */ + case MBX_WRITE_VPARMS: /* 0x32 */ case MBX_LOAD_AREA: /* 0x81 */ case MBX_WRITE_WWN: /* 0x98 */ case MBX_LOAD_EXP_ROM: /* 0x9C */ + case MBX_ACCESS_VDATA: /* 0xA5 */ return LPFC_MBOX_TMO_FLASH_CMD; case MBX_SLI4_CONFIG: /* 0x9b */ subsys = lpfc_sli_config_mbox_subsys_get(phba, mboxq); @@ -1625,11 +1631,17 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) case LPFC_MBOX_OPCODE_WRITE_OBJECT: case LPFC_MBOX_OPCODE_READ_OBJECT_LIST: case LPFC_MBOX_OPCODE_DELETE_OBJECT: - case LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG: case LPFC_MBOX_OPCODE_GET_PROFILE_LIST: case LPFC_MBOX_OPCODE_SET_ACT_PROFILE: + case LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG: case LPFC_MBOX_OPCODE_SET_PROFILE_CONFIG: case LPFC_MBOX_OPCODE_GET_FACTORY_PROFILE_CONFIG: + case LPFC_MBOX_OPCODE_GET_PROFILE_CAPACITIES: + case LPFC_MBOX_OPCODE_SEND_ACTIVATION: + case LPFC_MBOX_OPCODE_RESET_LICENSES: + case LPFC_MBOX_OPCODE_SET_BOOT_CONFIG: + case LPFC_MBOX_OPCODE_GET_VPD_DATA: + case LPFC_MBOX_OPCODE_SET_PHYSICAL_LINK_CONFIG: return LPFC_MBOX_SLI4_CONFIG_EXTENDED_TMO; } } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ade763d3930a..cd86069a0ba8 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -194,6 +194,10 @@ lpfc_mem_free(struct lpfc_hba *phba) pci_pool_destroy(phba->lpfc_hbq_pool); phba->lpfc_hbq_pool = NULL; + if (phba->rrq_pool) + mempool_destroy(phba->rrq_pool); + phba->rrq_pool = NULL; + /* Free NLP memory pool */ mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 9133a97f045f..d8fadcb2db73 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1778,6 +1778,117 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, } static uint32_t +lpfc_rcv_plogi_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; + struct ls_rjt stat; + + memset(&stat, 0, sizeof(struct ls_rjt)); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_rcv_prli_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; + struct ls_rjt stat; + + memset(&stat, 0, sizeof(struct ls_rjt)); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_rcv_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; + + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= NLP_LOGO_ACC; + spin_unlock_irq(shost->host_lock); + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_rcv_padisc_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; + struct ls_rjt stat; + + memset(&stat, 0, sizeof(struct ls_rjt)); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_rcv_prlo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; + struct ls_rjt stat; + + memset(&stat, 0, sizeof(struct ls_rjt)); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_cmpl_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + ndlp->nlp_prev_state = NLP_STE_LOGO_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); + spin_unlock_irq(shost->host_lock); + lpfc_disc_set_adisc(vport, ndlp); + return ndlp->nlp_state; +} + +static uint32_t +lpfc_device_rm_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + /* + * Take no action. If a LOGO is outstanding, then possibly DevLoss has + * timed out and is calling for Device Remove. In this case, the LOGO + * must be allowed to complete in state LOGO_ISSUE so that the rpi + * and other NLP flags are correctly cleaned up. + */ + return ndlp->nlp_state; +} + +static uint32_t +lpfc_device_recov_logo_issue(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + /* + * Device Recovery events have no meaning for a node with a LOGO + * outstanding. The LOGO has to complete first and handle the + * node from that point. + */ + return ndlp->nlp_state; +} + +static uint32_t lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { @@ -2083,6 +2194,8 @@ lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + /* For the fabric port just clear the fc flags. */ if (ndlp->nlp_DID == Fabric_DID) { spin_lock_irq(shost->host_lock); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); @@ -2297,6 +2410,20 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_device_rm_prli_issue, /* DEVICE_RM */ lpfc_device_recov_prli_issue, /* DEVICE_RECOVERY */ + lpfc_rcv_plogi_logo_issue, /* RCV_PLOGI LOGO_ISSUE */ + lpfc_rcv_prli_logo_issue, /* RCV_PRLI */ + lpfc_rcv_logo_logo_issue, /* RCV_LOGO */ + lpfc_rcv_padisc_logo_issue, /* RCV_ADISC */ + lpfc_rcv_padisc_logo_issue, /* RCV_PDISC */ + lpfc_rcv_prlo_logo_issue, /* RCV_PRLO */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ + lpfc_disc_illegal, /* CMPL_PRLI */ + lpfc_cmpl_logo_logo_issue, /* CMPL_LOGO */ + lpfc_disc_illegal, /* CMPL_ADISC */ + lpfc_disc_illegal, /* CMPL_REG_LOGIN */ + lpfc_device_rm_logo_issue, /* DEVICE_RM */ + lpfc_device_recov_logo_issue, /* DEVICE_RECOVERY */ + lpfc_rcv_plogi_unmap_node, /* RCV_PLOGI UNMAPPED_NODE */ lpfc_rcv_prli_unmap_node, /* RCV_PRLI */ lpfc_rcv_logo_unmap_node, /* RCV_LOGO */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 925975d2d765..64013f3097ad 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -60,12 +60,6 @@ static char *dif_op_str[] = { "PROT_WRITE_PASS", }; -static char *dif_grd_str[] = { - "NO_GUARD", - "DIF_CRC", - "DIX_IP", -}; - struct scsi_dif_tuple { __be16 guard_tag; /* Checksum */ __be16 app_tag; /* Opaque storage */ @@ -3482,9 +3476,15 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } lp = (uint32_t *)cmnd->sense_buffer; - if (!scsi_status && (resp_info & RESID_UNDER) && - vport->cfg_log_verbose & LOG_FCP_UNDER) - logit = LOG_FCP_UNDER; + /* special handling for under run conditions */ + if (!scsi_status && (resp_info & RESID_UNDER)) { + /* don't log under runs if fcp set... */ + if (vport->cfg_log_verbose & LOG_FCP) + logit = LOG_FCP_ERROR; + /* unless operator says so */ + if (vport->cfg_log_verbose & LOG_FCP_UNDER) + logit = LOG_FCP_UNDER; + } lpfc_printf_vlog(vport, KERN_WARNING, logit, "9024 FCP command x%x failed: x%x SNS x%x x%x " @@ -3552,11 +3552,11 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, /* * Check SLI validation that all the transfer was actually done - * (fcpi_parm should be zero). Apply check only to reads. + * (fcpi_parm should be zero). */ - } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { + } else if (fcpi_parm) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, - "9029 FCP Read Check Error Data: " + "9029 FCP Data Transfer Check Error: " "x%x x%x x%x x%x x%x\n", be32_to_cpu(fcpcmd->fcpDl), be32_to_cpu(fcprsp->rspResId), @@ -3615,7 +3615,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd = lpfc_cmd->pCmd; shost = cmd->device->host; - lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; + lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK); lpfc_cmd->status = pIocbOut->iocb.ulpStatus; /* pick up SLI4 exhange busy status from HBA */ lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; @@ -3660,10 +3660,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->status = IOSTAT_DRIVER_REJECT; else if (lpfc_cmd->status >= IOSTAT_CNT) lpfc_cmd->status = IOSTAT_DEFAULT; - if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR - && !lpfc_cmd->fcp_rsp->rspStatus3 - && (lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) - && !(phba->cfg_log_verbose & LOG_FCP_UNDER)) + if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR && + !lpfc_cmd->fcp_rsp->rspStatus3 && + (lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) && + !(vport->cfg_log_verbose & LOG_FCP_UNDER)) logit = 0; else logit = LOG_FCP | LOG_FCP_UNDER; @@ -3829,12 +3829,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { + spin_lock_irq(&phba->hbalock); + lpfc_cmd->pCmd = NULL; + spin_unlock_irq(&phba->hbalock); + /* * If there is a thread waiting for command completion * wake up the thread. */ spin_lock_irqsave(shost->host_lock, flags); - lpfc_cmd->pCmd = NULL; if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); spin_unlock_irqrestore(shost->host_lock, flags); @@ -3868,12 +3871,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } + spin_lock_irq(&phba->hbalock); + lpfc_cmd->pCmd = NULL; + spin_unlock_irq(&phba->hbalock); + /* * If there is a thread waiting for command completion * wake up the thread. */ spin_lock_irqsave(shost->host_lock, flags); - lpfc_cmd->pCmd = NULL; if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); spin_unlock_irqrestore(shost->host_lock, flags); @@ -3919,6 +3925,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); int datadir = scsi_cmnd->sc_data_direction; char tag[2]; + uint8_t *ptr; + bool sli4; if (!pnode || !NLP_CHK_NODE_ACT(pnode)) return; @@ -3930,8 +3938,13 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, int_to_scsilun(lpfc_cmd->pCmd->device->lun, &lpfc_cmd->fcp_cmnd->fcp_lun); - memset(&fcp_cmnd->fcpCdb[0], 0, LPFC_FCP_CDB_LEN); - memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + ptr = &fcp_cmnd->fcpCdb[0]; + memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) { + ptr += scsi_cmnd->cmd_len; + memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); + } + if (scsi_populate_tag_msg(scsi_cmnd, tag)) { switch (tag[0]) { case HEAD_OF_QUEUE_TAG: @@ -3947,6 +3960,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } else fcp_cmnd->fcpCntl1 = 0; + sli4 = (phba->sli_rev == LPFC_SLI_REV4); + /* * There are three possibilities here - use scatter-gather segment, use * the single mapping, or neither. Start the lpfc command prep by @@ -3956,11 +3971,12 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if (scsi_sg_count(scsi_cmnd)) { if (datadir == DMA_TO_DEVICE) { iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; - if (phba->sli_rev < LPFC_SLI_REV4) { + if (sli4) + iocb_cmd->ulpPU = PARM_READ_CHECK; + else { iocb_cmd->un.fcpi.fcpi_parm = 0; iocb_cmd->ulpPU = 0; - } else - iocb_cmd->ulpPU = PARM_READ_CHECK; + } fcp_cmnd->fcpCntl3 = WRITE_DATA; phba->fc4OutputRequests++; } else { @@ -3984,7 +4000,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, * of the scsi_cmnd request_buffer */ piocbq->iocb.ulpContext = pnode->nlp_rpi; - if (phba->sli_rev == LPFC_SLI_REV4) + if (sli4) piocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[pnode->nlp_rpi]; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) @@ -4241,9 +4257,8 @@ void lpfc_poll_timeout(unsigned long ptr) * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ static int -lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) +lpfc_queuecommand(struct Scsi_Host *shost, 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_rport_data *rdata = cmnd->device->hostdata; @@ -4299,53 +4314,28 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) lpfc_cmd->timeout = 0; lpfc_cmd->start_time = jiffies; cmnd->host_scribble = (unsigned char *)lpfc_cmd; - cmnd->scsi_done = done; if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { if (vport->phba->cfg_enable_bg) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9033 BLKGRD: rcvd protected cmd:%02x op=%s " - "guard=%s\n", cmnd->cmnd[0], - dif_op_str[scsi_get_prot_op(cmnd)], - dif_grd_str[scsi_host_get_guard(shost)]); - if (cmnd->cmnd[0] == READ_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9035 BLKGRD: READ @ sector %llu, " - "cnt %u, rpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9036 BLKGRD: WRITE @ sector %llu, " - "cnt %u, wpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); + lpfc_printf_vlog(vport, KERN_INFO, LOG_BG, + "9033 BLKGRD: rcvd %s cmd:x%x " + "sector x%llx cnt %u pt %x\n", + dif_op_str[scsi_get_prot_op(cmnd)], + cmnd->cmnd[0], + (unsigned long long)scsi_get_lba(cmnd), + blk_rq_sectors(cmnd->request), + (cmnd->cmnd[1]>>5)); } - err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); } else { if (vport->phba->cfg_enable_bg) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9038 BLKGRD: rcvd unprotected cmd:" - "%02x op=%s guard=%s\n", cmnd->cmnd[0], - dif_op_str[scsi_get_prot_op(cmnd)], - dif_grd_str[scsi_host_get_guard(shost)]); - if (cmnd->cmnd[0] == READ_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9040 dbg: READ @ sector %llu, " - "cnt %u, rpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), + lpfc_printf_vlog(vport, KERN_INFO, LOG_BG, + "9038 BLKGRD: rcvd PROT_NORMAL cmd: " + "x%x sector x%llx cnt %u pt %x\n", + cmnd->cmnd[0], + (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9041 dbg: WRITE @ sector %llu, " - "cnt %u, wpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); + (cmnd->cmnd[1]>>5)); } err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } @@ -4363,11 +4353,9 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_host_busy_free_buf; } if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - spin_unlock(shost->host_lock); lpfc_sli_handle_fast_ring_event(phba, &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - spin_lock(shost->host_lock); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -4384,11 +4372,10 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return SCSI_MLQUEUE_TARGET_BUSY; out_fail_command: - done(cmnd); + cmnd->scsi_done(cmnd); return 0; } -static DEF_SCSI_QCMD(lpfc_queuecommand) /** * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point @@ -4414,7 +4401,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); status = fc_block_scsi_eh(cmnd); - if (status) + if (status != 0 && status != SUCCESS) return status; spin_lock_irq(&phba->hbalock); @@ -4428,7 +4415,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) } lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; - if (!lpfc_cmd) { + if (!lpfc_cmd || !lpfc_cmd->pCmd) { spin_unlock_irq(&phba->hbalock); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " @@ -4521,9 +4508,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ret = FAILED; lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0748 abort handler timed out waiting " - "for abort to complete: ret %#x, ID %d, " - "LUN %d\n", - ret, cmnd->device->id, cmnd->device->lun); + "for abortng I/O (xri:x%x) to complete: " + "ret %#x, ID %d, LUN %d\n", + iocb->sli4_xritag, ret, + cmnd->device->id, cmnd->device->lun); } goto out; @@ -4769,7 +4757,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) } pnode = rdata->pnode; status = fc_block_scsi_eh(cmnd); - if (status) + if (status != 0 && status != SUCCESS) return status; status = lpfc_chk_tgt_mapped(vport, cmnd); @@ -4836,7 +4824,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) } pnode = rdata->pnode; status = fc_block_scsi_eh(cmnd); - if (status) + if (status != 0 && status != SUCCESS) return status; status = lpfc_chk_tgt_mapped(vport, cmnd); @@ -4904,7 +4892,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); status = fc_block_scsi_eh(cmnd); - if (status) + if (status != 0 && status != SUCCESS) return status; /* diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9cbd20b1328b..6bacbdf156d8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -69,6 +69,8 @@ static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_cqe *); static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *, int); +static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *, struct lpfc_eqe *, + uint32_t); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -94,6 +96,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) union lpfc_wqe *temp_wqe; struct lpfc_register doorbell; uint32_t host_index; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -101,8 +104,12 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) temp_wqe = q->qe[q->host_index].wqe; /* If the host has not yet processed the next entry then we are done */ - if (((q->host_index + 1) % q->entry_count) == q->hba_index) + idx = ((q->host_index + 1) % q->entry_count); + if (idx == q->hba_index) { + q->WQ_overflow++; return -ENOMEM; + } + q->WQ_posted++; /* set consumption flag every once in a while */ if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); @@ -112,7 +119,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) /* Update the host index before invoking device */ host_index = q->host_index; - q->host_index = ((q->host_index + 1) % q->entry_count); + + q->host_index = idx; /* Ring Doorbell */ doorbell.word0 = 0; @@ -120,7 +128,6 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) bf_set(lpfc_wq_doorbell_index, &doorbell, host_index); bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr); - readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */ return 0; } @@ -194,7 +201,6 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1); bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr); - readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */ return 0; } @@ -234,6 +240,7 @@ static struct lpfc_eqe * lpfc_sli4_eq_get(struct lpfc_queue *q) { struct lpfc_eqe *eqe; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -244,14 +251,34 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) if (!bf_get_le32(lpfc_eqe_valid, eqe)) return NULL; /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) + idx = ((q->hba_index + 1) % q->entry_count); + if (idx == q->host_index) return NULL; - q->hba_index = ((q->hba_index + 1) % q->entry_count); + q->hba_index = idx; return eqe; } /** + * lpfc_sli4_eq_clr_intr - Turn off interrupts from this EQ + * @q: The Event Queue to disable interrupts + * + **/ +static inline void +lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) +{ + struct lpfc_register doorbell; + + doorbell.word0 = 0; + bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); + bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, + (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); +} + +/** * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ * @q: The Event Queue that the host has completed processing for. * @arm: Indicates whether the host wants to arms this CQ. @@ -318,6 +345,7 @@ static struct lpfc_cqe * lpfc_sli4_cq_get(struct lpfc_queue *q) { struct lpfc_cqe *cqe; + uint32_t idx; /* sanity check on queue memory */ if (unlikely(!q)) @@ -327,11 +355,12 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) return NULL; /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) + idx = ((q->hba_index + 1) % q->entry_count); + if (idx == q->host_index) return NULL; cqe = q->qe[q->hba_index].cqe; - q->hba_index = ((q->hba_index + 1) % q->entry_count); + q->hba_index = idx; return cqe; } @@ -472,8 +501,8 @@ lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) static inline IOCB_t * lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - return (IOCB_t *) (((char *) pring->cmdringaddr) + - pring->cmdidx * phba->iocb_cmd_size); + return (IOCB_t *) (((char *) pring->sli.sli3.cmdringaddr) + + pring->sli.sli3.cmdidx * phba->iocb_cmd_size); } /** @@ -489,8 +518,8 @@ lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) static inline IOCB_t * lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - return (IOCB_t *) (((char *) pring->rspringaddr) + - pring->rspidx * phba->iocb_rsp_size); + return (IOCB_t *) (((char *) pring->sli.sli3.rspringaddr) + + pring->sli.sli3.rspidx * phba->iocb_rsp_size); } /** @@ -1320,21 +1349,23 @@ static IOCB_t * lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - uint32_t max_cmd_idx = pring->numCiocb; - if ((pring->next_cmdidx == pring->cmdidx) && - (++pring->next_cmdidx >= max_cmd_idx)) - pring->next_cmdidx = 0; + uint32_t max_cmd_idx = pring->sli.sli3.numCiocb; + if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) && + (++pring->sli.sli3.next_cmdidx >= max_cmd_idx)) + pring->sli.sli3.next_cmdidx = 0; - if (unlikely(pring->local_getidx == pring->next_cmdidx)) { + if (unlikely(pring->sli.sli3.local_getidx == + pring->sli.sli3.next_cmdidx)) { - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); - if (unlikely(pring->local_getidx >= max_cmd_idx)) { + if (unlikely(pring->sli.sli3.local_getidx >= max_cmd_idx)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0315 Ring %d issue: portCmdGet %d " "is bigger than cmd ring %d\n", pring->ringno, - pring->local_getidx, max_cmd_idx); + pring->sli.sli3.local_getidx, + max_cmd_idx); phba->link_state = LPFC_HBA_ERROR; /* @@ -1349,7 +1380,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return NULL; } - if (pring->local_getidx == pring->next_cmdidx) + if (pring->sli.sli3.local_getidx == pring->sli.sli3.next_cmdidx) return NULL; } @@ -1484,8 +1515,8 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Let the HBA know what IOCB slot will be the next one the * driver will put a command into. */ - pring->cmdidx = pring->next_cmdidx; - writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); + pring->sli.sli3.cmdidx = pring->sli.sli3.next_cmdidx; + writel(pring->sli.sli3.cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); } /** @@ -2056,6 +2087,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_READ_EVENT_LOG: case MBX_SECURITY_MGMT: case MBX_AUTH_PORT: + case MBX_ACCESS_VDATA: ret = mbxCommand; break; default: @@ -2786,7 +2818,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) "0312 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, le32_to_cpu(pgp->rspPutInx), - pring->numRiocb); + pring->sli.sli3.numRiocb); phba->link_state = LPFC_HBA_ERROR; @@ -2815,10 +2847,26 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) void lpfc_poll_eratt(unsigned long ptr) { struct lpfc_hba *phba; - uint32_t eratt = 0; + uint32_t eratt = 0, rem; + uint64_t sli_intr, cnt; phba = (struct lpfc_hba *)ptr; + /* Here we will also keep track of interrupts per sec of the hba */ + sli_intr = phba->sli.slistat.sli_intr; + + if (phba->sli.slistat.sli_prev_intr > sli_intr) + cnt = (((uint64_t)(-1) - phba->sli.slistat.sli_prev_intr) + + sli_intr); + else + cnt = (sli_intr - phba->sli.slistat.sli_prev_intr); + + /* 64-bit integer division not supporte on 32-bit x86 - use do_div */ + rem = do_div(cnt, LPFC_ERATT_POLL_INTERVAL); + phba->sli.slistat.sli_ips = cnt; + + phba->sli.slistat.sli_prev_intr = sli_intr; + /* Check chip HA register for error event */ eratt = lpfc_sli_check_eratt(phba); @@ -2873,7 +2921,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * The next available response entry should never exceed the maximum * entries. If it does, treat it as an adapter hardware error. */ - portRspMax = pring->numRiocb; + portRspMax = pring->sli.sli3.numRiocb; portRspPut = le32_to_cpu(pgp->rspPutInx); if (unlikely(portRspPut >= portRspMax)) { lpfc_sli_rsp_pointers_error(phba, pring); @@ -2887,7 +2935,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, phba->fcp_ring_in_use = 1; rmb(); - while (pring->rspidx != portRspPut) { + while (pring->sli.sli3.rspidx != portRspPut) { /* * Fetch an entry off the ring and copy it into a local data * structure. The copy involves a byte-swap since the @@ -2896,8 +2944,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, entry = lpfc_resp_iocb(phba, pring); phba->last_completion_time = jiffies; - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; + if (++pring->sli.sli3.rspidx >= portRspMax) + pring->sli.sli3.rspidx = 0; lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, @@ -2915,7 +2963,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * queuedepths of the SCSI device. */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) { spin_unlock_irqrestore(&phba->hbalock, iflag); phba->lpfc_rampdown_queue_depth(phba); spin_lock_irqsave(&phba->hbalock, iflag); @@ -2998,9 +3047,10 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, * been updated, sync the pgp->rspPutInx and fetch the new port * response put pointer. */ - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); + writel(pring->sli.sli3.rspidx, + &phba->host_gp[pring->ringno].rspGetInx); - if (pring->rspidx == portRspPut) + if (pring->sli.sli3.rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); } @@ -3015,7 +3065,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) @@ -3086,7 +3136,8 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * queuedepths of the SCSI device. */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) { spin_unlock_irqrestore(&phba->hbalock, iflag); phba->lpfc_rampdown_queue_depth(phba); spin_lock_irqsave(&phba->hbalock, iflag); @@ -3247,7 +3298,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * The next available response entry should never exceed the maximum * entries. If it does, treat it as an adapter hardware error. */ - portRspMax = pring->numRiocb; + portRspMax = pring->sli.sli3.numRiocb; portRspPut = le32_to_cpu(pgp->rspPutInx); if (portRspPut >= portRspMax) { /* @@ -3269,7 +3320,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, } rmb(); - while (pring->rspidx != portRspPut) { + while (pring->sli.sli3.rspidx != portRspPut) { /* * Build a completion list and call the appropriate handler. * The process is to get the next available response iocb, get @@ -3297,8 +3348,8 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, phba->iocb_rsp_size); irsp = &rspiocbp->iocb; - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; + if (++pring->sli.sli3.rspidx >= portRspMax) + pring->sli.sli3.rspidx = 0; if (pring->ringno == LPFC_ELS_RING) { lpfc_debugfs_slow_ring_trc(phba, @@ -3308,7 +3359,8 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, *(((uint32_t *) irsp) + 7)); } - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); + writel(pring->sli.sli3.rspidx, + &phba->host_gp[pring->ringno].rspGetInx); spin_unlock_irqrestore(&phba->hbalock, iflag); /* Handle the response IOCB */ @@ -3320,10 +3372,10 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * the pgp->rspPutInx in the MAILBOX_tand fetch the new port * response put pointer. */ - if (pring->rspidx == portRspPut) { + if (pring->sli.sli3.rspidx == portRspPut) { portRspPut = le32_to_cpu(pgp->rspPutInx); } - } /* while (pring->rspidx != portRspPut) */ + } /* while (pring->sli.sli3.rspidx != portRspPut) */ if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) { /* At least one response entry has been freed */ @@ -3338,7 +3390,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, pring->stats.iocb_cmd_empty++; /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); + pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); lpfc_sli_resume_iocb(phba, pring); if ((pring->lpfc_sli_cmd_available)) @@ -3859,10 +3911,10 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; pring->flag = 0; - pring->rspidx = 0; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; + pring->sli.sli3.rspidx = 0; + pring->sli.sli3.next_cmdidx = 0; + pring->sli.sli3.local_getidx = 0; + pring->sli.sli3.cmdidx = 0; pring->missbufcnt = 0; } @@ -4893,16 +4945,15 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); fcp_eqidx = 0; if (phba->sli4_hba.fcp_cq) { - do + do { lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], LPFC_QUEUE_REARM); - while (++fcp_eqidx < phba->cfg_fcp_eq_count); + } while (++fcp_eqidx < phba->cfg_fcp_io_channel); } - lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.fp_eq) { - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; + if (phba->sli4_hba.hba_eq) { + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) - lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], + lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[fcp_eqidx], LPFC_QUEUE_REARM); } } @@ -7784,14 +7835,18 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, * * Return: index into SLI4 fast-path FCP queue index. **/ -static uint32_t +static inline uint32_t lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) { - ++phba->fcp_qidx; - if (phba->fcp_qidx >= phba->cfg_fcp_wq_count) - phba->fcp_qidx = 0; + int i; + + if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU) + i = smp_processor_id(); + else + i = atomic_add_return(1, &phba->fcp_qidx); - return phba->fcp_qidx; + i = (i % phba->cfg_fcp_io_channel); + return i; } /** @@ -8311,16 +8366,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if ((piocb->iocb_flag & LPFC_IO_FCP) || (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - /* - * For FCP command IOCB, get a new WQ index to distribute - * WQE across the WQsr. On the other hand, for abort IOCB, - * it carries the same WQ index to the original command - * IOCB. - */ - if (piocb->iocb_flag & LPFC_IO_FCP) - piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); - if (unlikely(!phba->sli4_hba.fcp_wq)) - return IOCB_ERROR; if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], &wqe)) return IOCB_ERROR; @@ -8401,13 +8446,68 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; + struct lpfc_sli_ring *pring; + struct lpfc_queue *fpeq; + struct lpfc_eqe *eqe; unsigned long iflags; - int rc; + int rc, idx; - spin_lock_irqsave(&phba->hbalock, iflags); - rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); - spin_unlock_irqrestore(&phba->hbalock, iflags); + if (phba->sli_rev == LPFC_SLI_REV4) { + if (piocb->iocb_flag & LPFC_IO_FCP) { + if (unlikely(!phba->sli4_hba.fcp_wq)) + return IOCB_ERROR; + idx = lpfc_sli4_scmd_to_wqidx_distr(phba); + piocb->fcp_wqidx = idx; + ring_number = MAX_SLI3_CONFIGURED_RINGS + idx; + + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + if (lpfc_fcp_look_ahead) { + fcp_eq_hdl = &phba->sli4_hba.fcp_eq_hdl[idx]; + + if (atomic_dec_and_test(&fcp_eq_hdl-> + fcp_eq_in_use)) { + /* Get associated EQ with this index */ + fpeq = phba->sli4_hba.hba_eq[idx]; + + /* Turn off interrupts from this EQ */ + lpfc_sli4_eq_clr_intr(fpeq); + + /* + * Process all the events on FCP EQ + */ + while ((eqe = lpfc_sli4_eq_get(fpeq))) { + lpfc_sli4_hba_handle_eqe(phba, + eqe, idx); + fpeq->EQ_processed++; + } + + /* Always clear and re-arm the EQ */ + lpfc_sli4_eq_release(fpeq, + LPFC_QUEUE_REARM); + } + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + } + } else { + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + } + } else { + /* For now, SLI2/3 will still use hbalock */ + spin_lock_irqsave(&phba->hbalock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); + spin_unlock_irqrestore(&phba->hbalock, iflags); + } return rc; } @@ -8434,18 +8534,18 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) /* Take some away from the FCP ring */ pring = &psli->ring[psli->fcp_ring]; - pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; /* and give them to the extra ring */ pring = &psli->ring[psli->extra_ring]; - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; /* Setup default profile for this ring */ pring->iotag_max = 4096; @@ -8457,56 +8557,6 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } -/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. - * @vport: pointer to virtual port object. - * @ndlp: nodelist pointer for the impacted rport. - * - * The driver calls this routine in response to a XRI ABORT CQE - * event from the port. In this event, the driver is required to - * recover its login to the rport even though its login may be valid - * from the driver's perspective. The failed ABTS notice from the - * port indicates the rport is not responding. - */ -static void -lpfc_sli_abts_recover_port(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost; - struct lpfc_hba *phba; - unsigned long flags = 0; - - shost = lpfc_shost_from_vport(vport); - phba = vport->phba; - if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { - lpfc_printf_log(phba, KERN_INFO, - LOG_SLI, "3093 No rport recovery needed. " - "rport in state 0x%x\n", - ndlp->nlp_state); - return; - } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3094 Start rport recovery on shost id 0x%x " - "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " - "flags 0x%x\n", - shost->host_no, ndlp->nlp_DID, - vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, - ndlp->nlp_flag); - /* - * The rport is not responding. Don't attempt ADISC recovery. - * Remove the FCP-2 flag to force a PLOGI. - */ - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_start(vport); -} - /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -8594,7 +8644,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT. */ - ext_status = axri->parameter & WCQE_PARAM_MASK; + ext_status = axri->parameter & IOERR_PARAM_MASK; if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) lpfc_sli_abts_recover_port(vport, ndlp); @@ -8692,7 +8742,9 @@ lpfc_sli_setup(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - psli->num_rings = MAX_CONFIGURED_RINGS; + psli->num_rings = MAX_SLI3_CONFIGURED_RINGS; + if (phba->sli_rev == LPFC_SLI_REV4) + psli->num_rings += phba->cfg_fcp_io_channel; psli->sli_flag = 0; psli->fcp_ring = LPFC_FCP_RING; psli->next_ring = LPFC_FCP_NEXT_RING; @@ -8707,16 +8759,20 @@ lpfc_sli_setup(struct lpfc_hba *phba) switch (i) { case LPFC_FCP_RING: /* ring 0 - FCP */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; + pring->sli.sli3.numCiocb += + SLI2_IOCB_CMD_R1XTRA_ENTRIES; + pring->sli.sli3.numRiocb += + SLI2_IOCB_RSP_R1XTRA_ENTRIES; + pring->sli.sli3.numCiocb += + SLI2_IOCB_CMD_R3XTRA_ENTRIES; + pring->sli.sli3.numRiocb += + SLI2_IOCB_RSP_R3XTRA_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->iotag_ctr = 0; @@ -8727,12 +8783,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) break; case LPFC_EXTRA_RING: /* ring 1 - EXTRA */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->iotag_max = phba->cfg_hba_queue_depth; @@ -8740,12 +8796,12 @@ lpfc_sli_setup(struct lpfc_hba *phba) break; case LPFC_ELS_RING: /* ring 2 - ELS / CT */ /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; + pring->sli.sli3.numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; + pring->sli.sli3.sizeCiocb = (phba->sli_rev == 3) ? SLI3_IOCB_CMD_SIZE : SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? + pring->sli.sli3.sizeRiocb = (phba->sli_rev == 3) ? SLI3_IOCB_RSP_SIZE : SLI2_IOCB_RSP_SIZE; pring->fast_iotag = 0; @@ -8786,8 +8842,9 @@ lpfc_sli_setup(struct lpfc_hba *phba) lpfc_sli4_ct_abort_unsol_event; break; } - totiocbsize += (pring->numCiocb * pring->sizeCiocb) + - (pring->numRiocb * pring->sizeRiocb); + totiocbsize += (pring->sli.sli3.numCiocb * + pring->sli.sli3.sizeCiocb) + + (pring->sli.sli3.numRiocb * pring->sli.sli3.sizeRiocb); } if (totiocbsize > MAX_SLIM_IOCB_SIZE) { /* Too many cmd / rsp ring entries in SLI2 SLIM */ @@ -8828,14 +8885,15 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; pring->ringno = i; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; + pring->sli.sli3.next_cmdidx = 0; + pring->sli.sli3.local_getidx = 0; + pring->sli.sli3.cmdidx = 0; INIT_LIST_HEAD(&pring->txq); INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); INIT_LIST_HEAD(&pring->iocb_continue_saveq); INIT_LIST_HEAD(&pring->postbufq); + spin_lock_init(&pring->ring_lock); } spin_unlock_irq(&phba->hbalock); return 1; @@ -9334,6 +9392,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; int retval; + unsigned long iflags; /* * There are certain command types we don't want to abort. And we @@ -9386,7 +9445,17 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->un.acxri.abortIoTag, iabt->un.acxri.abortContextTag, abtsiocbp->iotag); - retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0); + + if (phba->sli_rev == LPFC_SLI_REV4) { + /* Note: both hbalock and ring_lock need to be set here */ + spin_lock_irqsave(&pring->ring_lock, iflags); + retval = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbp, 0); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + } else { + retval = __lpfc_sli_issue_iocb(phba, pring->ringno, + abtsiocbp, 0); + } if (retval) __lpfc_sli_release_iocbq(phba, abtsiocbp); @@ -10947,12 +11016,12 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, unsigned long iflags; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, @@ -11154,6 +11223,7 @@ lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) /** * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event * @phba: Pointer to HBA context object. + * @cq: Pointer to associated CQ * @wcqe: Pointer to work-queue completion queue entry. * * This routine handles an ELS work-queue completion event. @@ -11161,12 +11231,12 @@ lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) * Return: true if work posted to worker thread, otherwise false. **/ static bool -lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, +lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_wcqe_complete *wcqe) { struct lpfc_iocbq *irspiocbq; unsigned long iflags; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; + struct lpfc_sli_ring *pring = cq->pring; /* Get an irspiocbq for later ELS response processing use */ irspiocbq = lpfc_sli_get_iocbq(phba); @@ -11311,14 +11381,17 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) case FC_STATUS_RQ_BUF_LEN_EXCEEDED: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2537 Receive Frame Truncated!!\n"); + hrq->RQ_buf_trunc++; case FC_STATUS_RQ_SUCCESS: lpfc_sli4_rq_release(hrq, drq); spin_lock_irqsave(&phba->hbalock, iflags); dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); if (!dma_buf) { + hrq->RQ_no_buf_found++; spin_unlock_irqrestore(&phba->hbalock, iflags); goto out; } + hrq->RQ_rcv_buf++; memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); /* save off the frame for the word thread to process */ list_add_tail(&dma_buf->cq_event.list, @@ -11330,6 +11403,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) break; case FC_STATUS_INSUFF_BUF_NEED_BUF: case FC_STATUS_INSUFF_BUF_FRM_DISC: + hrq->RQ_no_posted_buf++; /* Post more buffers if possible */ spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= HBA_POST_RECEIVE_BUFFER; @@ -11367,7 +11441,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, case CQE_CODE_COMPL_WQE: /* Process the WQ/RQ complete event */ phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_els_wcqe(phba, + workposted = lpfc_sli4_sp_handle_els_wcqe(phba, cq, (struct lpfc_wcqe_complete *)&cqevt); break; case CQE_CODE_RELEASE_WQE: @@ -11411,31 +11485,18 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * **/ static void -lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) +lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, + struct lpfc_queue *speq) { - struct lpfc_queue *cq = NULL, *childq, *speq; + struct lpfc_queue *cq = NULL, *childq; struct lpfc_cqe *cqe; bool workposted = false; int ecount = 0; uint16_t cqid; - if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0359 Not a valid slow-path completion " - "event: majorcode=x%x, minorcode=x%x\n", - bf_get_le32(lpfc_eqe_major_code, eqe), - bf_get_le32(lpfc_eqe_minor_code, eqe)); - return; - } - /* Get the reference to the corresponding CQ */ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); - /* Search for completion queue pointer matching this cqid */ - speq = phba->sli4_hba.sp_eq; - /* sanity check on queue memory */ - if (unlikely(!speq)) - return; list_for_each_entry(childq, &speq->child_list, list) { if (childq->queue_id == cqid) { cq = childq; @@ -11457,6 +11518,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe); if (!(++ecount % cq->entry_repost)) lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); + cq->CQ_mbox++; } break; case LPFC_WCQ: @@ -11470,6 +11532,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) if (!(++ecount % cq->entry_repost)) lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); } + + /* Track the max number of CQEs processed in 1 EQ */ + if (ecount > cq->CQ_max_cqe) + cq->CQ_max_cqe = ecount; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -11494,34 +11560,33 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) /** * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry - * @eqe: Pointer to fast-path completion queue entry. + * @phba: Pointer to HBA context object. + * @cq: Pointer to associated CQ + * @wcqe: Pointer to work-queue completion queue entry. * * This routine process a fast-path work queue completion entry from fast-path * event queue for FCP command response completion. **/ static void -lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, +lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_wcqe_complete *wcqe) { - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; + struct lpfc_sli_ring *pring = cq->pring; struct lpfc_iocbq *cmdiocbq; struct lpfc_iocbq irspiocbq; unsigned long iflags; - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_event++; - spin_unlock_irqrestore(&phba->hbalock, iflags); - /* Check for response status */ if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { /* If resource errors reported from HBA, reduce queue * depth of the SCSI device. */ - if ((bf_get(lpfc_wcqe_c_status, wcqe) == - IOSTAT_LOCAL_REJECT) && - (wcqe->parameter == IOERR_NO_RESOURCES)) { + if (((bf_get(lpfc_wcqe_c_status, wcqe) == + IOSTAT_LOCAL_REJECT)) && + ((wcqe->parameter & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) phba->lpfc_rampdown_queue_depth(phba); - } + /* Log the error status */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0373 FCP complete error: status=x%x, " @@ -11534,10 +11599,11 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, } /* Look up the FCP command IOCB and create pseudo response IOCB */ - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&pring->ring_lock, iflags); + pring->stats.iocb_event++; cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0374 FCP complete with no corresponding " @@ -11621,17 +11687,20 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Check and process for different type of WCQE and dispatch */ switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { case CQE_CODE_COMPL_WQE: + cq->CQ_wq++; /* Process the WQ complete event */ phba->last_completion_time = jiffies; - lpfc_sli4_fp_handle_fcp_wcqe(phba, + lpfc_sli4_fp_handle_fcp_wcqe(phba, cq, (struct lpfc_wcqe_complete *)&wcqe); break; case CQE_CODE_RELEASE_WQE: + cq->CQ_release_wqe++; /* Process the WQ release event */ lpfc_sli4_fp_handle_rel_wcqe(phba, cq, (struct lpfc_wcqe_release *)&wcqe); break; case CQE_CODE_XRI_ABORTED: + cq->CQ_xri_aborted++; /* Process the WQ XRI abort event */ phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, @@ -11647,7 +11716,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, } /** - * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry + * lpfc_sli4_hba_handle_eqe - Process a fast-path event queue entry * @phba: Pointer to HBA context object. * @eqe: Pointer to fast-path event queue entry. * @@ -11659,8 +11728,8 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * completion queue, and then return. **/ static void -lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, - uint32_t fcp_cqidx) +lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, + uint32_t qidx) { struct lpfc_queue *cq; struct lpfc_cqe *cqe; @@ -11670,30 +11739,38 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0366 Not a valid fast-path completion " + "0366 Not a valid completion " "event: majorcode=x%x, minorcode=x%x\n", bf_get_le32(lpfc_eqe_major_code, eqe), bf_get_le32(lpfc_eqe_minor_code, eqe)); return; } + /* Get the reference to the corresponding CQ */ + cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); + + /* Check if this is a Slow path event */ + if (unlikely(cqid != phba->sli4_hba.fcp_cq_map[qidx])) { + lpfc_sli4_sp_handle_eqe(phba, eqe, + phba->sli4_hba.hba_eq[qidx]); + return; + } + if (unlikely(!phba->sli4_hba.fcp_cq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3146 Fast-path completion queues " "does not exist\n"); return; } - cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; + cq = phba->sli4_hba.fcp_cq[qidx]; if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0367 Fast-path completion queue " - "(%d) does not exist\n", fcp_cqidx); + "(%d) does not exist\n", qidx); return; } - /* Get the reference to the corresponding CQ */ - cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); if (unlikely(cqid != cq->queue_id)) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0368 Miss-matched fast-path completion " @@ -11709,6 +11786,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); } + /* Track the max number of CQEs processed in 1 EQ */ + if (ecount > cq->CQ_max_cqe) + cq->CQ_max_cqe = ecount; + /* Catch the no cq entry condition */ if (unlikely(ecount == 0)) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -11737,86 +11818,7 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) } /** - * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is directly called from the PCI layer as an interrupt - * service routine when device with SLI-4 interface spec is enabled with - * MSI-X multi-message interrupt mode and there are slow-path events in - * the HBA. However, when the device is enabled with either MSI or Pin-IRQ - * interrupt mode, this function is called as part of the device-level - * interrupt handler. When the PCI slot is in error recovery or the HBA is - * undergoing initialization, the interrupt handler will not process the - * interrupt. The link attention and ELS ring attention events are handled - * by the worker thread. The interrupt handler signals the worker thread - * and returns for these events. This function is called without any lock - * held. It gets the hbalock to access and update SLI data structures. - * - * This function returns IRQ_HANDLED when interrupt is handled else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli4_sp_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - struct lpfc_queue *speq; - struct lpfc_eqe *eqe; - unsigned long iflag; - int ecount = 0; - - /* - * Get the driver's phba structure from the dev_id - */ - phba = (struct lpfc_hba *)dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* Get to the EQ struct associated with this vector */ - speq = phba->sli4_hba.sp_eq; - if (unlikely(!speq)) - return IRQ_NONE; - - /* Check device state for handling interrupt */ - if (unlikely(lpfc_intr_state_check(phba))) { - /* Check again for link_state with lock held */ - spin_lock_irqsave(&phba->hbalock, iflag); - if (phba->link_state < LPFC_LINK_DOWN) - /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, speq); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_NONE; - } - - /* - * Process all the event on FCP slow-path EQ - */ - while ((eqe = lpfc_sli4_eq_get(speq))) { - lpfc_sli4_sp_handle_eqe(phba, eqe); - if (!(++ecount % speq->entry_repost)) - lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM); - } - - /* Always clear and re-arm the slow-path EQ */ - lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM); - - /* Catch the no cq entry condition */ - if (unlikely(ecount == 0)) { - if (phba->intr_type == MSIX) - /* MSI-X treated interrupt served as no EQ share INT */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0357 MSI-X interrupt with no EQE\n"); - else - /* Non MSI-X treated on interrupt as EQ share INT */ - return IRQ_NONE; - } - - return IRQ_HANDLED; -} /* lpfc_sli4_sp_intr_handler */ - -/** - * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device + * lpfc_sli4_hba_intr_handler - HBA interrupt handler to SLI-4 device * @irq: Interrupt number. * @dev_id: The device context pointer. * @@ -11833,11 +11835,16 @@ lpfc_sli4_sp_intr_handler(int irq, void *dev_id) * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is * equal to that of FCP CQ index. * + * The link attention and ELS ring attention events are handled + * by the worker thread. The interrupt handler signals the worker thread + * and returns for these events. This function is called without any lock + * held. It gets the hbalock to access and update SLI data structures. + * * This function returns IRQ_HANDLED when interrupt is handled else it * returns IRQ_NONE. **/ irqreturn_t -lpfc_sli4_fp_intr_handler(int irq, void *dev_id) +lpfc_sli4_hba_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; @@ -11854,22 +11861,34 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) if (unlikely(!phba)) return IRQ_NONE; - if (unlikely(!phba->sli4_hba.fp_eq)) + if (unlikely(!phba->sli4_hba.hba_eq)) return IRQ_NONE; /* Get to the EQ struct associated with this vector */ - fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; + fpeq = phba->sli4_hba.hba_eq[fcp_eqidx]; if (unlikely(!fpeq)) return IRQ_NONE; + if (lpfc_fcp_look_ahead) { + if (atomic_dec_and_test(&fcp_eq_hdl->fcp_eq_in_use)) + lpfc_sli4_eq_clr_intr(fpeq); + else { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + } + /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { + fpeq->EQ_badstate++; /* Check again for link_state with lock held */ spin_lock_irqsave(&phba->hbalock, iflag); if (phba->link_state < LPFC_LINK_DOWN) /* Flush, clear interrupt, and rearm the EQ */ lpfc_sli4_eq_flush(phba, fpeq); spin_unlock_irqrestore(&phba->hbalock, iflag); + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_NONE; } @@ -11877,15 +11896,27 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) * Process all the event on FCP fast-path EQ */ while ((eqe = lpfc_sli4_eq_get(fpeq))) { - lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx); + lpfc_sli4_hba_handle_eqe(phba, eqe, fcp_eqidx); if (!(++ecount % fpeq->entry_repost)) lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM); + fpeq->EQ_processed++; } + /* Track the max number of EQEs processed in 1 intr */ + if (ecount > fpeq->EQ_max_eqe) + fpeq->EQ_max_eqe = ecount; + /* Always clear and re-arm the fast-path EQ */ lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); if (unlikely(ecount == 0)) { + fpeq->EQ_no_entry++; + + if (lpfc_fcp_look_ahead) { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + if (phba->intr_type == MSIX) /* MSI-X treated interrupt served as no EQ share INT */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, @@ -11895,6 +11926,8 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) return IRQ_NONE; } + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_HANDLED; } /* lpfc_sli4_fp_intr_handler */ @@ -11919,8 +11952,8 @@ irqreturn_t lpfc_sli4_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; - irqreturn_t sp_irq_rc, fp_irq_rc; - bool fp_handled = false; + irqreturn_t hba_irq_rc; + bool hba_handled = false; uint32_t fcp_eqidx; /* Get the driver's phba structure from the dev_id */ @@ -11930,21 +11963,16 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) return IRQ_NONE; /* - * Invokes slow-path host attention interrupt handling as appropriate. - */ - sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id); - - /* * Invoke fast-path host attention interrupt handling as appropriate. */ - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - fp_irq_rc = lpfc_sli4_fp_intr_handler(irq, + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) { + hba_irq_rc = lpfc_sli4_hba_intr_handler(irq, &phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]); - if (fp_irq_rc == IRQ_HANDLED) - fp_handled |= true; + if (hba_irq_rc == IRQ_HANDLED) + hba_handled |= true; } - return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc; + return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE; } /* lpfc_sli4_intr_handler */ /** @@ -12075,7 +12103,7 @@ lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) union lpfc_sli4_cfg_shdr *shdr; uint16_t dmult; - if (startq >= phba->cfg_fcp_eq_count) + if (startq >= phba->cfg_fcp_io_channel) return 0; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -12089,12 +12117,13 @@ lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) eq_delay = &mbox->u.mqe.un.eq_delay; /* Calculate delay multiper from maximum interrupt per second */ - dmult = LPFC_DMULT_CONST/phba->cfg_fcp_imax - 1; + dmult = phba->cfg_fcp_imax / phba->cfg_fcp_io_channel; + dmult = LPFC_DMULT_CONST/dmult - 1; cnt = 0; - for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_eq_count; + for (fcp_eqidx = startq; fcp_eqidx < phba->cfg_fcp_io_channel; fcp_eqidx++) { - eq = phba->sli4_hba.fp_eq[fcp_eqidx]; + eq = phba->sli4_hba.hba_eq[fcp_eqidx]; if (!eq) continue; eq_delay->u.request.eq[cnt].eq_id = eq->queue_id; diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 2626f58c0747..2f48d000a3b4 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -131,7 +131,9 @@ typedef struct lpfcMboxq { #define LPFC_MAX_RING_MASK 5 /* max num of rctl/type masks allowed per ring */ -#define LPFC_MAX_RING 4 /* max num of SLI rings used by driver */ +#define LPFC_SLI3_MAX_RING 4 /* Max num of SLI3 rings used by driver. + For SLI4, an additional ring for each + FCP WQ will be allocated. */ struct lpfc_sli_ring; @@ -158,6 +160,24 @@ struct lpfc_sli_ring_stat { uint64_t iocb_rsp_full; /* IOCB rsp ring full */ }; +struct lpfc_sli3_ring { + uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ + uint32_t next_cmdidx; /* next_cmd index */ + uint32_t rspidx; /* current index in response ring */ + uint32_t cmdidx; /* current index in command ring */ + uint16_t numCiocb; /* number of command iocb's per ring */ + uint16_t numRiocb; /* number of rsp iocb's per ring */ + uint16_t sizeCiocb; /* Size of command iocb's in this ring */ + uint16_t sizeRiocb; /* Size of response iocb's in this ring */ + uint32_t *cmdringaddr; /* virtual address for cmd rings */ + uint32_t *rspringaddr; /* virtual address for rsp rings */ +}; + +struct lpfc_sli4_ring { + struct lpfc_queue *wqp; /* Pointer to associated WQ */ +}; + + /* Structure used to hold SLI ring information */ struct lpfc_sli_ring { uint16_t flag; /* ring flags */ @@ -166,16 +186,10 @@ struct lpfc_sli_ring { #define LPFC_STOP_IOCB_EVENT 0x020 /* Stop processing IOCB cmds event */ uint16_t abtsiotag; /* tracks next iotag to use for ABTS */ - uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ - uint32_t next_cmdidx; /* next_cmd index */ - uint32_t rspidx; /* current index in response ring */ - uint32_t cmdidx; /* current index in command ring */ uint8_t rsvd; uint8_t ringno; /* ring number */ - uint16_t numCiocb; /* number of command iocb's per ring */ - uint16_t numRiocb; /* number of rsp iocb's per ring */ - uint16_t sizeCiocb; /* Size of command iocb's in this ring */ - uint16_t sizeRiocb; /* Size of response iocb's in this ring */ + + spinlock_t ring_lock; /* lock for issuing commands */ uint32_t fast_iotag; /* max fastlookup based iotag */ uint32_t iotag_ctr; /* keeps track of the next iotag to use */ @@ -186,8 +200,6 @@ struct lpfc_sli_ring { struct list_head txcmplq; uint16_t txcmplq_cnt; /* current length of queue */ uint16_t txcmplq_max; /* max length */ - uint32_t *cmdringaddr; /* virtual address for cmd rings */ - uint32_t *rspringaddr; /* virtual address for rsp rings */ uint32_t missbufcnt; /* keep track of buffers to post */ struct list_head postbufq; uint16_t postbufq_cnt; /* current length of queue */ @@ -207,6 +219,10 @@ struct lpfc_sli_ring { /* cmd ring available */ void (*lpfc_sli_cmd_available) (struct lpfc_hba *, struct lpfc_sli_ring *); + union { + struct lpfc_sli3_ring sli3; + struct lpfc_sli4_ring sli4; + } sli; }; /* Structure used for configuring rings to a specific profile or rctl / type */ @@ -239,6 +255,8 @@ struct lpfc_sli_stat { uint64_t mbox_stat_err; /* Mbox cmds completed status error */ uint64_t mbox_cmd; /* Mailbox commands issued */ uint64_t sli_intr; /* Count of Host Attention interrupts */ + uint64_t sli_prev_intr; /* Previous cnt of Host Attention interrupts */ + uint64_t sli_ips; /* Host Attention interrupts per sec */ uint32_t err_attn_event; /* Error Attn event counters */ uint32_t link_event; /* Link event counters */ uint32_t mbox_event; /* Mailbox event counters */ @@ -270,7 +288,7 @@ struct lpfc_sli { #define LPFC_MENLO_MAINT 0x1000 /* need for menl fw download */ #define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */ - struct lpfc_sli_ring ring[LPFC_MAX_RING]; + struct lpfc_sli_ring *ring; int fcp_ring; /* ring used for FCP initiator commands */ int next_ring; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index ec756118c5c1..bd4bc4342ae2 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -34,18 +34,10 @@ /* Number of SGL entries can be posted in a 4KB nonembedded mbox command */ #define LPFC_NEMBED_MBOX_SGL_CNT 254 -/* Multi-queue arrangement for fast-path FCP work queues */ -#define LPFC_FN_EQN_MAX 8 -#define LPFC_SP_EQN_DEF 1 -#define LPFC_FP_EQN_DEF 4 -#define LPFC_FP_EQN_MIN 1 -#define LPFC_FP_EQN_MAX (LPFC_FN_EQN_MAX - LPFC_SP_EQN_DEF) - -#define LPFC_FN_WQN_MAX 32 -#define LPFC_SP_WQN_DEF 1 -#define LPFC_FP_WQN_DEF 4 -#define LPFC_FP_WQN_MIN 1 -#define LPFC_FP_WQN_MAX (LPFC_FN_WQN_MAX - LPFC_SP_WQN_DEF) +/* Multi-queue arrangement for FCP EQ/CQ/WQ tuples */ +#define LPFC_FCP_IO_CHAN_DEF 4 +#define LPFC_FCP_IO_CHAN_MIN 1 +#define LPFC_FCP_IO_CHAN_MAX 8 /* * Provide the default FCF Record attributes used by the driver @@ -141,6 +133,37 @@ struct lpfc_queue { uint32_t page_count; /* Number of pages allocated for this queue */ uint32_t host_index; /* The host's index for putting or getting */ uint32_t hba_index; /* The last known hba index for get or put */ + + struct lpfc_sli_ring *pring; /* ptr to io ring associated with q */ + + /* For q stats */ + uint32_t q_cnt_1; + uint32_t q_cnt_2; + uint32_t q_cnt_3; + uint64_t q_cnt_4; +/* defines for EQ stats */ +#define EQ_max_eqe q_cnt_1 +#define EQ_no_entry q_cnt_2 +#define EQ_badstate q_cnt_3 +#define EQ_processed q_cnt_4 + +/* defines for CQ stats */ +#define CQ_mbox q_cnt_1 +#define CQ_max_cqe q_cnt_1 +#define CQ_release_wqe q_cnt_2 +#define CQ_xri_aborted q_cnt_3 +#define CQ_wq q_cnt_4 + +/* defines for WQ stats */ +#define WQ_overflow q_cnt_1 +#define WQ_posted q_cnt_4 + +/* defines for RQ stats */ +#define RQ_no_posted_buf q_cnt_1 +#define RQ_no_buf_found q_cnt_2 +#define RQ_buf_trunc q_cnt_3 +#define RQ_rcv_buf q_cnt_4 + union sli4_qe qe[1]; /* array to index entries (must be last) */ }; @@ -350,6 +373,7 @@ struct lpfc_hba; struct lpfc_fcp_eq_hdl { uint32_t idx; struct lpfc_hba *phba; + atomic_t fcp_eq_in_use; }; /* Port Capabilities for SLI4 Parameters */ @@ -407,6 +431,8 @@ struct lpfc_sli4_lnk_info { uint8_t lnk_no; }; +#define LPFC_SLI4_HANDLER_NAME_SZ 16 + /* SLI4 HBA data structure entries */ struct lpfc_sli4_hba { void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for @@ -463,20 +489,23 @@ struct lpfc_sli4_hba { struct lpfc_register sli_intf; struct lpfc_pc_sli4_params pc_sli4_params; struct msix_entry *msix_entries; + uint8_t handler_name[LPFC_FCP_IO_CHAN_MAX][LPFC_SLI4_HANDLER_NAME_SZ]; uint32_t cfg_eqn; uint32_t msix_vec_nr; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ + /* Pointers to the constructed SLI4 queues */ - struct lpfc_queue **fp_eq; /* Fast-path event queue */ - struct lpfc_queue *sp_eq; /* Slow-path event queue */ + struct lpfc_queue **hba_eq;/* Event queues for HBA */ + struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */ struct lpfc_queue **fcp_wq;/* Fast-path FCP work queue */ + uint16_t *fcp_cq_map; + + struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */ + struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */ struct lpfc_queue *mbx_wq; /* Slow-path MBOX work queue */ struct lpfc_queue *els_wq; /* Slow-path ELS work queue */ struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */ struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */ - struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */ - struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */ - struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */ /* Setup information for various queue parameters */ int eq_esize; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 4704e5b5088e..04265a1c4e52 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,11 +18,16 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.32" +#define LPFC_DRIVER_VERSION "8.3.34" #define LPFC_DRIVER_NAME "lpfc" + +/* Used for SLI 2/3 */ #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" +/* Used for SLI4 */ +#define LPFC_DRIVER_HANDLER_NAME "lpfc:" + #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION #define LPFC_COPYRIGHT "Copyright(c) 2004-2009 Emulex. All rights reserved." |