|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 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: /* Copyright 1997-1999 Apple Computer Inc. All Rights Reserved. */
24: /* @author Martin Minow */
25: /* Private structures and definitions for Apple 53C96 SCSI driver. */
26:
27:
28:
29: /***** For fans of kprintf, IOLog and debugging infrastructure of the *****/
30: /***** string ilk, please modify the ELG and PAUSE macros or their *****/
31: /***** associated EvLog and Pause functions to suit your taste. These *****/
32: /***** macros currently are set up to log events to a wraparound *****/
33: /***** buffer with minimal performance impact. They take 2 UInt32 *****/
34: /***** parameters so that when the buffer is dumped 16 bytes per line, *****/
35: /***** time stamps (~1 microsecond) run down the left side while *****/
36: /***** unique 4-byte ASCII codes can be read down the right side. *****/
37: /***** Preserving this convention facilitates different maintainers *****/
38: /***** using different debugging styles with minimal code clutter. *****/
39:
40: #define CustomMiniMon 0
41: //#define CustomMiniMon 1 // for debugging
42: #define USE_ELG 0
43: //#define USE_ELG 1 // for debugging
44: #define kEvLogSize (4096*16) // 16 pages = 64K = 4096 events
45:
46: #if USE_ELG /* (( */
47: #define ELG(A,B,ASCI,STRING) EvLog( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
48: #define PAUSE(A,B,ASCI,STRING) Pause( (UInt32)(A), (UInt32)(B), (UInt32)(ASCI), STRING )
49: #else /* ) not USE_ELG: ( */
50: #define ELG(A,B,ASCI,S)
51: #define PAUSE(A,B,ASCI,STRING) IOLog( "Curio: %8x %8x " STRING, (unsigned int)(A), (unsigned int)(B) )
52: #endif /* USE_ELG )) */
53:
54:
55: //#if USE_ELG && CustomMiniMon
56: #if USE_ELG
57: /* for debugging: */
58: // extern void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str );
59: // extern void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str );
60: // extern void AllocateEventLog( UInt32 ); // defined in miniMon
61: #endif /* NotMiniMon */
62:
63:
64: #ifndef SynchronizeIO
65: #define SynchronizeIO() eieio() /* TEMP */
66: #endif /* SynchronizeIO */
67:
68: #define SWAP(x) (UInt32)OSSwapInt32( (UInt32)(x) )
69:
70:
71:
72: enum /* Generic numeric parameters. */
73: { /* gMaxDMATransfer is set so that we don't have to worry about the */
74: /* ambiguous "zero" value in the Curio and DBDMA transfer registers */
75: /* that can mean either 65536 bytes or zero bytes. */
76: kMaxDMATransfer = 0xF000, // round down 1 page
77: /* Max number memory segments to fetch from the memory cursor. */
78: kMaxMemoryCursorSegments = 16,
79:
80: kMaxTargetID = 8,/* The maximum number of targets and logical units. */
81: kMaxLUN = 8,
82: /* The default initiator bus ID (needs to be fetched from NVRAM). */
83: kInitiatorIDDefault = 7,
84:
85: kSCSIResetDelay = 250, /* Delay (in msec) after Bus Reset */
86: /* Size of buffers used to store message-phase bytes. */
87: kMessageInBufferLength = 16,
88: kMessageOutBufferLength = 16
89: };
90:
91:
92: enum /* These values represent no active request: */
93: { kInvalidTarget = 0xFF,
94: kInvalidLUN = 0xFF,
95: kInvalidTag = 0xFFFFFFFF
96: };
97:
98: enum // Registry stuff:
99: {
100: kCurioRegisterBase = 0,
101: kDBDMARegisterBase = 1,
102: kNumberRegisters = 2
103: };
104:
105: enum // SCSI Message byte ranges
106: {
107: kSCSIMsgOneByteMax = 0x1Fu,
108: kSCSIMsgTwoByteMin = 0x20u,
109: kSCSIMsgTwoByteMax = 0x2Fu
110: };
111:
112:
113:
114: typedef enum BusPhase /* These are the real SCSI bus phases */
115: {
116: kBusPhaseDATO = 0,
117: kBusPhaseDATI,
118: kBusPhaseCMD,
119: kBusPhaseSTS,
120: kBusPhaseReserved1,
121: kBusPhaseReserved2,
122: kBusPhaseMSGO,
123: kBusPhaseMSGI,
124: kBusPhaseBusFree
125: } BusPhase;
126:
127:
128: typedef enum MsgInState
129: {
130: kMsgInInit = 0, /* 0 Not reading a message (must be zero) */
131: kMsgInReading, /* 1 MSG input state: reading counted data */
132: kMsgInCounting, /* 2 MSG input state: reading count byte */
133: kMsgInReady /* 3 MSG input state: a msg is now available */
134: } MsgInState;
135:
136:
137: /* Values for the finite-state automaton, stored in the fBusState */
138: /* instance variable: */
139: /* SCS_DISCONNECTED Normal "bus free" state (we're not processing */
140: /* any commands). */
141: /* SCS_SELECTING Just tried to select a remote target. */
142: /* SCS_RESELECTING Reselection transistion state */
143: /* SCS_INITIATOR Normal "processing bus phases" state. Set */
144: /* after correctly responding to an interrupt. */
145: /* Changed to an in-progress state. */
146: /* SCS_COMPLETING In command-complete sequence */
147: /* SCS_WAIT_FOR_BUS_FREE After disconnect or command complete, before*/
148: /* seeing disconnect interrupt or reselection */
149: /* SCS_DMACOMPLETE After starting DMA, waiting for completion */
150: /* SCS_SENDINGMSG After sending an MSGO byte */
151: /* SCS_GETTINGMSG While getting MSGI bytes */
152: /* SCS_SENDINGCMD While sending CMDO bytes */
153: /* SCS_DEATH_MARCH The target got lost. Follow phases until */
154: /* it disconnects. */
155: typedef enum
156: {
157: SCS_DISCONNECTED, /* disconnected */
158: SCS_SELECTING, /* SELECT command issued */
159: SCS_RESELECTING, /* Handle reselection after interrrupt */
160: SCS_INITIATOR, /* following target SCSI phase */
161: SCS_COMPLETING, /* initiator command complete in progress */
162: SCS_WAIT_FOR_BUS_FREE, /* transition after disconnect or complete */
163: SCS_DMACOMPLETE, /* dma (in or out) is in progress */
164: SCS_SENDINGMSG, /* MSG_OUT phase in progress */
165: SCS_GETTINGMSG, /* transfer msg in progress */
166: SCS_SENDINGCMD, /* command out in progress */
167: SCS_DEATH_MARCH /* recovery from target confusion */
168: } BusState;
169:
170:
171: /* These constants define the DBDMA channel command operations and modifiers: */
172:
173: enum /* Command.cmd operations */
174: {
175: OUTPUT_MORE = 0x00000000,
176: OUTPUT_LAST = 0x10000000,
177: INPUT_MORE = 0x20000000,
178: INPUT_LAST = 0x30000000,
179: IO_LAST = 0x10000000,
180: STOP_CMD = 0x70000000,
181: };
182:
183:
184: /* Define offsets into the Curio chip: */
185:
186: typedef enum
187: {
188: rXCL = 0x00, /* Transfer counter LSB */
189: rXCM = 0x10, /* Transfer counter MSB */
190: rFFO = 0x20, /* FIFO */
191: rCMD = 0x30, /* Command */
192: rSTA = 0x40, /* Status (r) or Destination bus ID */
193: rINT = 0x50, /* Interrupt (r) or Select/reselect timeout */
194: rSQS = 0x60, /* Sequence step (r) or Synch Period */
195: rFOS = 0x70, /* FIFO Flags/Sequence Step (r) or Sync Offset */
196: rCF1 = 0x80, /* Configuration 1 */
197: rCKF = 0x90, /* Clock Conversion Factor */
198: rTST = 0xA0, /* Test */
199: rCF2 = 0xB0, /* Configuration 2 */
200: rCF3 = 0xC0, /* Configuration 3 */
201: rCF4 = 0xD0, /* Configuration 4 */
202: rTCH = 0xE0, /* Transfer counter high/ID */
203: rDMA = 0xF0 /* Pseudo-DMA */
204: } CurioRegisters;
205:
206: /* SCSI 53C96 (ASC - Advanced SCSI Controller) Command Set */
207:
208: enum
209: {
210: cNOP = 0x00, /* NOP command */
211: cFlshFFO = 0x01, /* flush FIFO command */
212: cRstSChp = 0x02, /* reset SCSI chip */
213: cRstSBus = 0x03, /* reset SCSI bus */
214:
215: cIOXfer = 0x10, /* non-DMA Transfer command */
216: cCmdComp = 0x11, /* Initiator Command Complete Seq */
217: cMsgAcep = 0x12, /* Message Accepted */
218: cXferPad = 0x18, /* Transfer pad */
219: cDisconnect = 0x23, /* Disconnect from the SCSI bus */
220: cSlctNoAtn = 0x41, /* Select Without ATN Sequence */
221: cSlctAtn = 0x42, /* Select With ATN Sequence */
222: cSlctAtnStp = 0x43, /* Select With ATN and Stop Seq */
223: cEnSelResel = 0x44, /* Enable Selection/Reselection */
224: cDsSelResel = 0x45, /* Disable Selection/Reselection */
225: cSlctAtn3 = 0x46, /* Select with ATN, send 3 byte msg */
226:
227: cSetAtn = 0x1A, /* Set ATN command */
228: cRstAtn = 0x1B, /* Reset ATN command */
229:
230: bDMAEnBit = 0x80, /* DMA command */
231: bDscCmdState = 0x40, /* Disconnected State Group Cmd's */
232:
233: cDMAXfer = ( bDMAEnBit | cIOXfer ), /* DMA Transfer Cmd */
234: cDMAXferPad = ( bDMAEnBit | cXferPad ), /* DMA Transfer Pad */
235: cDMASelWAtn = ( bDMAEnBit | cSlctAtn ) /* Sel With ATN use DMA */
236: };
237:
238: /* (4 - rSTA) Status register bit definitions: */
239:
240: enum
241: {
242: sIO = 0x01, /* I/O bit */
243: sCD = 0x02, /* C/D bit */
244: sMsg = 0x04, /* MSG bit */
245: sCmdComp = 0x08, /* function complete bit */
246: sTermCount = 0x10, /* bus service bit */
247: sParityErr = 0x20, /* disconnected bit */
248: sGrossErr = 0x40, /* illegal command bit */
249: sIntPend = 0x80, /* SCSI interrupt pending */
250: mPhase = (sIO | sCD | sMsg), /* the phase bitmask */
251: sTCIntPend = (sTermCount | sIntPend) /* TC int pending */
252: };
253:
254:
255: /* (5 - rINT) Interrupt register bit definitions: */
256:
257: enum
258: {
259: iSelected = 0x01, /* selected bit */
260: iSelectWAtn = 0x02, /* selected w/ ATN bit */
261: iReselected = 0x04, /* reselected bit */
262: iFuncComp = 0x08, /* function complete bit */
263: iBusService = 0x10, /* bus service bit */
264: iDisconnect = 0x20, /* disconnected bit */
265: iIlegalCmd = 0x40, /* illegal command bit */
266: iResetDetect = 0x80u /* SCSI reset detected bit */
267: };
268:
269:
270: /* (7 - rFOS) FIFO Count/Sequence Step register. */
271:
272: enum
273: {
274: kFIFOCountMask = 0x1F /* mask to get FIFO count */
275: };
276:
277:
278: #define INS_STATE_MASK 0x07 /* internal state register. */
279:
280: /* Clock Conversion Values (based on SCSI chip clock - not CPU clock) */
281:
282: enum
283: {
284: ccf10MHz = 0x02, /* CLK conv factor 10.0Mhz */
285: ccf11to15MHz = 0x03, /* CLK conv factor 10.01 to 15.0Mhz */
286: ccf16to20MHz = 0x04, /* CLK conv factor 15.01 to 20.0Mhz */
287: ccf21to25MHz = 0x05, /* CLK conv factor 20.01 to 25.0Mhz */
288: ccf26to30MHz = 0x06, /* CLK conv factor 25.01 to 30.0Mhz */
289: ccf31to35MHz = 0x07, /* CLK conv factor 30.01 to 35.0Mhz */
290: ccf36to40MHz = 0x00 /* CLK conv factor 35.01 to 40.0Mhz (0 <- 8) */
291: };
292:
293: /* Select timeout values (these are the values stored in the */
294: /* chip register). */
295: /* The "Mhz" value is the SCSI bus speed from the Registry. */
296: enum
297: {
298: SelTO16Mhz = 126, /* (0x7e) using the formula: RV (regr value) */
299: /* 126 = (16MHz * 250mS)/ (7682 * 4) */
300: /* 250mS is ANSI standard. */
301: SelTO25Mhz = 167, /* (0xa7) using the formula: RV (regr value) */
302: /* 163 = (25MHz * 250mS)/ (7682 * 5) */
303: /* 250mS is ANSI standard. */
304: SelTO33Mhz = 167, /* (0xa7) using the formula: RV (regr value) */
305: /* 153 = (33MHz * 250mS)/ (7682 * 7) */
306: /* 250mS is ANSI standard. */
307: SelTO40Mhz = 167 /* (0xa7) using the formula: RV (regr value) */
308: /* 163 = (40MHz * 250mS)/ (7682 * 8) */
309: /* 250mS is ANSI standard. */
310: };
311:
312: /* (8) Configuration Register 1 bit definition */
313:
314: enum
315: {
316: CF1_SLOW = 0x80, /* Slow Cable Mode enabled bit */
317: CF1_SRD = 0x40, /* SCSI Reset Reporting Int Disabled bit */
318: CF1_PTEST = 0x20, /* Parity Test Mode bit */
319: CF1_ENABPAR = 0x10, /* Enable Parity Checking bit */
320: CF1_CHIPTEST = 0x08, /* Enable Chip Test Mode bit */
321: CF1_DEFAULT_ID_MASK = 0x07 /* The default host SCSI ID mask. */
322: };
323:
324: /* (B) Configuration Register 2 bit definition */
325: enum
326: {
327: CF2_RFB = 0x80, /* Reserve FIFO Byte */
328: CF2_EPL = 0x40, /* Enable phase latch */
329: CF2_EBC = 0x20, /* Enable Byte Control */
330: CF2_DREQHIZ = 0x10, /* Force DREQ to HI-Z state */
331: CF2_SCSI2 = 0x08, /* SCSI-2 features */
332: CF2_BPA = 0x04, /* Target:bad parity abort */
333: CF2_RPE = 0x02, /* Rregister parity enable */
334: CF2_DPE = 0x01 /* DMA parity enable */
335: };
336:
337: /* (C) Configuration Register 3 bit definition */
338: enum
339: {
340: CF3_MSGID = 0x80, /* Check for valid ID message */
341: CF3_QTAG = 0x40, /* Enable 3 byte QTAG messages */
342: CF3_CDB10 = 0x20, /* Recognize 10 bytes CDBs */
343: CF3_FASTCLOCK = 0x10, /* Enable fast clock for fast SCSI */
344: CF3_FASTSCSI = 0x08, /* Enable fast SCSI */
345: CF3_SRB = 0x04, /* Save residual byte */
346: CF3_ALTDMA = 0x02, /* Alternate DMA (for threshold 8 only) */
347: CF3_T8 = 0x01, /* Force 8-byte DMA caching */
348: CONFIG_FOR_DMA = (CF3_SRB | CF3_ALTDMA | CF3_T8),
349: CONFIG_FOR_NON_DMA = (CF3_SRB)
350: };
351:
352:
353: enum
354: {
355: kDefaultInitiatorID = 7, /* SCSI Bus Initiator ID */
356: kChipDefaultBusClockMHz = 25 /* Default 53c96 clock rate in MHz */
357: };
358:
359:
360:
361: #define WRITE_REGISTER( r, v ) { fCurioAddr[ r ] = v; SynchronizeIO(); }
362:
363:
364:
365:
366: class CurioSCSIController;
367:
368: typedef struct globals /* Globals for this module (not per instance) */
369: {
370: UInt32 evLogFlag; // debugging only
371: UInt8 *evLogBuf;
372: UInt8 *evLogBufe;
373: UInt8 *evLogBufp;
374: UInt8 intLevel;
375:
376: UInt32 shadowRegs[ 3 ]; // move to per instance??? /* Last MESH register state */
377:
378: UInt32 cclLogAddr, cclPhysAddr; // for debugging/miniMon ease
379: UInt32 curioAddr; // for debugging/miniMon ease
380: class CurioSCSIController *curioInstance;
381: } globals;
382:
383:
384: typedef struct PrivCmdData /* command data private to CurioSCSIController */
385: {
386: IOMemoryDescriptor *mdp; /* Memory Descriptor Pointer */
387: UInt32 xferCount;
388: UInt32 savedDataPosition; /* getPosition at disconnect */
389: SCSIResults results;
390: bool isWrite;
391: } PrivCmdData;
392:
393:
394:
395: #define super IOSCSIParallelController
396:
397:
398: class CurioSCSIController : public IOSCSIParallelController
399: {
400: OSDeclareDefaultStructors( CurioSCSIController ) ;/* Constructor & Destructor stuff */
401:
402: private:
403:
404: IOService *fProvider;
405: IOSCSICommand *fCmd;
406: PrivCmdData *fCmdData;
407: IOMemoryMap *fIOMap;
408: IOInterruptEventSource *fInterruptEvent;
409:
410:
411: IOMemoryMap *fSCSIMemoryMap;
412: volatile UInt8 *fCurioAddr; /* curio registers (logical) */
413: UInt32 fCurioPhysAddr; /* curio registers (physical) */
414:
415: IOMemoryMap *fDBDMAMemoryMap;
416: volatile IODBDMAChannelRegisters *fDBDMAAddr; /* DBDMA registers */
417: IOPhysicalAddress fDBDMAAddrPhys; /* DBDMA registers (physical) */
418:
419: IOPhysicalAddress fCCLPhysAddr; /* Channel Command List (physical) */
420: UInt8 *fCCL; /* Channel Command List (logical) */
421: UInt32 fCCLSize; /* Channel Command List size */
422: UInt32 fDBDMADescriptorMax;/* max # Channel Commands */
423:
424: IOBigMemoryCursor *fMemoryCursor; /* ptr to Big-endian memory Cursor */
425:
426: UInt32 fReadAlignmentCount; // hack for DBDMA bug at start of
427: UInt32 fReadAlignmentIndex; // Read when buffer is misaligned
428:
429: SCSITargetLun fCurrentTargetLun;
430: UInt32 fTag; /* Last tag value */
431: UInt8 fTagType; /* Last tag type - simple queue... */
432:
433: #define kFlagMsgIn_Reject 0x01
434: #define kFlagMsgIn_Disconnect 0x02
435: UInt8 fMsgInFlag;
436:
437: #define kFlagMsgOut_SDTR 0x01
438: #define kFlagMsgOut_Queuing 0x02
439:
440: UInt8 fInitiatorID; /* Our SCSI ID */
441: UInt8 fInitiatorIDMask; /* BusID bitmask for selection */
442: UInt8 fSelectionTimeout; /* In MESH 10 msec units */
443:
444: UInt8 fSaveStatus; /* Shadow status register */
445: UInt8 fSaveSeqStep; /* Shadow sequence xtep reg. */
446: UInt8 fSaveInterrupt; /* Shadow interrupt register */
447: bool fCkForAnotherInt;
448: bool fNeedAnotherInterrupt;
449: BusState fBusState; /* The overall state automaton */
450: bool fBusBusy;
451:
452: UInt32 fThisTransferLength; /* Current data transfer count */
453: UInt8 fCurrentBusPhase; /* Last known SCSI phase */
454:
455: SInt32 fMsgInCount; /* Message bytes still to read */
456: MsgInState fMsgInState; /* How are we handling messages */
457: UInt32 fMsgInIndex; /* Free spot in fMsgInBuffer */
458: UInt8 fMsgInBuffer[ kMessageInBufferLength ];
459:
460: UInt8 *fpMsgOut; /* next MsgO byte to buffer */
461: UInt8 *fpMsgPut; /* next MsgO byte fm buffer */
462: UInt8 fMsgOutBuffer[ kMessageOutBufferLength ];
463: UInt8 fMsgOutCount;
464:
465: UInt32 fSCSIClockRate; /* Chip clock in MHz */
466:
467:
468:
469: protected:
470:
471: bool configure( IOService*, SCSIControllerInfo* );
472: void executeCommand( IOSCSICommand* );
473: void cancelCommand( IOSCSICommand* );
474: void resetCommand( IOSCSICommand* );
475:
476: private:
477:
478: IOReturn initHardware();
479: IOReturn getHardwareMemoryMaps();
480: void releaseHardwareMemoryMaps();
481: IOReturn allocHdwAndChanMem();
482: IOReturn doHBASelfTest();
483: void initCP();
484:
485: void interruptOccurred( IOInterruptEventSource *ies, int intCount );
486: void doHardwareInterrupt();
487: void processInterrupt();
488: bool quickCheckForInterrupt();
489: bool interruptPending();
490: void handleReselectionInterrupt();
491: IOReturn getReselectionTargetID( UInt8 selectByte );
492: void reselectNexus();
493:
494: bool startCommand();
495: void completeCommand();
496:
497: void fsmSelecting();
498: void fsmDisconnected();
499: void fsmWaitForBusFree();
500: void fsmInitiator();
501: void fsmCompleting();
502: void fsmDMAComplete();
503: void fsmGettingMsg();
504: IOReturn fsmProcessMessage();
505: void fsmSendingCmd();
506: void fsmReselecting();
507: void fsmPhaseChange();
508: void fsmStartDataPhase( bool isDataInPhase );
509: void fsmStartErrorRecovery( IOReturn status );
510: void fsmErrorRecoveryInterruptService();
511: void fsmContinueErrorRecovery();
512:
513: IOReturn generateCCL();
514: void setCmdReg( UInt8 );
515: void putCDBIntoFIFO();
516:
517: void resetCurio();
518: IOReturn resetHardware( bool busReset );
519: void resetBus();
520:
521: void killActiveCommand( IOReturn finalStatus );
522: };/* end class CurioSCSIController */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.