Annotation of drvEIDE/EIDE.drvproj/EIDE.lksproj/AtapiCnt.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.0 (the 'License').  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License."
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*
        !            25:  * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved.
        !            26:  * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
        !            27:  *
        !            28:  * AtapiCnt.m - Implementation of ATAPI controller class.
        !            29:  *
        !            30:  * HISTORY
        !            31:  *
        !            32:  * 4-Jan-1998  Joe Liu at Apple
        !            33:  *     Modified the ATAPI to SCSI translation routines.
        !            34:  *
        !            35:  * 31-Aug-1994         Rakesh Dubey at NeXT 
        !            36:  *     Created. 
        !            37:  */
        !            38: 
        !            39: //#define DEBUG
        !            40: //#define COMMAND_HISTORY
        !            41: //#define COMMAND_PRINT   
        !            42: 
        !            43: #import "IdeCnt.h"
        !            44: #import "AtapiCnt.h"
        !            45: #import "AtapiCntInternal.h"
        !            46: #import <kern/assert.h>
        !            47: #import <driverkit/kernelDriver.h>
        !            48: #import <driverkit/interruptMsg.h>
        !            49: #import <mach/mach_interface.h>
        !            50: #import <driverkit/IODevice.h>
        !            51: #import <driverkit/align.h>
        !            52: #import <machkit/NXLock.h>
        !            53: #import <machdep/i386/io_inline.h>
        !            54: #import <bsd/dev/scsireg.h>
        !            55: 
        !            56: /*
        !            57:  * opcode groups
        !            58:  */
        !            59: #define        SCSI_OPGROUP(opcode)    ((opcode) & 0xe0)
        !            60: 
        !            61: #define        OPGROUP_0               0x00    /* six byte commands */
        !            62: #define        OPGROUP_1               0x20    /* ten byte commands */
        !            63: #define        OPGROUP_2               0x40    /* ten byte commands */
        !            64: #define        OPGROUP_5               0xa0    /* twelve byte commands */
        !            65: #define        OPGROUP_6               0xc0    /* six byte, vendor unique commands */
        !            66: #define        OPGROUP_7               0xe0    /* ten byte, vendor unique commands */
        !            67: 
        !            68: #ifdef undef
        !            69: static void testDebug(id driver);
        !            70: #endif undef
        !            71: 
        !            72: /*
        !            73:  * List of SCSI commands that do not have a counterpart in ATAPI
        !            74:  * implementation, or commands which have different command structure.
        !            75:  * These commands will need to be specially handled. 
        !            76:  */
        !            77: #define C10OP_MODESELECT 0x55
        !            78: 
        !            79: static unsigned char mapToAtapi[] = {
        !            80:     C6OP_MODESELECT,
        !            81:        C10OP_MODESELECT, 
        !            82:     C6OP_MODESENSE
        !            83: };
        !            84: 
        !            85: /*
        !            86:  * List of controllers that have been already probed. We need this since each
        !            87:  * Instance table lists IdeDisk as well as IdeController classes. And we need
        !            88:  * to create instances of disks attached to each controller only once. 
        !            89:  */
        !            90: static int probedControllerCount = 0;
        !            91: static id probedControllers[MAX_IDE_CONTROLLERS];
        !            92: 
        !            93: @implementation AtapiController
        !            94: 
        !            95: + (BOOL)probe : deviceDescription
        !            96: {
        !            97: 
        !            98:     int unit, i;
        !            99:     id direct;
        !           100:     id atapiCnt;
        !           101: 
        !           102: 
        !           103:        direct = [deviceDescription directDevice];
        !           104: 
        !           105: 
        !           106: #ifdef undef
        !           107:     IOLog("AtapiController probed with direct device %x\n", direct);
        !           108: #endif undef
        !           109:     
        !           110:     for (i = 0; i < probedControllerCount; i++)        {
        !           111:        if (probedControllers[i] == direct)     {
        !           112:                {
        !           113: #ifdef undef
        !           114:                        IOLog("AtapiController already probed for controller %x\n", 
        !           115:                        direct);
        !           116: #endif undef
        !           117:                return YES;
        !           118:                }
        !           119:        }
        !           120:     }
        !           121:     
        !           122:     probedControllers[probedControllerCount++] = direct;
        !           123: 
        !           124:     for (unit = 0; unit < [direct numDevices]; unit++) {
        !           125:     
        !           126:        if ([direct isAtapiDevice:unit]) {
        !           127:            atapiCnt = [[self alloc] 
        !           128:                initFromDeviceDescription:deviceDescription];
        !           129:            
        !           130:            if (atapiCnt == nil) {
        !           131:                        IOLog("ATAPI: failed to probe device %d.\n", unit);
        !           132:                        continue;
        !           133:            }
        !           134: 
        !           135: #ifdef undef
        !           136:                IOLog("ATAPI: found ATAPI device %d.\n", unit);
        !           137: #endif undef
        !           138: 
        !           139:            if ([atapiCnt initResources:direct] == nil) {
        !           140:                        IOLog("ATAPI: failed to initialize device %d.\n", unit);
        !           141:                [atapiCnt free];
        !           142:                        continue;
        !           143:                }
        !           144: 
        !           145:            /*
        !           146:             * To clear pending Unit attention. Not needed.
        !           147:             */
        !           148:            //[direct atapiRequestSense:NULL];
        !           149: 
        !           150:            /*
        !           151:             * Use this to test before we call registerDevice. 
        !           152:             */
        !           153:            //testDebug(direct);
        !           154:                    
        !           155:            if ([atapiCnt registerDevice] == nil) {
        !           156:                        IOLog("ATAPI: failed to register device %d.\n", unit);
        !           157:                        [atapiCnt free];
        !           158:                        continue;
        !           159:            } else {
        !           160:                        return YES;
        !           161:                }
        !           162:        }
        !           163:     }  
        !           164: 
        !           165:     return NO;
        !           166: }
        !           167: 
        !           168: /*
        !           169:  * We override IOSCSIController to make ourself look like an indirect device
        !           170:  * in order to get connected to IdeController.
        !           171:  */
        !           172: + (IODeviceStyle)deviceStyle
        !           173: {
        !           174:     return IO_IndirectDevice;
        !           175: }
        !           176: 
        !           177: /*
        !           178:  * The protocol we need as an indirect device.
        !           179:  */
        !           180: static Protocol *protocols[] = {
        !           181:     @protocol(AtapiControllerPublic),
        !           182:     nil
        !           183: };
        !           184: 
        !           185: + (Protocol **)requiredProtocols
        !           186: {
        !           187:     return protocols;
        !           188: }
        !           189: 
        !           190: - (unsigned short)scsiCmdLen:(IOSCSIRequest *) scsiReq
        !           191: {
        !           192:     unsigned char cmdlen;
        !           193:     union cdb *cdbp = &scsiReq->cdb;
        !           194: 
        !           195:     switch (SCSI_OPGROUP(cdbp->cdb_opcode)) {
        !           196: 
        !           197:       case OPGROUP_0:
        !           198:        cmdlen = sizeof(struct cdb_6);
        !           199:        break;
        !           200: 
        !           201:       case OPGROUP_1:
        !           202:       case OPGROUP_2:
        !           203:        cmdlen = sizeof(struct cdb_10);
        !           204:        break;
        !           205: 
        !           206:       case OPGROUP_5:
        !           207:        cmdlen = sizeof(struct cdb_12);
        !           208:        break;
        !           209: 
        !           210:       case OPGROUP_6:
        !           211:        if (scsiReq->cdbLength)
        !           212:            cmdlen = scsiReq->cdbLength;
        !           213:        else
        !           214:            cmdlen = sizeof(struct cdb_6);
        !           215:        break;
        !           216: 
        !           217:       case OPGROUP_7:
        !           218:        if (scsiReq->cdbLength)
        !           219:            cmdlen = scsiReq->cdbLength;
        !           220:        else
        !           221:            cmdlen = sizeof(struct cdb_10);
        !           222:        break;
        !           223: 
        !           224:       default:
        !           225:        scsiReq->driverStatus = SR_IOST_CMDREJ;
        !           226:        return 0;
        !           227:     }
        !           228:     
        !           229:     return cmdlen;
        !           230: }
        !           231: 
        !           232: #define        C10OP_MODESELECT        0x55    /* OPT: set device parameters */
        !           233: #define        C10OP_MODESENSE         0x5a    /* OPT: get device parameters */
        !           234: #define C10OP_READCAPACITY     0x25    /* read capacity */
        !           235: 
        !           236: /*
        !           237:  * This will enable us to print last 32 commands in case of an error. The
        !           238:  * command that caused the error is printed last. 
        !           239:  */
        !           240: #ifdef COMMAND_HISTORY
        !           241: #define MAXCMDS 32
        !           242: static atapiIoReq_t cmdBuf[MAXCMDS];
        !           243: static unsigned int cmdPos = 0;
        !           244: static unsigned int cmdsInBuf = 0;
        !           245: #endif COMMAND_HISTORY
        !           246: 
        !           247: /*
        !           248:  * Do a SCSI command, as specified by an IOSCSIRequest.
        !           249:  */
        !           250: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq 
        !           251:                    buffer : (void *)buffer 
        !           252:                    client : (vm_task_t)client
        !           253: {
        !           254:     int i;
        !           255:     atapiIoReq_t atapiIoReq;
        !           256:     atapiBuf_t *atapiBuf;
        !           257:     unsigned char *scsiCmd;
        !           258:     cdb_t my_cdb;
        !           259:     sc_status_t ret;
        !           260:     IOReturn driverStatus;
        !           261:        BOOL cmdMapped = NO;
        !           262:    
        !           263:        [_ataController atapiCntrlrLock];
        !           264:     
        !           265:     my_cdb = scsiReq->cdb;
        !           266: 
        !           267: #ifdef DEBUG
        !           268:      if ((scsiReq->lun == 0) && (scsiReq->target < 2))         {
        !           269:        IOLog("%s: executeRequest %x target %x lun %x Read %d\n", 
        !           270:            [self name], my_cdb.cdb_opcode, scsiReq->target, scsiReq->lun,
        !           271:            scsiReq->read);
        !           272:     }
        !           273: #endif DEBUG
        !           274:     
        !           275:     bzero(&atapiIoReq, sizeof(atapiIoReq_t));
        !           276:     
        !           277:     atapiIoReq.cmdLen = [_ataController 
        !           278:                atapiCommandPacketSize:scsiReq->target];
        !           279:        
        !           280:     atapiIoReq.read        = scsiReq->read;
        !           281:     atapiIoReq.maxTransfer = scsiReq->maxTransfer;
        !           282:     atapiIoReq.drive       = scsiReq->target;
        !           283:     atapiIoReq.lun         = scsiReq->lun;
        !           284:        atapiIoReq.timeout     = scsiReq->timeoutLength * 1000; // sec to ms
        !           285:     
        !           286:        // IOLog("max: %d\n", atapiIoReq.maxTransfer);
        !           287:        
        !           288:     scsiCmd = (unsigned char *) &(my_cdb.cdb_opcode);
        !           289:        atapiIoReq.scsiCmd = *scsiCmd;
        !           290: 
        !           291:     for (i = 0; i < [self scsiCmdLen:scsiReq]; i++)    {
        !           292:        atapiIoReq.atapiCmd[i] = *scsiCmd;
        !           293:                scsiCmd++;
        !           294:     }
        !           295: 
        !           296:     /*
        !           297:      * Use this to print SCSI commands being sent to ATA object. 
        !           298:      */
        !           299: 
        !           300: #ifdef COMMAND_PRINT
        !           301:     if ((atapiIoReq.atapiCmd[0] == 0x28) && (atapiIoReq.lun == 0))     {
        !           302:         IOLog("%s: Command 0x28.\n", [self name]);
        !           303:        for (i = 0; i < [self scsiCmdLen:scsiReq]; i+=2)        {
        !           304:            IOLog("%s: %02x %02x\n", [self name], 
        !           305:                atapiIoReq.atapiCmd[i],  atapiIoReq.atapiCmd[i+1]);
        !           306:        }
        !           307:        
        !           308:     }
        !           309:     if ((atapiIoReq.atapiCmd[0] == 0x15) && (atapiIoReq.lun == 0))     {
        !           310:         unsigned char *tmp = (unsigned char *)buffer;
        !           311:         IOLog("%s: Command 0x15 data.\n", [self name]);
        !           312:        for (i = 0; i < 0x1c; i+=2)     {
        !           313:            IOLog("%s: %02x %02x\n", [self name], 
        !           314:                tmp[i], tmp[i+1]);
        !           315:        }
        !           316:     }
        !           317: #endif COMMAND_PRINT
        !           318:        
        !           319: #ifdef COMMAND_HISTORY
        !           320:     /* Keep history */
        !           321:     cmdBuf[cmdPos++] = atapiIoReq;
        !           322:     if (cmdsInBuf < MAXCMDS)
        !           323:        cmdsInBuf += 1;
        !           324:     if (cmdPos == MAXCMDS)
        !           325:        cmdPos = 0;
        !           326: #endif COMMAND_HISTORY
        !           327: 
        !           328:     /*
        !           329:      * Map to available ATAPI command if necessary.
        !           330:      */
        !           331:     for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++) {
        !           332:        if (atapiIoReq.atapiCmd[0] == mapToAtapi[i]) {
        !           333:                        //IOLog("%s: Mapping to SCSI command\n", [self name]);
        !           334:                        bzero((void *)&modeData, sizeof(modeData));
        !           335:                        if ([self maptoAtapiCmd: &atapiIoReq buffer:buffer
        !           336:                                newBuffer:&modeData] == NO)     {
        !           337:                                [_ataController atapiCntrlrUnLock];
        !           338:                                return SR_IOST_CMDREJ;
        !           339:                        }
        !           340:                        cmdMapped = YES;
        !           341:                        break;
        !           342:                }
        !           343:     }
        !           344:        
        !           345:     /*
        !           346:      * If emulation is successful then return quickly. 
        !           347:      */
        !           348:     if ([self emulateSCSICmd: &atapiIoReq buffer:buffer] == YES) {
        !           349:                [_ataController atapiCntrlrUnLock];
        !           350:                return SR_IOST_GOOD;
        !           351:     }
        !           352: 
        !           353:     /*
        !           354:      * Send the command to the ioThread. 
        !           355:      */
        !           356:     atapiBuf = [self allocAtapiBuf];
        !           357:     atapiBuf->atapiIoReq = &atapiIoReq;
        !           358:        if (cmdMapped) {
        !           359:                atapiBuf->buffer = (void *)&modeData;
        !           360:                atapiBuf->client = IOVmTaskSelf();
        !           361:        }
        !           362:        else {
        !           363:                atapiBuf->buffer = buffer;
        !           364:                atapiBuf->client = client;
        !           365:        }
        !           366:     atapiBuf->command = ATAPI_CNT_IOREQ;
        !           367:     driverStatus = [self enqueueAtapiBuf:atapiBuf];
        !           368:     ret = atapiBuf->status;            // SCSI status
        !           369: 
        !           370:     /*
        !           371:      * Re-map to SCSI command if necessary.
        !           372:      */
        !           373:        if (driverStatus == SR_IOST_GOOD) {
        !           374:     for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++) {
        !           375:        if (atapiIoReq.scsiCmd == mapToAtapi[i]) {
        !           376:                        if ([self maptoSCSICmd: &atapiIoReq buffer:buffer
        !           377:                                newBuffer:&modeData] == NO)     {
        !           378:                                [_ataController atapiCntrlrUnLock];
        !           379:                                return SR_IOST_CMDREJ;
        !           380:                        }
        !           381:                        break;
        !           382:                }
        !           383:     }
        !           384:        }
        !           385: 
        !           386:     [self freeAtapiBuf:atapiBuf];
        !           387: 
        !           388:     /*
        !           389:      * Use this to filter and print data returned from the device. 
        !           390:      */
        !           391: #ifdef DEBUG
        !           392:     {
        !           393:        unsigned char *buf = (unsigned char *)buffer;
        !           394:        if ((atapiIoReq.atapiCmd[0] == 0x25) && (atapiIoReq.lun == 0))  {
        !           395:            IOLog("%s: Returned data.\n", [self name]);
        !           396:            for (i = 0; i < atapiIoReq.bytesTransferred; i+=4)  {
        !           397:                IOLog("%s: %02x %02x %02x %02x\n", [self name], buf[i], 
        !           398:                    buf[i+1], buf[i+2], buf[i+3]);
        !           399:            }
        !           400:            IOLog("%s: total bytes transferred = %d\n", [self name], 
        !           401:                        atapiIoReq.bytesTransferred);
        !           402:            IOLog("%s: scsi status: %x driver status: %x\n", [self name],
        !           403:                atapiIoReq.scsiStatus, ret);
        !           404:        }
        !           405: 
        !           406:     }
        !           407: #endif DEBUG
        !           408: 
        !           409:     /*
        !           410:      * This is a workaround for the Mitsumi Read CD-ROM capacity bug. It
        !           411:      * reports the block size as 2352 bytes instead of 2048 bytes. It is
        !           412:      * including preamble and other info. I have seen this on MITSUMI CD-ROM
        !           413:      * !B B02. The workaround is truncate the returned value. Remove this
        !           414:      * when it is no longer needed. 
        !           415:      */
        !           416:     {
        !           417:        unsigned int blockSize, value;
        !           418:        char *buf = (char *)buffer;
        !           419:        if ((atapiIoReq.atapiCmd[0] == C10OP_READCAPACITY) && 
        !           420:                (atapiIoReq.lun == 0))  {
        !           421:            blockSize = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | 
        !           422:                        buf[7];
        !           423:            if (blockSize == 0)                 /* self defense */
        !           424:                blockSize = 2048;
        !           425:            for (value = 16; value < blockSize; value *= 2)
        !           426:                ;
        !           427:            if (value > blockSize)      {
        !           428:                //IOLog("%s: block size set to %d from %d\n", [self name], value/2, blockSize);
        !           429:                blockSize = value / 2;
        !           430:                buf[4] = (blockSize >> 24) & 0xff;
        !           431:                buf[5] = (blockSize >> 16) & 0xff;
        !           432:                buf[6] = (blockSize >> 8) & 0xff;
        !           433:                buf[7] = blockSize & 0xff;
        !           434:            }
        !           435:        }
        !           436:    }
        !           437:     
        !           438: #ifdef COMMAND_HISTORY
        !           439:        {
        !           440:            int j, k;
        !           441:                
        !           442:            /* Print history in case of error. */
        !           443:            if ((ret != SR_IOST_GOOD) && (atapiIoReq.atapiCmd[0] != 0x00)
        !           444:                        && (atapiIoReq.atapiCmd[0] != 0x12))    {
        !           445:                IOLog("%s: Command %02x failed. Backtrace..\n", [self name], 
        !           446:                        atapiIoReq.atapiCmd[0]);
        !           447:                i = (cmdPos - cmdsInBuf) % MAXCMDS;
        !           448:                k = (int) cmdsInBuf;
        !           449:                while (--k >= 0)        {
        !           450:                    IOLog("%s: ", [self name]);
        !           451:                    for (j = 0; j < 12; j++)    {
        !           452:                        IOLog("%02x ", cmdBuf[i].atapiCmd[j]);
        !           453:                    }
        !           454:                    IOLog("\n");
        !           455:                    if (i == MAXCMDS)
        !           456:                        i = 0;
        !           457:                    else
        !           458:                        i += 1;
        !           459:                }
        !           460:                cmdsInBuf = 0;
        !           461:            } 
        !           462:        }
        !           463: #endif COMMAND_HISTORY
        !           464: 
        !           465:     scsiReq->bytesTransferred = atapiIoReq.bytesTransferred;
        !           466:     scsiReq->scsiStatus = atapiIoReq.scsiStatus;
        !           467:     scsiReq->driverStatus = driverStatus;
        !           468: 
        !           469:        [_ataController atapiCntrlrUnLock];
        !           470:     
        !           471:     return ret;    
        !           472: }
        !           473: 
        !           474: #define MPH_SCSI_6_SIZE                sizeof(mode_sel_hdr_t)
        !           475: #define MPH_SCSI_10_SIZE       8
        !           476: #define MPH_ATAPI_SIZE         sizeof(atapiMPH_t)
        !           477: #define MPH_DELTA                      (MPH_ATAPI_SIZE - MPH_SCSI_6_SIZE)
        !           478: 
        !           479: /*
        !           480:  * Map SCSI commands into ATAPI commands.
        !           481:  * We use this to modify the SCSI Mode Sense/Select commands to fit
        !           482:  * the ATAPI protocol.
        !           483:  *
        !           484:  * FIXME - We do not handle multiple mode pages. Only the first page is
        !           485:  * translated.
        !           486:  */
        !           487: - (BOOL) maptoAtapiCmd:(atapiIoReq_t *)atapiIoReq 
        !           488:                 buffer:(void *)buffer
        !           489:              newBuffer:(atapiMPL_t *)mode
        !           490: {
        !           491:     int i, pageLength, bd_len, page_start, hdr_size, maxTransfer;
        !           492:     unsigned char *data = (unsigned char *)buffer;
        !           493: 
        !           494:        /*
        !           495:         * Modify the SCSI mode sense (6) command.
        !           496:         *
        !           497:         * SCSI mode sense (10) should be fine for ATAPI since it matches
        !           498:         * the ATAPI spec very closely.
        !           499:         */     
        !           500:     if (atapiIoReq->scsiCmd == C6OP_MODESENSE) {
        !           501: 
        !           502:                /*
        !           503:                 * Our ATAPI buffer must be MPH_DELTA bytes larger than the size
        !           504:                 * of the SCSI buffer passed in.
        !           505:                 */
        !           506:                if ((atapiIoReq->atapiCmd[4] + MPH_DELTA) > sizeof(atapiMPL_t))
        !           507:                        return NO;
        !           508: 
        !           509:                /*
        !           510:                 * Transform the SCSI mode sense (6) command into a SCSI
        !           511:                 * mode sense (10) command.
        !           512:                 */
        !           513:                atapiIoReq->atapiCmd[0] = C10OP_MODESENSE;
        !           514:                atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4] + MPH_DELTA;
        !           515:                atapiIoReq->atapiCmd[4] = 0;
        !           516:                atapiIoReq->atapiCmd[5] = 0;
        !           517:                
        !           518:                /* Increase the maxTransfer by 4 bytes, since in SCSI Mode
        !           519:                 * Sense(6), the Mode Parameter Header is only 4 bytes long,
        !           520:                 * while in ATAPI, it is always 8-bytes. Therefore, we may
        !           521:                 * need to transfer 4 additional bytes over the set SCSI limit.
        !           522:                 * We also know that we have enough storage since we did the
        !           523:                 * check earlier.
        !           524:                 */
        !           525:                atapiIoReq->maxTransfer += MPH_DELTA;
        !           526:                
        !           527:                return YES;
        !           528:     } 
        !           529: 
        !           530:        /*
        !           531:         * Modify the SCSI mode select commands.
        !           532:         */              
        !           533:     if ((atapiIoReq->scsiCmd == C6OP_MODESELECT) || 
        !           534:                (atapiIoReq->scsiCmd == C10OP_MODESELECT)) {
        !           535:                
        !           536:                if (atapiIoReq->scsiCmd == C6OP_MODESELECT) {
        !           537:                        atapiIoReq->atapiCmd[0] = C10OP_MODESELECT;
        !           538:                        atapiIoReq->atapiCmd[4] = 0;
        !           539:                        atapiIoReq->atapiCmd[5] = 0;            /* reset control field */
        !           540:                        
        !           541:                        bd_len = data[3];                                       /* block descriptor length */
        !           542:                        hdr_size = MPH_SCSI_6_SIZE;                     /* mode parameter hdr size */
        !           543:                }
        !           544:                else {  // C10OP_MODESELECT
        !           545:                        atapiIoReq->atapiCmd[9] = 0;            /* reset control field */
        !           546:                        bd_len = (data[6] << 8) | data[7];      /* block descriptor length */
        !           547:                        hdr_size = MPH_SCSI_10_SIZE;            /* mode parameter hdr size */
        !           548:                }
        !           549:                
        !           550:                page_start = hdr_size + bd_len;                 /* start of mode page */
        !           551:                pageLength = data[page_start + 1] + 2;  /* total size of mode page */
        !           552:                if (pageLength > MODSEL_DATA_LEN)               /* page too large */
        !           553:                        return NO;
        !           554:                
        !           555:                /* copy the mode page to our own buffer space */
        !           556:                for (i = 0; i < pageLength; i++) {
        !           557:                        mode->pageData[i] = data[page_start + i];
        !           558:                }
        !           559:                
        !           560:                /* Update allocation length in the mode select command.
        !           561:                 * length = page size + ATAPI header size
        !           562:                 */
        !           563:                maxTransfer = pageLength + MPH_ATAPI_SIZE;
        !           564:                atapiIoReq->atapiCmd[8] = maxTransfer & 0xff;                   /* LSB */
        !           565:                atapiIoReq->atapiCmd[7] = (maxTransfer >> 8) & 0xff;    /* MSB */
        !           566:            
        !           567:                /*
        !           568:                 * Update the maxTransfer count.
        !           569:                 */
        !           570:                atapiIoReq->maxTransfer = maxTransfer;
        !           571:            return YES;
        !           572:        }
        !           573:     
        !           574:     return YES;
        !           575: }
        !           576: 
        !           577: /*
        !           578:  * Map the result of ATAPI commands into their SCSI counterparts.
        !           579:  *
        !           580:  * FIXME - We do not handle multiple mode pages. Only the first page is
        !           581:  * translated.
        !           582:  */
        !           583: - (BOOL) maptoSCSICmd:(atapiIoReq_t *)atapiIoReq
        !           584:                buffer:(void *)buffer
        !           585:             newBuffer:(atapiMPL_t *)mode
        !           586: {
        !           587:     int i, pageLength;
        !           588:     unsigned char *data = (unsigned char *)buffer;
        !           589: 
        !           590:        /*
        !           591:         * If the executed command was originally a SCSI Mode Sense(6)
        !           592:         * command, we need to modify the result since the returned
        !           593:         * Page Parameter Header size is now 8-bytes instead of the
        !           594:         * expected 4-bytes.
        !           595:         */ 
        !           596:     if ((atapiIoReq->scsiCmd == C6OP_MODESENSE) &&
        !           597:                (atapiIoReq->bytesTransferred >= 10)) {
        !           598:                
        !           599:                // bytesTransferred must be greater than 10 or otherwise the
        !           600:                // PageLength field in the page (byte 1) would not be valid.
        !           601: 
        !           602:                pageLength = mode->pageData[1] + 2;
        !           603:                
        !           604:                /* Mode Page + Mode Header must fit in the SCSI buffer.
        !           605:                 * Remember that the value in atapiCmd[8] was
        !           606:                 * artificially increased by 4 bytes, so we need to
        !           607:                 * take that into account.
        !           608:                 */
        !           609:                if ((pageLength + MPH_SCSI_6_SIZE) >
        !           610:                        (atapiIoReq->atapiCmd[8] - MPH_DELTA)) {
        !           611:                        /* SCSI buffer is too small */
        !           612: #ifdef DEBUG
        !           613:                        IOLog("maptoSCSICmd:  Mode Select buffer too small\n");
        !           614: #endif DEBUG
        !           615:                        return NO;
        !           616:                }
        !           617:                
        !           618:                data[0] = mode->mph.mdl0;               // mode data length
        !           619:                data[1] = mode->mph.mt;                 // medium type
        !           620:                data[2] = 0;                                    // device-specific parameter
        !           621:                data[3] = 0;                                    // block descriptor length
        !           622:                
        !           623:                for (i = 0; i < pageLength; i++) {
        !           624:                        data[4 + i] = mode->pageData[i];
        !           625:                }
        !           626:                
        !           627:                /*
        !           628:                 * Modify bytesTransferred count to make it appear that
        !           629:                 * we transferred 4 less bytes.
        !           630:                 */
        !           631:                atapiIoReq->bytesTransferred -= MPH_DELTA;
        !           632:                return YES;
        !           633:     } 
        !           634:     
        !           635:     return YES;
        !           636: }
        !           637: 
        !           638: /*
        !           639:  * If this SCSI command is not supported by ATAPI then try to fake its
        !           640:  * execution if possible. 
        !           641:  */
        !           642: - (BOOL) emulateSCSICmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer
        !           643: {
        !           644:     unsigned char *data = (unsigned char *)buffer;
        !           645:     
        !           646:     /*
        !           647:      * We need to fake mode sense page 2. Workspace sends that and this page
        !           648:      * is reserved in ATAPI. In the SCSI world this page is for
        !           649:      * disconnect-reconnect and ATAPI doesn't support that now. 
        !           650:      */
        !           651:     if (atapiIoReq->atapiCmd[0] == C10OP_MODESENSE) {
        !           652:        if ((atapiIoReq->atapiCmd[2] & 0x1f) == 0x02) {
        !           653:            bzero(data, atapiIoReq->atapiCmd[4]);
        !           654:            data[0] = 0x02;
        !           655:            data[1] = atapiIoReq->atapiCmd[4];
        !           656:            data[2] = 1;                /* our preferred size: 2048 bytes */
        !           657:            atapiIoReq->bytesTransferred = atapiIoReq->atapiCmd[4];
        !           658:            atapiIoReq->scsiStatus = STAT_GOOD;
        !           659:            
        !           660:            return YES;
        !           661:        }
        !           662:     }
        !           663:      
        !           664:     return NO;         /* default */
        !           665: }
        !           666: 
        !           667: 
        !           668: /*
        !           669:  * Reset all ATAPI devices connected to this controller. Note that we have
        !           670:  * obtain a lock before resetting the controller. 
        !           671:  */
        !           672: - (sc_status_t)resetSCSIBus
        !           673: {
        !           674:     int unit;
        !           675:     atapi_return_t ret;
        !           676:     sc_status_t status = SR_IOST_GOOD;
        !           677:     
        !           678:     for (unit = 0; unit < [_ataController numDevices]; unit++) {
        !           679:     
        !           680:        if ([_ataController isAtapiDevice:unit])        {
        !           681:        
        !           682:            [_ataController atapiCntrlrLock];
        !           683:            ret = [_ataController atapiSoftReset:unit];
        !           684:            [_ataController atapiCntrlrUnLock];
        !           685:            
        !           686:            if (ret != IDER_SUCCESS)    {
        !           687:                IOLog("%s: ATAPI reset failed.\n", [self name]);
        !           688:                status = SR_IOST_HW;
        !           689:            }
        !           690:        }
        !           691:     }
        !           692:     
        !           693:     return status;
        !           694: }
        !           695: 
        !           696: #ifdef undef
        !           697: /* For testing individual commands. */
        !           698: static void testDebug(id driver)
        !           699: {
        !           700:     void *buffer;
        !           701:     atapiIoReq_t atapiIoReq;
        !           702:     
        !           703:     buffer = IOMalloc(2048);
        !           704:     bzero(&atapiIoReq, sizeof(atapiIoReq_t));
        !           705:     
        !           706:     atapiIoReq.cmdLen = 12;            
        !           707:     atapiIoReq.read = 1;
        !           708:     atapiIoReq.drive = 0;
        !           709:     atapiIoReq.lun = 0;
        !           710:     
        !           711:     atapiIoReq.atapiCmd[0] = 0x28;
        !           712:     atapiIoReq.atapiCmd[2] = 0;
        !           713:     atapiIoReq.atapiCmd[3] = 0;
        !           714:     atapiIoReq.atapiCmd[4] = 0;
        !           715:     atapiIoReq.atapiCmd[5] = 5;
        !           716:     atapiIoReq.atapiCmd[7] = 0;
        !           717:     atapiIoReq.atapiCmd[8] = 1;
        !           718:     
        !           719:    [driver atapiExecuteCmd:&atapiIoReq 
        !           720:                buffer:buffer client:IOVmTaskSelf()];
        !           721:                
        !           722: }
        !           723: #endif undef
        !           724: 
        !           725: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
        !           726: {
        !           727:     strcpy( classes, IOClassATAPIController);
        !           728:     return( self);
        !           729: }
        !           730: 
        !           731: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen
        !           732: {
        !           733:     strcat( types, " "IOTypeATAPI);
        !           734:     return( self);
        !           735: }
        !           736: 
        !           737: @end
        !           738: 

unix.superglobalmegacorp.com

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