Annotation of kernel/bsd/dev/ppc/drvPPCATA/AtapiCntCmds.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) 1994-1997 NeXT Software, Inc.  All rights reserved. 
        !            28:  *
        !            29:  * AtapiCntCmds.m - ATAPI command implementation for ATA interface. 
        !            30:  *
        !            31:  * HISTORY 
        !            32:  *
        !            33:  */
        !            34: 
        !            35: #import "AtapiCntCmds.h"
        !            36: #import "IdeCntInit.h"
        !            37: #import "IdeCntCmds.h"
        !            38: #import "IdeCntDma.h"
        !            39: 
        !            40: @implementation IdeController(ATAPI)
        !            41: 
        !            42: #define ATAPI_MAX_WAIT_FOR_NOTBUSY             (5 * 1000)
        !            43: 
        !            44: /*
        !            45:  * We could use the ATA version instead of rolling our own here. 
        !            46:  */
        !            47: - (atapi_return_t)atapiWaitForNotBusy
        !            48: {
        !            49:     int i;
        !            50:     unsigned char status;
        !            51: 
        !            52:     for (i = 0; i < ATAPI_MAX_WAIT_FOR_NOTBUSY; i++)  
        !            53:     {
        !            54:        status = inb(_ideRegsAddrs.status);
        !            55:        
        !            56:        if (!(status & BUSY)) 
        !            57:         {
        !            58:            return IDER_SUCCESS;
        !            59:        }
        !            60:        IOSleep(1);
        !            61:     }
        !            62:     return IDER_TIMEOUT;
        !            63: }
        !            64: 
        !            65: /*
        !            66:  * Before sending a packet to ATAPI device, we test if BSY == 0 and DRQ == 0. 
        !            67:  */
        !            68: #define ATAPI_MAX_WAIT_READY_FOR_PACKET                (5 * 1000)
        !            69: 
        !            70: - (atapi_return_t)atapiWaitReadyForPacket
        !            71: {
        !            72:     int i;
        !            73:     unsigned char status;
        !            74: 
        !            75:     for (i = 0; i < ATAPI_MAX_WAIT_READY_FOR_PACKET; i++)  
        !            76:     {
        !            77:        status = inb(_ideRegsAddrs.status);
        !            78:        
        !            79:        if (!(status & BUSY) && !(status & DREQUEST)) 
        !            80:         {
        !            81:            return IDER_SUCCESS;
        !            82:        }
        !            83:        IOSleep(1);     
        !            84:     }
        !            85:     
        !            86:     return IDER_DEV_NOT_READY;
        !            87: }
        !            88: 
        !            89: -(void)printAtapiInfo:(ideIdentifyInfo_t *)ideIdentifyInfo 
        !            90:                        Device:(unsigned char)unit
        !            91: {
        !            92:     int                i;
        !            93:     char               name[50];
        !            94:     char               firmware[9];
        !            95:     atapiGenConfig_t   *atapiGenConfig;
        !            96:     char               *protocolTypeStr, *deviceTypeStr, *cmdDrqTypeStr;
        !            97:     char               *removableStr, *cmdPacketSizeStr;
        !            98: 
        !            99:     /*
        !           100:      * Print drive name with firmware revision number after doing byte swaps. 
        !           101:      */
        !           102:     for (i = 0; i < 20; i++)   
        !           103:     {
        !           104:        name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
        !           105:        name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
        !           106:     }
        !           107:     name[40] = '\0';
        !           108:     
        !           109:     for (i = 0; i < 4; i++)    
        !           110:     {
        !           111:        firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
        !           112:        firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
        !           113:     }
        !           114:     firmware[8] = '\0';
        !           115:     
        !           116:     for (i = 38; i >= 0; i--)  {
        !           117:        if (name[i] != ' ')
        !           118:            break;
        !           119:     }
        !           120:     strcpy(name+i+2, firmware);
        !           121:     
        !           122:     /*
        !           123:      * This information should be printed since it is not duplicated
        !           124:      * elsewhere. 
        !           125:      */
        !           126:     atapiGenConfig = (atapiGenConfig_t *) &ideIdentifyInfo->genConfig;
        !           127:     
        !           128:     if (atapiGenConfig->protocolType == 0 || atapiGenConfig->protocolType == 1)
        !           129:        protocolTypeStr = "ATA";
        !           130:     else if (atapiGenConfig->protocolType == 2)
        !           131:        protocolTypeStr = "ATAPI";
        !           132:     else 
        !           133:        protocolTypeStr = "UNKNOWN PROTOCOL";
        !           134:        
        !           135:     if (atapiGenConfig->deviceType == 0)
        !           136:        deviceTypeStr = "DIRECT ACCESS";
        !           137:     else if (atapiGenConfig->deviceType == 5)
        !           138:        deviceTypeStr = "CD-ROM";
        !           139:     else if (atapiGenConfig->deviceType == 7)
        !           140:        deviceTypeStr = "OPTICAL";
        !           141:     else if (atapiGenConfig->deviceType == 1)
        !           142:        deviceTypeStr = "TAPE";
        !           143:     else
        !           144:        deviceTypeStr = "UNKNOWN DEVICE TYPE";
        !           145:        
        !           146:     if (atapiGenConfig->cmdDrqType == 0)
        !           147:        cmdDrqTypeStr = "SLOW DRQ";
        !           148:     else if (atapiGenConfig->cmdDrqType == 1)
        !           149:        cmdDrqTypeStr = "INTR DRQ";
        !           150:     else if (atapiGenConfig->cmdDrqType == 2)
        !           151:        cmdDrqTypeStr = "FAST DRQ";
        !           152:     else 
        !           153:        cmdDrqTypeStr = "UNKNOWN DRQ TYPE";
        !           154:        
        !           155:     if (atapiGenConfig->removable == 0)
        !           156:        removableStr = "NOT REMOVABLE";
        !           157:     else if (atapiGenConfig->removable == 1)
        !           158:        removableStr = "REMOVABLE";
        !           159:     
        !           160:     if (atapiGenConfig->cmdPacketSize == 0)
        !           161:        cmdPacketSizeStr = "CMD PKT LEN=12";
        !           162:     else if (atapiGenConfig->cmdPacketSize == 1)
        !           163:        cmdPacketSizeStr = "CMD PKT LEN=16";
        !           164:     else 
        !           165:        cmdPacketSizeStr = "CMD PKT LEN=UNKNOWN";       
        !           166: }
        !           167: 
        !           168: /*
        !           169:  * This is a private version for ATAPI Identify command below. It has a short
        !           170:  * delay time. 
        !           171:  */
        !           172: - (ide_return_t)atapiIdentifyDeviceWaitForDataReady
        !           173: {
        !           174:     int     delay = (100 * 1000);
        !           175:     unsigned char status;
        !           176: 
        !           177:     delay -= 2;
        !           178:     while (delay > 0) 
        !           179:     {
        !           180:        status = inb(_ideRegsAddrs.altStatus);
        !           181:        if ((!(status & BUSY)) && (status & DREQUEST))
        !           182:            return (IDER_SUCCESS);
        !           183:        if (delay % 1000)       
        !           184:         {
        !           185:            IODelay(2);
        !           186:             delay -= 2;
        !           187:        } 
        !           188:         else 
        !           189:         {
        !           190:            IOSleep(1);
        !           191:            delay -= 1000;
        !           192:        }
        !           193:     }
        !           194:     
        !           195:     return IDER_DEV_NOT_READY;
        !           196: }
        !           197: 
        !           198: /*
        !           199:  * There are lots of ATAPI CD-ROMs that shadow the task file register and
        !           200:  * hence show up as two devices. They also might issue a valid interrupt when
        !           201:  * ATAPI Identify Device command is sent so we need to really make sure
        !           202:  * whether the device has data for us. 
        !           203:  */
        !           204: -(atapi_return_t)_atapiIdentifyDevice:(struct vm_map *)client
        !           205:                                addr:(caddr_t)xferAddr
        !           206: {
        !           207:     unsigned int cmd = ATAPI_IDENTIFY_DRIVE;
        !           208:     unsigned char dh = ADDRESS_MODE_LBA;       /* ALWAYS */
        !           209:     unsigned char status;
        !           210:     atapi_return_t rtn;
        !           211:     
        !           212:     unsigned int oldTimeout;
        !           213: 
        !           214:     rtn = [self atapiWaitForNotBusy];
        !           215:     if (rtn != IDER_SUCCESS) 
        !           216:     {
        !           217:        return (rtn);
        !           218:     }
        !           219:     
        !           220:     [self setTransferRate: _driveNum UseDMA:NO];
        !           221: 
        !           222:     dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
        !           223:     outb(_ideRegsAddrs.driveSelect, dh);
        !           224:     
        !           225:     bzero(xferAddr, IDE_SECTOR_SIZE);
        !           226:     
        !           227:     [self enableInterrupts];
        !           228:     
        !           229:     outb(_ideRegsAddrs.command, ATAPI_IDENTIFY_DRIVE);
        !           230: 
        !           231:     oldTimeout = [self interruptTimeOut];
        !           232:     [self setInterruptTimeOut:4000];           // four seconds
        !           233:     
        !           234:     rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
        !           235:         
        !           236:     if (rtn != IDER_SUCCESS) {
        !           237:        [self getIdeRegisters:NULL Print:"Atapi Identify"];
        !           238:        [self setInterruptTimeOut:oldTimeout];
        !           239:        return rtn;
        !           240:     }
        !           241: 
        !           242:     /*
        !           243:      * Let's see if it really has data for us. 
        !           244:      */
        !           245:     rtn = [self atapiIdentifyDeviceWaitForDataReady];
        !           246:     if (rtn != IDER_SUCCESS) 
        !           247:     {
        !           248:        [self setInterruptTimeOut:oldTimeout];
        !           249:        return (rtn);
        !           250:     }
        !           251: 
        !           252:     /*
        !           253:      * FIXME: We need to do some sanity check on this data to be really sure
        !           254:      * that there is an ATAPI device out here. 
        !           255:      */
        !           256:     [self xferData:xferAddr read:YES client:client length:IDE_SECTOR_SIZE];
        !           257:     
        !           258:     [self setInterruptTimeOut:oldTimeout];
        !           259:     
        !           260:     return IDER_SUCCESS;
        !           261: }
        !           262: 
        !           263: /*
        !           264:  * Some CD-ROMS (like SONY CDU-55D) fail the first request so we reset the
        !           265:  * device and retry. 
        !           266:  */
        !           267: #define ATAPI_IDENTIFY_DEVICE_RETRIES          5
        !           268: 
        !           269: -(atapi_return_t)atapiIdentifyDevice:(struct vm_map *)client
        !           270:                                addr:(caddr_t)xferAddr
        !           271:                                unit:(unsigned char)unit
        !           272: {
        !           273:     int i;
        !           274:     atapi_return_t ret;
        !           275:     
        !           276:     for (i = 0; i < ATAPI_IDENTIFY_DEVICE_RETRIES; i++)        
        !           277:     {
        !           278:        ret = [self _atapiIdentifyDevice:client addr:xferAddr];
        !           279:        if (ret == IDER_SUCCESS)
        !           280:            break;
        !           281:            
        !           282:        /* Reset hardware and try again */
        !           283:        [self atapiSoftReset:unit];
        !           284:        IOSleep(500);
        !           285:     }
        !           286:     
        !           287:     if (i == ATAPI_IDENTIFY_DEVICE_RETRIES)    {
        !           288:        IOLog("%s: FATAL: Device %d: ATAPI Identify Device.\n", 
        !           289:                [self name], unit);
        !           290:     }
        !           291: 
        !           292:     return ret;
        !           293: }
        !           294: 
        !           295: -(void)atapiInitParameters:(ideIdentifyInfo_t *)infoPtr 
        !           296:                Device:(unsigned char)unit
        !           297: {
        !           298:     atapiGenConfig_t *atapiGenConfig = 
        !           299:        (atapiGenConfig_t *) &infoPtr->genConfig;
        !           300:     
        !           301:     if (atapiGenConfig->cmdPacketSize == 0x01)
        !           302:        _atapiCmdLen[unit] = 16;
        !           303:     else
        !           304:        _atapiCmdLen[unit] = 12;
        !           305: 
        !           306:     /*
        !           307:      * The command len is 12. However some devices think it is 16 which is
        !           308:      * actually reserved for SAM compatibility. See page 58, SFF 8020, rev
        !           309:      * 1.2. This is a workaround.
        !           310:      */
        !           311:     if (_atapiCmdLen[unit] != 12)      
        !           312:     {
        !           313:        IOLog("%s: ATAPI: command len changed to 12 from %d.\n", 
        !           314:                [self name], _atapiCmdLen[unit]);
        !           315:        _atapiCmdLen[unit] = 12;
        !           316:     }
        !           317: 
        !           318:     _atapiCmdDrqType[unit] = atapiGenConfig->cmdDrqType;
        !           319: 
        !           320:     if (infoPtr->capabilities & IDE_CAP_DMA_SUPPORTED) 
        !           321:     {
        !           322:         if ( [self allocDmaMemory] == IDER_SUCCESS )
        !           323:         {
        !           324:             _dmaSupported[unit] = YES;
        !           325:         }
        !           326:     }
        !           327: 
        !           328:     [self getTransferModes:infoPtr Unit:unit];
        !           329: 
        !           330:     /*
        !           331:      * Set the Disk/CDROM transfer mode (Set Features SC=3) 
        !           332:      */
        !           333:     [self setTransferMode: unit]; 
        !           334: }
        !           335: 
        !           336: /*
        !           337:  * Identify ATAPI device must have been executed first before callling this
        !           338:  * method. 
        !           339:  */
        !           340: -(unsigned char)atapiCommandPacketSize:(unsigned char)unit
        !           341: {
        !           342:     if (unit < MAX_IDE_DRIVES)
        !           343:        return _atapiCmdLen[unit];
        !           344:     else
        !           345:        return 0;
        !           346: }
        !           347: 
        !           348: 
        !           349: /*
        !           350:  * The amount of time in milliseconds it takes for an ATAPI device to post
        !           351:  * its signature after a reset. Some CD-ROMs take a long time to respond. Do
        !           352:  * not decrease it without testing with various makes of ATAPI devices. 
        !           353:  */
        !           354: #define ATAPI_RESET_DELAY              2500
        !           355: 
        !           356: -(atapi_return_t)atapiSoftReset:(unsigned char)unit
        !           357: {
        !           358:     int  delay;
        !           359:     unsigned char status;
        !           360:     atapi_return_t rtn;
        !           361:     unsigned char dh = ADDRESS_MODE_LBA;       /* ALWAYS */
        !           362: 
        !           363:     _driveReset[unit] = YES;
        !           364: 
        !           365:     dh |= unit ? SEL_DRIVE1 : SEL_DRIVE0;
        !           366: 
        !           367:     outb(_ideRegsAddrs.driveSelect, dh);
        !           368:     outb(_ideRegsAddrs.command, ATAPI_SOFT_RESET);
        !           369: 
        !           370:     delay = ATAPI_RESET_DELAY;
        !           371:     
        !           372:     IOSleep(50);                       /* Enough time to assert busy */
        !           373:     
        !           374:     rtn = IDER_ERROR;
        !           375:     
        !           376:     while (delay > 0) 
        !           377:     {
        !           378:        status = inb(_ideRegsAddrs.status);
        !           379:        if (!(status & BUSY)) 
        !           380:         {
        !           381:            rtn = IDER_SUCCESS;
        !           382:             break;
        !           383:        }
        !           384:        
        !           385:        IOSleep(10);
        !           386:        delay -= 10;
        !           387:     }
        !           388: 
        !           389:     return rtn;
        !           390: }
        !           391: 
        !           392: 
        !           393: #define MAX_DRQ_WAIT           (1000 * 2)              // milliseconds
        !           394: 
        !           395: -(atapi_return_t)atapiPacketCommand
        !           396: {
        !           397:     int i;
        !           398:     atapi_return_t rtn;
        !           399:     unsigned char interruptReason;
        !           400:     unsigned char status;
        !           401:        
        !           402:     outb(_ideRegsAddrs.command, ATAPI_PACKET);
        !           403: 
        !           404:     /*
        !           405:      * Some devices might have interrupted so we should take care of that
        !           406:      * first.
        !           407:      */
        !           408:     if (_atapiCmdDrqType[_driveNum] == ATAPI_CMD_DRQ_INT) 
        !           409:     {
        !           410:        rtn = [self ideWaitForInterrupt:ATAPI_PACKET ideStatus:&status];
        !           411:     }
        !           412:     
        !           413:     /*
        !           414:      * Wait till we get okay from the device. 
        !           415:      */
        !           416:     for (i = 0; i < MAX_DRQ_WAIT; i++) 
        !           417:     {
        !           418:        interruptReason = inb(_ideRegsAddrs.interruptReason);
        !           419:        if ((interruptReason & CMD_OR_DATA) && !(interruptReason & IO_DIRECTION))
        !           420:            break;
        !           421:        IOSleep(1);
        !           422:     }
        !           423: 
        !           424:     if (i == MAX_DRQ_WAIT)     
        !           425:     {
        !           426:        IOLog("%s: ATAPI Device %d:  Invalid Interrupt Reason: %x.\n", 
        !           427:                [self name], _driveNum, interruptReason);
        !           428:        return IDER_ERROR;
        !           429:     }
        !           430: 
        !           431:     /*
        !           432:      * Now DRQ should be set. 
        !           433:      */
        !           434:     status = inb(_ideRegsAddrs.status);
        !           435:     if (status & DREQUEST)     
        !           436:     {
        !           437:        return IDER_SUCCESS;
        !           438:     }
        !           439:     
        !           440:     IOLog("%s: ATAPI Device %d: No Data Request: %x.\n", 
        !           441:                [self name], _driveNum, status);
        !           442:        
        !           443:     return IDER_ERROR;
        !           444: }
        !           445: 
        !           446: /*
        !           447:  * Note that the command is sent out as words in little endian format. 
        !           448:  */
        !           449: - (void) sendAtapiCommand:(unsigned char *)atapiCmd
        !           450:        cmdLen:(unsigned char)len
        !           451: {
        !           452:     int i;
        !           453:     
        !           454:     for (i = 0; i < len/2; i++)        
        !           455:     {
        !           456:        outw(_ideRegsAddrs.data, (atapiCmd[2*i] << 8) | atapiCmd[2*i+1]);
        !           457:     }
        !           458: }
        !           459: 
        !           460: /*
        !           461:  * Prints command and result in case of error. 
        !           462:  */
        !           463: - (void)dumpStatus:(atapiIoReq_t *)atapiIoReq
        !           464: {
        !           465:     int i;
        !           466:     
        !           467:     IOLog("%s: Failed command: drive: %d lun: %d len: %d read: %d\n", 
        !           468:        [self name], 
        !           469:        atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen, 
        !           470:        atapiIoReq->read);
        !           471:     IOLog("%s: Failed command: ", [self name]); 
        !           472:     for (i = 0; i < atapiIoReq->cmdLen; i++)
        !           473:        IOLog("%x ", atapiIoReq->atapiCmd[i]);
        !           474:     IOLog("\n");
        !           475:     
        !           476:     [self getIdeRegisters:NULL Print:"dumpStatus"];
        !           477: }
        !           478: 
        !           479: 
        !           480: #define        C10OP_MODESELECT        0x55    /* OPT: set device parameters */
        !           481: #define        C10OP_MODESENSE         0x5a    /* OPT: get device parameters */
        !           482: 
        !           483: #define MAX_SENDPACKET_RETRIES         3
        !           484: 
        !           485: #define MAX_BUSY_WAIT                  (1000*100)
        !           486: 
        !           487: - (sc_status_t) atapiExecuteCmd:(atapiIoReq_t *)atapiIoReq 
        !           488:                    buffer : (void *)buffer 
        !           489:                    client : (struct vm_map *)client
        !           490: {
        !           491:     int                i;
        !           492:     atapi_return_t     rtn;
        !           493:     unsigned int       offset;
        !           494:     unsigned char      dh = ADDRESS_MODE_LBA;  /* ALWAYS */
        !           495:     unsigned char       xferType;
        !           496:     BOOL               dmaAllowed;
        !           497:     
        !           498:     /*
        !           499:      * Reject command if there are no ATAPI devices detected. 
        !           500:      */
        !           501:      if ((atapiIoReq->drive >= MAX_IDE_DRIVES) || (atapiIoReq->lun != 0))  
        !           502:      {
        !           503:        return SR_IOST_SELTO;
        !           504:      }
        !           505:      
        !           506:      if ([self isAtapiDevice:atapiIoReq->drive] == NO) 
        !           507:      {
        !           508:        return SR_IOST_SELTO;
        !           509:      }
        !           510:          
        !           511:     [self clearInterrupts];
        !           512:     
        !           513:     _driveNum = atapiIoReq->drive;
        !           514: 
        !           515:     dmaAllowed = [self atapiDmaAllowed: buffer];
        !           516: 
        !           517:     if ( atapiIoReq->maxTransfer != 0 )
        !           518:     {
        !           519:         [self setTransferRate: _driveNum UseDMA:dmaAllowed];
        !           520:     }
        !           521: 
        !           522:     if ( _driveReset[_driveNum] == YES )
        !           523:     {
        !           524:         [self setTransferMode: _driveNum];
        !           525:         _driveReset[_driveNum] = NO;
        !           526:     }
        !           527: 
        !           528:     /* Now execute the SCSI command. */
        !           529: 
        !           530:     for (i = 0; i < MAX_SENDPACKET_RETRIES; i++)       
        !           531:     {
        !           532:        rtn = [self atapiWaitReadyForPacket];
        !           533:        if (rtn != IDER_SUCCESS) 
        !           534:         {
        !           535:            IOLog("%s: ATAPI Device %d: Not Ready For Packet command.\n", 
        !           536:                [self name], _driveNum);
        !           537:            [self atapiSoftReset:_driveNum];
        !           538:            continue;
        !           539:        }
        !           540:        
        !           541:        /*
        !           542:         * Select the drive first. 
        !           543:         */
        !           544:        dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
        !           545:        outb(_ideRegsAddrs.driveSelect, dh);
        !           546: 
        !           547:        /*
        !           548:         * Send our preferred data transfer size (2048 bytes). 
        !           549:         */
        !           550:        outb(_ideRegsAddrs.byteCountLow, 0x00);
        !           551:        outb(_ideRegsAddrs.byteCountHigh, 0x08);
        !           552: 
        !           553:        /*
        !           554:         * Set data transfer mode PIO = 0x00 / DMA = 0x01 
        !           555:         */
        !           556:         xferType = (dmaAllowed == YES) ? 0x01 : 0x00;
        !           557:        outb(_ideRegsAddrs.features, xferType);
        !           558:        
        !           559:        /*
        !           560:         * First tell the ATAPI device that we are going to send it a packet
        !           561:         * command. If this command fails the ATAPI device needs to be reset. 
        !           562:         */
        !           563:        if ([self atapiPacketCommand] == IDER_SUCCESS)  
        !           564:         {
        !           565:            break;
        !           566:        }
        !           567:        
        !           568:        IOLog("%s: ATAPI Device %d: Packet command failed. Retrying...\n",
        !           569:                 [self name], _driveNum);
        !           570:        [self atapiSoftReset:_driveNum];
        !           571:     }
        !           572: 
        !           573:     /*
        !           574:      * Are we hosed? 
        !           575:      */
        !           576:     if (i == MAX_SENDPACKET_RETRIES)   
        !           577:     {
        !           578:        atapiIoReq->scsiStatus = STAT_CHECK;
        !           579:        IOLog("%s: ATAPI Device %d: FATAL: Packet command.\n", 
        !           580:                [self name], _driveNum);
        !           581:        return SR_IOST_CMDREJ;    
        !           582:     }
        !           583:     
        !           584:     /*
        !           585:      * Send the actual command to the device. 
        !           586:      */
        !           587:     [self sendAtapiCommand:atapiIoReq->atapiCmd cmdLen:atapiIoReq->cmdLen];
        !           588: 
        !           589:     atapiIoReq->bytesTransferred = 0;
        !           590:     offset = 0;
        !           591:     
        !           592:     [self enableInterrupts];
        !           593: 
        !           594:     if ( dmaAllowed == YES )
        !           595:     {
        !           596:         rtn = [self atapiXferDMA:(atapiIoReq_t *)atapiIoReq  buffer: (void *)buffer client: (struct vm_map *)client];
        !           597:     }
        !           598:     else
        !           599:     {
        !           600:         rtn =[self atapiXferPIO:(atapiIoReq_t *)atapiIoReq  buffer: (void *)buffer client: (struct vm_map *)client];
        !           601:     }
        !           602: 
        !           603: #if 0
        !           604:         kprintf("Disk(ATAPI): Cmd = %02x Length = %08x Addr=%08x:%08x Status = %d\n\r", 
        !           605:                atapiIoReq->atapiCmd[0], (int)atapiIoReq->maxTransfer, (int)buffer, (int)client, 
        !           606:                rtn);
        !           607: #endif   
        !           608: 
        !           609:     return rtn;
        !           610: }
        !           611: 
        !           612: - (sc_status_t) atapiXferPIO:(atapiIoReq_t *)atapiIoReq 
        !           613:                    buffer : (void *)buffer 
        !           614:                    client : (struct vm_map *)client
        !           615: {
        !           616:     int                i;
        !           617:     atapi_return_t     rtn;
        !           618:     unsigned char      status;
        !           619:     unsigned int       bytes;
        !           620:     unsigned int       offset = 0;
        !           621:     unsigned char      cmd = atapiIoReq->atapiCmd[0];
        !           622: 
        !           623:     for (;;)   
        !           624:     {
        !           625:        rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
        !           626: 
        !           627:        if (rtn != IDER_SUCCESS) 
        !           628:         {
        !           629:            IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n", 
        !           630:                [self name], _driveNum, atapiIoReq->atapiCmd[0]);
        !           631:            [self getIdeRegisters:NULL Print:"ATAPI Command"];
        !           632:            [self atapiSoftReset:_driveNum];
        !           633:            atapiIoReq->scsiStatus = STAT_CHECK;
        !           634:            return SR_IOST_CHKSNV;
        !           635:        }
        !           636: 
        !           637:        for (i = 0; i < MAX_BUSY_WAIT; i++)     
        !           638:         {
        !           639:            if (status & BUSY)  
        !           640:             {
        !           641:                IODelay(10);
        !           642:            } 
        !           643:             else 
        !           644:             {
        !           645:                break;
        !           646:            }
        !           647:            status = inb(_ideRegsAddrs.status); 
        !           648:        }
        !           649:        
        !           650:        /*
        !           651:         * If DRQ == 0 then host has terminated the command. 
        !           652:         */
        !           653:        if (!(status & DREQUEST))       
        !           654:         {
        !           655:            /*
        !           656:             * Check for command completion status. 
        !           657:             */
        !           658:            if (status & ERROR) 
        !           659:             {              
        !           660:                atapiIoReq->scsiStatus = STAT_CHECK;
        !           661:                return SR_IOST_CHKSNV;
        !           662:            } 
        !           663:             else 
        !           664:             {
        !           665:                atapiIoReq->scsiStatus = STAT_GOOD;
        !           666:                return SR_IOST_GOOD;
        !           667:            }
        !           668:        }
        !           669: 
        !           670:        /*
        !           671:         * Command is not completed. We need to transfer data as requested by
        !           672:         * the device. 
        !           673:         */
        !           674:        bytes =  inb(_ideRegsAddrs.byteCountHigh) << 8 | 
        !           675:            inb(_ideRegsAddrs.byteCountLow);
        !           676: 
        !           677:        /*
        !           678:         * If the device requests more data to be transferred than required
        !           679:         * by the command protocol, then we should transfer null data. 
        !           680:         */
        !           681: 
        !           682:        
        !           683:        if (atapiIoReq->bytesTransferred + bytes > atapiIoReq->maxTransfer)
        !           684:         {
        !           685:            IOLog("%s: ATAPI Device %d: "
        !           686:                "ERROR: Transfer limit (%x bytes) exceeded\n", 
        !           687:                [self name], _driveNum, atapiIoReq->maxTransfer);
        !           688:                
        !           689:            IOLog("%s: Bytes already transfered: %x, next request: %x\n", 
        !           690:                [self name], atapiIoReq->bytesTransferred, bytes);
        !           691:            
        !           692:            [self dumpStatus: atapiIoReq];
        !           693: 
        !           694:            /*
        !           695:             * This thing is probably hosed but let's do the best we can. 
        !           696:             */
        !           697:            {
        !           698:            int diff = atapiIoReq->maxTransfer-atapiIoReq->bytesTransferred;
        !           699:            IOLog("%s: Transferring %x bytes instead of %x\n", 
        !           700:                [self name], diff, bytes);
        !           701:            [self xferData:buffer+offset read:atapiIoReq->read 
        !           702:                    client:client length:diff];
        !           703:            atapiIoReq->bytesTransferred += diff;
        !           704:            offset += diff;
        !           705:            [self atapiSoftReset:_driveNum];    // reset hardware as well
        !           706:            }
        !           707:            
        !           708:            atapiIoReq->scsiStatus = STAT_GOOD;
        !           709:            return SR_IOST_GOOD;            
        !           710:        }
        !           711:        
        !           712:        /*
        !           713:         * Now transfer data from device to memory. 
        !           714:         */
        !           715:        [self xferData:buffer+offset read:atapiIoReq->read client:client 
        !           716:                length:bytes];
        !           717:        
        !           718:        atapiIoReq->bytesTransferred += bytes;
        !           719:        offset += bytes;
        !           720:     }
        !           721: 
        !           722:     /*
        !           723:      * Will never get here. 
        !           724:      */
        !           725:     atapiIoReq->scsiStatus = STAT_GOOD;
        !           726:     return SR_IOST_GOOD;
        !           727: }
        !           728: 
        !           729: 
        !           730: - (sc_status_t) atapiXferDMA:(atapiIoReq_t *)atapiIoReq 
        !           731:                    buffer : (void *)buffer 
        !           732:                    client : (struct vm_map *)client
        !           733: {
        !           734:     int                i;
        !           735:     atapi_return_t     rtn;
        !           736:     unsigned char      status;
        !           737:     unsigned char      cmd = atapiIoReq->atapiCmd[0];
        !           738:     unsigned long      cfgReg;
        !           739: 
        !           740:     [self setupDMA:(vm_offset_t) buffer client:(vm_task_t) client length:(int)atapiIoReq->maxTransfer fRead:(BOOL)atapiIoReq->read]; 
        !           741:     if ( _controllerType != kControllerTypeCmd646X )
        !           742:     {
        !           743:         IODBDMAContinue( _ideDMARegs );        
        !           744:     }
        !           745:     else
        !           746:     {
        !           747:         [[self deviceDescription] configReadLong:0x70 value: &cfgReg];
        !           748:         cfgReg &= ~0x08;
        !           749:         cfgReg |= 0x01 | ((atapiIoReq->read) ? 0x08 : 0x00);
        !           750:         [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
        !           751:     }
        !           752: 
        !           753:     rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
        !           754: 
        !           755:     if (rtn != IDER_SUCCESS) 
        !           756:     {
        !           757:        IOLog("%s: FATAL: ATAPI Device: %d Command %x failed.\n", [self name], _driveNum, atapiIoReq->atapiCmd[0]);
        !           758:        [self getIdeRegisters:NULL Print:"ATAPI Command"];
        !           759:        [self atapiSoftReset:_driveNum];
        !           760:        atapiIoReq->scsiStatus = STAT_CHECK;
        !           761:        return SR_IOST_CHKSNV;
        !           762:     }
        !           763: 
        !           764:     for (i = 0; i < MAX_BUSY_WAIT; i++)        
        !           765:     {
        !           766:        if (status & BUSY)      
        !           767:         {
        !           768:             IODelay(10);
        !           769:        } 
        !           770:         else 
        !           771:         {
        !           772:            break;
        !           773:        }
        !           774:         status    = inb(_ideRegsAddrs.status);
        !           775:     }
        !           776: 
        !           777:     if ( _controllerType != kControllerTypeCmd646X )
        !           778:     {
        !           779:         atapiIoReq->bytesTransferred = [self stopDBDMA];
        !           780:     }
        !           781:     else
        !           782:     {
        !           783:         [[self deviceDescription] configReadLong: 0x70 value: &cfgReg];
        !           784:         cfgReg &= ~0x01;
        !           785:         [[self deviceDescription] configWriteLong:0x70 value: cfgReg];
        !           786: 
        !           787:         atapiIoReq->bytesTransferred = atapiIoReq->maxTransfer;
        !           788:     }
        !           789: 
        !           790:     /*
        !           791:      * The DMA has handled all the data movement. 
        !           792:      * Must have final command status at this point. 
        !           793:      */
        !           794:      if ( status & (ERROR) )   
        !           795:      {             
        !           796:          atapiIoReq->scsiStatus = STAT_CHECK;
        !           797:          return SR_IOST_CHKSNV;
        !           798:      } 
        !           799:      else 
        !           800:      {
        !           801:          atapiIoReq->scsiStatus = STAT_GOOD;
        !           802:          return SR_IOST_GOOD;
        !           803:      }
        !           804: }     
        !           805:   
        !           806: - (BOOL) atapiDmaAllowed: (void *)buffer
        !           807: {
        !           808:     if ( _dmaSupported[_driveNum] == NO ) 
        !           809:     {
        !           810:         return NO;
        !           811:     }
        !           812:     
        !           813:     if ( (_controllerType == kControllerTypeCmd646X) && ((u_int)buffer & 1) )
        !           814:     {
        !           815:         return NO;
        !           816:     }
        !           817: 
        !           818:     return YES;
        !           819: }
        !           820:         
        !           821:       
        !           822: @end

unix.superglobalmegacorp.com

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