Commit 557d426c authored by Douglas Gilbert's avatar Douglas Gilbert Committed by Jaroslav Kysela

[PATCH] scsi generic (sg) driver 2.5.10

    Changes since 3.5.24 (20020319)
        - use Scsi_Request::upper_private_data
        - zero buffers for non-root users
    Changes since 3.5.23 (20011231)
        - change EACCES to EPERM when O_RDONLY is insufficient
        - suppress newlines in host string
        - fix xfer direction, old interface, short reply_len [Travers Carter]
parent 474018b8
...@@ -666,6 +666,8 @@ struct scsi_request { ...@@ -666,6 +666,8 @@ struct scsi_request {
unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
unsigned sr_underflow; /* Return error if less than unsigned sr_underflow; /* Return error if less than
this amount is transferred */ this amount is transferred */
void * upper_private_data; /* reserved for owner (usually upper
level driver) of this request */
}; };
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Original driver (sg.c): * Original driver (sg.c):
* Copyright (C) 1992 Lawrence Foard * Copyright (C) 1992 Lawrence Foard
* Version 2 and 3 extensions to driver: * Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2001 Douglas Gilbert * Copyright (C) 1998 - 2002 Douglas Gilbert
* *
* Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support * Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
* *
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static char sg_version_str[] = "Version: 3.5.23 (20020103)"; static char * sg_version_str = "Version: 3.5.25 (20020425)";
#endif #endif
static int sg_version_num = 30523; /* 2 digits for each component */ static int sg_version_num = 30525; /* 2 digits for each component */
/* /*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
...@@ -285,7 +285,7 @@ static int sg_open(struct inode * inode, struct file * filp) ...@@ -285,7 +285,7 @@ static int sg_open(struct inode * inode, struct file * filp)
if (flags & O_EXCL) { if (flags & O_EXCL) {
if (O_RDONLY == (flags & O_ACCMODE)) { if (O_RDONLY == (flags & O_ACCMODE)) {
retval = -EACCES; /* Can't lock it with read only access */ retval = -EPERM; /* Can't lock it with read only access */
goto error_out; goto error_out;
} }
if (sdp->headfp && (flags & O_NONBLOCK)) if (sdp->headfp && (flags & O_NONBLOCK))
...@@ -574,7 +574,7 @@ static ssize_t sg_write(struct file * filp, const char * buf, ...@@ -574,7 +574,7 @@ static ssize_t sg_write(struct file * filp, const char * buf,
hp->iovec_count = 0; hp->iovec_count = 0;
hp->mx_sb_len = 0; hp->mx_sb_len = 0;
if (input_size > 0) if (input_size > 0)
hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ? hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
else else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
...@@ -643,7 +643,7 @@ static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, ...@@ -643,7 +643,7 @@ static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
if (read_only && if (read_only &&
(! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { (! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
sg_remove_request(sfp, srp); sg_remove_request(sfp, srp);
return -EACCES; return -EPERM;
} }
k = sg_common_write(sfp, srp, cmnd, timeout, blocking); k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
if (k < 0) return k; if (k < 0) return k;
...@@ -718,6 +718,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, ...@@ -718,6 +718,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
default: default:
SRpnt->sr_data_direction = SCSI_DATA_NONE; break; SRpnt->sr_data_direction = SCSI_DATA_NONE; break;
} }
SRpnt->upper_private_data = srp;
srp->data.k_use_sg = 0; srp->data.k_use_sg = 0;
srp->data.sglist_len = 0; srp->data.sglist_len = 0;
srp->data.bufflen = 0; srp->data.bufflen = 0;
...@@ -972,7 +973,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp, ...@@ -972,7 +973,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
copy_from_user(&opcode, siocp->data, 1); copy_from_user(&opcode, siocp->data, 1);
if (! sg_allow_access(opcode, sdp->device->type)) if (! sg_allow_access(opcode, sdp->device->type))
return -EACCES; return -EPERM;
} }
return scsi_ioctl_send_command(sdp->device, (void *)arg); return scsi_ioctl_send_command(sdp->device, (void *)arg);
case SG_SET_DEBUG: case SG_SET_DEBUG:
...@@ -989,7 +990,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp, ...@@ -989,7 +990,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
return scsi_ioctl(sdp->device, cmd_in, (void *)arg); return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
default: default:
if (read_only) if (read_only)
return -EACCES; /* don't know so take safe approach */ return -EPERM; /* don't know so take safe approach */
return scsi_ioctl(sdp->device, cmd_in, (void *)arg); return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
} }
} }
...@@ -1188,43 +1189,28 @@ static int sg_mmap(struct file * filp, struct vm_area_struct *vma) ...@@ -1188,43 +1189,28 @@ static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
* mid level when a command is completed (or has failed). */ * mid level when a command is completed (or has failed). */
static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
{ {
Scsi_Request * SRpnt = SCpnt->sc_request; Scsi_Request * SRpnt = NULL;
int dev = minor(SRpnt->sr_request.rq_dev);
Sg_device * sdp = NULL; Sg_device * sdp = NULL;
Sg_fd * sfp; Sg_fd * sfp;
Sg_request * srp = NULL; Sg_request * srp = NULL;
read_lock(&sg_dev_arr_lock); if (SCpnt && (SRpnt = SCpnt->sc_request))
if (sg_dev_arr && (dev >= 0)) { srp = (Sg_request *)SRpnt->upper_private_data;
if (dev < sg_template.dev_max) if (NULL == srp) {
sdp = sg_dev_arr[dev]; printk(KERN_ERR "sg_cmd_done_bh: NULL request\n");
} if (SRpnt)
if ((NULL == sdp) || sdp->detached) {
read_unlock(&sg_dev_arr_lock);
SCSI_LOG_TIMEOUT(1, printk("sg...bh: dev=%d gone\n", dev));
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
SRpnt = NULL;
return; return;
} }
sfp = sdp->headfp; sfp = srp->parentfp;
while (sfp) { if (sfp)
read_lock(&sfp->rq_list_lock); sdp = sfp->parentdp;
for (srp = sfp->headrp; srp; srp = srp->nextrp) { if ((NULL == sdp) || sdp->detached) {
if (SRpnt == srp->my_cmdp) printk(KERN_INFO "sg_cmd_done_bh: device detached\n");
break;
}
read_unlock(&sfp->rq_list_lock);
if (srp)
break;
sfp = sfp->nextfp;
}
if (! srp) {
read_unlock(&sg_dev_arr_lock);
SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev));
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
SRpnt = NULL;
return; return;
} }
/* First transfer ownership of data buffers to sg_device object. */ /* First transfer ownership of data buffers to sg_device object. */
srp->data.k_use_sg = SRpnt->sr_use_sg; srp->data.k_use_sg = SRpnt->sr_use_sg;
srp->data.sglist_len = SRpnt->sr_sglist_len; srp->data.sglist_len = SRpnt->sr_sglist_len;
...@@ -1240,10 +1226,10 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) ...@@ -1240,10 +1226,10 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
srp->my_cmdp = NULL; srp->my_cmdp = NULL;
srp->done = 1; srp->done = 1;
read_unlock(&sg_dev_arr_lock);
SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n",
dev, srp->header.pack_id, (int)SRpnt->sr_result)); minor(sdp->i_rdev), srp->header.pack_id,
(int)SRpnt->sr_result));
srp->header.resid = SCpnt->resid; srp->header.resid = SCpnt->resid;
/* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */
/* N.B. unit of duration changes here from jiffies to millisecs */ /* N.B. unit of duration changes here from jiffies to millisecs */
...@@ -2443,7 +2429,11 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) ...@@ -2443,7 +2429,11 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
return resp; return resp;
if (SG_HEAP_KMAL == mem_src) { if (SG_HEAP_KMAL == mem_src) {
resp = kmalloc(rqSz, page_mask); resp = kmalloc(rqSz, page_mask);
if (resp && retSzp) *retSzp = rqSz; if (resp) {
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
memset(resp, 0, rqSz);
if (retSzp) *retSzp = rqSz;
}
return resp; return resp;
} }
else if (SG_HEAP_PAGE == mem_src) { else if (SG_HEAP_PAGE == mem_src) {
...@@ -2460,8 +2450,12 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) ...@@ -2460,8 +2450,12 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
resp = (char *)__get_free_pages(page_mask, order); /* try half */ resp = (char *)__get_free_pages(page_mask, order); /* try half */
resSz = a_size; resSz = a_size;
} }
if (resp) {
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
memset(resp, 0, resSz);
if (retSzp) *retSzp = resSz; if (retSzp) *retSzp = resSz;
} }
}
else else
printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n",
mem_src, rqSz); mem_src, rqSz);
...@@ -2581,9 +2575,9 @@ static inline unsigned sg_jif_to_ms(int jifs) ...@@ -2581,9 +2575,9 @@ static inline unsigned sg_jif_to_ms(int jifs)
} }
} }
static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE,
READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
MODE_SENSE, MODE_SENSE_10}; MODE_SENSE, MODE_SENSE_10, LOG_SENSE};
static int sg_allow_access(unsigned char opcode, char dev_type) static int sg_allow_access(unsigned char opcode, char dev_type)
{ {
...@@ -2983,17 +2977,28 @@ static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset, ...@@ -2983,17 +2977,28 @@ static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset,
int size, int * eof, void * data) int size, int * eof, void * data)
{ SG_PROC_READ_FN(sg_proc_hoststrs_info); } { SG_PROC_READ_FN(sg_proc_hoststrs_info); }
#define SG_MAX_HOST_STR_LEN 256
static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin,
off_t offset, int size) off_t offset, int size)
{ {
struct Scsi_Host * shp; struct Scsi_Host * shp;
int k; int k;
char buff[SG_MAX_HOST_STR_LEN];
char * cp;
for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) {
for ( ; k < shp->host_no; ++k) for ( ; k < shp->host_no; ++k)
PRINT_PROC("<no active host>\n"); PRINT_PROC("<no active host>\n");
PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
(shp->hostt->name ? shp->hostt->name : "<no name>")); (shp->hostt->name ? shp->hostt->name : "<no name>"),
SG_MAX_HOST_STR_LEN);
buff[SG_MAX_HOST_STR_LEN - 1] = '\0';
for (cp = buff; *cp; ++cp) {
if ('\n' == *cp)
*cp = ' '; /* suppress imbedded newlines */
}
PRINT_PROC("%s\n", buff);
} }
return 1; return 1;
} }
......
...@@ -9,11 +9,18 @@ ...@@ -9,11 +9,18 @@
Original driver (sg.h): Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard * Copyright (C) 1992 Lawrence Foard
Version 2 and 3 extensions to driver: Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2001 Douglas Gilbert * Copyright (C) 1998 - 2002 Douglas Gilbert
Version: 3.5.23 (20011231) Version: 3.5.25 (20020425)
This version is for 2.5 series kernels. This version is for 2.5 series kernels.
Changes since 3.5.24 (20020319)
- use Scsi_Request::upper_private_data
- zero buffers for non-root users
Changes since 3.5.23 (20011231)
- change EACCES to EPERM when O_RDONLY is insufficient
- suppress newlines in host string
- fix xfer direction, old interface, short reply_len [Travers Carter]
Changes since 3.1.22 (20011208) Changes since 3.1.22 (20011208)
- branch sg driver for lk 2.5 series - branch sg driver for lk 2.5 series
- remove lock_kernel() from sg_close() - remove lock_kernel() from sg_close()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment