Commit b0f18eee authored by Andrew Vasquez's avatar Andrew Vasquez Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Update BPM enablement semantics.

commit e4e3a2ce ("scsi: qla2xxx: Add ability to autodetect SFP
type") takes a heavy handed approach to BPM (Buffer Plus Management)
enablement:

1) During hardware initialization, if an LR-capable transceiver is
   recognized, the driver schedules a disruptive post-initialization
   chip-reset (ISP-ABORT) to allow the BPM settings to be sent to the
   firmware.  This chip-reset will result in (short-term) path-loss to
   all fc-rports and their attached SCSI devices.

2) LR-detection is triggered during any link-up event, resulting in a
   refresh and potential chip-reset

Based on firmware-team guidance, upon LR-capable transceiver
recognition, the driver's hardware initialization code will now
re-execute firmware with the new BPM settings, then continue on with
driver initialization.  To address the second issue, the driver
performs LR-capable detection upon the driver receiving a
transceiver-insertion asynchronous event from firmware.  No short-term
path loss is needed with this new semantic.

Link: https://lore.kernel.org/r/20200226224022.24518-10-hmadhani@marvell.com


Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarAndrew Vasquez <andrewv@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent ce1ee122
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -1049,6 +1049,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
#define MBA_TEMPERATURE_ALERT	0x8070	/* Temperature Alert */
#define MBA_DPORT_DIAGNOSTICS	0x8080	/* D-port Diagnostics */
#define MBA_TRANS_INSERT	0x8130	/* Transceiver Insertion */
#define MBA_TRANS_REMOVE	0x8131	/* Transceiver Removal */
#define MBA_FW_INIT_FAILURE	0x8401	/* Firmware initialization failure */
#define MBA_MIRROR_LUN_CHANGE	0x8402	/* Mirror LUN State Change
					   Notification */
@@ -3802,8 +3803,8 @@ struct qla_hw_data {
		uint32_t	fw_started:1;
		uint32_t	fw_init_done:1;

		uint32_t	detected_lr_sfp:1;
		uint32_t	using_lr_setting:1;
		uint32_t	lr_detected:1;

		uint32_t	rida_fmt2:1;
		uint32_t	purge_mbox:1;
		uint32_t        n2n_bigger:1;
@@ -3812,7 +3813,7 @@ struct qla_hw_data {
	} flags;

	uint16_t max_exchg;
	uint16_t long_range_distance;	/* 32G & above */
	uint16_t lr_distance;	/* 32G & above */
#define LR_DISTANCE_5K  1
#define LR_DISTANCE_10K 0

@@ -4971,11 +4972,14 @@ struct sff_8247_a0 {
	u8 resv2[128];
};

#define AUTO_DETECT_SFP_SUPPORT(_vha)\
	(ql2xautodetectsfp && !_vha->vp_idx &&		\
	(IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\
	IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
	 IS_QLA28XX(_vha->hw)))
/* BPM -- Buffer Plus Management support. */
#define IS_BPM_CAPABLE(ha) \
	(IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
	 IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_BPM_RANGE_CAPABLE(ha) \
	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_BPM_ENABLED(vha) \
	(ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw))

#define FLASH_SEMAPHORE_REGISTER_ADDR   0x00101016

+1 −2
Original line number Diff line number Diff line
@@ -1867,9 +1867,8 @@ struct access_chip_rsp_84xx {

/* LR Distance bit positions */
#define LR_DIST_NV_POS		2
#define LR_DIST_NV_MASK		0xf
#define LR_DIST_FW_POS		12
#define LR_DIST_FW_SHIFT	(LR_DIST_FW_POS - LR_DIST_NV_POS)
#define LR_DIST_FW_FIELD(x)	((x) << LR_DIST_FW_SHIFT & 0xf000)

/* FAC semaphore defines */
#define FAC_SEMAPHORE_UNLOCK    0
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *,
int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*,
    void *, u8);
int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
int qla24xx_detect_sfp(scsi_qla_host_t *vha);
int qla24xx_detect_sfp(scsi_qla_host_t *);
int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);

extern void qla28xx_get_aux_images(struct scsi_qla_host *,
+64 −26
Original line number Diff line number Diff line
@@ -3550,53 +3550,77 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha)
}


/*
 * Return Code:
 *   QLA_SUCCESS: no action
 *   QLA_INTERFACE_ERROR: SFP is not there.
 *   QLA_FUNCTION_FAILED: detected New SFP
/**
 * qla24xx_detect_sfp()
 *
 * @vha: adapter state pointer.
 *
 * @return
 *	0 -- Configure firmware to use short-range settings -- normal
 *	     buffer-to-buffer credits.
 *
 *	1 -- Configure firmware to use long-range settings -- extra
 *	     buffer-to-buffer credits should be allocated with
 *	     ha->lr_distance containing distance settings from NVRAM or SFP
 *	     (if supported).
 */
int
qla24xx_detect_sfp(scsi_qla_host_t *vha)
{
	int rc = QLA_SUCCESS;
	int rc, used_nvram;
	struct sff_8247_a0 *a;
	struct qla_hw_data *ha = vha->hw;

	if (!AUTO_DETECT_SFP_SUPPORT(vha))
	struct nvram_81xx *nv = ha->nvram;
#define LR_DISTANCE_UNKNOWN	2
	static const char * const types[] = { "Short", "Long" };
	static const char * const lengths[] = { "(10km)", "(5km)", "" };
	u8 ll = 0;

	/* Seed with NVRAM settings. */
	used_nvram = 0;
	ha->flags.lr_detected = 0;
	if (IS_BPM_RANGE_CAPABLE(ha) &&
	    (nv->enhanced_features & NEF_LR_DIST_ENABLE)) {
		used_nvram = 1;
		ha->flags.lr_detected = 1;
		ha->lr_distance =
		    (nv->enhanced_features >> LR_DIST_NV_POS)
		     & LR_DIST_NV_MASK;
	}

	if (!IS_BPM_ENABLED(vha))
		goto out;

	/* Determine SR/LR capabilities of SFP/Transceiver. */
	rc = qla2x00_read_sfp_dev(vha, NULL, 0);
	if (rc)
		goto out;

	used_nvram = 0;
	a = (struct sff_8247_a0 *)vha->hw->sfp_data;
	qla2xxx_print_sfp_info(vha);

	if (a->fc_ll_cc7 & FC_LL_VL || a->fc_ll_cc7 & FC_LL_L) {
		/* long range */
		ha->flags.detected_lr_sfp = 1;
	ha->flags.lr_detected = 0;
	ll = a->fc_ll_cc7;
	if (ll & FC_LL_VL || ll & FC_LL_L) {
		/* Long range, track length. */
		ha->flags.lr_detected = 1;

		if (a->length_km > 5 || a->length_100m > 50)
			ha->long_range_distance = LR_DISTANCE_10K;
			ha->lr_distance = LR_DISTANCE_10K;
		else
			ha->long_range_distance = LR_DISTANCE_5K;

		if (ha->flags.detected_lr_sfp != ha->flags.using_lr_setting)
			ql_dbg(ql_dbg_async, vha, 0x507b,
			    "Detected Long Range SFP.\n");
	} else {
		/* short range */
		ha->flags.detected_lr_sfp = 0;
		if (ha->flags.using_lr_setting)
			ql_dbg(ql_dbg_async, vha, 0x5084,
			    "Detected Short Range SFP.\n");
			ha->lr_distance = LR_DISTANCE_5K;
	}

	if (!vha->flags.init_done)
		rc = QLA_SUCCESS;
out:
	return rc;
	ql_dbg(ql_dbg_async, vha, 0x507b,
	    "SFP detect: %s-Range SFP %s (nvr=%x ll=%x lr=%x lrd=%x).\n",
	    types[ha->flags.lr_detected],
	    ha->flags.lr_detected ? lengths[ha->lr_distance] :
	       lengths[LR_DISTANCE_UNKNOWN],
	    used_nvram, ll, ha->flags.lr_detected, ha->lr_distance);
	return ha->flags.lr_detected;
}

/**
@@ -3614,6 +3638,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
	unsigned long flags;
	uint16_t fw_major_version;
	int done_once = 0;

	if (IS_P3P_TYPE(ha)) {
		rval = ha->isp_ops->load_risc(vha, &srisc_address);
@@ -3634,6 +3659,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)

	qla81xx_mpi_sync(vha);

execute_fw_with_lr:
	/* Load firmware sequences */
	rval = ha->isp_ops->load_risc(vha, &srisc_address);
	if (rval == QLA_SUCCESS) {
@@ -3655,7 +3681,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
			rval = qla2x00_execute_fw(vha, srisc_address);
			/* Retrieve firmware information. */
			if (rval == QLA_SUCCESS) {
				qla24xx_detect_sfp(vha);
				/* Enable BPM support? */
				if (!done_once++ && qla24xx_detect_sfp(vha)) {
					ql_dbg(ql_dbg_init, vha, 0x00ca,
					    "Re-starting firmware -- BPM.\n");
					/* Best-effort - re-init. */
					ha->isp_ops->reset_chip(vha);
					ha->isp_ops->chip_diag(vha);
					goto execute_fw_with_lr;
				}

				if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
				    IS_QLA28XX(ha)) &&
@@ -3932,6 +3966,10 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
	if (ql2xrdpenable)
		ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;

	/* Enable Async 8130/8131 events -- transceiver insertion/removal */
	if (IS_BPM_RANGE_CAPABLE(ha))
		ha->fw_options[3] |= BIT_10;

	ql_dbg(ql_dbg_init, vha, 0x00e8,
	    "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n",
	    __func__, ha->fw_options[1], ha->fw_options[2],
+5 −4
Original line number Diff line number Diff line
@@ -960,10 +960,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);

		if (AUTO_DETECT_SFP_SUPPORT(vha)) {
			set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
			qla2xxx_wake_dpc(vha);
		}
		break;

	case MBA_LOOP_DOWN:		/* Loop Down Event */
@@ -1436,6 +1432,11 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
	case MBA_TRANS_INSERT:
		ql_dbg(ql_dbg_async, vha, 0x5091,
		    "Transceiver Insertion: %04x\n", mb[1]);
		set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
		break;

	case MBA_TRANS_REMOVE:
		ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n");
		break;

	default:
Loading