diff options
Diffstat (limited to 'i386/i386at/gpl/linux/scsi/scsi_ioctl.c')
-rw-r--r-- | i386/i386at/gpl/linux/scsi/scsi_ioctl.c | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/i386/i386at/gpl/linux/scsi/scsi_ioctl.c b/i386/i386at/gpl/linux/scsi/scsi_ioctl.c deleted file mode 100644 index 11d57bae..00000000 --- a/i386/i386at/gpl/linux/scsi/scsi_ioctl.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Don't import our own symbols, as this would severely mess up our - * symbol tables. - */ -#define _SCSI_SYMS_VER_ -#define __NO_VERSION__ -#include <linux/module.h> - -#include <asm/io.h> -#include <asm/segment.h> -#include <asm/system.h> - -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/string.h> - -#include <linux/blk.h> -#include "scsi.h" -#include "hosts.h" -#include "scsi_ioctl.h" - -#define MAX_RETRIES 5 -#define MAX_TIMEOUT 900 -#define MAX_BUF 4096 - -#define max(a,b) (((a) > (b)) ? (a) : (b)) - -/* - * If we are told to probe a host, we will return 0 if the host is not - * present, 1 if the host is present, and will return an identifying - * string at *arg, if arg is non null, filling to the length stored at - * (int *) arg - */ - -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; - - len = get_user ((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; - - memcpy_tofs (buffer, string, len); - } - } - return temp; -} - -/* - * - * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. - * The MAX_TIMEOUT and MAX_RETRIES variables are used. - * - * dev is the SCSI device struct ptr, *(int *) arg is the length of the - * input data, if any, not including the command string & counts, - * *((int *)arg + 1) is the output buffer size in bytes. - * - * *(char *) ((int *) arg)[2] the actual command byte. - * - * Note that no more than MAX_BUF data bytes will be transfered. Since - * SCSI block device size is 512 bytes, I figured 1K was good. - * but (WDE) changed it to 8192 to handle large bad track buffers. - * ERY: I changed this to a dynamic allocation using scsi_malloc - we were - * getting a kernel stack overflow which was crashing the system when we - * were using 8192 bytes. - * - * This size *does not* include the initial lengths that were passed. - * - * The SCSI command is read from the memory location immediately after the - * length words, and the input data is right after the command. The SCSI - * routines know the command size based on the opcode decode. - * - * The output area is then filled in starting from the command byte. - */ - -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) -{ - int result; - Scsi_Cmnd * SCpnt; - - SCpnt = allocate_device(NULL, dev, 1); - { - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, cmd, NULL, 0, - scsi_ioctl_done, MAX_TIMEOUT, - MAX_RETRIES); - down(&sem); - } - - 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){ - 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 */ - 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; - SCpnt->request.rq_status = RQ_INACTIVE; - wake_up(&SCpnt->device->device_wait); - return result; -} - -/* - * This interface is depreciated - users should use the scsi generics - * interface instead, as this is a more flexible approach to performing - * generic SCSI commands on a device. - */ -static int ioctl_command(Scsi_Device *dev, void *buffer) -{ - char * buf; - char cmd[12]; - char * cmd_in; - Scsi_Cmnd * SCpnt; - unsigned char opcode; - int inlen, outlen, cmdlen; - int needed, buf_needed; - int result; - - if (!buffer) - return -EINVAL; - - - /* - * Verify that we can read at least this much. - */ - result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1); - if (result) return result; - - /* - * The structure that we are passed should look like: - * - * struct sdata{ - * int inlen; - * int outlen; - * char cmd[]; # However many bytes are used for cmd. - * char data[]; - */ - inlen = get_user((unsigned int *) buffer); - outlen = get_user( ((unsigned int *) buffer) + 1); - - /* - * 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 ) inlen = MAX_BUF; - if( outlen > MAX_BUF ) outlen = MAX_BUF; - - cmd_in = (char *) ( ((int *)buffer) + 2); - opcode = get_user(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; - buf = (char *) scsi_malloc(buf_needed); - 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 : inlen); - if (result) return result; - - memcpy_fromfs ((void *) cmd, cmd_in, cmdlen); - - /* - * Obtain the data to be sent to the device (if any). - */ - memcpy_fromfs ((void *) buf, - (void *) (cmd_in + cmdlen), - inlen); - - /* - * Set the lun field to the correct value. - */ - cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); - -#ifndef DEBUG_NO_CMD - - SCpnt = allocate_device(NULL, dev, 1); - - { - struct semaphore sem = MUTEX_LOCKED; - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT, - MAX_RETRIES); - down(&sem); - } - - /* - * 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; - memcpy_tofs((void *) cmd_in, - SCpnt->sense_buffer, - sizeof(SCpnt->sense_buffer)); - } else { - result = verify_area(VERIFY_WRITE, cmd_in, outlen); - if (result) return result; - memcpy_tofs ((void *) cmd_in, buf, outlen); - } - result = SCpnt->result; - - SCpnt->request.rq_status = RQ_INACTIVE; - - if (buf) scsi_free(buf, buf_needed); - - if(SCpnt->device->scsi_request_fn) - (*SCpnt->device->scsi_request_fn)(); - - wake_up(&SCpnt->device->device_wait); - 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; -#endif -} - -/* - * the scsi_ioctl() function differs from most ioctls in that it does - * not take a major/minor number as the dev filed. Rather, it takes - * a pointer to a scsi_devices[] element, a structure. - */ -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; - - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long)); - if (result) return result; - - put_user(dev->id - + (dev->lun << 8) - + (dev->channel << 16) - + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24), - (unsigned long *) arg); - put_user( dev->host->unique_id, (unsigned long *) arg+1); - return 0; - case SCSI_IOCTL_TAGGED_ENABLE: - if(!suser()) return -EACCES; - if(!dev->tagged_supported) return -EINVAL; - dev->tagged_queue = 1; - dev->current_tag = 1; - break; - case SCSI_IOCTL_TAGGED_DISABLE: - if(!suser()) return -EACCES; - if(!dev->tagged_supported) return -EINVAL; - dev->tagged_queue = 0; - dev->current_tag = 0; - break; - case SCSI_IOCTL_PROBE_HOST: - return ioctl_probe(dev->host, arg); - case SCSI_IOCTL_SEND_COMMAND: - if(!suser()) return -EACCES; - return ioctl_command((Scsi_Device *) dev, 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); - 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); - 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); - break; - default : - return -EINVAL; - } - return -EINVAL; -} - -/* - * Just like scsi_ioctl, only callable from kernel space with no - * fs segment fiddling. - */ - -int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { - unsigned long oldfs; - int tmp; - oldfs = get_fs(); - set_fs(get_ds()); - tmp = scsi_ioctl (dev, cmd, arg); - set_fs(oldfs); - return tmp; -} - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ |