|
|
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.