예제 #1
0
/*
 * Send status from completed task management request.
 */
void ft_queue_tm_resp(struct se_cmd *se_cmd)
{
	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
	struct se_tmr_req *tmr = se_cmd->se_tmr_req;
	enum fcp_resp_rsp_codes code;

	if (cmd->aborted)
		return;
	switch (tmr->response) {
	case TMR_FUNCTION_COMPLETE:
		code = FCP_TMF_CMPL;
		break;
	case TMR_LUN_DOES_NOT_EXIST:
		code = FCP_TMF_INVALID_LUN;
		break;
	case TMR_FUNCTION_REJECTED:
		code = FCP_TMF_REJECTED;
		break;
	case TMR_TASK_DOES_NOT_EXIST:
	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
	default:
		code = FCP_TMF_FAILED;
		break;
	}
	pr_debug("tmr fn %d resp %d fcp code %d\n",
		  tmr->function, tmr->response, code);
	ft_send_resp_code(cmd, code);
}
예제 #2
0
/*
 * Send status from completed task management request.
 */
int ft_queue_tm_resp(struct se_cmd *se_cmd)
{
	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
	struct se_tmr_req *tmr = se_cmd->se_tmr_req;
	enum fcp_resp_rsp_codes code;

	switch (tmr->response) {
	case TMR_FUNCTION_COMPLETE:
		code = FCP_TMF_CMPL;
		break;
	case TMR_LUN_DOES_NOT_EXIST:
		code = FCP_TMF_INVALID_LUN;
		break;
	case TMR_FUNCTION_REJECTED:
		code = FCP_TMF_REJECTED;
		break;
	case TMR_TASK_DOES_NOT_EXIST:
	case TMR_TASK_STILL_ALLEGIANT:
	case TMR_TASK_FAILOVER_NOT_SUPPORTED:
	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
	case TMR_FUNCTION_AUTHORIZATION_FAILED:
	default:
		code = FCP_TMF_FAILED;
		break;
	}
	FT_TM_DBG("tmr fn %d resp %d fcp code %d\n",
		  tmr->function, tmr->response, code);
	ft_send_resp_code(cmd, code);
	return 0;
}
예제 #3
0
/*
 * Send status from completed task management request.
 */
void ft_queue_tm_resp(struct se_cmd *se_cmd)
{
	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
	struct se_tmr_req *tmr = se_cmd->se_tmr_req;
	enum fcp_resp_rsp_codes code;

	if (cmd->aborted)
		return;
	switch (tmr->response) {
	case TMR_FUNCTION_COMPLETE:
		code = FCP_TMF_CMPL;
		break;
	case TMR_LUN_DOES_NOT_EXIST:
		code = FCP_TMF_INVALID_LUN;
		break;
	case TMR_FUNCTION_REJECTED:
		code = FCP_TMF_REJECTED;
		break;
	case TMR_TASK_DOES_NOT_EXIST:
	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
	default:
		code = FCP_TMF_FAILED;
		break;
	}
	pr_debug("tmr fn %d resp %d fcp code %d\n",
		  tmr->function, tmr->response, code);
	ft_send_resp_code(cmd, code);
	/*
	 * Drop the extra ACK_KREF reference taken by target_submit_tmr()
	 * ahead of ft_check_stop_free() -> transport_generic_free_cmd()
	 * final se_cmd->cmd_kref put.
	 */
	target_put_sess_cmd(&cmd->se_cmd);
}
예제 #4
0
/*
 * Send error or task management response.
 * Always frees the cmd and associated state.
 */
static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
				      enum fcp_resp_rsp_codes code)
{
	ft_send_resp_code(cmd, code);
	ft_free_cmd(cmd);
}
예제 #5
0
/*
 * Send new command to target.
 */
static void ft_send_cmd(struct ft_cmd *cmd)
{
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct se_cmd *se_cmd;
	struct fcp_cmnd *fcp;
	int data_dir;
	u32 data_len;
	int task_attr;
	int ret;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
	if (!fcp)
		goto err;

	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
		goto err;		/* not handling longer CDBs yet */

	if (fcp->fc_tm_flags) {
		task_attr = FCP_PTA_SIMPLE;
		data_dir = DMA_NONE;
		data_len = 0;
	} else {
		switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) {
		case 0:
			data_dir = DMA_NONE;
			break;
		case FCP_CFL_RDDATA:
			data_dir = DMA_FROM_DEVICE;
			break;
		case FCP_CFL_WRDATA:
			data_dir = DMA_TO_DEVICE;
			break;
		case FCP_CFL_WRDATA | FCP_CFL_RDDATA:
			goto err;	/* TBD not supported by tcm_fc yet */
		}
		/*
		 * Locate the SAM Task Attr from fc_pri_ta
		 */
		switch (fcp->fc_pri_ta & FCP_PTA_MASK) {
		case FCP_PTA_HEADQ:
			task_attr = MSG_HEAD_TAG;
			break;
		case FCP_PTA_ORDERED:
			task_attr = MSG_ORDERED_TAG;
			break;
		case FCP_PTA_ACA:
			task_attr = MSG_ACA_TAG;
			break;
		case FCP_PTA_SIMPLE: /* Fallthrough */
		default:
			task_attr = MSG_SIMPLE_TAG;
		}


		task_attr = fcp->fc_pri_ta & FCP_PTA_MASK;
		data_len = ntohl(fcp->fc_dl);
		cmd->cdb = fcp->fc_cdb;
	}

	se_cmd = &cmd->se_cmd;
	/*
	 * Initialize struct se_cmd descriptor from target_core_mod
	 * infrastructure
	 */
	transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess,
			      data_len, data_dir, task_attr,
			      &cmd->ft_sense_buffer[0]);
	/*
	 * Check for FCP task management flags
	 */
	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);

	cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
	ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun);
	if (ret < 0) {
		ft_dump_cmd(cmd, __func__);
		transport_send_check_condition_and_sense(&cmd->se_cmd,
			cmd->se_cmd.scsi_sense_reason, 0);
		return;
	}

	ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb);

	FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret);
	ft_dump_cmd(cmd, __func__);

	if (ret == -1) {
		transport_send_check_condition_and_sense(se_cmd,
				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
		transport_generic_free_cmd(se_cmd, 0, 1, 0);
		return;
	}
	if (ret == -2) {
		if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
			ft_queue_status(se_cmd);
		else
			transport_send_check_condition_and_sense(se_cmd,
					se_cmd->scsi_sense_reason, 0);
		transport_generic_free_cmd(se_cmd, 0, 1, 0);
		return;
	}
	transport_generic_handle_cdb(se_cmd);
	return;

err:
	ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
	return;
}
예제 #6
0
/*
 * Handle Task Management Request.
 */
static void ft_send_tm(struct ft_cmd *cmd)
{
	struct se_tmr_req *tmr;
	struct fcp_cmnd *fcp;
	struct ft_sess *sess;
	u8 tm_func;

	fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));

	switch (fcp->fc_tm_flags) {
	case FCP_TMF_LUN_RESET:
		tm_func = TMR_LUN_RESET;
		break;
	case FCP_TMF_TGT_RESET:
		tm_func = TMR_TARGET_WARM_RESET;
		break;
	case FCP_TMF_CLR_TASK_SET:
		tm_func = TMR_CLEAR_TASK_SET;
		break;
	case FCP_TMF_ABT_TASK_SET:
		tm_func = TMR_ABORT_TASK_SET;
		break;
	case FCP_TMF_CLR_ACA:
		tm_func = TMR_CLEAR_ACA;
		break;
	default:
		/*
		 * FCP4r01 indicates having a combination of
		 * tm_flags set is invalid.
		 */
		FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
		ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
		return;
	}

	FT_TM_DBG("alloc tm cmd fn %d\n", tm_func);
	tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
	if (!tmr) {
		FT_TM_DBG("alloc failed\n");
		ft_send_resp_code(cmd, FCP_TMF_FAILED);
		return;
	}
	cmd->se_cmd.se_tmr_req = tmr;

	switch (fcp->fc_tm_flags) {
	case FCP_TMF_LUN_RESET:
		cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
		if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) {
			/*
			 * Make sure to clean up newly allocated TMR request
			 * since "unable to  handle TMR request because failed
			 * to get to LUN"
			 */
			FT_TM_DBG("Failed to get LUN for TMR func %d, "
				  "se_cmd %p, unpacked_lun %d\n",
				  tm_func, &cmd->se_cmd, cmd->lun);
			ft_dump_cmd(cmd, __func__);
			sess = cmd->sess;
			transport_send_check_condition_and_sense(&cmd->se_cmd,
				cmd->se_cmd.scsi_sense_reason, 0);
			transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
			ft_sess_put(sess);
			return;
		}
		break;
	case FCP_TMF_TGT_RESET:
	case FCP_TMF_CLR_TASK_SET:
	case FCP_TMF_ABT_TASK_SET:
	case FCP_TMF_CLR_ACA:
		break;
	default:
		return;
	}
	transport_generic_handle_tmr(&cmd->se_cmd);
}