Ejemplo n.º 1
0
static void tcm_loop_submission_work(struct work_struct *work)
{
	struct tcm_loop_cmd *tl_cmd =
		container_of(work, struct tcm_loop_cmd, work);
	struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
	struct scsi_cmnd *sc = tl_cmd->sc;
	struct tcm_loop_nexus *tl_nexus;
	struct tcm_loop_hba *tl_hba;
	struct tcm_loop_tpg *tl_tpg;
	struct scatterlist *sgl_bidi = NULL;
	u32 sgl_bidi_count = 0;
	int ret;

	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];

	/*
	 * Ensure that this tl_tpg reference from the incoming sc->device->id
	 * has already been configured via tcm_loop_make_naa_tpg().
	 */
	if (!tl_tpg->tl_hba) {
		set_host_byte(sc, DID_NO_CONNECT);
		goto out_done;
	}

	tl_nexus = tl_hba->tl_nexus;
	if (!tl_nexus) {
		scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus"
				" does not exist\n");
		set_host_byte(sc, DID_ERROR);
		goto out_done;
	}

	transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo,
			tl_nexus->se_sess,
			scsi_bufflen(sc), sc->sc_data_direction,
			tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]);

	if (scsi_bidi_cmnd(sc)) {
		struct scsi_data_buffer *sdb = scsi_in(sc);

		sgl_bidi = sdb->table.sgl;
		sgl_bidi_count = sdb->table.nents;
		se_cmd->se_cmd_flags |= SCF_BIDI;

	}

	if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) {
		kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
		set_host_byte(sc, DID_NO_CONNECT);
		goto out_done;
	}

	/*
	 * Because some userspace code via scsi-generic do not memset their
	 * associated read buffers, go ahead and do that here for type
	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
	 * by target core in target_setup_cmd_from_cdb() ->
	 * transport_generic_cmd_sequencer().
	 */
	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
	    se_cmd->data_direction == DMA_FROM_DEVICE) {
		struct scatterlist *sg = scsi_sglist(sc);
		unsigned char *buf = kmap(sg_page(sg)) + sg->offset;

		if (buf != NULL) {
			memset(buf, 0, sg->length);
			kunmap(sg_page(sg));
		}
	}

	ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
	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;
	} else if (ret < 0) {
		if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
			tcm_loop_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;
	}

	ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc),
			scsi_sg_count(sc), sgl_bidi, sgl_bidi_count);
	if (ret) {
		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;

out_done:
	sc->scsi_done(sc);
	return;
}
Ejemplo n.º 2
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);
}