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