patch-2.4.7 linux/drivers/scsi/sg.c
Next file: linux/drivers/scsi/sr.c
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 1202
- Date:
Wed Jul 4 15:39:28 2001
- Orig file:
v2.4.6/linux/drivers/scsi/sg.c
- Orig date:
Mon Jan 15 13:08:15 2001
diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
@@ -7,7 +7,7 @@
* Original driver (sg.c):
* Copyright (C) 1992 Lawrence Foard
* Version 2 and 3 extensions to driver:
- * Copyright (C) 1998 - 2000 Douglas Gilbert
+ * Copyright (C) 1998 - 2001 Douglas Gilbert
*
* Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*
@@ -19,9 +19,9 @@
*/
#include <linux/config.h>
#ifdef CONFIG_PROC_FS
- static char * sg_version_str = "Version: 3.1.17 (20001002)";
+ static char sg_version_str[] = "Version: 3.1.19 (20010623)";
#endif
- static int sg_version_num = 30117; /* 2 digits for each component */
+ static int sg_version_num = 30119; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,8 +76,9 @@
#include <linux/version.h>
#endif /* LINUX_VERSION_CODE */
-/* #define SG_ALLOW_DIO */
-#ifdef SG_ALLOW_DIO
+#define SG_ALLOW_DIO_DEF 0
+#define SG_ALLOW_DIO_CODE /* compile out be commenting this define */
+#ifdef SG_ALLOW_DIO_CODE
#include <linux/iobuf.h>
#endif
@@ -89,6 +90,7 @@
readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
the kernel (i.e. it is not a module).] */
static int def_reserved_size = -1; /* picks up init parameter */
+static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -112,7 +114,7 @@
static int sg_detect(Scsi_Device *);
static void sg_detach(Scsi_Device *);
-static Scsi_Request * dummy_cmdp = 0; /* only used for sizeof */
+static Scsi_Request * dummy_cmdp; /* only used for sizeof */
static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock
file descriptor list for device */
@@ -157,7 +159,7 @@
char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
char orphan; /* 1 -> drop on sight, 0 -> normal */
char sg_io_owned; /* 1 -> packet belongs to SG_IO */
- char done; /* 0->before bh, 1->before read, 2->read */
+ volatile char done; /* 0->before bh, 1->before read, 2->read */
} Sg_request; /* 168 bytes long on i386 */
typedef struct sg_fd /* holds the state of a file descriptor */
@@ -174,12 +176,12 @@
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
char low_dma; /* as in parent but possibly overridden to 1 */
char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
- char closed; /* 1 -> fd closed but request(s) outstanding */
+ volatile char closed; /* 1 -> fd closed but request(s) outstanding */
char fd_mem_src; /* heap whereabouts of this Sg_fd object */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */
-} Sg_fd; /* 2768 bytes long on i386 */
+} Sg_fd; /* 2760 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
{
@@ -189,10 +191,10 @@
Sg_fd * headfp; /* first open fd belonging to this device */
devfs_handle_t de;
kdev_t i_rdev; /* holds device major+minor number */
- char exclude; /* opened for exclusive access */
+ volatile char detached; /* 0->attached, 1->detached pending removal */
+ volatile char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
- char detached; /* 0->attached, 1->detached pending removal */
-} Sg_device; /* 44 bytes long on i386 */
+} Sg_device; /* 36 bytes long on i386 */
static int sg_fasync(int fd, struct file * filp, int mode);
@@ -225,13 +227,12 @@
static void sg_low_free(char * buff, int size, int mem_src);
static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
+static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
static int sg_res_in_use(Sg_fd * sfp);
-static int sg_dio_in_use(Sg_fd * sfp);
static void sg_clr_srpnt(Scsi_Request * SRpnt);
-static void sg_shorten_timeout(Scsi_Request * srpnt);
static int sg_ms_to_jif(unsigned int msecs);
static unsigned sg_jif_to_ms(int jifs);
static int sg_allow_access(unsigned char opcode, char dev_type);
@@ -244,10 +245,10 @@
static Sg_device ** sg_dev_arr = NULL;
-static const int size_sg_header = sizeof(struct sg_header);
-static const int size_sg_io_hdr = sizeof(sg_io_hdr_t);
-static const int size_sg_iovec = sizeof(sg_iovec_t);
-static const int size_sg_req_info = sizeof(sg_req_info_t);
+#define SZ_SG_HEADER sizeof(struct sg_header)
+#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
+#define SZ_SG_IOVEC sizeof(sg_iovec_t)
+#define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
static int sg_open(struct inode * inode, struct file * filp)
@@ -257,43 +258,56 @@
Sg_device * sdp;
Sg_fd * sfp;
int res;
+ int retval = -EBUSY;
+ SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
sdp = sg_get_dev(dev);
- if ((! sdp) || (! sdp->device) || (! sdp->device->host))
- return -ENXIO;
- if (sdp->i_rdev != inode->i_rdev)
- printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n",
- MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
- MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));
- /* If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited. */
- if (! ((flags & O_NONBLOCK) ||
- scsi_block_when_processing_errors(sdp->device)))
+ if ((! sdp) || (! sdp->device))
return -ENXIO;
+ if (sdp->detached)
+ return -ENODEV;
- SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
+ /* This driver's module count bumped by fops_get in <linux/fs.h> */
+ /* Prevent the device driver from vanishing while we sleep */
+ if (sdp->device->host->hostt->module)
+ __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
+
+ if (! ((flags & O_NONBLOCK) ||
+ scsi_block_when_processing_errors(sdp->device))) {
+ retval = -ENXIO;
+ /* we are in error recovery for this device */
+ goto error_out;
+ }
if (flags & O_EXCL) {
- if (O_RDONLY == (flags & O_ACCMODE))
- return -EACCES; /* Can't lock it with read only access */
- if (sdp->headfp && (flags & O_NONBLOCK))
- return -EBUSY;
- res = 0; /* following is a macro that beats race condition */
+ if (O_RDONLY == (flags & O_ACCMODE)) {
+ retval = -EACCES; /* Can't lock it with read only access */
+ goto error_out;
+ }
+ if (sdp->headfp && (flags & O_NONBLOCK))
+ goto error_out;
+ res = 0;
__wait_event_interruptible(sdp->o_excl_wait,
((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),
res);
- if (res)
- return res; /* -ERESTARTSYS because signal hit process */
+ if (res) {
+ retval = res; /* -ERESTARTSYS because signal hit process */
+ goto error_out;
+ }
}
else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
if (flags & O_NONBLOCK)
- return -EBUSY;
- res = 0; /* following is a macro that beats race condition */
+ goto error_out;
+ res = 0;
__wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
- if (res)
- return res; /* -ERESTARTSYS because signal hit process */
+ if (res) {
+ retval = res; /* -ERESTARTSYS because signal hit process */
+ goto error_out;
+ }
+ }
+ if (sdp->detached) {
+ retval = -ENODEV;
+ goto error_out;
}
if (! sdp->headfp) { /* no existing opens on this device */
sdp->sgdebug = 0;
@@ -303,12 +317,15 @@
filp->private_data = sfp;
else {
if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto error_out;
}
-
- if (sdp->device->host->hostt->module)
- __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
return 0;
+
+error_out:
+ if ((! sdp->detached) && sdp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+ return retval;
}
/* Following function was formerly called 'sg_close' */
@@ -324,14 +341,12 @@
}
SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev)));
sg_fasync(-1, filp, 0); /* remove filp from async notification list */
- sg_remove_sfp(sdp, sfp);
- if (! sdp->headfp)
- filp->private_data = NULL;
-
- if (sdp->device->host->hostt->module)
- __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
- sdp->exclude = 0;
- wake_up_interruptible(&sdp->o_excl_wait);
+ if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
+ if ((! sdp->detached) && sdp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+ sdp->exclude = 0;
+ wake_up_interruptible(&sdp->o_excl_wait);
+ }
unlock_kernel();
return 0;
}
@@ -356,11 +371,11 @@
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_WRITE, buf, count)))
return k;
- if (sfp->force_packid && (count >= size_sg_header)) {
- __copy_from_user(&old_hdr, buf, size_sg_header);
+ if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
+ __copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
if (old_hdr.reply_len < 0) {
- if (count >= size_sg_io_hdr) {
- __copy_from_user(&new_hdr, buf, size_sg_io_hdr);
+ if (count >= SZ_SG_IO_HDR) {
+ __copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR);
req_pack_id = new_hdr.pack_id;
}
}
@@ -369,25 +384,26 @@
}
srp = sg_get_rq_mark(sfp, req_pack_id);
if (! srp) { /* now wait on packet to arrive */
+ if (sdp->detached)
+ return -ENODEV;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
while (1) {
- int dio = sg_dio_in_use(sfp);
res = 0; /* following is a macro that beats race condition */
- __wait_event_interruptible(sfp->read_wait,
- (srp = sg_get_rq_mark(sfp, req_pack_id)),
- res);
+ __wait_event_interruptible(sfp->read_wait, (sdp->detached ||
+ (srp = sg_get_rq_mark(sfp, req_pack_id))), res);
+ if (sdp->detached)
+ return -ENODEV;
if (0 == res)
break;
- else if (! dio) /* only let signal out if no dio */
- return res; /* -ERESTARTSYS because signal hit process */
+ return res; /* -ERESTARTSYS because signal hit process */
}
}
if (srp->header.interface_id != '\0')
return sg_new_read(sfp, buf, count, srp);
hp = &srp->header;
- memset(&old_hdr, 0, size_sg_header);
+ memset(&old_hdr, 0, SZ_SG_HEADER);
old_hdr.reply_len = (int)hp->timeout;
old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */
old_hdr.pack_id = hp->pack_id;
@@ -430,13 +446,13 @@
}
/* Now copy the result back to the user buffer. */
- if (count >= size_sg_header) {
- __copy_to_user(buf, &old_hdr, size_sg_header);
- buf += size_sg_header;
+ if (count >= SZ_SG_HEADER) {
+ __copy_to_user(buf, &old_hdr, SZ_SG_HEADER);
+ buf += SZ_SG_HEADER;
if (count > old_hdr.reply_len)
count = old_hdr.reply_len;
- if (count > size_sg_header)
- sg_read_oxfer(srp, buf, count - size_sg_header);
+ if (count > SZ_SG_HEADER)
+ sg_read_oxfer(srp, buf, count - SZ_SG_HEADER);
}
else
count = (old_hdr.result == 0) ? 0 : -EIO;
@@ -447,11 +463,14 @@
static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
Sg_request * srp)
{
- sg_io_hdr_t * hp = &srp->header;
- int k, len;
+ sg_io_hdr_t * hp = &srp->header;
+ int err = 0;
+ int len;
- if (count < size_sg_io_hdr)
- return -EINVAL;
+ if (count < SZ_SG_IO_HDR) {
+ err = -EINVAL;
+ goto err_out;
+ }
hp->sb_len_wr = 0;
if ((hp->mx_sb_len > 0) && hp->sbp) {
if ((CHECK_CONDITION & hp->masked_status) ||
@@ -460,20 +479,19 @@
sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */
len = (len > sb_len) ? sb_len : len;
- if ((k = verify_area(VERIFY_WRITE, hp->sbp, len)))
- return k;
+ if ((err = verify_area(VERIFY_WRITE, hp->sbp, len)))
+ goto err_out;
__copy_to_user(hp->sbp, srp->sense_b, len);
hp->sb_len_wr = len;
}
}
if (hp->masked_status || hp->host_status || hp->driver_status)
hp->info |= SG_INFO_CHECK;
- copy_to_user(buf, hp, size_sg_io_hdr);
-
- k = sg_read_xfer(srp);
- if (k) return k; /* probably -EFAULT, bad addr in dxferp or iovec list */
+ copy_to_user(buf, hp, SZ_SG_IO_HDR);
+ err = sg_read_xfer(srp);
+err_out:
sg_finish_rem_req(srp);
- return count;
+ return (0 == err) ? count : err;
}
@@ -494,7 +512,8 @@
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
-
+ if (sdp->detached)
+ return -ENODEV;
if (! ((filp->f_flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device)))
return -ENXIO;
@@ -503,20 +522,20 @@
if ((k = verify_area(VERIFY_READ, buf, count)))
return k; /* protects following copy_from_user()s + get_user()s */
- if (count < size_sg_header)
+ if (count < SZ_SG_HEADER)
return -EIO;
- __copy_from_user(&old_hdr, buf, size_sg_header);
+ __copy_from_user(&old_hdr, buf, SZ_SG_HEADER);
blocking = !(filp->f_flags & O_NONBLOCK);
if (old_hdr.reply_len < 0)
return sg_new_write(sfp, buf, count, blocking, 0, NULL);
- if (count < (size_sg_header + 6))
+ if (count < (SZ_SG_HEADER + 6))
return -EIO; /* The minimum scsi command length is 6 bytes. */
if (! (srp = sg_add_request(sfp))) {
SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
return -EDOM;
}
- buf += size_sg_header;
+ buf += SZ_SG_HEADER;
__get_user(opcode, buf);
if (sfp->next_cmd_len > 0) {
if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
@@ -539,8 +558,8 @@
input_size = count - cmd_size;
mxsize = (input_size > old_hdr.reply_len) ? input_size :
old_hdr.reply_len;
- mxsize -= size_sg_header;
- input_size -= size_sg_header;
+ mxsize -= SZ_SG_HEADER;
+ input_size -= SZ_SG_HEADER;
if (input_size < 0) {
sg_remove_request(sfp, srp);
return -EIO; /* User did not pass enough bytes for this command. */
@@ -550,16 +569,12 @@
hp->cmd_len = (unsigned char)cmd_size;
hp->iovec_count = 0;
hp->mx_sb_len = 0;
-#if 0
- hp->dxfer_direction = SG_DXFER_UNKNOWN;
-#else
if (input_size > 0)
- hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ?
+ hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ?
SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV :
SG_DXFER_NONE;
-#endif
hp->dxfer_len = mxsize;
hp->dxferp = (unsigned char *)buf + cmd_size;
hp->sbp = NULL;
@@ -581,7 +596,7 @@
unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)];
int timeout;
- if (count < size_sg_io_hdr)
+ if (count < SZ_SG_IO_HDR)
return -EINVAL;
if ((k = verify_area(VERIFY_READ, buf, count)))
return k; /* protects following copy_from_user()s + get_user()s */
@@ -592,7 +607,7 @@
return -EDOM;
}
hp = &srp->header;
- __copy_from_user(hp, buf, size_sg_io_hdr);
+ __copy_from_user(hp, buf, SZ_SG_IO_HDR);
if (hp->interface_id != 'S') {
sg_remove_request(sfp, srp);
return -ENOSYS;
@@ -648,7 +663,10 @@
sg_finish_rem_req(srp);
return k;
}
-/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
+ if (sdp->detached) {
+ sg_finish_rem_req(srp);
+ return -ENODEV;
+ }
SRpnt = scsi_allocate_request(sdp->device);
if(SRpnt == NULL) {
SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n"));
@@ -656,17 +674,15 @@
return -ENOMEM;
}
-/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */
srp->my_cmdp = SRpnt;
SRpnt->sr_request.rq_dev = sdp->i_rdev;
SRpnt->sr_request.rq_status = RQ_ACTIVE;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_cmd_len = hp->cmd_len;
-/* Set the LUN field in the command structure, overriding user input */
- if (! (hp->flags & SG_FLAG_LUN_INHIBIT))
- cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
-
-/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
+ if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
+ if (sdp->device->scsi_level <= SCSI_2)
+ cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+ }
SRpnt->sr_use_sg = srp->data.k_use_sg;
SRpnt->sr_sglist_len = srp->data.sglist_len;
SRpnt->sr_bufflen = srp->data.bufflen;
@@ -719,30 +735,31 @@
{
int blocking = 1; /* ignore O_NONBLOCK flag */
+ if (sdp->detached)
+ return -ENODEV;
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
- result = verify_area(VERIFY_WRITE, (void *)arg, size_sg_io_hdr);
+ result = verify_area(VERIFY_WRITE, (void *)arg, SZ_SG_IO_HDR);
if (result) return result;
- result = sg_new_write(sfp, (const char *)arg, size_sg_io_hdr,
+ result = sg_new_write(sfp, (const char *)arg, SZ_SG_IO_HDR,
blocking, read_only, &srp);
if (result < 0) return result;
srp->sg_io_owned = 1;
while (1) {
- int dio = sg_dio_in_use(sfp);
result = 0; /* following macro to beat race condition */
__wait_event_interruptible(sfp->read_wait,
- (sfp->closed || srp->done), result);
+ (sdp->detached || sfp->closed || srp->done), result);
+ if (sdp->detached)
+ return -ENODEV;
if (sfp->closed)
return 0; /* request packet dropped already */
if (0 == result)
break;
- else if (! dio) { /* only let signal out if no dio */
- srp->orphan = 1;
- return result; /* -ERESTARTSYS because signal hit process */
- }
+ srp->orphan = 1;
+ return result; /* -ERESTARTSYS because signal hit process */
}
srp->done = 2;
- result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp);
+ result = sg_new_read(sfp, (char *)arg, SZ_SG_IO_HDR, srp);
return (result < 0) ? result : 0;
}
case SG_SET_TIMEOUT:
@@ -765,8 +782,11 @@
sg_build_reserve(sfp, val);
}
}
- else
+ else {
+ if (sdp->detached)
+ return -ENODEV;
sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+ }
return 0;
case SG_GET_LOW_DMA:
return put_user((int)sfp->low_dma, (int *)arg);
@@ -775,6 +795,9 @@
if (result) return result;
else {
sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg;
+
+ if (sdp->detached)
+ return -ENODEV;
__put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
__put_user((int)sdp->device->channel, &sg_idp->channel);
__put_user((int)sdp->device->id, &sg_idp->scsi_id);
@@ -853,7 +876,7 @@
return put_user(sg_version_num, (int *)arg);
case SG_GET_REQUEST_TABLE:
result = verify_area(VERIFY_WRITE, (void *) arg,
- size_sg_req_info * SG_MAX_QUEUE);
+ SZ_SG_REQ_INFO * SG_MAX_QUEUE);
if (result) return result;
else {
sg_req_info_t rinfo[SG_MAX_QUEUE];
@@ -861,7 +884,7 @@
read_lock_irqsave(&sfp->rq_list_lock, iflags);
for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
++val, srp = srp ? srp->nextrp : srp) {
- memset(&rinfo[val], 0, size_sg_req_info);
+ memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
if (srp) {
rinfo[val].req_state = srp->done + 1;
rinfo[val].problem = srp->header.masked_status &
@@ -876,12 +899,16 @@
}
}
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE);
+ __copy_to_user((void *)arg, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE);
return 0;
}
case SG_EMULATED_HOST:
+ if (sdp->detached)
+ return -ENODEV;
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
case SG_SCSI_RESET:
+ if (sdp->detached)
+ return -ENODEV;
if (filp->f_flags & O_NONBLOCK) {
if (sdp->device->host->in_recovery)
return -EBUSY;
@@ -907,13 +934,16 @@
default:
return -EINVAL;
}
- if(! capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
#else
SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
result = -EINVAL;
#endif
case SCSI_IOCTL_SEND_COMMAND:
+ if (sdp->detached)
+ return -ENODEV;
if (read_only) {
unsigned char opcode = WRITE_6;
Scsi_Ioctl_Command * siocp = (void *)arg;
@@ -932,6 +962,8 @@
case SCSI_IOCTL_GET_BUS_NUMBER:
case SCSI_IOCTL_PROBE_HOST:
case SG_GET_TRANSFORM:
+ if (sdp->detached)
+ return -ENODEV;
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
default:
if (read_only)
@@ -949,7 +981,8 @@
int count = 0;
unsigned long iflags;
- if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
+ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))
+ || sfp->closed)
return POLLERR;
poll_wait(filp, &sfp->read_wait, wait);
read_lock_irqsave(&sfp->rq_list_lock, iflags);
@@ -960,7 +993,10 @@
++count;
}
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- if (! sfp->cmd_q) {
+
+ if (sdp->detached)
+ res |= POLLHUP;
+ else if (! sfp->cmd_q) {
if (0 == count)
res |= POLLOUT | POLLWRNORM;
}
@@ -1001,9 +1037,9 @@
if (dev < sg_template.dev_max)
sdp = sg_dev_arr[dev];
}
- if (NULL == sdp) {
+ if ((NULL == sdp) || sdp->detached) {
read_unlock(&sg_dev_arr_lock);
- SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev));
+ SCSI_LOG_TIMEOUT(1, printk("sg...bh: dev=%d gone\n", dev));
scsi_release_request(SRpnt);
SRpnt = NULL;
return;
@@ -1020,8 +1056,8 @@
break;
sfp = sfp->nextfp;
}
- read_unlock(&sg_dev_arr_lock);
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);
SRpnt = NULL;
@@ -1035,6 +1071,7 @@
sg_clr_srpnt(SRpnt);
srp->my_cmdp = NULL;
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",
dev, srp->header.pack_id, (int)SRpnt->sr_result));
@@ -1071,7 +1108,6 @@
if (sfp->closed) { /* whoops this fd already released, cleanup */
SCSI_LOG_TIMEOUT(1,
printk("sg...bh: already closed, freeing ...\n"));
- /* should check if module is unloaded <<<<<<< */
sg_finish_rem_req(srp);
srp = NULL;
if (NULL == sfp->headrp) {
@@ -1080,6 +1116,10 @@
sg_remove_sfp(sdp, sfp);
sfp = NULL;
}
+ if (sg_template.module)
+ __MOD_DEC_USE_COUNT(sg_template.module);
+ if (sdp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
}
else if (srp && srp->orphan) {
if (sfp->keep_orphan)
@@ -1110,19 +1150,6 @@
static int sg_detect(Scsi_Device * scsidp)
{
- switch (scsidp->type) {
- case TYPE_DISK:
- case TYPE_MOD:
- case TYPE_ROM:
- case TYPE_WORM:
- case TYPE_TAPE: break;
- default:
- printk("Detected scsi generic sg%d at scsi%d,"
- " channel %d, id %d, lun %d, type %d\n",
- sg_template.dev_noticed,
- scsidp->host->host_no, scsidp->channel,
- scsidp->id, scsidp->lun, scsidp->type);
- }
sg_template.dev_noticed++;
return 1;
}
@@ -1241,51 +1268,73 @@
sg_template.nr_dev++;
sg_dev_arr[k] = sdp;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ switch (scsidp->type) {
+ case TYPE_DISK:
+ case TYPE_MOD:
+ case TYPE_ROM:
+ case TYPE_WORM:
+ case TYPE_TAPE: break;
+ default:
+ printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
+ " lun %d, type %d\n", k, scsidp->host->host_no,
+ scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
+ }
return 0;
}
/* Called at 'finish' of init process, after all attaches */
static void sg_finish(void)
-{
- SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n",
- scsi_dma_free_sectors));
-}
+{ }
static void sg_detach(Scsi_Device * scsidp)
{
Sg_device * sdp;
unsigned long iflags;
Sg_fd * sfp;
+ Sg_fd * tsfp;
Sg_request * srp;
- int k;
+ Sg_request * tsrp;
+ int k, delay;
if (NULL == sg_dev_arr)
return;
+ delay = 0;
write_lock_irqsave(&sg_dev_arr_lock, iflags);
for (k = 0; k < sg_template.dev_max; k++) {
sdp = sg_dev_arr[k];
if ((NULL == sdp) || (sdp->device != scsidp))
continue; /* dirty but lowers nesting */
if (sdp->headfp) {
- for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) {
- /* no lock on request list here */
- for (srp = sfp->headrp; srp; srp = srp->nextrp) {
- if (! srp->done) {
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- sg_shorten_timeout(srp->my_cmdp);
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- }
- }
+ sdp->detached = 1;
+ for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+ tsfp = sfp->nextfp;
+ for (srp = sfp->headrp; srp; srp = tsrp) {
+ tsrp = srp->nextrp;
+ if (sfp->closed || (0 == srp->done))
+ sg_finish_rem_req(srp);
+ }
+ if (sfp->closed) {
+ if (sg_template.module)
+ __MOD_DEC_USE_COUNT(sg_template.module);
+ if (sdp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+ __sg_remove_sfp(sdp, sfp);
+ }
+ else {
+ delay = 1;
+ wake_up_interruptible(&sfp->read_wait);
+ kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
+ }
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k));
- scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */
+ SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
devfs_unregister (sdp->de);
sdp->de = NULL;
- sdp->detached = 1;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ if (NULL == sdp->headfp) {
+ kfree((char *)sdp);
+ sg_dev_arr[k] = NULL;
+ }
}
- else {
+ else { /* nothing active, simple case */
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
devfs_unregister (sdp->de);
kfree((char *)sdp);
@@ -1293,13 +1342,12 @@
}
scsidp->attached--;
sg_template.nr_dev--;
-/* avoid associated device /dev/sg? being incremented
- * each time module is inserted/removed , <dan@lectra.fr> */
- sg_template.dev_noticed--;
+ sg_template.dev_noticed--; /* from <dan@lectra.fr> */
break;
}
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- return;
+ if (delay)
+ scsi_sleep(2); /* dirty detach so delay device destruction */
}
MODULE_AUTHOR("Douglas Gilbert");
@@ -1322,8 +1370,6 @@
scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
if(sg_dev_arr != NULL) {
-/* Really worrying situation of writes still pending and get here */
-/* Strategy: shorten timeout on release + wait on detach ... */
kfree((char *)sg_dev_arr);
sg_dev_arr = NULL;
}
@@ -1331,29 +1377,6 @@
}
-#if 0
-extern void scsi_times_out (Scsi_Cmnd * SCpnt);
-extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
-#endif
-
-/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */
-static void sg_shorten_timeout(Scsi_Request * srpnt)
-{
-#if 0 /* scsi_syms.c is very miserly about exported functions */
- scsi_delete_timer(scpnt);
- if (! scpnt)
- return;
- scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */
- if (scpnt->host->hostt->use_new_eh_code)
- scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out);
- else
- scsi_add_timer(scpnt, scpnt->timeout_per_command,
- scsi_old_times_out);
-#else
- scsi_sleep(HZ); /* just sleep 1 second and hope ... */
-#endif
-}
-
static int sg_start_req(Sg_request * srp)
{
int res;
@@ -1367,9 +1390,8 @@
SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
return 0;
- if ((hp->flags & SG_FLAG_DIRECT_IO) &&
- (dxfer_dir != SG_DXFER_UNKNOWN) &&
- (0 == hp->iovec_count) &&
+ if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
+ (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
(! sfp->parentdp->device->host->unchecked_isa_dma)) {
res = sg_build_dir(srp, sfp, dxfer_len);
if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */
@@ -1427,7 +1449,7 @@
static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
{
-#ifdef SG_ALLOW_DIO
+#ifdef SG_ALLOW_DIO_CODE
if (schp && schp->kiobp) {
if (schp->mapped) {
unmap_kiobuf(schp->kiobp);
@@ -1443,7 +1465,7 @@
static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
{
-#ifdef SG_ALLOW_DIO
+#ifdef SG_ALLOW_DIO_CODE
int res, k, split, offset, num, mx_sc_elems, rem_sz;
struct kiobuf * kp;
char * mem_src_arr;
@@ -1519,7 +1541,7 @@
return 0;
#else
return 1;
-#endif /* SG_ALLOW_DIO */
+#endif /* SG_ALLOW_DIO_CODE */
}
static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
@@ -1629,7 +1651,7 @@
if (iovec_count) {
onum = iovec_count;
if ((k = verify_area(VERIFY_READ, hp->dxferp,
- size_sg_iovec * onum)))
+ SZ_SG_IOVEC * onum)))
return k;
}
else
@@ -1707,8 +1729,8 @@
}
else {
__copy_from_user(&u_iovec,
- (unsigned char *)hp->dxferp + (ind * size_sg_iovec),
- size_sg_iovec);
+ (unsigned char *)hp->dxferp + (ind * SZ_SG_IOVEC),
+ SZ_SG_IOVEC);
p = (unsigned char *)u_iovec.iov_base;
count = (int)u_iovec.iov_len;
}
@@ -1778,7 +1800,7 @@
if (iovec_count) {
onum = iovec_count;
if ((k = verify_area(VERIFY_READ, hp->dxferp,
- size_sg_iovec * onum)))
+ SZ_SG_IOVEC * onum)))
return k;
}
else
@@ -2124,6 +2146,34 @@
return sfp;
}
+static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+{
+ Sg_fd * fp;
+ Sg_fd * prev_fp;
+
+ prev_fp = sdp->headfp;
+ if (sfp == prev_fp)
+ sdp->headfp = prev_fp->nextfp;
+ else {
+ while ((fp = prev_fp->nextfp)) {
+ if (sfp == fp) {
+ prev_fp->nextfp = fp->nextfp;
+ break;
+ }
+ prev_fp = fp;
+ }
+ }
+ if (sfp->reserve.bufflen > 0) {
+ SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n",
+ (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+ sg_remove_scat(&sfp->reserve);
+ }
+ sfp->parentdp = NULL;
+ SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: sfp=0x%p\n", sfp));
+ sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+}
+
+/* Returns 0 in normal case, 1 when detached and sdp object removed */
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
{
Sg_request * srp;
@@ -2131,44 +2181,18 @@
int dirty = 0;
int res = 0;
- srp = sfp->headrp;
- if (srp) {
- while (srp) {
- tsrp = srp->nextrp;
- if (srp->done)
- sg_finish_rem_req(srp);
- else
- ++dirty;
- srp = tsrp;
- }
+ for (srp = sfp->headrp; srp; srp = tsrp) {
+ tsrp = srp->nextrp;
+ if (srp->done)
+ sg_finish_rem_req(srp);
+ else
+ ++dirty;
}
if (0 == dirty) {
- Sg_fd * fp;
- Sg_fd * prev_fp;
unsigned long iflags;
write_lock_irqsave(&sg_dev_arr_lock, iflags);
- prev_fp = sdp->headfp;
- if (sfp == prev_fp)
- sdp->headfp = prev_fp->nextfp;
- else {
- while ((fp = prev_fp->nextfp)) {
- if (sfp == fp) {
- prev_fp->nextfp = fp->nextfp;
- break;
- }
- prev_fp = fp;
- }
- }
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- if (sfp->reserve.bufflen > 0) {
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n",
- (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
- sg_remove_scat(&sfp->reserve);
- }
- sfp->parentdp = NULL;
- SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp));
- sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src);
+ __sg_remove_sfp(sdp, sfp);
if (sdp->detached && (NULL == sdp->headfp)) {
int k, maxd;
@@ -2180,11 +2204,17 @@
if (k < maxd)
sg_dev_arr[k] = NULL;
kfree((char *)sdp);
+ res = 1;
}
- res = 1;
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
}
else {
sfp->closed = 1; /* flag dirty state on this fd */
+ /* MOD_INC's to inhibit unloading sg and associated adapter driver */
+ if (sg_template.module)
+ __MOD_INC_USE_COUNT(sg_template.module);
+ if (sdp->device->host->hostt->module)
+ __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
SCSI_LOG_TIMEOUT(1, printk(
"sg_remove_sfp: worrisome, %d writes pending\n", dirty));
}
@@ -2203,31 +2233,15 @@
return srp ? 1 : 0;
}
-static int sg_dio_in_use(Sg_fd * sfp)
-{
- const Sg_request * srp;
- unsigned long iflags;
-
- read_lock_irqsave(&sfp->rq_list_lock, iflags);
- for (srp = sfp->headrp; srp; srp = srp->nextrp)
- if ((! srp->done) && srp->data.kiobp) break;
- read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- return srp ? 1 : 0;
-}
-
/* If retSzp==NULL want exact size or fail */
-/* sg_low_malloc() should always be called from a process context allowing
- GFP_KERNEL to be used instead of GFP_ATOMIC */
static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
{
char * resp = NULL;
- int page_mask = lowDma ? (GFP_KERNEL | GFP_DMA) : GFP_KERNEL;
+ int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
if (rqSz <= 0)
return resp;
if (SG_HEAP_KMAL == mem_src) {
- page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC;
- /* Seen kmalloc(..,GFP_KERNEL) hang for 40 secs! */
resp = kmalloc(rqSz, page_mask);
if (resp && retSzp) *retSzp = rqSz;
return resp;
@@ -2355,7 +2369,7 @@
case SG_USER_MEM:
break; /* nothing to do */
default:
- printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n",
+ printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
mem_src, buff, size);
break;
}
@@ -2451,11 +2465,17 @@
static struct proc_dir_entry * sg_proc_sgp = NULL;
-static const char * sg_proc_sg_dirname = "sg";
-static const char * sg_proc_leaf_names[] = {"def_reserved_size", "debug",
- "devices", "device_hdr", "device_strs",
- "hosts", "host_hdr", "host_strs", "version"};
+static char sg_proc_sg_dirname[] = "sg";
+static const char * sg_proc_leaf_names[] = {"allow_dio", "def_reserved_size",
+ "debug", "devices", "device_hdr", "device_strs",
+ "hosts", "host_hdr", "host_strs", "version"};
+static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
+ int size, int * eof, void * data);
+static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
+ off_t offset, int size);
+static int sg_proc_adio_write(struct file * filp, const char * buffer,
+ unsigned long count, void * data);
static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
int size, int * eof, void * data);
static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin,
@@ -2495,12 +2515,12 @@
static int sg_proc_version_info(char * buffer, int * len, off_t * begin,
off_t offset, int size);
static read_proc_t * sg_proc_leaf_reads[] = {
- sg_proc_dressz_read, sg_proc_debug_read,
+ sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read,
sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read,
sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read,
sg_proc_version_read};
static write_proc_t * sg_proc_leaf_writes[] = {
- sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0};
+ sg_proc_adio_write, sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0};
#define PRINT_PROC(fmt,args...) \
do { \
@@ -2562,6 +2582,32 @@
remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
}
+static int sg_proc_adio_read(char * buffer, char ** start, off_t offset,
+ int size, int * eof, void * data)
+{ SG_PROC_READ_FN(sg_proc_adio_info); }
+
+static int sg_proc_adio_info(char * buffer, int * len, off_t * begin,
+ off_t offset, int size)
+{
+ PRINT_PROC("%d\n", sg_allow_dio);
+ return 1;
+}
+
+static int sg_proc_adio_write(struct file * filp, const char * buffer,
+ unsigned long count, void * data)
+{
+ int num;
+ char buff[11];
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ num = (count < 10) ? count : 10;
+ copy_from_user(buff, buffer, num);
+ buff[num] = '\0';
+ sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0;
+ return count;
+}
+
static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
int size, int * eof, void * data)
{ SG_PROC_READ_FN(sg_proc_dressz_info); }
@@ -2580,7 +2626,7 @@
unsigned long k = ULONG_MAX;
char buff[11];
- if (! capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
num = (count < 10) ? count : 10;
copy_from_user(buff, buffer, num);
@@ -2620,8 +2666,9 @@
Sg_request * srp;
struct scsi_device * scsidp;
int dev, k, m, blen, usg;
-
- if (! (scsidp = sdp->device)) {
+
+ scsidp = sdp->device;
+ if (NULL == scsidp) {
PRINT_PROC("device %d detached ??\n", j);
continue;
}
@@ -2629,10 +2676,14 @@
if (sg_get_nth_sfp(sdp, 0)) {
PRINT_PROC(" >>> device=sg%d ", dev);
- PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d"
- " excl=%d\n", scsidp->host->host_no, scsidp->channel,
- scsidp->id, scsidp->lun, scsidp->host->hostt->emulated,
- sdp->sg_tablesize, sdp->exclude);
+ if (sdp->detached)
+ PRINT_PROC("detached pending close ");
+ else
+ PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d",
+ scsidp->host->host_no, scsidp->channel,
+ scsidp->id, scsidp->lun, scsidp->host->hostt->emulated);
+ PRINT_PROC(" sg_tablesize=%d excl=%d\n", sdp->sg_tablesize,
+ sdp->exclude);
}
for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
PRINT_PROC(" FD(%d): timeout=%dms bufflen=%d "
@@ -2683,13 +2734,14 @@
max_dev = sg_last_dev();
for (j = 0; j < max_dev; ++j) {
sdp = sg_get_dev(j);
- if (sdp && (scsidp = sdp->device))
- PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ if (sdp && (scsidp = sdp->device) && (! sdp->detached))
+ PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
scsidp->host->host_no, scsidp->channel, scsidp->id,
scsidp->lun, (int)scsidp->type, (int)scsidp->access_count,
- (int)scsidp->queue_depth, (int)scsidp->device_busy);
+ (int)scsidp->queue_depth, (int)scsidp->device_busy,
+ (int)scsidp->online);
else
- PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
+ PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
}
return 1;
}
@@ -2701,7 +2753,7 @@
static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin,
off_t offset, int size)
{
- PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\n");
+ PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\tonline\n");
return 1;
}
@@ -2719,7 +2771,7 @@
max_dev = sg_last_dev();
for (j = 0; j < max_dev; ++j) {
sdp = sg_get_dev(j);
- if (sdp && (scsidp = sdp->device))
+ if (sdp && (scsidp = sdp->device) && (! sdp->detached))
PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
scsidp->vendor, scsidp->model, scsidp->rev);
else
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)