Find attached a patch that adds a "service action" framework to stgt
and as an example
adds MaintenanceIn/ReportSupportedOpcodes (0xa3/0x0c).

Patch is also attached in gzip format if gmail decides to mangle the
pasted text.

I have reworked the patch and implemented the changes suggested.

regards
ronnie sahlberg


>From 58bbd3fa1ee8f05ed82071c2939fd48e507797a8 Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <[EMAIL PROTECTED]>
Date: Mon, 26 May 2008 14:55:50 +1000
Subject: [PATCH 1/1] add infrastructure to handle commands taking
service actions

implement Maintenance / ReportAllSupportedOpcodes as an example

Expand device_type_operations to also include a list of possible service
actions for this cdb. We need to know how many/what service actions
a certain cdb can take in order to be able to report
SupportedOpcodes properly. (MaintIn/service action 0x0c)

Implement MaintenanceIn and implement service action 0x0c for this command.
the provided infrastructure should make it easier to add other MaintIn
service actions, of which there are quite a few.

there are many other opcodes that also take service actions and which
could build on this framework:
0xa4 MaintOut
0x7f: variable length cdb
0x5e/0x5f persistent reservarion in/out
0xab
0x9e
0x9f

Signed-off-by: Ronnie Sahlberg <[EMAIL PROTECTED]>
---
 usr/sbc.c  |    2 +-
 usr/scc.c  |    2 +-
 usr/scsi.c |   10 ++++
 usr/smc.c  |    2 +-
 usr/spc.c  |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 usr/spc.h  |    2 +
 usr/tgtd.h |    8 +++
 7 files changed, 193 insertions(+), 3 deletions(-)

diff --git a/usr/sbc.c b/usr/sbc.c
index 5612ebe..13dd33c 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -384,7 +384,7 @@ static struct device_type_template sbc_template = {
                {spc_report_luns,},
                {spc_illegal_op,},
                {spc_illegal_op,},
-               {spc_illegal_op,},
+               {spc_maint_in, maint_in_service_actions,},
                {spc_illegal_op,},
                {spc_illegal_op,},
                {spc_illegal_op,},
diff --git a/usr/scc.c b/usr/scc.c
index 7a6a66e..eed48a0 100644
--- a/usr/scc.c
+++ b/usr/scc.c
@@ -143,7 +143,7 @@ static struct device_type_template scc_template = {
                {spc_report_luns,},
                {spc_illegal_op,},
                {spc_illegal_op,},
-               {spc_illegal_op,},
+               {spc_maint_in, maint_in_service_actions,},
                {spc_illegal_op,},
                {spc_illegal_op,},
                {spc_illegal_op,},
diff --git a/usr/scsi.c b/usr/scsi.c
index 37d50dd..daf4aef 100644
--- a/usr/scsi.c
+++ b/usr/scsi.c
@@ -44,6 +44,16 @@ static unsigned char scsi_command_size[8] = {6, 10,
10, 12, 16, 12, 10, 10};
 #define CDB_SIZE(cmd) (((((cmd)->scb[0] >> 5) & 7) < 6) ? \
                                COMMAND_SIZE((cmd)->scb[0]) : (cmd)->scb_len)

+int get_scsi_command_size(unsigned char op)
+{
+       return COMMAND_SIZE(op);
+}
+
+int get_scsi_cdb_size(struct scsi_cmd *cmd)
+{
+       return CDB_SIZE(cmd);
+}
+
 void sense_data_build(struct scsi_cmd *cmd, uint8_t key, uint16_t asc)
 {

diff --git a/usr/smc.c b/usr/smc.c
index ef5f1b0..9a46d30 100644
--- a/usr/smc.c
+++ b/usr/smc.c
@@ -805,7 +805,7 @@ struct device_type_template smc_template = {
                {spc_report_luns,},
                {spc_illegal_op,},
                {spc_illegal_op,},
-               {spc_illegal_op,},
+               {spc_maint_in, maint_in_service_actions,},
                {spc_illegal_op,},
                {smc_move_medium,},
                {spc_illegal_op,},
diff --git a/usr/spc.c b/usr/spc.c
index e3e4d98..eafae8e 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -431,6 +431,176 @@ sense:
        return SAM_STAT_CHECK_CONDITION;
 }

+static int report_opcodes_all(struct scsi_cmd *cmd, int rctd,
+uint32_t alloc_len)
+{
+       uint8_t buf[2048], *data;
+       struct device_type_operations *ops;
+       struct service_action *service_action;
+       int i;
+       uint32_t len;
+       int cdb_length;
+
+       /* cant request RCTD for all descriptors */
+       if (rctd) {
+               scsi_set_in_resid_by_actual(cmd, 0);
+               sense_data_build(cmd, ILLEGAL_REQUEST,
+                       ASC_INVALID_FIELD_IN_CDB);
+               return SAM_STAT_CHECK_CONDITION;
+       }
+
+       memset(buf, 0, sizeof(buf));
+       data = &buf[4];
+
+       ops = cmd->dev->dev_type_template.ops;
+       for (i = 0; i < 256; i++) {
+               if (ops[i].cmd_perform == spc_illegal_op)
+                       continue;
+
+               /* this command does not take a service action, so just
+                  report the opcode
+               */
+               if (!ops[i].service_actions) {
+                       *data++ = i;
+
+                       /* reserved */
+                       data++;
+
+                       /* service action */
+                       data += 2;
+
+                       /* reserved */
+                       data++;
+
+                       /* flags : no service action, no command descriptor */
+                       data++;
+
+                       /* cdb length */
+                       cdb_length = get_scsi_command_size(i);
+                       *data++ = (cdb_length >> 8) & 0xff;
+                       *data++ = cdb_length & 0xff;
+
+                       continue;
+               }
+
+               for (service_action = ops[i].service_actions;
+                       service_action->cmd_perform;
+                       service_action++) {
+                       /* opcode */
+                       *data++ = i;
+
+                       /* reserved */
+                       data++;
+
+                       /* service action */
+                       *data++ = (service_action->service_action >> 8) & 0xff;
+                       *data++ = service_action->service_action & 0xff;
+
+                       /* reserved */
+                       data++;
+
+                       /* flags : service action */
+                       *data++ = 0x01;
+
+                       /* cdb length */
+                       cdb_length = get_scsi_command_size(i);
+                       *data++ = (cdb_length >> 8) & 0xff;
+                       *data++ = cdb_length & 0xff;
+               }
+       }
+
+       len = data - &buf[0];
+       len -= 4;
+       buf[0] = (len >> 24) & 0xff;
+       buf[1] = (len >> 16) & 0xff;
+       buf[2] = (len >> 8)  & 0xff;
+       buf[3] = len & 0xff;
+
+       memcpy(scsi_get_in_buffer(cmd), buf,
+              min(scsi_get_in_length(cmd), len+4));
+
+       scsi_set_in_resid_by_actual(cmd, len+4);
+
+       return SAM_STAT_GOOD;
+}
+
+int spc_report_supported_opcodes(int host_no, struct scsi_cmd *cmd)
+{
+       uint8_t reporting_options;
+       uint8_t requested_opcode;
+       uint16_t requested_service_action;
+       uint32_t alloc_len;
+       int rctd;
+       int ret = SAM_STAT_GOOD;
+
+       reporting_options = cmd->scb[2] & 0x07;
+
+       requested_opcode = cmd->scb[3];
+
+       requested_service_action = cmd->scb[4];
+       requested_service_action <<= 8;
+       requested_service_action |= cmd->scb[5];
+
+       alloc_len = (uint32_t)cmd->scb[6] << 24 |
+                       (uint32_t)cmd->scb[7] << 16 |
+                       (uint32_t)cmd->scb[8] << 8 |
+                       (uint32_t)cmd->scb[9];
+
+       rctd = cmd->scb[2] & 0x80;
+
+       switch (reporting_options) {
+       case 0x00: /* report all */
+               ret = report_opcodes_all(cmd, rctd, alloc_len);
+               break;
+       case 0x01: /* report one no service action*/
+       case 0x02: /* report one service action */
+       default:
+               scsi_set_in_resid_by_actual(cmd, 0);
+               sense_data_build(cmd, ILLEGAL_REQUEST,
+                       ASC_INVALID_FIELD_IN_CDB);
+               ret = SAM_STAT_CHECK_CONDITION;
+       }
+
+       return ret;
+}
+
+struct service_action maint_in_service_actions[] = {
+       {0x0c, spc_report_supported_opcodes},
+       {0, NULL}
+};
+
+struct service_action *
+find_service_action(struct service_action *service_action, uint32_t action)
+{
+       while (service_action->cmd_perform) {
+               if (service_action->service_action == action)
+                       return service_action;
+               service_action++;
+       }
+       return NULL;
+}
+
+/**
+ * This functions emulates the various commands using the 0xa3 cdb opcode
+ */
+int spc_maint_in(int host_no, struct scsi_cmd *cmd)
+{
+       uint8_t action;
+       struct service_action *service_action;
+
+       action = cmd->scb[1] & 0x1f;
+       service_action = find_service_action(maint_in_service_actions, action);
+
+       if (!service_action) {
+               scsi_set_in_resid_by_actual(cmd, 0);
+               sense_data_build(cmd, ILLEGAL_REQUEST,
+                               ASC_INVALID_FIELD_IN_CDB);
+               return SAM_STAT_CHECK_CONDITION;
+       }
+
+       return service_action->cmd_perform(host_no, cmd);
+}
+
 int spc_request_sense(int host_no, struct scsi_cmd *cmd)
 {
        scsi_set_in_resid_by_actual(cmd, 0);
diff --git a/usr/spc.h b/usr/spc.h
index a63436a..1a6d8d5 100644
--- a/usr/spc.h
+++ b/usr/spc.h
@@ -1,6 +1,8 @@
 #ifndef __SPC_H
 #define __SPC_H

+extern struct service_action maint_in_service_actions[];
+extern int spc_maint_in(int host_no, struct scsi_cmd *cmd);
 extern int spc_inquiry(int host_no, struct scsi_cmd *cmd);
 extern int spc_report_luns(int host_no, struct scsi_cmd *cmd);
 extern int spc_start_stop(int host_no, struct scsi_cmd *cmd);
diff --git a/usr/tgtd.h b/usr/tgtd.h
index e516b0a..36bc0d6 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -80,8 +80,14 @@ struct it_nexus_lu_info {
        struct list_head pending_ua_sense_list;
 };

+struct service_action {
+       uint32_t service_action;
+       int (*cmd_perform)(int host_no, struct scsi_cmd *cmd);
+};
+
 struct device_type_operations {
        int (*cmd_perform)(int host_no, struct scsi_cmd *cmd);
+       struct service_action *service_actions;
 };

 struct device_type_template {
@@ -218,6 +224,8 @@ extern uint64_t scsi_rw_offset(uint8_t *scb);
 extern uint32_t scsi_rw_count(uint8_t *scb);
 extern int scsi_is_io_opcode(unsigned char op);
 extern enum data_direction scsi_data_dir_opcode(unsigned char op);
+extern int get_scsi_cdb_size(struct scsi_cmd *cmd);
+extern int get_scsi_command_size(unsigned char op);

 extern enum scsi_target_state tgt_get_target_state(int tid);
 extern int tgt_set_target_state(int tid, char *str);
-- 
1.5.5

Attachment: 0001-add-infrastructure-to-handle-commands-taking-service.patch.gz
Description: GNU Zip compressed data

_______________________________________________
Stgt-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/stgt-devel

Reply via email to