|
|
1.1 ! root 1: /* ! 2: * Don't import our own symbols, as this would severely mess up our ! 3: * symbol tables. ! 4: */ ! 5: #define _SCSI_SYMS_VER_ ! 6: #define __NO_VERSION__ ! 7: #include <linux/module.h> ! 8: ! 9: #include <asm/io.h> ! 10: #include <asm/segment.h> ! 11: #include <asm/system.h> ! 12: ! 13: #include <linux/errno.h> ! 14: #include <linux/kernel.h> ! 15: #include <linux/sched.h> ! 16: #include <linux/mm.h> ! 17: #include <linux/string.h> ! 18: ! 19: #include <linux/blk.h> ! 20: #include "scsi.h" ! 21: #include "hosts.h" ! 22: #include "scsi_ioctl.h" ! 23: ! 24: #define MAX_RETRIES 5 ! 25: #define MAX_TIMEOUT 900 ! 26: #define MAX_BUF 4096 ! 27: ! 28: #define max(a,b) (((a) > (b)) ? (a) : (b)) ! 29: ! 30: /* ! 31: * If we are told to probe a host, we will return 0 if the host is not ! 32: * present, 1 if the host is present, and will return an identifying ! 33: * string at *arg, if arg is non null, filling to the length stored at ! 34: * (int *) arg ! 35: */ ! 36: ! 37: static int ioctl_probe(struct Scsi_Host * host, void *buffer) ! 38: { ! 39: int temp, result; ! 40: unsigned int len,slen; ! 41: const char * string; ! 42: ! 43: if ((temp = host->hostt->present) && buffer) { ! 44: result = verify_area(VERIFY_READ, buffer, sizeof(long)); ! 45: if (result) return result; ! 46: ! 47: len = get_user ((unsigned int *) buffer); ! 48: if(host->hostt->info) ! 49: string = host->hostt->info(host); ! 50: else ! 51: string = host->hostt->name; ! 52: if(string) { ! 53: slen = strlen(string); ! 54: if (len > slen) ! 55: len = slen + 1; ! 56: result = verify_area(VERIFY_WRITE, buffer, len); ! 57: if (result) return result; ! 58: ! 59: memcpy_tofs (buffer, string, len); ! 60: } ! 61: } ! 62: return temp; ! 63: } ! 64: ! 65: /* ! 66: * ! 67: * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. ! 68: * The MAX_TIMEOUT and MAX_RETRIES variables are used. ! 69: * ! 70: * dev is the SCSI device struct ptr, *(int *) arg is the length of the ! 71: * input data, if any, not including the command string & counts, ! 72: * *((int *)arg + 1) is the output buffer size in bytes. ! 73: * ! 74: * *(char *) ((int *) arg)[2] the actual command byte. ! 75: * ! 76: * Note that no more than MAX_BUF data bytes will be transfered. Since ! 77: * SCSI block device size is 512 bytes, I figured 1K was good. ! 78: * but (WDE) changed it to 8192 to handle large bad track buffers. ! 79: * ERY: I changed this to a dynamic allocation using scsi_malloc - we were ! 80: * getting a kernel stack overflow which was crashing the system when we ! 81: * were using 8192 bytes. ! 82: * ! 83: * This size *does not* include the initial lengths that were passed. ! 84: * ! 85: * The SCSI command is read from the memory location immediately after the ! 86: * length words, and the input data is right after the command. The SCSI ! 87: * routines know the command size based on the opcode decode. ! 88: * ! 89: * The output area is then filled in starting from the command byte. ! 90: */ ! 91: ! 92: static void scsi_ioctl_done (Scsi_Cmnd * SCpnt) ! 93: { ! 94: struct request * req; ! 95: ! 96: req = &SCpnt->request; ! 97: req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ ! 98: ! 99: if (req->sem != NULL) { ! 100: up(req->sem); ! 101: } ! 102: } ! 103: ! 104: static int ioctl_internal_command(Scsi_Device *dev, char * cmd) ! 105: { ! 106: int result; ! 107: Scsi_Cmnd * SCpnt; ! 108: ! 109: SCpnt = allocate_device(NULL, dev, 1); ! 110: { ! 111: struct semaphore sem = MUTEX_LOCKED; ! 112: SCpnt->request.sem = &sem; ! 113: scsi_do_cmd(SCpnt, cmd, NULL, 0, ! 114: scsi_ioctl_done, MAX_TIMEOUT, ! 115: MAX_RETRIES); ! 116: down(&sem); ! 117: } ! 118: ! 119: if(driver_byte(SCpnt->result) != 0) ! 120: switch(SCpnt->sense_buffer[2] & 0xf) { ! 121: case ILLEGAL_REQUEST: ! 122: if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; ! 123: else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); ! 124: break; ! 125: case NOT_READY: /* This happens if there is no disc in drive */ ! 126: if(dev->removable){ ! 127: printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); ! 128: break; ! 129: }; ! 130: case UNIT_ATTENTION: ! 131: if (dev->removable){ ! 132: dev->changed = 1; ! 133: SCpnt->result = 0; /* This is no longer considered an error */ ! 134: printk(KERN_INFO "Disc change detected.\n"); ! 135: break; ! 136: }; ! 137: default: /* Fall through for non-removable media */ ! 138: printk("SCSI error: host %d id %d lun %d return code = %x\n", ! 139: dev->host->host_no, ! 140: dev->id, ! 141: dev->lun, ! 142: SCpnt->result); ! 143: printk("\tSense class %x, sense error %x, extended sense %x\n", ! 144: sense_class(SCpnt->sense_buffer[0]), ! 145: sense_error(SCpnt->sense_buffer[0]), ! 146: SCpnt->sense_buffer[2] & 0xf); ! 147: ! 148: }; ! 149: ! 150: result = SCpnt->result; ! 151: SCpnt->request.rq_status = RQ_INACTIVE; ! 152: wake_up(&SCpnt->device->device_wait); ! 153: return result; ! 154: } ! 155: ! 156: /* ! 157: * This interface is depreciated - users should use the scsi generics ! 158: * interface instead, as this is a more flexible approach to performing ! 159: * generic SCSI commands on a device. ! 160: */ ! 161: static int ioctl_command(Scsi_Device *dev, void *buffer) ! 162: { ! 163: char * buf; ! 164: char cmd[12]; ! 165: char * cmd_in; ! 166: Scsi_Cmnd * SCpnt; ! 167: unsigned char opcode; ! 168: int inlen, outlen, cmdlen; ! 169: int needed, buf_needed; ! 170: int result; ! 171: ! 172: if (!buffer) ! 173: return -EINVAL; ! 174: ! 175: ! 176: /* ! 177: * Verify that we can read at least this much. ! 178: */ ! 179: result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1); ! 180: if (result) return result; ! 181: ! 182: /* ! 183: * The structure that we are passed should look like: ! 184: * ! 185: * struct sdata{ ! 186: * int inlen; ! 187: * int outlen; ! 188: * char cmd[]; # However many bytes are used for cmd. ! 189: * char data[]; ! 190: */ ! 191: inlen = get_user((unsigned int *) buffer); ! 192: outlen = get_user( ((unsigned int *) buffer) + 1); ! 193: ! 194: /* ! 195: * We do not transfer more than MAX_BUF with this interface. ! 196: * If the user needs to transfer more data than this, they ! 197: * should use scsi_generics instead. ! 198: */ ! 199: if( inlen > MAX_BUF ) inlen = MAX_BUF; ! 200: if( outlen > MAX_BUF ) outlen = MAX_BUF; ! 201: ! 202: cmd_in = (char *) ( ((int *)buffer) + 2); ! 203: opcode = get_user(cmd_in); ! 204: ! 205: needed = buf_needed = (inlen > outlen ? inlen : outlen); ! 206: if(buf_needed){ ! 207: buf_needed = (buf_needed + 511) & ~511; ! 208: if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; ! 209: buf = (char *) scsi_malloc(buf_needed); ! 210: if (!buf) return -ENOMEM; ! 211: memset(buf, 0, buf_needed); ! 212: } else ! 213: buf = NULL; ! 214: ! 215: /* ! 216: * Obtain the command from the user's address space. ! 217: */ ! 218: cmdlen = COMMAND_SIZE(opcode); ! 219: ! 220: result = verify_area(VERIFY_READ, cmd_in, ! 221: cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen); ! 222: if (result) return result; ! 223: ! 224: memcpy_fromfs ((void *) cmd, cmd_in, cmdlen); ! 225: ! 226: /* ! 227: * Obtain the data to be sent to the device (if any). ! 228: */ ! 229: memcpy_fromfs ((void *) buf, ! 230: (void *) (cmd_in + cmdlen), ! 231: inlen); ! 232: ! 233: /* ! 234: * Set the lun field to the correct value. ! 235: */ ! 236: cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); ! 237: ! 238: #ifndef DEBUG_NO_CMD ! 239: ! 240: SCpnt = allocate_device(NULL, dev, 1); ! 241: ! 242: { ! 243: struct semaphore sem = MUTEX_LOCKED; ! 244: SCpnt->request.sem = &sem; ! 245: scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT, ! 246: MAX_RETRIES); ! 247: down(&sem); ! 248: } ! 249: ! 250: /* ! 251: * If there was an error condition, pass the info back to the user. ! 252: */ ! 253: if(SCpnt->result) { ! 254: result = verify_area(VERIFY_WRITE, ! 255: cmd_in, ! 256: sizeof(SCpnt->sense_buffer)); ! 257: if (result) return result; ! 258: memcpy_tofs((void *) cmd_in, ! 259: SCpnt->sense_buffer, ! 260: sizeof(SCpnt->sense_buffer)); ! 261: } else { ! 262: result = verify_area(VERIFY_WRITE, cmd_in, outlen); ! 263: if (result) return result; ! 264: memcpy_tofs ((void *) cmd_in, buf, outlen); ! 265: } ! 266: result = SCpnt->result; ! 267: ! 268: SCpnt->request.rq_status = RQ_INACTIVE; ! 269: ! 270: if (buf) scsi_free(buf, buf_needed); ! 271: ! 272: if(SCpnt->device->scsi_request_fn) ! 273: (*SCpnt->device->scsi_request_fn)(); ! 274: ! 275: wake_up(&SCpnt->device->device_wait); ! 276: return result; ! 277: #else ! 278: { ! 279: int i; ! 280: printk("scsi_ioctl : device %d. command = ", dev->id); ! 281: for (i = 0; i < 12; ++i) ! 282: printk("%02x ", cmd[i]); ! 283: printk("\nbuffer ="); ! 284: for (i = 0; i < 20; ++i) ! 285: printk("%02x ", buf[i]); ! 286: printk("\n"); ! 287: printk("inlen = %d, outlen = %d, cmdlen = %d\n", ! 288: inlen, outlen, cmdlen); ! 289: printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); ! 290: } ! 291: return 0; ! 292: #endif ! 293: } ! 294: ! 295: /* ! 296: * the scsi_ioctl() function differs from most ioctls in that it does ! 297: * not take a major/minor number as the dev filed. Rather, it takes ! 298: * a pointer to a scsi_devices[] element, a structure. ! 299: */ ! 300: int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) ! 301: { ! 302: int result; ! 303: char scsi_cmd[12]; ! 304: ! 305: /* No idea how this happens.... */ ! 306: if (!dev) return -ENXIO; ! 307: ! 308: switch (cmd) { ! 309: case SCSI_IOCTL_GET_IDLUN: ! 310: result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long)); ! 311: if (result) return result; ! 312: ! 313: put_user(dev->id ! 314: + (dev->lun << 8) ! 315: + (dev->channel << 16) ! 316: + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24), ! 317: (unsigned long *) arg); ! 318: put_user( dev->host->unique_id, (unsigned long *) arg+1); ! 319: return 0; ! 320: case SCSI_IOCTL_TAGGED_ENABLE: ! 321: if(!suser()) return -EACCES; ! 322: if(!dev->tagged_supported) return -EINVAL; ! 323: dev->tagged_queue = 1; ! 324: dev->current_tag = 1; ! 325: break; ! 326: case SCSI_IOCTL_TAGGED_DISABLE: ! 327: if(!suser()) return -EACCES; ! 328: if(!dev->tagged_supported) return -EINVAL; ! 329: dev->tagged_queue = 0; ! 330: dev->current_tag = 0; ! 331: break; ! 332: case SCSI_IOCTL_PROBE_HOST: ! 333: return ioctl_probe(dev->host, arg); ! 334: case SCSI_IOCTL_SEND_COMMAND: ! 335: if(!suser()) return -EACCES; ! 336: return ioctl_command((Scsi_Device *) dev, arg); ! 337: case SCSI_IOCTL_DOORLOCK: ! 338: if (!dev->removable || !dev->lockable) return 0; ! 339: scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; ! 340: scsi_cmd[1] = dev->lun << 5; ! 341: scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; ! 342: scsi_cmd[4] = SCSI_REMOVAL_PREVENT; ! 343: return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); ! 344: break; ! 345: case SCSI_IOCTL_DOORUNLOCK: ! 346: if (!dev->removable || !dev->lockable) return 0; ! 347: scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; ! 348: scsi_cmd[1] = dev->lun << 5; ! 349: scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; ! 350: scsi_cmd[4] = SCSI_REMOVAL_ALLOW; ! 351: return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); ! 352: case SCSI_IOCTL_TEST_UNIT_READY: ! 353: scsi_cmd[0] = TEST_UNIT_READY; ! 354: scsi_cmd[1] = dev->lun << 5; ! 355: scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; ! 356: scsi_cmd[4] = 0; ! 357: return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); ! 358: break; ! 359: default : ! 360: return -EINVAL; ! 361: } ! 362: return -EINVAL; ! 363: } ! 364: ! 365: /* ! 366: * Just like scsi_ioctl, only callable from kernel space with no ! 367: * fs segment fiddling. ! 368: */ ! 369: ! 370: int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { ! 371: unsigned long oldfs; ! 372: int tmp; ! 373: oldfs = get_fs(); ! 374: set_fs(get_ds()); ! 375: tmp = scsi_ioctl (dev, cmd, arg); ! 376: set_fs(oldfs); ! 377: return tmp; ! 378: } ! 379: ! 380: /* ! 381: * Overrides for Emacs so that we almost follow Linus's tabbing style. ! 382: * Emacs will notice this stuff at the end of the file and automatically ! 383: * adjust the settings for this buffer only. This must remain at the end ! 384: * of the file. ! 385: * --------------------------------------------------------------------------- ! 386: * Local variables: ! 387: * c-indent-level: 4 ! 388: * c-brace-imaginary-offset: 0 ! 389: * c-brace-offset: -4 ! 390: * c-argdecl-indent: 4 ! 391: * c-label-offset: -4 ! 392: * c-continued-statement-offset: 4 ! 393: * c-continued-brace-offset: 0 ! 394: * indent-tabs-mode: nil ! 395: * tab-width: 8 ! 396: * End: ! 397: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.