sg: relax 16 byte cdb restriction
[cascardo/linux.git] / drivers / scsi / sg.c
index df5e961..37fb44b 100644 (file)
@@ -7,9 +7,7 @@
  * Original driver (sg.c):
  *        Copyright (C) 1992 Lawrence Foard
  * Version 2 and 3 extensions to driver:
- *        Copyright (C) 1998 - 2005 Douglas Gilbert
- *
- *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support
+ *        Copyright (C) 1998 - 2014 Douglas Gilbert
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  */
 
-static int sg_version_num = 30534;     /* 2 digits for each component */
-#define SG_VERSION_STR "3.5.34"
+static int sg_version_num = 30536;     /* 2 digits for each component */
+#define SG_VERSION_STR "3.5.36"
 
 /*
- *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
+ *  D. P. Gilbert (dgilbert@interlog.com), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
  *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
  *        (otherwise the macros compile to empty statements).
@@ -64,7 +62,7 @@ static int sg_version_num = 30534;    /* 2 digits for each component */
 
 #ifdef CONFIG_SCSI_PROC_FS
 #include <linux/proc_fs.h>
-static char *sg_version_date = "20061027";
+static char *sg_version_date = "20140603";
 
 static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
@@ -74,6 +72,12 @@ static void sg_proc_cleanup(void);
 
 #define SG_MAX_DEVS 32768
 
+/* SG_MAX_CDB_SIZE should be 260 (spc4r37 section 3.1.30) however the type
+ * of sg_io_hdr::cmd_len can only represent 255. All SCSI commands greater
+ * than 16 bytes are "variable length" whose length is a multiple of 4
+ */
+#define SG_MAX_CDB_SIZE 252
+
 /*
  * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
  * Then when using 32 bit integers x * m may overflow during the calculation.
@@ -161,7 +165,7 @@ typedef struct sg_fd {              /* holds the state of a file descriptor */
        char low_dma;           /* as in parent but possibly overridden to 1 */
        char force_packid;      /* 1 -> pack_id input to read(), 0 -> ignored */
        char cmd_q;             /* 1 -> allow command queuing, 0 -> don't */
-       char next_cmd_len;      /* 0 -> automatic (def), >0 -> use on next write() */
+       unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
        char keep_orphan;       /* 0 -> drop orphan (def), 1 -> keep for read() */
        char mmap_called;       /* 0 -> mmap() never called on this fd */
        struct kref f_ref;
@@ -566,7 +570,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        Sg_request *srp;
        struct sg_header old_hdr;
        sg_io_hdr_t *hp;
-       unsigned char cmnd[MAX_COMMAND_SIZE];
+       unsigned char cmnd[SG_MAX_CDB_SIZE];
 
        if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
                return -ENXIO;
@@ -598,12 +602,6 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        buf += SZ_SG_HEADER;
        __get_user(opcode, buf);
        if (sfp->next_cmd_len > 0) {
-               if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
-                       SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
-                       sfp->next_cmd_len = 0;
-                       sg_remove_request(sfp, srp);
-                       return -EIO;
-               }
                cmd_size = sfp->next_cmd_len;
                sfp->next_cmd_len = 0;  /* reset so only this write() effected */
        } else {
@@ -675,7 +673,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
        int k;
        Sg_request *srp;
        sg_io_hdr_t *hp;
-       unsigned char cmnd[MAX_COMMAND_SIZE];
+       unsigned char cmnd[SG_MAX_CDB_SIZE];
        int timeout;
        unsigned long ul_timeout;
 
@@ -806,6 +804,15 @@ static int srp_done(Sg_fd *sfp, Sg_request *srp)
        return ret;
 }
 
+static int max_sectors_bytes(struct request_queue *q)
+{
+       unsigned int max_sectors = queue_max_sectors(q);
+
+       max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9);
+
+       return max_sectors << 9;
+}
+
 static long
 sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
 {
@@ -945,7 +952,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                 if (val < 0)
                         return -EINVAL;
                val = min_t(int, val,
-                           queue_max_sectors(sdp->device->request_queue) * 512);
+                           max_sectors_bytes(sdp->device->request_queue));
                if (val != sfp->reserve.bufflen) {
                        if (sg_res_in_use(sfp) || sfp->mmap_called)
                                return -EBUSY;
@@ -955,7 +962,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                return 0;
        case SG_GET_RESERVED_SIZE:
                val = min_t(int, sfp->reserve.bufflen,
-                           queue_max_sectors(sdp->device->request_queue) * 512);
+                           max_sectors_bytes(sdp->device->request_queue));
                return put_user(val, ip);
        case SG_SET_COMMAND_Q:
                result = get_user(val, ip);
@@ -1095,7 +1102,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
                        return -ENODEV;
                return scsi_ioctl(sdp->device, cmd_in, p);
        case BLKSECTGET:
-               return put_user(queue_max_sectors(sdp->device->request_queue) * 512,
+               return put_user(max_sectors_bytes(sdp->device->request_queue),
                                ip);
        case BLKTRACESETUP:
                return blk_trace_setup(sdp->device->request_queue,
@@ -1645,18 +1652,29 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
        struct request_queue *q = sfp->parentdp->device->request_queue;
        struct rq_map_data *md, map_data;
        int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
+       unsigned char *long_cmdp = NULL;
 
        SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n",
                                   dxfer_len));
 
+       if (hp->cmd_len > BLK_MAX_CDB) {
+               long_cmdp = kzalloc(hp->cmd_len, GFP_KERNEL);
+               if (!long_cmdp)
+                       return -ENOMEM;
+       }
+
        rq = blk_get_request(q, rw, GFP_ATOMIC);
-       if (!rq)
+       if (!rq) {
+               kfree(long_cmdp);
                return -ENOMEM;
+       }
 
-       memcpy(rq->cmd, cmd, hp->cmd_len);
+       blk_rq_set_block_pc(rq);
 
+       if (hp->cmd_len > BLK_MAX_CDB)
+               rq->cmd = long_cmdp;
+       memcpy(rq->cmd, cmd, hp->cmd_len);
        rq->cmd_len = hp->cmd_len;
-       rq->cmd_type = REQ_TYPE_BLOCK_PC;
 
        srp->rq = rq;
        rq->end_io_data = srp;
@@ -1739,6 +1757,8 @@ static int sg_finish_rem_req(Sg_request * srp)
                if (srp->bio)
                        ret = blk_rq_unmap_user(srp->bio);
 
+               if (srp->rq->cmd != srp->rq->__cmd)
+                       kfree(srp->rq->cmd);
                blk_put_request(srp->rq);
        }
 
@@ -2086,7 +2106,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
                sg_big_buff = def_reserved_size;
 
        bufflen = min_t(int, sg_big_buff,
-                       queue_max_sectors(sdp->device->request_queue) * 512);
+                       max_sectors_bytes(sdp->device->request_queue));
        sg_build_reserve(sfp, bufflen);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
                           sfp->reserve.bufflen, sfp->reserve.k_use_sg));