예제 #1
0
static void ft_send_work(struct work_struct *work)
{
	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct fcp_cmnd *fcp;
	int data_dir = 0;
	int task_attr;

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

	if (fcp->fc_flags & FCP_CFL_LEN_MASK)
		goto err;		

	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	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;	
	}
	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: 
	default:
		task_attr = MSG_SIMPLE_TAG;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
	target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
			&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
			ntohl(fcp->fc_dl), task_attr, data_dir, 0);
	pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
	return;

err:
	ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
예제 #2
0
/*
 * Handle Task Management Request.
 */
static void ft_send_tm(struct ft_cmd *cmd)
{
	struct fcp_cmnd *fcp;
	int rc;
	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.
		 */
		pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
		ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
		return;
	}

	/* FIXME: Add referenced task tag for ABORT_TASK */
	rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess,
		&cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
		cmd, tm_func, GFP_KERNEL, 0, 0);
	if (rc < 0)
		ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
}
예제 #3
0
/*
 * Send new command to target.
 */
static void ft_send_work(struct work_struct *work)
{
	struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
	struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
	struct fcp_cmnd *fcp;
	int data_dir = 0;
	int task_attr;

	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 */

	/*
	 * Check for FCP task management flags
	 */
	if (fcp->fc_tm_flags) {
		ft_send_tm(cmd);
		return;
	}

	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;
	}

	fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
	/*
	 * Use a single se_cmd->cmd_kref as we expect to release se_cmd
	 * directly from ft_check_stop_free callback in response path.
	 */
	if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
			      &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
			      ntohl(fcp->fc_dl), task_attr, data_dir, 0))
		goto err;

	pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
	return;

err:
	ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}
예제 #4
0
파일: tfc_cmd.c 프로젝트: jebtang/mortar
/*
 * 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;

	transport_init_se_cmd(&cmd->se_cmd, &ft_configfs->tf_ops,
			cmd->sess->se_sess, 0, DMA_NONE, 0,
			&cmd->ft_sense_buffer[0]);
	target_get_sess_cmd(cmd->sess->se_sess, &cmd->se_cmd, false);

	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.
		 */
		pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
		ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
		return;
	}

	pr_debug("alloc tm cmd fn %d\n", tm_func);
	tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL);
	if (!tmr) {
		pr_debug("alloc failed\n");
		ft_send_resp_code_and_free(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_lookup_tmr_lun(&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"
			 */
			pr_debug("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);
			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);
}
예제 #5
0
/*
 * Send new command to target.
 */
static void ft_send_work(struct work_struct *work)
{
    struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
    struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
    struct se_cmd *se_cmd;
    struct fcp_cmnd *fcp;
    int data_dir = 0;
    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_lookup_cmd_lun(&cmd->se_cmd, 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);

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

    if (ret == -ENOMEM) {
        transport_send_check_condition_and_sense(se_cmd,
                TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
        transport_generic_free_cmd(se_cmd, 0);
        return;
    }
    if (ret == -EINVAL) {
        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);
        return;
    }
    transport_handle_cdb_direct(se_cmd);
    return;

err:
    ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
}