Annotation of drvEIDE/EIDE.drvproj/EIDE.lksproj/IdePIIX.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.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:  * IdePIIX.m - PIIX/PCI specific ATA controller initialization module. 
        !            29:  *
        !            30:  * 23-Jan-1998 Joe Liu at Apple
        !            31:  *  Added support for PIIX/PIIX3/PIIX4 PCI IDE controllers.
        !            32:  *
        !            33:  * 05-Apr-1995 Rakesh Dubey at NeXT
        !            34:  *     Fixed some bugs in PCI support.
        !            35:  * 03-Oct-1994         Rakesh Dubey at NeXT
        !            36:  *      Created. 
        !            37:  */
        !            38: 
        !            39: #import "IdeCnt.h"
        !            40: #import "IdePIIX.h"
        !            41: #import "IdeCntCmds.h"
        !            42: #import <driverkit/i386/IOPCIDeviceDescription.h>
        !            43: #import <driverkit/i386/IOPCIDirectDevice.h>
        !            44: #import <driverkit/generalFuncs.h>
        !            45: #import <driverkit/kernelDriver.h>
        !            46: #import <driverkit/interruptMsg.h>
        !            47: #import <mach/mach_interface.h>
        !            48: #import <machdep/i386/io_inline.h>
        !            49: #import <string.h>
        !            50: #import <stdio.h>
        !            51: #import "IdeDDM.h"
        !            52: #import "PIIX.h"
        !            53: #import "PIIXTiming.h"
        !            54: #import "IdeShared.h"
        !            55: 
        !            56: // XXX get rid of this
        !            57: #if (IO_DRIVERKIT_VERSION != 330)
        !            58: #import <machdep/machine/pmap.h>
        !            59: #endif
        !            60: 
        !            61: extern vm_offset_t pmap_resident_extract(pmap_t pmap, vm_offset_t va);
        !            62: 
        !            63: //#define DEBUG
        !            64: 
        !            65: #ifndef MIN
        !            66: #define MIN(a,b)    ((a) < (b) ? (a) : (b))
        !            67: #endif  MIN
        !            68: 
        !            69: #ifndef MAX
        !            70: #define MAX(a,b)    ((a) > (b) ? (a) : (b))
        !            71: #endif  MAX
        !            72: 
        !            73: /*
        !            74:  * Function: IOMallocPage
        !            75:  *
        !            76:  * Purpose:
        !            77:  *   Returns a pointer to a page-aligned memory block of size >= PAGE_SIZE.
        !            78:  *   Note that on Intel, the hardware page size of 4K. However, MACH's
        !            79:  *   notion of a page is 8K, which is comprised of two contiguous
        !            80:  *   (physical/virtual) hardware pages.
        !            81:  *
        !            82:  * Return:
        !            83:  *   Actual pointer and size of block returned in actual_ptr and actual_size.
        !            84:  *   Use these as arguments to IOFree: IOFree(*actual_ptr, *actual_size);
        !            85:  */
        !            86: static void *
        !            87: IOMallocPage(int request_size, void ** actual_ptr,
        !            88:                                 int * actual_size)
        !            89: {
        !            90:     void * mem_ptr;
        !            91:     
        !            92:        /*
        !            93:         * Minimize memory use by first trying to allocate the requested size
        !            94:         * without any padding.
        !            95:         */
        !            96:        *actual_size = round_page(request_size);
        !            97:        mem_ptr = IOMalloc(*actual_size);
        !            98:        if (mem_ptr == NULL)
        !            99:                return NULL;
        !           100:        
        !           101:        /*
        !           102:         * Check alignment of this page.
        !           103:         */
        !           104:        if ((vm_offset_t)mem_ptr & (PAGE_SIZE - 1)) {   // NOT page aligned.
        !           105:                IOFree(mem_ptr, *actual_size);
        !           106:                *actual_size = round_page(request_size) + PAGE_SIZE;
        !           107:                mem_ptr = IOMalloc(*actual_size);
        !           108:                if (mem_ptr == NULL)
        !           109:                        return NULL;            
        !           110:        }
        !           111: 
        !           112:        *actual_ptr = mem_ptr;
        !           113:        return ((void *)round_page(mem_ptr));           
        !           114: }
        !           115: 
        !           116: @implementation IdeController(PIIX)
        !           117: 
        !           118: /*
        !           119:  * Method: probePCIController
        !           120:  *
        !           121:  * Purpose:
        !           122:  * Probe the existence of a supported PCI chipset, then proceed to
        !           123:  * record the PCI IDE controller found.
        !           124:  *
        !           125:  * Note:
        !           126:  * This is called before [super init...], and so we use the class version
        !           127:  * of getPCIdevice method calls.
        !           128:  *
        !           129:  */
        !           130: - (BOOL) probePCIController:(IOPCIDeviceDescription *)devDesc
        !           131: {
        !           132:     unsigned char      devNum, funcNum, busNum;
        !           133:     const char                 *value;
        !           134:        const char              *deviceName;
        !           135:        IOConfigTable   *configTable;
        !           136:     IOReturn           rtn;
        !           137:     const id self_class = [self class];
        !           138: 
        !           139:        /*
        !           140:         * Initialize PCI ivars.
        !           141:         */
        !           142:        _controllerID = PCI_ID_NONE;
        !           143:        _ideChannel   = PCI_CHANNEL_OTHER;
        !           144:        _busMaster    = NO;
        !           145:        bzero((char *)&_prdTable, sizeof(_prdTable));
        !           146:        
        !           147:        /*
        !           148:         * Make sure we are dealing with a PCI config table by reading the
        !           149:         * BUS_TYPE key.
        !           150:         */
        !           151:     configTable = [devDesc configTable];
        !           152:     value = [configTable valueForStringKey:BUS_TYPE];
        !           153:     if (!value || strcmp(value, "PCI") != 0) {
        !           154:                // Not PCI, return YES to continue probing for non PCI controllers.
        !           155:                return YES;
        !           156:     }
        !           157:     
        !           158:        /*
        !           159:         * Read PCI config space for VendorID and DeviceID.
        !           160:         */
        !           161:     rtn = [devDesc getPCIdevice:&devNum function:&funcNum bus:&busNum];
        !           162:     if (rtn != IO_R_SUCCESS) {
        !           163:        IOLog("%s: Unsupported PCI hardware\n", [self name]);
        !           164:                return NO;
        !           165:     }
        !           166:     rtn = [self_class getPCIConfigData:&_controllerID atRegister:0x00
        !           167:                withDeviceDescription:devDesc];
        !           168:     if (rtn != IO_R_SUCCESS)   {
        !           169:        IOLog("%s: PCI config space access error %d\n", [self name], rtn);
        !           170:                return NO;
        !           171:     }    
        !           172: 
        !           173:        switch (_controllerID) {
        !           174:                case PCI_ID_PIIX:
        !           175:                        deviceName = "PIIX";
        !           176:                        break;
        !           177:                case PCI_ID_PIIX3:
        !           178:                        deviceName = "PIIX3";
        !           179:                        break;
        !           180:                case PCI_ID_PIIX4:
        !           181:                        deviceName = "PIIX4";
        !           182:                        break;
        !           183:                default:
        !           184:                        IOLog("%s: Unknown PCI IDE controller (0x%08lx)\n",
        !           185:                                [self name], _controllerID);
        !           186:                        _controllerID = PCI_ID_NONE;
        !           187:                        return NO;
        !           188:        }
        !           189: 
        !           190:        /*
        !           191:         * Report the PCI controller found.
        !           192:         */
        !           193:        IOLog("%s: %s PCI IDE Controller at Dev:%d Func:%d Bus:%d\n",
        !           194:                [self name], deviceName, devNum, funcNum, busNum);
        !           195: 
        !           196:        /*
        !           197:         * At this point, we are certain that we are dealing with a
        !           198:         * Intel PIIX class controller.
        !           199:         */
        !           200:        return ([self PIIXInitController:devDesc]);
        !           201: }
        !           202: 
        !           203: /*
        !           204:  * Method: initPIIXController
        !           205:  *
        !           206:  * Initializes the Intel PIIX IDE controller.
        !           207:  */
        !           208: - (BOOL) PIIXInitController:(IOPCIDeviceDescription *)devDesc
        !           209: {
        !           210:        piix_idetim_u   idetim;
        !           211:        IOReturn                rtn;
        !           212:        unsigned long   configReg;
        !           213:        const id self_class = [self class];
        !           214: 
        !           215:        /*
        !           216:         * Are we initializing the primary or the secondary channel?
        !           217:         * Set the ivar _ideChannel.
        !           218:         */
        !           219:        switch ([devDesc portRangeList]->start) {
        !           220:                case PIIX_P_CMD_ADDR:
        !           221:                        _ideChannel = PCI_CHANNEL_PRIMARY;
        !           222:                        break;
        !           223:                case PIIX_S_CMD_ADDR:
        !           224:                        _ideChannel = PCI_CHANNEL_SECONDARY;
        !           225:                        break;
        !           226:                default:
        !           227:                        _ideChannel = PCI_CHANNEL_OTHER;
        !           228:        }
        !           229:        
        !           230:        /*
        !           231:         * PIIX configured on a weird location, cannot continue.
        !           232:         *
        !           233:         * NOTE:
        !           234:         * The I/O ranges does NOT show up as a I/O range in the PCI
        !           235:         * configuration space. However, the Bus-Mastering I/O range
        !           236:         * does show up at configuration space location 0x20.
        !           237:         */
        !           238:        if ((_ideChannel == PCI_CHANNEL_OTHER) ||
        !           239:                ([devDesc portRangeList]->size != PIIX_CMD_SIZE)) {
        !           240:                IOLog("%s: Invalid IDE Command Block set to 0x%x size %d\n",
        !           241:                        [self name],
        !           242:                        [devDesc portRangeList]->start,
        !           243:                        [devDesc portRangeList]->size);
        !           244:                return NO;
        !           245:        }
        !           246:        
        !           247:        /*
        !           248:         * Verify our IRQ assignment.
        !           249:         *
        !           250:         * PIIX hardcodes the following settings:
        !           251:         * IRQ 14 - primary channel
        !           252:         * IRQ 15 - secondary channel
        !           253:         */
        !           254:        {
        !           255:        unsigned int irq;
        !           256:        
        !           257:        irq = (_ideChannel == PCI_CHANNEL_PRIMARY) ? PIIX_P_IRQ : PIIX_S_IRQ;
        !           258:        if ([devDesc interrupt] != irq) {
        !           259:                IOLog("%s: Invalid IRQ: %d\n", [self name], [devDesc interrupt]);
        !           260:                return NO;
        !           261:        }
        !           262:        }
        !           263:        
        !           264:        /*
        !           265:         * Check the I/O Space Enable bit in the PCI command register.
        !           266:         *
        !           267:         * This is the master enable bit for the PIIX controller.
        !           268:         */
        !           269:     rtn = [self_class getPCIConfigData:&configReg atRegister:PIIX_PCICMD
        !           270:                withDeviceDescription:devDesc];
        !           271:     if (rtn != IO_R_SUCCESS)   {
        !           272:        IOLog("%s: PCI config space access error %d\n", [self name], rtn);
        !           273:                return NO;
        !           274:     }  
        !           275:        if (!(configReg & 0x0001)) {
        !           276:                IOLog("%s: PCI IDE controller is not enabled\n", [self name]);
        !           277:                return NO;
        !           278:        }
        !           279:        if (configReg & 0x0004)
        !           280:                _busMaster = YES;
        !           281:        else
        !           282:                _busMaster = NO;
        !           283:        
        !           284:        /*
        !           285:         * Fetch the corresponding primary/secondary IDETIM register and
        !           286:         * verify that the individual channels are enabled.
        !           287:         */
        !           288:     rtn = [self_class getPCIConfigData:&configReg atRegister:PIIX_IDETIM
        !           289:                withDeviceDescription:devDesc];
        !           290:     if (rtn != IO_R_SUCCESS)   {
        !           291:        IOLog("%s: PCI config space access error %d\n", [self name], rtn);
        !           292:                return NO;
        !           293:     }
        !           294:        if (_ideChannel == PCI_CHANNEL_SECONDARY)
        !           295:                configReg >>= 16;       // PIIX_IDETIM + 2 for secondary channel
        !           296:        idetim.word = (u_short)configReg;
        !           297:        
        !           298:        if (!idetim.bits.ide) {
        !           299:                IOLog("%s: %s PCI IDE channel is not enabled\n",
        !           300:                        [self name],
        !           301:                        (_ideChannel == PCI_CHANNEL_PRIMARY) ? "Primary" : "Secondary");
        !           302:                return NO;
        !           303:        }
        !           304: 
        !           305:        /*
        !           306:         * Register and record the location of our Bus Master 
        !           307:         * interface registers.
        !           308:         */
        !           309:        if (_busMaster && ([self PIIXRegisterBMRange:devDesc] == NO)) {
        !           310:                IOLog("%s: Bus master I/O range registration failed\n",
        !           311:                        [self name]);
        !           312:                _busMaster = NO;
        !           313:        }
        !           314:        
        !           315:        /*
        !           316:         * Allocate a 4K-page (perhaps 8K) aligned page of memory for
        !           317:         * the PRD table.
        !           318:         */
        !           319:        if (_busMaster && ([self PIIXInitPRDTable] == NO)) {
        !           320:                IOLog("%s: cannot allocate memory for descriptor table\n",
        !           321:                        [self name]);
        !           322:                _busMaster = NO;
        !           323:        }
        !           324: 
        !           325: #if 0
        !           326:        IOLog("%s: PCI bus master DMA: %s\n",
        !           327:                [self name], busMaster ? "Enabled" : "Disabled");
        !           328: #endif
        !           329: 
        !           330:        /*
        !           331:         * Revert to default timing.
        !           332:         */
        !           333:        [self PIIXResetTimings:devDesc];
        !           334:        
        !           335:     return YES;
        !           336: }
        !           337: 
        !           338: /*
        !           339:  * Method: getPCIControllerCapabilities
        !           340:  *
        !           341:  * Return the capability of the PCI IDE controller in 'm'.
        !           342:  *
        !           343:  */
        !           344: - (void) getPCIControllerCapabilities:(txferModes_t *)m
        !           345: {
        !           346:        m->mode.swdma = m->mode.mwdma = m->mode.udma = ATA_MODE_NONE;
        !           347:        switch (_controllerID) {
        !           348:                case PCI_ID_PIIX:
        !           349:                case PCI_ID_PIIX3:
        !           350:                case PCI_ID_PIIX4:
        !           351:                        m->mode.pio   = ata_mode_to_mask(ATA_MODE_4);
        !           352:                        if (_busMaster) {
        !           353:                                m->mode.mwdma = ata_mode_to_mask(ATA_MODE_2);
        !           354:                                if (_controllerID == PCI_ID_PIIX4)
        !           355:                                        m->mode.udma = ata_mode_to_mask(ATA_MODE_2);
        !           356:                        }
        !           357:                        break;
        !           358:        }
        !           359: }
        !           360: 
        !           361: /*
        !           362:  * Get the PIO port transfer width. This refers to the width of the
        !           363:  * I/O transfer on the PIO port, the IDE bus width is always 16-bits.
        !           364:  *
        !           365:  * All PIIX controllers are capable of 32-bit transfers on the data
        !           366:  * port.
        !           367:  */
        !           368: - (ideTransferWidth_t) getPIOTransferWidth
        !           369: {
        !           370:        return (IDE_TRANSFER_32_BIT);
        !           371: }
        !           372: 
        !           373: /*
        !           374:  * Method: resetPCIController
        !           375:  *
        !           376:  * Not a true RESET, simply return the PCI controller to a quiescent state
        !           377:  * and return all IDE ports to the default timing.
        !           378:  */
        !           379: - (void) resetPCIController
        !           380: {
        !           381:        switch (_controllerID) {
        !           382:                case PCI_ID_PIIX:
        !           383:                case PCI_ID_PIIX3:
        !           384:                case PCI_ID_PIIX4:
        !           385:                        [self PIIXInit];
        !           386:                        [self PIIXResetTimings:[self deviceDescription]];
        !           387:                        break;
        !           388:        }
        !           389: }
        !           390: 
        !           391: /*
        !           392:  * Method: PIIXResetTimings
        !           393:  *
        !           394:  * Purpose:
        !           395:  * Revert the timing register to the default value. The transfer timing
        !           396:  * is set to the compatible mode. We need to be careful to initialize the
        !           397:  * register only for our current IDE channel.
        !           398:  */
        !           399: - (void) PIIXResetTimings:(IOPCIDeviceDescription *)devDesc
        !           400: {
        !           401:        union {
        !           402:                u_long dword;
        !           403:                struct {
        !           404:                        piix_idetim_u pri;
        !           405:                        piix_idetim_u sec;
        !           406:                } tim;
        !           407:        } timings;
        !           408: 
        !           409:     IOReturn rtn;
        !           410:        u_long udma;
        !           411: 
        !           412:        /*
        !           413:         * Read the PIIX_IDETIM register.
        !           414:         */     
        !           415:        rtn = [[self class] getPCIConfigData:&timings.dword
        !           416:                atRegister:PIIX_IDETIM
        !           417:                withDeviceDescription:devDesc];
        !           418:     if (rtn != IO_R_SUCCESS)
        !           419:                return;
        !           420: 
        !           421:        /*
        !           422:         * Read both PIIX_UDMACTL and PIIX_UDMATIM register.
        !           423:         */
        !           424:        rtn = [[self class] getPCIConfigData:&udma atRegister:PIIX_UDMACTL
        !           425:                withDeviceDescription:devDesc];
        !           426: 
        !           427:        /*
        !           428:         * Set compatible timing.
        !           429:         * Disable UDDMA and set its timing registers to the slowest mode.
        !           430:         */     
        !           431:        switch (_ideChannel) {
        !           432:                case PCI_CHANNEL_PRIMARY:
        !           433:                        timings.tim.pri.word &= 0x8000;
        !           434:                        udma &= 0xffccfffc;
        !           435:                        break;
        !           436:                case PCI_CHANNEL_SECONDARY:
        !           437:                        timings.tim.sec.word &= 0x8000;
        !           438:                        udma &= 0xccfffff3;
        !           439:                        break;
        !           440:                default:
        !           441:                        return;
        !           442:        }
        !           443:        
        !           444:        /*
        !           445:         * Write the modified PCI config space registers back.
        !           446:         */
        !           447:        [[self class] setPCIConfigData:timings.dword atRegister:PIIX_IDETIM
        !           448:                withDeviceDescription:devDesc];
        !           449:        [[self class] setPCIConfigData:udma atRegister:PIIX_UDMACTL
        !           450:                withDeviceDescription:devDesc];
        !           451: }
        !           452: 
        !           453: /*
        !           454:  * Method: PIIXRegisterBMRange:
        !           455:  *
        !           456:  * Purpose:
        !           457:  * Add the 8-byte Bus-Master control registers to the portRangeList in
        !           458:  * the deviceDescription. The base address for the registers resides in
        !           459:  * PCI config space location 0x20. The first 8 bytes are for the primary
        !           460:  * IDE channel, the next eight bytes are for the secondary IDE channel.
        !           461:  *
        !           462:  * Note:
        !           463:  * This must be called before [super init...] because that's when the
        !           464:  * resources are registered.
        !           465:  */
        !           466: - (BOOL) PIIXRegisterBMRange:(IOPCIDeviceDescription *)devDesc
        !           467: {
        !           468:     IOReturn           rtn;
        !           469:        unsigned long   bmiba;
        !           470:        IORange                 io_range[2];
        !           471:        
        !           472:     rtn = [[self class] getPCIConfigData:&bmiba atRegister:PIIX_BMIBA
        !           473:                withDeviceDescription:devDesc];
        !           474:     if (rtn != IO_R_SUCCESS) {
        !           475:        IOLog("%s: PCI config space access error %d\n", [self name], rtn);
        !           476:                return NO;
        !           477:     }
        !           478:        
        !           479:        /*
        !           480:         * Sanity check. Make sure this is an I/O range.
        !           481:         */
        !           482:        if ((bmiba & 0x01) == 0) {
        !           483:                IOLog("%s: PCI memory range 0x%02x (0x%08lx) is not an I/O range\n",
        !           484:                        [self name], PIIX_BMIBA, bmiba);
        !           485:                return NO;
        !           486:        }
        !           487:        
        !           488:        _bmRegs = bmiba & PIIX_BM_MASK;
        !           489: 
        !           490:        if (_bmRegs == 0)       // uninitialized range
        !           491:                return NO;
        !           492: 
        !           493:        if (_ideChannel == PCI_CHANNEL_SECONDARY)
        !           494:                _bmRegs += PIIX_BM_OFFSET;
        !           495:        
        !           496:        /*
        !           497:         * Add this range to our device description's port range list.
        !           498:         */
        !           499:        io_range[0] = [devDesc portRangeList][0];
        !           500:        io_range[1].start = _bmRegs;
        !           501:        io_range[1].size  = PIIX_BM_SIZE;
        !           502:        if ([devDesc setPortRangeList:io_range num:2] != IO_R_SUCCESS) {
        !           503:                IOLog("%s: setPortRangeList failed\n", [self name]);
        !           504:                return NO;
        !           505:        }
        !           506:        
        !           507:        return YES;
        !           508: }
        !           509: 
        !           510: /*
        !           511:  * Method: PIIXInitPRDTable
        !           512:  *
        !           513:  * Purpose:
        !           514:  * Initialize a "page-aligned" page of memory for the PRD descriptors
        !           515:  * used by the bus master IDE controller.
        !           516:  *
        !           517:  * FIXME: Need to free the _prdTable memory.
        !           518:  */
        !           519: - (BOOL) PIIXInitPRDTable
        !           520: {
        !           521:        _prdTable.size = PAGE_SIZE;
        !           522:        _prdTable.ptr = (void *)IOMallocPage(
        !           523:                                                _prdTable.size,
        !           524:                                                &_prdTable.ptrReal,
        !           525:                                                &_prdTable.sizeReal
        !           526:                                                );
        !           527: 
        !           528:        /*
        !           529:         * _prdTable->ptr should now points to a physically contiguous block
        !           530:         * of PAGE_SIZE bytes.
        !           531:         */
        !           532:     if (_prdTable.ptr == NULL)
        !           533:                return NO;
        !           534:        
        !           535:        /*
        !           536:         * cache the physical address of the descriptor table to _tablePhyAddr.
        !           537:         */
        !           538:        if (IOPhysicalFromVirtual(IOVmTaskSelf(), (vm_address_t)_prdTable.ptr,
        !           539:                &_tablePhyAddr) != IO_R_SUCCESS) {
        !           540:                IOFree(_prdTable.ptrReal, _prdTable.sizeReal);
        !           541:                return NO;
        !           542:        }
        !           543: 
        !           544:        bzero(_prdTable.ptr, _prdTable.size);
        !           545:        return YES;
        !           546: }
        !           547: 
        !           548: /*
        !           549:  * Method: PIIXReportTimings:slaveTiming:isPrimary:
        !           550:  *
        !           551:  * Purpose:
        !           552:  * Log the drive timings set in the two PIIX timing registers.
        !           553:  * The units for the values are in PCI clocks.
        !           554:  */
        !           555: - (void) PIIXReportTimings:(piix_idetim_u)tim
        !           556:               slaveTiming:(piix_sidetim_u)stim
        !           557:                 isPrimary:(BOOL)primary
        !           558: {
        !           559:        if (!_ide_debug)
        !           560:                return;
        !           561: 
        !           562:        IOLog("%s: Drive 0: ISP:%d Clks RCT:%d Clks\n",
        !           563:                [self name],
        !           564:                PIIX_ISP_TO_CLK(tim.bits.isp),
        !           565:                PIIX_RCT_TO_CLK(tim.bits.rct));
        !           566: #if 0
        !           567:        IOLog("%s: Drive 0 Fast timing DMA only: %s\n", [self name],
        !           568:                tim.bits.dte0 ? "on" : "off");
        !           569:        IOLog("%s: Drive 0 Prefetch and Posting: %s\n", [self name],
        !           570:                tim.bits.ppe0 ? "on" : "off");
        !           571:        IOLog("%s: Drive 0 IORDY sample enable : %s\n", [self name],
        !           572:                tim.bits.ie0 ? "on" : "off");
        !           573:        IOLog("%s: Drive 0 Fast timing enable  : %s\n", [self name],
        !           574:                tim.bits.time0 ? "on" : "off");
        !           575: #endif 0
        !           576:        IOLog("%s: Drive 1: ISP:%d Clks RCT:%d Clks\n", [self name],
        !           577:                tim.bits.sitre ?
        !           578:                        (primary ?
        !           579:                                PIIX_ISP_TO_CLK(stim.bits.pisp1) : 
        !           580:                                PIIX_ISP_TO_CLK(stim.bits.sisp1)) : 
        !           581:                        PIIX_ISP_TO_CLK(tim.bits.isp),
        !           582:                tim.bits.sitre ?
        !           583:                        (primary ?
        !           584:                                PIIX_RCT_TO_CLK(stim.bits.prct1) :
        !           585:                                PIIX_RCT_TO_CLK(stim.bits.srct1)) :
        !           586:                        PIIX_RCT_TO_CLK(tim.bits.rct));
        !           587: #if 0
        !           588:        IOLog("%s: Drive 1 Fast timing DMA only: %s\n", [self name],
        !           589:                tim.bits.dte1 ? "on" : "off");
        !           590:        IOLog("%s: Drive 1 Prefetch and Posting: %s\n", [self name],
        !           591:                tim.bits.ppe1 ? "on" : "off");
        !           592:        IOLog("%s: Drive 1 IORDY sample enable : %s\n", [self name],
        !           593:                tim.bits.ie1 ? "on" : "off");
        !           594:        IOLog("%s: Drive 1 Fast timing enable  : %s\n", [self name],
        !           595:                tim.bits.time1 ? "on" : "off");
        !           596: #endif 0
        !           597: }
        !           598: 
        !           599: /*
        !           600:  * Method: setPCIControllerCapabilities
        !           601:  *
        !           602:  * Purpose:
        !           603:  * Based on the transfer modes and types for both IDE drives, setup the
        !           604:  * controller to support those modes.
        !           605:  *
        !           606:  */
        !           607: - (BOOL) setPCIControllerCapabilitiesForDrives:(driveInfo_t *)drives
        !           608: {
        !           609:        IOPCIConfigSpace configSpace;
        !           610:        
        !           611:        if (_controllerID == PCI_ID_NONE)
        !           612:                return NO;
        !           613:        
        !           614:        [self getPCIConfigSpace:&configSpace];
        !           615:        
        !           616:        switch (_controllerID) {
        !           617:                case PCI_ID_PIIX:
        !           618:                case PCI_ID_PIIX3:
        !           619:                case PCI_ID_PIIX4:
        !           620:                        [self PIIXComputePCIConfigSpace:&configSpace forDrives:drives];
        !           621:                        break;
        !           622:                default:
        !           623:                        return NO;
        !           624:        }
        !           625: 
        !           626:        [self setPCIConfigSpace:&configSpace];
        !           627:     return YES;
        !           628: }
        !           629: 
        !           630: /*
        !           631:  * Method: computePCIConfigSpaceForPIIX:modes:
        !           632:  *
        !           633:  * Purpose:
        !           634:  * Set the IDETIM and the SIDETIM IDE timing registers based on the
        !           635:  * PIO modes supported by the two drives on the IDE channel.
        !           636:  */
        !           637: - (void) PIIXComputePCIConfigSpace:(IOPCIConfigSpace *)configSpace
        !           638:                forDrives:(driveInfo_t *)drv
        !           639: {
        !           640:        u_char *pci_space = (u_char *)configSpace;
        !           641:     piix_idetim_u      *idetim;
        !           642:        piix_sidetim_u  *sidetim;
        !           643:        piix_udmactl_u  *udmactl;
        !           644:        piix_udmatim_u  *udmatim;
        !           645:        unsigned char   modeDrive0;
        !           646:        unsigned char   modeDrive1;
        !           647:        u_char                  isp, rct;
        !           648: 
        !           649:        if (MAX_IDE_DRIVES != 2)
        !           650:                return;
        !           651:        
        !           652:        switch (_ideChannel) {
        !           653:                case PCI_CHANNEL_PRIMARY:
        !           654:                        idetim = (piix_idetim_u *)&pci_space[PIIX_IDETIM];
        !           655:                        break;
        !           656:                case PCI_CHANNEL_SECONDARY:
        !           657:                        idetim = (piix_idetim_u *)&pci_space[PIIX_IDETIM_S];
        !           658:                        break;
        !           659:                default:
        !           660:                        IOLog("%s: PIIX: Unknown IDE channel\n", [self name]);
        !           661:                        return;
        !           662:        }
        !           663:        sidetim = (piix_sidetim_u *)&pci_space[PIIX_SIDETIM];
        !           664:        udmactl = (piix_udmactl_u *)&pci_space[PIIX_UDMACTL];
        !           665:        udmatim = (piix_udmatim_u *)&pci_space[PIIX_UDMATIM];
        !           666: 
        !           667:        modeDrive0 = ata_mode_to_num(drv[0].transferMode);
        !           668:        modeDrive1 = ata_mode_to_num(drv[1].transferMode);
        !           669:        
        !           670:        /* Enable slave timing if timings are different and
        !           671:         * a slave device is present.
        !           672:         */
        !           673:        idetim->bits.sitre = 0;
        !           674:        isp = PIIXGetISPForMode(modeDrive0, drv[0].transferType);
        !           675:        rct = PIIXGetRCTForMode(modeDrive0, drv[0].transferType);
        !           676:        
        !           677:        if ((PIIXGetCycleForMode(modeDrive0, drv[0].transferType) != 
        !           678:                PIIXGetCycleForMode(modeDrive1, drv[1].transferType)) &&
        !           679:                (drv[1].ideInfo.type != 0)) {
        !           680:                if (_controllerID == PCI_ID_PIIX) {
        !           681:                        /* Do not have the luxury of separate timing register for
        !           682:                         * drive 0 and drive 1. Use the minimum of the two PIO modes.
        !           683:                         * Or, the max of the two timings.
        !           684:                         */
        !           685:                        isp = MAX(PIIXGetISPForMode(modeDrive0, drv[0].transferType),
        !           686:                                      PIIXGetISPForMode(modeDrive1, drv[1].transferType));
        !           687:                        rct = MAX(PIIXGetRCTForMode(modeDrive0, drv[0].transferType),
        !           688:                                      PIIXGetRCTForMode(modeDrive1, drv[1].transferType));                      
        !           689:                }
        !           690:                else
        !           691:                        idetim->bits.sitre = 1;         // enable slave timing
        !           692:        }
        !           693:        
        !           694:        /*
        !           695:         * Reset all performance tuning bits and disable UDMA.
        !           696:         */
        !           697:        idetim->word &= 0xc000;
        !           698:        switch (_ideChannel) {
        !           699:                case PCI_CHANNEL_PRIMARY:
        !           700:                        udmactl->bits.psde0 = 0;
        !           701:                        udmactl->bits.psde1 = 0;
        !           702:                        break;
        !           703:                default:
        !           704:                        udmactl->bits.ssde0 = 0;
        !           705:                        udmactl->bits.ssde1 = 0;
        !           706:        }
        !           707: 
        !           708:        /*
        !           709:         * Set the timings for drive 0 (master).
        !           710:         */
        !           711:        if (drv[0].ideInfo.type == 0) {
        !           712:                IOLog("%s: Drive 0 is not present\n", [self name]);
        !           713:                return;
        !           714:        }
        !           715: 
        !           716:        /*
        !           717:         * Set timings for Drive 0 (Master drive).
        !           718:         */
        !           719:        if (drv[0].transferType == IDE_TRANSFER_ULTRA_DMA) {
        !           720:                if (modeDrive0 > 2) modeDrive0 = 2;
        !           721:                switch (_ideChannel) {
        !           722:                        case PCI_CHANNEL_PRIMARY:
        !           723:                                udmactl->bits.psde0 = 1;
        !           724:                                udmatim->bits.pct0 = modeDrive0;
        !           725:                                break;
        !           726:                        case PCI_CHANNEL_SECONDARY:
        !           727:                                udmactl->bits.ssde0 = 1;
        !           728:                                udmatim->bits.sct0 = modeDrive0;
        !           729:                                break;
        !           730:                        default:
        !           731:                                break;
        !           732:                }
        !           733:        }
        !           734:        idetim->bits.isp = isp;
        !           735:        idetim->bits.rct = rct;
        !           736:        
        !           737:        /* Set timings for drive 1 (Slave drive).
        !           738:         */
        !           739:        if (drv[1].transferType == IDE_TRANSFER_ULTRA_DMA) {
        !           740:                if (modeDrive1 > 2) modeDrive1 = 2;
        !           741:                switch (_ideChannel) {
        !           742:                        case PCI_CHANNEL_PRIMARY:
        !           743:                                udmactl->bits.psde1 = 1;
        !           744:                                udmatim->bits.pct1 = modeDrive1;
        !           745:                                break;
        !           746:                        case PCI_CHANNEL_SECONDARY:
        !           747:                                udmactl->bits.ssde1 = 1;
        !           748:                                udmatim->bits.sct1 = modeDrive1;
        !           749:                                break;
        !           750:                        default:
        !           751:                                break;
        !           752:                }
        !           753:        }
        !           754:        if (idetim->bits.sitre) {
        !           755:                isp = PIIXGetISPForMode(modeDrive1, drv[1].transferType);
        !           756:                rct = PIIXGetRCTForMode(modeDrive1, drv[1].transferType);       
        !           757:                if (_ideChannel == PCI_CHANNEL_PRIMARY) {
        !           758:                        sidetim->bits.pisp1 = isp;
        !           759:                        sidetim->bits.prct1 = rct;
        !           760:                }
        !           761:                else {
        !           762:                        sidetim->bits.sisp1 = isp;
        !           763:                        sidetim->bits.srct1 = rct;
        !           764:                }
        !           765:        }
        !           766: 
        !           767:        /*
        !           768:         * Enable fast timings. Turn on IORDY sampling always?
        !           769:         */
        !           770:        idetim->bits.time0 = 1;
        !           771:        idetim->bits.ppe0  = 1;
        !           772:        idetim->bits.ie0   = 1;
        !           773:        if (drv[1].ideInfo.type != 0) {
        !           774:                idetim->bits.time1 = 1;
        !           775:                idetim->bits.ppe1  = 1;
        !           776:                idetim->bits.ie1   = 1;
        !           777:        }
        !           778: 
        !           779:        /*
        !           780:         * For DMA, disable fast timing for PIO.
        !           781:         */
        !           782:        if (drv[0].transferType != IDE_TRANSFER_PIO)
        !           783:                idetim->bits.dte0 = 1;
        !           784:        if (drv[1].transferType != IDE_TRANSFER_PIO)
        !           785:                idetim->bits.dte1 = 1;
        !           786: 
        !           787:        [self PIIXReportTimings:*idetim slaveTiming:*sidetim 
        !           788:                isPrimary:(_ideChannel == PCI_CHANNEL_PRIMARY)];
        !           789: 
        !           790:        return;
        !           791: }
        !           792: 
        !           793: /*************************************************************************
        !           794:  *
        !           795:  * Intel PIIX/PIIX3/PIIX4 Bus-Mastering IDE DMA support
        !           796:  *
        !           797:  *************************************************************************/
        !           798: 
        !           799: /*
        !           800:  * Function: PIIXVirtualToPhysical
        !           801:  *
        !           802:  * Similar to IOPhysicalFromVirtual but with no SPLVM/SPLX and locking.
        !           803:  */
        !           804: static __inline__ vm_offset_t
        !           805: PIIXVirtualToPhysical(struct vm_map *map, vm_offset_t vaddr)
        !           806: {
        !           807:        return (vm_offset_t)pmap_resident_extract(
        !           808:                        (pmap_t)vm_map_pmap_EXTERNAL(map),
        !           809:                        vaddr);
        !           810: }
        !           811: 
        !           812: /*
        !           813:  * Function: PIIXStartDMA
        !           814:  *
        !           815:  * Purpose:
        !           816:  * Start the bus master by writing a 1 to the SSBM bit in BMICX register.
        !           817:  *
        !           818:  * Argument:
        !           819:  * piix_base - base address of the I/O space mapped bus master registers
        !           820:  */
        !           821: static __inline__ void
        !           822: PIIXStartDMA(u_short piix_base)
        !           823: {
        !           824:        piix_bmicx_u piix_cmd;
        !           825:        
        !           826:        /*
        !           827:         * Engage the bus master by writing 1 to the start bit in the
        !           828:         * Command Register.
        !           829:         */
        !           830:        piix_cmd.byte = inb(piix_base + PIIX_BMICX);
        !           831:        piix_cmd.bits.ssbm = 1;
        !           832:        outb(piix_base + PIIX_BMICX, piix_cmd.byte);
        !           833: }
        !           834: 
        !           835: /*
        !           836:  * Function: PIIXStopDMA
        !           837:  *
        !           838:  * Purpose:
        !           839:  * Stop the bus master by clearing the SSBM bit in BMICX register.
        !           840:  *
        !           841:  * Argument:
        !           842:  * piix_base - base address of the I/O space mapped bus master registers
        !           843:  */
        !           844: static __inline__ void
        !           845: PIIXStopDMA(u_short piix_base)
        !           846: {
        !           847:        piix_bmicx_u piix_cmd;
        !           848:        
        !           849:        /*
        !           850:         * Stop the bus master by writing 0 to the start bit in the
        !           851:         * Command Register.
        !           852:         */
        !           853:        piix_cmd.byte = inb(piix_base + PIIX_BMICX);
        !           854:        piix_cmd.bits.ssbm = 0;
        !           855:        outb(piix_base + PIIX_BMICX, piix_cmd.byte);    
        !           856: }
        !           857: 
        !           858: /*
        !           859:  * Function: PIIXGetStatus
        !           860:  *
        !           861:  * Purpose:
        !           862:  * Return the PIIX BMISX (bus master IDE status register).
        !           863:  *
        !           864:  * Argument:
        !           865:  * piix_base - base address of the I/O space mapped bus master registers
        !           866:  */
        !           867: static __inline__ u_char
        !           868: PIIXGetStatus(u_short piix_base)
        !           869: {
        !           870:        return (inb(piix_base + PIIX_BMISX));
        !           871: }
        !           872:                        
        !           873: /*
        !           874:  * Function: PIIXSetupPRDTable
        !           875:  *
        !           876:  * Purpose:
        !           877:  * Setup the PRD (descriptor) table for the current IDE transfer.
        !           878:  * This table must be aligned on a DWord (4 byte) boundary.
        !           879:  *
        !           880:  * Arguments:
        !           881:  * table    - points to the start of the PRD table
        !           882:  * size     - max number of PRD entries that the table can hold
        !           883:  * vaddr       - virtual address of the start of memory buffer
        !           884:  * size                - size of memory buffer in bytes
        !           885:  * map         - vm_map for the memory buffer
        !           886:  *
        !           887:  * Return:
        !           888:  *     YES: table is setup and ready for use
        !           889:  *     NO : table full or alignment error
        !           890:  *
        !           891:  */
        !           892: static __inline__ BOOL
        !           893: PIIXSetupPRDTable(piix_prd_t *table, u_int table_size, vm_offset_t vaddr,
        !           894:        u_int size, struct vm_map *map)
        !           895: {
        !           896:        vm_offset_t vaddr_next;
        !           897:        vm_offset_t paddr;
        !           898:        vm_offset_t paddr_next;
        !           899:        vm_offset_t paddr_start;
        !           900:        const char *name = "PIIXSetupPRDTable";
        !           901:        u_int len_prd;
        !           902:        u_int index;
        !           903: 
        !           904: #ifdef DEBUG   
        !           905:        piix_prd_t *table_saved = table;
        !           906: #endif DEBUG
        !           907: 
        !           908:        ddm_ide_dma("  PIIXSetupPRDTable: vaddr:%08x size:%d\n",
        !           909:                (u_int)vaddr, (u_int)size, 3, 4, 5);
        !           910: 
        !           911:        if (vaddr & (PIIX_BUF_ALIGN - 1)) {
        !           912:                IOLog("%s: buffer is not %d byte aligned\n", name, PIIX_BUF_ALIGN);
        !           913:                return NO;
        !           914:        }
        !           915:        
        !           916:        if (size == 0) {
        !           917:                IOLog("%s: zero length DMA buffer\n", name);
        !           918:                return NO;
        !           919:        }
        !           920:        
        !           921:        index = len_prd = 0;
        !           922:        paddr = PIIXVirtualToPhysical(map, vaddr);
        !           923:        paddr_start = paddr;
        !           924:        do {
        !           925:                u_int len;
        !           926: 
        !           927:                vaddr_next = trunc_page(vaddr) + PAGE_SIZE;             // next virtual page
        !           928:                paddr_next = trunc_page(paddr) + PAGE_SIZE;             // next phys page
        !           929:                vaddr      = vaddr_next;
        !           930:                
        !           931:                len = paddr_next - paddr;               // length to transfer in this page
        !           932:                if (len > size) len = size;             // take the minimum
        !           933:                size  -= len;                                   // decrement total remaining bytes
        !           934:                len_prd += len;                                 // increment current PRD counter
        !           935: 
        !           936:                /*
        !           937:                 * If there are more bytes remaining, try to append the next
        !           938:                 * page into the same PRD. We must check that the next page
        !           939:                 * is physically contiguous with the current one.
        !           940:                 *
        !           941:                 * Each PRD cannot cross 64K boundary, and is limited to 64K per PRD.
        !           942:                 */
        !           943:                if (size && 
        !           944:                (paddr_next == (paddr = PIIXVirtualToPhysical(map, vaddr))) &&
        !           945:                ((paddr_start & ~(PIIX_BUF_BOUND-1))==(paddr & ~(PIIX_BUF_BOUND-1))) &&
        !           946:                (len_prd <= (PIIX_BUF_LIMIT - PAGE_SIZE))) {
        !           947:                continue;
        !           948:                }
        !           949: 
        !           950:                /*
        !           951:                 * Setup PRD entry
        !           952:                 *
        !           953:                 * For the length field in PRD, 0 is used to denote the max
        !           954:                 * transfer size of 64K.
        !           955:                 */
        !           956:                table->base = paddr_start;
        !           957:                table->count = (len_prd == PIIX_BUF_LIMIT) ? 0 : len_prd;
        !           958:                table->eot = 0;
        !           959:                table++;
        !           960: 
        !           961:                len_prd = 0;
        !           962:                paddr_start = paddr;
        !           963: 
        !           964:        } while (size && (++index < table_size));
        !           965:        
        !           966:        if (size) {
        !           967:                IOLog("%s: PRD table exhausted\n", name);
        !           968:                return NO;
        !           969:        } 
        !           970:        
        !           971:        /*
        !           972:         * Set the 'end-of-table' bit on the last PRD entry.
        !           973:         */
        !           974:        --table;
        !           975:        table->eot = 1;
        !           976: 
        !           977: #ifdef DEBUG
        !           978:        {
        !           979:        int i = 0;
        !           980:        u_int *ip = (u_int *)&table_saved[0];
        !           981:        do {
        !           982:                ddm_ide_dma("    table[%d]  %08x:%08x\n", i, *ip, *(ip+1), 4, 5);
        !           983:                ip += 2;
        !           984:        } while (i++ < index);
        !           985:        }
        !           986: #endif DEBUG
        !           987: 
        !           988:        return YES;
        !           989: }
        !           990: 
        !           991: /*
        !           992:  * Function: PIIXPrepareDMA
        !           993:  *
        !           994:  * Purpose:
        !           995:  * Prepare the PIIX bus master for a DMA transfer.
        !           996:  *
        !           997:  * Arguments:
        !           998:  *  piix_base - base address of the I/O space mapped bus master registers
        !           999:  *  table     - points to the start of the PRD table
        !          1000:  *  tableAddr - physical address of the table
        !          1001:  *  isRead    - YES for read transfers (from device to host)
        !          1002:  */
        !          1003: static __inline__ BOOL
        !          1004: PIIXPrepareDMA(u_short piix_base, u_int tableAddr, BOOL isRead)
        !          1005: {
        !          1006:        piix_bmicx_u piix_cmd;
        !          1007:        piix_bmisx_u piix_status;
        !          1008: 
        !          1009:        /*
        !          1010:         * Provide the starting address of the PRD table by loading the
        !          1011:         * PRD Table Pointer Register.
        !          1012:         *
        !          1013:         * For some reason, outl(piix_base + PIIX_BMIDTPX, tableAddr)
        !          1014:         * will only write the lower 16-bit WORD. That's why we use
        !          1015:         * two outw instructions.
        !          1016:         */     
        !          1017:        outw(piix_base + PIIX_BMIDTPX, tableAddr & 0xffff);
        !          1018:        outw(piix_base + PIIX_BMIDTPX + 2, (tableAddr >> 16) & 0xffff);
        !          1019: 
        !          1020:        /*
        !          1021:         * Set the R/W bit depending on the direction of the transfer.
        !          1022:         * The controller is also STOP'ed.
        !          1023:         *
        !          1024:         * Arghh!!! Why does the Intel PIIX3 and PIIX4 doc have this backwards?
        !          1025:         */
        !          1026:        piix_cmd.byte = 0;
        !          1027:        piix_cmd.bits.rwcon = isRead ? 1 : 0;
        !          1028:        outb(piix_base + PIIX_BMICX, piix_cmd.byte);
        !          1029:        
        !          1030:        /*
        !          1031:         * Clear interrupt and error bits in the Status Register.
        !          1032:         */
        !          1033:        piix_status.byte = inb(piix_base + PIIX_BMISX);
        !          1034:        piix_status.bits.err = piix_status.bits.ideints = 1;
        !          1035: //     piix_status.bits.dma0cap = piix_status.bits.dma1cap = 1;
        !          1036:        outb(piix_base + PIIX_BMISX, piix_status.byte);
        !          1037:        
        !          1038:        return YES;
        !          1039: }
        !          1040: 
        !          1041: /*
        !          1042:  * Method: PIIXInit
        !          1043:  *
        !          1044:  * Purpose:
        !          1045:  * Initializes the PIIX controller.
        !          1046:  */
        !          1047: - (void) PIIXInit
        !          1048: {
        !          1049:        return (PIIXStopDMA(_bmRegs));
        !          1050: }
        !          1051: 
        !          1052: /*
        !          1053:  * Even if an interrupt is missed, consider the transfer operation
        !          1054:  * successful if the PIIX status flags says so.
        !          1055:  */
        !          1056: #define TRUST_PIIX     1
        !          1057: 
        !          1058: /*
        !          1059:  * Method: PIIXPerformDMA
        !          1060:  *
        !          1061:  * Purpose:
        !          1062:  * Program the PIIX controller to perform DMA READ/WRITE transfers
        !          1063:  * based on the transfer request ideIoReq. The entire transfer is
        !          1064:  * translated into one or more PRD entries in the PRD table. We will
        !          1065:  * get a single interrupt when the entire transfer is complete.
        !          1066:  *
        !          1067:  * Note:
        !          1068:  * The PIIX status register should have bit 2 and bit 0 set at the
        !          1069:  * conclusion of the transfer. This corresponds to the case when the
        !          1070:  * IDE device generated an interrupt and the size of the PRD is equal
        !          1071:  * to the IDE device transfer size.
        !          1072:  *
        !          1073:  * If bit 1 is set, meaning that the controller encountered a target
        !          1074:  * or master abort, it is very likely that we told it to DMA to/from
        !          1075:  * an invalid piece of memory. Perhaps due to an incorrect virtual
        !          1076:  * to physical map conversion.
        !          1077:  */
        !          1078: - (ide_return_t) performDMA:(ideIoReq_t *)ideIoReq
        !          1079: {
        !          1080:        ideRegsVal_t    *ideRegs = &(ideIoReq->regValues);
        !          1081:        ideRegsAddrs_t  *rp = &_ideRegsAddrs;
        !          1082:     unsigned char      status;
        !          1083:        piix_bmisx_u    piix_status;
        !          1084:        ide_return_t    rtn = IDER_SUCCESS;
        !          1085:        unsigned                cmd = ideIoReq->cmd;
        !          1086: 
        !          1087:        ddm_ide_dma("DMA block:%d count:%d read:%d map:%d rp:%x\n",
        !          1088:                ideIoReq->block,
        !          1089:                ideIoReq->blkcnt,
        !          1090:                (ideIoReq->cmd == IDE_READ_DMA),
        !          1091:                ideIoReq->map,
        !          1092:                rp->data);
        !          1093: 
        !          1094:        if ((cmd != IDE_READ_DMA) && (cmd != IDE_WRITE_DMA)) {
        !          1095:                IOLog("%s: ideDmaRwCommon: unknown command %d\n", [self name], cmd);
        !          1096:                return IDER_REJECT;
        !          1097:        }
        !          1098: 
        !          1099:        /*
        !          1100:         * wait for BSY = 0 and DRDY = 1
        !          1101:         */
        !          1102:     rtn = [self waitForDeviceReady];
        !          1103:     if (rtn != IDER_SUCCESS) {
        !          1104:                IOLog("%s: drive not ready\n", [self name]);
        !          1105:                return (rtn);
        !          1106:     }
        !          1107: 
        !          1108:        /*
        !          1109:         * Set up PRD descriptor table
        !          1110:         */
        !          1111:        if (PIIXSetupPRDTable(_prdTable.ptr,
        !          1112:                PIIX_DT_BOUND/sizeof(piix_prd_t),
        !          1113:                (vm_offset_t)ideIoReq->addr,
        !          1114:                ideIoReq->blkcnt * IDE_SECTOR_SIZE,
        !          1115:                (struct vm_map *)ideIoReq->map) == NO) {
        !          1116:                return NO;
        !          1117:        }
        !          1118: 
        !          1119:        /*
        !          1120:         * Prepare the PIIX controller for the current transfer.
        !          1121:         */
        !          1122:        if (PIIXPrepareDMA(_bmRegs, _tablePhyAddr,
        !          1123:                (ideIoReq->cmd == IDE_READ_DMA)) == NO) {
        !          1124:                IOLog("%s: PIIXPrepareDMA error\n", [self name]);
        !          1125:                return IDER_CMD_ERROR;
        !          1126:        }
        !          1127:        
        !          1128:        /*
        !          1129:         * Program the drive (task file).
        !          1130:         * Recall that _driveNum must be set prior to calling logToPhys.
        !          1131:         * This is already done in the method ideExecuteCmd which calls
        !          1132:         * this method. testDMA also calls this method with _driveNum set.
        !          1133:         */
        !          1134:        *ideRegs = [self logToPhys:ideIoReq->block numOfBlocks:ideIoReq->blkcnt];
        !          1135:     outb(rp->drHead,  ideRegs->drHead);
        !          1136:     outb(rp->sectNum, ideRegs->sectNum);
        !          1137:     outb(rp->sectCnt, ideRegs->sectCnt);
        !          1138:     outb(rp->cylLow,  ideRegs->cylLow);
        !          1139:     outb(rp->cylHigh, ideRegs->cylHigh);
        !          1140: 
        !          1141:        ddm_ide_dma(
        !          1142:                "DMA drHead:%02x sectNum:%02x sectCnt:%02x cylLow:%02x cylHigh:%02x\n",
        !          1143:                ideRegs->drHead,
        !          1144:                ideRegs->sectNum,
        !          1145:                ideRegs->sectCnt,
        !          1146:                ideRegs->cylLow,
        !          1147:                ideRegs->cylHigh);
        !          1148: 
        !          1149:        /*
        !          1150:         * Issue DMA READ/WRITE command to drive.
        !          1151:         */
        !          1152: //     [self enableInterrupts];
        !          1153: //     [self clearInterrupts];
        !          1154:     outb(rp->command, cmd);
        !          1155: 
        !          1156:        /*
        !          1157:         * Start the PIIX bus master.
        !          1158:         */
        !          1159:        PIIXStartDMA(_bmRegs);
        !          1160:        
        !          1161:        /* Wait for interrupt to signal the completion of the transfer.
        !          1162:         */
        !          1163:     rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];    
        !          1164:        piix_status.byte = PIIXGetStatus(_bmRegs);
        !          1165:        PIIXStopDMA(_bmRegs);
        !          1166:        
        !          1167: #ifdef TRUST_PIIX
        !          1168:        if ((piix_status.byte & PIIX_STATUS_MASK) == PIIX_STATUS_OK) {
        !          1169: 
        !          1170:                        if (rtn != IDER_SUCCESS) {
        !          1171:                                /* Interrupt timed-out, but PIIX claims that transaction
        !          1172:                                 * was completed without errors.
        !          1173:                                 * This may require more testing. Always trust PIIX?
        !          1174:                                 * First, read status from the drive.
        !          1175:                                 */
        !          1176:                                if ((rtn = [self waitForNotBusy]) != IDER_SUCCESS)
        !          1177:                                        return IDER_CMD_ERROR;
        !          1178:                                status = inb(rp->status);
        !          1179:                        }                        
        !          1180: #else
        !          1181:        if ((rtn == IDER_SUCCESS) && ((piix_status.byte & PIIX_STATUS_MASK) == 
        !          1182:                PIIX_STATUS_OK)) {
        !          1183: #endif TRUST_PIIX
        !          1184: 
        !          1185:                    if (status & (ERROR | WRITE_FAULT)) {
        !          1186:                                [self getIdeRegisters:ideRegs Print:"DMA error"];
        !          1187:                                return IDER_CMD_ERROR;
        !          1188:                }
        !          1189: 
        !          1190:                if (status & ERROR_CORRECTED) {
        !          1191:                                IOLog("%s: Error during data transfer (corrected).\n", 
        !          1192:                                [self name]);
        !          1193:                    }
        !          1194:        }
        !          1195:        else {
        !          1196:                [self getIdeRegisters:ideRegs Print:NULL];
        !          1197:                IOLog("%s: PIIX status:0x%02x error code:%d\n",
        !          1198:                        [self name], piix_status.byte, rtn);
        !          1199:                rtn = IDER_CMD_ERROR;
        !          1200:        }
        !          1201: 
        !          1202:        ddm_ide_dma(
        !          1203:                "END drHead:%02x sectNum:%02x sectCnt:%02x cylLow:%02x cylHigh:%02x\n",
        !          1204:        inb(rp->drHead),
        !          1205:        inb(rp->sectNum),
        !          1206:        inb(rp->sectCnt),
        !          1207:        inb(rp->cylLow),
        !          1208:        inb(rp->cylHigh));
        !          1209: 
        !          1210:        return (rtn);
        !          1211: }
        !          1212: 
        !          1213: #define MAX_BUSY_WAIT                          (1000*100)
        !          1214: 
        !          1215: /*
        !          1216:  * Perform DMA transfers for ATAPI devices.
        !          1217:  */
        !          1218: - (sc_status_t) performATAPIDMA:(atapiIoReq_t *)atapiIoReq
        !          1219:        buffer:(void *)buffer 
        !          1220:        client:(struct vm_map *)client
        !          1221: {
        !          1222:        piix_bmisx_u piix_status;
        !          1223:        unsigned char cmd = atapiIoReq->atapiCmd[0];
        !          1224:        ide_return_t    rtn;
        !          1225:     unsigned char      status;
        !          1226:        ideRegsAddrs_t  *rp = &_ideRegsAddrs;
        !          1227:        int     i;
        !          1228: 
        !          1229:        //IOLog("DMA transfer\n");
        !          1230: 
        !          1231:        atapiIoReq->bytesTransferred = 0;
        !          1232:        
        !          1233:        /*
        !          1234:         * Set up PRD descriptor table
        !          1235:         */
        !          1236:        if (PIIXSetupPRDTable(_prdTable.ptr,
        !          1237:                PIIX_DT_BOUND/sizeof(piix_prd_t),
        !          1238:                (vm_offset_t)buffer,
        !          1239:                atapiIoReq->maxTransfer,
        !          1240:                client) == NO)
        !          1241:                {
        !          1242:                atapiIoReq->scsiStatus = STAT_CHECK;
        !          1243:                return SR_IOST_CMDREJ;
        !          1244:        }
        !          1245: 
        !          1246:        if (PIIXPrepareDMA(_bmRegs, _tablePhyAddr, atapiIoReq->read) == NO) {
        !          1247:                IOLog("%s: PIIXPrepareDMA error\n", [self name]);
        !          1248:                atapiIoReq->scsiStatus = STAT_CHECK;
        !          1249:                return SR_IOST_CMDREJ;
        !          1250:        }
        !          1251: 
        !          1252:        /*
        !          1253:         * Start the PIIX bus master.
        !          1254:         */
        !          1255:        PIIXStartDMA(_bmRegs);
        !          1256: 
        !          1257:        if (atapiIoReq->timeout > IDE_INTR_TIMEOUT) {
        !          1258:                u_int current_timeout = [self interruptTimeOut];
        !          1259:                
        !          1260:                //IOLog("using SCSI timeout:%d\n", atapiIoReq->timeout);
        !          1261:                [self setInterruptTimeOut:atapiIoReq->timeout];
        !          1262:                rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
        !          1263:                [self setInterruptTimeOut:current_timeout];
        !          1264:        }
        !          1265:        else {
        !          1266:                rtn = [self ideWaitForInterrupt:cmd ideStatus:&status];
        !          1267:        }
        !          1268: 
        !          1269:        piix_status.byte = PIIXGetStatus(_bmRegs);
        !          1270:        PIIXStopDMA(_bmRegs);
        !          1271: 
        !          1272:        /*
        !          1273:         * This is stupid but the Chinon drive fires off an interrupt first
        !          1274:         * and then updates the status register. It appears that any drive
        !          1275:         * based on Western Digital chipset will do this. At any rate, this
        !          1276:         * code is harmless and should be left here. 
        !          1277:         */
        !          1278:        for (i = 0; i < MAX_BUSY_WAIT; i++)     {
        !          1279:                if (status & BUSY)
        !          1280:                        IODelay(10);
        !          1281:                else
        !          1282:                        break;
        !          1283:                status = inb(_ideRegsAddrs.status);     
        !          1284:        }
        !          1285: 
        !          1286: #ifdef TRUST_PIIX
        !          1287:        if ((piix_status.byte & PIIX_STATUS_MASK) == PIIX_STATUS_OK) {
        !          1288:                if (rtn != IDER_SUCCESS) {
        !          1289:                        /* Interrupt timed-out, but PIIX claims that transaction
        !          1290:                         * was completed without errors.
        !          1291:                         * This may require more testing. Always trust PIIX?
        !          1292:                         * First, read status from the drive.
        !          1293:                         */
        !          1294:                        if ((rtn = [self waitForNotBusy]) != IDER_SUCCESS) {
        !          1295:                                IOLog("%s: FATAL: ATAPI Drive: %d Command %x failed.\n", 
        !          1296:                                        [self name], _driveNum, atapiIoReq->atapiCmd[0]);
        !          1297:                                [self getIdeRegisters:NULL Print:"ATAPI DMA"];
        !          1298:                                IOLog("%s: transfer size: %d\n",
        !          1299:                                        [self name], atapiIoReq->maxTransfer);
        !          1300:                                [self atapiSoftReset:_driveNum];
        !          1301:                                atapiIoReq->scsiStatus = STAT_CHECK;
        !          1302:                                return SR_IOST_CHKSNV;
        !          1303:                        }
        !          1304:                        status = inb(rp->status);
        !          1305:                }
        !          1306: #else
        !          1307:        if ((rtn == IDER_SUCCESS) && ((piix_status.byte & PIIX_STATUS_MASK) == 
        !          1308:                PIIX_STATUS_OK)) {
        !          1309: #endif TRUST_PIIX
        !          1310: 
        !          1311:                if (status & ERROR) {
        !          1312:                        atapiIoReq->scsiStatus = STAT_CHECK;
        !          1313:                        return SR_IOST_CHKSNV;  
        !          1314:                }
        !          1315:        }
        !          1316:        else {
        !          1317:                [self getIdeRegisters:NULL Print:"ATAPI DMA"];
        !          1318:                IOLog("%s: PIIX status:0x%02x error code:%d\n",
        !          1319:                        [self name], piix_status.byte, rtn);
        !          1320:                IOLog("%s: transfer size: %d\n", [self name], atapiIoReq->maxTransfer);
        !          1321:                [self atapiSoftReset:_driveNum];
        !          1322:                atapiIoReq->scsiStatus = STAT_CHECK;
        !          1323:                return SR_IOST_CHKSNV;
        !          1324:        }
        !          1325: 
        !          1326:        atapiIoReq->bytesTransferred = atapiIoReq->maxTransfer;
        !          1327:        atapiIoReq->scsiStatus = STAT_GOOD;
        !          1328:        return SR_IOST_GOOD;
        !          1329: }
        !          1330: 
        !          1331: @end

unix.superglobalmegacorp.com

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