cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tfc_cmd.c (13915B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2010 Cisco Systems, Inc.
      4 */
      5
      6/* XXX TBD some includes may be extraneous */
      7
      8#include <linux/module.h>
      9#include <linux/moduleparam.h>
     10#include <linux/utsname.h>
     11#include <linux/init.h>
     12#include <linux/slab.h>
     13#include <linux/kthread.h>
     14#include <linux/types.h>
     15#include <linux/string.h>
     16#include <linux/configfs.h>
     17#include <linux/ctype.h>
     18#include <linux/hash.h>
     19#include <asm/unaligned.h>
     20#include <scsi/scsi_tcq.h>
     21#include <scsi/libfc.h>
     22
     23#include <target/target_core_base.h>
     24#include <target/target_core_fabric.h>
     25
     26#include "tcm_fc.h"
     27
     28/*
     29 * Dump cmd state for debugging.
     30 */
     31static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
     32{
     33	struct fc_exch *ep;
     34	struct fc_seq *sp;
     35	struct se_cmd *se_cmd;
     36	struct scatterlist *sg;
     37	int count;
     38
     39	se_cmd = &cmd->se_cmd;
     40	pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n",
     41		caller, cmd, cmd->sess, cmd->seq, se_cmd);
     42
     43	pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
     44		caller, cmd, se_cmd->t_data_nents,
     45	       se_cmd->data_length, se_cmd->se_cmd_flags);
     46
     47	for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count)
     48		pr_debug("%s: cmd %p sg %p page %p "
     49			"len 0x%x off 0x%x\n",
     50			caller, cmd, sg,
     51			sg_page(sg), sg->length, sg->offset);
     52
     53	sp = cmd->seq;
     54	if (sp) {
     55		ep = fc_seq_exch(sp);
     56		pr_debug("%s: cmd %p sid %x did %x "
     57			"ox_id %x rx_id %x seq_id %x e_stat %x\n",
     58			caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid,
     59			sp->id, ep->esb_stat);
     60	}
     61}
     62
     63void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
     64{
     65	if (unlikely(ft_debug_logging))
     66		_ft_dump_cmd(cmd, caller);
     67}
     68
     69static void ft_free_cmd(struct ft_cmd *cmd)
     70{
     71	struct fc_frame *fp;
     72	struct ft_sess *sess;
     73
     74	if (!cmd)
     75		return;
     76	sess = cmd->sess;
     77	fp = cmd->req_frame;
     78	if (fr_seq(fp))
     79		fc_seq_release(fr_seq(fp));
     80	fc_frame_free(fp);
     81	target_free_tag(sess->se_sess, &cmd->se_cmd);
     82	ft_sess_put(sess);	/* undo get from lookup at recv */
     83}
     84
     85void ft_release_cmd(struct se_cmd *se_cmd)
     86{
     87	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
     88
     89	ft_free_cmd(cmd);
     90}
     91
     92int ft_check_stop_free(struct se_cmd *se_cmd)
     93{
     94	return transport_generic_free_cmd(se_cmd, 0);
     95}
     96
     97/*
     98 * Send response.
     99 */
    100int ft_queue_status(struct se_cmd *se_cmd)
    101{
    102	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
    103	struct fc_frame *fp;
    104	struct fcp_resp_with_ext *fcp;
    105	struct fc_lport *lport;
    106	struct fc_exch *ep;
    107	size_t len;
    108	int rc;
    109
    110	if (cmd->aborted)
    111		return 0;
    112	ft_dump_cmd(cmd, __func__);
    113	ep = fc_seq_exch(cmd->seq);
    114	lport = ep->lp;
    115	len = sizeof(*fcp) + se_cmd->scsi_sense_length;
    116	fp = fc_frame_alloc(lport, len);
    117	if (!fp) {
    118		se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
    119		return -ENOMEM;
    120	}
    121
    122	fcp = fc_frame_payload_get(fp, len);
    123	memset(fcp, 0, len);
    124	fcp->resp.fr_status = se_cmd->scsi_status;
    125
    126	len = se_cmd->scsi_sense_length;
    127	if (len) {
    128		fcp->resp.fr_flags |= FCP_SNS_LEN_VAL;
    129		fcp->ext.fr_sns_len = htonl(len);
    130		memcpy((fcp + 1), se_cmd->sense_buffer, len);
    131	}
    132
    133	/*
    134	 * Test underflow and overflow with one mask.  Usually both are off.
    135	 * Bidirectional commands are not handled yet.
    136	 */
    137	if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) {
    138		if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
    139			fcp->resp.fr_flags |= FCP_RESID_OVER;
    140		else
    141			fcp->resp.fr_flags |= FCP_RESID_UNDER;
    142		fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count);
    143	}
    144
    145	/*
    146	 * Send response.
    147	 */
    148	cmd->seq = fc_seq_start_next(cmd->seq);
    149	fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP,
    150		       FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0);
    151
    152	rc = fc_seq_send(lport, cmd->seq, fp);
    153	if (rc) {
    154		pr_info_ratelimited("%s: Failed to send response frame %p, "
    155				    "xid <0x%x>\n", __func__, fp, ep->xid);
    156		/*
    157		 * Generate a TASK_SET_FULL status to notify the initiator
    158		 * to reduce it's queue_depth after the se_cmd response has
    159		 * been re-queued by target-core.
    160		 */
    161		se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
    162		return -ENOMEM;
    163	}
    164	fc_exch_done(cmd->seq);
    165	/*
    166	 * Drop the extra ACK_KREF reference taken by target_submit_cmd()
    167	 * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
    168	 * final se_cmd->cmd_kref put.
    169	 */
    170	target_put_sess_cmd(&cmd->se_cmd);
    171	return 0;
    172}
    173
    174/*
    175 * Send TX_RDY (transfer ready).
    176 */
    177int ft_write_pending(struct se_cmd *se_cmd)
    178{
    179	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
    180	struct fc_frame *fp;
    181	struct fcp_txrdy *txrdy;
    182	struct fc_lport *lport;
    183	struct fc_exch *ep;
    184	struct fc_frame_header *fh;
    185	u32 f_ctl;
    186
    187	ft_dump_cmd(cmd, __func__);
    188
    189	if (cmd->aborted)
    190		return 0;
    191	ep = fc_seq_exch(cmd->seq);
    192	lport = ep->lp;
    193	fp = fc_frame_alloc(lport, sizeof(*txrdy));
    194	if (!fp)
    195		return -ENOMEM; /* Signal QUEUE_FULL */
    196
    197	txrdy = fc_frame_payload_get(fp, sizeof(*txrdy));
    198	memset(txrdy, 0, sizeof(*txrdy));
    199	txrdy->ft_burst_len = htonl(se_cmd->data_length);
    200
    201	cmd->seq = fc_seq_start_next(cmd->seq);
    202	fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP,
    203		       FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
    204
    205	fh = fc_frame_header_get(fp);
    206	f_ctl = ntoh24(fh->fh_f_ctl);
    207
    208	/* Only if it is 'Exchange Responder' */
    209	if (f_ctl & FC_FC_EX_CTX) {
    210		/* Target is 'exchange responder' and sending XFER_READY
    211		 * to 'exchange initiator (initiator)'
    212		 */
    213		if ((ep->xid <= lport->lro_xid) &&
    214		    (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
    215			if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
    216			    lport->tt.ddp_target(lport, ep->xid,
    217						 se_cmd->t_data_sg,
    218						 se_cmd->t_data_nents))
    219				cmd->was_ddp_setup = 1;
    220		}
    221	}
    222	fc_seq_send(lport, cmd->seq, fp);
    223	return 0;
    224}
    225
    226int ft_get_cmd_state(struct se_cmd *se_cmd)
    227{
    228	return 0;
    229}
    230
    231/*
    232 * FC sequence response handler for follow-on sequences (data) and aborts.
    233 */
    234static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
    235{
    236	struct ft_cmd *cmd = arg;
    237	struct fc_frame_header *fh;
    238
    239	if (IS_ERR(fp)) {
    240		/* XXX need to find cmd if queued */
    241		cmd->seq = NULL;
    242		cmd->aborted = true;
    243		return;
    244	}
    245
    246	fh = fc_frame_header_get(fp);
    247
    248	switch (fh->fh_r_ctl) {
    249	case FC_RCTL_DD_SOL_DATA:	/* write data */
    250		ft_recv_write_data(cmd, fp);
    251		break;
    252	case FC_RCTL_DD_UNSOL_CTL:	/* command */
    253	case FC_RCTL_DD_SOL_CTL:	/* transfer ready */
    254	case FC_RCTL_DD_DATA_DESC:	/* transfer ready */
    255	default:
    256		pr_debug("%s: unhandled frame r_ctl %x\n",
    257		       __func__, fh->fh_r_ctl);
    258		ft_invl_hw_context(cmd);
    259		fc_frame_free(fp);
    260		transport_generic_free_cmd(&cmd->se_cmd, 0);
    261		break;
    262	}
    263}
    264
    265/*
    266 * Send a FCP response including SCSI status and optional FCP rsp_code.
    267 * status is SAM_STAT_GOOD (zero) iff code is valid.
    268 * This is used in error cases, such as allocation failures.
    269 */
    270static void ft_send_resp_status(struct fc_lport *lport,
    271				const struct fc_frame *rx_fp,
    272				u32 status, enum fcp_resp_rsp_codes code)
    273{
    274	struct fc_frame *fp;
    275	struct fc_seq *sp;
    276	const struct fc_frame_header *fh;
    277	size_t len;
    278	struct fcp_resp_with_ext *fcp;
    279	struct fcp_resp_rsp_info *info;
    280
    281	fh = fc_frame_header_get(rx_fp);
    282	pr_debug("FCP error response: did %x oxid %x status %x code %x\n",
    283		  ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code);
    284	len = sizeof(*fcp);
    285	if (status == SAM_STAT_GOOD)
    286		len += sizeof(*info);
    287	fp = fc_frame_alloc(lport, len);
    288	if (!fp)
    289		return;
    290	fcp = fc_frame_payload_get(fp, len);
    291	memset(fcp, 0, len);
    292	fcp->resp.fr_status = status;
    293	if (status == SAM_STAT_GOOD) {
    294		fcp->ext.fr_rsp_len = htonl(sizeof(*info));
    295		fcp->resp.fr_flags |= FCP_RSP_LEN_VAL;
    296		info = (struct fcp_resp_rsp_info *)(fcp + 1);
    297		info->rsp_code = code;
    298	}
    299
    300	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0);
    301	sp = fr_seq(fp);
    302	if (sp) {
    303		fc_seq_send(lport, sp, fp);
    304		fc_exch_done(sp);
    305	} else {
    306		lport->tt.frame_send(lport, fp);
    307	}
    308}
    309
    310/*
    311 * Send error or task management response.
    312 */
    313static void ft_send_resp_code(struct ft_cmd *cmd,
    314			      enum fcp_resp_rsp_codes code)
    315{
    316	ft_send_resp_status(cmd->sess->tport->lport,
    317			    cmd->req_frame, SAM_STAT_GOOD, code);
    318}
    319
    320
    321/*
    322 * Send error or task management response.
    323 * Always frees the cmd and associated state.
    324 */
    325static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
    326				      enum fcp_resp_rsp_codes code)
    327{
    328	ft_send_resp_code(cmd, code);
    329	ft_free_cmd(cmd);
    330}
    331
    332/*
    333 * Handle Task Management Request.
    334 */
    335static void ft_send_tm(struct ft_cmd *cmd)
    336{
    337	struct fcp_cmnd *fcp;
    338	int rc;
    339	u8 tm_func;
    340
    341	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
    342
    343	switch (fcp->fc_tm_flags) {
    344	case FCP_TMF_LUN_RESET:
    345		tm_func = TMR_LUN_RESET;
    346		break;
    347	case FCP_TMF_TGT_RESET:
    348		tm_func = TMR_TARGET_WARM_RESET;
    349		break;
    350	case FCP_TMF_CLR_TASK_SET:
    351		tm_func = TMR_CLEAR_TASK_SET;
    352		break;
    353	case FCP_TMF_ABT_TASK_SET:
    354		tm_func = TMR_ABORT_TASK_SET;
    355		break;
    356	case FCP_TMF_CLR_ACA:
    357		tm_func = TMR_CLEAR_ACA;
    358		break;
    359	default:
    360		/*
    361		 * FCP4r01 indicates having a combination of
    362		 * tm_flags set is invalid.
    363		 */
    364		pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
    365		ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
    366		return;
    367	}
    368
    369	/* FIXME: Add referenced task tag for ABORT_TASK */
    370	rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
    371		&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
    372		cmd, tm_func, GFP_KERNEL, 0, TARGET_SCF_ACK_KREF);
    373	if (rc < 0)
    374		ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
    375}
    376
    377/*
    378 * Send status from completed task management request.
    379 */
    380void ft_queue_tm_resp(struct se_cmd *se_cmd)
    381{
    382	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
    383	struct se_tmr_req *tmr = se_cmd->se_tmr_req;
    384	enum fcp_resp_rsp_codes code;
    385
    386	if (cmd->aborted)
    387		return;
    388	switch (tmr->response) {
    389	case TMR_FUNCTION_COMPLETE:
    390		code = FCP_TMF_CMPL;
    391		break;
    392	case TMR_LUN_DOES_NOT_EXIST:
    393		code = FCP_TMF_INVALID_LUN;
    394		break;
    395	case TMR_FUNCTION_REJECTED:
    396		code = FCP_TMF_REJECTED;
    397		break;
    398	case TMR_TASK_DOES_NOT_EXIST:
    399	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
    400	default:
    401		code = FCP_TMF_FAILED;
    402		break;
    403	}
    404	pr_debug("tmr fn %d resp %d fcp code %d\n",
    405		  tmr->function, tmr->response, code);
    406	ft_send_resp_code(cmd, code);
    407	/*
    408	 * Drop the extra ACK_KREF reference taken by target_submit_tmr()
    409	 * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
    410	 * final se_cmd->cmd_kref put.
    411	 */
    412	target_put_sess_cmd(&cmd->se_cmd);
    413}
    414
    415void ft_aborted_task(struct se_cmd *se_cmd)
    416{
    417	return;
    418}
    419
    420static void ft_send_work(struct work_struct *work);
    421
    422/*
    423 * Handle incoming FCP command.
    424 */
    425static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
    426{
    427	struct ft_cmd *cmd;
    428	struct fc_lport *lport = sess->tport->lport;
    429	struct se_session *se_sess = sess->se_sess;
    430	int tag, cpu;
    431
    432	tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
    433	if (tag < 0)
    434		goto busy;
    435
    436	cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag];
    437	memset(cmd, 0, sizeof(struct ft_cmd));
    438
    439	cmd->se_cmd.map_tag = tag;
    440	cmd->se_cmd.map_cpu = cpu;
    441	cmd->sess = sess;
    442	cmd->seq = fc_seq_assign(lport, fp);
    443	if (!cmd->seq) {
    444		target_free_tag(se_sess, &cmd->se_cmd);
    445		goto busy;
    446	}
    447	cmd->req_frame = fp;		/* hold frame during cmd */
    448
    449	INIT_WORK(&cmd->work, ft_send_work);
    450	queue_work(sess->tport->tpg->workqueue, &cmd->work);
    451	return;
    452
    453busy:
    454	pr_debug("cmd or seq allocation failure - sending BUSY\n");
    455	ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0);
    456	fc_frame_free(fp);
    457	ft_sess_put(sess);		/* undo get from lookup */
    458}
    459
    460
    461/*
    462 * Handle incoming FCP frame.
    463 * Caller has verified that the frame is type FCP.
    464 */
    465void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp)
    466{
    467	struct fc_frame_header *fh = fc_frame_header_get(fp);
    468
    469	switch (fh->fh_r_ctl) {
    470	case FC_RCTL_DD_UNSOL_CMD:	/* command */
    471		ft_recv_cmd(sess, fp);
    472		break;
    473	case FC_RCTL_DD_SOL_DATA:	/* write data */
    474	case FC_RCTL_DD_UNSOL_CTL:
    475	case FC_RCTL_DD_SOL_CTL:
    476	case FC_RCTL_DD_DATA_DESC:	/* transfer ready */
    477	case FC_RCTL_ELS4_REQ:		/* SRR, perhaps */
    478	default:
    479		pr_debug("%s: unhandled frame r_ctl %x\n",
    480		       __func__, fh->fh_r_ctl);
    481		fc_frame_free(fp);
    482		ft_sess_put(sess);	/* undo get from lookup */
    483		break;
    484	}
    485}
    486
    487/*
    488 * Send new command to target.
    489 */
    490static void ft_send_work(struct work_struct *work)
    491{
    492	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
    493	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
    494	struct fcp_cmnd *fcp;
    495	int data_dir = 0;
    496	int task_attr;
    497
    498	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
    499	if (!fcp)
    500		goto err;
    501
    502	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
    503		goto err;		/* not handling longer CDBs yet */
    504
    505	/*
    506	 * Check for FCP task management flags
    507	 */
    508	if (fcp->fc_tm_flags) {
    509		ft_send_tm(cmd);
    510		return;
    511	}
    512
    513	switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
    514	case 0:
    515		data_dir = DMA_NONE;
    516		break;
    517	case FCP_CFL_RDDATA:
    518		data_dir = DMA_FROM_DEVICE;
    519		break;
    520	case FCP_CFL_WRDATA:
    521		data_dir = DMA_TO_DEVICE;
    522		break;
    523	case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
    524		goto err;	/* TBD not supported by tcm_fc yet */
    525	}
    526	/*
    527	 * Locate the SAM Task Attr from fc_pri_ta
    528	 */
    529	switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
    530	case FCP_PTA_HEADQ:
    531		task_attr = TCM_HEAD_TAG;
    532		break;
    533	case FCP_PTA_ORDERED:
    534		task_attr = TCM_ORDERED_TAG;
    535		break;
    536	case FCP_PTA_ACA:
    537		task_attr = TCM_ACA_TAG;
    538		break;
    539	case FCP_PTA_SIMPLE:
    540	default:
    541		task_attr = TCM_SIMPLE_TAG;
    542	}
    543
    544	fc_seq_set_resp(cmd->seq, ft_recv_seq, cmd);
    545	cmd->se_cmd.tag = fc_seq_exch(cmd->seq)->rxid;
    546
    547	/*
    548	 * Use a single se_cmd->cmd_kref as we expect to release se_cmd
    549	 * directly from ft_check_stop_free callback in response path.
    550	 */
    551	if (target_init_cmd(&cmd->se_cmd, cmd->sess->se_sess,
    552			    &cmd->ft_sense_buffer[0],
    553			    scsilun_to_int(&fcp->fc_lun), ntohl(fcp->fc_dl),
    554			    task_attr, data_dir, TARGET_SCF_ACK_KREF))
    555		goto err;
    556
    557	if (target_submit_prep(&cmd->se_cmd, fcp->fc_cdb, NULL, 0, NULL, 0,
    558			       NULL, 0, GFP_KERNEL))
    559		return;
    560
    561	target_submit(&cmd->se_cmd);
    562	pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd);
    563	return;
    564
    565err:
    566	ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
    567}