Annotation of kernel/bsd/dev/ppc/drvPPCATA/AtapiCnt.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     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.