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