brintos

brintos / linux-shallow public Read only

0
0
Text · 12.4 KiB · e6addab Raw
493 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term4 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.5 */6 7#include "efct_driver.h"8#include "efct_unsol.h"9 10#define frame_printf(efct, hdr, fmt, ...) \11	do { \12		char s_id_text[16]; \13		efc_node_fcid_display(ntoh24((hdr)->fh_s_id), \14			s_id_text, sizeof(s_id_text)); \15		efc_log_debug(efct, "[%06x.%s] %02x/%04x/%04x: " fmt, \16			ntoh24((hdr)->fh_d_id), s_id_text, \17			(hdr)->fh_r_ctl, be16_to_cpu((hdr)->fh_ox_id), \18			be16_to_cpu((hdr)->fh_rx_id), ##__VA_ARGS__); \19	} while (0)20 21static struct efct_node *22efct_node_find(struct efct *efct, u32 port_id, u32 node_id)23{24	struct efct_node *node;25	u64 id = (u64)port_id << 32 | node_id;26 27	/*28	 * During node shutdown, Lookup will be removed first,29	 * before announcing to backend. So, no new IOs will be allowed30	 */31	/* Find a target node, given s_id and d_id */32	node = xa_load(&efct->lookup, id);33	if (node)34		kref_get(&node->ref);35 36	return node;37}38 39static int40efct_dispatch_frame(struct efct *efct, struct efc_hw_sequence *seq)41{42	struct efct_node *node;43	struct fc_frame_header *hdr;44	u32 s_id, d_id;45 46	hdr = seq->header->dma.virt;47 48	/* extract the s_id and d_id */49	s_id = ntoh24(hdr->fh_s_id);50	d_id = ntoh24(hdr->fh_d_id);51 52	if (!(hdr->fh_type == FC_TYPE_FCP || hdr->fh_type == FC_TYPE_BLS))53		return -EIO;54 55	if (hdr->fh_type == FC_TYPE_FCP) {56		node = efct_node_find(efct, d_id, s_id);57		if (!node) {58			efc_log_err(efct,59				    "Node not found, drop cmd d_id:%x s_id:%x\n",60				    d_id, s_id);61			efct_hw_sequence_free(&efct->hw, seq);62			return 0;63		}64 65		efct_dispatch_fcp_cmd(node, seq);66	} else {67		node = efct_node_find(efct, d_id, s_id);68		if (!node) {69			efc_log_err(efct, "ABTS: Node not found, d_id:%x s_id:%x\n",70				    d_id, s_id);71			return -EIO;72		}73 74		efc_log_err(efct, "Received ABTS for Node:%p\n", node);75		efct_node_recv_abts_frame(node, seq);76	}77 78	kref_put(&node->ref, node->release);79	efct_hw_sequence_free(&efct->hw, seq);80	return 0;81}82 83int84efct_unsolicited_cb(void *arg, struct efc_hw_sequence *seq)85{86	struct efct *efct = arg;87 88	/* Process FCP command */89	if (!efct_dispatch_frame(efct, seq))90		return 0;91 92	/* Forward frame to discovery lib */93	efc_dispatch_frame(efct->efcport, seq);94	return 0;95}96 97static int98efct_fc_tmf_rejected_cb(struct efct_io *io,99			enum efct_scsi_io_status scsi_status,100			u32 flags, void *arg)101{102	efct_scsi_io_free(io);103	return 0;104}105 106static void107efct_dispatch_unsol_tmf(struct efct_io *io, u8 tm_flags, u32 lun)108{109	u32 i;110	struct {111		u32 mask;112		enum efct_scsi_tmf_cmd cmd;113	} tmflist[] = {114	{FCP_TMF_ABT_TASK_SET, EFCT_SCSI_TMF_ABORT_TASK_SET},115	{FCP_TMF_CLR_TASK_SET, EFCT_SCSI_TMF_CLEAR_TASK_SET},116	{FCP_TMF_LUN_RESET, EFCT_SCSI_TMF_LOGICAL_UNIT_RESET},117	{FCP_TMF_TGT_RESET, EFCT_SCSI_TMF_TARGET_RESET},118	{FCP_TMF_CLR_ACA, EFCT_SCSI_TMF_CLEAR_ACA} };119 120	io->exp_xfer_len = 0;121 122	for (i = 0; i < ARRAY_SIZE(tmflist); i++) {123		if (tmflist[i].mask & tm_flags) {124			io->tmf_cmd = tmflist[i].cmd;125			efct_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0);126			break;127		}128	}129	if (i == ARRAY_SIZE(tmflist)) {130		/* Not handled */131		efc_log_err(io->node->efct, "TMF x%x rejected\n", tm_flags);132		efct_scsi_send_tmf_resp(io, EFCT_SCSI_TMF_FUNCTION_REJECTED,133					NULL, efct_fc_tmf_rejected_cb, NULL);134	}135}136 137static int138efct_validate_fcp_cmd(struct efct *efct, struct efc_hw_sequence *seq)139{140	/*141	 * If we received less than FCP_CMND_IU bytes, assume that the frame is142	 * corrupted in some way and drop it.143	 * This was seen when jamming the FCTL144	 * fill bytes field.145	 */146	if (seq->payload->dma.len < sizeof(struct fcp_cmnd)) {147		struct fc_frame_header	*fchdr = seq->header->dma.virt;148 149		efc_log_debug(efct,150			      "drop ox_id %04x payload (%zd) less than (%zd)\n",151			      be16_to_cpu(fchdr->fh_ox_id),152			      seq->payload->dma.len, sizeof(struct fcp_cmnd));153		return -EIO;154	}155	return 0;156}157 158static void159efct_populate_io_fcp_cmd(struct efct_io *io, struct fcp_cmnd *cmnd,160			 struct fc_frame_header *fchdr, bool sit)161{162	io->init_task_tag = be16_to_cpu(fchdr->fh_ox_id);163	/* note, tgt_task_tag, hw_tag  set when HW io is allocated */164	io->exp_xfer_len = be32_to_cpu(cmnd->fc_dl);165	io->transferred = 0;166 167	/* The upper 7 bits of CS_CTL is the frame priority thru the SAN.168	 * Our assertion here is, the priority given to a frame containing169	 * the FCP cmd should be the priority given to ALL frames contained170	 * in that IO. Thus we need to save the incoming CS_CTL here.171	 */172	if (ntoh24(fchdr->fh_f_ctl) & FC_FC_RES_B17)173		io->cs_ctl = fchdr->fh_cs_ctl;174	else175		io->cs_ctl = 0;176 177	io->seq_init = sit;178}179 180static u32181efct_get_flags_fcp_cmd(struct fcp_cmnd *cmnd)182{183	u32 flags = 0;184 185	switch (cmnd->fc_pri_ta & FCP_PTA_MASK) {186	case FCP_PTA_SIMPLE:187		flags |= EFCT_SCSI_CMD_SIMPLE;188		break;189	case FCP_PTA_HEADQ:190		flags |= EFCT_SCSI_CMD_HEAD_OF_QUEUE;191		break;192	case FCP_PTA_ORDERED:193		flags |= EFCT_SCSI_CMD_ORDERED;194		break;195	case FCP_PTA_ACA:196		flags |= EFCT_SCSI_CMD_ACA;197		break;198	}199	if (cmnd->fc_flags & FCP_CFL_WRDATA)200		flags |= EFCT_SCSI_CMD_DIR_IN;201	if (cmnd->fc_flags & FCP_CFL_RDDATA)202		flags |= EFCT_SCSI_CMD_DIR_OUT;203 204	return flags;205}206 207static void208efct_sframe_common_send_cb(void *arg, u8 *cqe, int status)209{210	struct efct_hw_send_frame_context *ctx = arg;211	struct efct_hw *hw = ctx->hw;212 213	/* Free WQ completion callback */214	efct_hw_reqtag_free(hw, ctx->wqcb);215 216	/* Free sequence */217	efct_hw_sequence_free(hw, ctx->seq);218}219 220static int221efct_sframe_common_send(struct efct_node *node,222			struct efc_hw_sequence *seq,223			enum fc_rctl r_ctl, u32 f_ctl,224			u8 type, void *payload, u32 payload_len)225{226	struct efct *efct = node->efct;227	struct efct_hw *hw = &efct->hw;228	int rc = 0;229	struct fc_frame_header *req_hdr = seq->header->dma.virt;230	struct fc_frame_header hdr;231	struct efct_hw_send_frame_context *ctx;232 233	u32 heap_size = seq->payload->dma.size;234	uintptr_t heap_phys_base = seq->payload->dma.phys;235	u8 *heap_virt_base = seq->payload->dma.virt;236	u32 heap_offset = 0;237 238	/* Build the FC header reusing the RQ header DMA buffer */239	memset(&hdr, 0, sizeof(hdr));240	hdr.fh_r_ctl = r_ctl;241	/* send it back to whomever sent it to us */242	memcpy(hdr.fh_d_id, req_hdr->fh_s_id, sizeof(hdr.fh_d_id));243	memcpy(hdr.fh_s_id, req_hdr->fh_d_id, sizeof(hdr.fh_s_id));244	hdr.fh_type = type;245	hton24(hdr.fh_f_ctl, f_ctl);246	hdr.fh_ox_id = req_hdr->fh_ox_id;247	hdr.fh_rx_id = req_hdr->fh_rx_id;248	hdr.fh_cs_ctl = 0;249	hdr.fh_df_ctl = 0;250	hdr.fh_seq_cnt = 0;251	hdr.fh_parm_offset = 0;252 253	/*254	 * send_frame_seq_id is an atomic, we just let it increment,255	 * while storing only the low 8 bits to hdr->seq_id256	 */257	hdr.fh_seq_id = (u8)atomic_add_return(1, &hw->send_frame_seq_id);258	hdr.fh_seq_id--;259 260	/* Allocate and fill in the send frame request context */261	ctx = (void *)(heap_virt_base + heap_offset);262	heap_offset += sizeof(*ctx);263	if (heap_offset > heap_size) {264		efc_log_err(efct, "Fill send frame failed offset %d size %d\n",265			    heap_offset, heap_size);266		return -EIO;267	}268 269	memset(ctx, 0, sizeof(*ctx));270 271	/* Save sequence */272	ctx->seq = seq;273 274	/* Allocate a response payload DMA buffer from the heap */275	ctx->payload.phys = heap_phys_base + heap_offset;276	ctx->payload.virt = heap_virt_base + heap_offset;277	ctx->payload.size = payload_len;278	ctx->payload.len = payload_len;279	heap_offset += payload_len;280	if (heap_offset > heap_size) {281		efc_log_err(efct, "Fill send frame failed offset %d size %d\n",282			    heap_offset, heap_size);283		return -EIO;284	}285 286	/* Copy the payload in */287	memcpy(ctx->payload.virt, payload, payload_len);288 289	/* Send */290	rc = efct_hw_send_frame(&efct->hw, (void *)&hdr, FC_SOF_N3,291				FC_EOF_T, &ctx->payload, ctx,292				efct_sframe_common_send_cb, ctx);293	if (rc)294		efc_log_debug(efct, "efct_hw_send_frame failed: %d\n", rc);295 296	return rc;297}298 299static int300efct_sframe_send_fcp_rsp(struct efct_node *node, struct efc_hw_sequence *seq,301			 void *rsp, u32 rsp_len)302{303	return efct_sframe_common_send(node, seq, FC_RCTL_DD_CMD_STATUS,304				      FC_FC_EX_CTX |305				      FC_FC_LAST_SEQ |306				      FC_FC_END_SEQ |307				      FC_FC_SEQ_INIT,308				      FC_TYPE_FCP,309				      rsp, rsp_len);310}311 312static int313efct_sframe_send_task_set_full_or_busy(struct efct_node *node,314				       struct efc_hw_sequence *seq)315{316	struct fcp_resp_with_ext fcprsp;317	struct fcp_cmnd *fcpcmd = seq->payload->dma.virt;318	int rc = 0;319	unsigned long flags = 0;320	struct efct *efct = node->efct;321 322	/* construct task set full or busy response */323	memset(&fcprsp, 0, sizeof(fcprsp));324	spin_lock_irqsave(&node->active_ios_lock, flags);325	fcprsp.resp.fr_status = list_empty(&node->active_ios) ?326				SAM_STAT_BUSY : SAM_STAT_TASK_SET_FULL;327	spin_unlock_irqrestore(&node->active_ios_lock, flags);328	*((u32 *)&fcprsp.ext.fr_resid) = be32_to_cpu(fcpcmd->fc_dl);329 330	/* send it using send_frame */331	rc = efct_sframe_send_fcp_rsp(node, seq, &fcprsp, sizeof(fcprsp));332	if (rc)333		efc_log_debug(efct, "efct_sframe_send_fcp_rsp failed %d\n", rc);334 335	return rc;336}337 338int339efct_dispatch_fcp_cmd(struct efct_node *node, struct efc_hw_sequence *seq)340{341	struct efct *efct = node->efct;342	struct fc_frame_header *fchdr = seq->header->dma.virt;343	struct fcp_cmnd	*cmnd = NULL;344	struct efct_io *io = NULL;345	u32 lun;346 347	if (!seq->payload) {348		efc_log_err(efct, "Sequence payload is NULL.\n");349		return -EIO;350	}351 352	cmnd = seq->payload->dma.virt;353 354	/* perform FCP_CMND validation check(s) */355	if (efct_validate_fcp_cmd(efct, seq))356		return -EIO;357 358	lun = scsilun_to_int(&cmnd->fc_lun);359	if (lun == U32_MAX)360		return -EIO;361 362	io = efct_scsi_io_alloc(node);363	if (!io) {364		int rc;365 366		/* Use SEND_FRAME to send task set full or busy */367		rc = efct_sframe_send_task_set_full_or_busy(node, seq);368		if (rc)369			efc_log_err(efct, "Failed to send busy task: %d\n", rc);370 371		return rc;372	}373 374	io->hw_priv = seq->hw_priv;375 376	io->app_id = 0;377 378	/* RQ pair, if we got here, SIT=1 */379	efct_populate_io_fcp_cmd(io, cmnd, fchdr, true);380 381	if (cmnd->fc_tm_flags) {382		efct_dispatch_unsol_tmf(io, cmnd->fc_tm_flags, lun);383	} else {384		u32 flags = efct_get_flags_fcp_cmd(cmnd);385 386		if (cmnd->fc_flags & FCP_CFL_LEN_MASK) {387			efc_log_err(efct, "Additional CDB not supported\n");388			return -EIO;389		}390		/*391		 * Can return failure for things like task set full and UAs,392		 * no need to treat as a dropped frame if rc != 0393		 */394		efct_scsi_recv_cmd(io, lun, cmnd->fc_cdb,395				   sizeof(cmnd->fc_cdb), flags);396	}397 398	return 0;399}400 401static int402efct_process_abts(struct efct_io *io, struct fc_frame_header *hdr)403{404	struct efct_node *node = io->node;405	struct efct *efct = io->efct;406	u16 ox_id = be16_to_cpu(hdr->fh_ox_id);407	u16 rx_id = be16_to_cpu(hdr->fh_rx_id);408	struct efct_io *abortio;409 410	/* Find IO and attempt to take a reference on it */411	abortio = efct_io_find_tgt_io(efct, node, ox_id, rx_id);412 413	if (abortio) {414		/* Got a reference on the IO. Hold it until backend415		 * is notified below416		 */417		efc_log_info(node->efct, "Abort ox_id [%04x] rx_id [%04x]\n",418			     ox_id, rx_id);419 420		/*421		 * Save the ox_id for the ABTS as the init_task_tag in our422		 * manufactured423		 * TMF IO object424		 */425		io->display_name = "abts";426		io->init_task_tag = ox_id;427		/* don't set tgt_task_tag, don't want to confuse with XRI */428 429		/*430		 * Save the rx_id from the ABTS as it is431		 * needed for the BLS response,432		 * regardless of the IO context's rx_id433		 */434		io->abort_rx_id = rx_id;435 436		/* Call target server command abort */437		io->tmf_cmd = EFCT_SCSI_TMF_ABORT_TASK;438		efct_scsi_recv_tmf(io, abortio->tgt_io.lun,439				   EFCT_SCSI_TMF_ABORT_TASK, abortio, 0);440 441		/*442		 * Backend will have taken an additional443		 * reference on the IO if needed;444		 * done with current reference.445		 */446		kref_put(&abortio->ref, abortio->release);447	} else {448		/*449		 * Either IO was not found or it has been450		 * freed between finding it451		 * and attempting to get the reference,452		 */453		efc_log_info(node->efct, "Abort: ox_id [%04x], IO not found\n",454			     ox_id);455 456		/* Send a BA_RJT */457		efct_bls_send_rjt(io, hdr);458	}459	return 0;460}461 462int463efct_node_recv_abts_frame(struct efct_node *node, struct efc_hw_sequence *seq)464{465	struct efct *efct = node->efct;466	struct fc_frame_header *hdr = seq->header->dma.virt;467	struct efct_io *io = NULL;468 469	node->abort_cnt++;470	io = efct_scsi_io_alloc(node);471	if (io) {472		io->hw_priv = seq->hw_priv;473		/* If we got this far, SIT=1 */474		io->seq_init = 1;475 476		/* fill out generic fields */477		io->efct = efct;478		io->node = node;479		io->cmd_tgt = true;480 481		efct_process_abts(io, seq->header->dma.virt);482	} else {483		efc_log_err(efct,484			    "SCSI IO allocation failed for ABTS received ");485		efc_log_err(efct, "s_id %06x d_id %06x ox_id %04x rx_id %04x\n",486			    ntoh24(hdr->fh_s_id), ntoh24(hdr->fh_d_id),487			    be16_to_cpu(hdr->fh_ox_id),488			    be16_to_cpu(hdr->fh_rx_id));489	}490 491	return 0;492}493