Annotation of driverkit/libDriver/Kernel/IOSCSIController.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) 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.