patch-2.3.17 linux/drivers/scsi/scsi_ioctl.c

Next file: linux/drivers/scsi/scsi_module.c
Previous file: linux/drivers/scsi/scsi_error.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
@@ -18,12 +18,12 @@
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>
 
-#define NORMAL_RETRIES 5   
-#define NORMAL_TIMEOUT (10 * HZ)
-#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
-#define START_STOP_TIMEOUT (60 * HZ)
-#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
-#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
+#define NORMAL_RETRIES			5
+#define NORMAL_TIMEOUT			(10 * HZ)
+#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT		(60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
 
 #define MAX_BUF PAGE_SIZE
 
@@ -36,36 +36,38 @@
  * (int *) arg
  */
 
-static int ioctl_probe(struct Scsi_Host * host, void *buffer)
+static int ioctl_probe(struct Scsi_Host *host, void *buffer)
 {
-    int temp, result;
-    unsigned int len,slen;
-    const char * string;
-    
-    if ((temp = host->hostt->present) && buffer) {
-        result = verify_area(VERIFY_READ, buffer, sizeof(long));
-        if (result) return result;
-
-	get_user(len, (unsigned int *) buffer);
-	if(host->hostt->info)
-	    string = host->hostt->info(host);
-	else 
-	    string = host->hostt->name;
-	if(string) {
-	    slen = strlen(string);
-	    if (len > slen)
-		len = slen + 1;
-            result = verify_area(VERIFY_WRITE, buffer, len);
-            if (result) return result;
+	int temp, result;
+	unsigned int len, slen;
+	const char *string;
+
+	if ((temp = host->hostt->present) && buffer) {
+		result = verify_area(VERIFY_READ, buffer, sizeof(long));
+		if (result)
+			return result;
+
+		get_user(len, (unsigned int *) buffer);
+		if (host->hostt->info)
+			string = host->hostt->info(host);
+		else
+			string = host->hostt->name;
+		if (string) {
+			slen = strlen(string);
+			if (len > slen)
+				len = slen + 1;
+			result = verify_area(VERIFY_WRITE, buffer, len);
+			if (result)
+				return result;
 
-	    copy_to_user (buffer, string, len);
+			copy_to_user(buffer, string, len);
+		}
 	}
-    }
-    return temp;
+	return temp;
 }
 
 /*
- * 
+
  * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
  * The NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
  * 
@@ -88,87 +90,89 @@
  * The output area is then filled in starting from the command byte. 
  */
 
-static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
+static void scsi_ioctl_done(Scsi_Cmnd * SCpnt)
 {
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-    
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
-}   
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
+}
 
-static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
+static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
 				  int timeout, int retries)
 {
-    unsigned long flags;
-    int result;
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDpnt;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-
-    SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
-    SCpnt = scsi_allocate_device(NULL, dev, 1);
-    {
-	DECLARE_MUTEX_LOCKED(sem);
-	SCpnt->request.sem = &sem;
-	scsi_do_cmd(SCpnt,  cmd, NULL,  0, scsi_ioctl_done,  timeout, retries);
+	unsigned long flags;
+	int result;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
+	SCpnt = scsi_allocate_device(NULL, dev, 1);
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		down(&sem);
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->request.sem = NULL;
+	}
+
+	SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
+
+	if (driver_byte(SCpnt->result) != 0)
+		switch (SCpnt->sense_buffer[2] & 0xf) {
+		case ILLEGAL_REQUEST:
+			if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
+				dev->lockable = 0;
+			else
+				printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
+			break;
+		case NOT_READY:	/* This happens if there is no disc in drive */
+			if (dev->removable && (cmd[0] != TEST_UNIT_READY)) {
+				printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
+				break;
+			}
+		case UNIT_ATTENTION:
+			if (dev->removable) {
+				dev->changed = 1;
+				SCpnt->result = 0;	/* This is no longer considered an error */
+				/* gag this error, VFS will log it anyway /axboe */
+				/* printk(KERN_INFO "Disc change detected.\n"); */
+				break;
+			};
+		default:	/* Fall through for non-removable media */
+			printk("SCSI error: host %d id %d lun %d return code = %x\n",
+			       dev->host->host_no,
+			       dev->id,
+			       dev->lun,
+			       SCpnt->result);
+			printk("\tSense class %x, sense error %x, extended sense %x\n",
+			       sense_class(SCpnt->sense_buffer[0]),
+			       sense_error(SCpnt->sense_buffer[0]),
+			       SCpnt->sense_buffer[2] & 0xf);
+
+		};
+
+	result = SCpnt->result;
+
+	SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+		(*SDpnt->scsi_request_fn) ();
+
+	wake_up(&SDpnt->device_wait);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	down(&sem);
-        spin_lock_irqsave(&io_request_lock, flags);
-        SCpnt->request.sem = NULL;
-    }
-    
-    SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
-
-    if(driver_byte(SCpnt->result) != 0)
-	switch(SCpnt->sense_buffer[2] & 0xf) {
-	case ILLEGAL_REQUEST:
-	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
-	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
-	    break;
-	case NOT_READY: /* This happens if there is no disc in drive */
-	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
-		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
-		break;
-	    }
-	case UNIT_ATTENTION:
-	    if (dev->removable){
-		dev->changed = 1;
-		SCpnt->result = 0; /* This is no longer considered an error */
-		/* gag this error, VFS will log it anyway /axboe */
-		/* printk(KERN_INFO "Disc change detected.\n"); */
-		break;
-	    };
-	default: /* Fall through for non-removable media */
-	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
-		   dev->host->host_no,
-		   dev->id,
-		   dev->lun,
-		   SCpnt->result);
-	    printk("\tSense class %x, sense error %x, extended sense %x\n",
-		   sense_class(SCpnt->sense_buffer[0]),
-		   sense_error(SCpnt->sense_buffer[0]),
-		   SCpnt->sense_buffer[2] & 0xf);
-	    
-	};
-    
-    result = SCpnt->result;
-
-    SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
-    SDpnt = SCpnt->device;
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
-
-    wake_up(&SDpnt->device_wait);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return result;
+	return result;
 }
 
 /*
@@ -176,175 +180,183 @@
  * interface instead, as this is a more flexible approach to performing
  * generic SCSI commands on a device.
  */
-int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
+int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 {
-    unsigned long flags;
-    char * buf;
-    unsigned char cmd[12]; 
-    char * cmd_in;
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDpnt;
-    unsigned char opcode;
-    int inlen, outlen, cmdlen;
-    int needed, buf_needed;
-    int timeout, retries, result;
-    
-    if (!sic)
-	return -EINVAL;
-    
-
-    /*
-     * Verify that we can read at least this much.
-     */
-    result = verify_area(VERIFY_READ, sic, sizeof (Scsi_Ioctl_Command));
-    if (result) return result;
-
-    /*
-     * The structure that we are passed should look like:
-     *
-     * struct sdata {
-     *	unsigned int inlen;
-     *	unsigned int outlen;
-     *	unsigned char  cmd[];  # However many bytes are used for cmd.
-     *	unsigned char  data[];
-     * };
-     */
-    get_user(inlen, &sic->inlen);
-    get_user(outlen, &sic->outlen);
-    
-    /*
-     * We do not transfer more than MAX_BUF with this interface.
-     * If the user needs to transfer more data than this, they
-     * should use scsi_generics instead.
-     */
-    if( inlen > MAX_BUF ) return -EINVAL;
-    if( outlen > MAX_BUF ) return -EINVAL;
-
-    cmd_in = sic->data;
-    get_user(opcode, cmd_in); 
-    
-    needed = buf_needed = (inlen > outlen ? inlen : outlen);
-    if(buf_needed){
-	buf_needed = (buf_needed + 511) & ~511;
-	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
-        spin_lock_irqsave(&io_request_lock, flags);
-	buf = (char *) scsi_malloc(buf_needed);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if (!buf) return -ENOMEM;
-	memset(buf, 0, buf_needed);
-    } else
-	buf = NULL;
-    
-    /*
-     * Obtain the command from the user's address space.
-     */
-    cmdlen = COMMAND_SIZE(opcode);
-
-    result = verify_area(VERIFY_READ, cmd_in, 
-                         cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
-    if (result) return result;
-
-    copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
-    
-    /*
-     * Obtain the data to be sent to the device (if any).
-     */
-    copy_from_user ((void *) buf,  
-                   (void *) (cmd_in + cmdlen), 
-                   inlen);
-    
-    /*
-     * Set the lun field to the correct value.
-     */
-    cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
-    
-    switch (opcode)
-      {
-      case FORMAT_UNIT:
- 	timeout = FORMAT_UNIT_TIMEOUT;
-	retries = 1;
-	break;
-      case START_STOP:
- 	timeout = START_STOP_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      case MOVE_MEDIUM:
- 	timeout = MOVE_MEDIUM_TIMEOUT;
- 	retries = NORMAL_RETRIES;
- 	break;
-      case READ_ELEMENT_STATUS:
- 	timeout = READ_ELEMENT_STATUS_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      default:
- 	timeout = NORMAL_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      }
+	unsigned long flags;
+	char *buf;
+	unsigned char cmd[12];
+	char *cmd_in;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+	unsigned char opcode;
+	int inlen, outlen, cmdlen;
+	int needed, buf_needed;
+	int timeout, retries, result;
+
+	if (!sic)
+		return -EINVAL;
+
+
+	/*
+	 * Verify that we can read at least this much.
+	 */
+	result = verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command));
+	if (result)
+		return result;
+
+	/*
+	 * The structure that we are passed should look like:
+	 *
+	 * struct sdata {
+	 *  unsigned int inlen;
+	 *  unsigned int outlen;
+	 *  unsigned char  cmd[];  # However many bytes are used for cmd.
+	 *  unsigned char  data[];
+	 * };
+	 */
+	get_user(inlen, &sic->inlen);
+	get_user(outlen, &sic->outlen);
+
+	/*
+	 * We do not transfer more than MAX_BUF with this interface.
+	 * If the user needs to transfer more data than this, they
+	 * should use scsi_generics instead.
+	 */
+	if (inlen > MAX_BUF)
+		return -EINVAL;
+	if (outlen > MAX_BUF)
+		return -EINVAL;
+
+	cmd_in = sic->data;
+	get_user(opcode, cmd_in);
+
+	needed = buf_needed = (inlen > outlen ? inlen : outlen);
+	if (buf_needed) {
+		buf_needed = (buf_needed + 511) & ~511;
+		if (buf_needed > MAX_BUF)
+			buf_needed = MAX_BUF;
+		spin_lock_irqsave(&io_request_lock, flags);
+		buf = (char *) scsi_malloc(buf_needed);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		if (!buf)
+			return -ENOMEM;
+		memset(buf, 0, buf_needed);
+	} else
+		buf = NULL;
+
+	/*
+	 * Obtain the command from the user's address space.
+	 */
+	cmdlen = COMMAND_SIZE(opcode);
+
+	result = verify_area(VERIFY_READ, cmd_in,
+		    cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
+	if (result)
+		return result;
+
+	copy_from_user((void *) cmd, cmd_in, cmdlen);
+
+	/*
+	 * Obtain the data to be sent to the device (if any).
+	 */
+	copy_from_user((void *) buf,
+		       (void *) (cmd_in + cmdlen),
+		       inlen);
+
+	/*
+	 * Set the lun field to the correct value.
+	 */
+	cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+
+	switch (opcode) {
+	case FORMAT_UNIT:
+		timeout = FORMAT_UNIT_TIMEOUT;
+		retries = 1;
+		break;
+	case START_STOP:
+		timeout = START_STOP_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case MOVE_MEDIUM:
+		timeout = MOVE_MEDIUM_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case READ_ELEMENT_STATUS:
+		timeout = READ_ELEMENT_STATUS_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	default:
+		timeout = NORMAL_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	}
 
 #ifndef DEBUG_NO_CMD
 
-    spin_lock_irqsave(&io_request_lock, flags);
-    
-    SCpnt = scsi_allocate_device(NULL, dev, 1);
-
-    {
-	DECLARE_MUTEX_LOCKED(sem);
-	SCpnt->request.sem = &sem;
-	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
-		    timeout, retries);
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	SCpnt = scsi_allocate_device(NULL, dev, 1);
+
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
+			    timeout, retries);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		down(&sem);
+		SCpnt->request.sem = NULL;
+	}
+
+	/* 
+	 * If there was an error condition, pass the info back to the user. 
+	 */
+	if (SCpnt->result) {
+		result = verify_area(VERIFY_WRITE,
+				     cmd_in,
+				     sizeof(SCpnt->sense_buffer));
+		if (result)
+			return result;
+		copy_to_user((void *) cmd_in,
+			     SCpnt->sense_buffer,
+			     sizeof(SCpnt->sense_buffer));
+	} else {
+		result = verify_area(VERIFY_WRITE, cmd_in, outlen);
+		if (result)
+			return result;
+		copy_to_user((void *) cmd_in, buf, outlen);
+	}
+	result = SCpnt->result;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	wake_up(&SCpnt->device->device_wait);
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if (buf)
+		scsi_free(buf, buf_needed);
+
+	if (SDpnt->scsi_request_fn)
+		(*SDpnt->scsi_request_fn) ();
+
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	down(&sem);
-        SCpnt->request.sem = NULL;
-    }
-    
-    /* 
-     * If there was an error condition, pass the info back to the user. 
-     */
-    if(SCpnt->result) {
-        result = verify_area(VERIFY_WRITE, 
-                             cmd_in, 
-                             sizeof(SCpnt->sense_buffer));
-        if (result) return result;
-        copy_to_user((void *) cmd_in,  
-                    SCpnt->sense_buffer, 
-                    sizeof(SCpnt->sense_buffer));
-    } else {
-        result = verify_area(VERIFY_WRITE, cmd_in, outlen);
-        if (result) return result;
-        copy_to_user ((void *) cmd_in,  buf,  outlen);
-    }
-    result = SCpnt->result;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-
-    wake_up(&SCpnt->device->device_wait);
-    SDpnt = SCpnt->device;
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (buf) scsi_free(buf, buf_needed);
-    
-    if(SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
-    
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return result;
+	return result;
 #else
-    {
-	int i;
-	printk("scsi_ioctl : device %d.  command = ", dev->id);
-	for (i = 0; i < 12; ++i)
-	    printk("%02x ", cmd[i]);
-	printk("\nbuffer =");
-	for (i = 0; i < 20; ++i)
-	    printk("%02x ", buf[i]);
-	printk("\n");
-	printk("inlen = %d, outlen = %d, cmdlen = %d\n",
-	       inlen, outlen, cmdlen);
-	printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
-    }
-    return 0;
+	{
+		int i;
+		printk("scsi_ioctl : device %d.  command = ", dev->id);
+		for (i = 0; i < 12; ++i)
+			printk("%02x ", cmd[i]);
+		printk("\nbuffer =");
+		for (i = 0; i < 20; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+		printk("inlen = %d, outlen = %d, cmdlen = %d\n",
+		       inlen, outlen, cmdlen);
+		printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
+	}
+	return 0;
 #endif
 }
 
@@ -353,107 +365,115 @@
  * not take a major/minor number as the dev field.  Rather, it takes
  * a pointer to a scsi_devices[] element, a structure. 
  */
-int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
-    int result;
-    char scsi_cmd[12];
-    
-    /* No idea how this happens.... */
-    if (!dev) return -ENXIO;
-    
-    /*
-     * 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( !scsi_block_when_processing_errors(dev) )
-      {
-        return -ENODEV;
-      }
-    
-    switch (cmd) {
-    case SCSI_IOCTL_GET_IDLUN:
-        result = verify_area(VERIFY_WRITE, arg, sizeof (Scsi_Idlun));
-        if (result) return result;
-
-	put_user(dev->id 
-                 + (dev->lun << 8) 
-                 + (dev->channel << 16)
-                 + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
-		    &((Scsi_Idlun *) arg)->dev_id);
-        put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
-	return 0;
-    case SCSI_IOCTL_GET_BUS_NUMBER:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user( dev->host->host_no, (int *) arg);
-	return 0;
-    case SCSI_IOCTL_TAGGED_ENABLE:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	if(!dev->tagged_supported) return -EINVAL;
-	dev->tagged_queue = 1;
-	dev->current_tag = 1;
-	return 0;
-    case SCSI_IOCTL_TAGGED_DISABLE:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	if(!dev->tagged_supported) return -EINVAL;
-	dev->tagged_queue = 0;
-	dev->current_tag = 0;
-	return 0;
-    case SCSI_IOCTL_PROBE_HOST:
-	return ioctl_probe(dev->host, arg);
-    case SCSI_IOCTL_SEND_COMMAND:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	return scsi_ioctl_send_command((Scsi_Device *) dev,
-				       (Scsi_Ioctl_Command *) arg);
-    case SCSI_IOCTL_DOORLOCK:
-	if (!dev->removable || !dev->lockable) return 0;
-	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_DOORUNLOCK:
-	if (!dev->removable || !dev->lockable) return 0;
-	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-    case SCSI_IOCTL_TEST_UNIT_READY:
-	scsi_cmd[0] = TEST_UNIT_READY;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 0;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_START_UNIT:
-	scsi_cmd[0] = START_STOP;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 1;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      START_STOP_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_STOP_UNIT:
-	scsi_cmd[0] = START_STOP;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 0;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      START_STOP_TIMEOUT, NORMAL_RETRIES);
-	break;
-    default :           
-	if (dev->host->hostt->ioctl)
-		return dev->host->hostt->ioctl(dev, cmd, arg);
+	int result;
+	char scsi_cmd[12];
+
+	/* No idea how this happens.... */
+	if (!dev)
+		return -ENXIO;
+
+	/*
+	 * 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 (!scsi_block_when_processing_errors(dev)) {
+		return -ENODEV;
+	}
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+		result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun));
+		if (result)
+			return result;
+
+		put_user(dev->id
+			 + (dev->lun << 8)
+			 + (dev->channel << 16)
+		  + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
+			 &((Scsi_Idlun *) arg)->dev_id);
+		put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
+		return 0;
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+		if (result)
+			return result;
+		put_user(dev->host->host_no, (int *) arg);
+		return 0;
+	case SCSI_IOCTL_TAGGED_ENABLE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!dev->tagged_supported)
+			return -EINVAL;
+		dev->tagged_queue = 1;
+		dev->current_tag = 1;
+		return 0;
+	case SCSI_IOCTL_TAGGED_DISABLE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!dev->tagged_supported)
+			return -EINVAL;
+		dev->tagged_queue = 0;
+		dev->current_tag = 0;
+		return 0;
+	case SCSI_IOCTL_PROBE_HOST:
+		return ioctl_probe(dev->host, arg);
+	case SCSI_IOCTL_SEND_COMMAND:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return scsi_ioctl_send_command((Scsi_Device *) dev,
+					     (Scsi_Ioctl_Command *) arg);
+	case SCSI_IOCTL_DOORLOCK:
+		if (!dev->removable || !dev->lockable)
+			return 0;
+		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_DOORUNLOCK:
+		if (!dev->removable || !dev->lockable)
+			return 0;
+		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+	case SCSI_IOCTL_TEST_UNIT_READY:
+		scsi_cmd[0] = TEST_UNIT_READY;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 0;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_START_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 1;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_STOP_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 0;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+		break;
+	default:
+		if (dev->host->hostt->ioctl)
+			return dev->host->hostt->ioctl(dev, cmd, arg);
+		return -EINVAL;
+	}
 	return -EINVAL;
-    }
-    return -EINVAL;
 }
 
 /*
@@ -461,14 +481,15 @@
  * fs segment fiddling.
  */
 
-int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
-    mm_segment_t oldfs;
-    int tmp;
-    oldfs = get_fs();
-    set_fs(get_ds());
-    tmp = scsi_ioctl (dev, cmd, arg);
-    set_fs(oldfs);
-    return tmp;
+int kernel_scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
+{
+	mm_segment_t oldfs;
+	int tmp;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	tmp = scsi_ioctl(dev, cmd, arg);
+	set_fs(oldfs);
+	return tmp;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)