[stgt] [PATCH 1/2] [tgt]: Add proper STGT LUN backstore passthrough support
Nicholas A. Bellinger
nab at linux-iscsi.org
Tue Jun 1 10:50:45 CEST 2010
From: Nicholas Bellinger <nab at linux-iscsi.org>
This patch adds two new queueing and completion function pointers to struct scsi_lu called ->cmd_perform()
and ->cmd_done() for handling existing internal STGT port emulation and the struct scsi_cmd
passthrough with bs_sg.c. It retains the struct device_type_template->cmd_passthrough()
from the original patches, which still appears to be necessary for a device type to perform passthrough.
Also as before we modify the struct device_type_template sbc_template->cmd_passthrough() for sbc.c /
TYPE_DISK that we want to use passthrough for bs_sg LUNs.
For the setup path, we update tgt_device_create() to check if lu->cmd_perform() and lu->cmd_done()
have been set by struct backingstore_template->bs_init(). We expect bs_sg to setup these
pointers for us using the new target_cmd_perform_passthrough() and __cmd_done_passthrough() (see below).
Otherwise we setup the pointers following existing logic with target_cmd_perform() (also below) and
__cmd_done() for the non bs_sg case.
For the queue path and struct scsi_lu->cmd_perform() it made sense to split up target_cmd_queue()
into two functions, the original code at the tail of target_cmd_queue() now becomes
target_cmd_perform() and calls existing STGT port emulation code via cmd_enabled() -> scsi_cmd_perform().
A new function for passthrough has been added called target_cmd_perform_passthrough() that will do
struct scsi_lu->dev_type_template.cmd_passthrough() into the device type for bs_sg LUNs.
For the completion path and struct scsi_lu->cmd_done(), a new __cmd_done_passthrough()
has been added minus the original cmd_hlist_remove() and SCSI TASK attr checking in
__cmd_done(). __cmd_done() is used for the existing port emulation case, and modify the
two original users target_cmd_lookup() and abort_cmd() to call cmd->dev->cmd_done() instead.
This patch has been tested with STGT/iSCSI and TCM_Loop SPC-4 iSCSI Target Port emulation.
Signed-off-by: Nicholas A. Bellinger <nab at linux-iscsi.org>
---
usr/sbc.c | 1 +
usr/target.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
usr/tgtd.h | 15 +++++++++
3 files changed, 100 insertions(+), 8 deletions(-)
diff --git a/usr/sbc.c b/usr/sbc.c
index a048d53..d53f7f9 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -269,6 +269,7 @@ static struct device_type_template sbc_template = {
.lu_online = spc_lu_online,
.lu_offline = spc_lu_offline,
.lu_exit = spc_lu_exit,
+ .cmd_passthrough = sbc_rw,
.ops = {
{spc_test_unit,},
{spc_illegal_op,},
diff --git a/usr/target.c b/usr/target.c
index c848757..ac91f7e 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -425,6 +425,8 @@ static match_table_t device_tokens = {
{Opt_err, NULL},
};
+static void __cmd_done(struct target *, struct scsi_cmd *);
+
int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
int backing)
{
@@ -515,6 +517,26 @@ int tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
if (ret)
goto fail_lu_init;
}
+ /*
+ * Check if struct scsi_lu->cmd_perform() has been filled in
+ * by the SG_IO backstore for passthrough (SG_IO) in ->bs_init() call.
+ * If the function pointer does not exist, use the default internal
+ * target_cmd_perform() and __cmd_done() calls.
+ */
+ if (!(lu->cmd_perform)) {
+ lu->cmd_perform = &target_cmd_perform;
+ lu->cmd_done = &__cmd_done;
+ } else if (!(lu->cmd_done)) {
+ eprintf("Unable to locate struct scsi_lu->cmd_done() with"
+ " valid ->cmd_perform()\n");
+ ret = TGTADM_INVALID_REQUEST;
+ goto fail_bs_init;
+ } else if (!(lu->dev_type_template.cmd_passthrough)) {
+ eprintf("Unable to locate ->cmd_passthrough() handler"
+ " for device type template\n");
+ ret = TGTADM_INVALID_REQUEST;
+ goto fail_bs_init;
+ }
if (backing && !path && !lu->attrs.removable) {
ret = TGTADM_INVALID_REQUEST;
@@ -828,9 +850,7 @@ static struct it_nexus_lu_info *it_nexus_lu_info_lookup(struct it_nexus *itn,
int target_cmd_queue(int tid, struct scsi_cmd *cmd)
{
struct target *target;
- struct tgt_cmd_queue *q;
struct it_nexus *itn;
- int result, enabled = 0;
uint64_t dev_id, itn_id = cmd->cmd_itn_id;
itn = it_nexus_lookup(tid, itn_id);
@@ -857,16 +877,28 @@ int target_cmd_queue(int tid, struct scsi_cmd *cmd)
/* service delivery or target failure */
if (target->target_state != SCSI_TARGET_READY)
return -EBUSY;
+ /*
+ * Call struct scsi_lu->cmd_perform() that will either be setup for
+ * internal or passthrough CDB processing using 2 functions below.
+ */
+ return cmd->dev->cmd_perform(tid, cmd);
+}
- cmd_hlist_insert(itn, cmd);
+/*
+ * Used by all non bs_sg backstores for internal STGT port emulation
+ */
+int target_cmd_perform(int tid, struct scsi_cmd *cmd)
+{
+ struct tgt_cmd_queue *q = &cmd->dev->cmd_queue;
+ int result, enabled = 0;
- q = &cmd->dev->cmd_queue;
+ cmd_hlist_insert(cmd->it_nexus, cmd);
enabled = cmd_enabled(q, cmd);
- dprintf("%p %x %" PRIx64 " %d\n", cmd, cmd->scb[0], dev_id, enabled);
+ dprintf("%p %x %" PRIx64 " %d\n", cmd, cmd->scb[0], cmd->dev_id, enabled);
if (enabled) {
- result = scsi_cmd_perform(itn->host_no, cmd);
+ result = scsi_cmd_perform(cmd->it_nexus->host_no, cmd);
cmd_post_perform(q, cmd);
@@ -890,6 +922,30 @@ int target_cmd_queue(int tid, struct scsi_cmd *cmd)
return 0;
}
+/*
+ * Used by bs_sg for CDB passthrough to STGT LUNs
+ */
+int target_cmd_perform_passthrough(int tid, struct scsi_cmd *cmd)
+{
+ int result;
+
+ dprintf("%p %x %" PRIx64 " PT \n", cmd, cmd->scb[0], cmd->dev_id);
+
+ result = cmd->dev->dev_type_template.cmd_passthrough(tid, cmd);
+
+ dprintf("%" PRIx64 " %x %p %p %" PRIu64 " %u %u %d %d\n",
+ cmd->tag, cmd->scb[0], scsi_get_out_buffer(cmd),
+ scsi_get_in_buffer(cmd), cmd->offset,
+ scsi_get_out_length(cmd), scsi_get_in_length(cmd),
+ result, cmd_async(cmd));
+
+ set_cmd_processed(cmd);
+ if (!cmd_async(cmd))
+ target_cmd_io_done(cmd, result);
+
+ return 0;
+}
+
void target_cmd_io_done(struct scsi_cmd *cmd, int result)
{
scsi_set_result(cmd, result);
@@ -924,6 +980,10 @@ static void post_cmd_done(struct tgt_cmd_queue *q)
}
}
+/*
+ * Used by struct scsi_lu->cmd_done() for normal internal completion
+ * (non passthrough)
+ */
static void __cmd_done(struct target *target, struct scsi_cmd *cmd)
{
struct tgt_cmd_queue *q;
@@ -949,6 +1009,22 @@ static void __cmd_done(struct target *target, struct scsi_cmd *cmd)
post_cmd_done(q);
}
+/*
+ * Used by struct scsi_lu->cmd_done() for bs_sg (passthrough) completion
+ */
+void __cmd_done_passthrough(struct target *target, struct scsi_cmd *cmd)
+{
+ int err;
+
+ err = target->bst->bs_cmd_done(cmd);
+
+ dprintf("%d %p %p %u %u %d\n", cmd_mmapio(cmd), scsi_get_out_buffer(cmd),
+ scsi_get_in_buffer(cmd), scsi_get_out_length(cmd),
+ scsi_get_in_length(cmd), err);
+
+ post_cmd_done(&cmd->dev->cmd_queue);
+}
+
struct scsi_cmd *target_cmd_lookup(int tid, uint64_t itn_id, uint64_t tag)
{
struct scsi_cmd *cmd;
@@ -973,7 +1049,7 @@ void target_cmd_done(struct scsi_cmd *cmd)
free(mreq);
}
- __cmd_done(cmd->c_target, cmd);
+ cmd->dev->cmd_done(cmd->c_target, cmd);
}
static int abort_cmd(struct target* target, struct mgmt_req *mreq,
@@ -992,7 +1068,7 @@ static int abort_cmd(struct target* target, struct mgmt_req *mreq,
cmd->mreq = mreq;
err = -EBUSY;
} else {
- __cmd_done(target, cmd);
+ cmd->dev->cmd_done(target, cmd);
target_cmd_io_done(cmd, TASK_ABORTED);
}
return err;
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 3323a9b..ff3c5da 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -108,6 +108,7 @@ struct device_type_template {
int (*lu_config)(struct scsi_lu *lu, char *args);
int (*lu_online)(struct scsi_lu *lu);
int (*lu_offline)(struct scsi_lu *lu);
+ int (*cmd_passthrough)(int, struct scsi_cmd *);
struct device_type_operations ops[256];
@@ -178,6 +179,17 @@ struct scsi_lu {
* Currently used by ssc, smc and mmc modules.
*/
void *xxc_p;
+ /*
+ * Used internally for usr/target.c:target_cmd_perform() and with
+ * passthrough CMD processing with
+ * struct device_type_template->cmd_passthrough().
+ */
+ int (*cmd_perform)(int, struct scsi_cmd *);
+ /*
+ * Used internally for usr/target.c:__cmd_done() and with
+ * passthrough CMD processing with __cmd_done_passthrough()
+ */
+ void (*cmd_done)(struct target *, struct scsi_cmd *);
};
struct mgmt_req {
@@ -250,7 +262,10 @@ extern void tgt_remove_sched_event(struct event_data *evt);
extern int tgt_event_modify(int fd, int events);
extern int target_cmd_queue(int tid, struct scsi_cmd *cmd);
+extern int target_cmd_perform(int tid, struct scsi_cmd *cmd);
+extern int target_cmd_perform_passthrough(int tid, struct scsi_cmd *cmd);
extern void target_cmd_done(struct scsi_cmd *cmd);
+extern void __cmd_done_passthrough(struct target *target, struct scsi_cmd *cmd);
struct scsi_cmd *target_cmd_lookup(int tid, uint64_t itn_id, uint64_t tag);
extern enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id,
--
1.5.6.5
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list