Annotation of driverkit/libDriver/Kernel/SCSIDiskPrivate.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: /*     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.