Annotation of driverkit/libDriver/Kernel/SCSIDiskPrivate.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: /*     Copyright (c) 1991 NeXT Computer, Inc.  All rights reserved. 
        !            25:  *
        !            26:  * SCSIDiskPrivate.m - Implementation of Private methods for SCSIDisk class.
        !            27:  *
        !            28:  * HISTORY
        !            29:  *
        !            30:  * 30-Jul-98   Dan Markarian at Apple. See Radar 2260508, 2258860. If the
        !            31:  *             SCSIDisk driver attempts to probe a non-zero LUN and a
        !            32:  *             target exists on LUN 0 that is actively doing (tagged) I/O,
        !            33:  *             the target may abort all commands with an overlapped command
        !            34:  *             error, causing the original command to fail without completion.
        !            35:  *             Suggested work-arounds (for MacOS X Server, release 1): probe
        !            36:  *             only LUN 0. If a target is discovered, reserve all LUNs for
        !            37:  *             that target. This code must be revisited for IOKit.
        !            38:  *
        !            39:  *
        !            40:  * 11-Feb-91    Doug Mitchell at NeXT
        !            41:  *      Created.
        !            42:  */
        !            43: 
        !            44: #define MACH_USER_API  1       
        !            45: #undef KERNEL_PRIVATE
        !            46: 
        !            47: #import <sys/types.h>
        !            48: #import <driverkit/SCSIDiskPrivate.h>
        !            49: #import <driverkit/SCSIDiskTypes.h>
        !            50: #import <driverkit/SCSIDiskThread.h>
        !            51: #import <driverkit/SCSIDisk.h>
        !            52: #import <driverkit/IODiskPartition.h>
        !            53: #import <driverkit/scsiTypes.h>
        !            54: #import <bsd/dev/scsireg.h>
        !            55: #import <driverkit/xpr_mi.h>
        !            56: #import <driverkit/return.h>
        !            57: #import <driverkit/align.h>
        !            58: #import <driverkit/generalFuncs.h>
        !            59: #import <kernserv/prototypes.h>
        !            60: #import <mach/mach_interface.h>
        !            61: #import <machkit/NXLock.h>
        !            62: 
        !            63: static int moveString(char *inp, char *outp, int inlength, int outlength);
        !            64: 
        !            65: @implementation SCSIDisk(Private)
        !            66: 
        !            67: /*
        !            68:  * One-time only initialization.
        !            69:  */
        !            70: - initResources
        !            71: {
        !            72:        /*
        !            73:         * Radar 2005639: Initialize the instance with the
        !            74:         * compiled-in number of threads.
        !            75:         */
        !            76: #if defined(i386) || defined(hppa)
        !            77:        return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MAX]);
        !            78: #else
        !            79:        return ([self initResourcesWithThreadCount : NUM_SD_THREADS_MIN]);
        !            80: #endif
        !            81: }
        !            82: 
        !            83: - initResourcesWithThreadCount
        !            84:        : (int) threadCount       
        !            85: {
        !            86:        int threadNum;
        !            87: 
        !            88:        queue_init(&_ioQueueDisk);
        !            89:        queue_init(&_ioQueueNodisk);
        !            90:        _ioQLock = [NXConditionLock alloc];
        !            91:        [_ioQLock initWith:NO_WORK_AVAILABLE];
        !            92:        
        !            93:        /*
        !            94:         * This gets re-init'd per updateReadyState by IODiskPartitionProbe:.
        !            95:         */
        !            96:        [self setLastReadyState:IO_NotReady];
        !            97:        _ejectLock      = [NXConditionLock alloc];
        !            98:        [_ejectLock initWith:0];
        !            99:        _numDiskIos     = 0;
        !           100:        _ejectPending   = NO;
        !           101:        _isReserved     = 0;
        !           102:        _isRegistered   = 0;
        !           103:        
        !           104: 
        !           105:        /*
        !           106:         * Start up some I/O threads to perform the actual work of this device.
        !           107:         * FIXME - there should only be one thread if target does not 
        !           108:         * implement command queueing, and more (at least two, max TBD)
        !           109:         * if target does implement command queueing.
        !           110:         */
        !           111:        _numThreads = 0;
        !           112:        /*
        !           113:         * Radar 2005639: use the requested number of threads.
        !           114:         */
        !           115:        for(threadNum=0; threadNum < threadCount; threadNum++)
        !           116:        {
        !           117:                _thread[threadNum] = IOForkThread((IOThreadFunc)sdIoThread, 
        !           118:                                self);
        !           119:                _numThreads++;
        !           120:        }
        !           121:        return self;
        !           122: }
        !           123: 
        !           124: /*
        !           125:  * Device-specific initialization. We just do enough here to do some
        !           126:  * I/O and to find out if the requested target/lun is a SCSI disk device.
        !           127:  * This function is "reusable" for a given instance of SCSIDisk; initResources
        !           128:  * must have been called exactly once prior to any use of this method.
        !           129:  */
        !           130: 
        !           131: #define DRIVE_TYPE_LENGTH 80
        !           132: 
        !           133: - (sdInitReturn_t)SCSIDiskInit :(int)iunit     /* IODevice unit # */
        !           134:        targetId : (u_char)Target
        !           135:        lun : (u_char)Lun
        !           136:        controller : controllerId
        !           137: {
        !           138:        inquiry_reply_t inquiryData;
        !           139:        sc_status_t rtn;
        !           140:        char driveType[DRIVE_TYPE_LENGTH];      /* name from Inquiry */
        !           141:        char *outp;
        !           142:        char deviceName[30];
        !           143:        char location[IO_STRING_LENGTH];
        !           144:        
        !           145:        xpr_sd("SCSIDiskInit: iunit %d target %d lun %d\n", 
        !           146:                iunit, Target, Lun, 4,5);
        !           147:        
        !           148:        /*
        !           149:         * init common instance variables.
        !           150:         */
        !           151:        _controller = controllerId;
        !           152:        _target = Target;
        !           153:        _lun = Lun;
        !           154:        [self setUnit:iunit];
        !           155:        sprintf(deviceName, "sd%d", iunit);
        !           156:        [self setName:deviceName];
        !           157:        
        !           158:        /*
        !           159:         * Try an Inquiry command.
        !           160:         */
        !           161:        bzero(&inquiryData, sizeof(inquiry_reply_t));
        !           162:        rtn = [self sdInquiry:&inquiryData];
        !           163:        switch(rtn) {
        !           164:            case SR_IOST_GOOD:
        !           165:                break;
        !           166:            case SR_IOST_SELTO:
        !           167:                return(SDR_SELECTTO);
        !           168:            default:
        !           169:                return(SDR_ERROR);
        !           170:        }
        !           171: 
        !           172:        /*
        !           173:         * Is it a disk?
        !           174:         */
        !           175:        if(inquiryData.ir_qual != DEVQUAL_OK) {
        !           176:                return(SDR_NOTADISK);
        !           177:        }
        !           178:        switch(inquiryData.ir_devicetype) {
        !           179:            case DEVTYPE_DISK:
        !           180:            case DEVTYPE_WORM:
        !           181:            case DEVTYPE_OPTICAL:
        !           182:            case DEVTYPE_CDROM:
        !           183:                break;
        !           184:            default:
        !           185:                return(SDR_NOTADISK);
        !           186:        }
        !           187:        
        !           188:        /*
        !           189:         * The top 3 bits (ir_qual) have to be 0, so throw 'em out.
        !           190:         */
        !           191:        _inquiryDeviceType = inquiryData.ir_devicetype;
        !           192:        if(inquiryData.ir_removable)
        !           193:                [self setRemovable:1];
        !           194:        
        !           195:        /*
        !           196:         * Compress multiple blanks out of the vendor id and product ID. 
        !           197:         */
        !           198:        outp = driveType;
        !           199:        outp += moveString((char *)&inquiryData.ir_vendorid,
        !           200:                outp, 
        !           201:                8,
        !           202:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           203:        if(*(outp - 1) != ' ')
        !           204:                *outp++ = ' ';
        !           205:        outp += moveString((char *)&inquiryData.ir_productid,
        !           206:                outp, 
        !           207:                16,
        !           208:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           209:        if(*(outp - 1) != ' ')
        !           210:                *outp++ = ' ';
        !           211:        outp += moveString((char *)&inquiryData.ir_revision,
        !           212:                outp, 
        !           213:                4,
        !           214:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           215:        *outp = '\0';
        !           216:        [self setDriveName:driveType];
        !           217:        sprintf(location,"Target %d LUN %d at %s", _target, _lun,
        !           218:                [controllerId name]);
        !           219:        [self setLocation:location];
        !           220:        IOLog("%s: %s\n", deviceName, driveType);
        !           221: 
        !           222:        /*
        !           223:         * Do a Test Unit Ready to clear a possible Unit Attention condition.
        !           224:         * We don't care about the result.
        !           225:         */
        !           226:        [self updateReadyState];
        !           227: 
        !           228:        /*
        !           229:         * Start up motor. We'll ignore errors on this one too.
        !           230:         */
        !           231:        [self scsiStartStop:SS_START inhibitRetry:YES];
        !           232:        
        !           233:        /*
        !           234:         * Let's find out some more info. An error on the 
        !           235:         * updatePhysicalParameters could mean no disk present; that's OK...
        !           236:         */
        !           237:        [self setFormattedInternal:0];          // until we do a successful r/w
        !           238:        rtn = [self updatePhysicalParameters];
        !           239:        if(rtn) {
        !           240:                xpr_sd("SCSIDiskInit: updatePhysicalParameters failed; "
        !           241:                        "continuing\n", 
        !           242:                        1,2,3,4,5);
        !           243:        }
        !           244: 
        !           245:        /*
        !           246:         * log device name. DiskObject will log block_size and capacity.
        !           247:         */
        !           248:         
        !           249:        bzero(driveType, DRIVE_TYPE_LENGTH);
        !           250:        
        !           251:        /*
        !           252:         * Compress multiple blanks out of the vendor id and product ID. 
        !           253:         */
        !           254:        outp = driveType;
        !           255:        outp += moveString((char *)&inquiryData.ir_vendorid,
        !           256:                outp, 
        !           257:                8,
        !           258:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           259:        if(*(outp - 1) != ' ')
        !           260:                *outp++ = ' ';
        !           261:        outp += moveString((char *)&inquiryData.ir_productid,
        !           262:                outp, 
        !           263:                16,
        !           264:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           265:        if(*(outp - 1) != ' ')
        !           266:                *outp++ = ' ';
        !           267:        outp += moveString((char *)&inquiryData.ir_revision,
        !           268:                outp, 
        !           269:                32,
        !           270:                &driveType[DRIVE_TYPE_LENGTH] - outp);
        !           271:        *outp = '\0';
        !           272:        [self setDriveName:driveType];
        !           273:        sprintf(location,"Target %d LUN %d at %s", _target, _lun,
        !           274:                [controllerId name]);
        !           275:        [self setLocation:location];
        !           276:        [super init];
        !           277:        return(SDR_GOOD);
        !           278: }
        !           279: 
        !           280: /*
        !           281:  * Copy inp to outp for up to inlength input characters or outlength output
        !           282:  * characters. Compress multiple spaces and eliminate nulls. Returns number
        !           283:  * of characters copied to outp.
        !           284:  */
        !           285: static int moveString(char *inp, char *outp, int inlength, int outlength)
        !           286: {
        !           287:        int lastCharSpace = 0;
        !           288:        char *outpStart = outp;
        !           289:        
        !           290:        while(inlength && outlength) {
        !           291:                switch(*inp) {
        !           292:                    case '\0':
        !           293:                        inp++;
        !           294:                        inlength--;
        !           295:                        continue;
        !           296:                    case ' ':
        !           297:                        if(lastCharSpace) {
        !           298:                                inp++;
        !           299:                                inlength--;
        !           300:                                continue;
        !           301:                        }
        !           302:                        lastCharSpace = 1;
        !           303:                        goto copyit;
        !           304:                    default:
        !           305:                        lastCharSpace = 0;
        !           306: copyit:
        !           307:                        *outp++ = *inp++;
        !           308:                        inlength--;
        !           309:                        outlength--;
        !           310:                        break;
        !           311:                }
        !           312:        }
        !           313:        return(outp - outpStart);
        !           314: }
        !           315: 
        !           316: /*
        !           317:  * Free up local resources. 
        !           318:  */
        !           319: - free
        !           320: {
        !           321:        int threadNum;
        !           322:        sdBuf_t *sdBuf;
        !           323:        
        !           324:        xpr_sd("SCSIDisk free\n", 1,2,3,4,5);
        !           325:        
        !           326:        /* 
        !           327:         * Send a "thread abort" command to each thread.
        !           328:         */
        !           329:        sdBuf = [self allocSdBuf:NULL];
        !           330:        sdBuf->command = SDOP_ABORT_THREAD;
        !           331:        sdBuf->needsDisk = 0;
        !           332:        for(threadNum=0; threadNum<_numThreads; threadNum++) {
        !           333:                [self enqueueSdBuf:sdBuf];
        !           334:        }       
        !           335:        [self freeSdBuf:sdBuf];
        !           336:                
        !           337:        /*
        !           338:         * Release our target/lun reservation if we have one.
        !           339:         */
        !           340:        if(_isReserved) {
        !           341: #if 1  // Radar Fix #2260508
        !           342:                 /*
        !           343:                  * LUN 0 will be unreserved.  Unreserve
        !           344:                  * all the non-zero LUNs first.
        !           345:                  */
        !           346:                 [self releaseNonZeroLunsOnTarget:_target];
        !           347: #endif // Radar Fix #2260508
        !           348:                [_controller releaseTarget:_target
        !           349:                        lun:_lun
        !           350:                        forOwner:self];
        !           351:        }
        !           352:        [_ioQLock free];
        !           353:        return([super free]);
        !           354: }
        !           355: 
        !           356: - (IOReturn) reacquireTarget
        !           357: {
        !           358:        IOReturn        ret = IO_R_NOT_OPEN;
        !           359: 
        !           360:        if(NO == _isReserved) {
        !           361:             ret = IO_R_SUCCESS;
        !           362:             _isReserved = YES;
        !           363:            if( [self isRemovable])
        !           364:                 [self setLastReadyState:IO_NotReady];  // cause a volCheck probe
        !           365:            else if( IO_Ready == [self updateReadyState]) {
        !           366:                id      descr;
        !           367:                // duplicate the volCheck probe of IODiskPartition
        !           368:                 [self updatePhysicalParameters];
        !           369:                 [self diskBecameReady];
        !           370:                 descr = [IODeviceDescription new];
        !           371:                 [descr setDirectDevice:self];
        !           372:                 if( NO == [IODiskPartition probe:descr])
        !           373:                     [descr free];
        !           374:            }
        !           375:         } else
        !           376:             IOLog("SCSIDisk unexpected reacquireTarget\n");
        !           377: 
        !           378:        return( ret);
        !           379: }
        !           380: 
        !           381: - (IOReturn) requestReleaseTarget
        !           382: {
        !           383:        IOReturn        ret = IO_R_NOT_OPEN;
        !           384:        id              diskPart;
        !           385: 
        !           386:        if(_isReserved) {
        !           387:            if( _allowLoans) {
        !           388:                 diskPart = [self nextLogicalDisk];             // a partition always exists
        !           389: 
        !           390:                 ret = [diskPart requestRelease];
        !           391:                 if( ret)
        !           392:                     return( ret);
        !           393: 
        !           394:                 [self synchronizeCache];
        !           395:                 [self setLastReadyState:IO_Ready];             // stop volCheck activity
        !           396:                 _isReserved = NO;
        !           397:                 ret = IO_R_SUCCESS;
        !           398:            }
        !           399:         } else
        !           400:             IOLog("SCSIDisk unexpected requestReleaseTarget\n");
        !           401: 
        !           402:        return( ret);
        !           403: }
        !           404: 
        !           405: - (IOReturn)getCharValues              : (unsigned char *)parameterArray
        !           406:                           forParameter : (IOParameterName)parameterName
        !           407:                                  count : (unsigned *)count     // in/out
        !           408: {
        !           409: 
        !           410:        if( 0 == strncmp("IOSCSIDiskAllowLoans", parameterName, strlen("IOSCSIDiskAllowLoans")))
        !           411:            _allowLoans = 1;
        !           412:        else if( 0 == strncmp("IOSCSIDiskDisallowLoans", parameterName, strlen("IOSCSIDiskDisallowLoans")))
        !           413:            _allowLoans = 0;
        !           414: 
        !           415:        else return( [super getCharValues:parameterArray
        !           416:                             forParameter:parameterName
        !           417:                             count:count]);
        !           418: 
        !           419:        return( IO_R_SUCCESS);
        !           420: }
        !           421: 
        !           422: /*
        !           423:  * Internal I/O routines.
        !           424:  */
        !           425:  
        !           426: /*
        !           427:  * Inquiry. inquiryReply does not have to be well aligned.
        !           428:  * Retries and error logging disabled.
        !           429:  */
        !           430: - (sc_status_t)sdInquiry : (inquiry_reply_t *)inquiryReply
        !           431: {
        !           432:        IOSCSIRequest   scsiReq;
        !           433:        cdb_6_t         *cdbp = &scsiReq.cdb.cdb_c6;
        !           434:        sdBuf_t         *sdBuf;
        !           435:        inquiry_reply_t *alignedReply;
        !           436:        void            *freep;
        !           437:        int             freecnt;
        !           438:        sc_status_t     rtn;
        !           439:        IODMAAlignment  dmaAlign;
        !           440:        
        !           441:        xpr_sd("sd%d sdInquiry\n", [self unit], 2,3,4,5);
        !           442:        
        !           443:        /*
        !           444:         * Get some well-aligned memory.
        !           445:         */
        !           446:        alignedReply = [_controller allocateBufferOfLength:
        !           447:                                        sizeof(inquiry_reply_t)
        !           448:                        actualStart:&freep
        !           449:                        actualLength:&freecnt];
        !           450:        bzero(alignedReply, sizeof(inquiry_reply_t));
        !           451:        bzero(&scsiReq, sizeof(IOSCSIRequest));
        !           452:        scsiReq.target = _target;
        !           453:        scsiReq.lun = _lun;
        !           454:        scsiReq.read = YES;
        !           455:        
        !           456:        /*
        !           457:         * Get appropriate alignment from controller. 
        !           458:         */
        !           459:        [_controller getDMAAlignment:&dmaAlign];
        !           460:        if(dmaAlign.readLength > 1) {
        !           461:                scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t), 
        !           462:                        dmaAlign.readLength);
        !           463:        }
        !           464:        else {
        !           465:                scsiReq.maxTransfer = sizeof(inquiry_reply_t);
        !           466:        }
        !           467:        scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
        !           468:        scsiReq.disconnect = 1;
        !           469:        
        !           470:        sdBuf = [self allocSdBuf:NULL];
        !           471:        sdBuf->command = SDOP_CDB_READ;
        !           472:        sdBuf->scsiReq = &scsiReq;
        !           473:        sdBuf->buf = alignedReply;
        !           474:        sdBuf->client = IOVmTaskSelf();
        !           475:        cdbp->c6_opcode = C6OP_INQUIRY;
        !           476:        cdbp->c6_lun = _lun;
        !           477:        cdbp->c6_len = sizeof(inquiry_reply_t);
        !           478:        sdBuf->needsDisk = 0;
        !           479:        sdBuf->retryDisable = 1;
        !           480:        
        !           481:        [self enqueueSdBuf:sdBuf];
        !           482:        
        !           483:        if(scsiReq.driverStatus == SR_IOST_GOOD) {
        !           484:                unsigned required = (char *)(&alignedReply->ir_zero3) - 
        !           485:                                    (char *)(alignedReply);
        !           486:                if(scsiReq.bytesTransferred < required) {
        !           487:                        IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n", 
        !           488:                                [self name], scsiReq.bytesTransferred);
        !           489:                        rtn = SR_IOST_HW;
        !           490:                }
        !           491:                else {
        !           492:                        /*
        !           493:                         * Copy data back to caller's struct. Zero the 
        !           494:                         * portion of alignedReply which did not get valid
        !           495:                         * data; the last flush out of the DMA pipe could
        !           496:                         * have written trash to it (and our caller
        !           497:                         * expects NULL data).
        !           498:                         */
        !           499:                        unsigned zeroSize;
        !           500:                        
        !           501:                        zeroSize = sizeof(*alignedReply) - 
        !           502:                                scsiReq.bytesTransferred;
        !           503:                        if(zeroSize) {
        !           504:                                bzero((char *)alignedReply + 
        !           505:                                        scsiReq.bytesTransferred,
        !           506:                                        zeroSize);
        !           507:                        }
        !           508:                        *inquiryReply = *alignedReply;
        !           509:                        rtn = scsiReq.driverStatus;
        !           510:                }
        !           511:        }
        !           512:        else {
        !           513:                rtn = scsiReq.driverStatus;
        !           514:        }
        !           515:        IOFree(freep, freecnt);
        !           516:        xpr_sd("sdInquiry: returning %s\n", 
        !           517:                IOFindNameForValue(rtn, IOScStatusStrings),
        !           518:                2,3,4,5);
        !           519:        return rtn;
        !           520: }
        !           521: 
        !           522: /*
        !           523:  * Read Capacity. capacityReply does not have to be well aligned. Fails
        !           524:  * if disk not ready.
        !           525:  */
        !           526: - (sc_status_t)sdReadCapacity  : (capacity_reply_t *)capacityReply
        !           527: {
        !           528:        IOSCSIRequest   scsiReq;
        !           529:        cdb_10_t        *cdbp = &scsiReq.cdb.cdb_c10;
        !           530:        sdBuf_t         *sdBuf;
        !           531:        capacity_reply_t *alignedReply;
        !           532:        void            *freep;
        !           533:        int             freecnt;
        !           534:        sc_status_t     rtn;
        !           535:        IODMAAlignment  dmaAlign;
        !           536:        
        !           537:        xpr_sd("sd%d sdReadCapacity\n", [self unit], 2,3,4,5);
        !           538:        
        !           539:        /*
        !           540:         * Get some well-aligned memory.
        !           541:         */
        !           542:        alignedReply = [_controller allocateBufferOfLength:
        !           543:                                        sizeof(capacity_reply_t)
        !           544:                        actualStart:&freep
        !           545:                        actualLength:&freecnt];
        !           546: 
        !           547:        bzero(&scsiReq, sizeof(IOSCSIRequest));
        !           548:        scsiReq.target = _target;
        !           549:        scsiReq.lun = _lun;
        !           550:        scsiReq.read = YES;
        !           551:        
        !           552:        /*
        !           553:         * Get appropriate alignment from controller. 
        !           554:         */
        !           555:        [_controller getDMAAlignment:&dmaAlign];
        !           556:        if(dmaAlign.readLength > 1) {
        !           557:                scsiReq.maxTransfer = IOAlign(int, sizeof(capacity_reply_t), 
        !           558:                        dmaAlign.readLength);
        !           559:        }
        !           560:        else {
        !           561:                scsiReq.maxTransfer = sizeof(capacity_reply_t);
        !           562:        }
        !           563:        scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
        !           564:        scsiReq.disconnect = 1;
        !           565:        
        !           566:        sdBuf = [self allocSdBuf:NULL];
        !           567:        sdBuf->command = SDOP_CDB_READ;
        !           568:        sdBuf->scsiReq = &scsiReq;
        !           569:        sdBuf->buf = alignedReply;
        !           570:        sdBuf->client = IOVmTaskSelf();
        !           571:        cdbp->c10_opcode = C10OP_READCAPACITY;
        !           572:        cdbp->c10_lun = _lun;
        !           573:        sdBuf->needsDisk = 0;
        !           574:        
        !           575:        [self enqueueSdBuf:sdBuf];
        !           576:        
        !           577:        if(scsiReq.driverStatus == SR_IOST_GOOD) {
        !           578: #if    !i386
        !           579:                if(scsiReq.bytesTransferred != sizeof(capacity_reply_t)) {
        !           580:                        IOLog("%s: bad DMA Transfer count (%d) on Read"
        !           581:                                " Capacity\n", 
        !           582:                                [self name], scsiReq.bytesTransferred);
        !           583:                        rtn = SR_IOST_HW;
        !           584:                }
        !           585:                else {
        !           586: #else
        !           587:                {
        !           588: #endif
        !           589:                        /*
        !           590:                         * Copy data back to caller's struct.
        !           591:                         */
        !           592:                        *capacityReply = *alignedReply;
        !           593:                        rtn = scsiReq.driverStatus;
        !           594:                }
        !           595:        }
        !           596:        else {
        !           597:                rtn = scsiReq.driverStatus;
        !           598:        }
        !           599:        IOFree(freep, freecnt);
        !           600:        xpr_sd("sdReadCapacity: returning %s\n", 
        !           601:                IOFindNameForValue(rtn, IOScStatusStrings),
        !           602:                2,3,4,5);
        !           603:        return rtn;
        !           604: }
        !           605: 
        !           606: 
        !           607: /*
        !           608:  * Mode Sense. 
        !           609:  */
        !           610: - (sc_status_t)sdModeSense     : (mode_sel_data_t *)modeSenseReply
        !           611: {
        !           612:        IOSCSIRequest   scsiReq;
        !           613:        cdb_6_t         *cdbp = &scsiReq.cdb.cdb_c6;
        !           614:        sdBuf_t         *sdBuf;
        !           615:        mode_sel_data_t *alignedReply;
        !           616:        void            *freep;
        !           617:        int             freecnt;
        !           618:        sc_status_t     rtn;
        !           619:        IODMAAlignment  dmaAlign;
        !           620:        
        !           621:        xpr_sd("sd%d sdModeSense\n", [self unit], 2,3,4,5);
        !           622:        
        !           623:        /*
        !           624:         * Get some well-aligned memory.
        !           625:         */
        !           626:        alignedReply = [_controller allocateBufferOfLength:
        !           627:                                        sizeof(mode_sel_data_t)
        !           628:                        actualStart:&freep
        !           629:                        actualLength:&freecnt];
        !           630: 
        !           631:        bzero(&scsiReq, sizeof(IOSCSIRequest));
        !           632:        scsiReq.target = _target;
        !           633:        scsiReq.lun = _lun;
        !           634:        scsiReq.read = YES;
        !           635:        
        !           636:        /*
        !           637:         * Get appropriate alignment from controller. 
        !           638:         */
        !           639:        [_controller getDMAAlignment:&dmaAlign];
        !           640:        if(dmaAlign.readLength > 1) {
        !           641:                scsiReq.maxTransfer = IOAlign(int, sizeof(mode_sel_data_t), 
        !           642:                        dmaAlign.readLength);
        !           643:        }
        !           644:        else {
        !           645:                scsiReq.maxTransfer = sizeof(mode_sel_data_t);
        !           646:        }
        !           647:        scsiReq.timeoutLength = SD_TIMEOUT_SIMPLE;
        !           648:        scsiReq.disconnect = 1;
        !           649:        
        !           650:        sdBuf = [self allocSdBuf:NULL];
        !           651:        sdBuf->command = SDOP_CDB_READ;
        !           652:        sdBuf->scsiReq = &scsiReq;
        !           653:        sdBuf->buf = alignedReply;
        !           654:        sdBuf->client = IOVmTaskSelf();
        !           655:        cdbp->c6_opcode = C6OP_MODESENSE;
        !           656:        cdbp->c6_lun = _lun;
        !           657:        cdbp->c6_len = sizeof(mode_sel_data_t);
        !           658:        sdBuf->needsDisk = 1;
        !           659:        
        !           660:        [self enqueueSdBuf:sdBuf];
        !           661:        
        !           662:        if(scsiReq.driverStatus == SR_IOST_GOOD) {
        !           663: 
        !           664:                /*
        !           665:                 * Copy data back to caller's struct.
        !           666:                 */
        !           667:                *modeSenseReply = *alignedReply;
        !           668:                rtn = scsiReq.driverStatus;
        !           669:        }
        !           670:        else {
        !           671:                rtn = scsiReq.driverStatus;
        !           672:        }
        !           673: 
        !           674:        IOFree(freep, freecnt);
        !           675: 
        !           676:        xpr_sd("sdModeSense: returning %s\n", 
        !           677:                IOFindNameForValue(rtn, IOScStatusStrings),
        !           678:                2,3,4,5);
        !           679:        return rtn;
        !           680: }
        !           681: 
        !           682: /*
        !           683:  * Read data; retries and error reporting disabled. Assumes disk is present.
        !           684:  */ 
        !           685: - (IOReturn)sdRawRead          : (int)block
        !           686:                                  blockCnt:(int)blockCnt
        !           687:                                  buffer:(void *)buffer
        !           688: {
        !           689:        sdBuf_t *sdBuf;
        !           690:        IOReturn rtn;
        !           691:        
        !           692:        xpr_sd("sdRawRead block %d cnt %d\n", block, blockCnt, 3,4,5);
        !           693:        sdBuf = [self allocSdBuf:NULL];
        !           694:        sdBuf->command = SDOP_READ;
        !           695:        sdBuf->block = block;
        !           696:        sdBuf->blockCnt = blockCnt;
        !           697:        sdBuf->buf = buffer;
        !           698:        sdBuf->client = IOVmTaskSelf();
        !           699:        sdBuf->needsDisk = 1;
        !           700:        sdBuf->retryDisable = 1;
        !           701:        rtn = [self enqueueSdBuf:sdBuf];
        !           702:        [self freeSdBuf:sdBuf];
        !           703:        xpr_sd("sdRawRead: returning %s\n", [self stringFromReturn:rtn], 
        !           704:                2,3,4,5);
        !           705:        return(rtn);
        !           706: }
        !           707: 
        !           708: /*
        !           709:  * Start, stop, eject.
        !           710:  */
        !           711: - (IOReturn)scsiStartStop : (startStop_t)cmd
        !           712:                            inhibitRetry : (BOOL)inhibitRetry
        !           713: {
        !           714:        IOSCSIRequest scsiReq;
        !           715:        sdBuf_t *sdBuf;
        !           716:        cdb_6_t *cdbp = &scsiReq.cdb.cdb_c6;
        !           717:        IOReturn rtn;
        !           718:        
        !           719:        xpr_sd("%s: scsiStartStop: cmd 0x%x\n", [self name], cmd,3,4,5);
        !           720:        
        !           721:        bzero(&scsiReq, sizeof(IOSCSIRequest));
        !           722:        scsiReq.target = _target;
        !           723:        scsiReq.lun = _lun;
        !           724:        scsiReq.timeoutLength = SD_TIMEOUT_EJECT;
        !           725:        scsiReq.disconnect = 1;
        !           726:        
        !           727:        sdBuf = [self allocSdBuf:NULL];
        !           728:        sdBuf->scsiReq = &scsiReq;
        !           729:        sdBuf->retryDisable = inhibitRetry ? 1 : 0;
        !           730:        sdBuf->needsDisk = 1;
        !           731:        
        !           732:        cdbp->c6_opcode = C6OP_STARTSTOP;
        !           733:        cdbp->c6_lun = _lun;
        !           734: 
        !           735:        switch(cmd) {
        !           736:            case SS_EJECT:
        !           737:                cdbp->c6_len = C6S_SS_EJECT;
        !           738:                sdBuf->command = SDOP_EJECT;
        !           739:                break;
        !           740:            case SS_STOP:
        !           741:                cdbp->c6_len = C6S_SS_STOP;
        !           742:                sdBuf->command = SDOP_CDB_WRITE;
        !           743:                break;
        !           744:            case SS_START:
        !           745:                cdbp->c6_len = C6S_SS_START;
        !           746:                sdBuf->command = SDOP_CDB_WRITE;
        !           747:                break;
        !           748:        }
        !           749: 
        !           750:        rtn = [self enqueueSdBuf:sdBuf];
        !           751:        xpr_sd("%s scsiStartStop: returning %s\n", [self name], 
        !           752:                [self stringFromReturn:rtn], 3,4,5);
        !           753:        [self freeSdBuf:sdBuf];
        !           754:        return(rtn);
        !           755: }
        !           756: 
        !           757: /*
        !           758:  * Common read/write routine.
        !           759:  */
        !           760: - (IOReturn) deviceRwCommon : (sdOp_t)command
        !           761:                  block: (u_int) deviceBlock
        !           762:                  length : (u_int)length 
        !           763:                  buffer : (void *)buffer
        !           764:                  client : (vm_task_t)client
        !           765:                  pending : (void *)pending
        !           766:                  actualLength : (u_int *)actualLength
        !           767: {
        !           768:        sdBuf_t *sdBuf;
        !           769:        IOReturn rtn;
        !           770:        u_int blocksReq;
        !           771:        u_int block_size;
        !           772:        u_int dev_size;
        !           773:        
        !           774:        /*
        !           775:         * Note we have to 'fault in' a possible non-present disk in 
        !           776:         * order to get its physical parameters...
        !           777:         */
        !           778:        rtn = [self isDiskReady:YES];
        !           779:        switch(rtn) {
        !           780:            case IO_R_SUCCESS:
        !           781:                break;
        !           782:            case IO_R_NO_DISK:
        !           783:                xpr_sd("%s deviceRwCommon: disk not present\n",
        !           784:                        [self name], 2,3,4,5);
        !           785:                return(rtn);
        !           786:            default:
        !           787:                IOLog("%s deviceRwCommon: bogus return from isDiskReady "
        !           788:                        "(%s)\n",
        !           789:                        [self name], [self stringFromReturn:rtn]);
        !           790:                return(rtn);
        !           791:        }
        !           792: 
        !           793:        if(![self isFormatted])
        !           794:                return(IO_R_UNFORMATTED);
        !           795:        block_size = [self blockSize];
        !           796:        dev_size = [self diskSize];
        !           797:        
        !           798:        /*
        !           799:         * Verify access and legal parameters.
        !           800:         */
        !           801:        if(length % block_size) {
        !           802:                xpr_sd("deviceRwCommon: unaligned length\n", 1,2,3,4,5);
        !           803:                return(IO_R_INVALID);
        !           804:        }
        !           805:        blocksReq = length / block_size;
        !           806:        if((deviceBlock + blocksReq) > dev_size) {
        !           807:                if(deviceBlock >= dev_size) {
        !           808:                        xpr_sd("deviceRwCommon: invalid "
        !           809:                                "deviceBlock/byte count\n", 1,2,3,4,5);
        !           810:                        return(IO_R_INVALID_ARG);
        !           811:                }
        !           812:                /*
        !           813:                 * Truncate.
        !           814:                 */
        !           815:                blocksReq = dev_size - deviceBlock;
        !           816:                xpr_sd("deviceRwCommon: truncating to %d blocks\n", blocksReq,
        !           817:                        2,3,4,5);
        !           818:        }
        !           819:        sdBuf = [self allocSdBuf:pending];
        !           820:        sdBuf->command = command;
        !           821:        sdBuf->block = deviceBlock;
        !           822:        sdBuf->blockCnt = blocksReq;
        !           823:        sdBuf->buf = buffer;
        !           824:        sdBuf->client = client;
        !           825:        sdBuf->needsDisk = 1;
        !           826:        rtn = [self enqueueSdBuf:sdBuf];
        !           827:        if(pending == NULL) {
        !           828:                /* 
        !           829:                 * Sync I/O.
        !           830:                 */
        !           831:                *actualLength = sdBuf->bytesXfr;
        !           832:                [self freeSdBuf:sdBuf];
        !           833:        }
        !           834:        return(rtn);
        !           835: }
        !           836: 
        !           837: /*
        !           838:  * -- Enqueue an sdBuf on _ioQueue<Disk,Nodisk>
        !           839:  * -- wake up one of the I/O threads
        !           840:  * -- wait for I/O complete (if sdBuf->pending == NULL)
        !           841:  */
        !           842: - (IOReturn)enqueueSdBuf:(sdBuf_t *)sdBuf
        !           843: {      
        !           844:        queue_head_t *q;
        !           845:        
        !           846: #ifdef DDM_DEBUG
        !           847:        if(sdBuf->pending) {
        !           848:                xpr_sd("enqueueSdBuf: sdBuf 0x%x, ASYNC\n", sdBuf, 2,3,4,5);
        !           849:        }
        !           850:        else {
        !           851:                xpr_sd("enqueueSdBuf: sdBuf 0x%x, SYNC\n", sdBuf, 2,3,4,5);
        !           852:        }
        !           853: #endif DDM_DEBUG
        !           854: 
        !           855:        sdBuf->status = IO_R_INVALID;
        !           856:        [_ioQLock lock];
        !           857:        /*
        !           858:         * TBD - sort by disk block eventually.
        !           859:         */
        !           860:        if(sdBuf->needsDisk)
        !           861:                q = &_ioQueueDisk;
        !           862:        else
        !           863:                q = &_ioQueueNodisk;
        !           864:        queue_enter(q, sdBuf, sdBuf_t *, link);
        !           865:        [_ioQLock unlockWith:WORK_AVAILABLE];
        !           866:        if(sdBuf->pending != NULL)
        !           867:                return(IO_R_SUCCESS);
        !           868:        
        !           869:        /*
        !           870:         * wait for I/O complete.
        !           871:         */
        !           872:        [sdBuf->waitLock lockWhen:YES];
        !           873:        [sdBuf->waitLock unlockWith:NO];        // for easy reuse
        !           874:        xpr_sd("enqueueSdBuf: I/O Complete sdBuf 0x%x status %s\n",
        !           875:                sdBuf, [self stringFromReturn:sdBuf->status], 3,4,5);
        !           876:        return(sdBuf->status);
        !           877: }
        !           878: 
        !           879: /*
        !           880:  * Allocate and free sdBuf_t's.
        !           881:  *
        !           882:  * TBD - we might keep around a queue of free sdBuf_t's.
        !           883:  */
        !           884: - (sdBuf_t *)allocSdBuf : (void *)pending
        !           885: {
        !           886:        sdBuf_t *sdBuf = IOMalloc(sizeof(sdBuf_t));
        !           887:        
        !           888:        bzero(sdBuf, sizeof(sdBuf_t));
        !           889:        if(pending == NULL) {
        !           890:                sdBuf->waitLock = [NXConditionLock alloc];
        !           891:                [sdBuf->waitLock initWith:NO];
        !           892:        }
        !           893:        else
        !           894:                sdBuf->pending = pending;
        !           895:        return(sdBuf);
        !           896: }
        !           897: 
        !           898: - (void)freeSdBuf : (sdBuf_t *)sdBuf
        !           899: {
        !           900:        if(!sdBuf->pending) {
        !           901:                [sdBuf->waitLock free];
        !           902:        }
        !           903:        IOFree(sdBuf, sizeof(sdBuf_t));
        !           904: }
        !           905: 
        !           906: #if 1  // Radar Fix #2260508
        !           907: - (void) reserveNonZeroLunsOnTarget : (int) target
        !           908: {
        !           909:   //
        !           910:   // Reserves all non-zero LUNs for the specified target.  If a given
        !           911:   // LUN is already reserved by someone else,  reserveTarget is smart
        !           912:   // enough to leave it alone and reject our reservation request  (no
        !           913:   // errors are logged).
        !           914:   //
        !           915:   // Assumptions:
        !           916:   // o  _controller instance variable is already set
        !           917:   //
        !           918: 
        !           919:   unsigned char tempLun;
        !           920: 
        !           921:   for (tempLun = 1; tempLun < SCSI_NLUNS; tempLun++)
        !           922:   {
        !           923:     [_controller reserveTarget:target lun:tempLun forOwner:self];
        !           924:   }
        !           925: }
        !           926: 
        !           927: - (void) releaseNonZeroLunsOnTarget : (int) target
        !           928: {
        !           929:   //
        !           930:   // Unreserves all non-zero LUNs for the specified target.   If a given
        !           931:   // LUN has been reserved by someone other than us,   the releaseTarget
        !           932:   // method is smart enough to leave the LUN reserved (however, an error
        !           933:   // will be logged).
        !           934:   //
        !           935:   // Assumptions:
        !           936:   // o  _controller instance variable is already set
        !           937:   //
        !           938: 
        !           939:   unsigned char tempLun;
        !           940: 
        !           941:   // Release the luns in reverse order to avoid a problem when another
        !           942:   // client is simultaneously trying to acquire the luns. (This is,
        !           943:   // of course, impossible, but it can't hurt to be suspicious.)
        !           944: 
        !           945:   for (tempLun = SCSI_NLUNS - 1; tempLun >= 1; tempLun--)
        !           946:   {
        !           947:     [_controller releaseTarget:target lun:tempLun forOwner:self];
        !           948:   }
        !           949: }
        !           950: #endif // Radar Fix #2260508
        !           951: 
        !           952: @end
        !           953: 
        !           954: 
        !           955: 

unix.superglobalmegacorp.com

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