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

scsi: lpfc: Add support for the CM framework

Complete the enablement of the cm framework feature in the adapter. Perform
the following:

 - Detect the presence of the congestion management framework feature.

When the cm framework is present:

 - Issue the SET_FEATURE command to enable the feature.

 - Register the cm statistics buffer with the adapter.

 - Read the cm enablement buffer to determine the cm framework state for cm
   management.

When cm management is enabled:

 - Monitor all FPIN and congestion signalling events, incrementing
   counters.

 - Regularly sync with the adapter to communicate congestion events and to
   receive an rx request limit.

 - Monitor requests for rx data and ensure that no more than the
   adapter prescribed limit is issued on the link. If the limit is
   exceeded, SCSI and/or NVMe traffic is temporarily suspended.

 - Maintain the minute, hourly, daily statistics buffer.

 - Monitor for congestion enablement change events, causing a reread of the
   enablement buffer and acting on any change in enablement.

And:

 - Add teardown logic, including buffer deregistration, on adapter
   detachment or reset.

Link: https://lore.kernel.org/r/20210816162901.121235-10-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 daebf93f
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -550,6 +550,14 @@ struct lpfc_cgn_info {
#define LPFC_CGN_INFO_SZ	(sizeof(struct lpfc_cgn_info) -  \
				sizeof(uint32_t))

struct lpfc_cgn_stat {
	atomic64_t total_bytes;
	atomic64_t rcv_bytes;
	atomic64_t rx_latency;
#define LPFC_CGN_NOT_SENT	0xFFFFFFFFFFFFFFFFLL
	atomic_t rx_io_cnt;
};

struct lpfc_cgn_acqe_stat {
	atomic64_t alarm;
	atomic64_t warn;
@@ -1021,7 +1029,10 @@ struct lpfc_hba {
					 * capability
					 */
#define HBA_FLOGI_ISSUED	0x100000 /* FLOGI was issued */
#define HBA_CGN_RSVD1		0x200000 /* Reserved CGN flag */
#define HBA_CGN_DAY_WRAP	0x400000 /* HBA Congestion info day wraps */
#define HBA_DEFER_FLOGI		0x800000 /* Defer FLOGI till read_sparm cmpl */
#define HBA_SETUP		0x1000000 /* Signifies HBA setup is completed */
#define HBA_NEEDS_CFG_PORT	0x2000000 /* SLI3 - needs a CONFIG_PORT mbox */
#define HBA_HBEAT_INP		0x4000000 /* mbox HBEAT is in progress */
#define HBA_HBEAT_TMO		0x8000000 /* HBEAT initiated after timeout */
@@ -1272,6 +1283,7 @@ struct lpfc_hba {
	uint32_t total_iocbq_bufs;
	struct list_head active_rrq_list;
	spinlock_t hbalock;
	struct work_struct  unblock_request_work; /* SCSI layer unblock IOs */

	/* dma_mem_pools */
	struct dma_pool *lpfc_sg_dma_buf_pool;
@@ -1496,12 +1508,25 @@ struct lpfc_hba {
	uint64_t ktime_seg10_max;
#endif
	/* CMF objects */
	u32 cmf_active_mode;
#define LPFC_CFG_OFF		0

	struct lpfc_cgn_stat __percpu *cmf_stat;
	uint32_t cmf_interval_rate;  /* timer interval limit in ms */
	uint32_t cmf_timer_cnt;
#define LPFC_CMF_INTERVAL 90
	uint64_t cmf_link_byte_count;
	uint64_t cmf_max_line_rate;
	uint64_t cmf_max_bytes_per_interval;
	uint64_t cmf_last_sync_bw;
#define  LPFC_CMF_BLK_SIZE 512
	struct hrtimer cmf_timer;
	atomic_t cmf_bw_wait;
	atomic_t cmf_busy;
	atomic_t cmf_stop_io;      /* To block request and stop IO's */
	uint32_t cmf_active_mode;
	uint32_t cmf_info_per_interval;
#define LPFC_MAX_CMF_INFO 32
	struct timespec64 cmf_latency;  /* Interval congestion timestamp */
	uint32_t cmf_last_ts;   /* Interval congestion time (ms) */
	uint32_t cmf_active_info;

	/* Signal / FPIN handling for Congestion Mgmt */
	u8 cgn_reg_fpin;           /* Negotiated value from RDF */
@@ -1521,6 +1546,8 @@ struct lpfc_hba {
	u32 cgn_sig_freq;
	u32 cgn_acqe_cnt;

	uint64_t rx_block_cnt;

	/* Congestion parameters from flash */
	struct lpfc_cgn_param cgn_p;

+1 −0
Original line number Diff line number Diff line
@@ -7476,6 +7476,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	lpfc_enable_dpp_init(phba, lpfc_enable_dpp);
	lpfc_enable_mi_init(phba, lpfc_enable_mi);

	phba->cgn_p.cgn_param_mode = LPFC_CFG_OFF;
	phba->cmf_active_mode = LPFC_CFG_OFF;
	if (lpfc_fabric_cgn_frequency > EDC_CG_SIGFREQ_CNT_MAX ||
	   lpfc_fabric_cgn_frequency < EDC_CG_SIGFREQ_CNT_MIN)
+10 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *,
			   uint16_t, uint16_t, bool);
int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_congestion_buf(struct lpfc_hba *phba);
int lpfc_unreg_congestion_buf(struct lpfc_hba *phba);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
@@ -75,11 +76,17 @@ 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);
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);
void lpfc_cmf_stop(struct lpfc_hba *phba);
void lpfc_init_congestion_stat(struct lpfc_hba *phba);
void lpfc_init_congestion_buf(struct lpfc_hba *phba);
int lpfc_sli4_cgn_params_read(struct lpfc_hba *phba);
int lpfc_config_cgn_signal(struct lpfc_hba *phba);
int lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total);
void lpfc_unblock_requests(struct lpfc_hba *phba);
void lpfc_block_requests(struct lpfc_hba *phba);

void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -471,6 +478,9 @@ void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *);
void lpfc_create_static_vport(struct lpfc_hba *);
void lpfc_stop_hba_timers(struct lpfc_hba *);
void lpfc_stop_port(struct lpfc_hba *);
int lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t sz);
int lpfc_update_cmf_cmpl(struct lpfc_hba *phba, uint64_t val, uint32_t sz,
			 struct Scsi_Host *shost);
void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *);
void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t);
+69 −4
Original line number Diff line number Diff line
@@ -3333,9 +3333,11 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			lpfc_printf_vlog(vport, KERN_INFO,
					 LOG_ELS | LOG_CGN_MGMT,
					 "4677 Fabric RDF Notification Grant "
					 "Data: 0x%08x\n",
					 "Data: 0x%08x Reg: %x %x\n",
					 be32_to_cpu(
						prdf->reg_d1.desc_tags[i]));
						prdf->reg_d1.desc_tags[i]),
					 phba->cgn_reg_signal,
					 phba->cgn_reg_fpin);
	}

out:
@@ -3702,9 +3704,11 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
	prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION);

	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
			 "6444 Xmit RDF to remote NPORT x%x\n",
			 ndlp->nlp_DID);
			 "6444 Xmit RDF to remote NPORT x%x Reg: %x %x\n",
			 ndlp->nlp_DID, phba->cgn_reg_signal,
			 phba->cgn_reg_fpin);

	phba->cgn_fpin_frequency = LPFC_FPIN_INIT_FREQ;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1) {
@@ -3778,6 +3782,8 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
{
	u32 rsp_sig_cap = 0, drv_sig_cap = 0;
	u32 rsp_sig_freq_cyc = 0, rsp_sig_freq_scale = 0;
	struct lpfc_cgn_info *cp;
	u16 sig_freq;

	/* Get rsp signal and frequency capabilities.  */
	rsp_sig_cap = be32_to_cpu(pcgd->xmt_signal_capability);
@@ -3832,6 +3838,24 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
			phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN;
		}
	}

	if (!phba->cgn_i)
		return;

	/* Update signal frequency in congestion info buffer */
	cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;

	/* Frequency (in ms) Signal Warning/Signal Congestion Notifications
	 * are received by the HBA
	 */
	sig_freq = phba->cgn_sig_freq;

	if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY)
		cp->cgn_warn_freq = cpu_to_le16(sig_freq);
	if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
		cp->cgn_alarm_freq = cpu_to_le16(sig_freq);
		cp->cgn_warn_freq = cpu_to_le16(sig_freq);
	}
	return;

out_no_support:
@@ -9508,11 +9532,13 @@ lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
static int
lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
{
	struct lpfc_cgn_info *cp;
	struct fc_fn_congn_desc *cgn = (struct fc_fn_congn_desc *)tlv;
	const char *cgn_evt_str;
	u32 cgn_evt;
	const char *cgn_sev_str;
	u32 cgn_sev;
	uint16_t value;
	bool nm_log = false;
	int rc = 1;

@@ -9540,9 +9566,48 @@ lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
		switch (cgn_sev) {
		case FPIN_CONGN_SEVERITY_ERROR:
			/* Take action here for an Alarm event */
			if (phba->cmf_active_mode != LPFC_CFG_OFF) {
				if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) {
					/* Track of alarm cnt for cgn_info */
					atomic_inc(&phba->cgn_fabric_alarm_cnt);
					/* Track of alarm cnt for SYNC_WQE */
					atomic_inc(&phba->cgn_sync_alarm_cnt);
				}
				goto cleanup;
			}
			break;
		case FPIN_CONGN_SEVERITY_WARNING:
			/* Take action here for a Warning event */
			if (phba->cmf_active_mode != LPFC_CFG_OFF) {
				if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) {
					/* Track of warning cnt for cgn_info */
					atomic_inc(&phba->cgn_fabric_warn_cnt);
					/* Track of warning cnt for SYNC_WQE */
					atomic_inc(&phba->cgn_sync_warn_cnt);
				}
cleanup:
				/* Save frequency in ms */
				phba->cgn_fpin_frequency =
					be32_to_cpu(cgn->event_period);
				value = phba->cgn_fpin_frequency;
				if (phba->cgn_i) {
					cp = (struct lpfc_cgn_info *)
						phba->cgn_i->virt;
					if (phba->cgn_reg_fpin &
						LPFC_CGN_FPIN_ALARM)
						cp->cgn_alarm_freq =
							cpu_to_le16(value);
					if (phba->cgn_reg_fpin &
						LPFC_CGN_FPIN_WARN)
						cp->cgn_warn_freq =
							cpu_to_le16(value);
				}

				/* Don't deliver to upper layer since
				 * driver took action on this tlv.
				 */
				rc = 0;
			}
			break;
		}
		break;
+4 −0
Original line number Diff line number Diff line
@@ -3647,6 +3647,10 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
					phba->wait_4_mlo_maint_flg);
		}
		lpfc_mbx_process_link_up(phba, la);

		if (phba->cmf_active_mode != LPFC_CFG_OFF)
			lpfc_cmf_signal_init(phba);

	} else if (attn_type == LPFC_ATT_LINK_DOWN ||
		   attn_type == LPFC_ATT_UNEXP_WWPN) {
		phba->fc_stat.LinkDown++;
Loading