Commit dbb1e2ff authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Add reporting capability for Link Degrade Signaling

Firmware reports link degrade signaling via ACQES.

Handlers and new additions to the SET_FEATURES mbox command are implemented
so that link degrade parameters for 64GB capable links are reported through
EDC ELS frames.

Link: https://lore.kernel.org/r/20220911221505.117655-12-jsmart2021@gmail.com


Co-developed-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 045c58c8
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -403,6 +403,7 @@ struct lpfc_trunk_link {
				     link1,
				     link2,
				     link3;
	u32 phy_lnk_speed;
};

/* Format of congestion module parameters */
@@ -1596,6 +1597,11 @@ struct lpfc_hba {

	char os_host_name[MAXHOSTNAMELEN];

	/* LD Signaling */
	u32 degrade_activate_threshold;
	u32 degrade_deactivate_threshold;
	u32 fec_degrade_interval;

	atomic_t dbg_log_idx;
	atomic_t dbg_log_cnt;
	atomic_t dbg_log_dmping;
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ int lpfc_init_iocb_list(struct lpfc_hba *phba, int cnt);
void lpfc_free_iocb_list(struct lpfc_hba *phba);
int lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
			struct lpfc_queue *drq, int count, int idx);
int lpfc_read_lds_params(struct lpfc_hba *phba);
uint32_t lpfc_calc_cmf_latency(struct lpfc_hba *phba);
void lpfc_cmf_signal_init(struct lpfc_hba *phba);
void lpfc_cmf_start(struct lpfc_hba *phba);
+111 −43
Original line number Diff line number Diff line
@@ -3988,7 +3988,8 @@ lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		goto out;

	/* ELS cmd tag <ulpIoTag> completes */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
	lpfc_printf_log(phba, KERN_INFO,
			LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
			"4676 Fabric EDC Rsp: "
			"0x%02x, 0x%08x\n",
			edc_rsp->acc_hdr.la_cmd,
@@ -4025,18 +4026,18 @@ lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) ||
			    FC_TLV_DESC_SZ_FROM_LENGTH(tlv) !=
					sizeof(struct fc_diag_lnkflt_desc)) {
				lpfc_printf_log(
					phba, KERN_WARNING, LOG_CGN_MGMT,
				lpfc_printf_log(phba, KERN_WARNING,
					LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
					"6462 Truncated Link Fault Diagnostic "
					"descriptor[%d]: %d vs 0x%zx 0x%zx\n",
					desc_cnt, bytes_remain,
					FC_TLV_DESC_SZ_FROM_LENGTH(tlv),
					sizeof(struct fc_diag_cg_sig_desc));
					sizeof(struct fc_diag_lnkflt_desc));
				goto out;
			}
			plnkflt = (struct fc_diag_lnkflt_desc *)tlv;
			lpfc_printf_log(
				phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
			lpfc_printf_log(phba, KERN_INFO,
				LOG_ELS | LOG_LDS_EVENT,
				"4617 Link Fault Desc Data: 0x%08x 0x%08x "
				"0x%08x 0x%08x 0x%08x\n",
				be32_to_cpu(plnkflt->desc_tag),
@@ -4116,8 +4117,26 @@ lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}

static void
lpfc_format_edc_cgn_desc(struct lpfc_hba *phba, struct fc_diag_cg_sig_desc *cgd)
lpfc_format_edc_lft_desc(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
{
	struct fc_diag_lnkflt_desc *lft = (struct fc_diag_lnkflt_desc *)tlv;

	lft->desc_tag = cpu_to_be32(ELS_DTAG_LNK_FAULT_CAP);
	lft->desc_len = cpu_to_be32(
		FC_TLV_DESC_LENGTH_FROM_SZ(struct fc_diag_lnkflt_desc));

	lft->degrade_activate_threshold =
		cpu_to_be32(phba->degrade_activate_threshold);
	lft->degrade_deactivate_threshold =
		cpu_to_be32(phba->degrade_deactivate_threshold);
	lft->fec_degrade_interval = cpu_to_be32(phba->fec_degrade_interval);
}

static void
lpfc_format_edc_cgn_desc(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
{
	struct fc_diag_cg_sig_desc *cgd = (struct fc_diag_cg_sig_desc *)tlv;

	/* We are assuming cgd was zero'ed before calling this routine */

	/* Configure the congestion detection capability */
@@ -4161,6 +4180,23 @@ lpfc_format_edc_cgn_desc(struct lpfc_hba *phba, struct fc_diag_cg_sig_desc *cgd)
		cpu_to_be16(EDC_CG_SIGFREQ_MSEC);
}

static bool
lpfc_link_is_lds_capable(struct lpfc_hba *phba)
{
	if (!(phba->lmt & LMT_64Gb))
		return false;
	if (phba->sli_rev != LPFC_SLI_REV4)
		return false;

	if (phba->sli4_hba.conf_trunk) {
		if (phba->trunk_link.phy_lnk_speed == LPFC_USER_LINK_SPEED_64G)
			return true;
	} else if (phba->fc_linkspeed == LPFC_LINK_SPEED_64GHZ) {
		return true;
	}
	return false;
}

 /**
  * lpfc_issue_els_edc - Exchange Diagnostic Capabilities with the fabric.
  * @vport: pointer to a host virtual N_Port data structure.
@@ -4188,12 +4224,12 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
{
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_els_edc_req *edc_req;
	struct fc_diag_cg_sig_desc *cgn_desc;
	struct fc_els_edc *edc_req;
	struct fc_tlv_desc *tlv;
	u16 cmdsize;
	struct lpfc_nodelist *ndlp;
	u8 *pcmd = NULL;
	u32 edc_req_size, cgn_desc_size;
	u32 cgn_desc_size, lft_desc_size;
	int rc;

	if (vport->port_type == LPFC_NPIV_PORT)
@@ -4203,13 +4239,17 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
	if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
		return -ENODEV;

	/* If HBA doesn't support signals, drop into RDF */
	if (!phba->cgn_init_reg_signal)
	cgn_desc_size = (phba->cgn_init_reg_signal) ?
				sizeof(struct fc_diag_cg_sig_desc) : 0;
	lft_desc_size = (lpfc_link_is_lds_capable(phba)) ?
				sizeof(struct fc_diag_lnkflt_desc) : 0;
	cmdsize = cgn_desc_size + lft_desc_size;

	/* Skip EDC if no applicable descriptors */
	if (!cmdsize)
		goto try_rdf;

	edc_req_size = sizeof(struct fc_els_edc);
	cgn_desc_size = sizeof(struct fc_diag_cg_sig_desc);
	cmdsize = edc_req_size + cgn_desc_size;
	cmdsize += sizeof(struct fc_els_edc);
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_EDC);
	if (!elsiocb)
@@ -4218,15 +4258,19 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
	/* Configure the payload for the supported Diagnostics capabilities. */
	pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
	memset(pcmd, 0, cmdsize);
	edc_req = (struct lpfc_els_edc_req *)pcmd;
	edc_req->edc.desc_len = cpu_to_be32(cgn_desc_size);
	edc_req->edc.edc_cmd = ELS_EDC;

	cgn_desc = &edc_req->cgn_desc;

	lpfc_format_edc_cgn_desc(phba, cgn_desc);
	edc_req = (struct fc_els_edc *)pcmd;
	edc_req->desc_len = cpu_to_be32(cgn_desc_size + lft_desc_size);
	edc_req->edc_cmd = ELS_EDC;
	tlv = edc_req->desc;

	if (cgn_desc_size) {
		lpfc_format_edc_cgn_desc(phba, tlv);
		phba->cgn_sig_freq = lpfc_fabric_cgn_frequency;
		tlv = fc_tlv_next_desc(tlv);
	}

	if (lft_desc_size)
		lpfc_format_edc_lft_desc(phba, tlv);

	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
			 "4623 Xmit EDC to remote "
@@ -5780,14 +5824,21 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		       struct lpfc_nodelist *ndlp)
{
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_els_edc_rsp *edc_rsp;
	struct fc_els_edc_resp *edc_rsp;
	struct fc_tlv_desc *tlv;
	struct lpfc_iocbq *elsiocb;
	IOCB_t *icmd, *cmd;
	union lpfc_wqe128 *wqe;
	u32 cgn_desc_size, lft_desc_size;
	u16 cmdsize;
	uint8_t *pcmd;
	int cmdsize, rc;
	int rc;

	cmdsize = sizeof(struct lpfc_els_edc_rsp);
	cmdsize = sizeof(struct fc_els_edc_resp);
	cgn_desc_size = sizeof(struct fc_diag_cg_sig_desc);
	lft_desc_size = (lpfc_link_is_lds_capable(phba)) ?
				sizeof(struct fc_diag_lnkflt_desc) : 0;
	cmdsize += cgn_desc_size + lft_desc_size;
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, cmdiocb->retry,
				     ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
	if (!elsiocb)
@@ -5809,15 +5860,19 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	pcmd = elsiocb->cmd_dmabuf->virt;
	memset(pcmd, 0, cmdsize);

	edc_rsp = (struct lpfc_els_edc_rsp *)pcmd;
	edc_rsp->edc_rsp.acc_hdr.la_cmd = ELS_LS_ACC;
	edc_rsp->edc_rsp.desc_list_len = cpu_to_be32(
		FC_TLV_DESC_LENGTH_FROM_SZ(struct lpfc_els_edc_rsp));
	edc_rsp->edc_rsp.lsri.desc_tag = cpu_to_be32(ELS_DTAG_LS_REQ_INFO);
	edc_rsp->edc_rsp.lsri.desc_len = cpu_to_be32(
	edc_rsp = (struct fc_els_edc_resp *)pcmd;
	edc_rsp->acc_hdr.la_cmd = ELS_LS_ACC;
	edc_rsp->desc_list_len = cpu_to_be32(sizeof(struct fc_els_lsri_desc) +
						cgn_desc_size + lft_desc_size);
	edc_rsp->lsri.desc_tag = cpu_to_be32(ELS_DTAG_LS_REQ_INFO);
	edc_rsp->lsri.desc_len = cpu_to_be32(
		FC_TLV_DESC_LENGTH_FROM_SZ(struct fc_els_lsri_desc));
	edc_rsp->edc_rsp.lsri.rqst_w0.cmd = ELS_EDC;
	lpfc_format_edc_cgn_desc(phba, &edc_rsp->cgn_desc);
	edc_rsp->lsri.rqst_w0.cmd = ELS_EDC;
	tlv = edc_rsp->desc;
	lpfc_format_edc_cgn_desc(phba, tlv);
	tlv = fc_tlv_next_desc(tlv);
	if (lft_desc_size)
		lpfc_format_edc_lft_desc(phba, tlv);

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
			      "Issue EDC ACC:      did:x%x flg:x%x refcnt %d",
@@ -9082,7 +9137,7 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	uint32_t *ptr, dtag;
	const char *dtag_nm;
	int desc_cnt = 0, bytes_remain;
	bool rcv_cap_desc = false;
	struct fc_diag_lnkflt_desc *plnkflt;

	payload = cmdiocb->cmd_dmabuf->virt;

@@ -9090,7 +9145,8 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	bytes_remain = be32_to_cpu(edc_req->desc_len);

	ptr = (uint32_t *)payload;
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
	lpfc_printf_vlog(vport, KERN_INFO,
			 LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
			 "3319 Rcv EDC payload len %d: x%x x%x x%x\n",
			 bytes_remain, be32_to_cpu(*ptr),
			 be32_to_cpu(*(ptr + 1)), be32_to_cpu(*(ptr + 2)));
@@ -9109,9 +9165,10 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	 * cycle through EDC diagnostic descriptors to find the
	 * congestion signaling capability descriptor
	 */
	while (bytes_remain && !rcv_cap_desc) {
	while (bytes_remain) {
		if (bytes_remain < FC_TLV_DESC_HDR_SZ) {
			lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT,
			lpfc_printf_log(phba, KERN_WARNING,
					LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
					"6464 Truncated TLV hdr on "
					"Diagnostic descriptor[%d]\n",
					desc_cnt);
@@ -9124,16 +9181,27 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
			if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) ||
			    FC_TLV_DESC_SZ_FROM_LENGTH(tlv) !=
				sizeof(struct fc_diag_lnkflt_desc)) {
				lpfc_printf_log(
					phba, KERN_WARNING, LOG_CGN_MGMT,
				lpfc_printf_log(phba, KERN_WARNING,
					LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
					"6465 Truncated Link Fault Diagnostic "
					"descriptor[%d]: %d vs 0x%zx 0x%zx\n",
					desc_cnt, bytes_remain,
					FC_TLV_DESC_SZ_FROM_LENGTH(tlv),
					sizeof(struct fc_diag_cg_sig_desc));
					sizeof(struct fc_diag_lnkflt_desc));
				goto out;
			}
			/* No action for Link Fault descriptor for now */
			plnkflt = (struct fc_diag_lnkflt_desc *)tlv;
			lpfc_printf_log(phba, KERN_INFO,
				LOG_ELS | LOG_LDS_EVENT,
				"4626 Link Fault Desc Data: x%08x len x%x "
				"da x%x dd x%x interval x%x\n",
				be32_to_cpu(plnkflt->desc_tag),
				be32_to_cpu(plnkflt->desc_len),
				be32_to_cpu(
					plnkflt->degrade_activate_threshold),
				be32_to_cpu(
					plnkflt->degrade_deactivate_threshold),
				be32_to_cpu(plnkflt->fec_degrade_interval));
			break;
		case ELS_DTAG_CG_SIGNAL_CAP:
			if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) ||
@@ -9160,11 +9228,11 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,

			lpfc_least_capable_settings(
				phba, (struct fc_diag_cg_sig_desc *)tlv);
			rcv_cap_desc = true;
			break;
		default:
			dtag_nm = lpfc_get_tlv_dtag_nm(dtag);
			lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT,
			lpfc_printf_log(phba, KERN_WARNING,
					LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT,
					"6467 unknown Diagnostic "
					"Descriptor[%d]: tag x%x (%s)\n",
					desc_cnt, dtag, dtag_nm);
+9 −1
Original line number Diff line number Diff line
@@ -1242,6 +1242,8 @@ lpfc_linkdown(struct lpfc_hba *phba)
			phba->trunk_link.link1.state = 0;
			phba->trunk_link.link2.state = 0;
			phba->trunk_link.link3.state = 0;
			phba->trunk_link.phy_lnk_speed =
						LPFC_LINK_SPEED_UNKNOWN;
			phba->sli4_hba.link_state.logical_speed =
						LPFC_LINK_SPEED_UNKNOWN;
		}
@@ -3794,6 +3796,9 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
		if (phba->cmf_active_mode != LPFC_CFG_OFF)
			lpfc_cmf_signal_init(phba);

		if (phba->lmt & LMT_64Gb)
			lpfc_read_lds_params(phba);

	} else if (attn_type == LPFC_ATT_LINK_DOWN ||
		   attn_type == LPFC_ATT_UNEXP_WWPN) {
		phba->fc_stat.LinkDown++;
@@ -4393,8 +4398,11 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
			rc = lpfc_issue_els_edc(vport, 0);
			lpfc_printf_log(phba, KERN_INFO,
					LOG_INIT | LOG_ELS | LOG_DISCOVERY,
					"4220 EDC issue error x%x, Data: x%x\n",
					"4220 Issue EDC status x%x Data x%x\n",
					rc, phba->cgn_init_reg_signal);
		} else if (phba->lmt & LMT_64Gb) {
			/* may send link fault capability descriptor */
			lpfc_issue_els_edc(vport, 0);
		} else {
			lpfc_issue_els_rdf(vport, 0);
		}
+11 −19
Original line number Diff line number Diff line
@@ -3484,9 +3484,10 @@ struct lpfc_sli4_parameters {

#define LPFC_SET_UE_RECOVERY		0x10
#define LPFC_SET_MDS_DIAGS		0x12
#define LPFC_SET_CGN_SIGNAL		0x1f
#define LPFC_SET_DUAL_DUMP		0x1e
#define LPFC_SET_CGN_SIGNAL		0x1f
#define LPFC_SET_ENABLE_MI		0x21
#define LPFC_SET_LD_SIGNAL		0x23
#define LPFC_SET_ENABLE_CMF		0x24
struct lpfc_mbx_set_feature {
	struct mbox_header header;
@@ -3517,13 +3518,17 @@ struct lpfc_mbx_set_feature {
#define lpfc_mbx_set_feature_cmf_SHIFT		0
#define lpfc_mbx_set_feature_cmf_MASK		0x00000001
#define lpfc_mbx_set_feature_cmf_WORD		word6
#define lpfc_mbx_set_feature_lds_qry_SHIFT	0
#define lpfc_mbx_set_feature_lds_qry_MASK	0x00000001
#define lpfc_mbx_set_feature_lds_qry_WORD	word6
#define LPFC_QUERY_LDS_OP		1
#define lpfc_mbx_set_feature_mi_SHIFT		0
#define lpfc_mbx_set_feature_mi_MASK		0x0000ffff
#define lpfc_mbx_set_feature_mi_WORD		word6
#define lpfc_mbx_set_feature_milunq_SHIFT	16
#define lpfc_mbx_set_feature_milunq_MASK	0x0000ffff
#define lpfc_mbx_set_feature_milunq_WORD	word6
	uint32_t word7;
	u32 word7;
#define lpfc_mbx_set_feature_UERP_SHIFT 0
#define lpfc_mbx_set_feature_UERP_MASK  0x0000ffff
#define lpfc_mbx_set_feature_UERP_WORD  word7
@@ -3537,6 +3542,8 @@ struct lpfc_mbx_set_feature {
#define lpfc_mbx_set_feature_CGN_acqe_freq_SHIFT 0
#define lpfc_mbx_set_feature_CGN_acqe_freq_MASK  0x000000ff
#define lpfc_mbx_set_feature_CGN_acqe_freq_WORD  word8
	u32 word9;
	u32 word10;
};


@@ -4314,7 +4321,7 @@ struct lpfc_acqe_cgn_signal {
struct lpfc_acqe_sli {
	uint32_t event_data1;
	uint32_t event_data2;
	uint32_t reserved;
	uint32_t event_data3;
	uint32_t trailer;
#define LPFC_SLI_EVENT_TYPE_PORT_ERROR		0x1
#define LPFC_SLI_EVENT_TYPE_OVER_TEMP		0x2
@@ -4327,6 +4334,7 @@ struct lpfc_acqe_sli {
#define LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN	0xF
#define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE	0x10
#define LPFC_SLI_EVENT_TYPE_CGN_SIGNAL		0x11
#define LPFC_SLI_EVENT_TYPE_RD_SIGNAL           0x12
};

/*
@@ -5050,22 +5058,6 @@ struct lpfc_grp_hdr {
	{ FPIN_CONGN_SEVERITY_ERROR,		"Alarm" },	\
}

/* EDC supports two descriptors.  When allocated, it is the
 * size of this structure plus each supported descriptor.
 */
struct lpfc_els_edc_req {
	struct fc_els_edc               edc;       /* hdr up to descriptors */
	struct fc_diag_cg_sig_desc      cgn_desc;  /* 1st descriptor */
};

/* Minimum structure defines for the EDC response.
 * Balance is in buffer.
 */
struct lpfc_els_edc_rsp {
	struct fc_els_edc_resp          edc_rsp;   /* hdr up to descriptors */
	struct fc_diag_cg_sig_desc      cgn_desc;  /* 1st descriptor */
};

/* Used for logging FPIN messages */
#define LPFC_FPIN_WWPN_LINE_SZ  128
#define LPFC_FPIN_WWPN_LINE_CNT 6
Loading