|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: /* Sym8xxInit.m created by russb2 on Sat 30-May-1998 */ ! 24: ! 25: /*-----------------------------------------------------------------------------* ! 26: * This module contains initialization routines for the driver. ! 27: * ! 28: * Driver initialization consists of: ! 29: * ! 30: * - Doing PCI bus initialization for the script engine PCI device. ! 31: * - Setting up shared communication areas in system memory between the script ! 32: * and the driver. ! 33: * - Copying the script program into the script engine on-board ram, applying ! 34: * script relocation fixups as required. ! 35: * - Setting the initial register values for the script engine. ! 36: * - Setting up driver related storage and interfacing with driverKit. ! 37: * ! 38: *-----------------------------------------------------------------------------*/ ! 39: ! 40: /* ! 41: * This define causes Sym8xxScript.h to include the script instructions and ! 42: * relocation tables. Normally without this define we only will get #define ! 43: * values for interfacing with the script. ! 44: */ ! 45: #define INCL_SCRIPT_TEXT ! 46: ! 47: #import "Sym8xxController.h" ! 48: ! 49: #define super IOSCSIParallelController ! 50: ! 51: OSDefineMetaClassAndStructors( Sym8xxSCSIController, IOSCSIParallelController ) ; ! 52: ! 53: /*-----------------------------------------------------------------------------* ! 54: * This structure contains most of the inital register settings for ! 55: * the script engine. See Sym8xxRegs.h for the actual initialization ! 56: * values. ! 57: * ! 58: *-----------------------------------------------------------------------------*/ ! 59: typedef struct ChipInitRegs ! 60: { ! 61: UInt32 regNum; ! 62: UInt32 regSize; ! 63: UInt32 regValue; ! 64: ! 65: } ChipInitRegs; ! 66: ! 67: static ChipInitRegs Sym8xxInitRegs[] = ! 68: { ! 69: { SCNTL0, SCNTL0_SIZE, SCNTL0_INIT }, ! 70: { SCNTL1, SCNTL1_SIZE, SCNTL1_INIT }, ! 71: { SCNTL2, SCNTL2_SIZE, SCNTL2_INIT }, ! 72: { SCNTL3, SCNTL3_SIZE, SCNTL3_INIT_875 }, ! 73: { SXFER, SXFER_SIZE, SXFER_INIT }, ! 74: { SDID, SDID_SIZE, SDID_INIT }, ! 75: { GPREG, GPREG_SIZE, GPREG_INIT }, ! 76: { SFBR, SFBR_SIZE, SFBR_INIT }, ! 77: { SOCL, SOCL_SIZE, SOCL_INIT }, ! 78: { DSA, DSA_SIZE, DSA_INIT }, ! 79: { ISTAT, ISTAT_SIZE, ISTAT_INIT }, ! 80: { TEMP, TEMP_SIZE, TEMP_INIT }, ! 81: { CTEST0, CTEST0_SIZE, CTEST0_INIT }, ! 82: { CTEST3, CTEST3_SIZE, CTEST3_INIT_A }, ! 83: { CTEST4, CTEST4_SIZE, CTEST4_INIT }, ! 84: { CTEST5, CTEST5_SIZE, CTEST5_INIT_A_revB}, ! 85: { DBC, DBC_SIZE, DBC_INIT }, ! 86: { DCMD, DCMD_SIZE, DCMD_INIT }, ! 87: { DNAD, DNAD_SIZE, DNAD_INIT }, ! 88: { DSPS, DSPS_SIZE, DSPS_INIT }, ! 89: { SCRATCHA, SCRATCHA_SIZE, SCRATCHA_INIT }, ! 90: { DMODE, DMODE_SIZE, DMODE_INIT_A }, ! 91: { DIEN, DIEN_SIZE, DIEN_INIT }, ! 92: { DWT, DWT_SIZE, DWT_INIT }, ! 93: { DCNTL, DCNTL_SIZE, DCNTL_INIT_A }, ! 94: { SIEN, SIEN_SIZE, SIEN_INIT }, ! 95: { SLPAR, SLPAR_SIZE, SLPAR_INIT }, ! 96: { MACNTL, MACNTL_SIZE, MACNTL_INIT }, ! 97: { GPCNTL, GPCNTL_SIZE, GPCNTL_INIT }, ! 98: { STIME0, STIME0_SIZE, STIME0_INIT }, ! 99: { STIME1, STIME1_SIZE, STIME1_INIT }, ! 100: { RESPID0, RESPID0_SIZE, RESPID0_INIT }, ! 101: { RESPID1, RESPID1_SIZE, RESPID1_INIT }, ! 102: { STEST2, STEST2_SIZE, STEST2_INIT }, ! 103: { STEST3, STEST3_SIZE, STEST3_INIT }, ! 104: { SODL, SODL_SIZE, SODL_INIT }, ! 105: { SCRATCHB, SCRATCHB_SIZE, SCRATCHB_INIT } ! 106: }; ! 107: ! 108: /*-----------------------------------------------------------------------------* ! 109: * ! 110: * ! 111: *-----------------------------------------------------------------------------*/ ! 112: bool Sym8xxSCSIController::configure( IOService *forProvider, SCSIControllerInfo *controllerInfo ) ! 113: { ! 114: provider = (IOPCIDevice *)forProvider; ! 115: ! 116: if ( Sym8xxInit() == false ) ! 117: { ! 118: return false; ! 119: } ! 120: ! 121: initialReset = true; ! 122: ! 123: Sym8xxSCSIBusReset( 0 ); ! 124: IOSleep(3000); ! 125: ! 126: controllerInfo->initiatorId = 7; ! 127: ! 128: controllerInfo->maxTargetsSupported = 16; ! 129: controllerInfo->maxLunsSupported = 8; ! 130: ! 131: controllerInfo->minTransferPeriodpS = (chipId == kChipIdSym875) ? 50000 : 0; ! 132: controllerInfo->maxTransferOffset = (chipId == kChipIdSym875) ? 16 : 0; ! 133: controllerInfo->maxTransferWidth = 2; ! 134: ! 135: controllerInfo->maxCommandsPerController = 0; ! 136: controllerInfo->maxCommandsPerTarget = 0; ! 137: controllerInfo->maxCommandsPerLun = 0; ! 138: ! 139: controllerInfo->tagAllocationMethod = kTagAllocationPerController; ! 140: controllerInfo->maxTags = 128; ! 141: ! 142: controllerInfo->commandPrivateDataSize = sizeof( SRB ); ! 143: controllerInfo->targetPrivateDataSize = 0; ! 144: controllerInfo->lunPrivateDataSize = 0; ! 145: ! 146: controllerInfo->disableCancelCommands = false; ! 147: ! 148: return true; ! 149: } ! 150: ! 151: ! 152: /*-----------------------------------------------------------------------------* ! 153: * Script Initialization ! 154: * ! 155: *-----------------------------------------------------------------------------*/ ! 156: bool Sym8xxSCSIController::Sym8xxInit() ! 157: { ! 158: /* ! 159: * Perform PCI related initialization ! 160: */ ! 161: if ( Sym8xxInitPCI() == false ) ! 162: { ! 163: return false; ! 164: } ! 165: ! 166: /* ! 167: * Allocate/initialize driver resources ! 168: */ ! 169: if ( Sym8xxInitVars() == false ) ! 170: { ! 171: return false; ! 172: } ! 173: ! 174: /* ! 175: * Initialize the script engine registers ! 176: */ ! 177: if ( Sym8xxInitChip() == false ) ! 178: { ! 179: return false; ! 180: } ! 181: ! 182: /* ! 183: * Apply fixups to script and copy script to script engine's on-board ram ! 184: */ ! 185: if ( Sym8xxInitScript() == false ) ! 186: { ! 187: return false; ! 188: } ! 189: ! 190: getWorkLoop()->enableAllInterrupts(); ! 191: ! 192: /* ! 193: * Start script execution ! 194: */ ! 195: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, (UInt32) &chipRamAddrPhys[Ent_select_phase] ); ! 196: ! 197: return true; ! 198: } ! 199: ! 200: /*-----------------------------------------------------------------------------* ! 201: * Script engine PCI initialization ! 202: * ! 203: * This routine determines the chip version/revision, enables the chip address ! 204: * ranges and allocates a virtual mapping to the script engine's registers and ! 205: * on-board ram. ! 206: *-----------------------------------------------------------------------------*/ ! 207: bool Sym8xxSCSIController::Sym8xxInitPCI() ! 208: { ! 209: unsigned long pciReg0, pciReg8; ! 210: UInt32 chipRev; ! 211: UInt32 n; ! 212: UInt32 ramReg; ! 213: OSString *matchEntry; ! 214: ! 215: ! 216: /* ! 217: * Determine the number of memory ranges for the PCI device. ! 218: * ! 219: * The hardware implementation may or may not have a ROM present ! 220: * accounting for the difference in the number of ranges. ! 221: */ ! 222: n = provider->getDeviceMemoryCount(); ! 223: if ( !( n == 3 || n == 4 ) ) ! 224: { ! 225: return false; ! 226: } ! 227: ! 228: /* ! 229: * Determine the hardware version. Check the deviceID and ! 230: * RevID in the PCI config regs. ! 231: */ ! 232: pciReg0 = provider->configRead32( 0x00 ); ! 233: pciReg8 = provider->configRead32( 0x08 ); ! 234: ! 235: chipId = pciReg0 >> 16; ! 236: chipRev = pciReg8 & 0xff; ! 237: ! 238: // IOLog( "SCSI(Symbios8xx): Chip Id = %04x Chip rev = %02x\n\r", chipId, chipRev ); ! 239: ! 240: ! 241: ioMapRegs = provider->mapDeviceMemoryWithRegister( 0x14 ); ! 242: if ( ioMapRegs == 0 ) ! 243: { ! 244: return false; ! 245: } ! 246: ! 247: switch ( chipId ) ! 248: { ! 249: case kChipIdSym875: ! 250: ramReg = 0x18; ! 251: break; ! 252: ! 253: case kChipIdSym895: ! 254: case kChipIdSym896: ! 255: ramReg = 0x1C; ! 256: break; ! 257: ! 258: default: ! 259: ramReg = 0x1C; ! 260: } ! 261: ! 262: ioMapRam = provider->mapDeviceMemoryWithRegister( ramReg ); ! 263: if ( ioMapRam == 0 ) ! 264: { ! 265: return false; ! 266: } ! 267: ! 268: /* ! 269: * Assume 80Mhz external clock rate for motherboard 875 implementations ! 270: * and 40Mhz for others. ! 271: */ ! 272: matchEntry = OSDynamicCast( OSString, getProperty( gIONameMatchedKey ) ); ! 273: if ( matchEntry == 0 ) ! 274: { ! 275: IOLog("SCSI(Sym8xx): Cannot obtain matching property.\n"); ! 276: return false; ! 277: } ! 278: ! 279: if ( matchEntry->isEqualTo( "apple53C8xx" ) == true ) ! 280: { ! 281: chipClockRate = CLK_80MHz; ! 282: } ! 283: else ! 284: { ! 285: chipClockRate = CLK_40MHz; ! 286: } ! 287: ! 288: /* ! 289: * BUS MASTER, MEM I/O Space, MEM WR & INV ! 290: */ ! 291: provider->configWrite32( 0x04, 0x16 ); ! 292: ! 293: /* ! 294: * set Latency to Max , cache 32 ! 295: */ ! 296: provider->configWrite32( 0x0C, 0x2008 ); ! 297: ! 298: /* ! 299: * get chip register block mapped into pci memory ! 300: */ ! 301: chipBaseAddr = (UInt8 *)ioMapRegs->getVirtualAddress(); ! 302: chipBaseAddrPhys = (UInt8 *)ioMapRegs->getPhysicalAddress(); ! 303: ! 304: // kprintf( "SCSI(Symbios8xx): Chip Base addr = %08x(p) %08x(v)\n\r", ! 305: // (UInt32)chipBaseAddrPhys, (UInt32)chipBaseAddr ); ! 306: ! 307: chipRamAddr = (UInt8 *)ioMapRam->getVirtualAddress(); ! 308: chipRamAddrPhys = (UInt8 *)ioMapRam->getPhysicalAddress(); ! 309: ! 310: // kprintf( "SCSI(Symbios8xx): Chip Ram addr = %08x(p) %08x(v)\n\r", ! 311: // (UInt32)chipRamAddrPhys, (UInt32)chipRamAddr ); ! 312: ! 313: /* ! 314: * Attach interrupt ! 315: */ ! 316: interruptEvent = IOInterruptEventSource::interruptEventSource( ! 317: (OSObject *) this, ! 318: (IOInterruptEventAction) &Sym8xxSCSIController::interruptOccurred, ! 319: (IOService *) provider, ! 320: (int) 0 ); ! 321: ! 322: if ( interruptEvent == NULL ) ! 323: { ! 324: return false; ! 325: } ! 326: ! 327: getWorkLoop()->addEventSource( interruptEvent ); ! 328: ! 329: interruptEvent->enable(); ! 330: ! 331: /* ! 332: * ! 333: */ ! 334: memoryCursor = IOBigMemoryCursor::withSpecification( 16*1024*1024, 0xffffffff ); ! 335: if ( memoryCursor == NULL ) ! 336: { ! 337: return false; ! 338: } ! 339: ! 340: ! 341: ! 342: return true; ! 343: } ! 344: ! 345: /*-----------------------------------------------------------------------------* ! 346: * This routine allocates/initializes shared memory for communication between ! 347: * the script and the driver. In addition other driver resources semaphores, ! 348: * queues are initialized here. ! 349: * ! 350: *-----------------------------------------------------------------------------*/ ! 351: bool Sym8xxSCSIController::Sym8xxInitVars() ! 352: { ! 353: UInt32 i; ! 354: ! 355: adapter = (AdapterInterface *)IOMallocContiguous( page_size, page_size, (IOPhysicalAddress *)&adapterPhys ); ! 356: if ( adapter == 0 ) ! 357: { ! 358: return false; ! 359: } ! 360: bzero( adapter, page_size ); ! 361: ! 362: /* ! 363: * We keep two copies of the Nexus pointer array. One contains physical addresses and ! 364: * is located in the script/driver shared storage. The other copy holds the corresponding ! 365: * virtual addresses to the active Nexus structures and is located in the drivers instance ! 366: * data. ! 367: * Both tables can be accessed through indirect pointers in the script/driver communication ! 368: * area. This is the preferred method to access these arrays. ! 369: */ ! 370: adapter->nexusPtrsVirt = (Nexus **)nexusArrayVirt; ! 371: adapter->nexusPtrsPhys = (Nexus **)adapter->nexusArrayPhys; ! 372: ! 373: for (i=0; i < MAX_SCSI_TAG; i ++ ) ! 374: { ! 375: adapter->nexusPtrsVirt[i] = (Nexus *) -1; ! 376: adapter->nexusPtrsPhys[i] = (Nexus *) -1; ! 377: } ! 378: ! 379: /* ! 380: * The script/driver communication area also contains a 16-entry table clock ! 381: * settings for each target. ! 382: */ ! 383: for (i=0; i < MAX_SCSI_TARGETS; i++ ) ! 384: { ! 385: adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875; ! 386: } ! 387: ! 388: ! 389: return true; ! 390: } ! 391: ! 392: ! 393: /*-----------------------------------------------------------------------------* ! 394: * This routine makes a temporary copy of the script program, applies script fixups, ! 395: * initializes the script local data table at the top of the script image, and ! 396: * copies the modified script image to the script engine's on-board ram. ! 397: * ! 398: *-----------------------------------------------------------------------------*/ ! 399: bool Sym8xxSCSIController::Sym8xxInitScript() ! 400: { ! 401: UInt32 i; ! 402: UInt32 scriptPgm[sizeof(BSC_SCRIPT)/sizeof(UInt32)]; ! 403: ! 404: /* ! 405: * Make a copy of the script ! 406: */ ! 407: bcopy( BSC_SCRIPT, scriptPgm, sizeof(scriptPgm) ); ! 408: bzero( scriptPgm, R_ld_size ); ! 409: ! 410: /* ! 411: * Apply fixups to the script copy ! 412: */ ! 413: for ( i=0; i < sizeof(Rel_Patches)/sizeof(UInt32); i++ ) ! 414: { ! 415: scriptPgm[Rel_Patches[i]] += (UInt32)chipRamAddrPhys; ! 416: } ! 417: for ( i=0; i < sizeof(LABELPATCHES)/sizeof(UInt32); i++ ) ! 418: { ! 419: scriptPgm[LABELPATCHES[i]] += (UInt32)chipRamAddrPhys; ! 420: } ! 421: ! 422: /* ! 423: * Initialize the script working variables with pointers to the script/driver ! 424: * communications area. ! 425: */ ! 426: scriptPgm[R_ld_sched_mlbx_base_adr >> 2] = (UInt32)&adapterPhys->schedMailBox; ! 427: scriptPgm[R_ld_nexus_array_base >> 2] = (UInt32)&adapterPhys->nexusArrayPhys; ! 428: scriptPgm[R_ld_device_table_base_adr >> 2] = (UInt32)&adapterPhys->targetClocks; ! 429: ! 430: /* ! 431: * Load the script image into the script engine's on-board ram. ! 432: */ ! 433: Sym8xxLoadScript( (UInt32 *)scriptPgm, sizeof(scriptPgm)/sizeof(UInt32) ); ! 434: ! 435: return true; ! 436: } ! 437: ! 438: ! 439: /*-----------------------------------------------------------------------------* ! 440: * This routine transfers the script program image into the script engine's ! 441: * on-board ram ! 442: * ! 443: *-----------------------------------------------------------------------------*/ ! 444: void Sym8xxSCSIController::Sym8xxLoadScript( UInt32 *scriptPgm, UInt32 scriptWords ) ! 445: { ! 446: UInt32 i; ! 447: volatile UInt32 *ramPtr = (volatile UInt32 *)chipRamAddr; ! 448: ! 449: for ( i = 0; i < scriptWords; i++ ) ! 450: { ! 451: ramPtr[i] = OSSwapHostToLittleInt32(scriptPgm[i]); ! 452: } ! 453: } ! 454: ! 455: /*-----------------------------------------------------------------------------* ! 456: * This routine initializes the script engine's register block. ! 457: * ! 458: *-----------------------------------------------------------------------------*/ ! 459: bool Sym8xxSCSIController::Sym8xxInitChip() ! 460: { ! 461: UInt32 i; ! 462: ! 463: /* ! 464: * Reset the script engine ! 465: */ ! 466: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, RST ); ! 467: IODelay( 25 ); ! 468: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ISTAT_INIT ); ! 469: ! 470: /* ! 471: * Load our canned register values into the script engine ! 472: */ ! 473: for ( i = 0; i < sizeof(Sym8xxInitRegs)/sizeof(ChipInitRegs); i++ ) ! 474: { ! 475: Sym8xxWriteRegs( chipBaseAddr, Sym8xxInitRegs[i].regNum, Sym8xxInitRegs[i].regSize, Sym8xxInitRegs[i].regValue ); ! 476: IODelay( 10 ); ! 477: } ! 478: ! 479: /* ! 480: * For hardware implementations that have a 40Mhz SCLK input, we enable the chip's on-board ! 481: * clock doubler to bring the clock rate upto 80Mhz which is required for Ultra-SCSI timings. ! 482: */ ! 483: if ( chipClockRate == CLK_40MHz ) ! 484: { ! 485: /* ! 486: * Clock doubler setup for 875 (rev 3 and above). ! 487: */ ! 488: /* set clock doubler enabler bit */ ! 489: Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN); ! 490: IODelay(30); ! 491: /* halt scsi clock */ ! 492: Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT | HSC ); ! 493: IODelay(10); ! 494: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, SCNTL3_INIT_875); ! 495: IODelay(10); ! 496: /* set clock doubler select bit */ ! 497: Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN | DBLSEL); ! 498: IODelay(10); ! 499: /* clear hold on scsi clock */ ! 500: Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT); ! 501: } ! 502: ! 503: /* ! 504: * Set our host-adapter ID in the script engine's registers ! 505: */ ! 506: initiatorID = kHostAdapterSCSIId; ! 507: ! 508: if ( initiatorID > 7 ) ! 509: { ! 510: Sym8xxWriteRegs( chipBaseAddr, RESPID1, RESPID1_SIZE, 1 << (initiatorID-8)); ! 511: } ! 512: else ! 513: { ! 514: Sym8xxWriteRegs( chipBaseAddr, RESPID0, RESPID0_SIZE, 1 << initiatorID); ! 515: } ! 516: ! 517: Sym8xxWriteRegs( chipBaseAddr, SCID, SCID_SIZE, SCID_INIT | initiatorID ); ! 518: ! 519: return true; ! 520: } ! 521: ! 522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.