Annotation of drvEIDE/EIDE.drvproj/EIDE.lksproj/AtapiCntCmds.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.0 (the 'License').  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License."
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: /*
                     25:  * Copyright 1997-1998 by Apple Computer, Inc., All rights reserved.
                     26:  * Copyright 1994-1997 NeXT Software, Inc., All rights reserved.
                     27:  *
                     28:  * AtapiCntCmds.m - ATAPI command implementation for ATA interface. 
                     29:  *
                     30:  * HISTORY 
                     31:  *
                     32:  * 4-Jan-1998  Joe Liu at Apple
                     33:  *             Merged the various wait routines into a single routine.
                     34:  *             Wait routine now sleeps longer to generate a more accurate wait
                     35:  *             interval.
                     36:  *             Check the BSY bit before sending the packet command.
                     37:  *             Detect shadow/phantom drives and timeout more quickly.
                     38:  *             Sprinkled some IODelays before checking the BSY bit. Since according
                     39:  *             to the spec, a drive may take up to 400ns to set the BSY bit, and
                     40:  *             we don't want to read it before it has enough time to assert itself.
                     41:  *
                     42:  * 3-Sep-1996  Becky Divinski at NeXT
                     43:  *             Moved LBA, IORDY, and buffer capabilities out
                     44:  *             from under DEBUG statements, so they will
                     45:  *             always print out during startup.
                     46:  *
                     47:  * 13-Feb-1996         Rakesh Dubey at NeXT
                     48:  *      More resistant to broken firmwares. 
                     49:  *
                     50:  * 13-Jul-1995         Rakesh Dubey at NeXT
                     51:  *      Improved device detection and log messages. 
                     52:  *
                     53:  * 1-Sep-1994   Rakesh Dubey at NeXT
                     54:  *     Created.
                     55:  */
                     56: 
                     57: #import "AtapiCntCmds.h"
                     58: #import "IdePIIX.h"
                     59: 
                     60: //#define DEBUG
                     61: 
                     62: /*
                     63:  * Max timeout while waiting for BSY == 0.
                     64:  */
                     65: #define ATAPI_MAX_WAIT_FOR_NOTBUSY             (5 * 1000)              // 5 secs
                     66: 
                     67: @implementation IdeController(ATAPI)
                     68: 
                     69: /*
                     70:  * Method: atapiWaitStatusBitsFor:on:off:alt:
                     71:  *
                     72:  * General purpose wait routine. Wait for BSY bit in the Status/AltStatus
                     73:  * register to clear, then make sure that the "on" bits are set, and the
                     74:  * "off" bits are cleared in the status register.
                     75:  *
                     76:  * The routine busy waits for an initial count, then it uses IOSleeps to
                     77:  * do non-blocking delays. IOSleep() has a minimum delay of around 15ms.
                     78:  * Anything smaller will yield a longer than expected delay.
                     79:  *
                     80:  * Arguments:
                     81:  *  timeout    - How long to wait for BSY bit to clear in milliseconds.
                     82:  *  on         - Set bit mask.
                     83:  *  off                - Cleared bit mask (BSY bit is implicitly checked).
                     84:  *  alt                - YES to poll using AltStatus instead of Status register.
                     85:  *
                     86:  * Returns:
                     87:  *  IDER_SUCCESS - successful completion.
                     88:  *  IDER_TIMEOUT - timeout or bits check failed.
                     89:  *
                     90:  */
                     91: 
                     92: #define ATAPI_WAIT_DELAYS              5               // how many initial 1ms busy waits
                     93: #define ATAPI_SLEEP_DURATION   20              // how long to sleep using IOSleep
                     94: 
                     95: - (atapi_return_t) atapiWaitStatusBitsFor:(unsigned int)timeout
                     96:        on:(unsigned char)on
                     97:        off:(unsigned char)off
                     98:        alt:(BOOL)alt
                     99: {
                    100:     unsigned char status;
                    101:     int  delays = ATAPI_WAIT_DELAYS;
                    102:        
                    103:        if (timeout == 0)
                    104:                return IDER_TIMEOUT;
                    105:        
                    106:        IODelay(1);     /* give the drive 400ns to assert BSY bit */
                    107:        do {
                    108:                status = alt ? inb(_ideRegsAddrs.altStatus) :
                    109:                                           inb(_ideRegsAddrs.status);
                    110:                if (!(status & BUSY))
                    111:                        break;
                    112:                if (delays-- > 0) {     // use IODelay for initial wait
                    113:                        IODelay(1000);  // busy-wait for 1ms
                    114:                        timeout--;
                    115:                }
                    116:                else {                          // too long, use IOSleep instead
                    117:                        int sleep_interval = ATAPI_SLEEP_DURATION;
                    118:                        if (timeout < sleep_interval)
                    119:                                sleep_interval = timeout;
                    120:                        IOSleep(sleep_interval);
                    121:                        timeout -= sleep_interval;
                    122:                }
                    123:        } while (timeout > 0);
                    124:        if (timeout == 0)
                    125:                return IDER_TIMEOUT;
                    126: 
                    127:        IODelay(1);     /* give the drive another 400ns to update Status Register */
                    128:        if (((status & on) == on) && ((~status & off) == off))
                    129:                return IDER_SUCCESS;
                    130: 
                    131:        return IDER_TIMEOUT;
                    132: }
                    133: 
                    134: - (void) printAtapiInfo:(ideIdentifyInfo_t *)ideIdentifyInfo 
                    135:                        Device:(unsigned char)unit
                    136: {
                    137:     int i;
                    138:     char name[50];
                    139:     char firmware[9];
                    140:     atapiGenConfig_t *atapiGenConfig;
                    141:     char *protocolTypeStr, *deviceTypeStr, *cmdDrqTypeStr;
                    142:     char *removableStr, *cmdPacketSizeStr;
                    143: 
                    144:        // IOLog("Capability: %04x\n", ideIdentifyInfo->capabilities);
                    145: 
                    146:     /*
                    147:      * Print drive name with firmware revision number after doing byte swaps. 
                    148:      */
                    149:     for (i = 0; i < 20; i++)   {
                    150:        name[2*i] = ideIdentifyInfo->modelNumber[2*i+1];
                    151:        name[2*i+1] = ideIdentifyInfo->modelNumber[2*i];
                    152:     }
                    153:     name[40] = '\0';
                    154:     
                    155:     for (i = 0; i < 4; i++)    {
                    156:        firmware[2*i] = ideIdentifyInfo->firmwareRevision[2*i+1];
                    157:        firmware[2*i+1] = ideIdentifyInfo->firmwareRevision[2*i];
                    158:     }
                    159:     firmware[8] = '\0';
                    160:     
                    161:     for (i = 38; i >= 0; i--)  {
                    162:        if (name[i] != ' ')
                    163:            break;
                    164:     }
                    165:     strcpy(name+i+2, firmware);
                    166:     
                    167: #ifdef DEBUG
                    168:     IOLog("%s: %s\n", [self name], name);
                    169: #endif DEBUG
                    170: 
                    171:     /*
                    172:      * This information should be printed since it is not duplicated
                    173:      * elsewhere. 
                    174:      */
                    175:     atapiGenConfig = (atapiGenConfig_t *) &ideIdentifyInfo->genConfig;
                    176:     
                    177: #ifdef undef
                    178:     IOLog("%s: gen config: %x\n", [self name], ideIdentifyInfo->genConfig);
                    179: #endif undef
                    180:     
                    181:     if (atapiGenConfig->protocolType == 0 || atapiGenConfig->protocolType == 1)
                    182:        protocolTypeStr = "ATA";
                    183:     else if (atapiGenConfig->protocolType == 2)
                    184:        protocolTypeStr = "ATAPI";
                    185:     else 
                    186:        protocolTypeStr = "UNKNOWN PROTOCOL";
                    187:        
                    188:     if (atapiGenConfig->deviceType == 0)
                    189:        deviceTypeStr = "DIRECT ACCESS";
                    190:     else if (atapiGenConfig->deviceType == 5)
                    191:        deviceTypeStr = "CD-ROM";
                    192:     else if (atapiGenConfig->deviceType == 7)
                    193:        deviceTypeStr = "OPTICAL";
                    194:     else if (atapiGenConfig->deviceType == 1)
                    195:        deviceTypeStr = "TAPE";
                    196:     else
                    197:        deviceTypeStr = "UNKNOWN DEVICE TYPE";
                    198:        
                    199:     if (atapiGenConfig->cmdDrqType == 0)
                    200:        cmdDrqTypeStr = "SLOW DRQ";
                    201:     else if (atapiGenConfig->cmdDrqType == 1)
                    202:        cmdDrqTypeStr = "INTR DRQ";
                    203:     else if (atapiGenConfig->cmdDrqType == 2)
                    204:        cmdDrqTypeStr = "FAST DRQ";
                    205:     else 
                    206:        cmdDrqTypeStr = "UNKNOWN DRQ TYPE";
                    207:        
                    208:     if (atapiGenConfig->removable == 0)
                    209:        removableStr = "NOT REMOVABLE";
                    210:     else if (atapiGenConfig->removable == 1)
                    211:        removableStr = "REMOVABLE";
                    212:     
                    213:     if (atapiGenConfig->cmdPacketSize == 0)
                    214:        cmdPacketSizeStr = "CMD PKT LEN=12";
                    215:     else if (atapiGenConfig->cmdPacketSize == 1)
                    216:        cmdPacketSizeStr = "CMD PKT LEN=16";
                    217:     else 
                    218:        cmdPacketSizeStr = "CMD PKT LEN=UNKNOWN";
                    219:        
                    220: 
                    221:     IOLog("%s: Drive %d: %s %s (%s, %s, %s)\n", [self name], unit,
                    222:                protocolTypeStr, 
                    223:                deviceTypeStr, cmdDrqTypeStr,
                    224:                removableStr, cmdPacketSizeStr);
                    225: 
                    226: #ifdef DEBUG  
                    227:     if (ideIdentifyInfo->capabilities & IDE_CAP_LBA_SUPPORTED) {
                    228:        IOLog("%s: LBA supported.\n", [self name]); 
                    229:     }
                    230:     if (ideIdentifyInfo->capabilities & IDE_CAP_IORDY_SUPPORTED)       {
                    231:        IOLog("%s: IORDY supported.\n", [self name]); 
                    232:     }
                    233: 
                    234:     if (ideIdentifyInfo->bufferType != 0)      {
                    235:        IOLog("%s: buffer type %d, %d sectors.\n", [self name],
                    236:                ideIdentifyInfo->bufferType, ideIdentifyInfo->bufferSize);
                    237:     }
                    238:  
                    239:     IOLog("%s: PIO timing cycle: %d ns.\n", [self name],
                    240:            ideIdentifyInfo->pioDataTransferCyleTimingMode &
                    241:            IDE_PIO_TIMING_MODE_MASK);
                    242: 
                    243:     if (ideIdentifyInfo->capabilities & IDE_CAP_DMA_SUPPORTED) {
                    244:         IOLog("%s: DMA timing cycle: %d ns.\n", [self name],
                    245:                ideIdentifyInfo->dmaDataTransferCyleTimingMode &
                    246:                IDE_DMA_TIMING_MODE_MASK);
                    247:     }
                    248: 
                    249: #endif DEBUG
                    250: }
                    251: 
                    252: /*
                    253:  * There are lots of ATAPI CD-ROMs that shadow the task file register and
                    254:  * hence show up as two devices. They also might issue a valid interrupt when
                    255:  * ATAPI Identify Device command is sent so we need to really make sure
                    256:  * whether the device has data for us. 
                    257:  */
                    258: - (atapi_return_t) _atapiIdentifyDevice:(struct vm_map *)client
                    259:                                addr:(caddr_t)xferAddr
                    260: {
                    261:     unsigned int cmd = ATAPI_IDENTIFY_DRIVE;
                    262:     unsigned char dh = ADDRESS_MODE_LBA;       /* ALWAYS */
                    263:     unsigned char status;
                    264:     atapi_return_t rtn;
                    265:     
                    266:     unsigned int oldTimeout;
                    267: 
                    268: #ifdef DEBUG    
                    269:     IOLog("ATAPI Identify Device\n");
                    270: #endif DEBUG
                    271: 
                    272:        rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
                    273:                        on:0 off:0 alt:NO];
                    274:     if (rtn != IDER_SUCCESS)
                    275:                return (rtn);
                    276:     
                    277:     dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
                    278:     outb(_ideRegsAddrs.driveSelect, dh);
                    279:     
                    280:     bzero(xferAddr, IDE_SECTOR_SIZE);
                    281:     
                    282:     [self enableInterrupts];
                    283:        [self clearInterrupts];
                    284:        
                    285:     outb(_ideRegsAddrs.command, ATAPI_IDENTIFY_DRIVE);
                    286: 
                    287:        /* Wait for BSY bit to clear before reading from AltStatus.
                    288:         * We do this to avoid a long interrupt timeout when probing
                    289:         * "phantom" CD-ROM drives shadowed by another device on the same
                    290:         * IDE connector.
                    291:        /* Read from AltStatus instead of Status register to avoid
                    292:         * ack'ing any pending interrupts.
                    293:         */
                    294:        rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
                    295:                        on:0 off:0 alt:YES];
                    296:     if (rtn != IDER_SUCCESS) {
                    297:                IOLog("%s: Polling BSY bit timed-out\n", [self name]);
                    298:                return (rtn);
                    299:     }
                    300: 
                    301:        /* Shadow (false) devices should set the ABORT bit in the ATA
                    302:         * Error register. We check for ABORT bit and return an error
                    303:         * if that bit is set.
                    304:         */
                    305:        if ((inb(_ideRegsAddrs.altStatus) & ERROR) &&
                    306:                (inb(_ideRegsAddrs.error) & CMD_ABORTED)) {
                    307:                // Don't bother waiting for an interrupt, abort immediately.
                    308: #ifdef DEBUG
                    309:                IOLog("%s: Phantom ATAPI drive detected. Status:0x%02x\n",
                    310:                        [self name], inb(_ideRegsAddrs.altStatus));
                    311: #endif DEBUG
                    312:                return IDER_ERROR;
                    313:        }
                    314: 
                    315:     oldTimeout = [self interruptTimeOut];
                    316:     [self setInterruptTimeOut:4000];           // four seconds
                    317:     rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
                    318:        [self setInterruptTimeOut:oldTimeout];
                    319: 
                    320:     if (rtn != IDER_SUCCESS) {
                    321:                [self getIdeRegisters:NULL Print:"Atapi Identify"];
                    322:                return (rtn);
                    323:     }
                    324:                
                    325:        // Make sure DRQ is set
                    326:        rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
                    327:                        on:DREQUEST off:0 alt:NO];
                    328:     if (rtn != IDER_SUCCESS)
                    329:                return (rtn);
                    330:        
                    331:     /*
                    332:      * FIXME: We need to do some sanity check on this data to be really sure
                    333:      * that there is an ATAPI device out here. 
                    334:      */
                    335:     [self xferData:xferAddr read:YES client:client length:IDE_SECTOR_SIZE];
                    336:     return IDER_SUCCESS;
                    337: }
                    338: 
                    339: /*
                    340:  * Some CD-ROMS (like SONY CDU-55D) fail the first request so we reset the
                    341:  * device and retry. 
                    342:  */
                    343: #define ATAPI_IDENTIFY_DEVICE_RETRIES          3
                    344: 
                    345: - (atapi_return_t) atapiIdentifyDevice:(struct vm_map *)client
                    346:                                addr:(caddr_t)xferAddr
                    347:                                unit:(unsigned char)unit
                    348: {
                    349:     int i;
                    350:     atapi_return_t ret;
                    351:     
                    352:     for (i = 0; i < ATAPI_IDENTIFY_DEVICE_RETRIES; i++)        {
                    353:     
                    354:                ret = [self _atapiIdentifyDevice:client addr:xferAddr];
                    355:                if (ret == IDER_SUCCESS)
                    356:                break;
                    357:                
                    358:                /* Reset hardware and try again */
                    359:                [self atapiSoftReset:unit];
                    360:                IOSleep(500);
                    361:                if (_ide_debug) {
                    362:                IOLog("%s: Drive %d: ATAPI Identify Device failed "
                    363:                        "(error %d). Retrying..\n", [self name], unit, ret);
                    364:                }
                    365:     }
                    366: #ifdef DEBUG
                    367:     if (i == ATAPI_IDENTIFY_DEVICE_RETRIES)    {
                    368:                IOLog("%s: FATAL: Drive %d: ATAPI Identify Device.\n", 
                    369:                [self name], unit);
                    370:     }
                    371: #endif DEBUG
                    372:     return ret;
                    373: }
                    374: 
                    375: - (void) atapiInitParameters:(ideIdentifyInfo_t *)infoPtr 
                    376:                Device:(unsigned char)unit
                    377: {
                    378:     atapiGenConfig_t *atapiGenConfig = 
                    379:        (atapiGenConfig_t *) &infoPtr->genConfig;
                    380:     
                    381:     if (atapiGenConfig->cmdPacketSize == 0x01)
                    382:                _drives[unit].atapiCmdLen = 16;
                    383:     else
                    384:        _drives[unit].atapiCmdLen = 12;
                    385: 
                    386:     /*
                    387:      * The command len is 12. However some devices think it is 16 which is
                    388:      * actually reserved for SAM compatibility. See page 58, SFF 8020, rev
                    389:      * 1.2. This is a workaround.
                    390:      */
                    391:     if (_drives[unit].atapiCmdLen != 12)       {
                    392:        IOLog("%s: ATAPI: command len changed to 12 from %d.\n", 
                    393:                [self name], _drives[unit].atapiCmdLen);
                    394:        _drives[unit].atapiCmdLen = 12;
                    395:     }
                    396: 
                    397:     _drives[unit].atapiCmdDrqType = atapiGenConfig->cmdDrqType;
                    398: }
                    399: 
                    400: /*
                    401:  * Identify ATAPI device must have been executed first before callling this
                    402:  * method. 
                    403:  */
                    404: - (unsigned char) atapiCommandPacketSize:(unsigned char)unit
                    405: {
                    406:     if (unit < MAX_IDE_DRIVES)
                    407:        return _drives[unit].atapiCmdLen;
                    408:     else
                    409:        return 0;
                    410: }
                    411: 
                    412: 
                    413: /*
                    414:  * The amount of time in milliseconds it takes for an ATAPI device to post
                    415:  * its signature after a reset. Some CD-ROMs take a long time to respond. Do
                    416:  * not decrease it without testing with various makes of ATAPI devices. 
                    417:  */
                    418: #define ATAPI_RESET_DELAY              2500
                    419: 
                    420: - (atapi_return_t) atapiSoftReset:(unsigned char)unit
                    421: {
                    422:     unsigned char dh = ADDRESS_MODE_LBA;       /* ALWAYS */
                    423: 
                    424: #ifdef DEBUG
                    425:     IOLog("%s: atapiSoftReset:device %d\n", [self name], unit);
                    426: #endif DEBUG
                    427: 
                    428:     dh |= unit ? SEL_DRIVE1 : SEL_DRIVE0;
                    429: 
                    430:     outb(_ideRegsAddrs.driveSelect, dh);
                    431:     outb(_ideRegsAddrs.command, ATAPI_SOFT_RESET);
                    432:     
                    433:     IOSleep(50);       /* Enough time to assert busy */
                    434: 
                    435:        if ([self atapiWaitStatusBitsFor:ATAPI_RESET_DELAY on:0 off:0 alt:NO] ==
                    436:                IDER_SUCCESS)
                    437:                return IDER_SUCCESS;
                    438: 
                    439: #ifdef DEBUG
                    440:     IOLog("%s: atapiSoftReset: FAILED. Status = %x\n", [self name], status);
                    441: #endif DEBUG
                    442: 
                    443:     return IDER_ERROR;
                    444: }
                    445: 
                    446: /*
                    447:  * Method: issuePacketCommand
                    448:  *
                    449:  * This method will issue the Packet Command code (0xA0) to the command
                    450:  * register. Then wait for an interrupt (INT DRQ devices only) and poll
                    451:  * the Ireason/Status for:
                    452:  *
                    453:  *  BSY = 0
                    454:  *  CoD = 1
                    455:  *  IO  = 0
                    456:  *
                    457:  * We assume that the task file has been initialized prior to calling
                    458:  * this method.
                    459:  *
                    460:  * Returns:
                    461:  *  IDER_SUCCESS - DRQ is set and ready to send the 12-byte command.
                    462:  *  IDER_ERROR   - Abort and send a ATAPI soft reset.
                    463:  */
                    464: #define MAX_DRQ_WAIT           (100 * 1000 * 5)        // 5 second wait
                    465: 
                    466: - (atapi_return_t) issuePacketCommand
                    467: {
                    468:     int i;
                    469:     unsigned char interruptReason;
                    470:     unsigned char status;
                    471:        
                    472: #ifdef DEBUG    
                    473:     IOLog("%s: issuePacketCommand\n", [self name]);
                    474: #endif DEBUG
                    475: 
                    476:        /*
                    477:         * Send the packet command.
                    478:         */
                    479:     outb(_ideRegsAddrs.command, ATAPI_PACKET);
                    480: 
                    481:     /*
                    482:      * Some devices might have interrupted so we should take care of that
                    483:      * first.
                    484:      */
                    485:     if (_drives[_driveNum].atapiCmdDrqType == ATAPI_CMD_DRQ_INT) {
                    486:            atapi_return_t rtn;
                    487:                rtn = [self ideWaitForInterrupt:ATAPI_PACKET ideStatus:&status];
                    488:                if (rtn != IDER_SUCCESS)
                    489:                        return rtn;
                    490:     }
                    491:     
                    492:     /*
                    493:      * Wait till we get okay from the device. 
                    494:      */
                    495:        IODelay(1);
                    496:     for (i = 0; i < MAX_DRQ_WAIT; i++) {
                    497:                interruptReason = inb(_ideRegsAddrs.interruptReason);
                    498:                status = inb(_ideRegsAddrs.status);
                    499:                
                    500:                if (!(status & BUSY) &&
                    501:                        (interruptReason & CMD_OR_DATA) &&
                    502:                        !(interruptReason & IO_DIRECTION))
                    503:                        break;
                    504:                IODelay(10);
                    505:     }
                    506: 
                    507:     if (i == MAX_DRQ_WAIT)     {
                    508:                IOLog("%s: ATAPI Drive %d:  Invalid Interrupt Reason: %x.\n", 
                    509:                        [self name], _driveNum, interruptReason);
                    510:                return IDER_ERROR;
                    511:     }
                    512: 
                    513:     /*
                    514:      * Now DRQ should be set. 
                    515:      */
                    516:     status = inb(_ideRegsAddrs.status);
                    517:     if (status & DREQUEST) {
                    518:                return IDER_SUCCESS;
                    519:     }
                    520:     
                    521:     IOLog("%s: ATAPI Drive %d: DRQ not set: %x\n", 
                    522:                [self name], _driveNum, status);
                    523:     return IDER_ERROR;
                    524: }
                    525: 
                    526: /*
                    527:  * Method: sendAtapiCommand:cmdLen:
                    528:  *
                    529:  * Send the ATAPI command packet bytes.
                    530:  * Note that the command is sent out as words in little endian format. 
                    531:  */
                    532: - (void) sendAtapiCommand:(unsigned char *)atapiCmd
                    533:        cmdLen:(unsigned char)len
                    534: {
                    535:     int i;
                    536:     
                    537:     for (i = 0; i < len/2; i++)        {
                    538:        outw(_ideRegsAddrs.data, atapiCmd[2*i+1] << 8 | atapiCmd[2*i]);
                    539:     }
                    540: }
                    541: 
                    542: #define MAX_SENDPACKET_RETRIES         3
                    543: #define MAX_BUSY_WAIT                          (1000*100)
                    544: 
                    545: /*
                    546:  * Transfer data between host and the ATAPI device through PIO.
                    547:  *
                    548:  * Before calling this method, the packet command and command data bytes
                    549:  * have been issued to the drive. This method will transfer data until
                    550:  * DRQ = 0, or if the maximum transfer count is reached, whichever
                    551:  * occurs first. This method will require an interrupt for every iteration
                    552:  * of the loop.
                    553:  */
                    554: - (sc_status_t) atapiPIODataTransfer:(atapiIoReq_t *)atapiIoReq 
                    555:                        buffer:(void *)buffer 
                    556:                        client:(struct vm_map *)client
                    557: {
                    558:     int i;
                    559:     atapi_return_t rtn;
                    560:     unsigned char status;
                    561:     unsigned int offset;
                    562:     unsigned char cmd = atapiIoReq->atapiCmd[0];
                    563:     unsigned int bytes;
                    564:        
                    565:        /*
                    566:         * Zero the counters.
                    567:         */
                    568:     atapiIoReq->bytesTransferred = 0;
                    569:     offset = 0;
                    570:        
                    571:     for (;;) {
                    572:     
                    573:                /* At this point, the drive is executing the packet command.
                    574:                        * For commands such as FORMAT_UNIT (0x04), the may take a very
                    575:                        * long time. Probably much longer than IDE_INTR_TIMEOUT.
                    576:                        *
                    577:                        * To guard against those cases, we take the maximum of
                    578:                        * IDE_INTR_TIMEOUT vs. scsiReq.timeout.
                    579:                        */
                    580:                if (atapiIoReq->timeout > IDE_INTR_TIMEOUT) {
                    581:                        u_int current_timeout = [self interruptTimeOut];
                    582:                        
                    583:                        //IOLog("using SCSI timeout:%d\n", atapiIoReq->timeout);
                    584:                        [self setInterruptTimeOut:atapiIoReq->timeout];
                    585:                        rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
                    586:                        [self setInterruptTimeOut:current_timeout];
                    587:                }
                    588:                else {
                    589:                        rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
                    590:                }
                    591:        
                    592:                if (rtn != IDER_SUCCESS) {
                    593:                        IOLog("%s: FATAL: ATAPI Drive: %d Command %x failed.\n", 
                    594:                                [self name], _driveNum, atapiIoReq->atapiCmd[0]);
                    595:                        [self getIdeRegisters:NULL Print:"ATAPI Command"];
                    596:                        [self atapiSoftReset:_driveNum];
                    597:                        atapiIoReq->scsiStatus = STAT_CHECK;
                    598:                        return SR_IOST_CHKSNV;
                    599:                }
                    600: 
                    601:                /*
                    602:                 * This is stupid but the Chinon drive fires off an interrupt first
                    603:                 * and then updates the status register. It appears that any drive
                    604:                 * based on Western Digital chipset will do this. At any rate, this
                    605:                 * code is harmless and should be left here. 
                    606:                 */
                    607:                for (i = 0; i < MAX_BUSY_WAIT; i++)     {
                    608:                        if (status & BUSY)
                    609:                                IODelay(10);
                    610:                        else
                    611:                                break;
                    612:                        status = inb(_ideRegsAddrs.status);     
                    613:                }
                    614:        
                    615:                /*
                    616:                 * If DRQ == 0 then host has terminated the command. 
                    617:                 */
                    618:                if (!(status & DREQUEST)) {
                    619:                /*
                    620:                 * Check for command completion status. 
                    621:                 */
                    622:                        if (status & ERROR)     {
                    623: #ifdef DEBUG
                    624:                                // Don't complain for TEST UNIT READY command
                    625:                                if (cmd != 0x00) {
                    626:                                        [self dumpStatus: atapiIoReq];
                    627:                                }
                    628:                                IOLog("%s: ATAPI command %x failed. "
                    629:                                        "Error: %x Status: %x\n", [self name], 
                    630:                                        atapiIoReq->atapiCmd[0], 
                    631:                                        inb(_ideRegsAddrs.error), status);
                    632: #endif DEBUG
                    633:                    
                    634:                                atapiIoReq->scsiStatus = STAT_CHECK;
                    635:                                return SR_IOST_CHKSNV;
                    636:                } 
                    637:                        else {
                    638: #ifdef DEBUG
                    639:                        IOLog("%s: Comamnd %x completed. status %x\n", 
                    640:                                        [self name], atapiIoReq->atapiCmd[0], status);
                    641: #endif DEBUG   
                    642:                                atapiIoReq->scsiStatus = STAT_GOOD;
                    643:                                return SR_IOST_GOOD;
                    644:                }
                    645:                }
                    646: 
                    647:                /*
                    648:                 * Command is not completed. We need to transfer data as requested by
                    649:                 * the device. 
                    650:                 */
                    651:        bytes = inb(_ideRegsAddrs.byteCountHigh) << 8 |
                    652:                                inb(_ideRegsAddrs.byteCountLow);
                    653: 
                    654: #ifdef DEBUG
                    655:                IOLog("%s: ATAPI Drive %d: completed: %x, request: %x max: %x\n", 
                    656:                [self name], _driveNum, atapiIoReq->bytesTransferred, 
                    657:                bytes, atapiIoReq->maxTransfer);
                    658: #endif DEBUG   
                    659: 
                    660:                /*
                    661:                 * If the device requests more data to be transferred than required
                    662:                 * by the command protocol, then we should transfer null data. 
                    663:                 */
                    664: 
                    665:                if (atapiIoReq->bytesTransferred + bytes > atapiIoReq->maxTransfer) {
                    666: 
                    667:                IOLog("%s: ATAPI Drive %d: "
                    668:                                "ERROR: Transfer limit (%x bytes) exceeded\n", 
                    669:                        [self name], _driveNum, atapiIoReq->maxTransfer);
                    670:                
                    671:                IOLog("%s: Bytes already transfered: %x, next request: %x\n", 
                    672:                        [self name], atapiIoReq->bytesTransferred, bytes);
                    673:            
                    674:                [self dumpStatus: atapiIoReq];
                    675: 
                    676:                    /*
                    677:                     * This thing is probably hosed but let's do the best we can. 
                    678:                 */
                    679:                        {
                    680:                int diff = atapiIoReq->maxTransfer-atapiIoReq->bytesTransferred;
                    681:                IOLog("%s: Transferring %x bytes instead of %x\n", 
                    682:                        [self name], diff, bytes);
                    683:                [self xferData:buffer+offset read:atapiIoReq->read 
                    684:                        client:client length:diff];
                    685:                atapiIoReq->bytesTransferred += diff;
                    686:                offset += diff;
                    687:                [self atapiSoftReset:_driveNum];        // reset hardware as well
                    688:                }
                    689: 
                    690:                atapiIoReq->scsiStatus = STAT_GOOD;
                    691:                return SR_IOST_GOOD;
                    692: #if 0
                    693:                        /* this was old behavior */
                    694:                        atapiIoReq->scsiStatus = STAT_CHECK;
                    695:                        return SR_IOST_CMDREJ;
                    696: #endif 0
                    697:                }
                    698:        
                    699:                /*
                    700:                 * Now transfer data between device and memory.
                    701:                 */
                    702:                [self xferData:buffer+offset read:atapiIoReq->read client:client 
                    703:                        length:bytes];
                    704:        
                    705:                atapiIoReq->bytesTransferred += bytes;
                    706:                offset += bytes;
                    707:        }
                    708: 
                    709:     /*
                    710:      * Will never get here. 
                    711:      */
                    712:     atapiIoReq->scsiStatus = STAT_GOOD;
                    713:     return SR_IOST_GOOD;
                    714: }
                    715: 
                    716: /*
                    717:  * Prints command and result in case of error. 
                    718:  */
                    719: - (void) dumpStatus:(atapiIoReq_t *)atapiIoReq
                    720: {
                    721:     int i;
                    722:     
                    723:     IOLog("%s: Failed command: drive: %d lun: %d len: %d read: %d\n", 
                    724:        [self name], 
                    725:        atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen, 
                    726:        atapiIoReq->read);
                    727:     IOLog("%s: Failed command: ", [self name]); 
                    728:     for (i = 0; i < atapiIoReq->cmdLen; i++)
                    729:        IOLog("%x ", atapiIoReq->atapiCmd[i]);
                    730:     IOLog("\n");
                    731:     
                    732:     [self getIdeRegisters:NULL Print:"dumpStatus"];
                    733: }
                    734: 
                    735: /*
                    736:  * Execute the ATAPI command specified in 'atapiIoReq'.
                    737:  */
                    738: - (sc_status_t) atapiExecuteCmd:(atapiIoReq_t *)atapiIoReq 
                    739:                    buffer : (void *)buffer 
                    740:                    client : (struct vm_map *)client
                    741: {
                    742:     int i;
                    743:     atapi_return_t rtn;
                    744:     unsigned char dh = ADDRESS_MODE_LBA;       /* ALWAYS */
                    745:        sc_status_t sc_ret;
                    746:        unsigned char cmd = atapiIoReq->atapiCmd[0];
                    747:        BOOL useDMA = NO;
                    748:     
                    749:     /*
                    750:      * Reject command if there are no ATAPI devices detected. 
                    751:      */
                    752:        if ((atapiIoReq->drive >= MAX_IDE_DRIVES) ||
                    753:                (atapiIoReq->lun != 0) ||
                    754:                ([self isAtapiDevice:atapiIoReq->drive] == NO)) {
                    755:                return SR_IOST_SELTO;
                    756:        }
                    757: 
                    758:     /* Now execute the SCSI command. */
                    759: 
                    760: #ifdef DEBUG
                    761:     /* Print out the command received. */
                    762:     IOLog("%s: atapiExecuteCmd: drive: %d lun: %d len: %d read %d\n", 
                    763:        [self name], atapiIoReq->drive, atapiIoReq->lun, atapiIoReq->cmdLen, 
                    764:        atapiIoReq->read);
                    765:     IOLog("%s: Command: ", [self name]); 
                    766:     if (atapiIoReq->atapiCmd[4] == 0x41)
                    767:        atapiIoReq->atapiCmd[4] = 0x24;
                    768:     for (i = 0; i < atapiIoReq->cmdLen; i++)
                    769:        IOLog("%x ", atapiIoReq->atapiCmd[i]);
                    770:     IOLog("\n");
                    771:     //IOBreakToDebugger();
                    772: #endif DEBUG
                    773: 
                    774:        _driveNum = atapiIoReq->drive;
                    775: 
                    776:        /*
                    777:         * We are very particular on the type of commands that we allow
                    778:         * DMA to be used.
                    779:         *
                    780:         * 1. It must be a Read/Write data command.
                    781:         * 2. Buffer must be 4-byte aligned.
                    782:         # 3. The drive must be DMA capable.
                    783:         */
                    784:        useDMA = ((_drives[_driveNum].transferType != IDE_TRANSFER_PIO) &&
                    785:                         (((vm_offset_t)buffer & (PIIX_BUF_ALIGN - 1)) == 0) &&
                    786:                         ((cmd == 0x28) || (cmd == 0xa8) ||             // read 10 and read 12
                    787:               (cmd == 0x2a) || (cmd == 0xaa) ||                // write 10 and write 12
                    788:                          (cmd == 0x2f) || (cmd == 0x2e)));             // write and verify
                    789: 
                    790:     for (i = 0; i < MAX_SENDPACKET_RETRIES; i++) {
                    791: 
                    792:                /*
                    793:                 * Select the drive. Make sure the BSY bit is off before
                    794:                 * changing the drv bit.
                    795:                 */
                    796:                [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
                    797:                        on:0 off:0 alt:NO];
                    798:                dh |= _driveNum ? SEL_DRIVE1 : SEL_DRIVE0;
                    799:                outb(_ideRegsAddrs.driveSelect, dh);
                    800:                
                    801:                /*
                    802:                 * Wait for BSY = 0, DRQ = 0.
                    803:                 */
                    804:                rtn = [self atapiWaitStatusBitsFor:ATAPI_MAX_WAIT_FOR_NOTBUSY
                    805:                                on:0 off:DREQUEST alt:NO];
                    806:                if (rtn != IDER_SUCCESS) {
                    807:                        IOLog("%s: ATAPI Drive %d: Not Ready For Packet command.\n", 
                    808:                                [self name], _driveNum);
                    809:                        [self atapiSoftReset:_driveNum];
                    810:                        continue;
                    811:                }
                    812:        
                    813:                /*
                    814:                 * Send our preferred data transfer size (2048 bytes). 
                    815:                 */
                    816:                outb(_ideRegsAddrs.byteCountLow, 0x00);
                    817:                outb(_ideRegsAddrs.byteCountHigh, 0x08);
                    818:        
                    819:                /*
                    820:                 * We will use PIO for data transfers. 
                    821:                 */
                    822:                if (useDMA == YES)
                    823:                        outb(_ideRegsAddrs.features, 1);
                    824:                else
                    825:                        outb(_ideRegsAddrs.features, 0);
                    826:                
                    827:                [self enableInterrupts];
                    828:                [self clearInterrupts];
                    829:        
                    830:                /*
                    831:                 * First tell the ATAPI device that we are going to send it a packet
                    832:                 * command. If this command fails the ATAPI device needs to be reset. 
                    833:                 */
                    834:                if ([self issuePacketCommand] == IDER_SUCCESS) {
                    835:                        break;
                    836:                }
                    837:                
                    838:                IOLog("%s: ATAPI Drive %d: Packet command failed. Retrying...\n",
                    839:                                [self name], _driveNum);
                    840:                [self atapiSoftReset:_driveNum];
                    841:     }
                    842: 
                    843:     /*
                    844:      * Are we hosed? 
                    845:      */
                    846:     if (i == MAX_SENDPACKET_RETRIES) {
                    847:                atapiIoReq->scsiStatus = STAT_CHECK;
                    848:                IOLog("%s: ATAPI Drive %d: FATAL: Packet command.\n",
                    849:                        [self name], _driveNum);
                    850:                return SR_IOST_CMDREJ;
                    851:     }
                    852: 
                    853: //     [self clearInterrupts];
                    854: 
                    855:     /*
                    856:      * Send the ATAPI command packet bytes (usually 12-bytes) to the device.
                    857:      */
                    858:     [self sendAtapiCommand:atapiIoReq->atapiCmd cmdLen:atapiIoReq->cmdLen];
                    859: 
                    860:        /*
                    861:         * Peform data transfer (if any) and return the result code.
                    862:         */
                    863:        if (useDMA == YES)
                    864:                sc_ret = [self performATAPIDMA:atapiIoReq buffer:buffer client:client];
                    865:        else
                    866:                sc_ret = [self atapiPIODataTransfer:atapiIoReq buffer:buffer 
                    867:                                 client:client];
                    868:        
                    869:        return sc_ret;
                    870: }
                    871: 
                    872: #if 0
                    873: #define ATAPI_SET_CDROM_SPEED  0xbb
                    874: 
                    875: /*
                    876:  * Doesn't seem to make any difference. 
                    877:  */
                    878: - (void)setMaxSpeedForATAPICDROM:(unsigned char)unit
                    879: {
                    880:     atapiIoReq_t atapiIoReq;
                    881:     
                    882:     bzero(&atapiIoReq, sizeof(atapiIoReq_t));
                    883:     
                    884:     atapiIoReq.cmdLen = [self atapiCommandPacketSize:unit];
                    885:     atapiIoReq.drive = unit;
                    886:     
                    887:     atapiIoReq.atapiCmd[0] = ATAPI_SET_CDROM_SPEED;
                    888:     atapiIoReq.atapiCmd[2] = 0xff;
                    889:     atapiIoReq.atapiCmd[3] = 0xff;
                    890:     
                    891:     (void) [self atapiExecuteCmd:&atapiIoReq 
                    892:                buffer:NULL client:(struct vm_map *)IOVmTaskSelf()];
                    893: }
                    894: #endif 0
                    895: 
                    896: @end

unix.superglobalmegacorp.com

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