diff options
Diffstat (limited to 'drivers/scsi/scsi_ioctl.c')
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 775 |
1 files changed, 398 insertions, 377 deletions
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index c99366145..dbd078299 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/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; - - copy_to_user (buffer, string, len); + 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); + } } - } - 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 @@ static int ioctl_probe(struct Scsi_Host * host, void *buffer) * 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); - } -} - -static int ioctl_internal_command(Scsi_Device *dev, char * cmd, + 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, 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 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd, * 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); + 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) (); - { - 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); - 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 @@ int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic) * 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 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) * 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; } /* |