Annotation of driverkit/libDriver/Kernel/SCSIGeneric.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) 1992 NeXT Computer, Inc.  All rights reserved. 
                     25:  *
                     26:  * SCSIGeneric.m - Generic SCSI Driver.
                     27:  *
                     28:  * HISTORY
                     29:  * 14-Jun-95   Doug Mitchell at NeXT
                     30:  *     Added SCSI-3 support.
                     31:  * 19-Aug-92    Doug Mitchell at NeXT
                     32:  *      Created. 
                     33:  */
                     34:  
                     35: #import <driverkit/SCSIGeneric.h>
                     36: #import <driverkit/SCSIGenericPrivate.h>
                     37: #import <driverkit/scsiTypes.h>
                     38: #import <driverkit/return.h>
                     39: #import <driverkit/generalFuncs.h>
                     40: #import <driverkit/kernelDriver.h>
                     41: #import <machkit/NXLock.h>
                     42: #import <driverkit/xpr_mi.h>
                     43: #import <driverkit/align.h>
                     44: 
                     45: /*
                     46:  * Private method declarations.
                     47:  */
                     48: @interface SCSIGeneric(Private)
                     49: 
                     50: - (sc_status_t)getSense                : (esense_reply_t *)sense;
                     51: - (void)clearReservation;
                     52: 
                     53: @end
                     54: 
                     55: /* 
                     56:  * Public method implementation.
                     57:  */
                     58: @implementation SCSIGeneric
                     59: 
                     60: + (IODeviceStyle)deviceStyle
                     61: {
                     62:        return IO_IndirectDevice;
                     63: }
                     64: 
                     65: /*
                     66:  * The protocol we need as an indirect device.
                     67:  */
                     68: static Protocol *protocols[] = {
                     69:        @protocol(IOSCSIControllerExported),
                     70:        nil
                     71: };
                     72: 
                     73: + (Protocol **)requiredProtocols
                     74: {
                     75:        return protocols;
                     76: }
                     77: 
                     78: 
                     79: - registerLoudly
                     80: {
                     81:     return( nil);
                     82: }
                     83: 
                     84: + (BOOL)probe : deviceDescription
                     85: {
                     86:        id sgId;
                     87:        int i;
                     88:        id controller = [deviceDescription directDevice];
                     89:        
                     90:         /*
                     91:          * We only bother attaching to controller 0 at probe time. 
                     92:          * Clients can specify other controllers later via
                     93:          * -setController:.
                     94:          */
                     95:         if([controller unit] != 0) {
                     96:                 return NO;
                     97:         }
                     98:        for(i=0; i<NUM_SG_DEV; i++) {
                     99:                sgId = [self alloc];
                    100:                sgIdMap[i] = sgId;
                    101:                [sgId sgInit:i controller:controller];
                    102:        }
                    103:        return YES;
                    104: }
                    105: 
                    106: /*
                    107:  * One-time only init. Returns non-zero on error.
                    108:  */
                    109: - (int)sgInit : (unsigned)unitNum 
                    110:                controller : controller
                    111: {
                    112:        char name[20];
                    113:        
                    114:        _controller    = controller;
                    115:         _controllerNum = 0;
                    116:        _autoSense     = 0;
                    117:        _isReserved    = 0;
                    118:        _targLunValid  = 0;
                    119:        _openLock      = [NXLock new];
                    120:        _owner         = nil;
                    121:        sprintf(name, "sg%d", unitNum);
                    122:        [self setName:name];
                    123:        [self setDeviceKind:"SCSIGeneric"];
                    124:        [self setLocation:[controller name]];
                    125:        [self setUnit:unitNum];
                    126:        [self registerDevice];
                    127:        return 0;
                    128: }
                    129: 
                    130: - (unsigned char)target
                    131: {
                    132:        return (unsigned char)_target;
                    133: }
                    134: 
                    135: - (unsigned char)lun
                    136: {
                    137:        return (unsigned char)_lun;
                    138: }
                    139: 
                    140: - (unsigned long long)SCSI3_target
                    141: {
                    142:        return _target;
                    143: }
                    144: 
                    145: - (unsigned long long)SCSI3_lun
                    146: {
                    147:        return _lun;
                    148: }
                    149: 
                    150: /*
                    151:  * Acquire and release, to allow exclusive access to this device.
                    152:  * 
                    153:  * -acquire returns non-zero if device in use, else reserves device for
                    154:  * exclusive use by 'caller'.
                    155:  * -release returns non-zero if device not currently in use by 'caller'.
                    156:  */
                    157: - (int)acquire : caller
                    158: {
                    159:        int rtn;
                    160:        
                    161:        xpr_sdev("SCSIGeneric acquire\n", 1,2,3,4,5);
                    162:        [_openLock lock];
                    163:        if(_owner) {
                    164:                rtn = 1;
                    165:        }
                    166:        else {
                    167:                _autoSense = 0;
                    168:                _owner = caller;
                    169:                rtn = 0;
                    170:        }
                    171:        [_openLock unlock];
                    172:        return rtn;
                    173: }
                    174: 
                    175: - (int)release : caller
                    176: {
                    177:        int rtn;
                    178:        
                    179:        xpr_sdev("SCSIGeneric release\n", 1,2,3,4,5);
                    180:        [_openLock lock];
                    181:        if(caller != _owner) {
                    182:                IOLog("%s: bogus close call\n", [self name]);
                    183:                rtn = 1;
                    184:        }
                    185:        else {
                    186:                /*
                    187:                 * Clear possible pending reservation.
                    188:                 */
                    189:                [self clearReservation];
                    190:                _owner = nil;
                    191:        }
                    192:        [_openLock unlock];
                    193: }
                    194: 
                    195: /* 
                    196:  * ioctl equivalents.
                    197:  */
                    198:  
                    199: /*
                    200:  * Set target and lun. If isRoot is true, this will succeed even if specified
                    201:  * target/lun are currently reserved. otherwise, returns IO_R_BUSY if 
                    202:  * desired target/lun already reserved.
                    203:  */
                    204: - (IOReturn)setTarget          : (unsigned char)target
                    205:                                  lun:(unsigned char)lun
                    206:                                  isRoot:(BOOL)isRoot
                    207: {
                    208:        xpr_sdev("SCSIGeneric setTarget t %d l %d\n", target, lun, 3,4,5);
                    209:        if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) {
                    210:                return IO_R_INVALID_ARG;  
                    211:        }
                    212:        
                    213:        [self clearReservation];
                    214:        if([_controller reserveSCSI3Target:(unsigned long long)target 
                    215:                        lun:(unsigned long long)lun
                    216:                        forOwner:self]) {
                    217:                if(!isRoot) {
                    218:                        return IO_R_BUSY;
                    219:                }               
                    220:                /*
                    221:                 * else: playing dangerously, but we'll do it...
                    222:                 */
                    223:        }
                    224:        else {
                    225:                _isReserved = 1;
                    226:        }
                    227:        _target = target;
                    228:        _lun = lun;
                    229:        _targLunValid = 1;
                    230:        return IO_R_SUCCESS;
                    231: }
                    232: 
                    233: - (IOReturn)setSCSI3Target     : (unsigned long long)target
                    234:                                  lun:(unsigned long long)lun
                    235:                                  isRoot:(BOOL)isRoot
                    236: {
                    237:        xpr_sdev("setSCSI3Target: t %x:%x l %x:%x\n",
                    238:                (unsigned)(target >> 32),
                    239:                (unsigned)target,
                    240:                (unsigned)(lun >> 32),
                    241:                (unsigned)lun, 5);
                    242:        if((target >= [_controller numberOfTargets]) || (lun > SCSI_NLUNS)) {
                    243:                return IO_R_INVALID_ARG;  
                    244:        }
                    245: 
                    246:        [self clearReservation];
                    247:        if([_controller reserveSCSI3Target:target 
                    248:                        lun:lun
                    249:                        forOwner:self]) {
                    250:                if(!isRoot) {
                    251:                        return IO_R_BUSY;
                    252:                }               
                    253:                /*
                    254:                 * else: playing dangerously, but we'll do it...
                    255:                 */
                    256:        }
                    257:        else {
                    258:                _isReserved = 1;
                    259:        }
                    260:        _target = target;
                    261:        _lun = lun;
                    262:        _targLunValid = 1;
                    263:        return IO_R_SUCCESS;
                    264: }
                    265: 
                    266: 
                    267: /*
                    268:  * Select controller number. Clears pending reservation if controllerNum
                    269:  * is changing.
                    270:  */
                    271: - (IOReturn)setController : (unsigned)controllerNum
                    272: {
                    273:        char contrStr[10];
                    274:        IOReturn drtn;
                    275:        id newController;
                    276: 
                    277:        if(controllerNum == _controllerNum) {
                    278:                return IO_R_SUCCESS;
                    279:        }
                    280:        [self clearReservation];
                    281: 
                    282:        /* 
                    283:         * Look up new controller.
                    284:         */
                    285:        sprintf(contrStr, "sc%d", controllerNum);
                    286:        drtn = IOGetObjectForDeviceName(contrStr, &newController);
                    287:        if(drtn) {
                    288:                return IO_R_NO_DEVICE;
                    289:        }
                    290:        _controllerNum = controllerNum;
                    291:        _controller = newController;
                    292:        _targLunValid = 0;
                    293:        return IO_R_SUCCESS;
                    294: }
                    295: 
                    296: /*
                    297:  * Enable/disable 'autosense' mechanism.
                    298:  */
                    299: - (IOReturn)enableAutoSense
                    300: {
                    301:        _autoSense = 1;
                    302:        return IO_R_SUCCESS;
                    303: }
                    304: 
                    305: - (IOReturn)disableAutoSense
                    306: {
                    307:        _autoSense = 0;
                    308:        return IO_R_SUCCESS;
                    309: }
                    310: 
                    311: - (int)autoSense
                    312: {
                    313:        return _autoSense;
                    314: }
                    315: 
                    316: 
                    317: /*
                    318:  * Execute CDB. Buffer must be well aligned. 
                    319:  * *sense will contain sense data if autoSense is enabled and command 
                    320:  * resulted in Check status.
                    321:  */
                    322: - (sc_status_t)executeRequest  : (IOSCSIRequest *)scsiReq
                    323:                                   buffer:(void *)buffer /* data destination */
                    324:                                   client:(vm_task_t)client
                    325:                                   senseBuf:(esense_reply_t *)senseBuf
                    326: {
                    327:        sc_status_t rtn;
                    328: 
                    329:        xpr_sdev("sg executeRequest; op %s\n", 
                    330:                IOFindNameForValue(scsiReq->cdb.cdb_opcode, 
                    331:                        IOSCSIOpcodeStrings),2,3,4,5);
                    332:        if(!_targLunValid ||
                    333:           ((unsigned long long)scsiReq->target != _target) || 
                    334:           ((unsigned long long)scsiReq->lun != _lun)) {
                    335:                rtn = SR_IOST_CMDREJ;
                    336:                goto out;
                    337:        }
                    338:        rtn = [_controller executeRequest:scsiReq
                    339:                buffer:buffer
                    340:                client:client];
                    341:        
                    342:        /*
                    343:         * The only thing we deal with is Check Status, for which we'll do
                    344:         * a Request Sense if autoSense is enabled.
                    345:         */
                    346:        if(rtn == SR_IOST_CHKSV) {
                    347:                /*
                    348:                 * Host adaptor already got us sense data.
                    349:                 */
                    350:                *senseBuf = scsiReq->senseData;
                    351:        }
                    352:        else if((rtn == SR_IOST_CHKSNV) && _autoSense) {
                    353:                rtn = [self getSense:senseBuf];
                    354:                if(rtn == SR_IOST_GOOD) {
                    355:                        rtn = SR_IOST_CHKSV;
                    356:                }
                    357:                else {
                    358:                        IOLog("%s: Request Sense on target %d lun %d "
                    359:                                "failed (%s)\n",
                    360:                                [self name], (unsigned)_target, (unsigned)_lun, 
                    361:                                IOFindNameForValue(rtn, IOScStatusStrings));
                    362:                        rtn = SR_IOST_CHKSNV;
                    363:                }
                    364:        }
                    365: out:
                    366:        xpr_sdev("sg executeRequest: returning %s\n", 
                    367:                IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5);
                    368:        return rtn;
                    369: }                                 
                    370:        
                    371: /*
                    372:  * Execute CDB, SCSI-3 style. Buffer must be well aligned. 
                    373:  * *sense will contain sense data if autoSense is enabled and command 
                    374:  * resulted in Check status.
                    375:  */
                    376: - (sc_status_t)executeSCSI3Request : (IOSCSI3Request *)scsiReq
                    377:                            buffer : (void *)buffer /* data destination */
                    378:                            client : (vm_task_t)client
                    379:                          senseBuf : (esense_reply_t *)senseBuf
                    380: {
                    381:        sc_status_t rtn;
                    382: 
                    383:        xpr_sdev("sg executeSCSI3Request; op %s\n", 
                    384:                IOFindNameForValue(scsiReq->cdb.cdb_opcode, 
                    385:                        IOSCSIOpcodeStrings),2,3,4,5);
                    386:        if(!_targLunValid ||
                    387:           (scsiReq->target != _target) || 
                    388:           (scsiReq->lun != _lun)) {
                    389:                rtn = SR_IOST_CMDREJ;
                    390:                goto out;
                    391:        }
                    392:        rtn = [_controller executeSCSI3Request:scsiReq
                    393:                buffer:buffer
                    394:                client:client];
                    395:        
                    396:        /*
                    397:         * The only thing we deal with is Check Status, for which we'll do
                    398:         * a Request Sense if autoSense is enabled.
                    399:         */
                    400:        if(rtn == SR_IOST_CHKSV) {
                    401:                /*
                    402:                 * Host adaptor already got us sense data.
                    403:                 */
                    404:                *senseBuf = scsiReq->senseData;
                    405:        }
                    406:        else if((rtn == SR_IOST_CHKSNV) && _autoSense) {
                    407:                rtn = [self getSense:senseBuf];
                    408:                if(rtn == SR_IOST_GOOD) {
                    409:                        rtn = SR_IOST_CHKSV;
                    410:                }
                    411:                else {
                    412:                        IOLog("%s: Request Sense on target %d lun %d "
                    413:                                "failed (%s)\n",
                    414:                                [self name], (unsigned)_target, (unsigned)_lun, 
                    415:                                IOFindNameForValue(rtn, IOScStatusStrings));
                    416:                        rtn = SR_IOST_CHKSNV;
                    417:                }
                    418:        }
                    419: out:
                    420:        xpr_sdev("sg executeSCSI3Request: returning %s\n", 
                    421:                IOFindNameForValue(rtn, IOScStatusStrings), 2,3,4,5);
                    422:        return rtn;
                    423: }                                 
                    424:                          
                    425: /*
                    426:  * Reset SCSI bus. We can't authorize this; caller should ensure that 
                    427:  * client is root!
                    428:  */
                    429: - (sc_status_t) resetSCSIBus;
                    430: {
                    431:        return [_controller resetSCSIBus];
                    432: }
                    433: 
                    434: - controller
                    435: {
                    436:        return _controller;
                    437: }
                    438: 
                    439: @end /* of SCSIGeneric */
                    440: 
                    441: /*
                    442:  * Private methods.
                    443:  */
                    444: @implementation SCSIGeneric(Private)
                    445: 
                    446: /*
                    447:  * Get sense data from current target and lun. senseBuf does not have
                    448:  * to be well aligned.
                    449:  */
                    450: - (sc_status_t)getSense                : (esense_reply_t *)senseBuf
                    451: {
                    452:        IOSCSIRequest   scsiReq;
                    453:        cdb_6_t         *cdbp = &scsiReq.cdb.cdb_c6;
                    454:        esense_reply_t  *alignedBuf;
                    455:        void            *freePtr;
                    456:        int             freeCnt;
                    457:        sc_status_t     rtn;
                    458:        IODMAAlignment  dmaAlign;
                    459:        
                    460:        alignedBuf = [_controller allocateBufferOfLength:
                    461:                                        sizeof(esense_reply_t)
                    462:                        actualStart:&freePtr
                    463:                        actualLength:&freeCnt];
                    464:        bzero(&scsiReq, sizeof(IOSCSIRequest));
                    465:        [_controller getDMAAlignment:&dmaAlign];
                    466:        
                    467:        scsiReq.target          = _target;
                    468:        scsiReq.lun             = _lun;
                    469:        scsiReq.read            = YES;
                    470:        if(dmaAlign.readLength > 1) {
                    471:                scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), 
                    472:                                            dmaAlign.readLength);
                    473:        } else {
                    474:                scsiReq.maxTransfer = sizeof(esense_reply_t);
                    475:        }
                    476:        scsiReq.timeoutLength   = 10;
                    477:        scsiReq.disconnect      = 0;
                    478:        cdbp->c6_opcode         = C6OP_REQSENSE;
                    479:        cdbp->c6_lun            = _lun;
                    480:        cdbp->c6_len            = sizeof(esense_reply_t);
                    481:        
                    482:        rtn = [_controller executeRequest:&scsiReq
                    483:                buffer:alignedBuf
                    484:                client:IOVmTaskSelf()];
                    485:        if(rtn == SR_IOST_GOOD) {
                    486:                *senseBuf = *alignedBuf;
                    487:        }
                    488:        IOFree(freePtr, freeCnt);
                    489:        return rtn;
                    490: }
                    491: 
                    492: /*
                    493:  * Clear possible pending reservation, whichever style was last used.
                    494:  */
                    495: - (void)clearReservation
                    496: {
                    497:        if(_isReserved) {
                    498:                if(_targLunValid) {
                    499:                        [_controller releaseSCSI3Target:_target 
                    500:                                lun:_lun
                    501:                                forOwner:self];
                    502:                        _targLunValid = 0;
                    503:                }
                    504:                else {
                    505:                        IOLog("%s: clearReservation, no valid target\n", 
                    506:                                [self name]);
                    507:                }
                    508:                _isReserved = 0;
                    509:        }
                    510:        
                    511:        /*
                    512:         * Note _targLunValid could have been true on entry even if 
                    513:         * _isReserved was false - that's the case where root set a target
                    514:         * and LUN which was already reserved.
                    515:         */
                    516:        _targLunValid = 0;
                    517: }
                    518: 
                    519: 
                    520: @end /* of SCSIGeneric(Private) */
                    521: 
                    522: 

unix.superglobalmegacorp.com

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