]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/scsi/drvSymbios8xx/Sym8xxInit.cpp
64bb689dee6446aa719e8cf43d80a6d508bac295
[apple/xnu.git] / iokit / Drivers / scsi / drvSymbios8xx / Sym8xxInit.cpp
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 #include "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 case kChipIdSym1010:
256 ramReg = 0x1C;
257 break;
258
259 default:
260 ramReg = 0x1C;
261 }
262
263 ioMapRam = provider->mapDeviceMemoryWithRegister( ramReg );
264 if ( ioMapRam == 0 )
265 {
266 return false;
267 }
268
269 /*
270 * Assume 80Mhz external clock rate for motherboard 875 implementations
271 * and 40Mhz for others.
272 */
273 matchEntry = OSDynamicCast( OSString, getProperty( gIONameMatchedKey ) );
274 if ( matchEntry == 0 )
275 {
276 IOLog("SCSI(Sym8xx): Cannot obtain matching property.\n");
277 return false;
278 }
279
280 if ( matchEntry->isEqualTo( "apple53C8xx" ) == true )
281 {
282 chipClockRate = CLK_80MHz;
283 }
284 else
285 {
286 chipClockRate = CLK_40MHz;
287 }
288
289 /*
290 * BUS MASTER, MEM I/O Space, MEM WR & INV
291 */
292 provider->configWrite32( 0x04, 0x16 );
293
294 /*
295 * set Latency to Max , cache 32
296 */
297 provider->configWrite32( 0x0C, 0x2008 );
298
299 /*
300 * get chip register block mapped into pci memory
301 */
302 chipBaseAddr = (UInt8 *)ioMapRegs->getVirtualAddress();
303 chipBaseAddrPhys = (UInt8 *)ioMapRegs->getPhysicalAddress();
304
305 // kprintf( "SCSI(Symbios8xx): Chip Base addr = %08x(p) %08x(v)\n\r",
306 // (UInt32)chipBaseAddrPhys, (UInt32)chipBaseAddr );
307
308 chipRamAddr = (UInt8 *)ioMapRam->getVirtualAddress();
309 chipRamAddrPhys = (UInt8 *)ioMapRam->getPhysicalAddress();
310
311 // kprintf( "SCSI(Symbios8xx): Chip Ram addr = %08x(p) %08x(v)\n\r",
312 // (UInt32)chipRamAddrPhys, (UInt32)chipRamAddr );
313
314 /*
315 * Attach interrupt
316 */
317 interruptEvent = IOInterruptEventSource::interruptEventSource(
318 (OSObject *) this,
319 (IOInterruptEventAction) &Sym8xxSCSIController::interruptOccurred,
320 (IOService *) provider,
321 (int) 0 );
322
323 if ( interruptEvent == NULL )
324 {
325 return false;
326 }
327
328 getWorkLoop()->addEventSource( interruptEvent );
329
330 interruptEvent->enable();
331
332 /*
333 *
334 */
335 memoryCursor = IOBigMemoryCursor::withSpecification( 16*1024*1024, 0xffffffff );
336 if ( memoryCursor == NULL )
337 {
338 return false;
339 }
340
341
342
343 return true;
344 }
345
346 /*-----------------------------------------------------------------------------*
347 * This routine allocates/initializes shared memory for communication between
348 * the script and the driver. In addition other driver resources semaphores,
349 * queues are initialized here.
350 *
351 *-----------------------------------------------------------------------------*/
352 bool Sym8xxSCSIController::Sym8xxInitVars()
353 {
354 UInt32 i;
355
356 adapter = (AdapterInterface *)IOMallocContiguous( page_size, page_size, (IOPhysicalAddress *)&adapterPhys );
357 if ( adapter == 0 )
358 {
359 return false;
360 }
361 bzero( adapter, page_size );
362
363 /*
364 * We keep two copies of the Nexus pointer array. One contains physical addresses and
365 * is located in the script/driver shared storage. The other copy holds the corresponding
366 * virtual addresses to the active Nexus structures and is located in the drivers instance
367 * data.
368 * Both tables can be accessed through indirect pointers in the script/driver communication
369 * area. This is the preferred method to access these arrays.
370 */
371 adapter->nexusPtrsVirt = (Nexus **)nexusArrayVirt;
372 adapter->nexusPtrsPhys = (Nexus **)adapter->nexusArrayPhys;
373
374 for (i=0; i < MAX_SCSI_TAG; i ++ )
375 {
376 adapter->nexusPtrsVirt[i] = (Nexus *) -1;
377 adapter->nexusPtrsPhys[i] = (Nexus *) -1;
378 }
379
380 /*
381 * The script/driver communication area also contains a 16-entry table clock
382 * settings for each target.
383 */
384 for (i=0; i < MAX_SCSI_TARGETS; i++ )
385 {
386 adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875;
387 }
388
389
390 return true;
391 }
392
393
394 /*-----------------------------------------------------------------------------*
395 * This routine makes a temporary copy of the script program, applies script fixups,
396 * initializes the script local data table at the top of the script image, and
397 * copies the modified script image to the script engine's on-board ram.
398 *
399 *-----------------------------------------------------------------------------*/
400 bool Sym8xxSCSIController::Sym8xxInitScript()
401 {
402 UInt32 i;
403 UInt32 scriptPgm[sizeof(BSC_SCRIPT)/sizeof(UInt32)];
404
405 /*
406 * Make a copy of the script
407 */
408 bcopy( BSC_SCRIPT, scriptPgm, sizeof(scriptPgm) );
409 bzero( scriptPgm, R_ld_size );
410
411 /*
412 * Apply fixups to the script copy
413 */
414 for ( i=0; i < sizeof(Rel_Patches)/sizeof(UInt32); i++ )
415 {
416 scriptPgm[Rel_Patches[i]] += (UInt32)chipRamAddrPhys;
417 }
418 for ( i=0; i < sizeof(LABELPATCHES)/sizeof(UInt32); i++ )
419 {
420 scriptPgm[LABELPATCHES[i]] += (UInt32)chipRamAddrPhys;
421 }
422
423 /*
424 * Initialize the script working variables with pointers to the script/driver
425 * communications area.
426 */
427 scriptPgm[R_ld_sched_mlbx_base_adr >> 2] = (UInt32)&adapterPhys->schedMailBox;
428 scriptPgm[R_ld_nexus_array_base >> 2] = (UInt32)&adapterPhys->nexusArrayPhys;
429 scriptPgm[R_ld_device_table_base_adr >> 2] = (UInt32)&adapterPhys->targetClocks;
430
431 /*
432 * Load the script image into the script engine's on-board ram.
433 */
434 Sym8xxLoadScript( (UInt32 *)scriptPgm, sizeof(scriptPgm)/sizeof(UInt32) );
435
436 return true;
437 }
438
439
440 /*-----------------------------------------------------------------------------*
441 * This routine transfers the script program image into the script engine's
442 * on-board ram
443 *
444 *-----------------------------------------------------------------------------*/
445 void Sym8xxSCSIController::Sym8xxLoadScript( UInt32 *scriptPgm, UInt32 scriptWords )
446 {
447 UInt32 i;
448 volatile UInt32 *ramPtr = (volatile UInt32 *)chipRamAddr;
449
450 for ( i = 0; i < scriptWords; i++ )
451 {
452 ramPtr[i] = OSSwapHostToLittleInt32(scriptPgm[i]);
453 }
454 }
455
456 /*-----------------------------------------------------------------------------*
457 * This routine initializes the script engine's register block.
458 *
459 *-----------------------------------------------------------------------------*/
460 bool Sym8xxSCSIController::Sym8xxInitChip()
461 {
462 UInt32 i;
463
464 /*
465 * Reset the script engine
466 */
467 Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, RST );
468 IODelay( 25 );
469 Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ISTAT_INIT );
470
471 /*
472 * Load our canned register values into the script engine
473 */
474 for ( i = 0; i < sizeof(Sym8xxInitRegs)/sizeof(ChipInitRegs); i++ )
475 {
476 Sym8xxWriteRegs( chipBaseAddr, Sym8xxInitRegs[i].regNum, Sym8xxInitRegs[i].regSize, Sym8xxInitRegs[i].regValue );
477 IODelay( 10 );
478 }
479
480 /*
481 * For hardware implementations that have a 40Mhz SCLK input, we enable the chip's on-board
482 * clock doubler to bring the clock rate upto 80Mhz which is required for Ultra-SCSI timings.
483 */
484 if ( chipClockRate == CLK_40MHz )
485 {
486 /*
487 * Clock doubler setup for 875 (rev 3 and above).
488 */
489 /* set clock doubler enabler bit */
490 Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN);
491 IODelay(30);
492 /* halt scsi clock */
493 Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT | HSC );
494 IODelay(10);
495 Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, SCNTL3_INIT_875);
496 IODelay(10);
497 /* set clock doubler select bit */
498 Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN | DBLSEL);
499 IODelay(10);
500 /* clear hold on scsi clock */
501 Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT);
502 }
503
504 /*
505 * Set our host-adapter ID in the script engine's registers
506 */
507 initiatorID = kHostAdapterSCSIId;
508
509 if ( initiatorID > 7 )
510 {
511 Sym8xxWriteRegs( chipBaseAddr, RESPID1, RESPID1_SIZE, 1 << (initiatorID-8));
512 }
513 else
514 {
515 Sym8xxWriteRegs( chipBaseAddr, RESPID0, RESPID0_SIZE, 1 << initiatorID);
516 }
517
518 Sym8xxWriteRegs( chipBaseAddr, SCID, SCID_SIZE, SCID_INIT | initiatorID );
519
520 return true;
521 }
522
523