Skip to content

Commit

Permalink
target/user: Disallow full passthrough (pass_level=0)
Browse files Browse the repository at this point in the history
TCMU requires more work to correctly handle both user handlers that want
all SCSI commands (pass_level=0) for a se_device, and also handlers that
just want I/O commands and let the others be emulated by the kernel
(pass_level=1). Only support the latter for now.

For full passthrough, we will need to support a second se_subsystem_api
template, due to configfs attributes being different between the two modes.
Thus pass_level is extraneous, and we can remove it.

The ABI break for TCMU v2 is already applied for this release, so it's
best to do this now to avoid another ABI break in the future.

Signed-off-by: Andy Grover <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Nicholas Bellinger <[email protected]>
  • Loading branch information
Andy Grover authored and Nicholas Bellinger committed May 3, 2015
1 parent a928d28 commit 8ee83a7
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 76 deletions.
18 changes: 7 additions & 11 deletions Documentation/target/tcmu-design.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Contents:
a) Discovering and configuring TCMU uio devices
b) Waiting for events on the device(s)
c) Managing the command ring
3) Command filtering and pass_level
3) Command filtering
4) A final note


Expand Down Expand Up @@ -360,17 +360,13 @@ int handle_device_events(int fd, void *map)
}


Command filtering and pass_level
--------------------------------
Command filtering
-----------------

TCMU supports a "pass_level" option with valid values of 0 or 1. When
the value is 0 (the default), nearly all SCSI commands received for
the device are passed through to the handler. This allows maximum
flexibility but increases the amount of code required by the handler,
to support all mandatory SCSI commands. If pass_level is set to 1,
then only IO-related commands are presented, and the rest are handled
by LIO's in-kernel command emulation. The commands presented at level
1 include all versions of:
Initial TCMU support is for a filtered commandset. Only IO-related
commands are presented to userspace, and the rest are handled by LIO's
in-kernel command emulation. The commands presented are all versions
of:

READ
WRITE
Expand Down
68 changes: 3 additions & 65 deletions drivers/target/target_core_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ struct tcmu_hba {
u32 host_id;
};

/* User wants all cmds or just some */
enum passthru_level {
TCMU_PASS_ALL = 0,
TCMU_PASS_IO,
TCMU_PASS_INVALID,
};

#define TCMU_CONFIG_LEN 256

struct tcmu_dev {
Expand All @@ -89,7 +82,6 @@ struct tcmu_dev {
#define TCMU_DEV_BIT_OPEN 0
#define TCMU_DEV_BIT_BROKEN 1
unsigned long flags;
enum passthru_level pass_level;

struct uio_info uio_info;

Expand Down Expand Up @@ -683,8 +675,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
setup_timer(&udev->timeout, tcmu_device_timedout,
(unsigned long)udev);

udev->pass_level = TCMU_PASS_ALL;

return &udev->se_dev;
}

Expand Down Expand Up @@ -948,13 +938,12 @@ static void tcmu_free_device(struct se_device *dev)
}

enum {
Opt_dev_config, Opt_dev_size, Opt_err, Opt_pass_level,
Opt_dev_config, Opt_dev_size, Opt_err,
};

static match_table_t tokens = {
{Opt_dev_config, "dev_config=%s"},
{Opt_dev_size, "dev_size=%u"},
{Opt_pass_level, "pass_level=%u"},
{Opt_err, NULL}
};

Expand All @@ -965,7 +954,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
char *orig, *ptr, *opts, *arg_p;
substring_t args[MAX_OPT_ARGS];
int ret = 0, token;
int arg;

opts = kstrdup(page, GFP_KERNEL);
if (!opts)
Expand Down Expand Up @@ -998,16 +986,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
if (ret < 0)
pr_err("kstrtoul() failed for dev_size=\n");
break;
case Opt_pass_level:
match_int(args, &arg);
if (arg >= TCMU_PASS_INVALID) {
pr_warn("TCMU: Invalid pass_level: %d\n", arg);
break;
}

pr_debug("TCMU: Setting pass_level to %d\n", arg);
udev->pass_level = arg;
break;
default:
break;
}
Expand All @@ -1024,8 +1002,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)

bl = sprintf(b + bl, "Config: %s ",
udev->dev_config[0] ? udev->dev_config : "NULL");
bl += sprintf(b + bl, "Size: %zu PassLevel: %u\n",
udev->dev_size, udev->pass_level);
bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size);

return bl;
}
Expand Down Expand Up @@ -1074,46 +1051,7 @@ static struct sbc_ops tcmu_sbc_ops = {
static sense_reason_t
tcmu_parse_cdb(struct se_cmd *cmd)
{
unsigned char *cdb = cmd->t_task_cdb;
struct tcmu_dev *udev = TCMU_DEV(cmd->se_dev);
sense_reason_t ret;

switch (udev->pass_level) {
case TCMU_PASS_ALL:
/* We're just like pscsi, then */
/*
* For REPORT LUNS we always need to emulate the response, for everything
* else, pass it up.
*/
switch (cdb[0]) {
case REPORT_LUNS:
cmd->execute_cmd = spc_emulate_report_luns;
break;
case READ_6:
case READ_10:
case READ_12:
case READ_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
case WRITE_VERIFY:
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
/* FALLTHROUGH */
default:
cmd->execute_cmd = tcmu_pass_op;
}
ret = TCM_NO_SENSE;
break;
case TCMU_PASS_IO:
ret = sbc_parse_cdb(cmd, &tcmu_sbc_ops);
break;
default:
pr_err("Unknown tcm-user pass level %d\n", udev->pass_level);
ret = TCM_CHECK_CONDITION_ABORT_CMD;
}

return ret;
return sbc_parse_cdb(cmd, &tcmu_sbc_ops);
}

DEF_TB_DEFAULT_ATTRIBS(tcmu);
Expand Down

0 comments on commit 8ee83a7

Please sign in to comment.