2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 /* Sym8xxInit.m created by russb2 on Sat 30-May-1998 */
25 /*-----------------------------------------------------------------------------*
26 * This module contains initialization routines for the driver.
28 * Driver initialization consists of:
30 * - Doing PCI bus initialization for the script engine PCI device.
31 * - Setting up shared communication areas in system memory between the script
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.
38 *-----------------------------------------------------------------------------*/
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.
45 #define INCL_SCRIPT_TEXT
47 #include "Sym8xxController.h"
49 #define super IOSCSIParallelController
51 OSDefineMetaClassAndStructors( Sym8xxSCSIController
, IOSCSIParallelController
) ;
53 /*-----------------------------------------------------------------------------*
54 * This structure contains most of the inital register settings for
55 * the script engine. See Sym8xxRegs.h for the actual initialization
58 *-----------------------------------------------------------------------------*/
59 typedef struct ChipInitRegs
67 static ChipInitRegs Sym8xxInitRegs
[] =
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
}
108 /*-----------------------------------------------------------------------------*
111 *-----------------------------------------------------------------------------*/
112 bool Sym8xxSCSIController::configure( IOService
*forProvider
, SCSIControllerInfo
*controllerInfo
)
114 provider
= (IOPCIDevice
*)forProvider
;
116 if ( Sym8xxInit() == false )
123 Sym8xxSCSIBusReset( 0 );
126 controllerInfo
->initiatorId
= 7;
128 controllerInfo
->maxTargetsSupported
= 16;
129 controllerInfo
->maxLunsSupported
= 8;
131 controllerInfo
->minTransferPeriodpS
= (chipId
== kChipIdSym875
) ? 50000 : 0;
132 controllerInfo
->maxTransferOffset
= (chipId
== kChipIdSym875
) ? 16 : 0;
133 controllerInfo
->maxTransferWidth
= 2;
135 controllerInfo
->maxCommandsPerController
= 0;
136 controllerInfo
->maxCommandsPerTarget
= 0;
137 controllerInfo
->maxCommandsPerLun
= 0;
139 controllerInfo
->tagAllocationMethod
= kTagAllocationPerController
;
140 controllerInfo
->maxTags
= 128;
142 controllerInfo
->commandPrivateDataSize
= sizeof( SRB
);
143 controllerInfo
->targetPrivateDataSize
= 0;
144 controllerInfo
->lunPrivateDataSize
= 0;
146 controllerInfo
->disableCancelCommands
= false;
152 /*-----------------------------------------------------------------------------*
153 * Script Initialization
155 *-----------------------------------------------------------------------------*/
156 bool Sym8xxSCSIController::Sym8xxInit()
159 * Perform PCI related initialization
161 if ( Sym8xxInitPCI() == false )
167 * Allocate/initialize driver resources
169 if ( Sym8xxInitVars() == false )
175 * Initialize the script engine registers
177 if ( Sym8xxInitChip() == false )
183 * Apply fixups to script and copy script to script engine's on-board ram
185 if ( Sym8xxInitScript() == false )
190 getWorkLoop()->enableAllInterrupts();
193 * Start script execution
195 Sym8xxWriteRegs( chipBaseAddr
, DSP
, DSP_SIZE
, (UInt32
) &chipRamAddrPhys
[Ent_select_phase
] );
200 /*-----------------------------------------------------------------------------*
201 * Script engine PCI initialization
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
206 *-----------------------------------------------------------------------------*/
207 bool Sym8xxSCSIController::Sym8xxInitPCI()
209 unsigned long pciReg0
, pciReg8
;
213 OSString
*matchEntry
;
217 * Determine the number of memory ranges for the PCI device.
219 * The hardware implementation may or may not have a ROM present
220 * accounting for the difference in the number of ranges.
222 n
= provider
->getDeviceMemoryCount();
223 if ( !( n
== 3 || n
== 4 ) )
229 * Determine the hardware version. Check the deviceID and
230 * RevID in the PCI config regs.
232 pciReg0
= provider
->configRead32( 0x00 );
233 pciReg8
= provider
->configRead32( 0x08 );
235 chipId
= pciReg0
>> 16;
236 chipRev
= pciReg8
& 0xff;
238 // IOLog( "SCSI(Symbios8xx): Chip Id = %04x Chip rev = %02x\n\r", chipId, chipRev );
241 ioMapRegs
= provider
->mapDeviceMemoryWithRegister( 0x14 );
242 if ( ioMapRegs
== 0 )
263 ioMapRam
= provider
->mapDeviceMemoryWithRegister( ramReg
);
270 * Assume 80Mhz external clock rate for motherboard 875 implementations
271 * and 40Mhz for others.
273 matchEntry
= OSDynamicCast( OSString
, getProperty( gIONameMatchedKey
) );
274 if ( matchEntry
== 0 )
276 IOLog("SCSI(Sym8xx): Cannot obtain matching property.\n");
280 if ( matchEntry
->isEqualTo( "apple53C8xx" ) == true )
282 chipClockRate
= CLK_80MHz
;
286 chipClockRate
= CLK_40MHz
;
290 * BUS MASTER, MEM I/O Space, MEM WR & INV
292 provider
->configWrite32( 0x04, 0x16 );
295 * set Latency to Max , cache 32
297 provider
->configWrite32( 0x0C, 0x2008 );
300 * get chip register block mapped into pci memory
302 chipBaseAddr
= (UInt8
*)ioMapRegs
->getVirtualAddress();
303 chipBaseAddrPhys
= (UInt8
*)ioMapRegs
->getPhysicalAddress();
305 // kprintf( "SCSI(Symbios8xx): Chip Base addr = %08x(p) %08x(v)\n\r",
306 // (UInt32)chipBaseAddrPhys, (UInt32)chipBaseAddr );
308 chipRamAddr
= (UInt8
*)ioMapRam
->getVirtualAddress();
309 chipRamAddrPhys
= (UInt8
*)ioMapRam
->getPhysicalAddress();
311 // kprintf( "SCSI(Symbios8xx): Chip Ram addr = %08x(p) %08x(v)\n\r",
312 // (UInt32)chipRamAddrPhys, (UInt32)chipRamAddr );
317 interruptEvent
= IOInterruptEventSource::interruptEventSource(
319 (IOInterruptEventAction
) &Sym8xxSCSIController::interruptOccurred
,
320 (IOService
*) provider
,
323 if ( interruptEvent
== NULL
)
328 getWorkLoop()->addEventSource( interruptEvent
);
330 interruptEvent
->enable();
335 memoryCursor
= IOBigMemoryCursor::withSpecification( 16*1024*1024, 0xffffffff );
336 if ( memoryCursor
== NULL
)
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.
351 *-----------------------------------------------------------------------------*/
352 bool Sym8xxSCSIController::Sym8xxInitVars()
356 adapter
= (AdapterInterface
*)IOMallocContiguous( page_size
, page_size
, (IOPhysicalAddress
*)&adapterPhys
);
361 bzero( adapter
, page_size
);
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
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.
371 adapter
->nexusPtrsVirt
= (Nexus
**)nexusArrayVirt
;
372 adapter
->nexusPtrsPhys
= (Nexus
**)adapter
->nexusArrayPhys
;
374 for (i
=0; i
< MAX_SCSI_TAG
; i
++ )
376 adapter
->nexusPtrsVirt
[i
] = (Nexus
*) -1;
377 adapter
->nexusPtrsPhys
[i
] = (Nexus
*) -1;
381 * The script/driver communication area also contains a 16-entry table clock
382 * settings for each target.
384 for (i
=0; i
< MAX_SCSI_TARGETS
; i
++ )
386 adapter
->targetClocks
[i
].scntl3Reg
= SCNTL3_INIT_875
;
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.
399 *-----------------------------------------------------------------------------*/
400 bool Sym8xxSCSIController::Sym8xxInitScript()
403 UInt32 scriptPgm
[sizeof(BSC_SCRIPT
)/sizeof(UInt32
)];
406 * Make a copy of the script
408 bcopy( BSC_SCRIPT
, scriptPgm
, sizeof(scriptPgm
) );
409 bzero( scriptPgm
, R_ld_size
);
412 * Apply fixups to the script copy
414 for ( i
=0; i
< sizeof(Rel_Patches
)/sizeof(UInt32
); i
++ )
416 scriptPgm
[Rel_Patches
[i
]] += (UInt32
)chipRamAddrPhys
;
418 for ( i
=0; i
< sizeof(LABELPATCHES
)/sizeof(UInt32
); i
++ )
420 scriptPgm
[LABELPATCHES
[i
]] += (UInt32
)chipRamAddrPhys
;
424 * Initialize the script working variables with pointers to the script/driver
425 * communications area.
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
;
432 * Load the script image into the script engine's on-board ram.
434 Sym8xxLoadScript( (UInt32
*)scriptPgm
, sizeof(scriptPgm
)/sizeof(UInt32
) );
440 /*-----------------------------------------------------------------------------*
441 * This routine transfers the script program image into the script engine's
444 *-----------------------------------------------------------------------------*/
445 void Sym8xxSCSIController::Sym8xxLoadScript( UInt32
*scriptPgm
, UInt32 scriptWords
)
448 volatile UInt32
*ramPtr
= (volatile UInt32
*)chipRamAddr
;
450 for ( i
= 0; i
< scriptWords
; i
++ )
452 ramPtr
[i
] = OSSwapHostToLittleInt32(scriptPgm
[i
]);
456 /*-----------------------------------------------------------------------------*
457 * This routine initializes the script engine's register block.
459 *-----------------------------------------------------------------------------*/
460 bool Sym8xxSCSIController::Sym8xxInitChip()
465 * Reset the script engine
467 Sym8xxWriteRegs( chipBaseAddr
, ISTAT
, ISTAT_SIZE
, RST
);
469 Sym8xxWriteRegs( chipBaseAddr
, ISTAT
, ISTAT_SIZE
, ISTAT_INIT
);
472 * Load our canned register values into the script engine
474 for ( i
= 0; i
< sizeof(Sym8xxInitRegs
)/sizeof(ChipInitRegs
); i
++ )
476 Sym8xxWriteRegs( chipBaseAddr
, Sym8xxInitRegs
[i
].regNum
, Sym8xxInitRegs
[i
].regSize
, Sym8xxInitRegs
[i
].regValue
);
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.
484 if ( chipClockRate
== CLK_40MHz
)
487 * Clock doubler setup for 875 (rev 3 and above).
489 /* set clock doubler enabler bit */
490 Sym8xxWriteRegs( chipBaseAddr
, STEST1
, STEST1_SIZE
, STEST1_INIT
| DBLEN
);
492 /* halt scsi clock */
493 Sym8xxWriteRegs( chipBaseAddr
, STEST3
, STEST3_SIZE
, STEST3_INIT
| HSC
);
495 Sym8xxWriteRegs( chipBaseAddr
, SCNTL3
, SCNTL3_SIZE
, SCNTL3_INIT_875
);
497 /* set clock doubler select bit */
498 Sym8xxWriteRegs( chipBaseAddr
, STEST1
, STEST1_SIZE
, STEST1_INIT
| DBLEN
| DBLSEL
);
500 /* clear hold on scsi clock */
501 Sym8xxWriteRegs( chipBaseAddr
, STEST3
, STEST3_SIZE
, STEST3_INIT
);
505 * Set our host-adapter ID in the script engine's registers
507 initiatorID
= kHostAdapterSCSIId
;
509 if ( initiatorID
> 7 )
511 Sym8xxWriteRegs( chipBaseAddr
, RESPID1
, RESPID1_SIZE
, 1 << (initiatorID
-8));
515 Sym8xxWriteRegs( chipBaseAddr
, RESPID0
, RESPID0_SIZE
, 1 << initiatorID
);
518 Sym8xxWriteRegs( chipBaseAddr
, SCID
, SCID_SIZE
, SCID_INIT
| initiatorID
);