* 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).
#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);
#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.
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;
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;
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 {
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;
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)
{
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;
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);
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,
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;
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);
}
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));