Annotation of kernel/bsd/dev/ppc/drvPPCATA/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.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: // Copyright 1997 by Apple Computer, Inc., all rights reserved.
        !            26: /*
        !            27:  * Copyright (c) 1995-1997 NeXT Software, Inc.  All rights reserved. 
        !            28:  *
        !            29:  * AtapiCnt.m - Implementation of ATAPI controller class.
        !            30:  *
        !            31:  *
        !            32:  * HISTORY 
        !            33:  * 31-Aug-1994         Rakesh Dubey at NeXT 
        !            34:  *     Created. 
        !            35:  */
        !            36: 
        !            37: #undef DEBUG
        !            38: 
        !            39: #import <kern/assert.h>
        !            40: #import <driverkit/kernelDriver.h>
        !            41: #import <driverkit/interruptMsg.h>
        !            42: #import <mach/mach_interface.h>
        !            43: #import <driverkit/IODevice.h>
        !            44: #import <driverkit/ppc/IOTreeDevice.h>
        !            45: #import <driverkit/align.h>
        !            46: #import <machkit/NXLock.h>
        !            47: #import "io_inline.h"
        !            48: 
        !            49: #import "IdeCnt.h"
        !            50: #import "AtapiCnt.h"
        !            51: #import "AtapiCntInternal.h"
        !            52: 
        !            53: /*
        !            54:  * opcode groups
        !            55:  */
        !            56: #define        SCSI_OPGROUP(opcode)    ((opcode) & 0xe0)
        !            57: 
        !            58: #define        OPGROUP_0               0x00    /* six byte commands */
        !            59: #define        OPGROUP_1               0x20    /* ten byte commands */
        !            60: #define        OPGROUP_2               0x40    /* ten byte commands */
        !            61: #define        OPGROUP_5               0xa0    /* twelve byte commands */
        !            62: #define        OPGROUP_6               0xc0    /* six byte, vendor unique commands */
        !            63: #define        OPGROUP_7               0xe0    /* ten byte, vendor unique commands */
        !            64: 
        !            65: /*
        !            66:  * List of SCSI commands that do not have a counterpart in ATAPI
        !            67:  * implementation. These commands will need to be mapped individually. 
        !            68:  */
        !            69: static unsigned char mapToAtapi[] = {
        !            70:     C6OP_MODESELECT, 
        !            71:     C6OP_MODESENSE
        !            72: };
        !            73: 
        !            74: /*
        !            75:  * List of controllers that have been already probed. We need this since each
        !            76:  * Instance table lists IdeDisk as well as IdeCOntroller classes. And we need
        !            77:  * to create instances of disks attached to each controller only once. 
        !            78:  */
        !            79: static int probedControllerCount = 0;
        !            80: static id probedControllers[MAX_IDE_CONTROLLERS];
        !            81: 
        !            82: @implementation AtapiController
        !            83: 
        !            84: + (BOOL)probe : deviceDescription
        !            85: {
        !            86: 
        !            87:     int unit, i;
        !            88:     id direct;
        !            89:     id atapiCnt;
        !            90: 
        !            91:     direct = [deviceDescription directDevice];
        !            92: 
        !            93:     for (i = 0; i < probedControllerCount; i++)        
        !            94:     {
        !            95:        if (probedControllers[i] == direct)     
        !            96:        {
        !            97:            return YES;
        !            98:        }
        !            99:     }
        !           100:     
        !           101:     probedControllers[probedControllerCount++] = direct;
        !           102: 
        !           103:     for (unit = 0; unit < [direct numDevices]; unit++) 
        !           104:     {
        !           105:        if ([direct isAtapiDevice:unit])        
        !           106:         {
        !           107:            atapiCnt = [[self alloc]  initFromDeviceDescription:deviceDescription];
        !           108:            
        !           109:            if (atapiCnt == nil)        
        !           110:             {
        !           111:                IOLog("ATAPI: failed to probe device %d.\n", unit);
        !           112:                continue;
        !           113:            }
        !           114: 
        !           115:            if ([atapiCnt initResources:direct] == nil) 
        !           116:             {
        !           117:                IOLog("ATAPI: failed to initialize device %d.\n", unit);
        !           118:                [atapiCnt free];
        !           119:                continue;
        !           120:             }
        !           121:                    
        !           122:            if ([atapiCnt registerDevice] == nil)       
        !           123:             {
        !           124:                IOLog("ATAPI: failed to register device %d.\n", unit);
        !           125:                [atapiCnt free];
        !           126:                continue;
        !           127:            } 
        !           128:             else 
        !           129:             {
        !           130:                return YES;
        !           131:             }
        !           132:        }
        !           133:     }  
        !           134:     return NO;
        !           135: }
        !           136: 
        !           137: /*
        !           138:  * We override IOSCSIController to make ourself look like an indirect device
        !           139:  * in order to get connected to IdeController.
        !           140:  */
        !           141: + (IODeviceStyle)deviceStyle
        !           142: {
        !           143:     return IO_IndirectDevice;
        !           144: }
        !           145: 
        !           146: /*
        !           147:  * The protocol we need as an indirect device.
        !           148:  */
        !           149: static Protocol *protocols[] = {
        !           150:     @protocol(AtapiControllerPublic),
        !           151:     nil
        !           152: };
        !           153: 
        !           154: + (Protocol **)requiredProtocols
        !           155: {
        !           156:     return protocols;
        !           157: }
        !           158: 
        !           159: 
        !           160: - (unsigned short)scsiCmdLen:(IOSCSIRequest *) scsiReq
        !           161: {
        !           162:     unsigned char cmdlen;
        !           163:     union cdb *cdbp = &scsiReq->cdb;
        !           164: 
        !           165:     switch (SCSI_OPGROUP(cdbp->cdb_opcode)) {
        !           166: 
        !           167:       case OPGROUP_0:
        !           168:        cmdlen = sizeof(struct cdb_6);
        !           169:        break;
        !           170: 
        !           171:       case OPGROUP_1:
        !           172:       case OPGROUP_2:
        !           173:        cmdlen = sizeof(struct cdb_10);
        !           174:        break;
        !           175: 
        !           176:       case OPGROUP_5:
        !           177:        cmdlen = sizeof(struct cdb_12);
        !           178:        break;
        !           179: 
        !           180:       case OPGROUP_6:
        !           181:        if (scsiReq->cdbLength)
        !           182:            cmdlen = scsiReq->cdbLength;
        !           183:        else
        !           184:            cmdlen = sizeof(struct cdb_6);
        !           185:        break;
        !           186: 
        !           187:       case OPGROUP_7:
        !           188:        if (scsiReq->cdbLength)
        !           189:            cmdlen = scsiReq->cdbLength;
        !           190:        else
        !           191:            cmdlen = sizeof(struct cdb_10);
        !           192:        break;
        !           193: 
        !           194:       default:
        !           195:        scsiReq->driverStatus = SR_IOST_CMDREJ;
        !           196:        return 0;
        !           197:     }
        !           198:     
        !           199:     return cmdlen;
        !           200: }
        !           201: 
        !           202: #define        C10OP_MODESELECT        0x55    /* OPT: set device parameters */
        !           203: #define        C10OP_MODESENSE         0x5a    /* OPT: get device parameters */
        !           204: #define C10OP_READCAPACITY      0x25    /* read capacity */
        !           205: 
        !           206: /*
        !           207:  * Do a SCSI command, as specified by an IOSCSIRequest.
        !           208:  */
        !           209: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq 
        !           210:                    buffer : (void *)buffer 
        !           211:                    client : (vm_task_t)client
        !           212: {
        !           213:     int i;
        !           214:     atapiIoReq_t atapiIoReq;
        !           215:     atapiBuf_t *atapiBuf;
        !           216:     unsigned char *scsiCmd;
        !           217:     cdb_t my_cdb;
        !           218:     sc_status_t ret;
        !           219:     IOReturn driverStatus;
        !           220:    
        !           221:     [_ataController atapiCntrlrLock];
        !           222:     
        !           223:     my_cdb = scsiReq->cdb;
        !           224:     
        !           225:     bzero(&atapiIoReq, sizeof(atapiIoReq_t));
        !           226:     
        !           227:     atapiIoReq.cmdLen = [_ataController atapiCommandPacketSize:scsiReq->target];
        !           228:        
        !           229:     atapiIoReq.read = scsiReq->read;
        !           230:     atapiIoReq.maxTransfer = scsiReq->maxTransfer;
        !           231:     atapiIoReq.drive = scsiReq->target;
        !           232:     atapiIoReq.lun = scsiReq->lun;
        !           233:     
        !           234:     scsiCmd = (unsigned char *) &(my_cdb.cdb_opcode);
        !           235: 
        !           236:     for (i = 0; i < [self scsiCmdLen:scsiReq]; i++)    {
        !           237:        atapiIoReq.atapiCmd[i] = *scsiCmd;
        !           238:        scsiCmd++;
        !           239:     }
        !           240: 
        !           241:     /*
        !           242:      * Map to available ATAPI command if necessary.
        !           243:      */
        !           244:     for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++)     
        !           245:     {
        !           246:        if (atapiIoReq.atapiCmd[0] == mapToAtapi[i])    
        !           247:         {
        !           248:            if ([self maptoAtapiCmd: &atapiIoReq buffer:buffer] == NO)  
        !           249:             {
        !           250:                [_ataController atapiCntrlrUnLock];
        !           251:                return SR_IOST_CMDREJ;
        !           252:            }
        !           253:            break;
        !           254:        }
        !           255:     }
        !           256: 
        !           257:     /*
        !           258:      * If emulation is successful then return quickly. 
        !           259:      */
        !           260:     if ([self emulateSCSICmd: &atapiIoReq buffer:buffer] == YES)       
        !           261:     {
        !           262:        [_ataController atapiCntrlrUnLock];
        !           263:        return SR_IOST_GOOD;
        !           264:     }
        !           265: 
        !           266:     /*
        !           267:      * Send the command to the ioThread. 
        !           268:      */
        !           269:     atapiBuf = [self allocAtapiBuf];
        !           270:     atapiBuf->atapiIoReq = &atapiIoReq;
        !           271:     atapiBuf->buffer = buffer;
        !           272:     atapiBuf->client = client;
        !           273:     atapiBuf->command = ATAPI_CNT_IOREQ;
        !           274:     driverStatus = [self enqueueAtapiBuf:atapiBuf];
        !           275:     ret = atapiBuf->status;            // SCSI status
        !           276:     [self freeAtapiBuf:atapiBuf];
        !           277:          
        !           278:     /*
        !           279:      * This is a workaround for the Mitsumi Read CD-ROM capacity bug. It
        !           280:      * reports the block size as 2352 bytes instead of 2048 bytes. It is
        !           281:      * including preamble and other info. I have seen this on MITSUMI CD-ROM
        !           282:      * !B B02. The workaround is truncate the returned value. Remove this
        !           283:      * when it is no longer needed. 
        !           284:      */
        !           285:     {
        !           286:        unsigned int blockSize;
        !           287:        char *buf = (char *)buffer;
        !           288: 
        !           289:        if ((atapiIoReq.atapiCmd[0] == C10OP_READCAPACITY) && (atapiIoReq.lun == 0))    
        !           290:         {
        !           291:            blockSize = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
        !           292: 
        !           293:            if ( blockSize == 2352 )    
        !           294:             {
        !           295:                blockSize = 2048;
        !           296:                buf[4] = (blockSize >> 24) & 0xff;
        !           297:                buf[5] = (blockSize >> 16) & 0xff;
        !           298:                buf[6] = (blockSize >> 8) & 0xff;
        !           299:                buf[7] = blockSize & 0xff;
        !           300:            }
        !           301:        }
        !           302:    }
        !           303:        
        !           304:     scsiReq->bytesTransferred = atapiIoReq.bytesTransferred;
        !           305:     scsiReq->scsiStatus = atapiIoReq.scsiStatus;
        !           306:     scsiReq->driverStatus = driverStatus;
        !           307: 
        !           308:     [_ataController atapiCntrlrUnLock];
        !           309:     
        !           310:     return ret;    
        !           311: }
        !           312: 
        !           313: - (BOOL) maptoAtapiCmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer
        !           314: {
        !           315:     int i, pageLength;
        !           316:     unsigned char *data = (unsigned char *)buffer;
        !           317: 
        !           318:     if (atapiIoReq->atapiCmd[0] == C6OP_MODESENSE) 
        !           319:     {
        !           320:        atapiIoReq->atapiCmd[0] = C10OP_MODESENSE;
        !           321:        atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4];
        !           322:        atapiIoReq->atapiCmd[4] = 0;
        !           323:        return YES;
        !           324:     } 
        !           325:     
        !           326:     if (atapiIoReq->atapiCmd[0] == C6OP_MODESELECT) 
        !           327:     {
        !           328:        atapiIoReq->atapiCmd[0] = C10OP_MODESELECT;
        !           329:        atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4];
        !           330:        atapiIoReq->atapiCmd[4] = 0;
        !           331:     
        !           332:        /*
        !           333:         * This is complicated since SCSI and ATAPI have very different
        !           334:         * data layouts for mode select. 
        !           335:         */
        !           336:        if ((atapiIoReq->atapiCmd[0] == C10OP_MODESELECT) &&
        !           337:                (data[3] == 0x08))      {
        !           338:            data[0] = data[1] = 0;      /* mode data length is reserved */
        !           339:            data[2] = 0;                /* always for CD-ROM. Tape? FIXME */
        !           340:            data[3] = 0;                /* reserved for ATAPI */
        !           341:     
        !           342:            /*
        !           343:             * Move the data up by four bytes since there only four bytes of
        !           344:             * block descriptor in ATAPI while SCSI has eight. 
        !           345:             */
        !           346:            pageLength = data[13] & 0x01f;
        !           347:            for (i = 8; i < pageLength+8; i++)  
        !           348:             {
        !           349:                data[i] = data[i+4];
        !           350:                data[i+4] = 0;
        !           351:            }
        !           352:            
        !           353:            atapiIoReq->atapiCmd[8] = 0x14;     /* 8 + 12 */
        !           354:            data[9] = 0;
        !           355:            
        !           356:            return YES;
        !           357:        }
        !           358:     
        !           359:        /*
        !           360:         * Now handle the case where block descriptor length is zero. This is
        !           361:         * more messy since we are short of memory. FIXME later.. 
        !           362:         */
        !           363:         
        !           364:         return YES;            /* this will fail now */
        !           365:     }
        !           366:     
        !           367:     return YES;
        !           368: }
        !           369: 
        !           370: /*
        !           371:  * If this SCSI command is not supported by ATAPI then try to fake its
        !           372:  * execution if possible. 
        !           373:  */
        !           374: - (BOOL) emulateSCSICmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer
        !           375: {
        !           376:     unsigned char *data = (unsigned char *)buffer;
        !           377:     
        !           378:     /*
        !           379:      * We need to fake mode sense page 2. Workspace sends that and this page
        !           380:      * is reserved in ATAPI. In the SCSI world this page is for
        !           381:      * disconnect-reconnect and ATAPI doesn't support that now. 
        !           382:      */
        !           383:     if (atapiIoReq->atapiCmd[0] == C10OP_MODESENSE) 
        !           384:     {
        !           385:        if ((atapiIoReq->atapiCmd[2] & 0x1f) == 0x02) 
        !           386:         {
        !           387:            bzero(data, atapiIoReq->atapiCmd[4]);
        !           388:            data[0] = 0x02;
        !           389:            data[1] = atapiIoReq->atapiCmd[4];
        !           390:            data[2] = 1;                /* our preferred size: 2048 bytes */
        !           391:            atapiIoReq->bytesTransferred = atapiIoReq->atapiCmd[4];
        !           392:            atapiIoReq->scsiStatus = STAT_GOOD;
        !           393:            
        !           394:            return YES;
        !           395:        }
        !           396:     }
        !           397:      
        !           398:     return NO;         /* default */
        !           399: }
        !           400: 
        !           401: 
        !           402: /*
        !           403:  * Reset all ATAPI devices connected to this controller. Note that we have
        !           404:  * obtain a lock before resetting the controller. 
        !           405:  */
        !           406: - (sc_status_t)resetSCSIBus
        !           407: {
        !           408:     int unit;
        !           409:     atapi_return_t ret;
        !           410:     sc_status_t status = SR_IOST_GOOD;
        !           411:     
        !           412:     for (unit = 0; unit < [_ataController numDevices]; unit++) {
        !           413:     
        !           414:        if ([_ataController isAtapiDevice:unit])        
        !           415:         {
        !           416:            [_ataController atapiCntrlrLock];
        !           417:            ret = [_ataController atapiSoftReset:unit];
        !           418:            [_ataController atapiCntrlrUnLock];
        !           419:            
        !           420:            if (ret != IDER_SUCCESS)    
        !           421:             {
        !           422:                IOLog("%s: ATAPI reset failed.\n", [self name]);
        !           423:                status = SR_IOST_HW;
        !           424:            }
        !           425:        }
        !           426:     }
        !           427:     
        !           428:     return status;
        !           429: }
        !           430: 
        !           431: /*
        !           432:  * Note: ATAPI requires transfer byte counts be even. 
        !           433:  *       The alignment fields readLength and writeLength are set 2.
        !           434:  */
        !           435: 
        !           436: - (void)getDMAAlignment:(IODMAAlignment *)alignment
        !           437: {
        !           438:        alignment->readStart   = 1;     /* XXX */
        !           439:        alignment->writeStart  = 1;     /* XXX */
        !           440:        alignment->readLength  = 2;     /* XXX */
        !           441:        alignment->writeLength = 2;     /* XXX */
        !           442: }
        !           443: 
        !           444: /*
        !           445:  * Set maximum I/O length for SCSI framework.
        !           446:  *
        !           447:  * There are 256 DBDMA descriptors available. One is used for a DBDMA STOP command. Another is 
        !           448:  * potentially used to handle odd-byte transfers. An additional one may be potentially used if
        !           449:  * the transfer address is not page-aligned, for ex: a 64KB unaligned transfer requires 17 descriptors.
        !           450:  */
        !           451: - (unsigned) maxTransfer
        !           452: {
        !           453:     return  (MAX_IDE_DESCRIPTORS - 3) * PAGE_SIZE;
        !           454: }
        !           455: 
        !           456: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
        !           457: {
        !           458:     strcpy( classes, IOClassATAPIController);
        !           459:     return( self);
        !           460: }
        !           461: 
        !           462: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen
        !           463: {
        !           464:     strcat( types, " "IOTypeATAPI);
        !           465:     return( self);
        !           466: }
        !           467: 
        !           468: 
        !           469: @end
        !           470: 

unix.superglobalmegacorp.com

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