|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.