Commit 8ee83a74 authored by Andy Grover's avatar Andy Grover Committed by Nicholas Bellinger

target/user: Disallow full passthrough (pass_level=0)

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: default avatarAndy Grover <agrover@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent a928d28d
...@@ -15,7 +15,7 @@ Contents: ...@@ -15,7 +15,7 @@ Contents:
a) Discovering and configuring TCMU uio devices a) Discovering and configuring TCMU uio devices
b) Waiting for events on the device(s) b) Waiting for events on the device(s)
c) Managing the command ring c) Managing the command ring
3) Command filtering and pass_level 3) Command filtering
4) A final note 4) A final note
...@@ -360,17 +360,13 @@ int handle_device_events(int fd, void *map) ...@@ -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 Initial TCMU support is for a filtered commandset. Only IO-related
the value is 0 (the default), nearly all SCSI commands received for commands are presented to userspace, and the rest are handled by LIO's
the device are passed through to the handler. This allows maximum in-kernel command emulation. The commands presented are all versions
flexibility but increases the amount of code required by the handler, of:
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:
READ READ
WRITE WRITE
......
...@@ -71,13 +71,6 @@ struct tcmu_hba { ...@@ -71,13 +71,6 @@ struct tcmu_hba {
u32 host_id; 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 #define TCMU_CONFIG_LEN 256
struct tcmu_dev { struct tcmu_dev {
...@@ -89,7 +82,6 @@ struct tcmu_dev { ...@@ -89,7 +82,6 @@ struct tcmu_dev {
#define TCMU_DEV_BIT_OPEN 0 #define TCMU_DEV_BIT_OPEN 0
#define TCMU_DEV_BIT_BROKEN 1 #define TCMU_DEV_BIT_BROKEN 1
unsigned long flags; unsigned long flags;
enum passthru_level pass_level;
struct uio_info uio_info; struct uio_info uio_info;
...@@ -683,8 +675,6 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) ...@@ -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, setup_timer(&udev->timeout, tcmu_device_timedout,
(unsigned long)udev); (unsigned long)udev);
udev->pass_level = TCMU_PASS_ALL;
return &udev->se_dev; return &udev->se_dev;
} }
...@@ -948,13 +938,12 @@ static void tcmu_free_device(struct se_device *dev) ...@@ -948,13 +938,12 @@ static void tcmu_free_device(struct se_device *dev)
} }
enum { 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 = { static match_table_t tokens = {
{Opt_dev_config, "dev_config=%s"}, {Opt_dev_config, "dev_config=%s"},
{Opt_dev_size, "dev_size=%u"}, {Opt_dev_size, "dev_size=%u"},
{Opt_pass_level, "pass_level=%u"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -965,7 +954,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, ...@@ -965,7 +954,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
char *orig, *ptr, *opts, *arg_p; char *orig, *ptr, *opts, *arg_p;
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
int ret = 0, token; int ret = 0, token;
int arg;
opts = kstrdup(page, GFP_KERNEL); opts = kstrdup(page, GFP_KERNEL);
if (!opts) if (!opts)
...@@ -998,16 +986,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, ...@@ -998,16 +986,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
if (ret < 0) if (ret < 0)
pr_err("kstrtoul() failed for dev_size=\n"); pr_err("kstrtoul() failed for dev_size=\n");
break; 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: default:
break; break;
} }
...@@ -1024,8 +1002,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b) ...@@ -1024,8 +1002,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)
bl = sprintf(b + bl, "Config: %s ", bl = sprintf(b + bl, "Config: %s ",
udev->dev_config[0] ? udev->dev_config : "NULL"); udev->dev_config[0] ? udev->dev_config : "NULL");
bl += sprintf(b + bl, "Size: %zu PassLevel: %u\n", bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size);
udev->dev_size, udev->pass_level);
return bl; return bl;
} }
...@@ -1074,46 +1051,7 @@ static struct sbc_ops tcmu_sbc_ops = { ...@@ -1074,46 +1051,7 @@ static struct sbc_ops tcmu_sbc_ops = {
static sense_reason_t static sense_reason_t
tcmu_parse_cdb(struct se_cmd *cmd) tcmu_parse_cdb(struct se_cmd *cmd)
{ {
unsigned char *cdb = cmd->t_task_cdb; return sbc_parse_cdb(cmd, &tcmu_sbc_ops);
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;
} }
DEF_TB_DEFAULT_ATTRIBS(tcmu); DEF_TB_DEFAULT_ATTRIBS(tcmu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment