Annotation of kernel/bsd/dev/SCSIGenericKern.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*     Copyright (c) 1992 NeXT Computer, Inc.  All rights reserved. 
                     26:  *
                     27:  * SCSIGenericKern.m - UNIX front end for SCSIGeneric device. 
                     28:  *
                     29:  * HISTORY
                     30:  * 19-Aug-91    Doug Mitchell at NeXT
                     31:  *      Created. 
                     32:  */
                     33:  
                     34: /*
                     35:  * Note that this file builds with KERNEL_PRIVATE and !MACH_USER_API.
                     36:  */
                     37: #import <sys/param.h>
                     38: #import <sys/proc.h>
                     39: #import <sys/user.h>
                     40: #import <bsd/dev/scsireg.h>
                     41: 
                     42: #import <vm/vm_kern.h>
                     43: 
                     44: #import <driverkit/SCSIGeneric.h>
                     45: #import <driverkit/SCSIGenericPrivate.h>
                     46: #import <driverkit/scsiTypes.h>
                     47: #import <driverkit/xpr_mi.h>
                     48: #import <driverkit/align.h>
                     49: #import <kernserv/ns_timer.h>
                     50: 
                     51: /*
                     52:  * Map minor number to an id of a SCSIGeneric instance.
                     53:  */
                     54: id sgIdMap[NUM_SG_DEV];
                     55: 
                     56: /*
                     57:  * Index of our entry in cdevsw.
                     58:  */
                     59: static int sg_major;
                     60: 
                     61: /*
                     62:  * prototypes of static functions.
                     63:  */
                     64: static id sgDevToId(dev_t dev);
                     65: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp);
                     66: 
                     67: /*
                     68:  * cdevsw callouts.
                     69:  */
                     70:  
                     71: int sgopen(dev_t dev, 
                     72:        int oflags, 
                     73:        int devtype, 
                     74:        struct proc *pp)
                     75: {
                     76:        id devId = sgDevToId(dev);
                     77:        
                     78:        xpr_sdev("sgopen: unit %d\n", minor(dev), 2,3,4,5);
                     79:        if(devId == nil) {
                     80:                return ENXIO;
                     81:        }
                     82:        
                     83:        /*
                     84:         * Note we use devId as "caller" since we're not an object; this 
                     85:         * works since "caller" isn't used for any authentication.
                     86:         */
                     87:        if([devId acquire:devId]) {
                     88:                return EBUSY;
                     89:        }
                     90:        else {
                     91:                return 0;
                     92:        }
                     93: }
                     94: 
                     95: int sgclose(dev_t dev,
                     96:        int fflag,
                     97:        int devtype,
                     98:        struct proc *pp)
                     99: {
                    100:        id devId = sgDevToId(dev);
                    101:        
                    102:        xpr_sdev("sgclose: unit %d\n", minor(dev), 2,3,4,5);
                    103:        if(devId == nil) {
                    104:                return ENXIO;
                    105:        }
                    106:        [devId release:devId];
                    107: }
                    108: 
                    109: #define SCSI3_DEBUG    0
                    110: 
                    111: int
                    112: sgioctl(dev_t dev, 
                    113:        u_long cmd,             /* SGIOCREQ, etc */
                    114:        caddr_t data,           /* actually a ptr to scsi_req, if used */
                    115:        int flag,               /* for historical reasons. Not used. */
                    116:        struct proc *p)
                    117: {
                    118:        id devId = sgDevToId(dev);
                    119:        
                    120:        scsi_req_t *srp = (scsi_req_t *)data;
                    121:        scsi_adr_t *sap = (scsi_adr_t *)data;
                    122:        scsi3_req_t *s3rp = (scsi3_req_t *)data;
                    123:        scsi3_adr_t *s3ap = (scsi3_adr_t *)data;
                    124:        int rtn = 0;
                    125:        
                    126:        xpr_sdev("sgioctl: unit %d\n", minor(dev), 2,3,4,5);
                    127:        if(devId == nil) {
                    128:                return ENXIO;
                    129:        }
                    130:        switch (cmd) {
                    131:            case SGIOCSTL:                      /* set target/lun */
                    132:                if([devId setTarget:sap->sa_target
                    133:                                lun:sap->sa_lun
                    134:                                isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) {
                    135:                        rtn = EACCES;
                    136:                }
                    137:                break;
                    138: 
                    139:            case SGIOCCNTR:
                    140:                if([devId setController:*(int *)data]) {
                    141:                        rtn = ENODEV;
                    142:                }
                    143:                break;
                    144: 
                    145:            case SGIOCSTL3:                     /* set SCSI3 target/lun */
                    146:                #if     SCSI3_DEBUG
                    147:                IOLog("SGIOCSTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n",
                    148:                        (unsigned)(s3ap->s3a_target >> 32),
                    149:                        (unsigned)(s3ap->s3a_target),
                    150:                        (unsigned)(s3ap->s3a_lun >> 32),
                    151:                        (unsigned)(s3ap->s3a_lun));
                    152:                #endif  SCSI3_DEBUG
                    153:                if([devId setSCSI3Target:s3ap->s3a_target
                    154:                                lun:s3ap->s3a_lun
                    155:                                isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) {
                    156:                        rtn = EACCES;
                    157:                }
                    158:                break;
                    159: 
                    160:            case SGIOCGTL3:
                    161:                s3ap->s3a_target = [devId SCSI3_target];
                    162:                s3ap->s3a_lun    = [devId SCSI3_lun];
                    163:                #if     SCSI3_DEBUG
                    164:                IOLog("SGIOCGTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n",
                    165:                        (unsigned)(s3ap->s3a_target >> 32),
                    166:                        (unsigned)(s3ap->s3a_target),
                    167:                        (unsigned)(s3ap->s3a_lun >> 32),
                    168:                        (unsigned)(s3ap->s3a_lun));
                    169:                #endif  SCSI3_DEBUG
                    170:                break;
                    171:                
                    172:            case SGIOCREQ:
                    173:                rtn = sg_doiocreq(devId, srp, NULL);
                    174:                break;
                    175:                
                    176:            case SGIOCREQ3:
                    177:                rtn = sg_doiocreq(devId, NULL, s3rp);
                    178:                break;
                    179:                
                    180:            case SGIOCENAS:                     /* enable auto sense */
                    181:                if([devId enableAutoSense]) {
                    182:                        rtn = EINVAL;
                    183:                }
                    184:                break;
                    185:                
                    186:            case SGIOCDAS:                      /* disable auto sense */
                    187:                if([devId disableAutoSense]) {
                    188:                        rtn = EINVAL;
                    189:                }
                    190:                break;
                    191:                
                    192:            case SGIOCGAS:
                    193:                *(int *)data = ([devId autoSense] ? 1 : 0);
                    194:                break;
                    195:                
                    196:            case SGIOCMAXDMA:
                    197:                *(int *)data = [[devId controller] maxTransfer];
                    198:                break;
                    199:                
                    200:            case SGIOCNUMTARGS:
                    201:                *(int *)data = [[devId controller] numberOfTargets];
                    202:                break;
                    203: 
                    204:            case SGIOCRST:
                    205: #ifndef        DEBUG
                    206:                if (suser(p->p_ucred, &p->p_acflag)) {                  
                    207:                                /* this is too dangerous for
                    208:                                 * the hoi polloi */
                    209:                        rtn = EPERM;
                    210:                        break;
                    211:                }
                    212: #endif DEBUG
                    213:                if([devId resetSCSIBus]) {      /* what could go wrong? */
                    214:                        rtn = EIO;
                    215:                }
                    216:                break;
                    217: 
                    218:            default:
                    219:                rtn = EINVAL;
                    220:        }
                    221:        xpr_sdev("sgioctl: returning %d\n", rtn, 2,3,4,5);
                    222:        return rtn;
                    223: } /* sgioctl() */
                    224: 
                    225: /*
                    226:  * Static functions.
                    227:  */
                    228: 
                    229: /* 
                    230:  * Obtain id for SCSIGeneric instance associated with specified dev_t.
                    231:  * A return of nil indicates ENXIO.
                    232:  */
                    233: static id sgDevToId(dev_t dev)
                    234: {
                    235:        int minor = minor(dev);
                    236:        
                    237:        if((minor < 0) || (minor >= NUM_SG_DEV)) {
                    238:                return nil;
                    239:        }
                    240:        return sgIdMap[minor];
                    241: }
                    242: 
                    243: /* 
                    244:  * Execute one scsi_req. Called from client's task context. Returns an errno.
                    245:  * Exactly one of srp and s3rp must be non-NULL.
                    246:  */
                    247: 
                    248: /*
                    249:  * FIXME - DMA to non-page-aligned user memory doesn't work. There
                    250:  * is data corruption on read operations;l the corruption occurs on page
                    251:  * boundaries. 
                    252:  */
                    253: #define FORCE_PAGE_ALIGN       1
                    254: #if    FORCE_PAGE_ALIGN
                    255: int forcePageAlign = 1;
                    256: #endif FORCE_PAGE_ALIGN
                    257: 
                    258: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp)
                    259: {
                    260:        void            *alignedPtr;
                    261:        unsigned        alignedLen = 0;
                    262:        void            *freePtr;
                    263:        unsigned        freeLen;
                    264:        BOOL            didAlign = NO;
                    265:        vm_task_t       client = NULL;
                    266:        int             rtn = 0;
                    267:        sc_status_t     srtn;
                    268:        int             dma_max;
                    269:        sc_dma_dir_t    dma_dir;
                    270:        caddr_t         dma_addr;
                    271:        unsigned        bytesTransferred;
                    272:        
                    273:        if(srp) {
                    274:                dma_max  = srp->sr_dma_max;
                    275:                dma_dir  = srp->sr_dma_dir;
                    276:                dma_addr = srp->sr_addr;
                    277:        }
                    278:        else if(s3rp) {
                    279:                dma_max  = s3rp->s3r_dma_max;
                    280:                dma_dir  = s3rp->s3r_dma_dir;
                    281:                dma_addr = s3rp->s3r_addr;
                    282:        }
                    283:        else {
                    284:                IOPanic("sg_doiocreq: no scsi_req ptr");
                    285:        }
                    286:        if(dma_max > [[devId controller] maxTransfer]) {
                    287:                return EINVAL;
                    288:        }
                    289:        
                    290:        /* Get some well-aligned memory if necessary. By using 
                    291:         * allocateBufferOfLength we guarantee that there is enough space 
                    292:         * in the buffer we pass to the controller to handle 
                    293:         * end-of-buffer alignment, although we won't copy more 
                    294:         * than sr_dma_max to or from the  caller.
                    295:         */
                    296:        if(dma_max != 0) {
                    297: 
                    298:                IODMAAlignment dmaAlign;
                    299:                id controller = [devId controller];
                    300:                unsigned alignLength;
                    301:                unsigned alignStart;
                    302: 
                    303:                /*
                    304:                 * Get appropriate alignment from controller.
                    305:                 */
                    306:                [controller getDMAAlignment:&dmaAlign];
                    307:                if(dma_dir == SR_DMA_WR) {
                    308:                        alignLength = dmaAlign.writeLength;
                    309:                        alignStart  = dmaAlign.writeStart;
                    310:                }
                    311:                else {
                    312:                        alignLength = dmaAlign.readLength;
                    313:                        alignStart  = dmaAlign.readStart;
                    314:                }
                    315: #if            FORCE_PAGE_ALIGN
                    316:                if(forcePageAlign) {
                    317:                        alignStart = PAGE_SIZE;
                    318:                }
                    319: #endif         FORCE_PAGE_ALIGN
                    320:                if (1) {        /* XXX fix the well aligned case for 3.3 */
                    321: 
                    322:                        /* 
                    323:                         * DMA from kernel memory, we allocate and copy.
                    324:                         */
                    325:                        
                    326:                        didAlign = YES;
                    327:                        client = kernel_map;
                    328:                        
                    329:                        if(alignLength > 1) {
                    330:                                alignedLen = IOAlign(unsigned,
                    331:                                                dma_max,
                    332:                                                alignLength);
                    333:                        }
                    334:                        else {
                    335:                                alignedLen = dma_max;
                    336:                        }       
                    337:                        alignedPtr = [controller allocateBufferOfLength:
                    338:                                                dma_max
                    339:                                        actualStart:&freePtr
                    340:                                        actualLength:&freeLen];
                    341:                        if(dma_dir == SR_DMA_WR) {
                    342:                                rtn = copyin(dma_addr, alignedPtr, dma_max);
                    343:                                if(rtn) {
                    344:                                    xpr_sd(" ...copyin() returned %d\n",
                    345:                                            rtn, 2,3,4,5);
                    346:                                    rtn = EFAULT;
                    347:                                    goto err_exit;
                    348:                                }
                    349:                        }
                    350:                }
                    351:                else {
                    352:                        /*
                    353:                         * Well-aligned buffer, DMA directly to/from user 
                    354:                         * space.
                    355:                         */
                    356:                        alignedLen = dma_max;
                    357:                        alignedPtr = dma_addr;
                    358:                        client = current_task()->map;
                    359:                        didAlign = NO;
                    360:                }
                    361:                
                    362:        } else {
                    363:                alignedPtr = dma_addr;
                    364:        }
                    365:        
                    366: 
                    367:        /*
                    368:         * Generate a contemporary version of scsi_req.
                    369:         */
                    370:        if(srp) {
                    371:            IOSCSIRequest       scsiReq;
                    372:            unsigned long long  addr;
                    373:            
                    374:            bzero(&scsiReq, sizeof(scsiReq));
                    375:            addr = [devId SCSI3_target];
                    376:            
                    377:            /*
                    378:             * Can only deal with SCSI-2 style addressing
                    379:             * (32 targets, 8 LUNs).
                    380:             */
                    381:            if(addr >= SCSI3_NTARGETS) {
                    382:                rtn = EINVAL;
                    383:                goto err_exit;
                    384:            }
                    385:            scsiReq.target = (unsigned char)addr;
                    386:            addr = [devId SCSI3_lun];
                    387:            if(addr >= SCSI_NLUNS) {
                    388:                rtn = EINVAL;
                    389:                goto err_exit;
                    390:            }
                    391:            scsiReq.lun = (unsigned char)addr;
                    392:            
                    393:            /*
                    394:             * Careful. this assumes that the old and new cdb structs are
                    395:             * equivalent...
                    396:             */
                    397:            scsiReq.cdb                 = srp->sr_cdb;
                    398:            scsiReq.read                = (srp->sr_dma_dir == SR_DMA_RD) 
                    399:                                                ? YES : NO;
                    400:            scsiReq.maxTransfer         = alignedLen;
                    401:            scsiReq.timeoutLength       = srp->sr_ioto;
                    402:            scsiReq.disconnect          = srp->sr_discon_disable ? 0 : 1;
                    403:            scsiReq.cmdQueueDisable     = srp->sr_cmd_queue_disable;
                    404:            scsiReq.syncDisable         = srp->sr_sync_disable;
                    405:            scsiReq.cdbLength           = srp->sr_cdb_length;
                    406:            
                    407:            
                    408:            /*
                    409:             * Go for it.
                    410:             */
                    411:            srtn = [devId executeRequest : &scsiReq
                    412:                                  buffer : alignedPtr
                    413:                                  client : client
                    414:                                senseBuf : &srp->sr_esense];
                    415:            
                    416:            /*
                    417:             * Copy status back to user. Note that if we got this far, we
                    418:             * return good status from the function; errors are in 
                    419:             * srp->sr_io_status.
                    420:             */
                    421:            srp->sr_io_status = srtn;
                    422:            srp->sr_scsi_status = scsiReq.scsiStatus;
                    423:            bytesTransferred = srp->sr_dma_xfr = scsiReq.bytesTransferred;
                    424:            if(srp->sr_dma_xfr > srp->sr_dma_max) {
                    425:                    srp->sr_dma_xfr = srp->sr_dma_max;
                    426:            }
                    427:            ns_time_to_timeval(scsiReq.totalTime, &srp->sr_exec_time);
                    428:        }
                    429:        else {
                    430:            IOSCSI3Request      scsi3Req;
                    431: 
                    432:            bzero(&scsi3Req, sizeof(scsi3Req));
                    433:            scsi3Req.target = [devId SCSI3_target];
                    434:            scsi3Req.lun    = [devId SCSI3_lun];
                    435:            
                    436:            /*
                    437:             * Careful. this assumes that the old and new cdb structs are
                    438:             * equivalent...
                    439:             */
                    440:            scsi3Req.cdb                = s3rp->s3r_cdb;
                    441:            scsi3Req.read               = (s3rp->s3r_dma_dir == SR_DMA_RD) 
                    442:                                                ? YES : NO;
                    443:            scsi3Req.maxTransfer        = alignedLen;
                    444:            scsi3Req.timeoutLength      = s3rp->s3r_ioto;
                    445:            scsi3Req.disconnect         = s3rp->s3r_discon_disable ? 0 : 1;
                    446:            scsi3Req.cmdQueueDisable    = s3rp->s3r_cmd_queue_disable;
                    447:            scsi3Req.syncDisable        = s3rp->s3r_sync_disable;
                    448:            scsi3Req.cdbLength          = s3rp->s3r_cdb_length;
                    449:            
                    450:            
                    451:            /*
                    452:             * Go for it.
                    453:             */
                    454:            srtn = [devId executeSCSI3Request : &scsi3Req
                    455:                                       buffer : alignedPtr
                    456:                                       client : client
                    457:                                     senseBuf : &srp->sr_esense];
                    458:            
                    459:            /*
                    460:             * Copy status back to user. Note that if we got this far, we
                    461:             * return good status from the function; errors are in 
                    462:             * s3rp->sr_io_status.
                    463:             */
                    464:            s3rp->s3r_io_status = srtn;
                    465:            s3rp->s3r_scsi_status = scsi3Req.scsiStatus;
                    466:            bytesTransferred = s3rp->s3r_dma_xfr = scsi3Req.bytesTransferred;
                    467:            if(s3rp->s3r_dma_xfr > s3rp->s3r_dma_max) {
                    468:                    s3rp->s3r_dma_xfr = s3rp->s3r_dma_max;
                    469:            }
                    470:            ns_time_to_timeval(scsi3Req.totalTime, &s3rp->s3r_exec_time);
                    471:        }
                    472:        
                    473:        /*
                    474:         * Copy read data back to user if appropriate.
                    475:         */
                    476:        if((dma_dir == SR_DMA_RD) && 
                    477:           (bytesTransferred != 0) &&
                    478:            didAlign) {
                    479:                rtn = copyout(alignedPtr, dma_addr, bytesTransferred);
                    480:        }
                    481: err_exit:
                    482:        if(didAlign) {
                    483:                IOFree(freePtr, freeLen);
                    484:        }
                    485:        return rtn;
                    486: }
                    487: 
                    488: 
                    489: 

unix.superglobalmegacorp.com

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