summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h23
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c107
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c22
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h13
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c13
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h15
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h141
-rw-r--r--drivers/scsi/lpfc/lpfc_ids.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c320
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c22
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c427
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.c470
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.h10
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c64
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c692
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h42
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h8
26 files changed, 1793 insertions, 664 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 61fb46da05d4..6c0d351c0d0d 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -544,16 +544,10 @@ struct unsol_rcv_ct_ctx {
#define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */
#define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */
#define LPFC_USER_LINK_SPEED_32G 32 /* 32 Gigabaud */
-#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_32G
-#define LPFC_USER_LINK_SPEED_BITMAP ((1ULL << LPFC_USER_LINK_SPEED_32G) | \
- (1 << LPFC_USER_LINK_SPEED_16G) | \
- (1 << LPFC_USER_LINK_SPEED_10G) | \
- (1 << LPFC_USER_LINK_SPEED_8G) | \
- (1 << LPFC_USER_LINK_SPEED_4G) | \
- (1 << LPFC_USER_LINK_SPEED_2G) | \
- (1 << LPFC_USER_LINK_SPEED_1G) | \
- (1 << LPFC_USER_LINK_SPEED_AUTO))
-#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32"
+#define LPFC_USER_LINK_SPEED_64G 64 /* 64 Gigabaud */
+#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_64G
+
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32, 64"
enum nemb_type {
nemb_mse = 1,
@@ -760,6 +754,7 @@ struct lpfc_hba {
uint8_t mds_diags_support;
uint32_t initial_imax;
uint8_t bbcredit_support;
+ uint8_t enab_exp_wqcq_pages;
/* HBA Config Parameters */
uint32_t cfg_ack0;
@@ -787,6 +782,7 @@ struct lpfc_hba {
uint32_t cfg_fcp_io_channel;
uint32_t cfg_suppress_rsp;
uint32_t cfg_nvme_oas;
+ uint32_t cfg_nvme_embed_cmd;
uint32_t cfg_nvme_io_channel;
uint32_t cfg_nvmet_mrq;
uint32_t cfg_enable_nvmet;
@@ -839,11 +835,14 @@ struct lpfc_hba {
uint32_t cfg_enable_SmartSAN;
uint32_t cfg_enable_mds_diags;
uint32_t cfg_enable_fc4_type;
- uint32_t cfg_enable_bbcr; /*Enable BB Credit Recovery*/
+ uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */
+ uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */
uint32_t cfg_xri_split;
#define LPFC_ENABLE_FCP 1
#define LPFC_ENABLE_NVME 2
#define LPFC_ENABLE_BOTH 3
+ uint32_t nvme_embed_pbde;
+ uint32_t fcp_embed_pbde;
uint32_t io_channel_irqs; /* number of irqs for io channels */
struct nvmet_fc_target_port *targetport;
lpfc_vpd_t vpd; /* vital product data */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index ac77081e6e9e..2ac1d21c553f 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -259,6 +259,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
atomic_read(&tgtp->xmt_abort_rsp),
atomic_read(&tgtp->xmt_abort_rsp_error));
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "DELAY: ctx %08x fod %08x wqfull %08x\n",
+ atomic_read(&tgtp->defer_ctx),
+ atomic_read(&tgtp->defer_fod),
+ atomic_read(&tgtp->defer_wqfull));
+
/* Calculate outstanding IOs */
tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
tot += atomic_read(&tgtp->xmt_fcp_release);
@@ -905,7 +911,12 @@ lpfc_issue_lip(struct Scsi_Host *shost)
LPFC_MBOXQ_t *pmboxq;
int mbxstatus = MBXERR_ERROR;
+ /*
+ * If the link is offline, disabled or BLOCK_MGMT_IO
+ * it doesn't make any sense to allow issue_lip
+ */
if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+ (phba->hba_flag & LINK_DISABLED) ||
(phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
return -EPERM;
@@ -3458,8 +3469,8 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
# tgt_queue_depth: This parameter is used to limit the number of outstanding
# commands per target port. Value range is [10,65535]. Default value is 65535.
*/
-LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
- "Max number of FCP commands we can queue to a specific target port");
+LPFC_VPORT_ATTR_RW(tgt_queue_depth, 65535, 10, 65535,
+ "Max number of FCP commands we can queue to a specific target port");
/*
# hba_queue_depth: This parameter is used to limit the number of outstanding
@@ -4104,23 +4115,32 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) ||
((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) ||
- ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb))) {
+ ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb)) ||
+ ((val == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2879 lpfc_link_speed attribute cannot be set "
"to %d. Speed is not supported by this port.\n",
val);
return -EINVAL;
}
- if (val == LPFC_USER_LINK_SPEED_16G &&
- phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
+ if (val >= LPFC_USER_LINK_SPEED_16G &&
+ phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3112 lpfc_link_speed attribute cannot be set "
"to %d. Speed is not supported in loop mode.\n",
val);
return -EINVAL;
}
- if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
- (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
+
+ switch (val) {
+ case LPFC_USER_LINK_SPEED_AUTO:
+ case LPFC_USER_LINK_SPEED_1G:
+ case LPFC_USER_LINK_SPEED_2G:
+ case LPFC_USER_LINK_SPEED_4G:
+ case LPFC_USER_LINK_SPEED_8G:
+ case LPFC_USER_LINK_SPEED_16G:
+ case LPFC_USER_LINK_SPEED_32G:
+ case LPFC_USER_LINK_SPEED_64G:
prev_val = phba->cfg_link_speed;
phba->cfg_link_speed = val;
if (nolip)
@@ -4130,13 +4150,18 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
if (err) {
phba->cfg_link_speed = prev_val;
return -EINVAL;
- } else
- return strlen(buf);
+ }
+ return strlen(buf);
+ default:
+ break;
}
+
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0469 lpfc_link_speed attribute cannot be set to %d, "
- "allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val);
+ "0469 lpfc_link_speed attribute cannot be set to %d, "
+ "allowed values are [%s]\n",
+ val, LPFC_LINK_SPEED_STRING);
return -EINVAL;
+
}
static int lpfc_link_speed = 0;
@@ -4163,24 +4188,33 @@ lpfc_param_show(link_speed)
static int
lpfc_link_speed_init(struct lpfc_hba *phba, int val)
{
- if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) {
+ if (val >= LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3111 lpfc_link_speed of %d cannot "
"support loop mode, setting topology to default.\n",
val);
phba->cfg_topology = 0;
}
- if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
- (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
+
+ switch (val) {
+ case LPFC_USER_LINK_SPEED_AUTO:
+ case LPFC_USER_LINK_SPEED_1G:
+ case LPFC_USER_LINK_SPEED_2G:
+ case LPFC_USER_LINK_SPEED_4G:
+ case LPFC_USER_LINK_SPEED_8G:
+ case LPFC_USER_LINK_SPEED_16G:
+ case LPFC_USER_LINK_SPEED_32G:
+ case LPFC_USER_LINK_SPEED_64G:
phba->cfg_link_speed = val;
return 0;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0405 lpfc_link_speed attribute cannot "
+ "be set to %d, allowed values are "
+ "["LPFC_LINK_SPEED_STRING"]\n", val);
+ phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
+ return -EINVAL;
}
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0405 lpfc_link_speed attribute cannot "
- "be set to %d, allowed values are "
- "["LPFC_LINK_SPEED_STRING"]\n", val);
- phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
- return -EINVAL;
}
static DEVICE_ATTR_RW(lpfc_link_speed);
@@ -5008,6 +5042,18 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
"Use OAS bit on NVME IOs");
/*
+ * lpfc_nvme_embed_cmd: Use the oas bit when sending NVME/NVMET IOs
+ *
+ * 0 = Put NVME Command in SGL
+ * 1 = Embed NVME Command in WQE (unless G7)
+ * 2 = Embed NVME Command in WQE (force)
+ *
+ * Value range is [0,2]. Default value is 1.
+ */
+LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
+ "Embed NVME Command in WQE");
+
+/*
* lpfc_fcp_io_channel: Set the number of FCP IO channels the driver
* will advertise it supports to the SCSI layer. This also will map to
* the number of WQs the driver will create.
@@ -5175,6 +5221,14 @@ LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");
*/
LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery");
+/*
+ * lpfc_enable_dpp: Enable DPP on G7
+ * 0 = DPP on G7 disabled
+ * 1 = DPP on G7 enabled (default)
+ * Value range is [0,1]. Default value is 1.
+ */
+LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push");
+
struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_nvme_info,
&dev_attr_bg_info,
@@ -5240,6 +5294,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_task_mgmt_tmo,
&dev_attr_lpfc_use_msi,
&dev_attr_lpfc_nvme_oas,
+ &dev_attr_lpfc_nvme_embed_cmd,
&dev_attr_lpfc_auto_imax,
&dev_attr_lpfc_fcp_imax,
&dev_attr_lpfc_fcp_cpu_map,
@@ -5283,6 +5338,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_xlane_supported,
&dev_attr_lpfc_enable_mds_diags,
&dev_attr_lpfc_enable_bbcr,
+ &dev_attr_lpfc_enable_dpp,
NULL,
};
@@ -5696,6 +5752,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
case LPFC_LINK_SPEED_32GHZ:
fc_host_speed(shost) = FC_PORTSPEED_32GBIT;
break;
+ case LPFC_LINK_SPEED_64GHZ:
+ fc_host_speed(shost) = FC_PORTSPEED_64GBIT;
+ break;
default:
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break;
@@ -6260,6 +6319,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
+ lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd);
lpfc_auto_imax_init(phba, lpfc_auto_imax);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -6284,6 +6344,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
phba->cfg_poll = 0;
else
phba->cfg_poll = lpfc_poll;
+
+ if (phba->cfg_enable_bg)
+ phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
+
lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp);
lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type);
@@ -6295,6 +6359,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
lpfc_nvme_io_channel_init(phba, lpfc_nvme_io_channel);
lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr);
+ lpfc_enable_dpp_init(phba, lpfc_enable_dpp);
if (phba->sli_rev != LPFC_SLI_REV4) {
/* NVME only supported on SLI4 */
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index d89816222b23..0f174ca80f67 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2009-2015 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -3867,7 +3867,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
"ext_buf_cnt:%d\n", ext_buf_cnt);
} else {
/* sanity check on interface type for support */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
LPFC_SLI_INTF_IF_TYPE_2) {
rc = -ENODEV;
goto job_error;
@@ -4053,7 +4053,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
"ext_buf_cnt:%d\n", ext_buf_cnt);
} else {
/* sanity check on interface type for support */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
LPFC_SLI_INTF_IF_TYPE_2)
return -ENODEV;
/* nemb_tp == nemb_hbd */
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 559f9aa0ed08..4ae9ba425e78 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -254,6 +254,7 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba,
struct lpfc_nvmet_ctxbuf *ctxp);
int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
struct fc_frame_header *fc_hdr);
+void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq);
void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba);
void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba);
void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
@@ -564,6 +565,8 @@ void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba);
void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocb,
struct lpfc_wcqe_complete *abts_cmpl);
+void lpfc_nvme_cmd_template(void);
+void lpfc_nvmet_cmd_template(void);
extern int lpfc_enable_nvmet_cnt;
extern unsigned long long lpfc_enable_nvmet[];
extern int lpfc_no_hba_reset_cnt;
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 9d20d2c208c7..0617c8ea88c6 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -471,7 +471,6 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
"Parse GID_FTrsp: did:x%x flg:x%x x%x",
Did, ndlp->nlp_flag, vport->fc_flag);
- ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
/* By default, the driver expects to support FCP FC4 */
if (fc4_type == FC_TYPE_FCP)
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
@@ -2130,6 +2129,8 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
ae->un.AttrInt = 0;
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ if (phba->lmt & LMT_64Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
if (phba->lmt & LMT_32Gb)
ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
if (phba->lmt & LMT_16Gb)
@@ -2201,6 +2202,9 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
case LPFC_LINK_SPEED_32GHZ:
ae->un.AttrInt = HBA_PORTSPEED_32GFC;
break;
+ case LPFC_LINK_SPEED_64GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_64GFC;
+ break;
default:
ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
break;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 17ea3bb04266..fb0dc2aeed91 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2007-2015 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -3944,10 +3944,15 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
return 0;
switch (drbregid) {
- case LPFC_DRB_EQCQ:
- len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
- "EQCQ-DRB-REG: 0x%08x\n",
- readl(phba->sli4_hba.EQCQDBregaddr));
+ case LPFC_DRB_EQ:
+ len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
+ "EQ-DRB-REG: 0x%08x\n",
+ readl(phba->sli4_hba.EQDBregaddr));
+ break;
+ case LPFC_DRB_CQ:
+ len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
+ "CQ-DRB-REG: 0x%08x\n",
+ readl(phba->sli4_hba.CQDBregaddr));
break;
case LPFC_DRB_MQ:
len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
@@ -4086,8 +4091,11 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
switch (drb_reg_id) {
- case LPFC_DRB_EQCQ:
- drb_reg = phba->sli4_hba.EQCQDBregaddr;
+ case LPFC_DRB_EQ:
+ drb_reg = phba->sli4_hba.EQDBregaddr;
+ break;
+ case LPFC_DRB_CQ:
+ drb_reg = phba->sli4_hba.CQDBregaddr;
break;
case LPFC_DRB_MQ:
drb_reg = phba->sli4_hba.MQDBregaddr;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index c4edd87bfc65..f32eaeb2225a 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2007-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -126,12 +126,13 @@
#define LPFC_DRB_ACC_WR_CMD_ARG 2
#define LPFC_DRB_ACC_BUF_SIZE 256
-#define LPFC_DRB_EQCQ 1
-#define LPFC_DRB_MQ 2
-#define LPFC_DRB_WQ 3
-#define LPFC_DRB_RQ 4
+#define LPFC_DRB_EQ 1
+#define LPFC_DRB_CQ 2
+#define LPFC_DRB_MQ 3
+#define LPFC_DRB_WQ 4
+#define LPFC_DRB_RQ 5
-#define LPFC_DRB_MAX 4
+#define LPFC_DRB_MAX 5
#define IDIAG_DRBACC_REGID_INDX 0
#define IDIAG_DRBACC_VALUE_INDX 1
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 234c7c015982..74895e62aaea 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1661,6 +1661,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
if (ndlp->nrport) {
ndlp->nrport = NULL;
lpfc_nlp_put(ndlp);
+ new_ndlp->nlp_fc4_type = ndlp->nlp_fc4_type;
}
/* We shall actually free the ndlp with both nlp_DID and
@@ -2293,10 +2294,11 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (phba->nvmet_support) {
bf_set(prli_tgt, npr_nvme, 1);
bf_set(prli_disc, npr_nvme, 1);
-
} else {
bf_set(prli_init, npr_nvme, 1);
+ bf_set(prli_conf, npr_nvme, 1);
}
+
npr_nvme->word1 = cpu_to_be32(npr_nvme->word1);
npr_nvme->word4 = cpu_to_be32(npr_nvme->word4);
elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ;
@@ -5269,6 +5271,9 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
case LPFC_LINK_SPEED_32GHZ:
rdp_speed = RDP_PS_32GB;
break;
+ case LPFC_LINK_SPEED_64GHZ:
+ rdp_speed = RDP_PS_64GB;
+ break;
default:
rdp_speed = RDP_PS_UNKNOWN;
break;
@@ -5276,6 +5281,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
desc->info.port_speed.speed = cpu_to_be16(rdp_speed);
+ if (phba->lmt & LMT_64Gb)
+ rdp_cap |= RDP_PS_64GB;
if (phba->lmt & LMT_32Gb)
rdp_cap |= RDP_PS_32GB;
if (phba->lmt & LMT_16Gb)
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index b159a5c4e388..3e7712cd6c9a 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -696,8 +696,9 @@ lpfc_work_done(struct lpfc_hba *phba)
phba->hba_flag & HBA_SP_QUEUE_EVT)) {
if (pring->flag & LPFC_STOP_IOCB_EVENT) {
pring->flag |= LPFC_DEFERRED_RING_EVENT;
- /* Set the lpfc data pending flag */
- set_bit(LPFC_DATA_READY, &phba->data_flags);
+ /* Preserve legacy behavior. */
+ if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
+ set_bit(LPFC_DATA_READY, &phba->data_flags);
} else {
if (phba->link_state >= LPFC_LINK_UP ||
phba->link_flag & LS_MDS_LOOPBACK) {
@@ -958,6 +959,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport)
struct lpfc_nodelist *ndlp;
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
@@ -3083,6 +3085,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
case LPFC_LINK_SPEED_10GHZ:
case LPFC_LINK_SPEED_16GHZ:
case LPFC_LINK_SPEED_32GHZ:
+ case LPFC_LINK_SPEED_64GHZ:
break;
default:
phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
@@ -3873,6 +3876,10 @@ int
lpfc_issue_gidft(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+ ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
/* Good status, issue CT Request to NameServer */
if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index bdc1f184f67a..08a3f1520159 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1177,6 +1177,9 @@ struct fc_rdp_link_error_status_desc {
#define RDP_PS_8GB 0x0800
#define RDP_PS_16GB 0x0400
#define RDP_PS_32GB 0x0200
+#define RDP_PS_64GB 0x0100
+#define RDP_PS_128GB 0x0080
+#define RDP_PS_256GB 0x0040
#define RDP_CAP_USER_CONFIGURED 0x0002
#define RDP_CAP_UNKNOWN 0x0001
@@ -1580,6 +1583,7 @@ struct lpfc_fdmi_reg_portattr {
#define PCI_DEVICE_ID_LANCER_FCOE 0xe260
#define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268
#define PCI_DEVICE_ID_LANCER_G6_FC 0xe300
+#define PCI_DEVICE_ID_LANCER_G7_FC 0xf400
#define PCI_DEVICE_ID_SAT_SMB 0xf011
#define PCI_DEVICE_ID_SAT_MID 0xf015
#define PCI_DEVICE_ID_RFLY 0xf095
@@ -2257,6 +2261,9 @@ typedef struct {
#define LINK_SPEED_10G 0x10 /* 10 Gigabaud */
#define LINK_SPEED_16G 0x11 /* 16 Gigabaud */
#define LINK_SPEED_32G 0x14 /* 32 Gigabaud */
+#define LINK_SPEED_64G 0x17 /* 64 Gigabaud */
+#define LINK_SPEED_128G 0x1A /* 128 Gigabaud */
+#define LINK_SPEED_256G 0x1D /* 256 Gigabaud */
} INIT_LINK_VAR;
@@ -2441,6 +2448,9 @@ typedef struct {
#define LMT_10Gb 0x100
#define LMT_16Gb 0x200
#define LMT_32Gb 0x400
+#define LMT_64Gb 0x800
+#define LMT_128Gb 0x1000
+#define LMT_256Gb 0x2000
uint32_t rsvd2;
uint32_t rsvd3;
uint32_t max_xri;
@@ -2965,6 +2975,9 @@ struct lpfc_mbx_read_top {
#define LPFC_LINK_SPEED_10GHZ 0x40
#define LPFC_LINK_SPEED_16GHZ 0x80
#define LPFC_LINK_SPEED_32GHZ 0x90
+#define LPFC_LINK_SPEED_64GHZ 0xA0
+#define LPFC_LINK_SPEED_128GHZ 0xB0
+#define LPFC_LINK_SPEED_256GHZ 0xC0
};
/* Structure for MB Command CLEAR_LA (22) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 73c2f6971d2b..98b80559c215 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -84,6 +84,7 @@ struct lpfc_sli_intf {
#define LPFC_SLI_INTF_IF_TYPE_0 0
#define LPFC_SLI_INTF_IF_TYPE_1 1
#define LPFC_SLI_INTF_IF_TYPE_2 2
+#define LPFC_SLI_INTF_IF_TYPE_6 6
#define lpfc_sli_intf_sli_family_SHIFT 8
#define lpfc_sli_intf_sli_family_MASK 0x0000000F
#define lpfc_sli_intf_sli_family_WORD word0
@@ -731,11 +732,13 @@ struct lpfc_register {
* register sets depending on the UCNA Port's reported if_type
* value. For UCNA ports running SLI4 and if_type 0, they reside in
* BAR4. For UCNA ports running SLI4 and if_type 2, they reside in
- * BAR0. The offsets are the same so the driver must account for
- * any base address difference.
+ * BAR0. For FC ports running SLI4 and if_type 6, they reside in
+ * BAR2. The offsets and base address are different, so the driver
+ * has to compute the register addresses accordingly
*/
#define LPFC_ULP0_RQ_DOORBELL 0x00A0
#define LPFC_ULP1_RQ_DOORBELL 0x00C0
+#define LPFC_IF6_RQ_DOORBELL 0x0080
#define lpfc_rq_db_list_fm_num_posted_SHIFT 24
#define lpfc_rq_db_list_fm_num_posted_MASK 0x00FF
#define lpfc_rq_db_list_fm_num_posted_WORD word0
@@ -770,6 +773,20 @@ struct lpfc_register {
#define lpfc_wq_db_ring_fm_id_MASK 0xFFFF
#define lpfc_wq_db_ring_fm_id_WORD word0
+#define LPFC_IF6_WQ_DOORBELL 0x0040
+#define lpfc_if6_wq_db_list_fm_num_posted_SHIFT 24
+#define lpfc_if6_wq_db_list_fm_num_posted_MASK 0x00FF
+#define lpfc_if6_wq_db_list_fm_num_posted_WORD word0
+#define lpfc_if6_wq_db_list_fm_dpp_SHIFT 23
+#define lpfc_if6_wq_db_list_fm_dpp_MASK 0x0001
+#define lpfc_if6_wq_db_list_fm_dpp_WORD word0
+#define lpfc_if6_wq_db_list_fm_dpp_id_SHIFT 16
+#define lpfc_if6_wq_db_list_fm_dpp_id_MASK 0x001F
+#define lpfc_if6_wq_db_list_fm_dpp_id_WORD word0
+#define lpfc_if6_wq_db_list_fm_id_SHIFT 0
+#define lpfc_if6_wq_db_list_fm_id_MASK 0xFFFF
+#define lpfc_if6_wq_db_list_fm_id_WORD word0
+
#define LPFC_EQCQ_DOORBELL 0x0120
#define lpfc_eqcq_doorbell_se_SHIFT 31
#define lpfc_eqcq_doorbell_se_MASK 0x0001
@@ -805,6 +822,38 @@ struct lpfc_register {
#define LPFC_CQID_HI_FIELD_SHIFT 10
#define LPFC_EQID_HI_FIELD_SHIFT 9
+#define LPFC_IF6_CQ_DOORBELL 0x00C0
+#define lpfc_if6_cq_doorbell_se_SHIFT 31
+#define lpfc_if6_cq_doorbell_se_MASK 0x0001
+#define lpfc_if6_cq_doorbell_se_WORD word0
+#define LPFC_IF6_CQ_SOLICIT_ENABLE_OFF 0
+#define LPFC_IF6_CQ_SOLICIT_ENABLE_ON 1
+#define lpfc_if6_cq_doorbell_arm_SHIFT 29
+#define lpfc_if6_cq_doorbell_arm_MASK 0x0001
+#define lpfc_if6_cq_doorbell_arm_WORD word0
+#define lpfc_if6_cq_doorbell_num_released_SHIFT 16
+#define lpfc_if6_cq_doorbell_num_released_MASK 0x1FFF
+#define lpfc_if6_cq_doorbell_num_released_WORD word0
+#define lpfc_if6_cq_doorbell_cqid_SHIFT 0
+#define lpfc_if6_cq_doorbell_cqid_MASK 0xFFFF
+#define lpfc_if6_cq_doorbell_cqid_WORD word0
+
+#define LPFC_IF6_EQ_DOORBELL 0x0120
+#define lpfc_if6_eq_doorbell_io_SHIFT 31
+#define lpfc_if6_eq_doorbell_io_MASK 0x0001
+#define lpfc_if6_eq_doorbell_io_WORD word0
+#define LPFC_IF6_EQ_INTR_OVERRIDE_OFF 0
+#define LPFC_IF6_EQ_INTR_OVERRIDE_ON 1
+#define lpfc_if6_eq_doorbell_arm_SHIFT 29
+#define lpfc_if6_eq_doorbell_arm_MASK 0x0001
+#define lpfc_if6_eq_doorbell_arm_WORD word0
+#define lpfc_if6_eq_doorbell_num_released_SHIFT 16
+#define lpfc_if6_eq_doorbell_num_released_MASK 0x1FFF
+#define lpfc_if6_eq_doorbell_num_released_WORD word0
+#define lpfc_if6_eq_doorbell_eqid_SHIFT 0
+#define lpfc_if6_eq_doorbell_eqid_MASK 0x0FFF
+#define lpfc_if6_eq_doorbell_eqid_WORD word0
+
#define LPFC_BMBX 0x0160
#define lpfc_bmbx_addr_SHIFT 2
#define lpfc_bmbx_addr_MASK 0x3FFFFFFF
@@ -817,6 +866,7 @@ struct lpfc_register {
#define lpfc_bmbx_rdy_WORD word0
#define LPFC_MQ_DOORBELL 0x0140
+#define LPFC_IF6_MQ_DOORBELL 0x0160
#define lpfc_mq_doorbell_num_posted_SHIFT 16
#define lpfc_mq_doorbell_num_posted_MASK 0x3FFF
#define lpfc_mq_doorbell_num_posted_WORD word0
@@ -990,6 +1040,9 @@ struct eq_context {
#define lpfc_eq_context_valid_SHIFT 29
#define lpfc_eq_context_valid_MASK 0x00000001
#define lpfc_eq_context_valid_WORD word0
+#define lpfc_eq_context_autovalid_SHIFT 28
+#define lpfc_eq_context_autovalid_MASK 0x00000001
+#define lpfc_eq_context_autovalid_WORD word0
uint32_t word1;
#define lpfc_eq_context_count_SHIFT 26
#define lpfc_eq_context_count_MASK 0x00000003
@@ -1123,6 +1176,9 @@ struct cq_context {
#define LPFC_CQ_CNT_512 0x1
#define LPFC_CQ_CNT_1024 0x2
#define LPFC_CQ_CNT_WORD7 0x3
+#define lpfc_cq_context_autovalid_SHIFT 15
+#define lpfc_cq_context_autovalid_MASK 0x00000001
+#define lpfc_cq_context_autovalid_WORD word0
uint32_t word1;
#define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */
#define lpfc_cq_eq_id_MASK 0x000000FF
@@ -1181,9 +1237,9 @@ struct lpfc_mbx_cq_create_set {
#define lpfc_mbx_cq_create_set_cqe_size_SHIFT 25
#define lpfc_mbx_cq_create_set_cqe_size_MASK 0x00000003
#define lpfc_mbx_cq_create_set_cqe_size_WORD word1
-#define lpfc_mbx_cq_create_set_auto_SHIFT 15
-#define lpfc_mbx_cq_create_set_auto_MASK 0x0000001
-#define lpfc_mbx_cq_create_set_auto_WORD word1
+#define lpfc_mbx_cq_create_set_autovalid_SHIFT 15
+#define lpfc_mbx_cq_create_set_autovalid_MASK 0x0000001
+#define lpfc_mbx_cq_create_set_autovalid_WORD word1
#define lpfc_mbx_cq_create_set_nodelay_SHIFT 14
#define lpfc_mbx_cq_create_set_nodelay_MASK 0x00000001
#define lpfc_mbx_cq_create_set_nodelay_WORD word1
@@ -1322,6 +1378,15 @@ struct lpfc_mbx_wq_create {
#define lpfc_mbx_wq_create_page_size_MASK 0x000000FF
#define lpfc_mbx_wq_create_page_size_WORD word1
#define LPFC_WQ_PAGE_SIZE_4096 0x1
+#define lpfc_mbx_wq_create_dpp_req_SHIFT 15
+#define lpfc_mbx_wq_create_dpp_req_MASK 0x00000001
+#define lpfc_mbx_wq_create_dpp_req_WORD word1
+#define lpfc_mbx_wq_create_doe_SHIFT 14
+#define lpfc_mbx_wq_create_doe_MASK 0x00000001
+#define lpfc_mbx_wq_create_doe_WORD word1
+#define lpfc_mbx_wq_create_toe_SHIFT 13
+#define lpfc_mbx_wq_create_toe_MASK 0x00000001
+#define lpfc_mbx_wq_create_toe_WORD word1
#define lpfc_mbx_wq_create_wqe_size_SHIFT 8
#define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F
#define lpfc_mbx_wq_create_wqe_size_WORD word1
@@ -1350,6 +1415,28 @@ struct lpfc_mbx_wq_create {
#define lpfc_mbx_wq_create_db_format_MASK 0x0000FFFF
#define lpfc_mbx_wq_create_db_format_WORD word2
} response;
+ struct {
+ uint32_t word0;
+#define lpfc_mbx_wq_create_dpp_rsp_SHIFT 31
+#define lpfc_mbx_wq_create_dpp_rsp_MASK 0x00000001
+#define lpfc_mbx_wq_create_dpp_rsp_WORD word0
+#define lpfc_mbx_wq_create_v1_q_id_SHIFT 0
+#define lpfc_mbx_wq_create_v1_q_id_MASK 0x0000FFFF
+#define lpfc_mbx_wq_create_v1_q_id_WORD word0
+ uint32_t word1;
+#define lpfc_mbx_wq_create_v1_bar_set_SHIFT 0
+#define lpfc_mbx_wq_create_v1_bar_set_MASK 0x0000000F
+#define lpfc_mbx_wq_create_v1_bar_set_WORD word1
+ uint32_t doorbell_offset;
+ uint32_t word3;
+#define lpfc_mbx_wq_create_dpp_id_SHIFT 16
+#define lpfc_mbx_wq_create_dpp_id_MASK 0x0000001F
+#define lpfc_mbx_wq_create_dpp_id_WORD word3
+#define lpfc_mbx_wq_create_dpp_bar_SHIFT 0
+#define lpfc_mbx_wq_create_dpp_bar_MASK 0x0000000F
+#define lpfc_mbx_wq_create_dpp_bar_WORD word3
+ uint32_t dpp_offset;
+ } response_1;
} u;
};
@@ -2154,6 +2241,7 @@ struct lpfc_mbx_redisc_fcf_tbl {
* command.
*/
#define ADD_STATUS_OPERATION_ALREADY_ACTIVE 0x67
+#define ADD_STATUS_FW_NOT_SUPPORTED 0xEB
struct lpfc_mbx_sli4_config {
struct mbox_header header;
@@ -2590,6 +2678,7 @@ struct lpfc_mbx_read_rev {
#define lpfc_mbx_rd_rev_vpd_MASK 0x00000001
#define lpfc_mbx_rd_rev_vpd_WORD word1
uint32_t first_hw_rev;
+#define LPFC_G7_ASIC_1 0xd
uint32_t second_hw_rev;
uint32_t word4_rsvd;
uint32_t third_hw_rev;
@@ -3207,11 +3296,20 @@ struct lpfc_sli4_parameters {
#define cfg_sli_hint_2_MASK 0x0000001f
#define cfg_sli_hint_2_WORD word1
uint32_t word2;
+#define cfg_eqav_SHIFT 31
+#define cfg_eqav_MASK 0x00000001
+#define cfg_eqav_WORD word2
uint32_t word3;
uint32_t word4;
#define cfg_cqv_SHIFT 14
#define cfg_cqv_MASK 0x00000003
#define cfg_cqv_WORD word4
+#define cfg_cqpsize_SHIFT 16
+#define cfg_cqpsize_MASK 0x000000ff
+#define cfg_cqpsize_WORD word4
+#define cfg_cqav_SHIFT 31
+#define cfg_cqav_MASK 0x00000001
+#define cfg_cqav_WORD word4
uint32_t word5;
uint32_t word6;
#define cfg_mqv_SHIFT 14
@@ -3290,6 +3388,9 @@ struct lpfc_sli4_parameters {
#define cfg_eqdr_SHIFT 8
#define cfg_eqdr_MASK 0x00000001
#define cfg_eqdr_WORD word19
+#define cfg_nosr_SHIFT 9
+#define cfg_nosr_MASK 0x00000001
+#define cfg_nosr_WORD word19
#define LPFC_NODELAY_MAX_IO 32
};
@@ -3874,6 +3975,9 @@ struct lpfc_acqe_fc_la {
#define LPFC_FC_LA_SPEED_10G 0xA
#define LPFC_FC_LA_SPEED_16G 0x10
#define LPFC_FC_LA_SPEED_32G 0x20
+#define LPFC_FC_LA_SPEED_64G 0x21
+#define LPFC_FC_LA_SPEED_128G 0x22
+#define LPFC_FC_LA_SPEED_256G 0x23
#define lpfc_acqe_fc_la_topology_SHIFT 16
#define lpfc_acqe_fc_la_topology_MASK 0x000000FF
#define lpfc_acqe_fc_la_topology_WORD word0
@@ -4079,6 +4183,7 @@ struct wqe_common {
#define wqe_iod_SHIFT 13
#define wqe_iod_MASK 0x00000001
#define wqe_iod_WORD word10
+#define LPFC_WQE_IOD_NONE 0
#define LPFC_WQE_IOD_WRITE 0
#define LPFC_WQE_IOD_READ 1
#define wqe_dbde_SHIFT 14
@@ -4123,6 +4228,9 @@ struct wqe_common {
#define wqe_irsp_SHIFT 4
#define wqe_irsp_MASK 0x00000001
#define wqe_irsp_WORD word11
+#define wqe_pbde_SHIFT 5
+#define wqe_pbde_MASK 0x00000001
+#define wqe_pbde_WORD word11
#define wqe_sup_SHIFT 6
#define wqe_sup_MASK 0x00000001
#define wqe_sup_WORD word11
@@ -4343,9 +4451,9 @@ struct lpfc_nvme_prli {
#define prli_init_SHIFT 5
#define prli_init_MASK 0x00000001
#define prli_init_WORD word4
-#define prli_recov_SHIFT 8
-#define prli_recov_MASK 0x00000001
-#define prli_recov_WORD word4
+#define prli_conf_SHIFT 7
+#define prli_conf_MASK 0x00000001
+#define prli_conf_WORD word4
uint32_t word5;
#define prli_fb_sz_SHIFT 0
#define prli_fb_sz_MASK 0x0000ffff
@@ -4494,17 +4602,20 @@ union lpfc_wqe128 {
struct fcp_icmnd64_wqe fcp_icmd;
struct fcp_iread64_wqe fcp_iread;
struct fcp_iwrite64_wqe fcp_iwrite;
+ struct abort_cmd_wqe abort_cmd;
+ struct create_xri_wqe create_xri;
+ struct xmit_bcast64_wqe xmit_bcast64;
+ struct xmit_seq64_wqe xmit_sequence;
+ struct xmit_bls_rsp64_wqe xmit_bls_rsp;
+ struct xmit_els_rsp64_wqe xmit_els_rsp;
+ struct els_request64_wqe els_req;
+ struct gen_req64_wqe gen_req;
struct fcp_trsp64_wqe fcp_trsp;
struct fcp_tsend64_wqe fcp_tsend;
struct fcp_treceive64_wqe fcp_treceive;
- struct xmit_seq64_wqe xmit_sequence;
- struct gen_req64_wqe gen_req;
+ struct send_frame_wqe send_frame;
};
-#define LPFC_GROUP_OJECT_MAGIC_G5 0xfeaa0001
-#define LPFC_GROUP_OJECT_MAGIC_G6 0xfeaa0003
-#define LPFC_FILE_TYPE_GROUP 0xf7
-#define LPFC_FILE_ID_GROUP 0xa2
struct lpfc_grp_hdr {
uint32_t size;
uint32_t magic_number;
diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h
index 0ba3733eb36d..07ee34017d88 100644
--- a/drivers/scsi/lpfc/lpfc_ids.h
+++ b/drivers/scsi/lpfc/lpfc_ids.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -116,6 +116,8 @@ const struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7_FC,
+ 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,
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f539c554588c..7887468c71b4 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -731,7 +731,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology,
((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) &&
!(phba->lmt & LMT_16Gb)) ||
((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) &&
- !(phba->lmt & LMT_32Gb))) {
+ !(phba->lmt & LMT_32Gb)) ||
+ ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) &&
+ !(phba->lmt & LMT_64Gb))) {
/* Reset link speed to auto */
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1302 Invalid speed for this board:%d "
@@ -958,6 +960,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
struct lpfc_sli_ring *pring;
LIST_HEAD(completions);
int i;
+ struct lpfc_iocbq *piocb, *next_iocb;
if (phba->sli_rev != LPFC_SLI_REV4) {
for (i = 0; i < psli->num_rings; i++) {
@@ -983,6 +986,9 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
if (!pring)
continue;
spin_lock_irq(&pring->ring_lock);
+ list_for_each_entry_safe(piocb, next_iocb,
+ &pring->txcmplq, list)
+ piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
list_splice_init(&pring->txcmplq, &completions);
pring->txcmplq_cnt = 0;
spin_unlock_irq(&pring->ring_lock);
@@ -1757,7 +1763,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action,
int rc;
uint32_t intr_mode;
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
LPFC_SLI_INTF_IF_TYPE_2) {
/*
* On error status condition, driver need to wait for port
@@ -1888,6 +1894,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
break;
case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_6:
pci_rd_rc1 = lpfc_readl(
phba->sli4_hba.u.if_type2.STATUSregaddr,
&portstat_reg.word0);
@@ -2269,7 +2276,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
&& descp && descp[0] != '\0')
return;
- if (phba->lmt & LMT_32Gb)
+ if (phba->lmt & LMT_64Gb)
+ max_speed = 64;
+ else if (phba->lmt & LMT_32Gb)
max_speed = 32;
else if (phba->lmt & LMT_16Gb)
max_speed = 16;
@@ -2468,6 +2477,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
case PCI_DEVICE_ID_LANCER_G6_FC:
m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"};
break;
+ case PCI_DEVICE_ID_LANCER_G7_FC:
+ m = (typeof(m)){"LPe36000", "PCIe", "Fibre Channel Adapter"};
+ break;
case PCI_DEVICE_ID_SKYHAWK:
case PCI_DEVICE_ID_SKYHAWK_VF:
oneConnect = 1;
@@ -4104,6 +4116,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
sizeof fc_host_symbolic_name(shost));
fc_host_supported_speeds(shost) = 0;
+ if (phba->lmt & LMT_64Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_64GBIT;
if (phba->lmt & LMT_32Gb)
fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT;
if (phba->lmt & LMT_16Gb)
@@ -4440,6 +4454,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code,
case LPFC_FC_LA_SPEED_32G:
port_speed = 32000;
break;
+ case LPFC_FC_LA_SPEED_64G:
+ port_speed = 64000;
+ break;
default:
port_speed = 0;
}
@@ -5895,7 +5912,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
* Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size
* used to create the sg_dma_buf_pool must be calculated.
*/
- if (phba->cfg_enable_bg) {
+ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
/*
* The scsi_buf for a T10-DIF I/O holds the FCP cmnd,
* the FCP rsp, and a SGE. Sice we have no control
@@ -6014,7 +6031,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
return -ENOMEM;
/* IF Type 2 ports get initialized now. */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
LPFC_SLI_INTF_IF_TYPE_2) {
rc = lpfc_pci_function_reset(phba);
if (unlikely(rc)) {
@@ -7344,6 +7361,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
}
break;
case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_6:
/* Final checks. The port status should be clean. */
if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
&reg_data.word0) ||
@@ -7426,13 +7444,36 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
phba->sli4_hba.WQDBregaddr =
phba->sli4_hba.conf_regs_memmap_p +
LPFC_ULP0_WQ_DOORBELL;
- phba->sli4_hba.EQCQDBregaddr =
+ phba->sli4_hba.CQDBregaddr =
phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
+ phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr;
phba->sli4_hba.MQDBregaddr =
phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL;
phba->sli4_hba.BMBXregaddr =
phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
break;
+ case LPFC_SLI_INTF_IF_TYPE_6:
+ phba->sli4_hba.u.if_type2.EQDregaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_EQ_DELAY_OFFSET;
+ phba->sli4_hba.u.if_type2.ERR1regaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_ER1_OFFSET;
+ phba->sli4_hba.u.if_type2.ERR2regaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_ER2_OFFSET;
+ phba->sli4_hba.u.if_type2.CTRLregaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_CTL_OFFSET;
+ phba->sli4_hba.u.if_type2.STATUSregaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_STA_OFFSET;
+ phba->sli4_hba.PSMPHRregaddr =
+ phba->sli4_hba.conf_regs_memmap_p +
+ LPFC_CTL_PORT_SEM_OFFSET;
+ phba->sli4_hba.BMBXregaddr =
+ phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
+ break;
case LPFC_SLI_INTF_IF_TYPE_1:
default:
dev_printk(KERN_ERR, &phba->pcidev->dev,
@@ -7446,20 +7487,43 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
* lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map.
* @phba: pointer to lpfc hba data structure.
*
- * This routine is invoked to set up SLI4 BAR1 control status register (CSR)
- * memory map.
+ * This routine is invoked to set up SLI4 BAR1 register memory map.
**/
static void
-lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
+lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
{
- phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_SLIPORT_IF0_SMPHR;
- phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISR0;
- phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_IMR0;
- phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
- LPFC_HST_ISCR0;
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ phba->sli4_hba.PSMPHRregaddr =
+ phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_SLIPORT_IF0_SMPHR;
+ phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_HST_ISR0;
+ phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_HST_IMR0;
+ phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+ LPFC_HST_ISCR0;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_6:
+ phba->sli4_hba.RQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+ LPFC_IF6_RQ_DOORBELL;
+ phba->sli4_hba.WQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+ LPFC_IF6_WQ_DOORBELL;
+ phba->sli4_hba.CQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+ LPFC_IF6_CQ_DOORBELL;
+ phba->sli4_hba.EQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+ LPFC_IF6_EQ_DOORBELL;
+ phba->sli4_hba.MQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+ LPFC_IF6_MQ_DOORBELL;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_1:
+ default:
+ dev_err(&phba->pcidev->dev,
+ "FATAL - unsupported SLI4 interface type - %d\n",
+ if_type);
+ break;
+ }
}
/**
@@ -7484,8 +7548,10 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
vf * LPFC_VFR_PAGE_SIZE +
LPFC_ULP0_WQ_DOORBELL);
- phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
- vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL);
+ phba->sli4_hba.CQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+ vf * LPFC_VFR_PAGE_SIZE +
+ LPFC_EQCQ_DOORBELL);
+ phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr;
phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL);
phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
@@ -7722,7 +7788,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
/* Update link speed if forced link speed is supported */
if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
- if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
forced_link_speed =
bf_get(lpfc_mbx_rd_conf_link_speed, rd_config);
if (forced_link_speed) {
@@ -7757,6 +7823,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->cfg_link_speed =
LPFC_USER_LINK_SPEED_32G;
break;
+ case LINK_SPEED_64G:
+ phba->cfg_link_speed =
+ LPFC_USER_LINK_SPEED_64G;
+ break;
case 0xffff:
phba->cfg_link_speed =
LPFC_USER_LINK_SPEED_AUTO;
@@ -7782,7 +7852,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->cfg_hba_queue_depth = length;
}
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
LPFC_SLI_INTF_IF_TYPE_2)
goto read_cfg_out;
@@ -7896,6 +7966,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba)
}
mempool_free(mboxq, phba->mbox_mem_pool);
break;
+ case LPFC_SLI_INTF_IF_TYPE_6:
case LPFC_SLI_INTF_IF_TYPE_2:
case LPFC_SLI_INTF_IF_TYPE_1:
default:
@@ -7992,6 +8063,7 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx)
wqidx);
return 1;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.nvme_cq[wqidx] = qdesc;
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
@@ -8011,9 +8083,10 @@ static int
lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
{
struct lpfc_queue *qdesc;
+ uint32_t wqesize;
/* Create Fast Path FCP CQs */
- if (phba->fcp_embed_io)
+ if (phba->enab_exp_wqcq_pages)
/* Increase the CQ size when WQEs contain an embedded cdb */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
phba->sli4_hba.cq_esize,
@@ -8028,18 +8101,22 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
"0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx);
return 1;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.fcp_cq[wqidx] = qdesc;
/* Create Fast Path FCP WQs */
- if (phba->fcp_embed_io)
+ if (phba->enab_exp_wqcq_pages) {
/* Increase the WQ size when WQEs contain an embedded cdb */
+ wqesize = (phba->fcp_embed_io) ?
+ LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
- LPFC_WQE128_SIZE,
+ wqesize,
LPFC_WQE_EXP_COUNT);
- else
+ } else
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
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",
@@ -8218,6 +8295,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
"0497 Failed allocate EQ (%d)\n", idx);
goto out_error;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.hba_eq[idx] = qdesc;
}
@@ -8243,6 +8321,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
"CQ Set (%d)\n", idx);
goto out_error;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.nvmet_cqset[idx] = qdesc;
}
}
@@ -8260,6 +8339,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
"0500 Failed allocate slow-path mailbox CQ\n");
goto out_error;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.mbx_cq = qdesc;
/* Create slow-path ELS Complete Queue */
@@ -8271,6 +8351,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
"0501 Failed allocate slow-path ELS CQ\n");
goto out_error;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.els_cq = qdesc;
@@ -8316,6 +8397,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
"6079 Failed allocate NVME LS CQ\n");
goto out_error;
}
+ qdesc->qe_valid = 1;
phba->sli4_hba.nvmels_cq = qdesc;
/* Create NVME LS Work Queue */
@@ -9303,6 +9385,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
}
break;
case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_6:
wait:
/*
* Poll the Port Status Register and wait for RDY for
@@ -9458,7 +9541,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
} else {
phba->pci_bar0_map = pci_resource_start(pdev, 1);
bar0map_len = pci_resource_len(pdev, 1);
- if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
dev_printk(KERN_ERR, &pdev->dev,
"FATAL - No BAR0 mapping for SLI4, if_type 2\n");
goto out;
@@ -9495,13 +9578,32 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
}
phba->pci_bar2_memmap_p =
phba->sli4_hba.ctrl_regs_memmap_p;
- lpfc_sli4_bar1_register_memmap(phba);
+ lpfc_sli4_bar1_register_memmap(phba, if_type);
} else {
error = -ENOMEM;
goto out_iounmap_conf;
}
}
+ if ((if_type == LPFC_SLI_INTF_IF_TYPE_6) &&
+ (pci_resource_start(pdev, PCI_64BIT_BAR2))) {
+ /*
+ * Map SLI4 if type 6 HBA Doorbell Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
+ bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
+ phba->sli4_hba.drbl_regs_memmap_p =
+ ioremap(phba->pci_bar1_map, bar1map_len);
+ if (!phba->sli4_hba.drbl_regs_memmap_p) {
+ dev_err(&pdev->dev,
+ "ioremap failed for SLI4 HBA doorbell registers.\n");
+ goto out_iounmap_conf;
+ }
+ phba->pci_bar2_memmap_p = phba->sli4_hba.drbl_regs_memmap_p;
+ lpfc_sli4_bar1_register_memmap(phba, if_type);
+ }
+
if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
if (pci_resource_start(pdev, PCI_64BIT_BAR4)) {
/*
@@ -9532,6 +9634,41 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
}
}
+ if (if_type == LPFC_SLI_INTF_IF_TYPE_6 &&
+ pci_resource_start(pdev, PCI_64BIT_BAR4)) {
+ /*
+ * Map SLI4 if type 6 HBA DPP Register base to a kernel
+ * virtual address and setup the registers.
+ */
+ phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
+ bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
+ phba->sli4_hba.dpp_regs_memmap_p =
+ ioremap(phba->pci_bar2_map, bar2map_len);
+ if (!phba->sli4_hba.dpp_regs_memmap_p) {
+ dev_err(&pdev->dev,
+ "ioremap failed for SLI4 HBA dpp registers.\n");
+ goto out_iounmap_ctrl;
+ }
+ phba->pci_bar4_memmap_p = phba->sli4_hba.dpp_regs_memmap_p;
+ }
+
+ /* Set up the EQ/CQ register handeling functions now */
+ switch (if_type) {
+ case LPFC_SLI_INTF_IF_TYPE_0:
+ case LPFC_SLI_INTF_IF_TYPE_2:
+ phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_eq_clr_intr;
+ phba->sli4_hba.sli4_eq_release = lpfc_sli4_eq_release;
+ phba->sli4_hba.sli4_cq_release = lpfc_sli4_cq_release;
+ break;
+ case LPFC_SLI_INTF_IF_TYPE_6:
+ phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_if6_eq_clr_intr;
+ phba->sli4_hba.sli4_eq_release = lpfc_sli4_if6_eq_release;
+ phba->sli4_hba.sli4_cq_release = lpfc_sli4_if6_cq_release;
+ break;
+ default:
+ break;
+ }
+
return 0;
out_iounmap_all:
@@ -9566,6 +9703,10 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
case LPFC_SLI_INTF_IF_TYPE_2:
iounmap(phba->sli4_hba.conf_regs_memmap_p);
break;
+ case LPFC_SLI_INTF_IF_TYPE_6:
+ iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+ iounmap(phba->sli4_hba.conf_regs_memmap_p);
+ break;
case LPFC_SLI_INTF_IF_TYPE_1:
default:
dev_printk(KERN_ERR, &phba->pcidev->dev,
@@ -10435,6 +10576,8 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
+ sli4_params->eqav = bf_get(cfg_eqav, mbx_sli4_parameters);
+ sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters);
sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
mbx_sli4_parameters);
@@ -10465,8 +10608,32 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
}
- if (bf_get(cfg_xib, mbx_sli4_parameters) && phba->cfg_suppress_rsp)
+ /* Only embed PBDE for if_type 6 */
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_6) {
+ phba->fcp_embed_pbde = 1;
+ phba->nvme_embed_pbde = 1;
+ }
+
+ /* PBDE support requires xib be set */
+ if (!bf_get(cfg_xib, mbx_sli4_parameters)) {
+ phba->fcp_embed_pbde = 0;
+ phba->nvme_embed_pbde = 0;
+ }
+
+ /*
+ * To support Suppress Response feature we must satisfy 3 conditions.
+ * lpfc_suppress_rsp module parameter must be set (default).
+ * In SLI4-Parameters Descriptor:
+ * Extended Inline Buffers (XIB) must be supported.
+ * Suppress Response IU Not Supported (SRIUNS) must NOT be supported
+ * (double negative).
+ */
+ if (phba->cfg_suppress_rsp && bf_get(cfg_xib, mbx_sli4_parameters) &&
+ !(bf_get(cfg_nosr, mbx_sli4_parameters)))
phba->sli.sli_flag |= LPFC_SLI_SUPPRESS_RSP;
+ else
+ phba->cfg_suppress_rsp = 0;
if (bf_get(cfg_eqdr, mbx_sli4_parameters))
phba->sli.sli_flag |= LPFC_SLI_USE_EQDR;
@@ -10476,15 +10643,28 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
/*
- * Issue IOs with CDB embedded in WQE to minimized the number
- * of DMAs the firmware has to do. Setting this to 1 also forces
- * the driver to use 128 bytes WQEs for FCP IOs.
+ * Check whether the adapter supports an embedded copy of the
+ * FCP CMD IU within the WQE for FCP_Ixxx commands. In order
+ * to use this option, 128-byte WQEs must be used.
*/
if (bf_get(cfg_ext_embed_cb, mbx_sli4_parameters))
phba->fcp_embed_io = 1;
else
phba->fcp_embed_io = 0;
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
+ "6422 XIB %d: FCP %d %d NVME %d %d %d %d\n",
+ bf_get(cfg_xib, mbx_sli4_parameters),
+ phba->fcp_embed_pbde, phba->fcp_embed_io,
+ phba->nvme_support, phba->nvme_embed_pbde,
+ phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp);
+
+ if ((bf_get(cfg_cqpsize, mbx_sli4_parameters) & LPFC_CQ_16K_PAGE_SZ) &&
+ (bf_get(cfg_wqpsize, mbx_sli4_parameters) & LPFC_WQ_16K_PAGE_SZ) &&
+ (sli4_params->wqsize & LPFC_WQ_SZ128_SUPPORT))
+ phba->enab_exp_wqcq_pages = 1;
+ else
+ phba->enab_exp_wqcq_pages = 0;
/*
* Check if the SLI port supports MDS Diagnostics
*/
@@ -11137,6 +11317,27 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba)
}
+static void
+lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset,
+ uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize,
+ const struct firmware *fw)
+{
+ if (offset == ADD_STATUS_FW_NOT_SUPPORTED)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3030 This firmware version is not supported on "
+ "this HBA model. Device:%x Magic:%x Type:%x "
+ "ID:%x Size %d %zd\n",
+ phba->pcidev->device, magic_number, ftype, fid,
+ fsize, fw->size);
+ else
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3022 FW Download failed. Device:%x Magic:%x Type:%x "
+ "ID:%x Size %d %zd\n",
+ phba->pcidev->device, magic_number, ftype, fid,
+ fsize, fw->size);
+}
+
+
/**
* lpfc_write_firmware - attempt to write a firmware image to the port
* @fw: pointer to firmware image returned from request_firmware.
@@ -11164,20 +11365,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
magic_number = be32_to_cpu(image->magic_number);
ftype = bf_get_be32(lpfc_grp_hdr_file_type, image);
- fid = bf_get_be32(lpfc_grp_hdr_id, image),
+ fid = bf_get_be32(lpfc_grp_hdr_id, image);
fsize = be32_to_cpu(image->size);
INIT_LIST_HEAD(&dma_buffer_list);
- if ((magic_number != LPFC_GROUP_OJECT_MAGIC_G5 &&
- magic_number != LPFC_GROUP_OJECT_MAGIC_G6) ||
- ftype != LPFC_FILE_TYPE_GROUP || fsize != fw->size) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3022 Invalid FW image found. "
- "Magic:%x Type:%x ID:%x Size %d %zd\n",
- magic_number, ftype, fid, fsize, fw->size);
- rc = -EINVAL;
- goto release_out;
- }
lpfc_decode_firmware_rev(phba, fwrev, 1);
if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -11218,11 +11409,18 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
}
rc = lpfc_wr_object(phba, &dma_buffer_list,
(fw->size - offset), &offset);
- if (rc)
+ if (rc) {
+ lpfc_log_write_firmware_error(phba, offset,
+ magic_number, ftype, fid, fsize, fw);
goto release_out;
+ }
}
rc = offset;
- }
+ } else
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3029 Skipped Firmware update, Current "
+ "Version:%s New Version:%s\n",
+ fwrev, image->revision);
release_out:
list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
@@ -11253,7 +11451,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade)
const struct firmware *fw;
/* Only supported on SLI4 interface type 2 for now */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
LPFC_SLI_INTF_IF_TYPE_2)
return -EPERM;
@@ -11493,13 +11691,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
/* Remove FC host and then SCSI host with the physical port */
fc_remove_host(shost);
scsi_remove_host(shost);
- /*
- * Bring down the SLI Layer. This step disables all interrupts,
- * clears the rings, discards all mailbox commands, and resets
- * the HBA FCoE function.
- */
- lpfc_debugfs_terminate(vport);
- lpfc_sli4_hba_unset(phba);
/* Perform ndlp cleanup on the physical port. The nvme and nvmet
* localports are destroyed after to cleanup all transport memory.
@@ -11508,6 +11699,13 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
lpfc_nvmet_destroy_targetport(phba);
lpfc_nvme_destroy_localport(vport);
+ /*
+ * Bring down the SLI Layer. This step disables all interrupts,
+ * clears the rings, discards all mailbox commands, and resets
+ * the HBA FCoE function.
+ */
+ lpfc_debugfs_terminate(vport);
+ lpfc_sli4_hba_unset(phba);
lpfc_stop_hba_timers(phba);
spin_lock_irq(&phba->hbalock);
@@ -12227,6 +12425,7 @@ int
lpfc_fof_queue_create(struct lpfc_hba *phba)
{
struct lpfc_queue *qdesc;
+ uint32_t wqesize;
/* Create FOF EQ */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
@@ -12235,12 +12434,13 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
if (!qdesc)
goto out_error;
+ qdesc->qe_valid = 1;
phba->sli4_hba.fof_eq = qdesc;
if (phba->cfg_fof) {
/* Create OAS CQ */
- if (phba->fcp_embed_io)
+ if (phba->enab_exp_wqcq_pages)
qdesc = lpfc_sli4_queue_alloc(phba,
LPFC_EXPANDED_PAGE_SIZE,
phba->sli4_hba.cq_esize,
@@ -12253,19 +12453,23 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
if (!qdesc)
goto out_error;
+ qdesc->qe_valid = 1;
phba->sli4_hba.oas_cq = qdesc;
/* Create OAS WQ */
- if (phba->fcp_embed_io)
+ if (phba->enab_exp_wqcq_pages) {
+ wqesize = (phba->fcp_embed_io) ?
+ LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
qdesc = lpfc_sli4_queue_alloc(phba,
LPFC_EXPANDED_PAGE_SIZE,
- LPFC_WQE128_SIZE,
+ wqesize,
LPFC_WQE_EXP_COUNT);
- else
+ } else
qdesc = lpfc_sli4_queue_alloc(phba,
LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.wq_esize,
phba->sli4_hba.wq_ecount);
+
if (!qdesc)
goto out_error;
@@ -12379,6 +12583,8 @@ lpfc_init(void)
fc_release_transport(lpfc_transport_template);
return -ENOMEM;
}
+ lpfc_nvme_cmd_template();
+ lpfc_nvmet_cmd_template();
/* Initialize in case vector mapping is needed */
lpfc_used_cpu = NULL;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 81fb92967b11..47c02da11f01 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -557,6 +557,10 @@ lpfc_init_link(struct lpfc_hba * phba,
mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
mb->un.varInitLnk.link_speed = LINK_SPEED_32G;
break;
+ case LPFC_USER_LINK_SPEED_64G:
+ mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+ mb->un.varInitLnk.link_speed = LINK_SPEED_64G;
+ break;
case LPFC_USER_LINK_SPEED_AUTO:
default:
mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
@@ -2170,10 +2174,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
/* Only FC supports upd bit */
if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
(vport->fc_flag & FC_VFI_REGISTERED) &&
- (!phba->fc_topology_changed)) {
- bf_set(lpfc_reg_vfi_vp, reg_vfi, 0);
+ (!phba->fc_topology_changed))
bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
- }
bf_set(lpfc_reg_vfi_bbcr, reg_vfi, 0);
bf_set(lpfc_reg_vfi_bbscn, reg_vfi, 0);
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 87c08ff37ddd..41361662ff08 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) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2014 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -753,12 +753,16 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
if (rc < 0) {
+ (rqbp->rqb_free_buffer)(phba, rqb_entry);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "6409 Cannot post to RQ %d: %x %x\n",
+ "6409 Cannot post to HRQ %d: %x %x %x "
+ "DRQ %x %x\n",
rqb_entry->hrq->queue_id,
rqb_entry->hrq->host_index,
- rqb_entry->hrq->hba_index);
- (rqbp->rqb_free_buffer)(phba, rqb_entry);
+ rqb_entry->hrq->hba_index,
+ rqb_entry->hrq->entry_count,
+ rqb_entry->drq->host_index,
+ rqb_entry->drq->hba_index);
} else {
list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
rqbp->buffer_count++;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index d841aa42f607..022060636ae1 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,7 +1,7 @@
- /*******************************************************************
+/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1998,8 +1998,14 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_type |= NLP_NVME_TARGET;
if (bf_get_be32(prli_disc, nvpr))
ndlp->nlp_type |= NLP_NVME_DISCOVERY;
+
+ /*
+ * If prli_fba is set, the Target supports FirstBurst.
+ * If prli_fb_sz is 0, the FirstBurst size is unlimited,
+ * otherwise it defines the actual size supported by
+ * the NVME Target.
+ */
if ((bf_get_be32(prli_fba, nvpr) == 1) &&
- (bf_get_be32(prli_fb_sz, nvpr) > 0) &&
(phba->cfg_nvme_enable_fb) &&
(!phba->nvmet_support)) {
/* Both sides support FB. The target's first
@@ -2008,12 +2014,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_flag |= NLP_FIRSTBURST;
ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz,
nvpr);
+
+ /* Expressed in units of 512 bytes */
+ if (ndlp->nvme_fb_size)
+ ndlp->nvme_fb_size <<=
+ LPFC_NVME_FB_SHIFT;
+ else
+ ndlp->nvme_fb_size = LPFC_NVME_MAX_FB;
}
}
- if (bf_get_be32(prli_recov, nvpr))
- ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
-
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
"6029 NVME PRLI Cmpl w1 x%08x "
"w4 x%08x w5 x%08x flag x%x, "
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 81e3a4f10c3c..378dca40ca20 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -65,6 +65,136 @@ lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_nvme_buf *);
static struct nvme_fc_port_template lpfc_nvme_template;
+static union lpfc_wqe128 lpfc_iread_cmd_template;
+static union lpfc_wqe128 lpfc_iwrite_cmd_template;
+static union lpfc_wqe128 lpfc_icmnd_cmd_template;
+
+/* Setup WQE templates for NVME IOs */
+void
+lpfc_nvme_cmd_template(void)
+{
+ union lpfc_wqe128 *wqe;
+
+ /* IREAD template */
+ wqe = &lpfc_iread_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 - cmd_buff_len, payload_offset_len is zero */
+
+ /* Word 4 - total_xfer_len is variable */
+
+ /* Word 5 - is zero */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 */
+ bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK);
+ bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI);
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag is variable */
+
+ /* Word 10 - dbde, wqes is variable */
+ bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0);
+ bf_set(wqe_nvme, &wqe->fcp_iread.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
+ bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4);
+ bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0);
+ bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1);
+
+ /* Word 11 - pbde is variable */
+ bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, NVME_READ_CMD);
+ bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1);
+
+ /* Word 12 - is zero */
+
+ /* Word 13, 14, 15 - PBDE is variable */
+
+ /* IWRITE template */
+ wqe = &lpfc_iwrite_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 - cmd_buff_len, payload_offset_len is zero */
+
+ /* Word 4 - total_xfer_len is variable */
+
+ /* Word 5 - initial_xfer_len is variable */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 */
+ bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK);
+ bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI);
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag is variable */
+
+ /* Word 10 - dbde, wqes is variable */
+ bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0);
+ bf_set(wqe_nvme, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4);
+ bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
+ bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
+
+ /* Word 11 - pbde is variable */
+ bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, NVME_WRITE_CMD);
+ bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1);
+
+ /* Word 12 - is zero */
+
+ /* Word 13, 14, 15 - PBDE is variable */
+
+ /* ICMND template */
+ wqe = &lpfc_icmnd_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 - payload_offset_len is variable */
+
+ /* Word 4, 5 - is zero */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 */
+ bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0);
+ bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI);
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag is variable */
+
+ /* Word 10 - dbde, wqes is variable */
+ bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE);
+ bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE);
+ bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0);
+ bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
+
+ /* Word 11 */
+ bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, FCP_COMMAND);
+ bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0);
+
+ /* Word 12, 13, 14, 15 - is zero */
+}
+
/**
* lpfc_nvme_create_queue -
* @lpfc_pnvme: Pointer to the driver's nvme instance data
@@ -241,10 +371,11 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
ndlp = (struct lpfc_nodelist *)cmdwqe->context1;
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
"6047 nvme cmpl Enter "
- "Data %p DID %x Xri: %x status %x cmd:%p lsreg:%p "
- "bmp:%p ndlp:%p\n",
+ "Data %p DID %x Xri: %x status %x reason x%x cmd:%p "
+ "lsreg:%p bmp:%p ndlp:%p\n",
pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
cmdwqe->sli4_xritag, status,
+ (wcqe->parameter & 0xffff),
cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp);
lpfc_nvmeio_data(phba, "NVME LS CMPL: xri x%x stat x%x parm x%x\n",
@@ -274,14 +405,14 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
static int
lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp,
- struct nvmefc_ls_req *pnvme_lsreq,
- void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
- struct lpfc_wcqe_complete *),
- struct lpfc_nodelist *ndlp, uint32_t num_entry,
- uint32_t tmo, uint8_t retry)
+ struct nvmefc_ls_req *pnvme_lsreq,
+ void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_wcqe_complete *),
+ struct lpfc_nodelist *ndlp, uint32_t num_entry,
+ uint32_t tmo, uint8_t retry)
{
- struct lpfc_hba *phba = vport->phba;
- union lpfc_wqe *wqe;
+ struct lpfc_hba *phba = vport->phba;
+ union lpfc_wqe128 *wqe;
struct lpfc_iocbq *genwqe;
struct ulp_bde64 *bpl;
struct ulp_bde64 bde;
@@ -419,6 +550,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
{
int ret = 0;
struct lpfc_nvme_lport *lport;
+ struct lpfc_nvme_rport *rport;
struct lpfc_vport *vport;
struct lpfc_nodelist *ndlp;
struct ulp_bde64 *bpl;
@@ -437,19 +569,18 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
*/
lport = (struct lpfc_nvme_lport *)pnvme_lport->private;
+ rport = (struct lpfc_nvme_rport *)pnvme_rport->private;
vport = lport->vport;
if (vport->load_flag & FC_UNLOADING)
return -ENODEV;
- if (vport->load_flag & FC_UNLOADING)
- return -ENODEV;
-
- ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id);
+ /* Need the ndlp. It is stored in the driver's rport. */
+ ndlp = rport->ndlp;
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR,
- "6051 DID x%06x not an active rport.\n",
- pnvme_rport->port_id);
+ "6051 Remoteport %p, rport has invalid ndlp. "
+ "Failing LS Req\n", pnvme_rport);
return -ENODEV;
}
@@ -500,8 +631,9 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
/* Expand print to include key fields. */
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
- "6149 ENTER. lport %p, rport %p lsreq%p rqstlen:%d "
- "rsplen:%d %pad %pad\n",
+ "6149 Issue LS Req to DID 0x%06x lport %p, rport %p "
+ "lsreq%p rqstlen:%d rsplen:%d %pad %pad\n",
+ ndlp->nlp_DID,
pnvme_lport, pnvme_rport,
pnvme_lsreq, pnvme_lsreq->rqstlen,
pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma,
@@ -517,7 +649,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
ndlp, 2, 30, 0);
if (ret != WQE_SUCCESS) {
atomic_inc(&lport->xmt_ls_err);
- lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
"6052 EXIT. issue ls wqe failed lport %p, "
"rport %p lsreq%p Status %x DID %x\n",
pnvme_lport, pnvme_rport, pnvme_lsreq,
@@ -610,16 +742,25 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport,
}
/* Fix up the existing sgls for NVME IO. */
-static void
+static inline void
lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
struct lpfc_nvme_buf *lpfc_ncmd,
struct nvmefc_fcp_req *nCmd)
{
+ struct lpfc_hba *phba = vport->phba;
struct sli4_sge *sgl;
union lpfc_wqe128 *wqe;
uint32_t *wptr, *dptr;
/*
+ * Get a local pointer to the built-in wqe and correct
+ * the cmd size to match NVME's 96 bytes and fix
+ * the dma address.
+ */
+
+ wqe = &lpfc_ncmd->cur_iocbq.wqe;
+
+ /*
* Adjust the FCP_CMD and FCP_RSP DMA data and sge_len to
* match NVME. NVME sends 96 bytes. Also, use the
* nvme commands command and response dma addresses
@@ -628,6 +769,60 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
*/
sgl = lpfc_ncmd->nvme_sgl;
sgl->sge_len = cpu_to_le32(nCmd->cmdlen);
+ if (phba->cfg_nvme_embed_cmd) {
+ sgl->addr_hi = 0;
+ sgl->addr_lo = 0;
+
+ /* Word 0-2 - NVME CMND IU (embedded payload) */
+ wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
+ wqe->generic.bde.tus.f.bdeSize = 56;
+ wqe->generic.bde.addrHigh = 0;
+ wqe->generic.bde.addrLow = 64; /* Word 16 */
+
+ /* Word 10 - dbde is 0, wqes is 1 in template */
+
+ /*
+ * Embed the payload in the last half of the WQE
+ * WQE words 16-30 get the NVME CMD IU payload
+ *
+ * WQE words 16-19 get payload Words 1-4
+ * WQE words 20-21 get payload Words 6-7
+ * WQE words 22-29 get payload Words 16-23
+ */
+ wptr = &wqe->words[16]; /* WQE ptr */
+ dptr = (uint32_t *)nCmd->cmdaddr; /* payload ptr */
+ dptr++; /* Skip Word 0 in payload */
+
+ *wptr++ = *dptr++; /* Word 1 */
+ *wptr++ = *dptr++; /* Word 2 */
+ *wptr++ = *dptr++; /* Word 3 */
+ *wptr++ = *dptr++; /* Word 4 */
+ dptr++; /* Skip Word 5 in payload */
+ *wptr++ = *dptr++; /* Word 6 */
+ *wptr++ = *dptr++; /* Word 7 */
+ dptr += 8; /* Skip Words 8-15 in payload */
+ *wptr++ = *dptr++; /* Word 16 */
+ *wptr++ = *dptr++; /* Word 17 */
+ *wptr++ = *dptr++; /* Word 18 */
+ *wptr++ = *dptr++; /* Word 19 */
+ *wptr++ = *dptr++; /* Word 20 */
+ *wptr++ = *dptr++; /* Word 21 */
+ *wptr++ = *dptr++; /* Word 22 */
+ *wptr = *dptr; /* Word 23 */
+ } else {
+ sgl->addr_hi = cpu_to_le32(putPaddrHigh(nCmd->cmddma));
+ sgl->addr_lo = cpu_to_le32(putPaddrLow(nCmd->cmddma));
+
+ /* Word 0-2 - NVME CMND IU Inline BDE */
+ wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ wqe->generic.bde.tus.f.bdeSize = nCmd->cmdlen;
+ wqe->generic.bde.addrHigh = sgl->addr_hi;
+ wqe->generic.bde.addrLow = sgl->addr_lo;
+
+ /* Word 10 */
+ bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->generic.wqe_com, 0);
+ }
sgl++;
@@ -641,58 +836,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
bf_set(lpfc_sli4_sge_last, sgl, 1);
sgl->word2 = cpu_to_le32(sgl->word2);
sgl->sge_len = cpu_to_le32(nCmd->rsplen);
-
- /*
- * Get a local pointer to the built-in wqe and correct
- * the cmd size to match NVME's 96 bytes and fix
- * the dma address.
- */
-
- /* 128 byte wqe support here */
- wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
-
- /* Word 0-2 - NVME CMND IU (embedded payload) */
- wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
- wqe->generic.bde.tus.f.bdeSize = 60;
- wqe->generic.bde.addrHigh = 0;
- wqe->generic.bde.addrLow = 64; /* Word 16 */
-
- /* Word 3 */
- bf_set(payload_offset_len, &wqe->fcp_icmd,
- (nCmd->rsplen + nCmd->cmdlen));
-
- /* Word 10 */
- bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1);
- bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
-
- /*
- * Embed the payload in the last half of the WQE
- * WQE words 16-30 get the NVME CMD IU payload
- *
- * WQE words 16-19 get payload Words 1-4
- * WQE words 20-21 get payload Words 6-7
- * WQE words 22-29 get payload Words 16-23
- */
- wptr = &wqe->words[16]; /* WQE ptr */
- dptr = (uint32_t *)nCmd->cmdaddr; /* payload ptr */
- dptr++; /* Skip Word 0 in payload */
-
- *wptr++ = *dptr++; /* Word 1 */
- *wptr++ = *dptr++; /* Word 2 */
- *wptr++ = *dptr++; /* Word 3 */
- *wptr++ = *dptr++; /* Word 4 */
- dptr++; /* Skip Word 5 in payload */
- *wptr++ = *dptr++; /* Word 6 */
- *wptr++ = *dptr++; /* Word 7 */
- dptr += 8; /* Skip Words 8-15 in payload */
- *wptr++ = *dptr++; /* Word 16 */
- *wptr++ = *dptr++; /* Word 17 */
- *wptr++ = *dptr++; /* Word 18 */
- *wptr++ = *dptr++; /* Word 19 */
- *wptr++ = *dptr++; /* Word 20 */
- *wptr++ = *dptr++; /* Word 21 */
- *wptr++ = *dptr++; /* Word 22 */
- *wptr = *dptr; /* Word 23 */
}
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
@@ -980,14 +1123,14 @@ out_err:
phba->cpucheck_cmpl_io[lpfc_ncmd->cpu]++;
}
#endif
- freqpriv = nCmd->private;
- freqpriv->nvme_buf = NULL;
/* NVME targets need completion held off until the abort exchange
* completes unless the NVME Rport is getting unregistered.
*/
if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) {
+ freqpriv = nCmd->private;
+ freqpriv->nvme_buf = NULL;
nCmd->done(nCmd);
lpfc_ncmd->nvmeCmd = NULL;
}
@@ -1025,7 +1168,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
struct lpfc_hba *phba = vport->phba;
struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq);
- union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&pwqeq->wqe;
+ union lpfc_wqe128 *wqe = &pwqeq->wqe;
uint32_t req_len;
if (!pnode || !NLP_CHK_NODE_ACT(pnode))
@@ -1035,9 +1178,16 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
* There are three possibilities here - use scatter-gather segment, use
* the single mapping, or neither.
*/
- wqe->fcp_iwrite.initial_xfer_len = 0;
if (nCmd->sg_cnt) {
if (nCmd->io_dir == NVMEFC_FCP_WRITE) {
+ /* From the iwrite template, initialize words 7 - 11 */
+ memcpy(&wqe->words[7],
+ &lpfc_iwrite_cmd_template.words[7],
+ sizeof(uint32_t) * 5);
+
+ /* Word 4 */
+ wqe->fcp_iwrite.total_xfer_len = nCmd->payload_length;
+
/* Word 5 */
if ((phba->cfg_nvme_enable_fb) &&
(pnode->nlp_flag & NLP_FIRSTBURST)) {
@@ -1048,69 +1198,28 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
else
wqe->fcp_iwrite.initial_xfer_len =
pnode->nvme_fb_size;
+ } else {
+ wqe->fcp_iwrite.initial_xfer_len = 0;
}
-
- /* Word 7 */
- bf_set(wqe_cmnd, &wqe->generic.wqe_com,
- CMD_FCP_IWRITE64_WQE);
- bf_set(wqe_pu, &wqe->generic.wqe_com,
- PARM_READ_CHECK);
-
- /* Word 10 */
- bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0);
- bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com,
- LPFC_WQE_IOD_WRITE);
- bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
- LPFC_WQE_LENLOC_WORD4);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1);
-
- /* Word 11 */
- bf_set(wqe_cmd_type, &wqe->generic.wqe_com,
- NVME_WRITE_CMD);
-
atomic_inc(&phba->fc4NvmeOutputRequests);
} else {
- /* Word 7 */
- bf_set(wqe_cmnd, &wqe->generic.wqe_com,
- CMD_FCP_IREAD64_WQE);
- bf_set(wqe_pu, &wqe->generic.wqe_com,
- PARM_READ_CHECK);
-
- /* Word 10 */
- bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0);
- bf_set(wqe_iod, &wqe->fcp_iread.wqe_com,
- LPFC_WQE_IOD_READ);
- bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
- LPFC_WQE_LENLOC_WORD4);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1);
-
- /* Word 11 */
- bf_set(wqe_cmd_type, &wqe->generic.wqe_com,
- NVME_READ_CMD);
+ /* From the iread template, initialize words 7 - 11 */
+ memcpy(&wqe->words[7],
+ &lpfc_iread_cmd_template.words[7],
+ sizeof(uint32_t) * 5);
+
+ /* Word 4 */
+ wqe->fcp_iread.total_xfer_len = nCmd->payload_length;
+
+ /* Word 5 */
+ wqe->fcp_iread.rsrvd5 = 0;
atomic_inc(&phba->fc4NvmeInputRequests);
}
} else {
- /* Word 4 */
- wqe->fcp_icmd.rsrvd4 = 0;
-
- /* Word 7 */
- bf_set(wqe_cmnd, &wqe->generic.wqe_com, CMD_FCP_ICMND64_WQE);
- bf_set(wqe_pu, &wqe->generic.wqe_com, 0);
-
- /* Word 10 */
- bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
- bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE);
- bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
- LPFC_WQE_LENLOC_NONE);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1);
-
- /* Word 11 */
- bf_set(wqe_cmd_type, &wqe->generic.wqe_com, NVME_READ_CMD);
-
+ /* From the icmnd template, initialize words 4 - 11 */
+ memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4],
+ sizeof(uint32_t) * 8);
atomic_inc(&phba->fc4NvmeControlRequests);
}
/*
@@ -1118,25 +1227,21 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
* of the nvme_cmnd request_buffer
*/
+ /* Word 3 */
+ bf_set(payload_offset_len, &wqe->fcp_icmd,
+ (nCmd->rsplen + nCmd->cmdlen));
+
/* Word 6 */
bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com,
phba->sli4_hba.rpi_ids[pnode->nlp_rpi]);
bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag);
- /* Word 7 */
- /* Preserve Class data in the ndlp. */
- bf_set(wqe_class, &wqe->generic.wqe_com,
- (pnode->nlp_fcp_info & 0x0f));
-
/* Word 8 */
wqe->generic.wqe_com.abort_tag = pwqeq->iotag;
/* Word 9 */
bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag);
- /* Word 11 */
- bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
-
pwqeq->vport = vport;
return 0;
}
@@ -1164,10 +1269,11 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
{
struct lpfc_hba *phba = vport->phba;
struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
- union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
+ union lpfc_wqe128 *wqe = &lpfc_ncmd->cur_iocbq.wqe;
struct sli4_sge *sgl = lpfc_ncmd->nvme_sgl;
struct scatterlist *data_sg;
struct sli4_sge *first_data_sgl;
+ struct ulp_bde64 *bde;
dma_addr_t physaddr;
uint32_t num_bde = 0;
uint32_t dma_len;
@@ -1235,7 +1341,26 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
data_sg = sg_next(data_sg);
sgl++;
}
+ if (phba->nvme_embed_pbde) {
+ /* Use PBDE support for first SGL only, offset == 0 */
+ /* Words 13-15 */
+ bde = (struct ulp_bde64 *)
+ &wqe->words[13];
+ bde->addrLow = first_data_sgl->addr_lo;
+ bde->addrHigh = first_data_sgl->addr_hi;
+ bde->tus.f.bdeSize =
+ le32_to_cpu(first_data_sgl->sge_len);
+ bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bde->tus.w = cpu_to_le32(bde->tus.w);
+ /* wqe_pbde is 1 in template */
+ } else {
+ memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3));
+ bf_set(wqe_pbde, &wqe->generic.wqe_com, 0);
+ }
} else {
+ bf_set(wqe_pbde, &wqe->generic.wqe_com, 0);
+ memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3));
+
/* For this clause to be valid, the payload_length
* and sg_cnt must zero.
*/
@@ -1247,12 +1372,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
return 1;
}
}
-
- /*
- * Due to difference in data length between DIF/non-DIF paths,
- * we need to set word 4 of WQE here
- */
- wqe->fcp_iread.total_xfer_len = nCmd->payload_length;
return 0;
}
@@ -1554,7 +1673,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
struct lpfc_iocbq *abts_buf;
struct lpfc_iocbq *nvmereq_wqe;
struct lpfc_nvme_fcpreq_priv *freqpriv;
- union lpfc_wqe *abts_wqe;
+ union lpfc_wqe128 *abts_wqe;
unsigned long flags;
int ret_val;
@@ -2098,7 +2217,7 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc)
break;
}
pwqeq = &(lpfc_ncmd->cur_iocbq);
- wqe = (union lpfc_wqe128 *)&pwqeq->wqe;
+ wqe = &pwqeq->wqe;
/* Allocate iotag for lpfc_ncmd->cur_iocbq. */
iotag = lpfc_sli_next_iotag(phba, pwqeq);
@@ -2135,14 +2254,8 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc)
lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd;
- /* Word 7 */
- bf_set(wqe_erp, &wqe->generic.wqe_com, 0);
- /* NVME upper layers will time things out, if needed */
- bf_set(wqe_tmo, &wqe->generic.wqe_com, 0);
-
- /* Word 10 */
- bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0);
- bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
+ /* Initialize WQE */
+ memset(wqe, 0, sizeof(union lpfc_wqe));
/* add the nvme buffer to a post list */
list_add_tail(&lpfc_ncmd->list, &post_nblist);
diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h
index e79f8f75758c..9216653e0441 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.h
+++ b/drivers/scsi/lpfc/lpfc_nvme.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -27,6 +27,8 @@
#define LPFC_NVME_WAIT_TMO 10
#define LPFC_NVME_EXPEDITE_XRICNT 8
+#define LPFC_NVME_FB_SHIFT 9
+#define LPFC_NVME_MAX_FB (1 << 20) /* 1M */
struct lpfc_nvme_qhandle {
uint32_t index; /* WQ index to use */
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index 8dbf5c9d51aa..7271c9d885dd 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channsel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fs.h>
-#include <../drivers/nvme/host/nvme.h>
+#include <linux/nvme.h>
#include <linux/nvme-fc-driver.h>
#include <linux/nvme-fc.h>
@@ -71,6 +71,151 @@ static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *,
static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *,
struct lpfc_nvmet_rcv_ctx *,
uint32_t, uint16_t);
+static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *,
+ struct lpfc_nvmet_rcv_ctx *);
+
+static union lpfc_wqe128 lpfc_tsend_cmd_template;
+static union lpfc_wqe128 lpfc_treceive_cmd_template;
+static union lpfc_wqe128 lpfc_trsp_cmd_template;
+
+/* Setup WQE templates for NVME IOs */
+void
+lpfc_nvmet_cmd_template(void)
+{
+ union lpfc_wqe128 *wqe;
+
+ /* TSEND template */
+ wqe = &lpfc_tsend_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 - payload_offset_len is zero */
+
+ /* Word 4 - relative_offset is variable */
+
+ /* Word 5 - is zero */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 - wqe_ar is variable */
+ bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, PARM_REL_OFF);
+ bf_set(wqe_class, &wqe->fcp_tsend.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_tsend.wqe_com, SLI4_CT_RPI);
+ bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1);
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag, rcvoxid is variable */
+
+ /* Word 10 - wqes, xc is variable */
+ bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
+ bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
+ bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE);
+ bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com, LPFC_WQE_LENLOC_WORD12);
+
+ /* Word 11 - sup, irsp, irsplen is variable */
+ bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com, FCP_COMMAND_TSEND);
+ bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
+ bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
+ bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
+ bf_set(wqe_pbde, &wqe->fcp_tsend.wqe_com, 0);
+
+ /* Word 12 - fcp_data_len is variable */
+
+ /* Word 13, 14, 15 - PBDE is zero */
+
+ /* TRECEIVE template */
+ wqe = &lpfc_treceive_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 */
+ wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN;
+
+ /* Word 4 - relative_offset is variable */
+
+ /* Word 5 - is zero */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 */
+ bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com, CMD_FCP_TRECEIVE64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, PARM_REL_OFF);
+ bf_set(wqe_class, &wqe->fcp_treceive.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_treceive.wqe_com, SLI4_CT_RPI);
+ bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0);
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag, rcvoxid is variable */
+
+ /* Word 10 - xc is variable */
+ bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0);
+ bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
+ bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ);
+ bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12);
+ bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1);
+
+ /* Word 11 - pbde is variable */
+ bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com, FCP_COMMAND_TRECEIVE);
+ bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_sup, &wqe->fcp_treceive.wqe_com, 0);
+ bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0);
+ bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0);
+ bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 1);
+
+ /* Word 12 - fcp_data_len is variable */
+
+ /* Word 13, 14, 15 - PBDE is variable */
+
+ /* TRSP template */
+ wqe = &lpfc_trsp_cmd_template;
+ memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+ /* Word 0, 1, 2 - BDE is variable */
+
+ /* Word 3 - response_len is variable */
+
+ /* Word 4, 5 - is zero */
+
+ /* Word 6 - ctxt_tag, xri_tag is variable */
+
+ /* Word 7 */
+ bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE);
+ bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, PARM_UNUSED);
+ bf_set(wqe_class, &wqe->fcp_trsp.wqe_com, CLASS3);
+ bf_set(wqe_ct, &wqe->fcp_trsp.wqe_com, SLI4_CT_RPI);
+ bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1); /* wqe_ar */
+
+ /* Word 8 - abort_tag is variable */
+
+ /* Word 9 - reqtag is variable */
+
+ /* Word 10 wqes, xc is variable */
+ bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 1);
+ bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0);
+ bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 0);
+ bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_NONE);
+ bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com, LPFC_WQE_LENLOC_WORD3);
+
+ /* Word 11 irsp, irsplen is variable */
+ bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com, FCP_COMMAND_TRSP);
+ bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+ bf_set(wqe_sup, &wqe->fcp_trsp.wqe_com, 0);
+ bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0);
+ bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0);
+ bf_set(wqe_pbde, &wqe->fcp_trsp.wqe_com, 0);
+
+ /* Word 12, 13, 14, 15 - is zero */
+}
void
lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
@@ -130,7 +275,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
if (tgtp) {
if (status) {
atomic_inc(&tgtp->xmt_ls_rsp_error);
- if (status == IOERR_ABORT_REQUESTED)
+ if (result == IOERR_ABORT_REQUESTED)
atomic_inc(&tgtp->xmt_ls_rsp_aborted);
if (bf_get(lpfc_wcqe_c_xb, wcqe))
atomic_inc(&tgtp->xmt_ls_rsp_xb_set);
@@ -268,8 +413,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
"NVMET RCV BUSY: xri x%x sz %d "
"from %06x\n",
oxid, size, sid);
- /* defer repost rcv buffer till .defer_rcv callback */
- ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
atomic_inc(&tgtp->rcv_fcp_cmd_out);
return;
}
@@ -541,7 +684,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
rsp->transferred_length = 0;
if (tgtp) {
atomic_inc(&tgtp->xmt_fcp_rsp_error);
- if (status == IOERR_ABORT_REQUESTED)
+ if (result == IOERR_ABORT_REQUESTED)
atomic_inc(&tgtp->xmt_fcp_rsp_aborted);
}
@@ -741,7 +884,10 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
struct lpfc_nvmet_rcv_ctx *ctxp =
container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
struct lpfc_hba *phba = ctxp->phba;
+ struct lpfc_queue *wq;
struct lpfc_iocbq *nvmewqeq;
+ struct lpfc_sli_ring *pring;
+ unsigned long iflags;
int rc;
if (phba->pport->load_flag & FC_UNLOADING) {
@@ -820,6 +966,22 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
return 0;
}
+ if (rc == -EBUSY) {
+ /*
+ * WQ was full, so queue nvmewqeq to be sent after
+ * WQE release CQE
+ */
+ ctxp->flag |= LPFC_NVMET_DEFER_WQFULL;
+ wq = phba->sli4_hba.nvme_wq[rsp->hwqid];
+ pring = wq->pring;
+ spin_lock_irqsave(&pring->ring_lock, iflags);
+ list_add_tail(&nvmewqeq->list, &wq->wqfull_list);
+ wq->q_flag |= HBA_NVMET_WQFULL;
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+ atomic_inc(&lpfc_nvmep->defer_wqfull);
+ return 0;
+ }
+
/* Give back resources */
atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
@@ -851,6 +1013,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
struct lpfc_nvmet_rcv_ctx *ctxp =
container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
struct lpfc_hba *phba = ctxp->phba;
+ struct lpfc_queue *wq;
unsigned long flags;
if (phba->pport->load_flag & FC_UNLOADING)
@@ -880,6 +1043,15 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
}
ctxp->flag |= LPFC_NVMET_ABORT_OP;
+ if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) {
+ lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+ ctxp->oxid);
+ wq = phba->sli4_hba.nvme_wq[ctxp->wqeq->hba_wqidx];
+ spin_unlock_irqrestore(&ctxp->ctxlock, flags);
+ lpfc_nvmet_wqfull_flush(phba, wq, ctxp);
+ return;
+ }
+
/* An state of LPFC_NVMET_STE_RCV means we have just received
* the NVME command and have not started processing it.
* (by issuing any IO WQEs on this exchange yet)
@@ -946,11 +1118,9 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
tgtp = phba->targetport->private;
atomic_inc(&tgtp->rcv_fcp_cmd_defer);
- if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST)
- lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
- else
- nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
- ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
+
+ /* Free the nvmebuf since a new buffer already replaced it */
+ nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
}
static struct nvmet_fc_target_template lpfc_tgttemplate = {
@@ -1124,16 +1294,10 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba)
}
ctx_buf->iocbq->iocb_flag = LPFC_IO_NVMET;
nvmewqe = ctx_buf->iocbq;
- wqe = (union lpfc_wqe128 *)&nvmewqe->wqe;
+ wqe = &nvmewqe->wqe;
+
/* Initialize WQE */
memset(wqe, 0, sizeof(union lpfc_wqe));
- /* Word 7 */
- bf_set(wqe_ct, &wqe->generic.wqe_com, SLI4_CT_RPI);
- bf_set(wqe_class, &wqe->generic.wqe_com, CLASS3);
- /* Word 10 */
- bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
- bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0);
- bf_set(wqe_qosd, &wqe->generic.wqe_com, 0);
ctx_buf->iocbq->context1 = NULL;
spin_lock(&phba->sli4_hba.sgl_list_lock);
@@ -1280,6 +1444,9 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
atomic_set(&tgtp->xmt_abort_sol, 0);
atomic_set(&tgtp->xmt_abort_rsp, 0);
atomic_set(&tgtp->xmt_abort_rsp_error, 0);
+ atomic_set(&tgtp->defer_ctx, 0);
+ atomic_set(&tgtp->defer_fod, 0);
+ atomic_set(&tgtp->defer_wqfull, 0);
}
return error;
}
@@ -1435,16 +1602,103 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
return 0;
}
+static void
+lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq,
+ struct lpfc_nvmet_rcv_ctx *ctxp)
+{
+ struct lpfc_sli_ring *pring;
+ struct lpfc_iocbq *nvmewqeq;
+ struct lpfc_iocbq *next_nvmewqeq;
+ unsigned long iflags;
+ struct lpfc_wcqe_complete wcqe;
+ struct lpfc_wcqe_complete *wcqep;
+
+ pring = wq->pring;
+ wcqep = &wcqe;
+
+ /* Fake an ABORT error code back to cmpl routine */
+ memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete));
+ bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT);
+ wcqep->parameter = IOERR_ABORT_REQUESTED;
+
+ spin_lock_irqsave(&pring->ring_lock, iflags);
+ list_for_each_entry_safe(nvmewqeq, next_nvmewqeq,
+ &wq->wqfull_list, list) {
+ if (ctxp) {
+ /* Checking for a specific IO to flush */
+ if (nvmewqeq->context2 == ctxp) {
+ list_del(&nvmewqeq->list);
+ spin_unlock_irqrestore(&pring->ring_lock,
+ iflags);
+ lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq,
+ wcqep);
+ return;
+ }
+ continue;
+ } else {
+ /* Flush all IOs */
+ list_del(&nvmewqeq->list);
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+ lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep);
+ spin_lock_irqsave(&pring->ring_lock, iflags);
+ }
+ }
+ if (!ctxp)
+ wq->q_flag &= ~HBA_NVMET_WQFULL;
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+}
+
+void
+lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
+ struct lpfc_queue *wq)
+{
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+ struct lpfc_sli_ring *pring;
+ struct lpfc_iocbq *nvmewqeq;
+ unsigned long iflags;
+ int rc;
+
+ /*
+ * Some WQE slots are available, so try to re-issue anything
+ * on the WQ wqfull_list.
+ */
+ pring = wq->pring;
+ spin_lock_irqsave(&pring->ring_lock, iflags);
+ while (!list_empty(&wq->wqfull_list)) {
+ list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq,
+ list);
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+ rc = lpfc_sli4_issue_wqe(phba, LPFC_FCP_RING, nvmewqeq);
+ spin_lock_irqsave(&pring->ring_lock, iflags);
+ if (rc == -EBUSY) {
+ /* WQ was full again, so put it back on the list */
+ list_add(&nvmewqeq->list, &wq->wqfull_list);
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+ return;
+ }
+ }
+ wq->q_flag &= ~HBA_NVMET_WQFULL;
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+#endif
+}
+
void
lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
{
#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
struct lpfc_nvmet_tgtport *tgtp;
+ struct lpfc_queue *wq;
+ uint32_t qidx;
if (phba->nvmet_support == 0)
return;
if (phba->targetport) {
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+ for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) {
+ wq = phba->sli4_hba.nvme_wq[qidx];
+ lpfc_nvmet_wqfull_flush(phba, wq, NULL);
+ }
init_completion(&tgtp->tport_unreg_done);
nvmet_fc_unregister_targetport(phba->targetport);
wait_for_completion_timeout(&tgtp->tport_unreg_done, 5);
@@ -1694,6 +1948,8 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n",
oxid, size, smp_processor_id());
+ tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+
if (!ctx_buf) {
/* Queue this NVME IO to process later */
spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
@@ -1709,10 +1965,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
lpfc_post_rq_buffer(
phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
+
+ atomic_inc(&tgtp->defer_ctx);
return;
}
- tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
payload = (uint32_t *)(nvmebuf->dbuf.virt);
sid = sli4_sid_from_fc_hdr(fc_hdr);
@@ -1776,12 +2033,20 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
/* Processing of FCP command is deferred */
if (rc == -EOVERFLOW) {
+ /*
+ * Post a brand new DMA buffer to RQ and defer
+ * freeing rcv buffer till .defer_rcv callback
+ */
+ qno = nvmebuf->idx;
+ lpfc_post_rq_buffer(
+ phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
+ phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
+
lpfc_nvmeio_data(phba,
"NVMET RCV BUSY: xri x%x sz %d from %06x\n",
oxid, size, sid);
- /* defer reposting rcv buffer till .defer_rcv callback */
- ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST;
atomic_inc(&tgtp->rcv_fcp_cmd_out);
+ atomic_inc(&tgtp->defer_fod);
return;
}
ctxp->rqb_buffer = nvmebuf;
@@ -1897,7 +2162,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba,
{
struct lpfc_nodelist *ndlp;
struct lpfc_iocbq *nvmewqe;
- union lpfc_wqe *wqe;
+ union lpfc_wqe128 *wqe;
if (!lpfc_is_link_up(phba)) {
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC,
@@ -2023,9 +2288,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
struct lpfc_iocbq *nvmewqe;
struct scatterlist *sgel;
union lpfc_wqe128 *wqe;
+ struct ulp_bde64 *bde;
uint32_t *txrdy;
dma_addr_t physaddr;
int i, cnt;
+ int do_pbde;
int xc = 1;
if (!lpfc_is_link_up(phba)) {
@@ -2078,7 +2345,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
if (((ctxp->state == LPFC_NVMET_STE_RCV) &&
(ctxp->entry_cnt == 1)) ||
(ctxp->state == LPFC_NVMET_STE_DATA)) {
- wqe = (union lpfc_wqe128 *)&nvmewqe->wqe;
+ wqe = &nvmewqe->wqe;
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
"6111 Wrong state NVMET FCP: %d cnt %d\n",
@@ -2090,6 +2357,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
switch (rsp->op) {
case NVMET_FCOP_READDATA:
case NVMET_FCOP_READDATA_RSP:
+ /* From the tsend template, initialize words 7 - 11 */
+ memcpy(&wqe->words[7],
+ &lpfc_tsend_cmd_template.words[7],
+ sizeof(uint32_t) * 5);
+
/* Words 0 - 2 : The first sg segment */
sgel = &rsp->sg[0];
physaddr = sg_dma_address(sgel);
@@ -2106,6 +2378,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
wqe->fcp_tsend.relative_offset = ctxp->offset;
/* Word 5 */
+ wqe->fcp_tsend.reserved = 0;
/* Word 6 */
bf_set(wqe_ctxt_tag, &wqe->fcp_tsend.wqe_com,
@@ -2113,9 +2386,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
bf_set(wqe_xri_tag, &wqe->fcp_tsend.wqe_com,
nvmewqe->sli4_xritag);
- /* Word 7 */
- bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, 1);
- bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE);
+ /* Word 7 - set ar later */
/* Word 8 */
wqe->fcp_tsend.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2124,23 +2395,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
bf_set(wqe_reqtag, &wqe->fcp_tsend.wqe_com, nvmewqe->iotag);
bf_set(wqe_rcvoxid, &wqe->fcp_tsend.wqe_com, ctxp->oxid);
- /* Word 10 */
- bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
- bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1);
- bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE);
- bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com,
- LPFC_WQE_LENLOC_WORD12);
- bf_set(wqe_ebde_cnt, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, xc);
- bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_tsend.wqe_com, 1);
+ /* Word 10 - set wqes later, in template xc=1 */
+ if (!xc)
+ bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 0);
- /* Word 11 */
- bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com,
- LPFC_WQE_CQ_ID_DEFAULT);
- bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com,
- FCP_COMMAND_TSEND);
+ /* Word 11 - set sup, irsp, irsplen later */
+ do_pbde = 0;
/* Word 12 */
wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
@@ -2162,15 +2422,14 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
sgl++;
if (rsp->op == NVMET_FCOP_READDATA_RSP) {
atomic_inc(&tgtp->xmt_fcp_read_rsp);
- bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1);
- if ((ndlp->nlp_flag & NLP_SUPPRESS_RSP) &&
- (rsp->rsplen == 12)) {
- bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 1);
- bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
+
+ /* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */
+
+ if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) {
+ if (ndlp->nlp_flag & NLP_SUPPRESS_RSP)
+ bf_set(wqe_sup,
+ &wqe->fcp_tsend.wqe_com, 1);
} else {
- bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 1);
bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 1);
bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com,
@@ -2181,15 +2440,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
} else {
atomic_inc(&tgtp->xmt_fcp_read);
- bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
+ /* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */
bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 0);
- bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
}
break;
case NVMET_FCOP_WRITEDATA:
+ /* From the treceive template, initialize words 3 - 11 */
+ memcpy(&wqe->words[3],
+ &lpfc_treceive_cmd_template.words[3],
+ sizeof(uint32_t) * 9);
+
/* Words 0 - 2 : The first sg segment */
txrdy = dma_pool_alloc(phba->txrdy_payload_pool,
GFP_KERNEL, &physaddr);
@@ -2208,14 +2469,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
wqe->fcp_treceive.bde.addrHigh =
cpu_to_le32(putPaddrHigh(physaddr));
- /* Word 3 */
- wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN;
-
/* Word 4 */
wqe->fcp_treceive.relative_offset = ctxp->offset;
- /* Word 5 */
-
/* Word 6 */
bf_set(wqe_ctxt_tag, &wqe->fcp_treceive.wqe_com,
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
@@ -2223,10 +2479,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
nvmewqe->sli4_xritag);
/* Word 7 */
- bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, 1);
- bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0);
- bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com,
- CMD_FCP_TRECEIVE64_WQE);
/* Word 8 */
wqe->fcp_treceive.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2235,26 +2487,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
bf_set(wqe_reqtag, &wqe->fcp_treceive.wqe_com, nvmewqe->iotag);
bf_set(wqe_rcvoxid, &wqe->fcp_treceive.wqe_com, ctxp->oxid);
- /* Word 10 */
- bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
- bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1);
- bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ);
- bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com,
- LPFC_WQE_LENLOC_WORD12);
- bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, xc);
- bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0);
- bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0);
- bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0);
- bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_treceive.wqe_com, 1);
+ /* Word 10 - in template xc=1 */
+ if (!xc)
+ bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0);
- /* Word 11 */
- bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com,
- LPFC_WQE_CQ_ID_DEFAULT);
- bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com,
- FCP_COMMAND_TRECEIVE);
- bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
+ /* Word 11 - set pbde later */
+ if (phba->nvme_embed_pbde) {
+ do_pbde = 1;
+ } else {
+ bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0);
+ do_pbde = 0;
+ }
/* Word 12 */
wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
@@ -2282,6 +2525,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
break;
case NVMET_FCOP_RSP:
+ /* From the treceive template, initialize words 4 - 11 */
+ memcpy(&wqe->words[4],
+ &lpfc_trsp_cmd_template.words[4],
+ sizeof(uint32_t) * 8);
+
/* Words 0 - 2 */
physaddr = rsp->rspdma;
wqe->fcp_trsp.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
@@ -2294,12 +2542,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
/* Word 3 */
wqe->fcp_trsp.response_len = rsp->rsplen;
- /* Word 4 */
- wqe->fcp_trsp.rsvd_4_5[0] = 0;
-
-
- /* Word 5 */
-
/* Word 6 */
bf_set(wqe_ctxt_tag, &wqe->fcp_trsp.wqe_com,
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
@@ -2307,9 +2549,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
nvmewqe->sli4_xritag);
/* Word 7 */
- bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, 0);
- bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1);
- bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE);
/* Word 8 */
wqe->fcp_trsp.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2319,35 +2558,23 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
bf_set(wqe_rcvoxid, &wqe->fcp_trsp.wqe_com, ctxp->oxid);
/* Word 10 */
- bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
- bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 0);
- bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_WRITE);
- bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com,
- LPFC_WQE_LENLOC_WORD3);
- bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, xc);
- bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
- if (phba->cfg_nvme_oas)
- bf_set(wqe_oas, &wqe->fcp_trsp.wqe_com, 1);
+ if (xc)
+ bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 1);
/* Word 11 */
- bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com,
- LPFC_WQE_CQ_ID_DEFAULT);
- bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com,
- FCP_COMMAND_TRSP);
- bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
-
- if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) {
- /* Good response - all zero's on wire */
- bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0);
- bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0);
- bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0);
- } else {
+ /* In template wqes=0 irsp=0 irsplen=0 - good response */
+ if (rsp->rsplen != LPFC_NVMET_SUCCESS_LEN) {
+ /* Bad response - embed it */
bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 1);
bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 1);
bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com,
((rsp->rsplen >> 2) - 1));
memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen);
}
+ do_pbde = 0;
+
+ /* Word 12 */
+ wqe->fcp_trsp.rsvd_12_15[0] = 0;
/* Use rspbuf, NOT sg list */
rsp->sg_cnt = 0;
@@ -2380,6 +2607,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
bf_set(lpfc_sli4_sge_last, sgl, 1);
sgl->word2 = cpu_to_le32(sgl->word2);
sgl->sge_len = cpu_to_le32(cnt);
+ if (do_pbde && i == 0) {
+ bde = (struct ulp_bde64 *)&wqe->words[13];
+ memset(bde, 0, sizeof(struct ulp_bde64));
+ /* Words 13-15 (PBDE)*/
+ bde->addrLow = sgl->addr_lo;
+ bde->addrHigh = sgl->addr_hi;
+ bde->tus.f.bdeSize =
+ le32_to_cpu(sgl->sge_len);
+ bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bde->tus.w = cpu_to_le32(bde->tus.w);
+ }
sgl++;
ctxp->offset += cnt;
}
@@ -2597,7 +2835,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba,
{
struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_iocbq *abts_wqeq;
- union lpfc_wqe *wqe_abts;
+ union lpfc_wqe128 *wqe_abts;
struct lpfc_nodelist *ndlp;
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
@@ -2692,7 +2930,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
{
struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_iocbq *abts_wqeq;
- union lpfc_wqe *abts_wqe;
+ union lpfc_wqe128 *abts_wqe;
struct lpfc_nodelist *ndlp;
unsigned long flags;
int rc;
@@ -2882,7 +3120,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba,
{
struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_iocbq *abts_wqeq;
- union lpfc_wqe *wqe_abts;
+ union lpfc_wqe128 *wqe_abts;
unsigned long flags;
int rc;
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h
index 5b32c9e4d4ef..c1bcef3f103c 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.h
+++ b/drivers/scsi/lpfc/lpfc_nvmet.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -72,7 +72,6 @@ struct lpfc_nvmet_tgtport {
atomic_t xmt_fcp_rsp_aborted;
atomic_t xmt_fcp_rsp_drop;
-
/* Stats counters - lpfc_nvmet_xmt_fcp_abort */
atomic_t xmt_fcp_xri_abort_cqe;
atomic_t xmt_fcp_abort;
@@ -81,6 +80,11 @@ struct lpfc_nvmet_tgtport {
atomic_t xmt_abort_unsol;
atomic_t xmt_abort_rsp;
atomic_t xmt_abort_rsp_error;
+
+ /* Stats counters - defer IO */
+ atomic_t defer_ctx;
+ atomic_t defer_fod;
+ atomic_t defer_wqfull;
};
struct lpfc_nvmet_ctx_info {
@@ -131,7 +135,7 @@ struct lpfc_nvmet_rcv_ctx {
#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */
#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */
#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */
-#define LPFC_NVMET_DEFER_RCV_REPOST 0x20 /* repost to RQ on defer rcv */
+#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */
struct rqb_dmabuf *rqb_buffer;
struct lpfc_nvmet_ctxbuf *ctxbuf;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c0cdaef4db24..050f04418f5f 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -837,8 +837,13 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
* 4K Page alignment is CRITICAL to BlockGuard, double check
* to be sure.
*/
- if (phba->cfg_enable_bg && (((unsigned long)(psb->data) &
+ if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
+ (((unsigned long)(psb->data) &
(unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "3369 Memory alignment error "
+ "addr=%lx\n",
+ (unsigned long)psb->data);
dma_pool_free(phba->lpfc_sg_dma_buf_pool,
psb->data, psb->dma_handle);
kfree(psb);
@@ -3304,8 +3309,12 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
dma_offset += dma_len;
sgl++;
}
- /* setup the performance hint (first data BDE) if enabled */
- if (phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) {
+ /*
+ * Setup the first Payload BDE. For FCoE we just key off
+ * Performance Hints, for FC we utilize fcp_embed_pbde.
+ */
+ if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) ||
+ phba->fcp_embed_pbde) {
bde = (struct ulp_bde64 *)
&(iocb_cmd->unsli3.sli3Words[5]);
bde->addrLow = first_data_sgl->addr_lo;
@@ -3772,20 +3781,18 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
- "9025 FCP Read Underrun, expected %d, "
+ "9025 FCP Underrun, expected %d, "
"residual %d Data: x%x x%x x%x\n",
fcpDl,
scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
cmnd->underflow);
/*
- * If there is an under run check if under run reported by
+ * If there is an under run, check if under run reported by
* storage array is same as the under run reported by HBA.
* If this is not same, there is a dropped frame.
*/
- if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
- fcpi_parm &&
- (scsi_get_resid(cmnd) != fcpi_parm)) {
+ if (fcpi_parm && (scsi_get_resid(cmnd) != fcpi_parm)) {
lpfc_printf_vlog(vport, KERN_WARNING,
LOG_FCP | LOG_FCP_ERROR,
"9026 FCP Read Check Error "
@@ -3926,7 +3933,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd;
- int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
struct Scsi_Host *shost;
@@ -4132,16 +4138,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
spin_unlock_irqrestore(shost->host_lock, flags);
} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
- if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
- time_after(jiffies, pnode->last_change_time +
+ if ((pnode->cmd_qdepth != vport->cfg_tgt_queue_depth) &&
+ time_after(jiffies, pnode->last_change_time +
msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
spin_lock_irqsave(shost->host_lock, flags);
- depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
- / 100;
- depth = depth ? depth : 1;
- pnode->cmd_qdepth += depth;
- if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
- pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
+ pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
pnode->last_change_time = jiffies;
spin_unlock_irqrestore(shost->host_lock, flags);
}
@@ -4564,9 +4565,32 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
*/
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
goto out_tgt_busy;
- if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
+ if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR,
+ "3377 Target Queue Full, scsi Id:%d Qdepth:%d"
+ " Pending command:%d"
+ " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
+ " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ ndlp->nlp_sid, ndlp->cmd_qdepth,
+ atomic_read(&ndlp->cmd_pending),
+ ndlp->nlp_nodename.u.wwn[0],
+ ndlp->nlp_nodename.u.wwn[1],
+ ndlp->nlp_nodename.u.wwn[2],
+ ndlp->nlp_nodename.u.wwn[3],
+ ndlp->nlp_nodename.u.wwn[4],
+ ndlp->nlp_nodename.u.wwn[5],
+ ndlp->nlp_nodename.u.wwn[6],
+ ndlp->nlp_nodename.u.wwn[7],
+ ndlp->nlp_portname.u.wwn[0],
+ ndlp->nlp_portname.u.wwn[1],
+ ndlp->nlp_portname.u.wwn[2],
+ ndlp->nlp_portname.u.wwn[3],
+ ndlp->nlp_portname.u.wwn[4],
+ ndlp->nlp_portname.u.wwn[5],
+ ndlp->nlp_portname.u.wwn[6],
+ ndlp->nlp_portname.u.wwn[7]);
goto out_tgt_busy;
-
+ }
lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
if (lpfc_cmd == NULL) {
lpfc_rampdown_queue_depth(phba);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 5da7e15400cb..8e38e0204c47 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 5f5528a12308..cb17e2b2be81 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,8 +1,7 @@
-
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -36,6 +35,9 @@
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fs.h>
#include <linux/aer.h>
+#ifdef CONFIG_X86
+#include <asm/set_memory.h>
+#endif
#include <linux/nvme-fc-driver.h>
@@ -107,12 +109,14 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
* The caller is expected to hold the hbalock when calling this routine.
**/
static int
-lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
+lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
{
union lpfc_wqe *temp_wqe;
struct lpfc_register doorbell;
uint32_t host_index;
uint32_t idx;
+ uint32_t i = 0;
+ uint8_t *tmp;
/* sanity check on queue memory */
if (unlikely(!q))
@@ -129,10 +133,25 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
/* 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);
+ else
+ bf_set(wqe_wqec, &wqe->generic.wqe_com, 0);
if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
- /* ensure WQE bcopy flushed before doorbell write */
+ if (q->dpp_enable && q->phba->cfg_enable_dpp) {
+ /* write to DPP aperture taking advatage of Combined Writes */
+ tmp = (uint8_t *)temp_wqe;
+#ifdef __raw_writeq
+ for (i = 0; i < q->entry_size; i += sizeof(uint64_t))
+ __raw_writeq(*((uint64_t *)(tmp + i)),
+ q->dpp_regaddr + i);
+#else
+ for (i = 0; i < q->entry_size; i += sizeof(uint32_t))
+ __raw_writel(*((uint32_t *)(tmp + i)),
+ q->dpp_regaddr + i);
+#endif
+ }
+ /* ensure WQE bcopy and DPP flushed before doorbell write */
wmb();
/* Update the host index before invoking device */
@@ -143,9 +162,18 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
/* Ring Doorbell */
doorbell.word0 = 0;
if (q->db_format == LPFC_DB_LIST_FORMAT) {
- bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
- bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index);
- bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
+ if (q->dpp_enable && q->phba->cfg_enable_dpp) {
+ bf_set(lpfc_if6_wq_db_list_fm_num_posted, &doorbell, 1);
+ bf_set(lpfc_if6_wq_db_list_fm_dpp, &doorbell, 1);
+ bf_set(lpfc_if6_wq_db_list_fm_dpp_id, &doorbell,
+ q->dpp_id);
+ bf_set(lpfc_if6_wq_db_list_fm_id, &doorbell,
+ q->queue_id);
+ } else {
+ bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
+ bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index);
+ bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
+ }
} else if (q->db_format == LPFC_DB_RING_FORMAT) {
bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1);
bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id);
@@ -262,16 +290,18 @@ lpfc_sli4_mq_release(struct lpfc_queue *q)
static struct lpfc_eqe *
lpfc_sli4_eq_get(struct lpfc_queue *q)
{
+ struct lpfc_hba *phba;
struct lpfc_eqe *eqe;
uint32_t idx;
/* sanity check on queue memory */
if (unlikely(!q))
return NULL;
+ phba = q->phba;
eqe = q->qe[q->hba_index].eqe;
/* If the next EQE is not valid then we are done */
- if (!bf_get_le32(lpfc_eqe_valid, eqe))
+ if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid)
return NULL;
/* If the host has not yet processed the next entry then we are done */
idx = ((q->hba_index + 1) % q->entry_count);
@@ -279,6 +309,10 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
return NULL;
q->hba_index = idx;
+ /* if the index wrapped around, toggle the valid bit */
+ if (phba->sli4_hba.pc_sli4_params.eqav && !q->hba_index)
+ q->qe_valid = (q->qe_valid) ? 0 : 1;
+
/*
* insert barrier for instruction interlock : data from the hardware
@@ -298,7 +332,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
* @q: The Event Queue to disable interrupts
*
**/
-static inline void
+inline void
lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
{
struct lpfc_register doorbell;
@@ -309,7 +343,26 @@ lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
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);
+ writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
+}
+
+/**
+ * lpfc_sli4_if6_eq_clr_intr - Turn off interrupts from this EQ
+ * @q: The Event Queue to disable interrupts
+ *
+ **/
+inline void
+lpfc_sli4_if6_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.EQDBregaddr);
}
/**
@@ -331,17 +384,21 @@ uint32_t
lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
{
uint32_t released = 0;
+ struct lpfc_hba *phba;
struct lpfc_eqe *temp_eqe;
struct lpfc_register doorbell;
/* sanity check on queue memory */
if (unlikely(!q))
return 0;
+ phba = q->phba;
/* while there are valid entries */
while (q->hba_index != q->host_index) {
- temp_eqe = q->qe[q->host_index].eqe;
- bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+ if (!phba->sli4_hba.pc_sli4_params.eqav) {
+ temp_eqe = q->qe[q->host_index].eqe;
+ bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+ }
released++;
q->host_index = ((q->host_index + 1) % q->entry_count);
}
@@ -359,10 +416,63 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
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);
+ writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
/* PCI read to flush PCI pipeline on re-arming for INTx mode */
if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
- readl(q->phba->sli4_hba.EQCQDBregaddr);
+ readl(q->phba->sli4_hba.EQDBregaddr);
+ return released;
+}
+
+/**
+ * lpfc_sli4_if6_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.
+ *
+ * This routine will mark all Event Queue Entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the EQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of EQEs that were popped.
+ **/
+uint32_t
+lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm)
+{
+ uint32_t released = 0;
+ struct lpfc_hba *phba;
+ struct lpfc_eqe *temp_eqe;
+ struct lpfc_register doorbell;
+
+ /* sanity check on queue memory */
+ if (unlikely(!q))
+ return 0;
+ phba = q->phba;
+
+ /* while there are valid entries */
+ while (q->hba_index != q->host_index) {
+ if (!phba->sli4_hba.pc_sli4_params.eqav) {
+ temp_eqe = q->qe[q->host_index].eqe;
+ bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+ }
+ released++;
+ q->host_index = ((q->host_index + 1) % q->entry_count);
+ }
+ if (unlikely(released == 0 && !arm))
+ return 0;
+
+ /* ring doorbell for number popped */
+ doorbell.word0 = 0;
+ if (arm)
+ bf_set(lpfc_if6_eq_doorbell_arm, &doorbell, 1);
+ bf_set(lpfc_if6_eq_doorbell_num_released, &doorbell, released);
+ bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id);
+ writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
+ /* PCI read to flush PCI pipeline on re-arming for INTx mode */
+ if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
+ readl(q->phba->sli4_hba.EQDBregaddr);
return released;
}
@@ -378,23 +488,28 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
static struct lpfc_cqe *
lpfc_sli4_cq_get(struct lpfc_queue *q)
{
+ struct lpfc_hba *phba;
struct lpfc_cqe *cqe;
uint32_t idx;
/* sanity check on queue memory */
if (unlikely(!q))
return NULL;
+ phba = q->phba;
+ cqe = q->qe[q->hba_index].cqe;
/* If the next CQE is not valid then we are done */
- if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+ if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid)
return NULL;
/* If the host has not yet processed the next entry then we are done */
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 = idx;
+ /* if the index wrapped around, toggle the valid bit */
+ if (phba->sli4_hba.pc_sli4_params.cqav && !q->hba_index)
+ q->qe_valid = (q->qe_valid) ? 0 : 1;
/*
* insert barrier for instruction interlock : data from the hardware
@@ -427,16 +542,21 @@ uint32_t
lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
{
uint32_t released = 0;
+ struct lpfc_hba *phba;
struct lpfc_cqe *temp_qe;
struct lpfc_register doorbell;
/* sanity check on queue memory */
if (unlikely(!q))
return 0;
+ phba = q->phba;
+
/* while there are valid entries */
while (q->hba_index != q->host_index) {
- temp_qe = q->qe[q->host_index].cqe;
- bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+ if (!phba->sli4_hba.pc_sli4_params.cqav) {
+ temp_qe = q->qe[q->host_index].cqe;
+ bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+ }
released++;
q->host_index = ((q->host_index + 1) % q->entry_count);
}
@@ -452,7 +572,57 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
- writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+ writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
+ return released;
+}
+
+/**
+ * lpfc_sli4_if6_cq_release - Indicates the host has finished processing a CQ
+ * @q: The Completion Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Completion queue entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the CQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of CQEs that were released.
+ **/
+uint32_t
+lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm)
+{
+ uint32_t released = 0;
+ struct lpfc_hba *phba;
+ struct lpfc_cqe *temp_qe;
+ struct lpfc_register doorbell;
+
+ /* sanity check on queue memory */
+ if (unlikely(!q))
+ return 0;
+ phba = q->phba;
+
+ /* while there are valid entries */
+ while (q->hba_index != q->host_index) {
+ if (!phba->sli4_hba.pc_sli4_params.cqav) {
+ temp_qe = q->qe[q->host_index].cqe;
+ bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+ }
+ released++;
+ q->host_index = ((q->host_index + 1) % q->entry_count);
+ }
+ if (unlikely(released == 0 && !arm))
+ return 0;
+
+ /* ring doorbell for number popped */
+ doorbell.word0 = 0;
+ if (arm)
+ bf_set(lpfc_if6_cq_doorbell_arm, &doorbell, 1);
+ bf_set(lpfc_if6_cq_doorbell_num_released, &doorbell, released);
+ bf_set(lpfc_if6_cq_doorbell_cqid, &doorbell, q->queue_id);
+ writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
return released;
}
@@ -2218,18 +2388,18 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
void
lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
- wait_queue_head_t *pdone_q;
unsigned long drvr_flag;
+ struct completion *pmbox_done;
/*
- * If pdone_q is empty, the driver thread gave up waiting and
+ * If pmbox_done is empty, the driver thread gave up waiting and
* continued running.
*/
pmboxq->mbox_flag |= LPFC_MBX_WAKE;
spin_lock_irqsave(&phba->hbalock, drvr_flag);
- pdone_q = (wait_queue_head_t *) pmboxq->context1;
- if (pdone_q)
- wake_up_interruptible(pdone_q);
+ pmbox_done = (struct completion *)pmboxq->context3;
+ if (pmbox_done)
+ complete(pmbox_done);
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
return;
}
@@ -2330,7 +2500,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
if (phba->sli_rev == LPFC_SLI_REV4 &&
(bf_get(lpfc_sli_intf_if_type,
- &phba->sli4_hba.sli_intf) ==
+ &phba->sli4_hba.sli_intf) >=
LPFC_SLI_INTF_IF_TYPE_2)) {
if (ndlp) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
@@ -3776,6 +3946,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
uint32_t i;
+ struct lpfc_iocbq *piocb, *next_iocb;
spin_lock_irq(&phba->hbalock);
/* Indicate the I/O queues are flushed */
@@ -3790,6 +3961,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
spin_lock_irq(&pring->ring_lock);
/* Retrieve everything on txq */
list_splice_init(&pring->txq, &txq);
+ list_for_each_entry_safe(piocb, next_iocb,
+ &pring->txcmplq, list)
+ piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
pring->txq_cnt = 0;
@@ -3811,6 +3985,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
/* Retrieve everything on txq */
list_splice_init(&pring->txq, &txq);
+ list_for_each_entry_safe(piocb, next_iocb,
+ &pring->txcmplq, list)
+ piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
pring->txq_cnt = 0;
@@ -3842,6 +4019,7 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
LIST_HEAD(txcmplq);
struct lpfc_sli_ring *pring;
uint32_t i;
+ struct lpfc_iocbq *piocb, *next_iocb;
if (phba->sli_rev < LPFC_SLI_REV4)
return;
@@ -3858,8 +4036,11 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
for (i = 0; i < phba->cfg_nvme_io_channel; i++) {
pring = phba->sli4_hba.nvme_wq[i]->pring;
- /* Retrieve everything on the txcmplq */
spin_lock_irq(&pring->ring_lock);
+ list_for_each_entry_safe(piocb, next_iocb,
+ &pring->txcmplq, list)
+ piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+ /* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
pring->txcmplq_cnt = 0;
spin_unlock_irq(&pring->ring_lock);
@@ -4812,13 +4993,14 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
phba->port_gp = phba->mbox->us.s3_pgp.port;
- if (phba->cfg_enable_bg) {
- if (pmb->u.mb.un.varCfgPort.gbg)
- phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
- else
+ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+ if (pmb->u.mb.un.varCfgPort.gbg == 0) {
+ phba->cfg_enable_bg = 0;
+ phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0443 Adapter did not grant "
"BlockGuard\n");
+ }
}
} else {
phba->hbq_get = NULL;
@@ -5290,41 +5472,42 @@ static void
lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
{
int qidx;
+ struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
- lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
- lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
- if (phba->sli4_hba.nvmels_cq)
- lpfc_sli4_cq_release(phba->sli4_hba.nvmels_cq,
+ sli4_hba->sli4_cq_release(sli4_hba->mbx_cq, LPFC_QUEUE_REARM);
+ sli4_hba->sli4_cq_release(sli4_hba->els_cq, LPFC_QUEUE_REARM);
+ if (sli4_hba->nvmels_cq)
+ sli4_hba->sli4_cq_release(sli4_hba->nvmels_cq,
LPFC_QUEUE_REARM);
- if (phba->sli4_hba.fcp_cq)
+ if (sli4_hba->fcp_cq)
for (qidx = 0; qidx < phba->cfg_fcp_io_channel; qidx++)
- lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[qidx],
+ sli4_hba->sli4_cq_release(sli4_hba->fcp_cq[qidx],
LPFC_QUEUE_REARM);
- if (phba->sli4_hba.nvme_cq)
+ if (sli4_hba->nvme_cq)
for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++)
- lpfc_sli4_cq_release(phba->sli4_hba.nvme_cq[qidx],
+ sli4_hba->sli4_cq_release(sli4_hba->nvme_cq[qidx],
LPFC_QUEUE_REARM);
if (phba->cfg_fof)
- lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM);
+ sli4_hba->sli4_cq_release(sli4_hba->oas_cq, LPFC_QUEUE_REARM);
- if (phba->sli4_hba.hba_eq)
+ if (sli4_hba->hba_eq)
for (qidx = 0; qidx < phba->io_channel_irqs; qidx++)
- lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[qidx],
- LPFC_QUEUE_REARM);
+ sli4_hba->sli4_eq_release(sli4_hba->hba_eq[qidx],
+ LPFC_QUEUE_REARM);
if (phba->nvmet_support) {
for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) {
- lpfc_sli4_cq_release(
- phba->sli4_hba.nvmet_cqset[qidx],
+ sli4_hba->sli4_cq_release(
+ sli4_hba->nvmet_cqset[qidx],
LPFC_QUEUE_REARM);
}
}
if (phba->cfg_fof)
- lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM);
+ sli4_hba->sli4_eq_release(sli4_hba->fof_eq, LPFC_QUEUE_REARM);
}
/**
@@ -6533,9 +6716,11 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
struct lpfc_rqe hrqe;
struct lpfc_rqe drqe;
struct lpfc_rqb *rqbp;
+ unsigned long flags;
struct rqb_dmabuf *rqb_buffer;
LIST_HEAD(rqb_buf_list);
+ spin_lock_irqsave(&phba->hbalock, flags);
rqbp = hrq->rqbp;
for (i = 0; i < count; i++) {
/* IF RQ is already full, don't bother */
@@ -6559,6 +6744,15 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
if (rc < 0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "6421 Cannot post to HRQ %d: %x %x %x "
+ "DRQ %x %x\n",
+ hrq->queue_id,
+ hrq->host_index,
+ hrq->hba_index,
+ hrq->entry_count,
+ drq->host_index,
+ drq->hba_index);
rqbp->rqb_free_buffer(phba, rqb_buffer);
} else {
list_add_tail(&rqb_buffer->hbuf.list,
@@ -6566,6 +6760,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
rqbp->buffer_count++;
}
}
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return 1;
}
@@ -6693,6 +6888,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
/* Save information as VPD data */
phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
+
+ /*
+ * This is because first G7 ASIC doesn't support the standard
+ * 0x5a NVME cmd descriptor type/subtype
+ */
+ if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_6) &&
+ (phba->vpd.rev.biuRev == LPFC_G7_ASIC_1) &&
+ (phba->vpd.rev.smRev == 0) &&
+ (phba->cfg_nvme_embed_cmd == 1))
+ phba->cfg_nvme_embed_cmd = 0;
+
phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
&mqe->un.read_rev);
@@ -6771,21 +6978,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"0378 No support for fcpi mode.\n");
ftr_rsp++;
}
- if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
- phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
- else
- phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+
+ /* Performance Hints are ONLY for FCoE */
+ if (phba->hba_flag & HBA_FCOE_MODE) {
+ if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
+ phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
+ else
+ phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+ }
+
/*
* If the port cannot support the host's requested features
* then turn off the global config parameters to disable the
* feature in the driver. This is not a fatal error.
*/
- phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
- if (phba->cfg_enable_bg) {
- if (bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))
- phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
- else
+ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+ if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) {
+ phba->cfg_enable_bg = 0;
+ phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
ftr_rsp++;
+ }
}
if (phba->max_vpi && phba->cfg_enable_npiv &&
@@ -7209,6 +7421,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
struct lpfc_queue *mcq;
struct lpfc_mcqe *mcqe;
bool pending_completions = false;
+ uint8_t qe_valid;
if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
return false;
@@ -7217,7 +7430,8 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
mcq = phba->sli4_hba.mbx_cq;
idx = mcq->hba_index;
- while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe)) {
+ qe_valid = mcq->qe_valid;
+ while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe) == qe_valid) {
mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe;
if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
(!bf_get_le32(lpfc_trailer_async, mcqe))) {
@@ -7227,6 +7441,10 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
idx = (idx + 1) % mcq->entry_count;
if (mcq->hba_index == idx)
break;
+
+ /* if the index wrapped around, toggle the valid bit */
+ if (phba->sli4_hba.pc_sli4_params.cqav && !idx)
+ qe_valid = (qe_valid) ? 0 : 1;
}
return pending_completions;
@@ -7246,7 +7464,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
bool
lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
{
-
+ struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
uint32_t eqidx;
struct lpfc_queue *fpeq = NULL;
struct lpfc_eqe *eqe;
@@ -7257,11 +7475,11 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
/* Find the eq associated with the mcq */
- if (phba->sli4_hba.hba_eq)
+ if (sli4_hba->hba_eq)
for (eqidx = 0; eqidx < phba->io_channel_irqs; eqidx++)
- if (phba->sli4_hba.hba_eq[eqidx]->queue_id ==
- phba->sli4_hba.mbx_cq->assoc_qid) {
- fpeq = phba->sli4_hba.hba_eq[eqidx];
+ if (sli4_hba->hba_eq[eqidx]->queue_id ==
+ sli4_hba->mbx_cq->assoc_qid) {
+ fpeq = sli4_hba->hba_eq[eqidx];
break;
}
if (!fpeq)
@@ -7269,7 +7487,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
/* Turn off interrupts from this EQ */
- lpfc_sli4_eq_clr_intr(fpeq);
+ sli4_hba->sli4_eq_clr_intr(fpeq);
/* Check to see if a mbox completion is pending */
@@ -7290,7 +7508,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
/* Always clear and re-arm the EQ */
- lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+ sli4_hba->sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
return mbox_pending;
@@ -8100,7 +8318,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
} else if (flag == MBX_POLL) {
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
"(%d):2542 Try to issue mailbox command "
- "x%x (x%x/x%x) synchronously ahead of async"
+ "x%x (x%x/x%x) synchronously ahead of async "
"mailbox command queue: x%x x%x\n",
mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
@@ -8664,7 +8882,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
**/
static int
lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
- union lpfc_wqe *wqe)
+ union lpfc_wqe128 *wqe)
{
uint32_t xmit_len = 0, total_len = 0;
uint8_t ct = 0;
@@ -8767,7 +8985,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
iocbq->context2)->virt);
if_type = bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf);
- if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
*pcmd == ELS_CMD_SCR ||
*pcmd == ELS_CMD_FDISC ||
@@ -8870,31 +9088,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
}
/* Note, word 10 is already initialized to 0 */
+ /* Don't set PBDE for Perf hints, just fcp_embed_pbde */
+ if (phba->fcp_embed_pbde)
+ bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1);
+ else
+ bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0);
+
if (phba->fcp_embed_io) {
struct lpfc_scsi_buf *lpfc_cmd;
struct sli4_sge *sgl;
- union lpfc_wqe128 *wqe128;
struct fcp_cmnd *fcp_cmnd;
uint32_t *ptr;
/* 128 byte wqe support here */
- wqe128 = (union lpfc_wqe128 *)wqe;
lpfc_cmd = iocbq->context1;
sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
/* Word 0-2 - FCP_CMND */
- wqe128->generic.bde.tus.f.bdeFlags =
+ wqe->generic.bde.tus.f.bdeFlags =
BUFF_TYPE_BDE_IMMED;
- wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
- wqe128->generic.bde.addrHigh = 0;
- wqe128->generic.bde.addrLow = 88; /* Word 22 */
+ wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+ wqe->generic.bde.addrHigh = 0;
+ wqe->generic.bde.addrLow = 88; /* Word 22 */
- bf_set(wqe_wqes, &wqe128->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
/* Word 22-29 FCP CMND Payload */
- ptr = &wqe128->words[22];
+ ptr = &wqe->words[22];
memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
}
break;
@@ -8929,31 +9152,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
}
/* Note, word 10 is already initialized to 0 */
+ /* Don't set PBDE for Perf hints, just fcp_embed_pbde */
+ if (phba->fcp_embed_pbde)
+ bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1);
+ else
+ bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0);
+
if (phba->fcp_embed_io) {
struct lpfc_scsi_buf *lpfc_cmd;
struct sli4_sge *sgl;
- union lpfc_wqe128 *wqe128;
struct fcp_cmnd *fcp_cmnd;
uint32_t *ptr;
/* 128 byte wqe support here */
- wqe128 = (union lpfc_wqe128 *)wqe;
lpfc_cmd = iocbq->context1;
sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
/* Word 0-2 - FCP_CMND */
- wqe128->generic.bde.tus.f.bdeFlags =
+ wqe->generic.bde.tus.f.bdeFlags =
BUFF_TYPE_BDE_IMMED;
- wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
- wqe128->generic.bde.addrHigh = 0;
- wqe128->generic.bde.addrLow = 88; /* Word 22 */
+ wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+ wqe->generic.bde.addrHigh = 0;
+ wqe->generic.bde.addrLow = 88; /* Word 22 */
- bf_set(wqe_wqes, &wqe128->fcp_iread.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1);
+ bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0);
/* Word 22-29 FCP CMND Payload */
- ptr = &wqe128->words[22];
+ ptr = &wqe->words[22];
memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
}
break;
@@ -8990,28 +9218,27 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
if (phba->fcp_embed_io) {
struct lpfc_scsi_buf *lpfc_cmd;
struct sli4_sge *sgl;
- union lpfc_wqe128 *wqe128;
struct fcp_cmnd *fcp_cmnd;
uint32_t *ptr;
/* 128 byte wqe support here */
- wqe128 = (union lpfc_wqe128 *)wqe;
lpfc_cmd = iocbq->context1;
sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
/* Word 0-2 - FCP_CMND */
- wqe128->generic.bde.tus.f.bdeFlags =
+ wqe->generic.bde.tus.f.bdeFlags =
BUFF_TYPE_BDE_IMMED;
- wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
- wqe128->generic.bde.addrHigh = 0;
- wqe128->generic.bde.addrLow = 88; /* Word 22 */
+ wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+ wqe->generic.bde.addrHigh = 0;
+ wqe->generic.bde.addrLow = 88; /* Word 22 */
- bf_set(wqe_wqes, &wqe128->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
+ bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0);
/* Word 22-29 FCP CMND Payload */
- ptr = &wqe128->words[22];
+ ptr = &wqe->words[22];
memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
}
break;
@@ -9064,7 +9291,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
if_type = bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf);
- if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+ if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
if (iocbq->vport->fc_flag & FC_PT2PT) {
bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
@@ -9249,8 +9476,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_sglq *sglq;
- union lpfc_wqe *wqe;
- union lpfc_wqe128 wqe128;
+ union lpfc_wqe128 wqe;
struct lpfc_queue *wq;
struct lpfc_sli_ring *pring;
@@ -9270,9 +9496,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
/*
* The WQE can be either 64 or 128 bytes,
- * so allocate space on the stack assuming the largest.
*/
- wqe = (union lpfc_wqe *)&wqe128;
lockdep_assert_held(&phba->hbalock);
@@ -9322,10 +9546,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
}
- if (lpfc_sli4_iocb2wqe(phba, piocb, wqe))
+ if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
return IOCB_ERROR;
- if (lpfc_sli4_wq_put(wq, wqe))
+ if (lpfc_sli4_wq_put(wq, &wqe))
return IOCB_ERROR;
lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
@@ -9470,7 +9694,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
fpeq = phba->sli4_hba.hba_eq[idx];
/* Turn off interrupts from this EQ */
- lpfc_sli4_eq_clr_intr(fpeq);
+ phba->sli4_hba.sli4_eq_clr_intr(fpeq);
/*
* Process all the events on FCP EQ
@@ -9482,7 +9706,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
}
/* Always clear and re-arm the EQ */
- lpfc_sli4_eq_release(fpeq,
+ phba->sli4_hba.sli4_eq_release(fpeq,
LPFC_QUEUE_REARM);
}
atomic_inc(&hba_eq_hdl->hba_eq_in_use);
@@ -10695,7 +10919,7 @@ lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_iocbq *abtsiocbp;
- union lpfc_wqe *abts_wqe;
+ union lpfc_wqe128 *abts_wqe;
int retval;
/*
@@ -11442,31 +11666,25 @@ int
lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
uint32_t timeout)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
- MAILBOX_t *mb = NULL;
+ struct completion mbox_done;
int retval;
unsigned long flag;
- /* The caller might set context1 for extended buffer */
- if (pmboxq->context1)
- mb = (MAILBOX_t *)pmboxq->context1;
-
pmboxq->mbox_flag &= ~LPFC_MBX_WAKE;
/* setup wake call as IOCB callback */
pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
- /* setup context field to pass wait_queue pointer to wake function */
- pmboxq->context1 = &done_q;
+ /* setup context3 field to pass wait_queue pointer to wake function */
+ init_completion(&mbox_done);
+ pmboxq->context3 = &mbox_done;
/* now issue the command */
retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
- wait_event_interruptible_timeout(done_q,
- pmboxq->mbox_flag & LPFC_MBX_WAKE,
- msecs_to_jiffies(timeout * 1000));
+ wait_for_completion_timeout(&mbox_done,
+ msecs_to_jiffies(timeout * 1000));
spin_lock_irqsave(&phba->hbalock, flag);
- /* restore the possible extended buffer for free resource */
- pmboxq->context1 = (uint8_t *)mb;
+ pmboxq->context3 = NULL;
/*
* if LPFC_MBX_WAKE flag is set the mailbox is completed
* else do not free the resources.
@@ -11478,11 +11696,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
spin_unlock_irqrestore(&phba->hbalock, flag);
- } else {
- /* restore the possible extended buffer for free resource */
- pmboxq->context1 = (uint8_t *)mb;
}
-
return retval;
}
@@ -11648,6 +11862,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
}
break;
case LPFC_SLI_INTF_IF_TYPE_2:
+ case LPFC_SLI_INTF_IF_TYPE_6:
if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
&portstat_reg.word0) ||
lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
@@ -13112,7 +13327,7 @@ lpfc_sli4_sp_process_cq(struct work_struct *work)
"(x%x), type (%d)\n", cq->queue_id, cq->type);
/* In any case, flash and re-arm the RCQ */
- lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+ phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM);
/* wake up worker thread if there are works to be done */
if (workposted)
@@ -13230,6 +13445,8 @@ lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
if (childwq->queue_id == hba_wqid) {
lpfc_sli4_wq_release(childwq,
bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+ if (childwq->q_flag & HBA_NVMET_WQFULL)
+ lpfc_nvmet_wqfull_process(phba, childwq);
wqid_matched = true;
break;
}
@@ -13542,7 +13759,7 @@ lpfc_sli4_hba_process_cq(struct work_struct *work)
"queue fcpcqid=%d\n", cq->queue_id);
/* In any case, flash and re-arm the CQ */
- lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+ phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM);
/* wake up worker thread if there are works to be done */
if (workposted)
@@ -13559,7 +13776,7 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
;
/* Clear and re-arm the EQ */
- lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+ phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM);
}
@@ -13707,7 +13924,7 @@ lpfc_sli4_fof_intr_handler(int irq, void *dev_id)
}
}
/* Always clear and re-arm the fast-path EQ */
- lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+ phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM);
return IRQ_HANDLED;
}
@@ -13765,7 +13982,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
if (lpfc_fcp_look_ahead) {
if (atomic_dec_and_test(&hba_eq_hdl->hba_eq_in_use))
- lpfc_sli4_eq_clr_intr(fpeq);
+ phba->sli4_hba.sli4_eq_clr_intr(fpeq);
else {
atomic_inc(&hba_eq_hdl->hba_eq_in_use);
return IRQ_NONE;
@@ -13800,7 +14017,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
fpeq->EQ_max_eqe = ecount;
/* Always clear and re-arm the fast-path EQ */
- lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+ phba->sli4_hba.sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
if (unlikely(ecount == 0)) {
fpeq->EQ_no_entry++;
@@ -13948,6 +14165,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
INIT_LIST_HEAD(&queue->list);
INIT_LIST_HEAD(&queue->wq_list);
+ INIT_LIST_HEAD(&queue->wqfull_list);
INIT_LIST_HEAD(&queue->page_list);
INIT_LIST_HEAD(&queue->child_list);
@@ -14173,11 +14391,21 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
LPFC_MBOX_OPCODE_EQ_CREATE,
length, LPFC_SLI4_MBX_EMBED);
eq_create = &mbox->u.mqe.un.eq_create;
+ shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
eq->page_count);
bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
LPFC_EQE_SIZE);
bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
+
+ /* Use version 2 of CREATE_EQ if eqav is set */
+ if (phba->sli4_hba.pc_sli4_params.eqav) {
+ bf_set(lpfc_mbox_hdr_version, &shdr->request,
+ LPFC_Q_CREATE_VERSION_2);
+ bf_set(lpfc_eq_context_autovalid, &eq_create->u.request.context,
+ phba->sli4_hba.pc_sli4_params.eqav);
+ }
+
/* don't setup delay multiplier using EQ_CREATE */
dmult = 0;
bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
@@ -14222,7 +14450,6 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->context1 = NULL;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
- shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->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 (shdr_status || shdr_add_status || rc) {
@@ -14305,6 +14532,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
(cq->page_size / SLI4_PAGE_SIZE));
bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context,
eq->queue_id);
+ bf_set(lpfc_cq_context_autovalid, &cq_create->u.request.context,
+ phba->sli4_hba.pc_sli4_params.cqav);
} else {
bf_set(lpfc_cq_eq_id, &cq_create->u.request.context,
eq->queue_id);
@@ -14476,6 +14705,9 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
&cq_set->u.request, 0);
bf_set(lpfc_mbx_cq_create_set_num_cq,
&cq_set->u.request, numcq);
+ bf_set(lpfc_mbx_cq_create_set_autovalid,
+ &cq_set->u.request,
+ phba->sli4_hba.pc_sli4_params.cqav);
switch (cq->entry_count) {
case 2048:
case 4096:
@@ -14881,6 +15113,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
void __iomem *bar_memmap_p;
uint32_t db_offset;
uint16_t pci_barset;
+ uint8_t dpp_barset;
+ uint32_t dpp_offset;
+ unsigned long pg_addr;
uint8_t wq_create_version;
/* sanity check on queue memory */
@@ -14908,43 +15143,19 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
bf_set(lpfc_mbox_hdr_version, &shdr->request,
phba->sli4_hba.pc_sli4_params.wqv);
+ if ((phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) ||
+ (wq->page_size > SLI4_PAGE_SIZE))
+ wq_create_version = LPFC_Q_CREATE_VERSION_1;
+ else
+ wq_create_version = LPFC_Q_CREATE_VERSION_0;
+
+
if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT)
wq_create_version = LPFC_Q_CREATE_VERSION_1;
else
wq_create_version = LPFC_Q_CREATE_VERSION_0;
switch (wq_create_version) {
- case LPFC_Q_CREATE_VERSION_0:
- switch (wq->entry_size) {
- default:
- case 64:
- /* Nothing to do, version 0 ONLY supports 64 byte */
- page = wq_create->u.request.page;
- break;
- case 128:
- if (!(phba->sli4_hba.pc_sli4_params.wqsize &
- LPFC_WQ_SZ128_SUPPORT)) {
- status = -ERANGE;
- goto out;
- }
- /* If we get here the HBA MUST also support V1 and
- * we MUST use it
- */
- bf_set(lpfc_mbox_hdr_version, &shdr->request,
- LPFC_Q_CREATE_VERSION_1);
-
- bf_set(lpfc_mbx_wq_create_wqe_count,
- &wq_create->u.request_1, wq->entry_count);
- bf_set(lpfc_mbx_wq_create_wqe_size,
- &wq_create->u.request_1,
- LPFC_WQ_WQE_SIZE_128);
- bf_set(lpfc_mbx_wq_create_page_size,
- &wq_create->u.request_1,
- LPFC_WQ_PAGE_SIZE_4096);
- page = wq_create->u.request_1.page;
- break;
- }
- break;
case LPFC_Q_CREATE_VERSION_1:
bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
wq->entry_count);
@@ -14959,24 +15170,21 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
LPFC_WQ_WQE_SIZE_64);
break;
case 128:
- if (!(phba->sli4_hba.pc_sli4_params.wqsize &
- LPFC_WQ_SZ128_SUPPORT)) {
- status = -ERANGE;
- goto out;
- }
bf_set(lpfc_mbx_wq_create_wqe_size,
&wq_create->u.request_1,
LPFC_WQ_WQE_SIZE_128);
break;
}
+ /* Request DPP by default */
+ bf_set(lpfc_mbx_wq_create_dpp_req, &wq_create->u.request_1, 1);
bf_set(lpfc_mbx_wq_create_page_size,
&wq_create->u.request_1,
(wq->page_size / SLI4_PAGE_SIZE));
page = wq_create->u.request_1.page;
break;
default:
- status = -ERANGE;
- goto out;
+ page = wq_create->u.request.page;
+ break;
}
list_for_each_entry(dmabuf, &wq->page_list, list) {
@@ -15000,52 +15208,120 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
status = -ENXIO;
goto out;
}
- wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response);
+
+ if (wq_create_version == LPFC_Q_CREATE_VERSION_0)
+ wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id,
+ &wq_create->u.response);
+ else
+ wq->queue_id = bf_get(lpfc_mbx_wq_create_v1_q_id,
+ &wq_create->u.response_1);
+
if (wq->queue_id == 0xFFFF) {
status = -ENXIO;
goto out;
}
- if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
- wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
- &wq_create->u.response);
- if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
- (wq->db_format != LPFC_DB_RING_FORMAT)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3265 WQ[%d] doorbell format not "
- "supported: x%x\n", wq->queue_id,
- wq->db_format);
- status = -EINVAL;
- goto out;
- }
- pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
- &wq_create->u.response);
- bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset);
- if (!bar_memmap_p) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3263 WQ[%d] failed to memmap pci "
- "barset:x%x\n", wq->queue_id,
- pci_barset);
- status = -ENOMEM;
- goto out;
- }
- db_offset = wq_create->u.response.doorbell_offset;
- if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
- (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3252 WQ[%d] doorbell offset not "
- "supported: x%x\n", wq->queue_id,
- db_offset);
- status = -EINVAL;
- goto out;
- }
- wq->db_regaddr = bar_memmap_p + db_offset;
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "3264 WQ[%d]: barset:x%x, offset:x%x, "
- "format:x%x\n", wq->queue_id, pci_barset,
- db_offset, wq->db_format);
+
+ wq->db_format = LPFC_DB_LIST_FORMAT;
+ if (wq_create_version == LPFC_Q_CREATE_VERSION_0) {
+ if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
+ wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
+ &wq_create->u.response);
+ if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
+ (wq->db_format != LPFC_DB_RING_FORMAT)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3265 WQ[%d] doorbell format "
+ "not supported: x%x\n",
+ wq->queue_id, wq->db_format);
+ status = -EINVAL;
+ goto out;
+ }
+ pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
+ &wq_create->u.response);
+ bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+ pci_barset);
+ if (!bar_memmap_p) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3263 WQ[%d] failed to memmap "
+ "pci barset:x%x\n",
+ wq->queue_id, pci_barset);
+ status = -ENOMEM;
+ goto out;
+ }
+ db_offset = wq_create->u.response.doorbell_offset;
+ if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
+ (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3252 WQ[%d] doorbell offset "
+ "not supported: x%x\n",
+ wq->queue_id, db_offset);
+ status = -EINVAL;
+ goto out;
+ }
+ wq->db_regaddr = bar_memmap_p + db_offset;
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3264 WQ[%d]: barset:x%x, offset:x%x, "
+ "format:x%x\n", wq->queue_id,
+ pci_barset, db_offset, wq->db_format);
+ } else
+ wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
} else {
- wq->db_format = LPFC_DB_LIST_FORMAT;
- wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
+ /* Check if DPP was honored by the firmware */
+ wq->dpp_enable = bf_get(lpfc_mbx_wq_create_dpp_rsp,
+ &wq_create->u.response_1);
+ if (wq->dpp_enable) {
+ pci_barset = bf_get(lpfc_mbx_wq_create_v1_bar_set,
+ &wq_create->u.response_1);
+ bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+ pci_barset);
+ if (!bar_memmap_p) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3267 WQ[%d] failed to memmap "
+ "pci barset:x%x\n",
+ wq->queue_id, pci_barset);
+ status = -ENOMEM;
+ goto out;
+ }
+ db_offset = wq_create->u.response_1.doorbell_offset;
+ wq->db_regaddr = bar_memmap_p + db_offset;
+ wq->dpp_id = bf_get(lpfc_mbx_wq_create_dpp_id,
+ &wq_create->u.response_1);
+ dpp_barset = bf_get(lpfc_mbx_wq_create_dpp_bar,
+ &wq_create->u.response_1);
+ bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+ dpp_barset);
+ if (!bar_memmap_p) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3268 WQ[%d] failed to memmap "
+ "pci barset:x%x\n",
+ wq->queue_id, dpp_barset);
+ status = -ENOMEM;
+ goto out;
+ }
+ dpp_offset = wq_create->u.response_1.dpp_offset;
+ wq->dpp_regaddr = bar_memmap_p + dpp_offset;
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3271 WQ[%d]: barset:x%x, offset:x%x, "
+ "dpp_id:x%x dpp_barset:x%x "
+ "dpp_offset:x%x\n",
+ wq->queue_id, pci_barset, db_offset,
+ wq->dpp_id, dpp_barset, dpp_offset);
+
+ /* Enable combined writes for DPP aperture */
+ pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
+#ifdef CONFIG_X86
+ rc = set_memory_wc(pg_addr, 1);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3272 Cannot setup Combined "
+ "Write on WQ[%d] - disable DPP\n",
+ wq->queue_id);
+ phba->cfg_enable_dpp = 0;
+ }
+#else
+ phba->cfg_enable_dpp = 0;
+#endif
+ } else
+ wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
}
wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL);
if (wq->pring == NULL) {
@@ -18616,6 +18892,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
"status x%x add_status x%x, mbx status x%x\n",
shdr_status, shdr_add_status, rc);
rc = -ENXIO;
+ *offset = shdr_add_status;
} else
*offset += wr_object->u.response.actual_write_length;
return rc;
@@ -18753,8 +19030,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
unsigned long iflags = 0;
char *fail_msg = NULL;
struct lpfc_sglq *sglq;
- union lpfc_wqe128 wqe128;
- union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128;
+ union lpfc_wqe128 wqe;
uint32_t txq_cnt = 0;
pring = lpfc_phba_elsring(phba);
@@ -18797,9 +19073,9 @@ lpfc_drain_txq(struct lpfc_hba *phba)
piocbq->sli4_xritag = sglq->sli4_xritag;
if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
fail_msg = "to convert bpl to sgl";
- else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe))
+ else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
fail_msg = "to convert iocb to wqe";
- else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe))
+ else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
fail_msg = " - Wq is full";
else
lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
@@ -18849,7 +19125,7 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq,
struct ulp_bde64 bde;
struct sli4_sge *sgl = NULL;
struct lpfc_dmabuf *dmabuf;
- union lpfc_wqe *wqe;
+ union lpfc_wqe128 *wqe;
int numBdes = 0;
int i = 0;
uint32_t offset = 0; /* accumulated offset in the sg request list */
@@ -18958,7 +19234,7 @@ int
lpfc_sli4_issue_wqe(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *pwqe)
{
- union lpfc_wqe *wqe = &pwqe->wqe;
+ union lpfc_wqe128 *wqe = &pwqe->wqe;
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_queue *wq;
struct lpfc_sglq *sglq;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a3b1b5145d2b..431754195505 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -61,9 +61,8 @@ struct lpfc_iocbq {
struct lpfc_wcqe_complete wcqe_cmpl; /* WQE cmpl */
uint64_t isr_timestamp;
- /* Be careful here */
- union lpfc_wqe wqe; /* WQE cmd */
- IOCB_t iocb; /* For IOCB cmd or if we want 128 byte WQE */
+ union lpfc_wqe128 wqe; /* SLI-4 */
+ IOCB_t iocb; /* SLI-3 */
uint8_t rsvd2;
uint8_t priority; /* OAS priority */
@@ -148,6 +147,7 @@ typedef struct lpfcMboxq {
struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
+ void *context3;
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
uint8_t mbox_flag;
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 81fb58e59e60..cf64aca82bd0 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -145,6 +145,7 @@ struct lpfc_rqb {
struct lpfc_queue {
struct list_head list;
struct list_head wq_list;
+ struct list_head wqfull_list;
enum lpfc_sli4_queue_type type;
enum lpfc_sli4_queue_subtype subtype;
struct lpfc_hba *phba;
@@ -173,10 +174,16 @@ struct lpfc_queue {
#define LPFC_EXPANDED_PAGE_SIZE 16384
#define LPFC_DEFAULT_PAGE_SIZE 4096
uint16_t chann; /* IO channel this queue is associated with */
- uint16_t db_format;
+ uint8_t db_format;
#define LPFC_DB_RING_FORMAT 0x01
#define LPFC_DB_LIST_FORMAT 0x02
+ uint8_t q_flag;
+#define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */
void __iomem *db_regaddr;
+ uint16_t dpp_enable;
+ uint16_t dpp_id;
+ void __iomem *dpp_regaddr;
+
/* For q stats */
uint32_t q_cnt_1;
uint32_t q_cnt_2;
@@ -209,6 +216,7 @@ struct lpfc_queue {
struct work_struct spwork;
uint64_t isr_timestamp;
+ uint8_t qe_valid;
struct lpfc_queue *assoc_qp;
union sli4_qe qe[1]; /* array to index entries (must be last) */
};
@@ -479,12 +487,19 @@ struct lpfc_pc_sli4_params {
uint8_t mqv;
uint8_t wqv;
uint8_t rqv;
+ uint8_t eqav;
+ uint8_t cqav;
uint8_t wqsize;
#define LPFC_WQ_SZ64_SUPPORT 1
#define LPFC_WQ_SZ128_SUPPORT 2
uint8_t wqpcnt;
};
+#define LPFC_CQ_4K_PAGE_SZ 0x1
+#define LPFC_CQ_16K_PAGE_SZ 0x4
+#define LPFC_WQ_4K_PAGE_SZ 0x1
+#define LPFC_WQ_16K_PAGE_SZ 0x4
+
struct lpfc_iov {
uint32_t pf_number;
uint32_t vf_number;
@@ -516,11 +531,17 @@ struct lpfc_vector_map_info {
/* SLI4 HBA data structure entries */
struct lpfc_sli4_hba {
void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
- PCI BAR0, config space registers */
+ * config space registers
+ */
void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for
- PCI BAR1, control registers */
+ * control registers
+ */
void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
- PCI BAR2, doorbell registers */
+ * doorbell registers
+ */
+ void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for
+ * dpp registers
+ */
union {
struct {
/* IF Type 0, BAR 0 PCI cfg space reg mem map */
@@ -561,7 +582,8 @@ struct lpfc_sli4_hba {
/* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */
void __iomem *RQDBregaddr; /* RQ_DOORBELL register */
void __iomem *WQDBregaddr; /* WQ_DOORBELL register */
- void __iomem *EQCQDBregaddr; /* EQCQ_DOORBELL register */
+ void __iomem *CQDBregaddr; /* CQ_DOORBELL register */
+ void __iomem *EQDBregaddr; /* EQ_DOORBELL register */
void __iomem *MQDBregaddr; /* MQ_DOORBELL register */
void __iomem *BMBXregaddr; /* BootStrap MBX register */
@@ -574,6 +596,10 @@ struct lpfc_sli4_hba {
struct lpfc_bbscn_params bbscn_params;
struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */
+ void (*sli4_eq_clr_intr)(struct lpfc_queue *q);
+ uint32_t (*sli4_eq_release)(struct lpfc_queue *q, bool arm);
+ uint32_t (*sli4_cq_release)(struct lpfc_queue *q, bool arm);
+
/* Pointers to the constructed SLI4 queues */
struct lpfc_queue **hba_eq; /* Event queues for HBA */
struct lpfc_queue **fcp_cq; /* Fast-path FCP compl queue */
@@ -840,8 +866,12 @@ void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
int lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba);
int lpfc_sli4_init_vpi(struct lpfc_vport *);
+inline void lpfc_sli4_eq_clr_intr(struct lpfc_queue *);
uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
+inline void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q);
+uint32_t lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm);
+uint32_t lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm);
void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t);
int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index c232bf0e8998..e8b089abbfb3 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Limited and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -20,7 +20,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "11.4.0.6"
+#define LPFC_DRIVER_VERSION "12.0.0.1"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
@@ -32,6 +32,6 @@
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright (C) 2017 Broadcom. All Rights Reserved. " \
- "The term \"Broadcom\" refers to Broadcom Limited " \
+#define LPFC_COPYRIGHT "Copyright (C) 2017-2018 Broadcom. All Rights " \
+ "Reserved. The term \"Broadcom\" refers to Broadcom Limited " \
"and/or its subsidiaries."