Annotation of kernel/bsd/dev/SCSIGenericKern.m, revision 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.