Commit 84ed362a authored by Michael Hernandez's avatar Michael Hernandez Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Dual FCP-NVMe target port support

Some storage arrays advertise FCP LUNs and NVMe namespaces behind the same
WWN.  The driver now offers a user option by way of NVRAM parameter to
allow users to choose, on a per port basis, the kind of FC-4 type they
would like to prioritize for login.

Link: https://lore.kernel.org/r/20190912180918.6436-9-hmadhani@marvell.com


Signed-off-by: default avatarMichael Hernandez <mhernandez@marvell.com>
Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent a3a8d13f
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -2277,7 +2277,7 @@ typedef struct {
	uint8_t fabric_port_name[WWN_SIZE];
	uint16_t fp_speed;
	uint8_t fc4_type;
	uint8_t fc4f_nvme;	/* nvme fc4 feature bits */
	uint8_t fc4_features;
} sw_info_t;

/* FCP-4 types */
@@ -2445,7 +2445,7 @@ typedef struct fc_port {
	u32 supported_classes;

	uint8_t fc4_type;
	uint8_t	fc4f_nvme;
	uint8_t fc4_features;
	uint8_t scan_state;

	unsigned long last_queue_full;
@@ -2476,6 +2476,9 @@ typedef struct fc_port {
	u16 n2n_chip_reset;
} fc_port_t;

#define FC4_PRIORITY_NVME	0
#define FC4_PRIORITY_FCP	1

#define QLA_FCPORT_SCAN		1
#define QLA_FCPORT_FOUND	2

@@ -4291,6 +4294,8 @@ struct qla_hw_data {
	atomic_t        nvme_active_aen_cnt;
	uint16_t        nvme_last_rptd_aen;             /* Last recorded aen count */

	uint8_t fc4_type_priority;

	atomic_t zio_threshold;
	uint16_t last_zio_threshold;

@@ -4816,6 +4821,23 @@ struct sff_8247_a0 {
	 ha->current_topology == ISP_CFG_N || \
	 !ha->current_topology)

#define NVME_TYPE(fcport) \
	(fcport->fc4_type & FS_FC4TYPE_NVME) \

#define FCP_TYPE(fcport) \
	(fcport->fc4_type & FS_FC4TYPE_FCP) \

#define NVME_ONLY_TARGET(fcport) \
	(NVME_TYPE(fcport) && !FCP_TYPE(fcport))  \

#define NVME_FCP_TARGET(fcport) \
	(FCP_TYPE(fcport) && NVME_TYPE(fcport)) \

#define NVME_TARGET(ha, fcport) \
	((NVME_FCP_TARGET(fcport) && \
	(ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \
	NVME_ONLY_TARGET(fcport)) \

#include "qla_target.h"
#include "qla_gbl.h"
#include "qla_dbg.h"
+2 −0
Original line number Diff line number Diff line
@@ -2101,4 +2101,6 @@ struct qla_fcp_prio_cfg {
#define FA_FLASH_LAYOUT_ADDR_83	(0x3F1000/4)
#define FA_FLASH_LAYOUT_ADDR_28	(0x11000/4)

#define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET	0x196

#endif
+25 −17
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
		    WWN_SIZE);

		fcport->fc4_type = (ct_rsp->rsp.ga_nxt.fc4_types[2] & BIT_0) ?
		    FC4_TYPE_FCP_SCSI : FC4_TYPE_OTHER;
		    FS_FC4TYPE_FCP : FC4_TYPE_OTHER;

		if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE &&
		    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
@@ -2887,7 +2887,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
	struct ct_sns_req	*ct_req;
	struct ct_sns_rsp	*ct_rsp;
	struct qla_hw_data *ha = vha->hw;
	uint8_t fcp_scsi_features = 0;
	uint8_t fcp_scsi_features = 0, nvme_features = 0;
	struct ct_arg arg;

	for (i = 0; i < ha->max_fibre_devices; i++) {
@@ -2933,14 +2933,19 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
			   ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
			fcp_scsi_features &= 0x0f;

			if (fcp_scsi_features)
				list[i].fc4_type = FC4_TYPE_FCP_SCSI;
			else
				list[i].fc4_type = FC4_TYPE_OTHER;
			if (fcp_scsi_features) {
				list[i].fc4_type = FS_FC4TYPE_FCP;
				list[i].fc4_features = fcp_scsi_features;
			}

			list[i].fc4f_nvme =
			nvme_features =
			    ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];
			list[i].fc4f_nvme &= 0xf;
			nvme_features &= 0xf;

			if (nvme_features) {
				list[i].fc4_type |= FS_FC4TYPE_NVME;
				list[i].fc4_features = nvme_features;
			}
		}

		/* Last device exit. */
@@ -3435,6 +3440,8 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res)
	fc_port_t *fcport = sp->fcport;
	struct ct_sns_rsp *ct_rsp;
	struct event_arg ea;
	uint8_t fc4_scsi_feat;
	uint8_t fc4_nvme_feat;

	ql_dbg(ql_dbg_disc, vha, 0x2133,
	       "Async done-%s res %x ID %x. %8phC\n",
@@ -3442,24 +3449,25 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res)

	fcport->flags &= ~FCF_ASYNC_SENT;
	ct_rsp = &fcport->ct_desc.ct_sns->p.rsp;
	fc4_scsi_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
	fc4_nvme_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];

	/*
	 * FC-GS-7, 5.2.3.12 FC-4 Features - format
	 * The format of the FC-4 Features object, as defined by the FC-4,
	 * Shall be an array of 4-bit values, one for each type code value
	 */
	if (!res) {
		if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) {
		if (fc4_scsi_feat & 0xf) {
			/* w1 b00:03 */
			fcport->fc4_type =
			    ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
			fcport->fc4_type &= 0xf;
			fcport->fc4_type = FS_FC4TYPE_FCP;
			fcport->fc4_features = fc4_scsi_feat & 0xf;
		}

		if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) {
		if (fc4_nvme_feat & 0xf) {
			/* w5 [00:03]/28h */
			fcport->fc4f_nvme =
			    ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET];
			fcport->fc4f_nvme &= 0xf;
			fcport->fc4_type |= FS_FC4TYPE_NVME;
			fcport->fc4_features = fc4_nvme_feat & 0xf;
		}
	}

+37 −27
Original line number Diff line number Diff line
@@ -328,7 +328,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
	else
		lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;

	if (fcport->fc4f_nvme)
	if (NVME_TARGET(vha->hw, fcport))
		lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;

	ql_dbg(ql_dbg_disc, vha, 0x2072,
@@ -726,19 +726,17 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,

		loop_id = le16_to_cpu(e->nport_handle);
		loop_id = (loop_id & 0x7fff);
		if  (fcport->fc4f_nvme)
		if (NVME_TARGET(vha->hw, fcport))
			current_login_state = e->current_login_state >> 4;
		else
			current_login_state = e->current_login_state & 0xf;


		ql_dbg(ql_dbg_disc, vha, 0x20e2,
		    "%s found %8phC CLS [%x|%x] nvme %d ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n",
		    "%s found %8phC CLS [%x|%x] fc4_type %d ID[%06x|%06x] lid[%d|%d]\n",
		    __func__, fcport->port_name,
		    e->current_login_state, fcport->fw_login_state,
		    fcport->fc4f_nvme, id.b.domain, id.b.area, id.b.al_pa,
		    fcport->d_id.b.domain, fcport->d_id.b.area,
		    fcport->d_id.b.al_pa, loop_id, fcport->loop_id);
		    fcport->fc4_type, id.b24, fcport->d_id.b24,
		    loop_id, fcport->loop_id);

		switch (fcport->disc_state) {
		case DSC_DELETE_PEND:
@@ -1225,13 +1223,13 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport)
	sp->done = qla2x00_async_prli_sp_done;
	lio->u.logio.flags = 0;

	if  (fcport->fc4f_nvme)
	if (NVME_TARGET(vha->hw, fcport))
		lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI;

	ql_dbg(ql_dbg_disc, vha, 0x211b,
	    "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n",
	    fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24,
	    fcport->login_retry, fcport->fc4f_nvme ? "nvme" : "fc");
	    fcport->login_retry, NVME_TARGET(vha->hw, fcport) ? "nvme" : "fc");

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS) {
@@ -1382,14 +1380,14 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
	fcport->flags &= ~FCF_ASYNC_SENT;

	ql_dbg(ql_dbg_disc, vha, 0x20d2,
	    "%s %8phC DS %d LS %d nvme %x rc %d\n", __func__, fcport->port_name,
	    fcport->disc_state, pd->current_login_state, fcport->fc4f_nvme,
	    ea->rc);
	    "%s %8phC DS %d LS %d fc4_type %x rc %d\n", __func__,
	    fcport->port_name, fcport->disc_state, pd->current_login_state,
	    fcport->fc4_type, ea->rc);

	if (fcport->disc_state == DSC_DELETE_PEND)
		return;

	if (fcport->fc4f_nvme)
	if (NVME_TARGET(vha->hw, fcport))
		ls = pd->current_login_state >> 4;
	else
		ls = pd->current_login_state & 0xf;
@@ -1578,7 +1576,8 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
				ql_dbg(ql_dbg_disc, vha, 0x2118,
				    "%s %d %8phC post %s PRLI\n",
				    __func__, __LINE__, fcport->port_name,
				    fcport->fc4f_nvme ? "NVME" : "FC");
				    NVME_TARGET(vha->hw, fcport) ? "NVME" :
				    "FC");
				qla24xx_post_prli_work(vha, fcport);
			}
			break;
@@ -1860,13 +1859,22 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
			break;
		}

		if (ea->fcport->fc4f_nvme) {
		/*
		 * Retry PRLI with other FC-4 type if failure occurred on dual
		 * FCP/NVMe port
		 */
		if (NVME_FCP_TARGET(ea->fcport)) {
			if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME)
				ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME;
			else
				ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP;
			ql_dbg(ql_dbg_disc, vha, 0x2118,
				"%s %d %8phC post fc4 prli\n",
				__func__, __LINE__, ea->fcport->port_name);
			ea->fcport->fc4f_nvme = 0;
				"%s %d %8phC post %s prli\n",
				__func__, __LINE__, ea->fcport->port_name,
				(ea->fcport->fc4_type & FS_FC4TYPE_NVME) ?
				"NVMe" : "FCP");
			qla24xx_post_prli_work(vha, ea->fcport);
			return;
			break;
		}

		/* at this point both PRLI NVME & PRLI FCP failed */
@@ -1952,7 +1960,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
		 * force a relogin attempt via implicit LOGO, PLOGI, and PRLI
		 * requests.
		 */
		if (ea->fcport->fc4f_nvme) {
		if (NVME_TARGET(vha->hw, ea->fcport)) {
			ql_dbg(ql_dbg_disc, vha, 0x2117,
				"%s %d %8phC post prli\n",
				__func__, __LINE__, ea->fcport->port_name);
@@ -5382,7 +5390,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)

	qla2x00_iidma_fcport(vha, fcport);

	if (fcport->fc4f_nvme) {
	if (NVME_TARGET(vha->hw, fcport)) {
		qla_nvme_register_remote(vha, fcport);
		fcport->disc_state = DSC_LOGIN_COMPLETE;
		qla2x00_set_fcport_state(fcport, FCS_ONLINE);
@@ -5710,11 +5718,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
				new_fcport->fc4_type = swl[swl_idx].fc4_type;

				new_fcport->nvme_flag = 0;
				new_fcport->fc4f_nvme = 0;
				if (vha->flags.nvme_enabled &&
				    swl[swl_idx].fc4f_nvme) {
					new_fcport->fc4f_nvme =
					    swl[swl_idx].fc4f_nvme;
				    swl[swl_idx].fc4_type & FS_FC4TYPE_NVME) {
					ql_log(ql_log_info, vha, 0x2131,
					    "FOUND: NVME port %8phC as FC Type 28h\n",
					    new_fcport->port_name);
@@ -5770,7 +5775,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)

		/* Bypass ports whose FCP-4 type is not FCP_SCSI */
		if (ql2xgffidenable &&
		    (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI &&
		    (!(new_fcport->fc4_type & FS_FC4TYPE_FCP) &&
		    new_fcport->fc4_type != FC4_TYPE_UNKNOWN))
			continue;

@@ -5839,7 +5844,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
			break;
		}

		if (fcport->fc4f_nvme) {
		if (NVME_TARGET(vha->hw, fcport)) {
			if (fcport->disc_state == DSC_DELETE_PEND) {
				fcport->disc_state = DSC_GNL;
				vha->fcport_count--;
@@ -8514,6 +8519,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
	/* N2N: driver will initiate Login instead of FW */
	icb->firmware_options_3 |= BIT_8;

	/* Determine NVMe/FCP priority for target ports */
	ha->fc4_type_priority = qla2xxx_get_fc4_priority(vha);
	ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n",
	    ha->fc4_type_priority & BIT_0 ? "FCP" : "NVMe");

	if (rval) {
		ql_log(ql_log_warn, vha, 0x0076,
		    "NVRAM configuration failed.\n");
+12 −0
Original line number Diff line number Diff line
@@ -307,3 +307,15 @@ qla_83xx_start_iocbs(struct qla_qpair *qpair)

	WRT_REG_DWORD(req->req_q_in, req->ring_index);
}

static inline int
qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
{
	uint32_t data;

	data =
	    ((uint8_t *)vha->hw->nvram)[NVRAM_DUAL_FCP_NVME_FLAG_OFFSET];


	return ((data >> 6) & BIT_0);
}
Loading