Annotation of Gnu-Mach/linux/src/drivers/scsi/scsi_ioctl.c, revision 1.1

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:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.