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