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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: // Copyright 1997 by Apple Computer, Inc., all rights reserved.
                     26: /*
                     27:  * Copyright (c) 1994-1997 NeXT Software, Inc.  All rights reserved. 
                     28:  *
                     29:  * IdeCntCmds.m - Implementation of Commands category for IDE Controller 
                     30:  * device. 
                     31:  *
                     32:  * It contains implementation of the ATA command set. 
                     33:  *
                     34:  *
                     35:  * HISTORY 
                     36:  *
                     37:  * 1-Aug-1995          Rakesh Dubey at NeXT 
                     38:  *     Reduced the timeout in IDE_IDENTIFY_DRIVE method. 
                     39:  *
                     40:  * 17-July-1994        Rakesh Dubey at NeXT 
                     41:  *     Created. 
                     42:  */
                     43: 
                     44: #import "IdeCnt.h"
                     45: #import "IdeCntInit.h"
                     46: #import "IdeCntDma.h"
                     47: #import <kern/assert.h>
                     48: #import <driverkit/kernelDriver.h>
                     49: #import <driverkit/interruptMsg.h>
                     50: #import <mach/mach_interface.h>
                     51: #import <driverkit/IODevice.h>
                     52: #import <driverkit/align.h>
                     53: #import <machkit/NXLock.h>
                     54: #import "io_inline.h"
                     55: #import "IdeDDM.h"
                     56: 
                     57: /*
                     58:  * All methods in this file implement one or more of the IDE commands. These
                     59:  * commands get invoked by IdeDisk objects. 
                     60:  */
                     61: 
                     62: @implementation IdeController(Commands)
                     63: 
                     64: /*
                     65:  * Returns a struct containing IDE registers values for a given sector
                     66:  * address and size. Depending upon whether the drive supports LBA or CHS we
                     67:  * fill in different values. The calling routine must make sure that these
                     68:  * values are not overwritten. The only thing that they need to fill in is
                     69:  * the drive number. 
                     70:  */
                     71: - (ideRegsVal_t)logToPhys:(unsigned)block numOfBlocks:(unsigned)nblk
                     72: {
                     73:     ideRegsVal_t rv;
                     74:     unsigned int cyl, nheads;
                     75:     unsigned int track, spt;
                     76: 
                     77:     if (_addressMode[_driveNum] == ADDRESS_MODE_CHS)   
                     78:     {
                     79:        nheads = _ideInfo[_driveNum].heads;
                     80:        spt = _ideInfo[_driveNum].sectors_per_trk;
                     81:        
                     82:        track = (block / spt);
                     83:        cyl = track / nheads;
                     84:        rv.sectNum = block % spt + 1;
                     85:        
                     86:        rv.drHead = track % nheads;
                     87:        rv.cylLow = (cyl & 0xff);
                     88:        rv.cylHigh = ((cyl & 0xff00) >> 8);
                     89:     } 
                     90:     else 
                     91:     {
                     92:         rv.sectNum = block & 0x0ff;
                     93:        rv.cylLow = (block >> 8) & 0xff;
                     94:        rv.cylHigh = (block >> 16) & 0xff;
                     95:        rv.drHead = (block >> 24) & 0x0f;
                     96:     }
                     97:     
                     98:     rv.sectCnt = (unsigned char)nblk;
                     99: 
                    100:     rv.drHead |= _addressMode[_driveNum];
                    101:     rv.drHead |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    102:            
                    103:     return rv;
                    104: }
                    105: 
                    106: /*
                    107:  * Commands to the IDE controller. 
                    108:  */
                    109: 
                    110: 
                    111: - (ide_return_t)ideDiagnose:(unsigned *)diagError
                    112: {
                    113:     ide_return_t rtn;
                    114:     unsigned char status;
                    115:     
                    116:     rtn = [self waitForDeviceReady];
                    117:     if (rtn != IDER_SUCCESS)
                    118:        return IDER_CMD_ERROR;
                    119:        
                    120:     [self enableInterrupts];
                    121:     outb(_ideRegsAddrs.command, IDE_DIAGNOSE);
                    122:     
                    123:     rtn = [self ideWaitForInterrupt:IDE_DIAGNOSE ideStatus:&status];
                    124:     if (rtn != IDER_SUCCESS)   
                    125:     {
                    126:        [self getIdeRegisters:NULL Print:"Diagnose"];
                    127:        return IDER_CMD_ERROR;
                    128:     }
                    129: 
                    130:     rtn = [self waitForDeviceReady];
                    131:     if (rtn != IDER_SUCCESS)
                    132:        return IDER_CMD_ERROR;
                    133:     
                    134:     *diagError = inb(_ideRegsAddrs.error);
                    135:     
                    136:     if (*diagError == 0x01)    
                    137:     {
                    138:         /* FIXME: do we need to soft reset ATAPI devices? */
                    139:        return IDER_SUCCESS;
                    140:     }
                    141: 
                    142:     /*
                    143:      * At least one of the drives is bad. 
                    144:      */
                    145:     if (*diagError & 0x080) 
                    146:     {
                    147:        IOLog("%s: Drive 1 has failed diagnostics.\n", [self name]);
                    148:        _ideInfo[1].type = 0;
                    149: 
                    150:        if ((*diagError & 0x07f) != 1) 
                    151:         {
                    152:            IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
                    153:                    [self name], (*diagError & 0x07f));
                    154:            return IDER_CMD_ERROR;
                    155:        }
                    156:     } 
                    157:     else 
                    158:     {
                    159:        _ideInfo[0].type = 0;
                    160:        IOLog("%s: Drive 0 has failed diagnostics, error %d\n",
                    161:                [self name], (*diagError & 0x07f));
                    162:     }
                    163:     
                    164:     return IDER_CMD_ERROR;
                    165: }
                    166: 
                    167: - (ide_return_t)ideSetParams:(unsigned)sectCnt numHeads:(unsigned)nHeads
                    168:                        ForDrive:(unsigned)drive
                    169: {
                    170:     unsigned char dh = _addressMode[drive];
                    171:     ide_return_t rtn;
                    172: 
                    173:     rtn = [self waitForDeviceReady];
                    174:     if (rtn != IDER_SUCCESS)
                    175:        return rtn;
                    176:        
                    177:     dh |= ((drive ? SEL_DRIVE1 : SEL_DRIVE0) | ((nHeads - 1) & 0x0f));
                    178:     outb(_ideRegsAddrs.drHead, dh);
                    179:     outb(_ideRegsAddrs.sectCnt, (sectCnt & 0xff));
                    180:     
                    181:     [self enableInterrupts];
                    182:     outb(_ideRegsAddrs.command, IDE_SET_PARAMS);
                    183:     
                    184:     rtn = [self ideWaitForInterrupt:IDE_SET_PARAMS ideStatus:NULL];
                    185:     if (rtn != IDER_SUCCESS) 
                    186:     {
                    187:        [self getIdeRegisters:NULL Print:"SetParams"];
                    188:        return rtn;
                    189:     }
                    190:     
                    191:     return rtn;
                    192: }
                    193: 
                    194: - (ide_return_t)ideSetDriveFeature:(unsigned)feature value:(unsigned)val
                    195: {
                    196:     unsigned char dh = _addressMode[_driveNum];
                    197:     unsigned char status;
                    198:     ide_return_t rtn;
                    199:     
                    200:     rtn = [self waitForDeviceReady];
                    201:     if (rtn != IDER_SUCCESS)
                    202:        return rtn;
                    203:        
                    204:     dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    205:     outb(_ideRegsAddrs.drHead, dh);
                    206:     outb(_ideRegsAddrs.sectCnt, (val & 0xff));
                    207:     
                    208:     outb(_ideRegsAddrs.features, feature);
                    209:     
                    210:     [self enableInterrupts];
                    211:     outb(_ideRegsAddrs.command, IDE_SET_FEATURES);
                    212:     
                    213:     rtn = [self ideWaitForInterrupt:IDE_SET_FEATURES ideStatus:&status];
                    214:     if (rtn != IDER_SUCCESS) 
                    215:     {
                    216:        [self getIdeRegisters:NULL Print:"SetFeatures"];
                    217:        return rtn;
                    218:     }
                    219:     
                    220:     if (status & ERROR)
                    221:        return IDER_ERROR;
                    222:     
                    223:     return rtn;
                    224: }
                    225: 
                    226: - (ide_return_t)ideRestore:(ideRegsVal_t *)ideRegs
                    227: {
                    228:     ide_return_t rtn;
                    229:     unsigned char status;
                    230:     unsigned char dh = _addressMode[_driveNum];
                    231: 
                    232:     rtn = [self waitForDeviceReady];
                    233:     if (rtn != IDER_SUCCESS) 
                    234:     {
                    235:        return rtn;
                    236:     }
                    237:     
                    238:     dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    239:     outb(_ideRegsAddrs.drHead, dh);
                    240:     
                    241:     [self enableInterrupts];
                    242:     outb(_ideRegsAddrs.command, IDE_RESTORE);
                    243: 
                    244:     rtn = [self ideWaitForInterrupt:IDE_RESTORE ideStatus: &status];
                    245:     if (rtn != IDER_SUCCESS) 
                    246:     {
                    247:        [self getIdeRegisters:NULL Print:"Restore"];
                    248:        return rtn;
                    249:     }
                    250:     
                    251:     rtn = [self waitForDeviceReady];
                    252:     if (rtn == IDER_SUCCESS) 
                    253:     {
                    254:        if (status & ERROR) 
                    255:         {
                    256:            [self getIdeRegisters:ideRegs Print:"Restore"];
                    257:            rtn = IDER_CMD_ERROR;
                    258:        }
                    259:     }
                    260: 
                    261:     return (rtn);
                    262: }
                    263: 
                    264: - (ide_return_t)ideReadGetInfoCommon:(ideRegsVal_t *)ideRegs
                    265:                            client:(struct vm_map *)client
                    266:                            addr:(caddr_t)xferAddr
                    267:                            command:(unsigned int)cmd
                    268: {
                    269:     ide_return_t rtn;
                    270:     unsigned int sec_cnt = ideRegs->sectCnt;
                    271:     int i;
                    272:     unsigned char *taddr;
                    273:     unsigned char status;
                    274:     unsigned char dh = _addressMode[_driveNum];
                    275: 
                    276:     if (sec_cnt == 0)
                    277:        sec_cnt = MAX_BLOCKS_PER_XFER;
                    278:        
                    279:     taddr = xferAddr;
                    280: 
                    281:     /*
                    282:      * We have to define this for the IDE_IDENTIFY_DRIVE command. 
                    283:      */
                    284:     if (cmd == IDE_IDENTIFY_DRIVE)     
                    285:     {
                    286:        ideRegs->sectCnt = 1;
                    287:        sec_cnt = 1;
                    288:     }
                    289: 
                    290:     /*
                    291:      * Select the drive first. This routine is invoked by the initialization
                    292:      * code as well (-resetAndInit) so it is necessary to do this here. 
                    293:      */
                    294:     dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    295:     outb(_ideRegsAddrs.drHead, dh);
                    296: 
                    297:     
                    298:     rtn = [self waitForDeviceReady];
                    299:     if (rtn != IDER_SUCCESS) 
                    300:     {
                    301:        return (rtn);
                    302:     }
                    303:     
                    304:     if (cmd == IDE_READ) 
                    305:     {
                    306:        outb(_ideRegsAddrs.drHead, ideRegs->drHead);
                    307:        outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
                    308:        outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    309:        outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
                    310:        outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
                    311:     } 
                    312:     else 
                    313:     {
                    314:         /* probably unnecessary */
                    315:        outb(_ideRegsAddrs.drHead, dh);
                    316:        outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    317:     }
                    318:         
                    319:     [self enableInterrupts];
                    320:     outb(_ideRegsAddrs.command, cmd);
                    321:         
                    322:     for (i = 0; i < sec_cnt; i++)      
                    323:     {
                    324:        rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
                    325:        if (rtn != IDER_SUCCESS) 
                    326:         {
                    327:            return rtn;
                    328:        } 
                    329:         else 
                    330:         {
                    331:            /*
                    332:            if (status & ERROR_CORRECTED) {
                    333:                IOLog("%s: Corrected error during read.\n", [self name]);
                    334:            }
                    335:            */
                    336:        }
                    337:     
                    338:        /*
                    339:        * Same as waitForDataReady but with a quick timeout. 
                    340:        */
                    341:        rtn = [self ataIdeReadGetInfoCommonWaitForDataReady];
                    342:        if (rtn != IDER_SUCCESS) 
                    343:         {
                    344:            return (rtn);
                    345:        }
                    346:        
                    347:        [self xferData:taddr read:YES client:client length:IDE_SECTOR_SIZE];
                    348:        taddr += IDE_SECTOR_SIZE;
                    349:     }
                    350: 
                    351:     return rtn;
                    352: }
                    353: 
                    354: - (ide_return_t)ideWrite:(ideRegsVal_t *)ideRegs
                    355:                    client:(struct vm_map *)client
                    356:                    addr:(caddr_t)xferAddr
                    357: {
                    358:     ide_return_t rtn;
                    359:     unsigned int sec_cnt = ideRegs->sectCnt;
                    360:     int i;
                    361:     unsigned char *taddr;
                    362:     unsigned char status;
                    363: 
                    364:     if (sec_cnt == 0)
                    365:        sec_cnt = MAX_BLOCKS_PER_XFER;
                    366:     
                    367:     taddr = xferAddr;
                    368: 
                    369:     rtn = [self waitForDeviceReady];
                    370:     if (rtn != IDER_SUCCESS) 
                    371:     {
                    372:        return (rtn);
                    373:     }
                    374:     
                    375:     outb(_ideRegsAddrs.drHead, ideRegs->drHead);
                    376:     outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
                    377:     outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    378:     outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
                    379:     outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
                    380:     
                    381:     [self enableInterrupts];
                    382:     outb(_ideRegsAddrs.command, IDE_WRITE);
                    383: 
                    384:     for (i = 0; i < sec_cnt; i++)      
                    385:     {
                    386:        rtn = [self waitForDataReady];
                    387:        if (rtn != IDER_SUCCESS) 
                    388:         {
                    389:            return (rtn);
                    390:        }
                    391: 
                    392:        [self xferData:taddr read:NO client:client length:IDE_SECTOR_SIZE];
                    393:        taddr += IDE_SECTOR_SIZE;
                    394: 
                    395:        rtn = [self ideWaitForInterrupt:IDE_WRITE ideStatus:&status];
                    396:     
                    397:        if (rtn != IDER_SUCCESS) 
                    398:         {
                    399:            [self getIdeRegisters:ideRegs Print:"Write"];
                    400:            return (rtn);
                    401:        } 
                    402:         else 
                    403:         {
                    404:            /*
                    405:            if (status & ERROR_CORRECTED) {
                    406:                IOLog("%s: Corrected error during write.\n", [self name]);
                    407:            }
                    408:            */
                    409:        }
                    410:     }
                    411: 
                    412:     return (rtn);
                    413: }
                    414: 
                    415: - (ide_return_t)ideReadVerifySeekCommon:(ideRegsVal_t *)ideRegs
                    416:                            command:(unsigned int)cmd
                    417: {
                    418:     ide_return_t rtn;
                    419:     unsigned char status;
                    420: 
                    421:     rtn = [self waitForDeviceReady];
                    422:     if (rtn != IDER_SUCCESS) 
                    423:     {
                    424:        return (rtn);
                    425:     }
                    426:     
                    427:     outb(_ideRegsAddrs.drHead, ideRegs->drHead);
                    428:     outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
                    429:     if (cmd == IDE_READ_VERIFY)
                    430:        outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    431:     outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
                    432:     outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
                    433: 
                    434:     [self enableInterrupts];
                    435:     outb(_ideRegsAddrs.command, cmd);
                    436:     
                    437:     rtn = [self ideWaitForInterrupt:cmd ideStatus: &status];
                    438:     if (rtn != IDER_SUCCESS) 
                    439:     {
                    440:        [self getIdeRegisters:NULL Print:"ReadVerify/Seek"];
                    441:        return (rtn);
                    442:     }
                    443:     
                    444:     if (status & (ERROR | WRITE_FAULT)) 
                    445:     {
                    446:        rtn = IDER_CMD_ERROR;
                    447:     } 
                    448:     else 
                    449:     {
                    450:        if ((cmd == IDE_SEEK) && (!(status & SEEK_COMPLETE)))
                    451:            rtn = IDER_CMD_ERROR;
                    452:     }
                    453: 
                    454:     return (rtn);
                    455: }
                    456: 
                    457: - (ide_return_t)ideSetMultiSectorMode:(ideRegsVal_t *)ideRegs
                    458:                            numSectors:(unsigned char)nSectors
                    459: {
                    460:     ide_return_t rtn;
                    461:     unsigned char status;
                    462:     unsigned char dh = _addressMode[_driveNum];
                    463: 
                    464:     rtn = [self waitForDeviceReady];
                    465:     if (rtn != IDER_SUCCESS) 
                    466:     {
                    467:        return (rtn);
                    468:     }
                    469:     
                    470:     dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    471:     outb(_ideRegsAddrs.drHead, dh);
                    472:     outb(_ideRegsAddrs.sectCnt, nSectors);
                    473:     
                    474:     [self enableInterrupts];
                    475:     outb(_ideRegsAddrs.command, IDE_SET_MULTIPLE);
                    476: 
                    477:     rtn = [self ideWaitForInterrupt:IDE_SET_MULTIPLE ideStatus:&status];
                    478:     if (rtn != IDER_SUCCESS) 
                    479:     {
                    480:        return (rtn);
                    481:     }
                    482:     
                    483:     rtn = [self waitForDeviceReady];
                    484:     if (rtn == IDER_SUCCESS) 
                    485:     {
                    486:        if (status & ERROR) 
                    487:         {
                    488:            rtn = IDER_CMD_ERROR;
                    489:            [self getIdeRegisters:ideRegs Print:NULL];
                    490:        } 
                    491:         else
                    492:            rtn = IDER_SUCCESS;
                    493:     } 
                    494: 
                    495:     return (rtn);
                    496: }
                    497: 
                    498: /*
                    499:  * Note: Never read the status register at the end of data transfer, you may
                    500:  * clobber the next interrupt from the drive. If it is necessary to get
                    501:  * status use the alternate status register. 
                    502:  */
                    503: - (ide_return_t)ideReadMultiple:(ideRegsVal_t *)ideRegs
                    504:        client:(struct vm_map *)client
                    505:        addr:(caddr_t)xferAddr
                    506: {
                    507:     ide_return_t rtn;
                    508:     unsigned char status;
                    509:     unsigned sec_cnt = ideRegs->sectCnt;
                    510:     unsigned int nSectors;
                    511:     unsigned char *taddr;
                    512:     unsigned int length;
                    513: 
                    514:     if (sec_cnt == 0)
                    515:        sec_cnt = MAX_BLOCKS_PER_XFER;
                    516:        
                    517:     taddr = xferAddr;
                    518: 
                    519:     rtn = [self waitForDeviceReady];
                    520:     if (rtn != IDER_SUCCESS) 
                    521:     {
                    522:        return (rtn);
                    523:     }
                    524:     
                    525:     outb(_ideRegsAddrs.drHead, ideRegs->drHead);
                    526:     outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
                    527:     outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    528:     outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
                    529:     outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
                    530: 
                    531:     [self enableInterrupts];
                    532:     outb(_ideRegsAddrs.command, IDE_READ_MULTIPLE);
                    533: 
                    534:     while (sec_cnt > 0) 
                    535:     {
                    536:        rtn = [self ideWaitForInterrupt:IDE_READ_MULTIPLE
                    537:                        ideStatus: &status];
                    538: 
                    539:        if (rtn != IDER_SUCCESS) 
                    540:         {
                    541:            [self getIdeRegisters:ideRegs Print:"Read Multiple"];
                    542:            return (rtn);
                    543:        }
                    544: 
                    545: #if 1  
                    546:        rtn = [self waitForDataReady];
                    547:        if (rtn != IDER_SUCCESS) 
                    548:         {
                    549:            return (rtn);
                    550:        }
                    551: #endif 
                    552: 
                    553:        if (status & (ERROR | WRITE_FAULT)) 
                    554:         {
                    555:            [self getIdeRegisters:ideRegs Print:"Read Multiple"];
                    556:            return IDER_CMD_ERROR;
                    557:        }
                    558: 
                    559:        /*
                    560:         * Any drive formatted with 63 sector/track (which most over 400 MB
                    561:         * are) reporting this status (ERROR_CORRECTED) will cause an
                    562:         * fallacious error (possibly uncorrectable) due to a long-standing
                    563:         * bug in DOS. This status bit should be made vendor specific, like
                    564:         * IDX. It has outlived its usefulness. 
                    565:         * -- [email protected] 
                    566:         */
                    567:         
                    568:        /*
                    569:        if (status & ERROR_CORRECTED) 
                    570:         {
                    571:            IOLog("%s: Corrected error during read.\n", [self name]);
                    572:        }
                    573:        */
                    574: 
                    575:        /*
                    576:         * All is well. Read in the data. 
                    577:         */
                    578:        if (sec_cnt > _multiSector[_driveNum])
                    579:            nSectors = _multiSector[_driveNum];
                    580:        else
                    581:            nSectors = sec_cnt;
                    582:            
                    583:        sec_cnt -= nSectors;
                    584: 
                    585:        while (nSectors) 
                    586:         {
                    587:            if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) 
                    588:             {
                    589:                length = PAGE_SIZE;
                    590:                nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
                    591:            } 
                    592:             else 
                    593:             {
                    594:                length = nSectors * IDE_SECTOR_SIZE;
                    595:                nSectors = 0;
                    596:            }
                    597: 
                    598:            [self xferData:taddr read:YES client:client length:length];
                    599:            taddr += length;
                    600:        }
                    601:     }
                    602: 
                    603:     return (rtn);
                    604: }
                    605: 
                    606: - (ide_return_t)ideWriteMultiple:(ideRegsVal_t *)ideRegs
                    607:        client:(struct vm_map *)client 
                    608:        addr:(caddr_t)xferAddr
                    609: {
                    610:     ide_return_t rtn;
                    611:     unsigned char status;
                    612:     unsigned sec_cnt = ideRegs->sectCnt;
                    613:     unsigned int nSectors;
                    614:     unsigned char *taddr;
                    615:     unsigned int length;
                    616: 
                    617:     if (sec_cnt == 0)
                    618:        sec_cnt = MAX_BLOCKS_PER_XFER;
                    619:        
                    620:     taddr = xferAddr;
                    621: 
                    622:     rtn = [self waitForDeviceReady];
                    623:     if (rtn != IDER_SUCCESS) 
                    624:     {
                    625:        return (rtn);
                    626:     }
                    627:     
                    628:     outb(_ideRegsAddrs.drHead, ideRegs->drHead);
                    629:     outb(_ideRegsAddrs.sectNum, ideRegs->sectNum);
                    630:     outb(_ideRegsAddrs.sectCnt, ideRegs->sectCnt);
                    631:     outb(_ideRegsAddrs.cylLow, ideRegs->cylLow);
                    632:     outb(_ideRegsAddrs.cylHigh, ideRegs->cylHigh);
                    633:     
                    634:     [self enableInterrupts];
                    635:     outb(_ideRegsAddrs.command, IDE_WRITE_MULTIPLE);
                    636: 
                    637:     while (sec_cnt > 0) 
                    638:     {
                    639:     
                    640:        rtn = [self waitForDataReady];
                    641:        if (rtn != IDER_SUCCESS) 
                    642:         {
                    643:            return (rtn);
                    644:        }
                    645:        
                    646:        if (sec_cnt > _multiSector[_driveNum])
                    647:            nSectors = _multiSector[_driveNum];
                    648:        else
                    649:            nSectors = sec_cnt;
                    650:            
                    651:        sec_cnt -= nSectors;
                    652: 
                    653:        while (nSectors) 
                    654:         {
                    655:            if (nSectors > PAGE_SIZE / IDE_SECTOR_SIZE) 
                    656:             {
                    657:                length = PAGE_SIZE;
                    658:                nSectors -= (PAGE_SIZE / IDE_SECTOR_SIZE);
                    659:            } 
                    660:             else 
                    661:             {
                    662:                length = nSectors * IDE_SECTOR_SIZE;
                    663:                nSectors = 0;
                    664:            }
                    665: 
                    666:            [self xferData:taddr read:NO client:client length:length];
                    667:            taddr += length;
                    668:        }
                    669:        rtn = [self ideWaitForInterrupt:IDE_WRITE_MULTIPLE 
                    670:                                ideStatus:&status];
                    671: 
                    672:        if (rtn != IDER_SUCCESS) 
                    673:         {
                    674:            [self getIdeRegisters:ideRegs Print:"Write Multiple"];
                    675:            return (rtn);
                    676:        }
                    677:        
                    678:        if (status & (ERROR | WRITE_FAULT)) 
                    679:         {
                    680:            [self getIdeRegisters:ideRegs Print:"Write Multiple"];
                    681:            return IDER_CMD_ERROR;
                    682:        }
                    683:        
                    684:        /*
                    685:        if (status & ERROR_CORRECTED) 
                    686:         {
                    687:            IOLog("%s: Corrected error during write.\n", [self name]);
                    688:        }
                    689:        */
                    690:        
                    691:     }
                    692: 
                    693:     return (rtn);
                    694: }
                    695: 
                    696: /*
                    697:  * All I/O to to controller object is done through this method. We first
                    698:  * acquire a lock before executing any IDE commands since the IDE controller
                    699:  * can do only one thing at a time (both drivers can not be active
                    700:  * simultaneously except for reset and disgnostics). 
                    701:  *
                    702:  * If it necessary to call any of the IDE command methods (which are invoked by
                    703:  * the switch() below, like ideReadGetInfoCommon:client:addr:command) it is
                    704:  * necessary to acquire the lock. The IDE command methods should not be
                    705:  * invoked directly by the Disk object. 
                    706:  *
                    707:  * This method will in turn call one of several methods which deal with
                    708:  * hardware. 
                    709:  */
                    710: 
                    711: 
                    712: #define MAX_COMMAND_RETRY      3
                    713: 
                    714: - (IOReturn) _ideExecuteCmd:(ideIoReq_t *)ideIoReq ToDrive:(unsigned char)drive
                    715: {
                    716:     int                retry;
                    717:     ideRegsVal_t       irv;
                    718:     unsigned           block, cnt;
                    719:     unsigned           error;
                    720:     unsigned int       maxSectors;
                    721:     unsigned char      dh;
                    722: 
                    723:     /*
                    724:      * If the controller wishes to put the drive to sleep, it sets this flag
                    725:      * to YES and tries to acquire the lock. This method should not try to
                    726:      * get the lock (and execute any more commands) if the flag is set. This
                    727:      * is needed in order to enter sleep mode as soon as the current command
                    728:      * is finished. If we do not do this there is contention for lock between
                    729:      * the controller (which wants to put the drive to sleep) and this method
                    730:      * (which wants to service more requests). Note that this does not do
                    731:      * away with the need for a lock, it only gives the controller a little
                    732:      * head-start. 
                    733:      */
                    734:     
                    735:     while (_driveSleepRequest) 
                    736:     {
                    737:        IOSleep(100);
                    738:     }
                    739:      
                    740:     [self ideCntrlrLock];
                    741: 
                    742:     _driveNum = drive;         /* used by IDE command methods. */
                    743:     
                    744:     /*
                    745:      * Select the drive first. We don't know the head number at this time so
                    746:      * this register will be rewritten by the specific routine later. 
                    747:      */
                    748:     dh = _addressMode[_driveNum];
                    749:     dh |= (_driveNum ? SEL_DRIVE1 : SEL_DRIVE0);
                    750:     outb(_ideRegsAddrs.drHead, dh);
                    751:     
                    752:    /*
                    753:     * Check if we need to do a media access to get the drive respinning
                    754:     * after a suspend operation. 
                    755:     */
                    756:     if ([self drivePowerState] != IDE_PM_ACTIVE)       
                    757:     {
                    758:         (void)[self startUpAttachedDevices];
                    759:     }
                    760: 
                    761:     ideIoReq->status = IDER_CMD_ERROR;
                    762:     ideIoReq->blocks_xfered = 0;
                    763: 
                    764:     for  (retry = 0; retry < MAX_COMMAND_RETRY; retry++) 
                    765:     {    
                    766:        [self clearInterrupts];
                    767: 
                    768:        switch (ideIoReq->cmd) 
                    769:         {
                    770:          case IDE_READ:
                    771:          case IDE_READ_MULTIPLE:
                    772: 
                    773:            block = ideIoReq->block;
                    774:            cnt = ideIoReq->blkcnt;
                    775:            if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO/IDE_SECTOR_SIZE)))       
                    776:             {
                    777:                ideIoReq->status = IDER_REJECT;
                    778:                break;
                    779:            }
                    780:             [self setTransferRate: _driveNum UseDMA:NO];
                    781:            ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
                    782:            if (ideIoReq->cmd == IDE_READ)
                    783:                ideIoReq->status = 
                    784:                        [self ideReadGetInfoCommon:&(ideIoReq->regValues) 
                    785:                        client:(ideIoReq->map) 
                    786:                        addr:(ideIoReq->addr) command:IDE_READ];
                    787:            else
                    788:                ideIoReq->status =
                    789:                    [self ideReadMultiple:&(ideIoReq->regValues)
                    790:                     client:(ideIoReq->map) addr:(ideIoReq->addr)];
                    791: 
                    792:            if (ideIoReq->status == IDER_SUCCESS)
                    793:                ideIoReq->blocks_xfered = ideIoReq->blkcnt;
                    794:            break;
                    795: 
                    796:          case IDE_WRITE:
                    797:          case IDE_WRITE_MULTIPLE:
                    798: 
                    799:            block = ideIoReq->block;
                    800:            cnt = ideIoReq->blkcnt;
                    801:            if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO/IDE_SECTOR_SIZE)))       
                    802:             {
                    803:                ideIoReq->status = IDER_REJECT;
                    804:                break;
                    805:            }
                    806:             [self setTransferRate: _driveNum UseDMA:NO];
                    807:            ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
                    808:            if (ideIoReq->cmd == IDE_WRITE)
                    809:                ideIoReq->status = [self ideWrite:&(ideIoReq->regValues)
                    810:                                        client:(ideIoReq->map)
                    811:                                        addr:(ideIoReq->addr)];
                    812:            else
                    813:                ideIoReq->status = 
                    814:                        [self ideWriteMultiple:&(ideIoReq->regValues)
                    815:                        client:(ideIoReq->map) addr:(ideIoReq->addr)];
                    816: 
                    817:            if (ideIoReq->status == IDER_SUCCESS)
                    818:                ideIoReq->blocks_xfered = ideIoReq->blkcnt;
                    819:            break;
                    820: 
                    821:          case IDE_WRITE_DMA:
                    822:          case IDE_READ_DMA:
                    823:            block = ideIoReq->block;
                    824:            cnt = ideIoReq->blkcnt;
                    825:            if ((cnt > MAX_BLOCKS_PER_XFER) || (cnt > (IDE_MAX_PHYS_IO / IDE_SECTOR_SIZE))) 
                    826:             {
                    827:                ideIoReq->status = IDER_REJECT;
                    828:                break;
                    829:            }
                    830:             [self setTransferRate: _driveNum UseDMA:YES];
                    831:            ideIoReq->status = [self ideDmaRwCommon:ideIoReq];
                    832:            if (ideIoReq->status == IDER_SUCCESS)
                    833:                ideIoReq->blocks_xfered = ideIoReq->blkcnt;
                    834:            break;
                    835: 
                    836:          case IDE_SEEK:
                    837:            block = ideIoReq->block;
                    838:            cnt = 1;
                    839:            ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
                    840:            ideIoReq->status = 
                    841:                        [self ideReadVerifySeekCommon:&(ideIoReq->regValues) 
                    842:                                command:IDE_SEEK];
                    843:            break;
                    844: 
                    845:          case IDE_RESTORE:
                    846:            ideIoReq->status = [self ideRestore:&(ideIoReq->regValues)];
                    847:            break;
                    848: 
                    849:          case IDE_READ_VERIFY:
                    850:            block = ideIoReq->block;
                    851:            cnt = ideIoReq->blkcnt;
                    852:            if (cnt > MAX_BLOCKS_PER_XFER) {
                    853:                ideIoReq->status = IDER_REJECT;
                    854:                break;
                    855:            }
                    856:            ideIoReq->regValues = [self logToPhys:block numOfBlocks:cnt];
                    857:            ideIoReq->status = 
                    858:                [self ideReadVerifySeekCommon:&(ideIoReq->regValues)
                    859:                                command:IDE_READ_VERIFY];
                    860:            break;
                    861: 
                    862:          case IDE_DIAGNOSE:
                    863:            [self ideDiagnose:&error];
                    864:            ideIoReq->diagResult = error;
                    865:            ideIoReq->status = IDER_SUCCESS;
                    866:            break;
                    867: 
                    868:          case IDE_SET_PARAMS:
                    869:            ideIoReq->status = 
                    870:                        [self ideSetParams:_ideInfo[_driveNum].sectors_per_trk
                    871:                        numHeads:_ideInfo[_driveNum].heads ForDrive:_driveNum];
                    872:            break;
                    873: 
                    874:          case IDE_IDENTIFY_DRIVE:
                    875:             [self setTransferRate: _driveNum UseDMA:NO];
                    876:            ideIoReq->status = 
                    877:                        [self ideReadGetInfoCommon:&(ideIoReq->regValues)
                    878:                        client :(ideIoReq->map) addr :(ideIoReq->addr)
                    879:                        command:IDE_IDENTIFY_DRIVE];
                    880: 
                    881:            if (ideIoReq->status == IDER_SUCCESS)
                    882:                ideIoReq->blocks_xfered = 1;
                    883:            break;
                    884: 
                    885:          case IDE_SET_MULTIPLE:
                    886:             maxSectors = (_ideIdentifyInfo[_driveNum].multipleSectors) &
                    887:                        IDE_MULTI_SECTOR_MASK;
                    888:            if (ideIoReq->maxSectorsPerIntr > maxSectors) 
                    889:             {
                    890:                ideIoReq->status = IDER_REJECT;
                    891:            } 
                    892:             else 
                    893:             {
                    894:                ideIoReq->status = [self ideSetMultiSectorMode:
                    895:                                    &(ideIoReq->regValues)
                    896:                                    numSectors:ideIoReq->maxSectorsPerIntr];
                    897:                if (ideIoReq->status == IDER_SUCCESS)
                    898:                    _multiSector[_driveNum] = ideIoReq->maxSectorsPerIntr;
                    899:                else
                    900:                    _multiSector[_driveNum] = 0;
                    901:            }
                    902:            break;
                    903: 
                    904:          default:
                    905:            ideIoReq->status = IDER_REJECT;
                    906:            [self ideCntrlrUnLock];
                    907:            return (IDER_REJECT);
                    908:        }
                    909: 
                    910: #if 0
                    911:         kprintf("Disk(ATA): Cmd = %02x LBA = %08x Length = %08x Addr=%08x:%08x Status = %d\n\r", 
                    912:                ideIoReq->cmd, (int)ideIoReq->block, (int)ideIoReq->blkcnt, (int)ideIoReq->addr, (int)ideIoReq->map, 
                    913:                ideIoReq->status);
                    914: #endif
                    915: 
                    916:        /*
                    917:         * Return if command has been executed successfully or summarily
                    918:         * rejected. 
                    919:         */
                    920:        if (ideIoReq->status == IDER_SUCCESS)   
                    921:         {
                    922:            [self ideCntrlrUnLock];
                    923:            return IDER_SUCCESS;
                    924:        }
                    925:        
                    926:        if (ideIoReq->status == IDER_REJECT)    
                    927:         {
                    928:            [self ideCntrlrUnLock];
                    929:            return IDER_REJECT;
                    930:        }
                    931: 
                    932:        /*
                    933:         * The command failed to exceute properly but was accepted by the
                    934:         * drive. Reset the drives and try again. 
                    935:         */
                    936:        IOLog("%s: ATA command %x failed. Retrying..\n", [self name], 
                    937:                ideIoReq->cmd);
                    938:        [self getIdeRegisters:NULL Print:"ATA Command"];
                    939:        [self resetAndInit];
                    940:        (void) [self ideRestore:&irv];
                    941:     }
                    942: 
                    943:     /*
                    944:      * If we get here then this is a catastrophic failure. 
                    945:      */
                    946:     [self ideCntrlrUnLock];
                    947:     return ideIoReq->status;
                    948: }
                    949: 
                    950: @end

unix.superglobalmegacorp.com

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