[RFC 5/6] bidi support: varlen + OSD support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



- 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/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux