- Add support for varlen CDBs or large vendor specific commands in
  struct request.
- Add support for above at SCSI level API's and devices.
- Add the OSD device type.

Signed-off-by: Benny Halevy <[EMAIL PROTECTED]>
Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]>

---
 block/ll_rw_blk.c         |    2 ++
 drivers/scsi/scsi.c       |   11 ++++++++---
 drivers/scsi/scsi_debug.c |    6 +++++-
 drivers/scsi/scsi_lib.c   |   24 +++++++++++++++++++++---
 drivers/scsi/scsi_scan.c  |    1 +
 include/linux/blkdev.h    |    6 ++++++
 include/scsi/scsi.h       |    2 ++
 include/scsi/scsi_cmnd.h  |   20 +++++++++++++++++++-
 include/scsi/scsi_host.h  |    8 +++-----
 9 files changed, 67 insertions(+), 13 deletions(-)

diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 1358b35..04bc43e 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -256,6 +256,8 @@ static void rq_init(request_queue_t *q,
        rq->q = q;
        rq->special = NULL;
        rq->data = NULL;
+       rq->varlen_cdb_len = 0;
+       rq->varlen_cdb = NULL;
        rq->sense = NULL;
        rq->end_io = NULL;
        rq->end_io_data = NULL;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 24cffd9..f835496 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -485,6 +485,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
        unsigned long flags = 0;
        unsigned long timeout;
        int rtn = 0;
+       int cdb_size;

        /* check if the device is still usable */
        if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
@@ -566,9 +567,13 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
         * Before we queue this command, check if the command
         * length exceeds what the host adapter can handle.
         */
-       if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
-               SCSI_LOG_MLQUEUE(3,
-                               printk("queuecommand : command too long.\n"));
+       cdb_size = cmd->request->varlen_cdb ?
+               cmd->request->varlen_cdb_len : COMMAND_SIZE(cmd->cmnd[0]);
+       if (cdb_size > cmd->device->host->max_cmd_len) {
+               SCSI_LOG_MLQUEUE(0,
+                       printk("queuecommand : command too long. "
+                              "cdb_size(%d) host->max_cmd_len(%d)\n",
+                              cdb_size, cmd->device->host->max_cmd_len));
                cmd->result = (DID_ABORT << 16);

                scsi_done(cmd);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 30ee3d7..8520873 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1993,8 +1993,12 @@ static int scsi_debug_slave_configure(st
        if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
                printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
                       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-       if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+       if (sdp->host->max_cmd_len < SCSI_DEBUG_MAX_CMD_LEN) {
+               printk(KERN_INFO
+                      "scsi_debug: max_cmd_len(%d) < SCSI_DEBUG_MAX_CMD_LEN\n",
+                      sdp->host->max_cmd_len);
                sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+       }
        devip = devInfoReg(sdp);
        sdp->hostdata = devip;
        if (sdp->host->cmd_per_lun)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 92d3d44..d672ade 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -189,8 +189,17 @@ int scsi_execute(struct scsi_device *sde
                                        buffer, bufflen, __GFP_WAIT))
                goto out;

-       req->cmd_len = COMMAND_SIZE(cmd[0]);
+       if (cmd[0] == VARLEN_CDB) {
+               req->varlen_cdb_len = scsi_varlen_cdb_length(cmd);
+               req->varlen_cdb = (unsigned char *)cmd; /* varlen cmd is 
pointed to */
+       }
+       req->cmd_len = min(
+               req->varlen_cdb_len ? req->varlen_cdb_len : 
COMMAND_SIZE(cmd[0]),
+               MAX_COMMAND_SIZE);
        memcpy(req->cmd, cmd, req->cmd_len);
+       if (req->cmd_len < MAX_COMMAND_SIZE)
+               memset(&req->cmd[req->cmd_len], 0, 
MAX_COMMAND_SIZE-req->cmd_len);
+
        req->sense = sense;
        req->sense_len = 0;
        req->retries = retries;
@@ -452,8 +461,6 @@ int scsi_execute_bidi_async(struct scsi_
        if (err)
                goto free_req;

-       req->cmd_len = cmd_len;
-       memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
        if (is_bidi) {
                if (bidi_read_buff->use_sg)
                        err = scsi_req_map_sg(
@@ -469,7 +476,18 @@ int scsi_execute_bidi_async(struct scsi_
                }
        }

+       BUG_ON( (cmd[0]==VARLEN_CDB) && (scsi_varlen_cdb_length(cmd) > cmd_len) 
);
+       /* Unlike scsi_excute, scsi_execute_bidi_xxx supports big commands that 
are not VARLEN_CDB */
+       if ((cmd[0] == VARLEN_CDB) || (cmd_len > MAX_COMMAND_SIZE)) {
+               req->varlen_cdb_len = cmd_len;
+               req->varlen_cdb = cmd;
+       }
+       req->cmd_len = min( cmd_len ? cmd_len : COMMAND_SIZE(cmd[0]),
+               MAX_COMMAND_SIZE);
        memcpy(req->cmd, cmd, req->cmd_len);
+       if(req->cmd_len < MAX_COMMAND_SIZE)
+               memset(&req->cmd[req->cmd_len], 0, 
MAX_COMMAND_SIZE-req->cmd_len);
+
        req->sense = sioc->sense;
        req->sense_len = 0;
        req->timeout = timeout;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 14e635a..2aad10c 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -750,6 +750,7 @@ static int scsi_add_lun(struct scsi_devi
        case TYPE_COMM:
        case TYPE_RAID:
        case TYPE_RBC:
+       case TYPE_OSD:
                sdev->writeable = 1;
                break;
        case TYPE_WORM:
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index eff3960..d805ae4 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -294,6 +294,7 @@ struct request {
        unsigned long start_time;

        unsigned short ioprio;
+       unsigned short varlen_cdb_len; /* length of varlen_cdb buffer */

        void *special;
        char *buffer;                   /* FIXME: should be Deprecated */
@@ -309,6 +310,11 @@ struct request {
         */
        unsigned int cmd_len;
        unsigned char cmd[BLK_MAX_CDB];
+       unsigned char *varlen_cdb;      /* an optional variable-length cdb.
+                                        * first 16 bytes are copied also into 
cmd[].
+                                        * points to a user buffer that must be 
valid
+                                        * until end of request
+                                        */

        unsigned int sense_len;
        void *sense;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 5c0e979..49eec7c 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -96,6 +96,7 @@ #define RELEASE_10            0x57
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define VARLEN_CDB            0x7f
 #define REPORT_LUNS           0xa0
 #define MAINTENANCE_IN        0xa3
 #define MOVE_MEDIUM           0xa5
@@ -219,6 +220,7 @@ #define TYPE_COMM           0x09    /* C
 #define TYPE_RAID           0x0c
 #define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
 #define TYPE_RBC           0x0e
+#define TYPE_OSD            0x11
 #define TYPE_NO_LUN         0x7f

 /* Returns a human-readable name for the device */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 78ae417..ae17fff 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -11,6 +11,24 @@ struct scatterlist;
 struct Scsi_Host;
 struct scsi_device;

+#define SCSI_MAX_VARLEN_CDB_LEN 260
+
+/* defined in T10 SCSI Primary Commands-3 */
+struct scsi_varlen_cdb_hdr {
+       unsigned char opcode;                 /* opcode always == VARLEN_CDB */
+       unsigned char control;
+       unsigned char misc[5];
+       unsigned char additional_cdb_length;  /* total cdb length - 8 */
+       unsigned char service_action[2];
+       /* service specific data follows */
+};
+
+static inline int
+scsi_varlen_cdb_length(const void *hdr)
+{
+       return ((struct scsi_varlen_cdb_hdr*)hdr)->additional_cdb_length + 8;
+}
+
 /*
  * This structure maps data buffers into a scatter-gather list for DMA 
purposes.
  * Embedded in struct scsi_cmnd.
@@ -76,7 +94,7 @@ struct scsi_cmnd {
        int allowed;
        int timeout_per_command;

-       unsigned char cmd_len;
+       unsigned char cmd_len;         /* fixed cdb command length (<= 16) */
        enum dma_data_direction sc_data_direction;

        /* These elements define the operation we are about to perform */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7f1f411..9b77d6c 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -559,13 +559,11 @@ struct Scsi_Host {
        /*
         * The maximum length of SCSI commands that this host can accept.
         * Probably 12 for most host adapters, but could be 16 for others.
+        * or 260 if the driver supports variable length cdbs.
         * For drivers that don't set this field, a value of 12 is
-        * assumed.  I am leaving this as a number rather than a bit
-        * because you never know what subsequent SCSI standards might do
-        * (i.e. could there be a 20 byte or a 24-byte command a few years
-        * down the road?).
+        * assumed.
         */
-       unsigned char max_cmd_len;
+       unsigned short max_cmd_len;

        int this_id;
        int can_queue;
-- 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to