Annotation of Examples/DriverKit/SCSITape/SCSITape_reloc.tproj/SCSITape.m, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * SCSITape.m -- implementation of scsi tape driver routines
                      3:  *
                      4:  * HISTORY
                      5:  * 31-Mar-93   Phillip Dibner at NeXT
                      6:  *     Created.
                      7:  *
                      8:  */ 
                      9:  
                     10: 
                     11: #import <sys/errno.h>
                     12: #import <sys/types.h>
                     13: #import <sys/time.h>
                     14: #import <sys/conf.h>
                     15: #import <sys/uio.h>
                     16: #import <sys/mtio.h>
                     17: #import <bsd/dev/scsireg.h>
                     18: 
                     19: #import <driverkit/scsiTypes.h>
                     20: #import <driverkit/align.h>
                     21: #import <driverkit/kernelDriver.h>
                     22: #import <driverkit/scsiTypes.h>
                     23: #import <driverkit/return.h>
                     24: #import <machkit/NXLock.h>
                     25: #import <kernserv/prototypes.h>
                     26: #import <kernserv/kern_server_types.h>
                     27: #import "SCSITape.h"
                     28: #import "SCSITapeTypes.h"
                     29: 
                     30: #define DRIVE_TYPE_LENGTH 80
                     31: 
                     32: #define USE_EBD        1               /* use "even byte disconnect" rather than 
                     33:                                 * "no disconnect during data xfer" for exabyte
                     34:                                 */
                     35: 
                     36: extern int st_devsw_init();
                     37: 
                     38: static int moveString();       /* rmv nulls & blanks from inquiry strings */
                     39: void assign_cdb_c6s_len();     /* store length data in little-endian cdb_6s */
                     40: void assign_msbd_numblocks();  /* store nblks in little-endian modesel bd */
                     41: void assign_msbd_blocklength();        /* store blklen in little-endian modesel bd */
                     42: int cdb_c6s_len_value();       /* byte swap to read length data in cdb */
                     43: int er_info_value ();          /* byte swapping for sense reply info data */
                     44: 
                     45: id             stIdMap [NST];
                     46: 
                     47: @implementation SCSITape
                     48: 
                     49: + (IODeviceStyle)deviceStyle
                     50: {
                     51:        return IO_IndirectDevice;
                     52: }
                     53: 
                     54: /*
                     55:  * The protocol we need as an indirect device.
                     56:  */
                     57: static Protocol *protocols[] = {
                     58:     @protocol(IOSCSIControllerExported),
                     59:     nil
                     60: };
                     61: 
                     62: + (Protocol **)requiredProtocols
                     63: {
                     64:     return protocols;
                     65: }
                     66: 
                     67: static unsigned int tapeUnit = 0;
                     68: 
                     69: + (BOOL) probe: deviceDescription
                     70: {
                     71:     SCSITape                   *tapeId = nil;
                     72:     unsigned char              stTarget, stLun;
                     73:     id                         controllerId = 
                     74:                                        [deviceDescription directDevice];
                     75:     stInitReturn_t             irtn = STR_ERROR;
                     76:     BOOL                       brtn = NO;
                     77:     int                                major;
                     78:        
                     79: /* asm volatile("int3");  */ // Early break to debugger
                     80:     
                     81:     if ((major = st_devsw_init()) < 0) {
                     82:        return NO;
                     83:     }
                     84: 
                     85:     for (stTarget=0; stTarget<SCSI_NTARGETS; stTarget++) {
                     86:        for(stLun=0; stLun<SCSI_NLUNS; stLun++) {
                     87: 
                     88: #ifdef DEBUG
                     89: IOLog ("SCSITape probe: target %d  lun %d\n", stTarget, stLun);
                     90: #endif DEBUG
                     91: 
                     92:            if(tapeId == nil) {
                     93:                /*
                     94:                 * Create an instance, do some basic 
                     95:                 * initialization. Set up a default 
                     96:                 * device name for error reporting during
                     97:                 * initialization.
                     98:                 */
                     99:                tapeId = [SCSITape alloc];
                    100:            }
                    101: 
                    102:            if ([controllerId reserveTarget:stTarget
                    103:                lun:stLun
                    104:                forOwner:tapeId]) {
                    105:                /*
                    106:                 * Someone already has this one.
                    107:                 */
                    108:                continue;   
                    109:            }
                    110:            else {
                    111:                [tapeId setReservedTargetLun: YES];
                    112:            }
                    113: 
                    114: #ifdef DEBUG
                    115: IOLog ("SCSITape probe: about to init\n");
                    116: #endif DEBUG
                    117: 
                    118:            irtn = [tapeId initSCSITape:(int)tapeUnit
                    119:                target: stTarget
                    120:                lun: stLun
                    121:                controller: controllerId
                    122:                majorDeviceNumber: major];
                    123: 
                    124: #ifdef DEBUG
                    125: IOLog ("SCSITape probe: irtn is %d\n", irtn);
                    126: #endif DEBUG
                    127: 
                    128:            switch (irtn) {
                    129:                case STR_GOOD:
                    130:                    /*
                    131:                     * Init'd OK - still must register device.
                    132:                     */
                    133:                    [tapeId registerDevice];
                    134:                    stIdMap [tapeUnit] = tapeId;
                    135:                    tapeId = nil;
                    136:                    tapeUnit++;
                    137:                    if (tapeUnit >= NST) goto done;
                    138:                    brtn = YES;
                    139:                    break;
                    140:                                
                    141:                default:
                    142:                    [controllerId releaseTarget: stTarget
                    143:                        lun: stLun
                    144:                        forOwner: tapeId];
                    145:                    [tapeId setReservedTargetLun: NO];
                    146:                    if(irtn == STR_SELECTTO) {
                    147:                        /*
                    148:                         * Skip the rest of the luns on 
                    149:                         * this target.
                    150:                         */
                    151:                        goto nextTarget;
                    152:                    }
                    153:            /* 
                    154:             * else try next lun.
                    155:             */
                    156:            }   /* switch (irtn) */
                    157:        }       /* for lun */
                    158: 
                    159: nextTarget:
                    160: 
                    161:        continue;
                    162:     }          /* for target */
                    163:        
                    164: done:
                    165:     /*
                    166:      * Free up leftover owner and id.  At this point, tapeId does NOT have
                    167:      * a target/lun reserved.
                    168:      */
                    169:     if(tapeId) {
                    170:        [tapeId free];
                    171:     }
                    172:        
                    173:     return brtn;
                    174: }
                    175: 
                    176: 
                    177: - (stInitReturn_t) initSCSITape:(int)iunit     /* IODevice unit # */
                    178:     target:            (u_char) stTarget
                    179:     lun:               (u_char) stLun
                    180:     controller:                controllerId
                    181:     majorDeviceNumber: (int) major
                    182: {
                    183:     inquiry_reply_t    inquiryData;
                    184:     sc_status_t                rtn;
                    185:     char               driveType[DRIVE_TYPE_LENGTH];   /* name from Inquiry */
                    186:     char               *outp;
                    187:     char               deviceName[30];
                    188:     char               location[IO_STRING_LENGTH];
                    189:        
                    190:        
                    191:     /*
                    192:      * Initialize common instance variables.
                    193:      */
                    194:     _controller = controllerId;
                    195:     _target = stTarget;
                    196:     _lun = stLun;
                    197:     sprintf(deviceName, "st%d", iunit);
                    198:     [self setName: deviceName];
                    199:     [self setDeviceKind:"SCSITape"];
                    200:     [self setLocation:[_controller name]];
                    201:     [self setUnit: iunit];
                    202: 
                    203: #ifdef DEBUG
                    204: IOLog 
                    205:     ("InitSCSITape: target %d  lun %d  unit %d  deviceName %s  location %s\n",
                    206:     stTarget, stLun, iunit, deviceName, [_controller name]);
                    207: #endif DEBUG
                    208: 
                    209:     /*
                    210:      * Resources for commands during initialization.
                    211:      */
                    212:     _senseDataPtr = IOMalloc (sizeof (struct esense_reply));
                    213:     _senseDataValid = NO;
                    214: 
                    215:     /*
                    216:      * Other instance variables
                    217:      */
                    218:     _didWrite = NO;
                    219:     _suppressIllegalLength = NO;
                    220:     _isInitialized = NO;
                    221:     _devLock = nil;                    // Until we know we're a tape
                    222: 
                    223:     /*
                    224:      * Test Unit Ready to clear possible Unit Attention.   Success is
                    225:      * not important.
                    226:      */
                    227:     [self stTestReady];
                    228: 
                    229:     /*
                    230:      * Try an Inquiry command.
                    231:      */
                    232:     bzero(&inquiryData, sizeof(inquiry_reply_t));
                    233:     rtn = [self stInquiry:&inquiryData];
                    234: 
                    235: #ifdef DEBUG
                    236: IOLog ("InitSCSITape inquiry returned %d\n", rtn);
                    237: #endif DEBUG
                    238: 
                    239:     switch(rtn) {
                    240:        case SR_IOST_GOOD:
                    241:            break;
                    242:        case SR_IOST_SELTO:
                    243:            return STR_SELECTTO;
                    244:        default:
                    245:            return STR_ERROR;
                    246:     }
                    247: 
                    248:     /*
                    249:      * Is it a tape?  
                    250:      */
                    251:     if(inquiryData.ir_qual != DEVQUAL_OK ||
                    252:        inquiryData.ir_devicetype != DEVTYPE_TAPE) {
                    253: 
                    254: #ifdef DEBUG
                    255: IOLog ("InitSCSITape: not a tape\n");
                    256: #endif DEBUG
                    257: 
                    258:        return(STR_NOTATAPE);
                    259:     }
                    260:        
                    261:     /*
                    262:      * Set up resources for exclusive open.
                    263:      */
                    264:     _devLock = [[NXLock alloc] init];
                    265:     _devAcquired = NO;
                    266: 
                    267:     /*
                    268:      * Compress multiple blanks out of the vendor id and product ID. 
                    269:      */
                    270:     bzero (driveType, DRIVE_TYPE_LENGTH);
                    271:     outp = driveType;
                    272:     outp += moveString((char *)&inquiryData.ir_vendorid,
                    273:        outp, 
                    274:        8,
                    275:        &driveType[DRIVE_TYPE_LENGTH] - outp);
                    276:     if(*(outp - 1) != ' ')
                    277:        *outp++ = ' ';
                    278:     outp += moveString((char *)&inquiryData.ir_productid,
                    279:        outp, 
                    280:        16,
                    281:        &driveType[DRIVE_TYPE_LENGTH] - outp);
                    282:     if(*(outp - 1) != ' ')
                    283:        *outp++ = ' ';
                    284:     outp += moveString((char *)&inquiryData.ir_revision,
                    285:        outp, 
                    286:        4,
                    287:        &driveType[DRIVE_TYPE_LENGTH] - outp);
                    288:     *outp = '\0';
                    289: 
                    290:     sprintf(location, "Target %d LUN %d at %s", _target, _lun,
                    291:        [controllerId name]);
                    292:     [self setLocation: location];
                    293:     IOLog("%s: %s\n", deviceName, driveType);
                    294: 
                    295: 
                    296:     /*
                    297:      * Do another Test Unit Ready to clear a possible Unit Attention
                    298:      * condition.  We don't care about the result.
                    299:      */
                    300:     [self stTestReady];
                    301: 
                    302:     /*
                    303:      * Init to variable blk size.
                    304:      */
                    305:     [self setBlockSize: 0];
                    306: 
                    307:     /*
                    308:      * Store the major number in our instance.
                    309:      */
                    310:     _majorDevNum = major;
                    311: 
                    312:     [super init];
                    313:     _isInitialized = YES;
                    314:     return(STR_GOOD);
                    315: } /* - initSCSITape: */
                    316: 
                    317: 
                    318: - free
                    319: {
                    320:     if (_senseDataPtr)
                    321:        IOFree (_senseDataPtr, sizeof (struct esense_reply));
                    322:     if (_devLock)
                    323:        [_devLock free];
                    324:     if (_reservedTargetLun)
                    325:        [_controller releaseTarget: _target lun: _lun forOwner: _controller];
                    326:     return [super free];
                    327: }
                    328: 
                    329: 
                    330: - (IOReturn) getIntValues: (unsigned int *)values
                    331:     forParameter: (IOParameterName) parameter
                    332:     count: (unsigned int *) count
                    333: {
                    334:     int maxCount = *count;
                    335: 
                    336:     if(maxCount == 0) {
                    337:         maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
                    338:     }
                    339: 
                    340:     if(strcmp(parameter, "IOMajorDevice") == 0) {
                    341:        values [0] = [self majorDevNum];
                    342:        *count = 1;       
                    343:        return IO_R_SUCCESS;
                    344:     }
                    345: 
                    346:     if (strcmp(parameter, "Unit") == 0) {
                    347:        values [0] = [self unit];
                    348:        *count = 1;       
                    349:         return IO_R_SUCCESS;
                    350: 
                    351:     }
                    352:         
                    353:     return [super getIntValues:values 
                    354:        forParameter:parameter
                    355:        count:&maxCount];
                    356: }
                    357: 
                    358: 
                    359: 
                    360: /*
                    361:  * Gets and sets for instance variables.
                    362:  */
                    363: 
                    364: - (int) target                 /* Set only during initialization */
                    365: {
                    366:     return (int) _target;
                    367: }
                    368: 
                    369: - (int) lun                    /* Set only during initialization */
                    370: {
                    371:     return (int) _lun;
                    372: }
                    373: 
                    374: - controller                   /* Set only during initialization */
                    375: {
                    376:     return _controller;
                    377: }
                    378: 
                    379: - (BOOL) isInitialized         /* Object has been initialized */
                    380: {
                    381:     return _isInitialized;
                    382: }
                    383: 
                    384: - (BOOL) didWrite              /* Last command was a write */
                    385: {
                    386:     return _didWrite;
                    387: }
                    388: 
                    389: - (BOOL) isFixedBlock
                    390: {
                    391:     if (_blockSize) {          /* Zero blocksize means variable block size */
                    392:        return YES;
                    393:     } else {
                    394:        return NO;
                    395:     }
                    396: }
                    397: 
                    398: - (BOOL) senseDataValid
                    399: {
                    400:     return _senseDataValid;
                    401: }
                    402: 
                    403: - forceSenseDataInvalid                /* for MTIOCGET and friends */
                    404: {
                    405:     _senseDataValid = NO;
                    406:     return self;
                    407: }
                    408: 
                    409: - (struct esense_reply *) senseDataPtr
                    410: {
                    411:     return _senseDataPtr;
                    412: }
                    413: 
                    414: - (int) blockSize              /* Set only via setBlockSize SCSI operation */
                    415: {
                    416:     return _blockSize;
                    417: }
                    418: 
                    419: - (BOOL) suppressIllegalLength
                    420: {
                    421:     return _suppressIllegalLength;
                    422: }
                    423: 
                    424: - setSuppressIllegalLength: (BOOL) condition
                    425: {
                    426:     _suppressIllegalLength = condition;
                    427:     return self;
                    428: }
                    429: 
                    430: - (BOOL) ignoreCheckCondition
                    431: {
                    432:     return _ignoreCheckCondition;
                    433: }
                    434: 
                    435: - setIgnoreCheckCondition: (BOOL) condition
                    436: {
                    437:     _ignoreCheckCondition = condition;
                    438:     return self;
                    439: }
                    440: 
                    441: - (int) majorDevNum
                    442: {
                    443:     return _majorDevNum;
                    444: }
                    445: 
                    446: - setReservedTargetLun: (BOOL) condition
                    447: {
                    448:     _reservedTargetLun = condition;
                    449:     return self;
                    450: }
                    451: 
                    452: - (BOOL) reservedTargetLun
                    453: {
                    454:     return _reservedTargetLun;
                    455: }
                    456: 
                    457: - (IOReturn) acquireDevice
                    458: {
                    459:     IOReturn           ret = IO_R_INVALID;
                    460: 
                    461:     [_devLock lock];
                    462:     if (_devAcquired == YES) {
                    463:        ret = IO_R_BUSY;
                    464:     } else {
                    465:        _devAcquired = YES;
                    466:        ret = IO_R_SUCCESS;
                    467:     }
                    468:     [_devLock unlock];
                    469:     return ret;
                    470: }
                    471: 
                    472: - (IOReturn) releaseDevice
                    473: {
                    474:     [_devLock lock];
                    475:     _devAcquired = NO;
                    476:     [_devLock unlock];
                    477:     return IO_R_SUCCESS;
                    478: }
                    479: 
                    480: 
                    481: /*
                    482:  * General SCSI commands
                    483:  */
                    484: - (sc_status_t) stInquiry: (inquiry_reply_t *) inquiryReply
                    485: {
                    486:     IOSCSIRequest              scsiReq;
                    487:     cdb_6_t                    *cdbp = &scsiReq.cdb.cdb_c6;
                    488:     inquiry_reply_t            *alignedReply;
                    489:     void                       *freePtr;
                    490:     int                        freeCnt;
                    491:     sc_status_t                rtn;
                    492:     IODMAAlignment             dmaAlign;
                    493:        
                    494:        
                    495:     /*
                    496:      * Get some well-aligned memory.
                    497:      */
                    498:     alignedReply = [_controller
                    499:        allocateBufferOfLength: sizeof(inquiry_reply_t)
                    500:        actualStart:&freePtr
                    501:        actualLength:&freeCnt];
                    502:     bzero(alignedReply, sizeof(inquiry_reply_t));
                    503:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    504:     scsiReq.target = _target;
                    505:     scsiReq.lun = _lun;
                    506:     scsiReq.read = YES;
                    507:        
                    508:     /*
                    509:      * Get appropriate alignment from controller. 
                    510:      */
                    511:     [_controller getDMAAlignment:&dmaAlign];
                    512:     if(dmaAlign.readLength > 1) {
                    513:        scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t), 
                    514:            dmaAlign.readLength);
                    515:     }
                    516:     else {
                    517:        scsiReq.maxTransfer = sizeof(inquiry_reply_t);
                    518:     }
                    519: 
                    520:     scsiReq.timeoutLength = ST_IOTO_NORM;
                    521:     scsiReq.disconnect = 1;
                    522: 
                    523:     cdbp->c6_opcode = C6OP_INQUIRY;
                    524:     cdbp->c6_lun = _lun;
                    525:     cdbp->c6_len = sizeof(inquiry_reply_t);
                    526:        
                    527:     [self executeRequest: &scsiReq
                    528:        buffer: alignedReply
                    529:        client: IOVmTaskSelf()
                    530:        senseBuf: _senseDataPtr];
                    531: 
                    532:     if(scsiReq.driverStatus == SR_IOST_GOOD) {
                    533:        unsigned required = (char *)(&alignedReply->ir_zero3[0]) - 
                    534:            (char *)(alignedReply);
                    535:        if(scsiReq.bytesTransferred < required) {
                    536:            IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n", 
                    537:                [self name], scsiReq.bytesTransferred);
                    538:            rtn = SR_IOST_HW;
                    539:        }
                    540:        else {
                    541:        /*
                    542:         * Copy data back to caller's struct. Zero the 
                    543:         * portion of alignedReply which did not get valid
                    544:         * data; the last flush out of the DMA pipe could
                    545:         * have written trash to it (and our caller
                    546:         * expects NULL data).
                    547:         */
                    548:            unsigned zeroSize;
                    549:                        
                    550:            zeroSize = sizeof(*alignedReply) - scsiReq.bytesTransferred;
                    551:            if(zeroSize) {
                    552:                bzero((char *)alignedReply + scsiReq.bytesTransferred,
                    553:                    zeroSize);
                    554:            }
                    555:            *inquiryReply = *alignedReply;
                    556:            rtn = scsiReq.driverStatus;
                    557:        }
                    558:     }
                    559:     else {
                    560:        rtn = scsiReq.driverStatus;
                    561:     }
                    562: 
                    563:     IOFree(freePtr, freeCnt);
                    564:     return rtn;
                    565: } /* - stInquiry: */
                    566: 
                    567: 
                    568: 
                    569: - (BOOL) stTestReady
                    570: {
                    571:     IOSCSIRequest      scsiReq;
                    572:     cdb_6_t            *cdbp = &scsiReq.cdb.cdb_c6;
                    573:     BOOL               rtn;
                    574:        
                    575:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    576:     scsiReq.target = _target;
                    577:     scsiReq.lun = _lun;
                    578:     scsiReq.timeoutLength = ST_IOTO_NORM;
                    579:     scsiReq.disconnect = 1;
                    580:        
                    581:     cdbp->c6_opcode = C6OP_TESTRDY;
                    582:     cdbp->c6_lun = _lun;
                    583: 
                    584:     [self executeRequest: &scsiReq
                    585:        buffer: (void *) NULL
                    586:        client: IOVmTaskSelf()
                    587:        senseBuf: _senseDataPtr];
                    588: 
                    589:     /*
                    590:      * XXX Do we need to distinguish not ready from no tape?
                    591:      */
                    592:     switch(scsiReq.driverStatus) {
                    593:        case SR_IOST_GOOD:
                    594:            rtn = YES;
                    595:            break;
                    596:        default:
                    597:            rtn = NO;
                    598:            break;              
                    599:     }
                    600: 
                    601:     return rtn;
                    602: } /* - stTestReady: */
                    603: 
                    604: 
                    605: 
                    606: - (sc_status_t) stCloseFile
                    607: {
                    608:     IOSCSIRequest              scsiReq;
                    609:     cdb_6s_t                   *cdbp = &scsiReq.cdb.cdb_c6s;
                    610:        
                    611:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    612:     scsiReq.target = _target;
                    613:     scsiReq.lun = _lun;
                    614:     scsiReq.timeoutLength = ST_IOTO_NORM;
                    615:     scsiReq.disconnect = 1;
                    616:     cdbp->c6s_opcode = C6OP_WRTFM;
                    617:     assign_cdb_c6s_len (cdbp, 1);              /* one file mark */
                    618:     
                    619:     return [self executeRequest: &scsiReq
                    620:        buffer: NULL
                    621:        client: IOVmTaskSelf()
                    622:        senseBuf: _senseDataPtr];
                    623: } /* - stCloseFile */
                    624: 
                    625: 
                    626: - (sc_status_t) stRewind
                    627: {
                    628:     IOSCSIRequest              scsiReq;
                    629:     cdb_6s_t                   *cdbp = &scsiReq.cdb.cdb_c6s;
                    630:        
                    631:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    632:     scsiReq.target = _target;
                    633:     scsiReq.lun = _lun;
                    634:     scsiReq.timeoutLength = ST_IOTO_RWD;
                    635:     scsiReq.disconnect = 1;
                    636:     cdbp->c6s_opcode = C6OP_REWIND;
                    637:     
                    638:     return [self executeRequest: &scsiReq
                    639:        buffer: NULL
                    640:        client: IOVmTaskSelf()
                    641:        senseBuf: _senseDataPtr];
                    642: } /* - stRewind */
                    643: 
                    644: 
                    645: /*
                    646:  * Get sense data. senseBuf does not have to be well aligned.
                    647:  */
                    648: - (sc_status_t) requestSense: (esense_reply_t *)senseBuf
                    649: {
                    650:     IOSCSIRequest      scsiReq;
                    651:     cdb_6_t            *cdbp = &scsiReq.cdb.cdb_c6;
                    652:     esense_reply_t     *alignedBuf;
                    653:     void               *freePtr;
                    654:     int                freeCnt;
                    655:     sc_status_t        rtn;
                    656:     IODMAAlignment     dmaAlign;
                    657:        
                    658:     alignedBuf = [_controller allocateBufferOfLength: sizeof(esense_reply_t)
                    659:        actualStart: &freePtr
                    660:        actualLength: &freeCnt];
                    661:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    662:     [_controller getDMAAlignment:&dmaAlign];
                    663: 
                    664:     scsiReq.target             = _target;
                    665:     scsiReq.lun                = _lun;
                    666:     scsiReq.read               = YES;
                    667: 
                    668:     if(dmaAlign.readLength > 1) {
                    669:        scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), 
                    670:            dmaAlign.readLength);
                    671: 
                    672:     } else {
                    673:        scsiReq.maxTransfer = sizeof(esense_reply_t);
                    674:     }
                    675: 
                    676:     scsiReq.timeoutLength = ST_IOTO_NORM;  // XXX Should be ST_IOTO_SENSE??
                    677:     scsiReq.disconnect = 0;
                    678:     cdbp->c6_opcode = C6OP_REQSENSE;
                    679:     cdbp->c6_lun = _lun;
                    680:     cdbp->c6_len = sizeof(esense_reply_t);
                    681: 
                    682:     rtn = [_controller executeRequest:&scsiReq
                    683:        buffer:alignedBuf
                    684:        client:IOVmTaskSelf()];
                    685:     if(rtn == SR_IOST_GOOD) {
                    686:        *senseBuf = *alignedBuf;
                    687:        _senseDataValid = YES;
                    688:     }
                    689:     IOFree(freePtr, freeCnt);
                    690:     return rtn;
                    691: } /* - requestSense: */
                    692: 
                    693: 
                    694: 
                    695: 
                    696: - (sc_status_t) stModeSelect: (struct modesel_parms *) modeSelectParmsPtr
                    697: {
                    698:     IOSCSIRequest              scsiReq;
                    699:     cdb_6_t                    *cdbp = &scsiReq.cdb.cdb_c6;
                    700:     int                                count = modeSelectParmsPtr->msp_bcount;
                    701:     struct mode_sel_data       *alignedBuf;
                    702:     void                       *freePtr;
                    703:     int                        freeCnt;
                    704:     sc_status_t                rtn;
                    705:     IODMAAlignment             dmaAlign;
                    706:        
                    707:     alignedBuf = [_controller 
                    708:        allocateBufferOfLength: count
                    709:        actualStart: &freePtr
                    710:        actualLength: &freeCnt];
                    711: 
                    712: 
                    713:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    714: 
                    715:     scsiReq.target             = _target;
                    716:     scsiReq.lun                = _lun;
                    717:     scsiReq.read               = NO;
                    718: 
                    719:     [_controller getDMAAlignment:&dmaAlign];
                    720:     if(dmaAlign.readLength > 1) {
                    721:        scsiReq.maxTransfer = IOAlign(int, count, 
                    722:            dmaAlign.readLength);
                    723: 
                    724:     } else {
                    725:        scsiReq.maxTransfer = count;
                    726:     }
                    727: 
                    728:     scsiReq.timeoutLength = ST_IOTO_NORM;
                    729:     scsiReq.disconnect = 1;
                    730:     cdbp->c6_opcode = C6OP_MODESELECT;
                    731:     cdbp->c6_lun = _lun;
                    732:     cdbp->c6_len = count;
                    733: 
                    734:     bcopy (&modeSelectParmsPtr->msp_data, alignedBuf, count);
                    735: 
                    736:     rtn = [self executeRequest:&scsiReq
                    737:        buffer:alignedBuf
                    738:        client:IOVmTaskSelf()
                    739:        senseBuf: _senseDataPtr];
                    740: 
                    741:     IOFree(freePtr, freeCnt);
                    742:     return rtn;
                    743: } /* - stModeSelect: */
                    744: 
                    745: 
                    746: 
                    747: 
                    748: - (sc_status_t) stModeSense: (struct modesel_parms *) modeSenseParmsPtr
                    749: {
                    750:     IOSCSIRequest              scsiReq;
                    751:     cdb_6_t                    *cdbp = &scsiReq.cdb.cdb_c6;
                    752:     int                                count = modeSenseParmsPtr->msp_bcount;
                    753:     struct mode_sel_data       *alignedBuf;
                    754:     void                       *freePtr;
                    755:     int                        freeCnt;
                    756:     sc_status_t                rtn;
                    757:     IODMAAlignment             dmaAlign;
                    758:        
                    759:     alignedBuf = [_controller 
                    760:        allocateBufferOfLength: count
                    761:        actualStart: &freePtr
                    762:        actualLength: &freeCnt];
                    763: 
                    764: 
                    765:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    766: 
                    767:     scsiReq.target             = _target;
                    768:     scsiReq.lun                = _lun;
                    769:     scsiReq.read               = YES;
                    770: 
                    771:     [_controller getDMAAlignment:&dmaAlign];
                    772:     if(dmaAlign.readLength > 1) {
                    773:        scsiReq.maxTransfer = IOAlign(int, count, 
                    774:            dmaAlign.readLength);
                    775: 
                    776:     } else {
                    777:        scsiReq.maxTransfer = count;
                    778:     }
                    779: 
                    780:     scsiReq.timeoutLength = ST_IOTO_NORM;
                    781:     scsiReq.disconnect = 1;
                    782:     cdbp->c6_opcode = C6OP_MODESENSE;
                    783:     cdbp->c6_lun = _lun;
                    784:     cdbp->c6_len = count;
                    785: 
                    786:     rtn = [self executeRequest:&scsiReq
                    787:        buffer:alignedBuf
                    788:        client:IOVmTaskSelf()
                    789:        senseBuf: _senseDataPtr];
                    790: 
                    791:     if(rtn == SR_IOST_GOOD) {
                    792:        bcopy (alignedBuf, &modeSenseParmsPtr->msp_data, count);
                    793:     }
                    794: 
                    795:     IOFree(freePtr, freeCnt);
                    796:     return rtn;
                    797: } /* - stModeSense: */
                    798: 
                    799: 
                    800: 
                    801: - (sc_status_t) executeMTOperation: (struct mtop *) mtopp
                    802: {
                    803:     IOSCSIRequest              scsiReq;
                    804:     cdb_6s_t                   *cdbp = &scsiReq.cdb.cdb_c6s;
                    805:     int                                count;
                    806:     sc_status_t                        rtn;
                    807:        
                    808:     bzero(&scsiReq, sizeof(IOSCSIRequest));
                    809:     scsiReq.target = _target;
                    810:     scsiReq.lun = _lun;
                    811:     scsiReq.timeoutLength = ST_IOTO_NORM;      /* Some ops override this */
                    812:     scsiReq.disconnect = 1;  // XXX - maybe not for all ops.
                    813: 
                    814:     /* 
                    815:      * none of these operations performs DMA. For each, just fill in
                    816:      * the cdb, and pass it to the controller.
                    817:      */
                    818:         
                    819:     /* build a CDB */
                    820:        
                    821:     switch(mtopp->mt_op) {
                    822:        case MTWEOF:            /* write file marks */
                    823:            cdbp->c6s_opcode = C6OP_WRTFM;
                    824:            goto setcount_f;
                    825:                
                    826:        case MTFSF:             /* space file marks forward */
                    827:            cdbp->c6s_opcode = C6OP_SPACE;
                    828:            cdbp->c6s_opt = C6OPT_SPACE_FM;
                    829:            scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
                    830:            goto setcount_f;
                    831:                
                    832:        case MTBSF:             /* space file marks backward */
                    833:            cdbp->c6s_opcode = C6OP_SPACE;
                    834:            cdbp->c6s_opt = C6OPT_SPACE_FM;
                    835:            scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
                    836:            goto setcount_b;
                    837:                
                    838:        case MTFSR:             /* space records forward */
                    839:            cdbp->c6s_opcode = C6OP_SPACE;
                    840:            cdbp->c6s_opt = C6OPT_SPACE_LB;
                    841:            scsiReq.timeoutLength = ST_IOTO_SPR;
                    842: setcount_f:
                    843:            assign_cdb_c6s_len (cdbp, mtopp->mt_count);
                    844:            break;
                    845: 
                    846:        case MTBSR:                     /* space records backward */
                    847:            cdbp->c6s_opcode = C6OP_SPACE;
                    848:            cdbp->c6s_opt = C6OPT_SPACE_LB;
                    849:            scsiReq.timeoutLength = ST_IOTO_SPR;
                    850: setcount_b:
                    851:            count = 0 - mtopp->mt_count;
                    852:            assign_cdb_c6s_len (cdbp, count);
                    853:            break;
                    854:                        
                    855:        case MTREW:                     /* rewind */
                    856:            cdbp->c6s_opcode = C6OP_REWIND;
                    857:            scsiReq.timeoutLength = ST_IOTO_RWD;
                    858:            break;
                    859:                
                    860:        case MTOFFL:                    /* set offline */
                    861:            cdbp->c6s_opcode = C6OP_STARTSTOP;
                    862:                                        /* note load bit is 0 */
                    863:            scsiReq.timeoutLength = ST_IOTO_RWD;
                    864:            break;
                    865:                
                    866:        case MTNOP:             /* nop / get status */
                    867:        case MTCACHE:           /* enable cache */
                    868:        case MTNOCACHE:         /* disable cache */
                    869:        case MTRETEN:
                    870:        case MTERASE:
                    871:        default:
                    872:            rtn = SR_IOST_CMDREJ;       /* FIXME: unsupported? */
                    873:            goto out;
                    874:     }
                    875: 
                    876:     rtn = [self executeRequest: &scsiReq
                    877:        buffer: NULL
                    878:        client: IOVmTaskSelf()
                    879:        senseBuf: _senseDataPtr];   
                    880: out:
                    881:     return rtn;
                    882: } /* - executeMTOperation: */
                    883: 
                    884:        
                    885: 
                    886: /*
                    887:  * Set block size for SCSI tape device.   
                    888:  *
                    889:  * blocksize == 0 --> variable
                    890:  * blocksize != 0 --> fixed @ blocksize
                    891:  *
                    892:  * First, execute mode sense, then mode select with block length
                    893:  * set to 0 (variable) or blocksize (fixed)
                    894:  */
                    895: - (IOReturn) setBlockSize: (int) blockSize
                    896: {
                    897:     int                                rtn;
                    898:     struct modesel_parms       *mspp;
                    899:     struct mode_sel_hdr                *mshp;
                    900: 
                    901:     mspp = IOMalloc (sizeof(struct modesel_parms));
                    902:     mspp->msp_bcount = sizeof(struct mode_sel_hdr) + 
                    903:        sizeof(struct mode_sel_bd);
                    904: 
                    905:     if((rtn = [self stModeSense: mspp]) != SR_IOST_GOOD) {
                    906:        IOFree (mspp, sizeof (struct modesel_parms));
                    907:        return [_controller returnFromScStatus: rtn];
                    908:     }
                    909: 
                    910:     mshp = &mspp->msp_data.msd_header; 
                    911:     mshp->msh_sd_length_0 = 0;
                    912:     mshp-> msh_med_type = 0;
                    913:     mshp-> msh_wp = 0;
                    914:     mshp-> msh_bd_length = sizeof(struct mode_sel_bd);
                    915:     assign_msbd_blocklength 
                    916:        (&mspp->msp_data.msd_blockdescript, blockSize);
                    917:     assign_msbd_numblocks
                    918:        (&mspp->msp_data.msd_blockdescript, 0);
                    919: 
                    920:     if((rtn = [self stModeSelect: mspp]) != SR_IOST_GOOD) {
                    921:        IOFree (mspp, sizeof (struct modesel_parms));
                    922:        return [_controller returnFromScStatus: rtn];
                    923:     }
                    924: 
                    925:     _blockSize = blockSize;
                    926: 
                    927:     IOFree (mspp, sizeof (struct modesel_parms));
                    928:     return IO_R_SUCCESS;
                    929: } /* - setBlockSize: */
                    930: 
                    931: 
                    932: 
                    933: 
                    934: /*
                    935:  * Execute CDB.   Buffer must be well aligned.   If command results 
                    936:  * in Check Status, return the sense data in *senseBuf.
                    937:  */
                    938: - (sc_status_t) executeRequest: (IOSCSIRequest *)scsiReq
                    939:     buffer:(void *) buffer /* data destination */
                    940:     client:(vm_task_t) client
                    941:     senseBuf:(esense_reply_t *) senseBuf
                    942: {
                    943:     sc_status_t                        rtn;
                    944: 
                    945:     _senseDataValid = NO;
                    946: 
                    947: #ifdef DEBUG
                    948: IOLog("Entered SCSI Tape executeRequest: op %s, maxTransfer %d, len %d\n",
                    949:     IOFindNameForValue(scsiReq->cdb.cdb_opcode,
                    950:        IOSCSIOpcodeStrings),
                    951:     scsiReq->maxTransfer,
                    952:     (scsiReq->cdb.cdb_c6s.c6s_len2 << 16) | 
                    953:        (scsiReq->cdb.cdb_c6s.c6s_len1 << 8) |
                    954:        (scsiReq->cdb.cdb_c6s.c6s_len0));
                    955: #endif DEBUG
                    956: 
                    957:     rtn = [_controller executeRequest:scsiReq
                    958:        buffer:buffer
                    959:        client:client];
                    960: 
                    961: #ifdef DEBUG
                    962: IOLog ("Length %d on return from executeRequest\n", scsiReq->bytesTransferred);
                    963: #endif DEBUG
                    964: 
                    965:     /*
                    966:      * Log error returns.
                    967:      */
                    968:     if (rtn != SR_IOST_GOOD) {
                    969:        /*
                    970:         * If result is Check Condition, do a Request Sense, unless suppressed.
                    971:         */
                    972:        if(rtn == SR_IOST_CHKSV) {
                    973:                /* 
                    974:                 * Host Adaptor already got us sense data. Give sense data
                    975:                 * to user and save it.
                    976:                 */
                    977:                *senseBuf = *_senseDataPtr = scsiReq->senseData;
                    978:                _senseDataValid = YES;
                    979:        }
                    980:        if (((rtn == SR_IOST_CHKSNV) || (rtn == SR_IOST_CHKSV)) &&
                    981:                !_ignoreCheckCondition) {
                    982:            if(rtn == SR_IOST_CHKSV) {
                    983:                rtn = SR_IOST_GOOD;
                    984:            }
                    985:            else {
                    986:                rtn = [self requestSense: senseBuf];
                    987:            }
                    988:            if(rtn == SR_IOST_GOOD) {
                    989:                /*
                    990:                 * If the error is a filemark, and we are reading,
                    991:                 * then return no error.   Otherwise, return
                    992:                 * check sense, with valid sense data.
                    993:                 */
                    994:                if ((scsiReq->cdb.cdb_c6.c6_opcode == C6OP_READ) &&
                    995:                    (senseBuf->er_filemark)) {
                    996: 
                    997:                    /*
                    998:                     * Check for correct reporting of bytes transferred.
                    999:                     * (This works around a DPT firmware bug.)
                   1000:                     */
                   1001:                    int transferLength = 
                   1002:                        cdb_c6s_len_value (&scsiReq->cdb.cdb_c6s) -
                   1003:                        er_info_value (senseBuf);
                   1004: 
                   1005:                    if ([self isFixedBlock]) {
                   1006:                        transferLength = transferLength * _blockSize;
                   1007:                    }
                   1008:                                        
                   1009:                    if (scsiReq->bytesTransferred != transferLength) {
                   1010: #ifdef DEBUG
                   1011: IOLog ("%s: Incorrect byte count reported - "
                   1012:     "corrected to %d\n", [self name], transferLength);
                   1013: #endif DEBUG
                   1014:                        scsiReq->bytesTransferred = transferLength;
                   1015:                    }
                   1016: 
                   1017:                    rtn = SR_IOST_GOOD;
                   1018:                    scsiReq->driverStatus = SR_IOST_GOOD;
                   1019: 
                   1020: #ifdef DEBUG
                   1021: IOLog ("execReq sense: er_filemark %d, er_badlen %d, er_sensekey %d, er_addsensecode %d, er_qualifier %d, er_info %d\n", 
                   1022:        senseBuf->er_filemark, senseBuf->er_badlen, senseBuf->er_sensekey,
                   1023:        senseBuf->er_addsensecode, senseBuf->er_qualifier,
                   1024:        er_info_value (senseBuf));
                   1025: #endif DEBUG
                   1026: 
                   1027:                }
                   1028:                else {
                   1029:                    rtn = SR_IOST_CHKSV;
                   1030:                }
                   1031:            }
                   1032:            else {
                   1033:                if (_isInitialized) {
                   1034:                    IOLog("%s: Request Sense on target %d lun %d "
                   1035:                        "failed (%s)\n",
                   1036:                        [self name], _target, _lun, 
                   1037:                        IOFindNameForValue(rtn, IOScStatusStrings));
                   1038:                }
                   1039:                rtn = SR_IOST_CHKSNV;
                   1040:            }
                   1041:        }
                   1042: 
                   1043:        /*
                   1044:         * Log error messages, except the spate of timeouts and
                   1045:         * device not ready messages during initialization.
                   1046:         */
                   1047:        if (_isInitialized &&
                   1048:            (rtn != SR_IOST_GOOD) &&
                   1049:            !_ignoreCheckCondition) {
                   1050: 
                   1051:            IOLog("%s, target %d, lun %d: op %s returned %s\n",
                   1052:                [self name], _target, _lun,
                   1053:                IOFindNameForValue(scsiReq->cdb.cdb_opcode,
                   1054:                    IOSCSIOpcodeStrings),
                   1055:                IOFindNameForValue(rtn, IOScStatusStrings));
                   1056: 
                   1057:            if (rtn == SR_IOST_CHKSV) {
                   1058:                IOLog ("    Sense key = 0x%x  Sense Code = 0x%x\n",
                   1059:                    senseBuf->er_sensekey, senseBuf->er_addsensecode);
                   1060:            }
                   1061:        }
                   1062: 
                   1063:        _didWrite = NO;
                   1064:     }
                   1065: 
                   1066:     else {
                   1067:        /* Remember good writes for device close */
                   1068:        if (scsiReq->cdb.cdb_opcode == C6OP_WRITE) {
                   1069:            _didWrite = YES;
                   1070:        } else {
                   1071:            _didWrite = NO;
                   1072:        }
                   1073:     }
                   1074: 
                   1075:     return rtn;
                   1076: } /* executeRequest: */                           
                   1077:                          
                   1078: @end
                   1079: 
                   1080: /*
                   1081:  * Supporting functions.
                   1082:  */
                   1083: 
                   1084: /*
                   1085:  * moveString is taken directly from SCSIDiskPrivate.m.    
                   1086:  * It's used by -initSCSITape:
                   1087:  *
                   1088:  * Copy inp to outp for up to inlength input characters or outlength output
                   1089:  * characters. Compress multiple spaces and eliminate nulls. Returns number
                   1090:  * of characters copied to outp.
                   1091:  */
                   1092: static int 
                   1093: moveString(char *inp, char *outp, int inlength, int outlength)
                   1094: {
                   1095:     int lastCharSpace = 0;
                   1096:     char *outpStart = outp;
                   1097: 
                   1098:     while(inlength && outlength) {
                   1099:        switch(*inp) {
                   1100:            case '\0':
                   1101:                inp++;
                   1102:                inlength--;
                   1103:                continue;
                   1104:            case ' ':
                   1105:                if(lastCharSpace) {
                   1106:                    inp++;
                   1107:                    inlength--;
                   1108:                    continue;
                   1109:                }
                   1110:                lastCharSpace = 1;
                   1111:                goto copyit;
                   1112:            default:
                   1113:                lastCharSpace = 0;
                   1114: copyit:
                   1115:                *outp++ = *inp++;
                   1116:                inlength--;
                   1117:                outlength--;
                   1118:                break;
                   1119:            }
                   1120:     }
                   1121:     return(outp - outpStart);
                   1122: }
                   1123: 
                   1124: 
                   1125: 
                   1126: void
                   1127: assign_cdb_c6s_len (struct cdb_6s *cdbp, int length)
                   1128: {
                   1129: #if    __BIG_ENDIAN__
                   1130: #if    __NATURAL_ALIGNMENT__
                   1131:     cdbp->c6s_len[0] = (length >> 16) & 0xff;
                   1132:     cdbp->c6s_len[1] = (length >> 8) & 0xff;
                   1133:     cdbp->c6s_len[2] = length & 0xff;
                   1134: 
                   1135: #else  __NATURAL_ALIGNMENT__
                   1136: 
                   1137:     cdbp->c6s_len = length;
                   1138: 
                   1139: #endif __NATURAL_ALIGNMENT__
                   1140: 
                   1141: 
                   1142: #elif  __LITTLE_ENDIAN__
                   1143: 
                   1144:     cdbp->c6s_len0 = (u_char) length & 0xff;
                   1145:     cdbp->c6s_len1 = (u_char) (length >> 8) & 0xff;
                   1146:     cdbp->c6s_len2 = (u_char) (length >> 16) & 0xff;
                   1147: 
                   1148: #endif
                   1149: 
                   1150:     return;
                   1151: }
                   1152: 
                   1153: void
                   1154: assign_msbd_numblocks (struct mode_sel_bd *msbdp, int numblocks)
                   1155: {
                   1156: #if    __BIG_ENDIAN__
                   1157:     msbdp->msbd_numblocks = numblocks;
                   1158: #elif  __LITTLE_ENDIAN__
                   1159:     msbdp->msbd_numblocks0 = (u_char) numblocks & 0xff;
                   1160:     msbdp->msbd_numblocks1 = (u_char) (numblocks >> 8) & 0xff;
                   1161:     msbdp->msbd_numblocks2 = (u_char) (numblocks >> 16) & 0xff;
                   1162: #endif
                   1163:     return;
                   1164: }
                   1165: 
                   1166: void
                   1167: assign_msbd_blocklength (struct mode_sel_bd *msbdp, int length)
                   1168: {
                   1169: #if    __BIG_ENDIAN__
                   1170:     msbdp->msbd_blocklength = length;
                   1171: #elif  __LITTLE_ENDIAN__
                   1172:     msbdp->msbd_blocklength0 = (u_char) length & 0xff;
                   1173:     msbdp->msbd_blocklength1 = (u_char) (length >> 8) & 0xff;
                   1174:     msbdp->msbd_blocklength2 = (u_char) (length >> 16) & 0xff;
                   1175: #endif
                   1176:     return;
                   1177: }
                   1178: 
                   1179: int
                   1180: cdb_c6s_len_value (struct cdb_6s *cdbp)
                   1181: {
                   1182: #if    __BIG_ENDIAN__
                   1183:     return (cdbp->c6s_len);
                   1184: #elif  __LITTLE_ENDIAN__
                   1185:     return (cdbp->c6s_len0 | (cdbp->c6s_len1 << 8) | (cdbp->c6s_len2 << 16));
                   1186: #endif
                   1187: }
                   1188: 
                   1189: int
                   1190: er_info_value (struct esense_reply *esrp)
                   1191: {
                   1192: #if    __BIG_ENDIAN__
                   1193:     return (esrp->er_info);
                   1194: #elif  __LITTLE_ENDIAN__
                   1195:     return (esrp->er_info0 | (esrp->er_info1 << 8) |
                   1196:        (esrp->er_info2 << 16) | (esrp->er_info3 << 24));
                   1197: #endif
                   1198: }
                   1199:     

unix.superglobalmegacorp.com

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