Commit 44d01857 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: edif: Add encryption to I/O path

Some FC adapters from Marvell offer the ability to encrypt data in flight
(EDIF). This feature requires an application to act as an authenticator.

After the completion of PLOGI, both sides have authenticated and PRLI
completed, encrypted I/Os are allowed to proceed.

 - Use new firmware API to encrypt traffic on the wire

 - Add driver parameter to enable|disable EDIF feature

   # modprobe qla2xxx ql2xsecenable=1

Link: https://lore.kernel.org/r/20210624052606.21613-10-njavali@marvell.com


Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Co-developed-by: default avatarLarry Wisneski <Larry.Wisneski@marvell.com>
Signed-off-by: default avatarLarry Wisneski <Larry.Wisneski@marvell.com>
Co-developed-by: default avatarDuane Grigsby <duane.grigsby@marvell.com>
Signed-off-by: default avatarDuane Grigsby <duane.grigsby@marvell.com>
Co-developed-by: default avatarRick Hicksted Jr <rhicksted@marvell.com>
Signed-off-by: default avatarRick Hicksted Jr <rhicksted@marvell.com>
Signed-off-by: default avatarQuinn Tran <qutran@marvell.com>
Signed-off-by: default avatarNilesh Javali <njavali@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7a09e8d9
Loading
Loading
Loading
Loading
+296 −41
Original line number Diff line number Diff line
@@ -547,7 +547,6 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
	}

	list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
		if ((fcport->flags & FCF_FCSP_DEVICE)) {
		ql_dbg(ql_dbg_edif, vha, 0xf084,
		    "%s: sess %p %8phC lid %#04x s_id %06x logout %d\n",
		    __func__, fcport, fcport->port_name,
@@ -563,15 +562,7 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
		if (atomic_read(&vha->loop_state) == LOOP_DOWN)
			break;

			if (!fcport->edif.secured_login)
				continue;

		fcport->edif.app_started = 1;
			if (fcport->edif.app_stop ||
			    (fcport->disc_state != DSC_LOGIN_COMPLETE &&
			     fcport->disc_state != DSC_LOGIN_PEND &&
			     fcport->disc_state != DSC_DELETED)) {
				/* no activity */
		fcport->edif.app_stop = 0;

		ql_dbg(ql_dbg_edif, vha, 0x911e,
@@ -579,10 +570,8 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
		    __func__, fcport->port_name);
		fcport->edif.app_sess_online = 1;
		qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 0);
			}
		qla_edif_sa_ctl_init(vha, fcport);
	}
	}

	if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
		/* mark as active since an app is now present */
@@ -925,6 +914,9 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
			if (tdid.b24 != 0 && tdid.b24 != fcport->d_id.b24)
				continue;

			app_reply->ports[pcnt].rekey_count =
				fcport->edif.rekey_cnt;

			app_reply->ports[pcnt].remote_type =
				VND_CMD_RTYPE_UNKNOWN;
			if (fcport->port_type & (FCT_NVME_TARGET | FCT_TARGET))
@@ -1076,8 +1068,8 @@ qla_edif_app_mgmt(struct bsg_job *bsg_job)
	if (!vha->hw->flags.edif_enabled ||
		test_bit(VPORT_DELETE, &vha->dpc_flags)) {
		ql_dbg(ql_dbg_edif, vha, 0x911d,
		    "%s edif not enabled or vp delete. bsg ptr done %p\n",
		    __func__, bsg_job);
		    "%s edif not enabled or vp delete. bsg ptr done %p. dpc_flags %lx\n",
		    __func__, bsg_job, vha->dpc_flags);

		SET_DID_STATUS(bsg_reply->result, DID_ERROR);
		goto done;
@@ -2227,16 +2219,10 @@ void qla24xx_sa_update_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
		sa_update_iocb->sa_control |= SA_CNTL_KEY256;
		for (itr = 0; itr < 32; itr++)
			sa_update_iocb->sa_key[itr] = sa_frame->sa_key[itr];

		ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x921f, "%s 256 sa key=%32phN\n",
		    __func__, sa_update_iocb->sa_key);
	} else {
		sa_update_iocb->sa_control |= SA_CNTL_KEY128;
		for (itr = 0; itr < 16; itr++)
			sa_update_iocb->sa_key[itr] = sa_frame->sa_key[itr];

		ql_dbg(ql_dbg_edif +  ql_dbg_verbose, vha, 0x921f, "%s 128 sa key=%16phN\n",
		    __func__, sa_update_iocb->sa_key);
	}

	ql_dbg(ql_dbg_edif, vha, 0x921d,
@@ -2693,6 +2679,275 @@ qla28xx_sa_update_iocb_entry(scsi_qla_host_t *v, struct req_que *req,
	sp->done(sp, 0);
}

/**
 * qla28xx_start_scsi_edif() - Send a SCSI type 6 command to the ISP
 * @sp: command to send to the ISP
 *
 * Return: non-zero if a failure occurred, else zero.
 */
int
qla28xx_start_scsi_edif(srb_t *sp)
{
	int             nseg;
	unsigned long   flags;
	struct scsi_cmnd *cmd;
	uint32_t        *clr_ptr;
	uint32_t        index, i;
	uint32_t        handle;
	uint16_t        cnt;
	int16_t        req_cnt;
	uint16_t        tot_dsds;
	__be32 *fcp_dl;
	uint8_t additional_cdb_len;
	struct ct6_dsd *ctx;
	struct scsi_qla_host *vha = sp->vha;
	struct qla_hw_data *ha = vha->hw;
	struct cmd_type_6 *cmd_pkt;
	struct dsd64	*cur_dsd;
	uint8_t		avail_dsds = 0;
	struct scatterlist *sg;
	struct req_que *req = sp->qpair->req;
	spinlock_t *lock = sp->qpair->qp_lock_ptr;

	/* Setup device pointers. */
	cmd = GET_CMD_SP(sp);

	/* So we know we haven't pci_map'ed anything yet */
	tot_dsds = 0;

	/* Send marker if required */
	if (vha->marker_needed != 0) {
		if (qla2x00_marker(vha, sp->qpair, 0, 0, MK_SYNC_ALL) !=
			QLA_SUCCESS) {
			ql_log(ql_log_warn, vha, 0x300c,
			    "qla2x00_marker failed for cmd=%p.\n", cmd);
			return QLA_FUNCTION_FAILED;
		}
		vha->marker_needed = 0;
	}

	/* Acquire ring specific lock */
	spin_lock_irqsave(lock, flags);

	/* Check for room in outstanding command list. */
	handle = req->current_outstanding_cmd;
	for (index = 1; index < req->num_outstanding_cmds; index++) {
		handle++;
		if (handle == req->num_outstanding_cmds)
			handle = 1;
		if (!req->outstanding_cmds[handle])
			break;
	}
	if (index == req->num_outstanding_cmds)
		goto queuing_error;

	/* Map the sg table so we have an accurate count of sg entries needed */
	if (scsi_sg_count(cmd)) {
		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
		    scsi_sg_count(cmd), cmd->sc_data_direction);
		if (unlikely(!nseg))
			goto queuing_error;
	} else {
		nseg = 0;
	}

	tot_dsds = nseg;
	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
	if (req->cnt < (req_cnt + 2)) {
		cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr :
		    rd_reg_dword(req->req_q_out);
		if (req->ring_index < cnt)
			req->cnt = cnt - req->ring_index;
		else
			req->cnt = req->length -
			    (req->ring_index - cnt);
		if (req->cnt < (req_cnt + 2))
			goto queuing_error;
	}

	ctx = sp->u.scmd.ct6_ctx =
	    mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
	if (!ctx) {
		ql_log(ql_log_fatal, vha, 0x3010,
		    "Failed to allocate ctx for cmd=%p.\n", cmd);
		goto queuing_error;
	}

	memset(ctx, 0, sizeof(struct ct6_dsd));
	ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool,
	    GFP_ATOMIC, &ctx->fcp_cmnd_dma);
	if (!ctx->fcp_cmnd) {
		ql_log(ql_log_fatal, vha, 0x3011,
		    "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
		goto queuing_error;
	}

	/* Initialize the DSD list and dma handle */
	INIT_LIST_HEAD(&ctx->dsd_list);
	ctx->dsd_use_cnt = 0;

	if (cmd->cmd_len > 16) {
		additional_cdb_len = cmd->cmd_len - 16;
		if ((cmd->cmd_len % 4) != 0) {
			/*
			 * SCSI command bigger than 16 bytes must be
			 * multiple of 4
			 */
			ql_log(ql_log_warn, vha, 0x3012,
			    "scsi cmd len %d not multiple of 4 for cmd=%p.\n",
			    cmd->cmd_len, cmd);
			goto queuing_error_fcp_cmnd;
		}
		ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
	} else {
		additional_cdb_len = 0;
		ctx->fcp_cmnd_len = 12 + 16 + 4;
	}

	cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
	cmd_pkt->handle = make_handle(req->id, handle);

	/*
	 * Zero out remaining portion of packet.
	 * tagged queuing modifier -- default is TSK_SIMPLE (0).
	 */
	clr_ptr = (uint32_t *)cmd_pkt + 2;
	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);

	/* No data transfer */
	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
		cmd_pkt->byte_count = cpu_to_le32(0);
		goto no_dsds;
	}

	/* Set transfer direction */
	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
		cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA);
		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
		vha->qla_stats.output_requests++;
		sp->fcport->edif.tx_bytes += scsi_bufflen(cmd);
	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
		vha->qla_stats.input_requests++;
		sp->fcport->edif.rx_bytes += scsi_bufflen(cmd);
	}

	cmd_pkt->control_flags |= cpu_to_le16(CF_EN_EDIF);
	cmd_pkt->control_flags &= ~(cpu_to_le16(CF_NEW_SA));

	/* One DSD is available in the Command Type 6 IOCB */
	avail_dsds = 1;
	cur_dsd = &cmd_pkt->fcp_dsd;

	/* Load data segments */
	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
		dma_addr_t      sle_dma;
		cont_a64_entry_t *cont_pkt;

		/* Allocate additional continuation packets? */
		if (avail_dsds == 0) {
			/*
			 * Five DSDs are available in the Continuation
			 * Type 1 IOCB.
			 */
			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
			cur_dsd = cont_pkt->dsd;
			avail_dsds = 5;
		}

		sle_dma = sg_dma_address(sg);
		put_unaligned_le64(sle_dma, &cur_dsd->address);
		cur_dsd->length = cpu_to_le32(sg_dma_len(sg));
		cur_dsd++;
		avail_dsds--;
	}

no_dsds:
	/* Set NPORT-ID and LUN number*/
	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
	cmd_pkt->vp_index = sp->vha->vp_idx;

	cmd_pkt->entry_type = COMMAND_TYPE_6;

	/* Set total data segment count. */
	cmd_pkt->entry_count = (uint8_t)req_cnt;

	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));

	/* build FCP_CMND IU */
	int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun);
	ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;

	if (cmd->sc_data_direction == DMA_TO_DEVICE)
		ctx->fcp_cmnd->additional_cdb_len |= 1;
	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
		ctx->fcp_cmnd->additional_cdb_len |= 2;

	/* Populate the FCP_PRIO. */
	if (ha->flags.fcp_prio_enabled)
		ctx->fcp_cmnd->task_attribute |=
		    sp->fcport->fcp_prio << 3;

	memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);

	fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 +
	    additional_cdb_len);
	*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));

	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
	put_unaligned_le64(ctx->fcp_cmnd_dma, &cmd_pkt->fcp_cmnd_dseg_address);

	sp->flags |= SRB_FCP_CMND_DMA_VALID;
	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
	/* Set total data segment count. */
	cmd_pkt->entry_count = (uint8_t)req_cnt;
	cmd_pkt->entry_status = 0;

	/* Build command packet. */
	req->current_outstanding_cmd = handle;
	req->outstanding_cmds[handle] = sp;
	sp->handle = handle;
	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
	req->cnt -= req_cnt;

	/* Adjust ring index. */
	wmb();
	req->ring_index++;
	if (req->ring_index == req->length) {
		req->ring_index = 0;
		req->ring_ptr = req->ring;
	} else {
		req->ring_ptr++;
	}

	/* Set chip new ring index. */
	wrt_reg_dword(req->req_q_in, req->ring_index);

	spin_unlock_irqrestore(lock, flags);

	return QLA_SUCCESS;

queuing_error_fcp_cmnd:
	dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
queuing_error:
	if (tot_dsds)
		scsi_dma_unmap(cmd);

	if (sp->u.scmd.ct6_ctx) {
		mempool_free(sp->u.scmd.ct6_ctx, ha->ctx_mempool);
		sp->u.scmd.ct6_ctx = NULL;
	}
	spin_unlock_irqrestore(lock, flags);

	return QLA_FUNCTION_FAILED;
}

/**********************************************
 * edif update/delete sa_index list functions *
 **********************************************/
+3 −0
Original line number Diff line number Diff line
@@ -490,6 +490,9 @@ struct cmd_type_6 {
	struct scsi_lun lun;		/* FCP LUN (BE). */

	__le16	control_flags;		/* Control flags. */
#define CF_NEW_SA			BIT_12
#define CF_EN_EDIF			BIT_9
#define CF_ADDITIONAL_PARAM_BLK		BIT_8
#define CF_DIF_SEG_DESCR_ENABLE		BIT_3
#define CF_DATA_SEG_DESCR_ENABLE	BIT_2
#define CF_READ_DATA			BIT_1
+4 −0
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ extern int ql2xenablemsix;
extern int qla2xuseresexchforels;
extern int ql2xdifbundlinginternalbuffers;
extern int ql2xfulldump_on_mpifail;
extern int ql2xsecenable;
extern int ql2xenforce_iocb_limit;
extern int ql2xabts_wait_nvme;

@@ -297,6 +298,8 @@ extern int qla2x00_vp_abort_isp(scsi_qla_host_t *);
 */
void qla_els_pt_iocb(struct scsi_qla_host *vha,
	struct els_entry_24xx *pkt, struct qla_els_pt_arg *a);
cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha,
		struct req_que *que);
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
@@ -987,6 +990,7 @@ void qla_enode_init(scsi_qla_host_t *vha);
void qla_enode_stop(scsi_qla_host_t *vha);
void qla_edif_flush_sa_ctl_lists(fc_port_t *fcport);
void qla_edb_init(scsi_qla_host_t *vha);
int qla28xx_start_scsi_edif(srb_t *sp);
void qla24xx_sa_update_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb);
void qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb);
void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp);
+1 −1
Original line number Diff line number Diff line
@@ -632,7 +632,7 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id)
	ct_req->req.rft_id.port_id = port_id_to_be_id(vha->d_id);
	ct_req->req.rft_id.fc4_types[2] = 0x01;		/* FCP-3 */

	if (vha->flags.nvme_enabled)
	if (vha->flags.nvme_enabled && qla_ini_mode_enabled(vha))
		ct_req->req.rft_id.fc4_types[6] = 1;    /* NVMe type 28h */

	sp->u.iocb_cmd.u.ctarg.req_size = RFT_ID_REQ_SIZE;
+14 −15
Original line number Diff line number Diff line
@@ -345,15 +345,13 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
	if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) {
		lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY;
	} else {
		if (vha->hw->flags.edif_enabled) {
			if (fcport->edif.non_secured_login == 0) {
		if (vha->hw->flags.edif_enabled &&
		    vha->e_dbell.db_flags & EDB_ACTIVE) {
			lio->u.logio.flags |=
				(SRB_LOGIN_FCSP | SRB_LOGIN_SKIP_PRLI);
			ql_dbg(ql_dbg_disc, vha, 0x2072,
			    "Async-login: w/ FCSP %8phC hdl=%x, loopid=%x portid=%06x\n",
				    fcport->port_name, sp->handle, fcport->loop_id,
				    fcport->d_id.b24);
			}
			    fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24);
		} else {
			lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
		}
@@ -363,10 +361,9 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
		lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;

	ql_log(ql_log_warn, vha, 0x2072,
	       "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x retries=%d.\n",
	       "Async-login - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n",
	       fcport->port_name, sp->handle, fcport->loop_id,
	       fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
	       fcport->login_retry);
	       fcport->d_id.b24, fcport->login_retry);

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS) {
@@ -3964,7 +3961,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
		}

		/* Enable PUREX PASSTHRU */
		if (ql2xrdpenable || ha->flags.scm_supported_f)
		if (ql2xrdpenable || ha->flags.scm_supported_f ||
		    ha->flags.edif_enabled)
			qla25xx_set_els_cmds_supported(vha);
	} else
		goto failed;
@@ -4149,7 +4147,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
	}

	/* Move PUREX, ABTS RX & RIDA to ATIOQ */
	if (ql2xmvasynctoatio &&
	if (ql2xmvasynctoatio && !ha->flags.edif_enabled &&
	    (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) {
		if (qla_tgt_mode_enabled(vha) ||
		    qla_dual_mode_enabled(vha))
@@ -4177,7 +4175,8 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
			ha->fw_options[2] &= ~BIT_8;
	}

	if (ql2xrdpenable || ha->flags.scm_supported_f)
	if (ql2xrdpenable || ha->flags.scm_supported_f ||
	    ha->flags.edif_enabled)
		ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;

	/* Enable Async 8130/8131 events -- transceiver insertion/removal */
Loading