Annotation of driverkit/libDriver/Kernel/IOSCSIController.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) 1991, 1992, 1993 NeXT Computer, Inc.
        !            26:  *
        !            27:  * Abstract superclass for SCSI controllers.
        !            28:  *
        !            29:  * HISTORY
        !            30:  *
        !            31:  * 1998-3-11 [email protected] Moved SCSI user to drvSCSIServer project.
        !            32:  * 12 December 1997 Martin Minow at Apple
        !            33:  *     Added IOSCISUser kernel support
        !            34:  * 14 June 1995        Doug Mitchell at NeXT
        !            35:  *     Added SCSI-3 support.
        !            36:  * 25 June 1993 David E. Bohman at NeXT
        !            37:  *     Cleaned up some (made machine independent).  Added this header.
        !            38:  * ?? ??? ???? Doug Mitchell at NeXT
        !            39:  *     Created.
        !            40:  */
        !            41: 
        !            42: #import <driverkit/IOSCSIController.h>
        !            43: #import <machkit/NXLock.h>
        !            44: #import <driverkit/return.h>
        !            45: #import <driverkit/generalFuncs.h>
        !            46: #import <driverkit/interruptMsg.h>
        !            47: #import <driverkit/align.h>
        !            48: #import <driverkit/xpr_mi.h>
        !            49: #import <driverkit/kernelDriver.h>
        !            50: 
        !            51: static int scUnitNum = 0;
        !            52: 
        !            53: /*
        !            54:  * An element of _reserveQ.
        !            55:  */
        !            56: typedef struct {
        !            57:        unsigned long long      target;
        !            58:        unsigned long long      lun;
        !            59:        id                      owner;
        !            60:        id                      lender;
        !            61:        queue_chain_t           link;
        !            62: } reserveElt;
        !            63: 
        !            64: @interface IOSCSIController(private)
        !            65: 
        !            66: - (reserveElt *) searchReserveQ: (unsigned long long) target 
        !            67:                            lun: (unsigned long long) lun;
        !            68:                           
        !            69: @end
        !            70: 
        !            71: @implementation IOSCSIController
        !            72: 
        !            73: - initFromDeviceDescription:deviceDescription
        !            74: {
        !            75:        unsigned int    target, lun;
        !            76:        char            devName[20];
        !            77:        IODMAAlignment  dmaAlign;
        !            78: 
        !            79:        queue_init(&_reserveQ);
        !            80:        if([[self class] deviceStyle] == IO_DirectDevice) {
        !            81:                /*
        !            82:                 * Allow a subclass to act like an indirect device by 
        !            83:                 * skipping this stuff.
        !            84:                 */
        !            85:                if ([super initFromDeviceDescription:deviceDescription] == nil)
        !            86:                        return nil;
        !            87:                        
        !            88:                if ([self startIOThread] != IO_R_SUCCESS) {
        !            89:                    [self free]; return nil;
        !            90:                }
        !            91:        } else
        !            92:            [self setDeviceDescription:deviceDescription];
        !            93:        
        !            94:        /*
        !            95:         *  We keep track of all scsi controllers in the system by number.
        !            96:         *  Their device names look like 'scXX'.  Note that the rest of the
        !            97:         *  system actually LOOKS FOR sc0 instead of something more basic,
        !            98:         *  so we're forced into using this scheme.
        !            99:         */     
        !           100:        [self setUnit:scUnitNum];
        !           101:        sprintf(devName, "sc%d", scUnitNum++);
        !           102:        [self setName:devName];
        !           103:        [self setDeviceKind:"sc"];
        !           104: 
        !           105:        /*
        !           106:         * Determine worst case alignment requirement for this controller.
        !           107:         * The result will be used to do the alignment in 
        !           108:         * allocateBufferOfLength.
        !           109:         */
        !           110:        [self getDMAAlignment:&dmaAlign];
        !           111:        _worstCaseAlign = dmaAlign.readStart;
        !           112:        if(dmaAlign.writeStart > _worstCaseAlign) {
        !           113:                _worstCaseAlign = dmaAlign.writeStart;
        !           114:        }
        !           115:        if(dmaAlign.readLength > _worstCaseAlign) {
        !           116:                _worstCaseAlign = dmaAlign.readLength;
        !           117:        }
        !           118:        if(dmaAlign.writeLength > _worstCaseAlign) {
        !           119:                _worstCaseAlign = dmaAlign.writeLength;
        !           120:        }
        !           121:        if(_worstCaseAlign == 1) {
        !           122:                _worstCaseAlign = 0;
        !           123:        }
        !           124:        return self;
        !           125: }
        !           126: 
        !           127: 
        !           128: - free
        !           129: {
        !           130:        int size;
        !           131:        reserveElt *rsvElt;
        !           132:        
        !           133:        if(_reserveQ.next != NULL) {
        !           134:                /*
        !           135:                 * Avoid if queue hasn't been init'd....
        !           136:                 */
        !           137:                while(!queue_empty(&_reserveQ)) {
        !           138:                        rsvElt = (reserveElt *)queue_first(&_reserveQ);
        !           139:                        queue_remove(&_reserveQ, rsvElt, reserveElt *, link);
        !           140:                        IOFree(rsvElt, sizeof(*rsvElt));
        !           141:                }
        !           142:        }
        !           143:        
        !           144:        /*
        !           145:         * If this is the last IOSCSIController to have been initialized,
        !           146:         * update the global unit counter.
        !           147:         */
        !           148:        if([self unit] == (scUnitNum - 1)) {
        !           149:                scUnitNum--;
        !           150:        }
        !           151:        
        !           152:        /* XXX what about the SCSIController thread?? */
        !           153:        return [super free];
        !           154: }
        !           155: 
        !           156: /*
        !           157:  * Release a reserved element for the owner
        !           158:  * _reserveLock held
        !           159:  */
        !           160: 
        !           161: - (void) releaseReservationElement:(reserveElt *) rsvElt
        !           162: {
        !           163:     id lender;
        !           164: 
        !           165:     lender = rsvElt->lender;
        !           166:     if( lender
        !           167:     && [lender respondsTo:@selector(reacquireTarget)]
        !           168:     && (IO_R_SUCCESS == [lender reacquireTarget]) ) {
        !           169: 
        !           170:        rsvElt->lender = nil;
        !           171:        rsvElt->owner = lender;
        !           172: 
        !           173:     } else {
        !           174:         queue_remove(&_reserveQ, rsvElt, reserveElt *, link);
        !           175:         IOFree(rsvElt, sizeof(*rsvElt));
        !           176:         _reserveCount--;
        !           177:     }
        !           178: }
        !           179: 
        !           180: /*
        !           181:  * Attempt to reserve specified target and lun for calling device. Returns
        !           182:  * non-zero if device already reserved.
        !           183:  *
        !           184:  * This is called by a client (e.g., SCSIDisk) in an attempt to mark a 
        !           185:  * particular target/lun as being "in use" by that client; it's normally
        !           186:  * only used during SCSI bus configuration.
        !           187:  */
        !           188: 
        !           189: - releaseAllUnitsForOwner: owner;
        !           190: {
        !           191:     reserveElt *rsvElt, *nxtElt;
        !           192: 
        !           193:     [_reserveLock lock];
        !           194: 
        !           195:     rsvElt = (reserveElt *) queue_first(&_reserveQ);
        !           196:     while ( !queue_end(&_reserveQ, (queue_t) rsvElt) ) {
        !           197:        nxtElt = (reserveElt *) rsvElt->link.next;
        !           198:        if (rsvElt->owner == owner) {
        !           199:            [self releaseReservationElement:rsvElt];
        !           200:        }
        !           201:        rsvElt = nxtElt;
        !           202:     }
        !           203: 
        !           204:     [_reserveLock unlock];
        !           205: }
        !           206: 
        !           207: - (int) reserveTarget:(u_char)target lun:(u_char)lun forOwner:(id)owner
        !           208: {
        !           209:        return [self reserveSCSI3Target:(unsigned long long)target
        !           210:                lun:(unsigned long long)lun
        !           211:                forOwner:owner];
        !           212: }
        !           213: 
        !           214: 
        !           215: - (void)releaseTarget:(u_char)target lun:(u_char)lun forOwner:(id)owner
        !           216: {
        !           217:        [self releaseSCSI3Target:(unsigned long long)target
        !           218:                lun:(unsigned long long)lun
        !           219:                forOwner:owner];
        !           220: }
        !           221: 
        !           222: - (int)reserveSCSI3Target      : (unsigned long long)target
        !           223:                            lun : (unsigned long long)lun
        !           224:                       forOwner : owner
        !           225: {
        !           226:        int rtn = 0;
        !           227:        int targInt = target;
        !           228:        reserveElt *rsvElt;
        !           229:        id      currentOwner;
        !           230:        
        !           231:        xpr_sdev("reserveSCSI3Target: t %x:%x l %x:%x\n",
        !           232:                (unsigned)(target >> 32),
        !           233:                (unsigned)target,
        !           234:                (unsigned)(lun >> 32),
        !           235:                (unsigned)lun, 5);
        !           236:        [_reserveLock lock];
        !           237:        
        !           238:        if(targInt >= [self numberOfTargets]) {
        !           239:                rtn = 1;
        !           240:                goto out;
        !           241:        }
        !           242:        rsvElt = [self searchReserveQ:target lun:lun];
        !           243:        if(rsvElt) {
        !           244:                xpr_sdev("...already reserved\n", 1,2,3,4,5);
        !           245: 
        !           246:                currentOwner = rsvElt->owner;
        !           247:                if( (rsvElt->lender == nil)             // only 1 deep stack
        !           248:                && [currentOwner respondsTo:@selector(requestReleaseTarget)]
        !           249:                && (IO_R_SUCCESS == [currentOwner requestReleaseTarget]) ) {
        !           250: 
        !           251:                    rsvElt->lender = currentOwner;
        !           252:                    rsvElt->owner = owner;
        !           253: 
        !           254:                } else
        !           255:                     rtn = 1;
        !           256: 
        !           257:                 goto out;
        !           258:        }
        !           259:        
        !           260:        /*
        !           261:         * Cons up a new element for _reserveQ.
        !           262:         */
        !           263:        rsvElt = IOMalloc(sizeof(*rsvElt));
        !           264:        rsvElt->target = target;
        !           265:        rsvElt->lun = lun;
        !           266:        rsvElt->owner = owner;
        !           267:        rsvElt->lender = nil;
        !           268:        queue_enter(&_reserveQ, rsvElt, reserveElt *, link);
        !           269:        _reserveCount++;
        !           270: out:
        !           271:        [_reserveLock unlock];
        !           272:        return(rtn);
        !           273: }
        !           274: 
        !           275: - (void)releaseSCSI3Target     : (unsigned long long)target
        !           276:                            lun : (unsigned long long)lun
        !           277:                       forOwner : owner
        !           278: {
        !           279:        int targInt = target;
        !           280:        reserveElt *rsvElt;
        !           281:        
        !           282:        xpr_sdev("releaseSCSI3Target: t %x:%x l %x:%x\n",
        !           283:                (unsigned)(target >> 32),
        !           284:                (unsigned)target,
        !           285:                (unsigned)(lun >> 32),
        !           286:                (unsigned)lun, 5);
        !           287:        [_reserveLock lock];
        !           288:        if(targInt >= [self numberOfTargets]) {
        !           289:                IOLog("IOSCSIController releaseTarget: INVALID TARGET\n");
        !           290:                goto out;
        !           291:        }
        !           292:        rsvElt = [self searchReserveQ:target lun:lun];
        !           293:        if(rsvElt == NULL) {
        !           294:                IOLog("IOSCSIController releaseTarget: NOT RESERVED\n");
        !           295:                goto out;
        !           296:        }
        !           297:        if(rsvElt->owner != owner) {
        !           298:                IOLog("IOSCSIController releaseTarget: INVALID OWNER\n");
        !           299:                goto out;
        !           300:        }
        !           301: 
        !           302:        [self releaseReservationElement:rsvElt];
        !           303: 
        !           304: out:
        !           305:        [_reserveLock unlock];
        !           306: }
        !           307: 
        !           308: 
        !           309: /*
        !           310:  * Returns the number of SCSI targets supported. Default is 8, returned here.
        !           311:  * Subclasses may override if they support more than 8 targets.
        !           312:  */
        !           313: - (int)numberOfTargets
        !           314: {
        !           315:        return SCSI_NTARGETS;
        !           316: }
        !           317: 
        !           318: - (unsigned int) numReserved
        !           319: {
        !           320:        return _reserveCount;
        !           321: }
        !           322: 
        !           323: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq       
        !           324:                        buffer : (void *)buffer /* data destination */
        !           325:                        client : (vm_task_t)client
        !           326: {
        !           327:        /*
        !           328:         * Subclass must implement this; we should never get here.
        !           329:         */
        !           330:        return SR_IOST_INVALID;
        !           331: }
        !           332: 
        !           333: /*
        !           334:  * executeRequest (with an IOMemoryDescriptor) requires buffers aligned to
        !           335:  * IO_SCSI_DMA_ALIGNMENT. The client identification is contained in the
        !           336:  * IOMemoryDescriptor object
        !           337:  */
        !           338: - (sc_status_t) executeRequest : (IOSCSIRequest *) scsiReq
        !           339:        ioMemoryDescriptor      : (IOMemoryDescriptor *) ioMemoryDescriptor
        !           340: {
        !           341:        /*
        !           342:         * Subclass must implement this; we should never get here.
        !           343:         */
        !           344:        return SR_IOST_INVALID;
        !           345: }
        !           346:                           
        !           347: - (sc_status_t) executeSCSI3Request : (IOSCSI3Request *)scsiReq         
        !           348:        buffer                  : (void *)buffer /* data destination */
        !           349:        client                  : (vm_task_t)client
        !           350: {
        !           351:        /*
        !           352:         * Optional.
        !           353:         */
        !           354:        return SR_IOST_CMDREJ;
        !           355: }
        !           356: 
        !           357: /*
        !           358:  * executeRequest (with an IOMemoryDescriptor) requires buffers aligned to
        !           359:  * IO_SCSI_DMA_ALIGNMENT. The client identification is contained in the
        !           360:  * IOMemoryDescriptor object
        !           361:  */
        !           362: - (sc_status_t) executeSCSI3Request : (IOSCSI3Request *) scsiReq
        !           363:        ioMemoryDescriptor      : (IOMemoryDescriptor *) ioMemoryDescriptor
        !           364: {
        !           365:        /*
        !           366:         * Optional.
        !           367:         */
        !           368:        return SR_IOST_CMDREJ;
        !           369: }
        !           370:                           
        !           371: - (sc_status_t) resetSCSIBus
        !           372: {
        !           373:        return SR_IOST_INVALID;
        !           374: }
        !           375: 
        !           376: /*
        !           377:  * Convert an sc_status_t to an IOReturn.
        !           378:  */
        !           379: - (IOReturn)returnFromScStatus:(sc_status_t)sc_status
        !           380: {
        !           381:        switch(sc_status) {
        !           382:            case SR_IOST_GOOD:
        !           383:                return(IO_R_SUCCESS);
        !           384:            case SR_IOST_ALIGN:
        !           385:                return(IO_R_ALIGN);
        !           386:            case SR_IOST_CMDREJ:
        !           387:                return(IO_R_INVALID_ARG);
        !           388:            case SR_IOST_IPCFAIL:
        !           389:                return(IO_R_IPC_FAILURE);
        !           390:            case SR_IOST_INT:
        !           391:                return(IO_R_INTERNAL);
        !           392:            case SR_IOST_MEMF:
        !           393:                return(IO_R_VM_FAILURE);
        !           394:            case SR_IOST_MEMALL:
        !           395:                return(IO_R_RESOURCE);
        !           396:            case SR_IOST_DMA:
        !           397:                return(IO_R_DMA);
        !           398:            case SR_IOST_WP:
        !           399:                return(IO_R_NOT_WRITABLE);
        !           400:            default:
        !           401:                return(IO_R_IO);
        !           402:        }
        !           403: }
        !           404: 
        !           405: 
        !           406: /*
        !           407:  * Determine maximum DMA which can be peformed in a single call to 
        !           408:  * executeRequest:buffer:client:.
        !           409:  */
        !           410: - (unsigned)maxTransfer
        !           411: {
        !           412:        return 16 * 1024 * 1024;                /* XXX */
        !           413: }
        !           414: 
        !           415: 
        !           416: /*
        !           417:  * Return required DMA alignment for current architecture.
        !           418:  * May be overridden by subclass.
        !           419:  */
        !           420: - (void)getDMAAlignment:(IODMAAlignment *)alignment
        !           421: {
        !           422:        alignment->readStart   = 1;     /* XXX */
        !           423:        alignment->writeStart  = 1;     /* XXX */
        !           424:        alignment->readLength  = 1;     /* XXX */
        !           425:        alignment->writeLength = 1;     /* XXX */
        !           426: }
        !           427: 
        !           428: 
        !           429: 
        !           430: - (unsigned int) numQueueSamples
        !           431: {
        !           432:        return 0;
        !           433: }
        !           434: 
        !           435: 
        !           436: - (unsigned int) sumQueueLengths
        !           437: {
        !           438:        return 0;
        !           439: }
        !           440: 
        !           441: 
        !           442: - (unsigned int) maxQueueLength
        !           443: {
        !           444:        return 0;
        !           445: }
        !           446: 
        !           447: 
        !           448: - (void)resetStats
        !           449: {
        !           450: }
        !           451: 
        !           452: 
        !           453: - (IOReturn)getIntValues:(unsigned *)parameterArray
        !           454:        forParameter:(IOParameterName)parameterName
        !           455:        count:(unsigned int *)count
        !           456: {
        !           457:        unsigned maxCount = *count;
        !           458:        unsigned *returnedCount = count;
        !           459:        
        !           460:        unsigned int params[IO_SCSI_CONTROLLER_STAT_ARRAY_SIZE];
        !           461:        int i;
        !           462:        if(maxCount == 0) {
        !           463:                maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
        !           464:        }
        !           465:        if(strcmp(parameterName, IO_SCSI_CONTROLLER_STATS) == 0) {
        !           466:                params[IO_SCSI_CONTROLLER_MAX_QUEUE_LENGTH] = 
        !           467:                        [self maxQueueLength];
        !           468:                params[IO_SCSI_CONTROLLER_QUEUE_SAMPLES] = 
        !           469:                        [self numQueueSamples];
        !           470:                params[IO_SCSI_CONTROLLER_QUEUE_TOTAL] = 
        !           471:                        [self sumQueueLengths];
        !           472:        
        !           473:                *returnedCount = 0;
        !           474:                for(i=0; i<IO_SCSI_CONTROLLER_STAT_ARRAY_SIZE; i++) {
        !           475:                        if(*returnedCount == maxCount)
        !           476:                                break;
        !           477:                        parameterArray[i] = params[i];
        !           478:                        (*returnedCount)++;
        !           479:                }
        !           480:                return IO_R_SUCCESS;
        !           481:        }
        !           482:        else if(strcmp(parameterName, IO_IS_A_SCSI_CONTROLLER) == 0) {
        !           483:                /*
        !           484:                 * No data; just let caller know we're a disk.
        !           485:                 */
        !           486:                *returnedCount = 0;
        !           487:                return IO_R_SUCCESS;
        !           488:        }
        !           489:        else {
        !           490:                return [super getIntValues:parameterArray
        !           491:                        forParameter:parameterName
        !           492:                        count:count];
        !           493: 
        !           494:        }
        !           495: }                                      
        !           496: 
        !           497: 
        !           498: - (IOReturn)setIntValues:(unsigned *)parameterArray
        !           499:        forParameter:(IOParameterName)parameterName
        !           500:        count:(unsigned int)count
        !           501: {
        !           502:        if(strcmp(parameterName, IO_SCSI_CONTROLLER_STATS) == 0) {
        !           503:                [self resetStats];
        !           504:                return IO_R_SUCCESS;
        !           505:        }
        !           506:        else
        !           507:                return [super setIntValues:parameterArray
        !           508:                                   forParameter:parameterName
        !           509:                                   count : count];
        !           510: }
        !           511: 
        !           512: /*
        !           513:  * Allocate some well-aligned memory. *actualStart is what has to be 
        !           514:  * IOFree()'d eventually; *actualLength is the size arg to IOFree. The 
        !           515:  * return value is the well-aligned pointer. There is room at the end of 
        !           516:  * the returned pointer's buffer to do a DMA_DO_ALIGN(...,size, 
        !           517:  * _worstCaseAlign).
        !           518:  */
        !           519: 
        !           520: - (void *)allocateBufferOfLength: (unsigned)length
        !           521:        actualStart : (void **)actualStart
        !           522:        actualLength : (unsigned *)actualLength
        !           523: {
        !           524:        char *cp;
        !           525:        int cnt = length + 2 * _worstCaseAlign;
        !           526:        
        !           527:        cp = IOMalloc(cnt);
        !           528:        *actualStart = cp;
        !           529:        *actualLength = cnt;
        !           530:        if(_worstCaseAlign > 1) {
        !           531:                return(IOAlign(void *, cp, _worstCaseAlign));
        !           532:        } 
        !           533:        else {
        !           534:                return cp;
        !           535:        }
        !           536: }
        !           537: 
        !           538: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
        !           539: {
        !           540:     strcpy( classes, IOClassSCSIController);
        !           541:     return( self);
        !           542: }
        !           543: 
        !           544: - property_IODeviceType:(char *)classes length:(unsigned int *)maxLen
        !           545: {
        !           546:     if( [[self class] deviceStyle] == IO_DirectDevice)
        !           547:         strcat( classes, " "IOTypeSCSI);
        !           548:     return( self);
        !           549: }
        !           550: 
        !           551: @end
        !           552: 
        !           553: @implementation IOSCSIController(private)
        !           554: 
        !           555: /* 
        !           556:  * Locate reserveElt for specified target and LUN. _reserveLock must be
        !           557:  * held on entry.
        !           558:  */
        !           559: - (reserveElt *)searchReserveQ : (unsigned long long)target 
        !           560:                           lun : (unsigned long long)lun
        !           561: {
        !           562:        reserveElt      *rsvElt;
        !           563:        
        !           564:        rsvElt = (reserveElt *)queue_first(&_reserveQ);
        !           565:        while(!queue_end(&_reserveQ, (queue_t)rsvElt)) {
        !           566:                if((rsvElt->target == target) && (rsvElt->lun == lun)) {
        !           567:                        return rsvElt;
        !           568:                }
        !           569:                rsvElt = (reserveElt *)rsvElt->link.next;
        !           570:        }
        !           571:        return NULL;
        !           572: }
        !           573: 
        !           574: @end

unix.superglobalmegacorp.com

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