|
|
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: /* Edit History */
26: /* 1997.02.13 MM Initial conversion from AMDPCSCSIDriver sources. */
27: /* */
28:
29:
30:
31:
32: #include <string.h> /* bzero is defined in string.h */
33: #include <mach/clock_types.h>
34: #include <libkern/OSByteOrder.h>
35: #include <IOKit/IOLib.h>
36: #include <IOKit/IOInterruptEventSource.h>
37: #include <IOKit/pci/IOPCIDevice.h>
38: #include <IOKit/ppc/IODBDMA.h>
39: #include <IOKit/system.h> /* Definition of flush_dcache */
40: #include <IOKit/scsi/IOSCSIParallelInterface.h>
41:
42: #include "curio.h"
43:
44:
45:
46:
47: extern void IOGetTime( mach_timespec_t *clock_time );
48: extern void kprintf( const char *, ... );
49: extern void call_kdp(); // for debugging
50:
51:
52: #if CustomMiniMon
53: extern globals g; /**** Use custom MiniMon's globals ****/
54: extern UInt32 gMESH_DBDMA, gMESH_DBDMA_Phys;
55: #else
56: // globals g; /**** Instantiate the globals ****/
57: static globals g; /**** Instantiate the globals ****/
58: #endif /* CustomMiniMon */
59:
60:
61: OSDefineMetaClassAndStructors( CurioSCSIController, IOSCSIParallelController ) ;
62:
63:
64: #define kIOReturnParityError kIOReturnIOError /// ??? add to IOReturn.h
65: #define kIOReturnSelectionError kIOReturnIOError /// ??? add to IOReturn.h
66:
67:
68: enum /***** values for g.intLevel: *****/
69: {
70: kLevelISR = 0x80, /* In Interrupt Service Routine */
71: kLevelLocked = 0x40, /* Curio interrupts locked out */
72: kLevelSIH = 0x20, /* In Secondary Interrupt Handler */
73: kLevelLatched = 0x10 /* Interrupt latched */
74: };
75:
76:
77:
78: #if USE_ELG && !CustomMiniMon
79: static void AllocateEventLog( UInt32 size )
80: {
81: if ( g.evLogBuf )
82: return;
83:
84: g.evLogFlag = 0; /* assume insufficient memory */
85: g.evLogBuf = (UInt8*)kalloc( size );
86: if ( !g.evLogBuf )
87: {
88: kprintf( "AllocateEventLog - CurioSCSIController evLog allocation failed " );
89: return;
90: }
91:
92: bzero( g.evLogBuf, size );
93: g.evLogBufp = g.evLogBuf;
94: g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer?
95: g.evLogFlag = 0xFEEDBEEF;
96: // g.evLogFlag = 'step';
97: // g.evLogFlag = 0x0333;
98: return;
99: }/* end AllocateEventLog */
100:
101:
102: static void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
103: {
104: register UInt32 *lp; /* Long pointer */
105: mach_timespec_t time;
106:
107: if ( g.evLogFlag == 0 )
108: return;
109:
110: IOGetTime( &time );
111:
112: lp = (UInt32*)g.evLogBufp;
113: g.evLogBufp += 0x10;
114:
115: if ( g.evLogBufp >= g.evLogBufe ) /* handle buffer wrap around if any */
116: { g.evLogBufp = g.evLogBuf;
117: if ( g.evLogFlag != 0xFEEDBEEF )
118: g.evLogFlag = 0; /* stop tracing if wrap undesired */
119: }
120:
121: /* compose interrupt level with 3 byte time stamp: */
122:
123: *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); // ~ 1 microsec resolution
124: *lp++ = a;
125: *lp++ = b;
126: *lp = ascii;
127:
128: if( g.evLogFlag == 'step' )
129: { char code[ 5 ];
130: *(UInt32*)&code = ascii; code[ 4 ] = 0;
131: // kprintf( "%8x curio: %8x %8x %s %s\n", time.tv_nsec>>10, a, b, code, str );
132: kprintf( "%8x curio: %8x %8x %s\n", time.tv_nsec>>10, a, b, code );
133: }
134:
135: return;
136: }/* end EvLog */
137:
138:
139: static void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str )
140: {
141: char work [ 256 ];
142: char name[] = "CurioSCSIController:";
143: char *bp = work;
144: UInt8 x;
145: int i;
146:
147:
148: EvLog( a, b, ascii, str );
149: EvLog( '****', '** P', 'ause', "*** Pause" );
150:
151: bcopy( name, bp, sizeof( name ) );
152: bp += sizeof( name ) - 1;
153:
154: *bp++ = '{'; // prepend p1 in hex:
155: for ( i = 7; i >= 0; --i )
156: {
157: x = a & 0x0F;
158: if ( x < 10 )
159: x += '0';
160: else x += 'A' - 10;
161: bp[ i ] = x;
162: a >>= 4;
163: }
164: bp += 8;
165:
166: *bp++ = ' '; // prepend p2 in hex:
167:
168: for ( i = 7; i >= 0; --i )
169: {
170: x = b & 0x0F;
171: if ( x < 10 )
172: x += '0';
173: else x += 'A' - 10;
174: bp[ i ] = x;
175: b >>= 4;
176: }
177: bp += 8;
178: *bp++ = '}';
179:
180: *bp++ = ' ';
181:
182: for ( i = sizeof( work ) - (int)(bp - work); i && (*bp++ = *str++); --i ) ;
183:
184: // kprintf( work );
185: panic( work );
186: // call_kdp(); // ??? use kdp=3 in boot parameters
187: return;
188: }/* end Pause */
189: #endif /* not CustomMiniMon */
190:
191:
192:
193: bool CurioSCSIController::configure( IOService *provider,
194: SCSIControllerInfo *controllerInfo )
195: {
196: IOReturn ioReturn = kIOReturnInternalError;
197:
198:
199: g.intLevel = 0;
200: g.curioInstance = this;
201: #if USE_ELG
202: AllocateEventLog( kEvLogSize );
203: ELG( g.evLogBufp, &g.evLogFlag, 'Curo', "configure - event logging set up." );
204: #endif /* USE_ELG */
205:
206: ELG( this, provider, 'Cnfg', "configure" );
207:
208: fProvider = (IOPCIDevice*)provider;
209:
210: ioReturn = initHardware();
211: if ( ioReturn != kIOReturnSuccess )
212: return false;
213:
214: /* Register our interrupt handler routine: */
215:
216: fInterruptEvent = IOInterruptEventSource::interruptEventSource(
217: (OSObject*)this,
218:
219: (IOInterruptEventAction)&CurioSCSIController::interruptOccurred,
220: provider,
221: 0 );
222:
223: if ( fInterruptEvent == NULL )
224: {
225: ELG( 0, 0, 'IES-', "CurioSCSIController::configure - can't register interrupt action" );
226: return false;
227: }
228:
229: getWorkLoop()->addEventSource( fInterruptEvent );
230: fInterruptEvent->enable();
231:
232: /* allocate a big-endian memory cursor: */
233:
234: fMemoryCursor = IOBigMemoryCursor::withSpecification( kMaxDMATransfer, kMaxDMATransfer );
235: if ( fMemoryCursor == NULL )
236: {
237: ELG( 0, kMaxDMATransfer, 'Mem-', "CurioSCSIController::start - IOBigMemoryCursor::withSpecification NG" );
238: return false;
239: }
240:
241:
242: /* Fill in the SCSIControllerInfo structure and return: */
243:
244: controllerInfo->initiatorId = 7;
245:
246: controllerInfo->maxTargetsSupported = 8;
247: controllerInfo->maxLunsSupported = 8;
248:
249: controllerInfo->minTransferPeriodpS = 200000; /* picoSecs for 5 MHz */
250: controllerInfo->maxTransferOffset = 0;
251: controllerInfo->maxTransferWidth = 1;
252:
253: controllerInfo->maxCommandsPerController= 0; // 0 is unlimited
254: controllerInfo->maxCommandsPerTarget = 0;
255: controllerInfo->maxCommandsPerLun = 0;
256:
257: controllerInfo->tagAllocationMethod = kTagAllocationPerLun;
258: controllerInfo->maxTags = 256;
259:
260: controllerInfo->commandPrivateDataSize = sizeof( PrivCmdData );
261:
262: controllerInfo->disableCancelCommands = false;
263:
264: return true;
265: }/* end configure */
266:
267:
268: void CurioSCSIController::executeCommand( IOSCSICommand *scsiCommand )
269: {
270: SCSICDBInfo scsiCDB;
271: SCSITargetParms targetParms;
272: UInt8 msgByte;
273: bool rc;
274:
275:
276:
277: if ( fCmd || fBusBusy )
278: {
279: ELG( fCmd, scsiCommand, 'Busy', "CurioSCSIController::executeCommand - bus busy so bounce this cmd" );
280: disableCommands();
281: rescheduleCommand( scsiCommand );
282: return;
283: }
284:
285: fCmd = scsiCommand;
286: fCmdData = (PrivCmdData*)scsiCommand->getCommandData();
287:
288: scsiCommand->getTargetLun( &fCurrentTargetLun );
289: scsiCommand->getCDB( &scsiCDB );
290: scsiCommand->getDevice(kIOSCSIDevice)->getTargetParms( &targetParms );
291:
292: ELG( scsiCommand,
293: *(UInt16*)&fCurrentTargetLun<<16 | (scsiCDB.cdbTag & 0xFF),
294: 'Exec', "CurioSCSIController::executeCommand" );
295: ELG( *(UInt32*)&scsiCDB.cdb[0], *(UInt32*)&scsiCDB.cdb[4] , '=CDB', "executeCommand - CDB" );
296:
297: fpMsgOut = fpMsgPut = &fMsgOutBuffer[ 0 ];
298:
299: /* Identify byte: */
300:
301: msgByte = kSCSIMsgIdentify | kSCSIMsgEnableDisconnectMask | fCurrentTargetLun.lun;
302: if ( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect )
303: msgByte &= ~kSCSIMsgEnableDisconnectMask;
304: *fpMsgOut++ = msgByte;
305:
306: /* Tag msg: */
307:
308: if ( scsiCDB.cdbTagMsg )
309: {
310: *fpMsgOut++ = scsiCDB.cdbTagMsg;
311: *fpMsgOut++ = scsiCDB.cdbTag;
312: ELG( 0, scsiCDB.cdbTagMsg<<16 | (scsiCDB.cdbTag & 0xFF), ' tag', "CurioSCSIController::executeCommand - tag" );
313: }
314:
315: /* Abort msg: */
316:
317: if ( scsiCDB.cdbAbortMsg )
318: {
319: ELG( scsiCommand->getOriginalCmd(), scsiCDB.cdbAbortMsg, 'Abor', "CurioSCSIController::executeCommand - abort msg." );
320: *fpMsgOut++ = scsiCDB.cdbAbortMsg;
321: }
322:
323: fMsgOutCount = (UInt8)(fpMsgOut - &fMsgOutBuffer[ 0 ]);
324: ELG( fMsgOutCount, *(UInt32*)&fMsgOutBuffer[0], '=MgO', "executeCommand" );
325:
326: /***** Try to start the command on the hardware: *****/
327:
328: rc = startCommand(); /* Call the hardware layer. */
329:
330: if ( rc )
331: { /* Hardware can't start now */
332: ELG( fCmd, 0, 'Exe-', "CurioSCSIController::executeCommand - command bounced back" );
333: fCmd = NULL; /// ?redundant? - rescheduleCommand done in fsmSelecting
334: return;
335: }
336:
337: return;
338: }/* end executeCommand */
339:
340:
341:
342: bool CurioSCSIController::startCommand()
343: {
344: SCSICDBInfo scsiCDB;
345: UInt8 selectCmd;
346:
347:
348: fCmd->getPointers( &fCmdData->mdp, &fCmdData->xferCount, &fCmdData->isWrite );
349:
350: fCmdData->results.bytesTransferred = 0;
351: fCmdData->savedDataPosition = 0;
352:
353: fCmd->getCDB( &scsiCDB );
354:
355: setCmdReg( cFlshFFO );
356: WRITE_REGISTER( rSTA, fCurrentTargetLun.target );
357:
358: /* Put the contents of the message buffer into the FIFO. */
359: /* Figure out which flavor of Select command is indicated. */
360: /* The command depends on the number of message bytes. */
361:
362: switch ( fMsgOutCount )
363: {
364: case 0: /* Select, no ATN, send CDB */
365: selectCmd = cSlctNoAtn;
366: break;
367:
368: case 1: /* Select, ATN, 1 Msg, send CDB */
369: selectCmd = cSlctAtn;
370: break;
371:
372: case 3: /* Select, ATN, 3 Msg, send CDB */
373: selectCmd = cSlctAtn3;
374: break;
375:
376: default: /* Select, ATN, 1 Msg, stop */
377: selectCmd = cSlctAtnStp;
378: break;
379: }/* end SWITCH on size of MsgOut */
380:
381: if ( (fMsgOutCount > 3) || (fMsgOutCount + scsiCDB.cdbLength >= 16) )
382: { /* The FIFO only holds 16 bytes. */
383: /* We have to do the command phase in the state automaton. */
384: WRITE_REGISTER( rFFO, *fpMsgPut++ );
385: selectCmd = cSlctAtnStp;
386: }
387: else
388: { /* MsgOut and CDB both fit in FIFO: */
389: while ( fpMsgPut < fpMsgOut )
390: {
391: WRITE_REGISTER( rFFO, *fpMsgPut++ );
392: }
393: }
394:
395: if ( selectCmd != cSlctAtnStp )
396: { /* If we're not stopping after the messages, */
397: /* stuff the command into the FIFO, too. */
398: putCDBIntoFIFO();
399: }
400: /* Init the finite state automaton: */
401:
402: fBusState = SCS_SELECTING;
403: fCurrentBusPhase = kBusPhaseBusFree;
404:
405: /***** Issue the Arbitrate/Select/MessageOut combo: *****/
406:
407: setCmdReg( selectCmd );
408:
409: return false; /* return No Problem */
410: }/* end startCommand */
411:
412:
413: void CurioSCSIController::completeCommand()
414: {
415: ELG( fCmdData->results.returnCode, fCmdData->results.bytesTransferred, ' IOC', "CurioSCSIController::completeCommand" );
416:
417: switch ( fCmdData->results.scsiStatus )
418: {
419: case kSCSIStatusGood:
420: break;
421:
422: case kSCSIStatusCheckCondition:
423: ELG( 0, 0, 'Chek', "CurioSCSIController::completeCommand - Check Condition" );
424: fCmdData->results.returnCode = kIOReturnError;
425: break;
426:
427: default:
428: ELG( fCmd, fCmdData->results.scsiStatus, 'Sta?', "CurioSCSIController::completeCommand - bad status" );
429: fCmdData->results.returnCode = kIOReturnError;
430: break;
431: }/* end SWITCH on SCSI status */
432:
433: fCmd->setResults( &fCmdData->results );
434: fCmd->complete();
435:
436: fCmd = NULL;
437: fCmdData = NULL;
438: fCurrentTargetLun.target = kInvalidTarget;
439: fCurrentTargetLun.lun = kInvalidLUN;
440: return;
441: }/* end completeCommand */
442:
443:
444: void CurioSCSIController::cancelCommand( IOSCSICommand *scsiCommand )
445: {
446: IOSCSICommand *origCmd;
447: PrivCmdData *origCmdData;
448: SCSIResults results;
449:
450: origCmd = scsiCommand->getOriginalCmd();
451: origCmdData = (PrivCmdData*)origCmd->getCommandData();
452:
453: ELG( scsiCommand, origCmd, 'Can-', "CurioSCSIController::cancelCommand" );
454:
455: origCmd->getResults( &results );
456: results.bytesTransferred = origCmdData->results.bytesTransferred;
457: origCmd->setResults( &results );
458:
459: origCmd->complete();
460:
461: scsiCommand->complete();
462: return;
463: }/* end cancelCommand */
464:
465:
466: void CurioSCSIController::resetCommand( IOSCSICommand *scsiCommand )
467: {
468: ELG( scsiCommand, 0, 'Rst-', "CurioSCSIController::resetCommand" );
469: resetBus();
470: fCmdData = scsiCommand->getCommandData();
471: bzero( &fCmdData->results, sizeof( fCmdData->results ) );
472: scsiCommand->setResults( &fCmdData->results );
473: scsiCommand->complete();
474: return;
475: }/* end resetCommand */
476:
477:
478: /* Fetch the device's bus address and interrupt port number. */
479: /* Also, allocate one page of memory for the Channel Program. */
480:
481: IOReturn CurioSCSIController::initHardware()
482: {
483: IOReturn ioReturn;
484:
485:
486: fInitiatorID = kInitiatorIDDefault;
487: fInitiatorIDMask = 1 << kInitiatorIDDefault; /* BusID bitmask for reselection. */
488:
489: ELG( 0, fInitiatorID, 'IniH', "initHardware" );
490:
491: ioReturn = getHardwareMemoryMaps();
492:
493: if ( ioReturn == kIOReturnSuccess ) ioReturn = allocHdwAndChanMem();
494: if ( ioReturn == kIOReturnSuccess ) ioReturn = doHBASelfTest();
495: if ( ioReturn == kIOReturnSuccess ) ioReturn = resetHardware( true );
496:
497: if ( ioReturn != kIOReturnSuccess )
498: this->free();
499:
500: return ioReturn;
501: }/* end initHardware */
502:
503:
504: IOReturn CurioSCSIController::getHardwareMemoryMaps()
505: {
506:
507: if ( !fSCSIMemoryMap )
508: {
509: fSCSIMemoryMap = fProvider->mapDeviceMemoryWithIndex( kCurioRegisterBase );
510: if ( !fSCSIMemoryMap )
511: {
512: ELG( 0, 0, 'Map-', "CurioSCSIController::getHardwareMemoryMaps - can't map Curio." );
513: return kIOReturnInternalError;
514: }
515:
516: fCurioPhysAddr = fSCSIMemoryMap->getPhysicalAddress();
517: fCurioAddr = (UInt8*)fSCSIMemoryMap->getVirtualAddress();
518: ELG( fCurioPhysAddr, fCurioAddr, '=Cur', "getHardwareMemoryMaps - MESH regs" );
519: g.curioAddr = (UInt32)fCurioAddr; // for debugging, miniMon ...
520: }
521:
522: if ( !fDBDMAMemoryMap )
523: {
524: fDBDMAMemoryMap = fProvider->mapDeviceMemoryWithIndex( kDBDMARegisterBase );
525: if ( !fDBDMAMemoryMap )
526: {
527: ELG( 0, 0, 'map-', "CurioSCSIController::getHardwareMemoryMaps - can't map DBDMA." );
528: return kIOReturnInternalError;
529: }
530: fDBDMAAddrPhys = fDBDMAMemoryMap->getPhysicalAddress();
531: fDBDMAAddr = (IODBDMAChannelRegisters*)fDBDMAMemoryMap->getVirtualAddress();
532: ELG( fDBDMAAddrPhys, fDBDMAAddr, '=DMA', "getHardwareMemoryMaps - DBDMA regs" );
533: #if CustomMiniMon
534: gMESH_DBDMA = (UInt32)fDBDMAAddr;
535: gMESH_DBDMA_Phys = (UInt32)fDBDMAAddrPhys;
536: #endif /* CustomMiniMon */
537: }
538:
539: return kIOReturnSuccess;
540: }/* end getHardwareMemoryMaps */
541:
542:
543:
544: /* Fetch the device's bus address and allocate one page of memory */
545: /* for the channel command. (Strictly speaking, we don't need an */
546: /* entire page, but we can use the rest of the page for a permanent */
547: /* status log). */
548: /* @param deviceDescription Specify the device to initialize. */
549: /* @return kIOReturnSuccess if successful, else an error status. */
550:
551: IOReturn CurioSCSIController::allocHdwAndChanMem()
552: {
553: IOReturn ioReturn = kIOReturnSuccess;
554:
555:
556: fCCLSize = page_size;
557: fCCL = (UInt8*)kalloc( fCCLSize );
558: if ( !fCCL )
559: { PAUSE( 0, fCCLSize, 'CCA-', "allocHdwAndChanMem - can't allocate channel command area.\n" );
560: ioReturn = kIOReturnNoMemory;
561: }
562:
563: if ( ioReturn == kIOReturnSuccess )
564: {
565: /* Get the physical address corresponding the DBDMA channel area: */
566:
567: fCCLPhysAddr = pmap_extract( kernel_pmap,
568: (vm_offset_t)fCCL );
569:
570: g.cclPhysAddr = (UInt32)fCCLPhysAddr; // for debugging ease
571: g.cclLogAddr = (UInt32)fCCL;
572: if ( ioReturn != kIOReturnSuccess )
573: PAUSE( 0, ioReturn, 'MAP-', "allocHdwAndChanMem - DBDMA mapping err.\n" );
574: }
575:
576: if ( ioReturn == kIOReturnSuccess )
577: {
578: ELG( fCCLPhysAddr, fCCL, '=CCL', "allocHdwAndChanMem - CCL phys/logical addresses." );
579:
580: /* Set the Interrupt, Branch, and Wait DBDMA registers. */
581: /* Caution: the following Curio interrupt register bits */
582: /* are reverse polarity and are in a different position. */
583: /* The pattern is: 0x00MM00VV, where MM is a mask byte */
584: /* and VV is a value byte to match. */
585: /* 0x80 means NO errors (kMeshIntrError) */
586: /* 0x40 means NO exceptions (kMeshIntrException) */
587: /* 0x20 means NO command done (kMeshIntrCmdDone) */
588: /* Branch Select is used with BRANCH_FALSE */
589:
590: // IOSetDBDMAInterruptSelect( fDBDMAAddr, 0x00000000); /* Never let DBDMA interrupt */
591: // IOSetDBDMAWaitSelect( fDBDMAAddr, 0x00200020); /* Wait until command done */
592: // IOSetDBDMABranchSelect( fDBDMAAddr, 0x00000000); /* Never branch on error */
593: fDBDMAAddr->interruptSelect = 0x00000000;
594: fDBDMAAddr->waitSelect = 0x20002000;
595: fDBDMAAddr->branchSelect = 0x00000000;
596: SynchronizeIO();
597: }
598: /* What do we do on failure? Should we try to deallocate */
599: /* the stuff we created, or will the system do this for us? */
600:
601: return ioReturn;
602: }/* end allocHdwAndChanMem */
603:
604:
605: /* doHBASelfTest - This should be extended to perform a real chip self-test. */
606:
607: IOReturn CurioSCSIController::doHBASelfTest()
608: {
609: IOReturn ioReturn = kIOReturnSuccess;
610: UInt8 chipID;
611: UInt8 temp;
612:
613:
614: ELG( fCurioPhysAddr, fCurioAddr, 'Test', "doHBASelfTest" );
615: resetCurio();
616:
617: WRITE_REGISTER( rCF2, CF2_EPL );
618: setCmdReg( cNOP | bDMAEnBit );
619:
620: chipID = fCurioAddr[ rTCH ];
621:
622: /* Check data integrity by writing a NOP to the command register */
623: /* and verifying that it was read back correctly. */
624:
625: setCmdReg( cNOP );
626: temp = fCurioAddr[ rCMD ];
627: if ( temp != cNOP )
628: {
629: PAUSE( cNOP, temp, 'hba-', "doHBASelfTest - Expected NOP" );
630: ioReturn = kIOReturnNoDevice;
631: }
632: /* To do: write a test pattern into the FIFO and */
633: /* check for correct count and bits. */
634:
635: return ioReturn;
636: }/* end doHBASelfTest */
637:
638:
639: void CurioSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount )
640: {
641: // DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)fDBDMAAddr;
642:
643:
644: // ELG( ies, intCount, 'Int+', "interruptOccurred" );
645:
646: g.intLevel |= kLevelISR; /* set ISR flag */
647: g.intLevel &= ~kLevelLatched; /* clear latched */
648:
649: // ELG( DBDMARegs->channelStatus, DBDMARegs->commandPtrLo, 'Int+', "interruptOccurred." );
650: ELG( fCmd, 0, 'Int+', "interruptOccurred." );
651: // ELG( *(UInt32*)0xF3000024, *(UInt32*)0xF300002C, 'Int ', "interruptOccurred." );
652:
653: doHardwareInterrupt(); /**** HANDLE THE INTERRUPT ****/
654:
655: // ELG( fCmd, *(UInt32*)0xF300002C, 'Intx', "interruptOccurred." );
656:
657: g.intLevel &= ~kLevelISR; /* clear ISR flag */
658: return;
659: }/* end interruptOccurred */
660:
661:
662:
663: void CurioSCSIController::doHardwareInterrupt()
664: {
665: if ( !interruptPending() )
666: {
667: ELG( 0, 0, 'Int?', "CurioSCSIController::doHardwareInterrupt - spurious interrupt" );
668: return;
669: }
670:
671: fCkForAnotherInt = true; // keep going around
672: do
673: {
674: ELG( fCkForAnotherInt<<16 | fNeedAnotherInterrupt, fBusState, 'loop', "doHardwareInterrupt" );
675: fNeedAnotherInterrupt = false;
676:
677: /* Gross error is set incorrectly (according to Clinton Bauder). */
678:
679: if ( fSaveStatus & sGrossErr ) // ??? mlj was fSaveInterrupt
680: {
681: ELG( 0, fSaveInterrupt, 'GEr-', "doHardwareInterrupt - Gross Error set." );
682: fSaveStatus &= ~sGrossErr;
683: }
684:
685: /* iIlegalCmd - Software messed up. */
686: /* Start over from scratch. */
687: /* We can get this if we write too */
688: /* many commands into the register. */
689:
690: if ( fSaveInterrupt & iIlegalCmd )
691: {
692: ELG( 0, fSaveInterrupt, 'IllC', "doHardwareInterrupt - Illegal command interrupt" );
693: if ( fBusState != SCS_DEATH_MARCH )
694: fsmStartErrorRecovery( kIOReturnInternalError );
695:
696: fCkForAnotherInt = false;
697: }/* end IF iIlegalCmd */
698:
699:
700: /* Check for disconnect: */
701:
702: if ( fSaveInterrupt & iDisconnect )
703: {
704: setCmdReg( cEnSelResel );
705: /* Radar 1678545: this is the only (normal) place */
706: /* that fBusBusy is cleared. (It's also cleared by */
707: /* bus reset and driver initialization.) */
708: fBusBusy = false;
709: }
710:
711: if ( fSaveInterrupt & iResetDetect )
712: {
713: ELG( fSaveStatus, fSaveInterrupt, 'BusR', "doHardwareInterrupt - SCSI Bus Reset\n" );
714: if ( fCmd )
715: {
716: fCmdData->results.returnCode = kIOReturnSelectionError;
717: completeCommand();
718: }
719: super::resetOccurred();
720: enableCommands(); /* let superclass issue another command */
721: fCkForAnotherInt = false;
722: }/* end IF iResetDetect */
723: else if ( (fSaveStatus & sParityErr) && fBusBusy )
724: {
725: fsmStartErrorRecovery( kIOReturnParityError );
726: fCkForAnotherInt = false;
727: } /* If Parity Error and not disconnected */
728: else
729: { /* Only certain states are legal if the bus is busy. */
730: if ( fBusBusy )
731: {
732: /* This is a legitimate interrupt (parity error and */
733: /* bus reset have already been handled). The entity */
734: /* that started the chip action that caused the */
735: /* interrupt (deep breath) set fBusState to indicate*/
736: /* why the interrupt happened. */
737: /* Call the proper finite-state machine function. */
738: /* On return, fBusState will be set to one of the */
739: /* following values: */
740: /* SCS_INITIATOR Start an action on the */
741: /* current phase. */
742: /* SCS_DISCONNECT The bus is free. */
743: /* SCS_WAIT_FOR_BUS_FREE The bus should go free */
744: /* shortly. */
745: /* Note that SCS_WAIT_FOR_BUS_FREE and */
746: /* fsmWaitForBusFree short-circuit some of the */
747: /* automaton to avoid unnecessary interrupt events. */
748: switch ( fBusState )
749: {
750: case SCS_DISCONNECTED: fsmDisconnected(); break;
751: case SCS_SELECTING: fsmSelecting(); break;
752: case SCS_RESELECTING: fsmReselecting(); break;
753: case SCS_INITIATOR: fsmInitiator(); break;
754: case SCS_COMPLETING: fsmCompleting(); break;
755: case SCS_DMACOMPLETE: fsmDMAComplete(); break;
756: case SCS_SENDINGMSG: break;
757: case SCS_GETTINGMSG: fsmGettingMsg(); break;
758: case SCS_SENDINGCMD: fsmSendingCmd(); break;
759: case SCS_WAIT_FOR_BUS_FREE: fsmWaitForBusFree();break;
760: case SCS_DEATH_MARCH: fsmErrorRecoveryInterruptService(); break;
761:
762: default:
763: PAUSE( fSaveStatus, fBusState, 'FSM-', "doHardwareInterrupt - Illegal bus automaton state." );
764: }/* end SWITCH fBusState */
765: }/* end IF bus is busy */
766: else
767: { /* The bus is (or just went) free. */
768: /* We only allow selection, reselection, */
769: /* wait for disconnect, or death march interrupts. */
770: switch ( fBusState )
771: {
772: case SCS_DISCONNECTED: fsmDisconnected(); break;
773: case SCS_SELECTING: fsmSelecting(); break;
774: case SCS_WAIT_FOR_BUS_FREE: fsmWaitForBusFree(); break;
775: case SCS_DEATH_MARCH: fsmErrorRecoveryInterruptService(); break;
776:
777: default:
778: fsmStartErrorRecovery( kIOReturnInternalError );
779: fCkForAnotherInt = false;
780: break;
781: }/* end SWITCH on fBusState */
782: }/* end ELSE bus is not busy */
783: }
784:
785: /* We have (presumably) completely handled the previous */
786: /* interrupt. At this point, there are five legitimate */
787: /* fBusState values: */
788: /* SCS_RESELECTING Just got a reselection interrupt */
789: /* SCS_INITIATOR Continue operation for this target. */
790: /* SCS_DISCONNECTED Enable selection/reselection */
791: /* SCS_WAIT_FOR_BUS_FREE Command completion transition */
792: /* SCS_DEATH_MARCH Error recovery */
793: /* Handle a SCSI Phase change if necessary. This will */
794: /* leave the bus state in the "expected" state for the next */
795: /* operation. */
796:
797: switch ( fBusState )
798: {
799: case SCS_DEATH_MARCH:
800: fCkForAnotherInt = false;
801: break;
802:
803: case SCS_INITIATOR:
804: ELG( fCkForAnotherInt<<16 | fNeedAnotherInterrupt, 0, 'SCSi', "doHardwareInterrupt" );
805: if ( fNeedAnotherInterrupt )
806: { // from tagged reselect
807: fNeedAnotherInterrupt = false;
808: if ( quickCheckForInterrupt() )
809: {
810: fsmPhaseChange();
811: }
812: }
813: else
814: {
815: fsmPhaseChange();
816: }
817: break;
818:
819: case SCS_WAIT_FOR_BUS_FREE:
820: default:
821: break;
822: }/* end SWITCH on fBusState */
823:
824: /* This is the final check: if we determine that the */
825: /* previous action will complete quickly (for example, */
826: /* it's a message in byte), we'll spin for up to ten */
827: /* microseconds to see if the chip is ready for another */
828: /* operation. */
829:
830: } while ( fCkForAnotherInt && quickCheckForInterrupt() );
831:
832: if ( fBusState == SCS_DEATH_MARCH )
833: fsmContinueErrorRecovery();
834:
835: if ( fBusState == SCS_DISCONNECTED )
836: enableCommands(); /* Try to start another command */
837:
838: return;
839: }/* end doHardwareInterrupt */
840:
841:
842: /* This is called from fsmDisconnected when we receive a reselected interrupt. */
843:
844: void CurioSCSIController::handleReselectionInterrupt()
845: {
846: UInt8 selectByte;
847: UInt32 fifoDepth;
848: UInt8 msgByte;
849: IOReturn ioReturn = kIOReturnSuccess;
850:
851:
852: /* Make sure there's a selection byte and an Identify message in the FIFO. */
853:
854: fBusBusy = ((fSaveInterrupt & iDisconnect) == 0);
855: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask;
856:
857: ELG( fifoDepth, fSaveInterrupt, 'fHRI', "handleReselectionInterrupt" );
858: if ( fifoDepth != 2 )
859: {
860: ioReturn = kIOReturnInternalError;
861: PAUSE( 0, 0, 'Rsl-', "handleReselectionInterrupt - Bad FIFO count on reselect" );
862: }
863:
864: if ( ioReturn == kIOReturnSuccess )
865: {
866: selectByte = fCurioAddr[ rFFO ];
867: /* During reselection, the first message byte */
868: /* must be an Identify with the LUN. */
869: ioReturn = getReselectionTargetID( selectByte );
870: }
871:
872: if ( ioReturn == kIOReturnSuccess )
873: {
874: msgByte = fCurioAddr[ rFFO ]; /* Pull the Identify byte */
875: if ( fSaveStatus & sParityErr )
876: ioReturn = kIOReturnParityError;
877: }
878:
879: if ( ioReturn == kIOReturnSuccess )
880: {
881: if ( (msgByte & kSCSIMsgIdentify) == 0 )
882: {
883: ioReturn = kIOReturnInternalError;
884: PAUSE( 0, msgByte, ' ID-', "handleReselectionInterrupt - Bad ID Message (no Identify) on reselect" );
885: }
886:
887: fCurrentTargetLun.lun = msgByte & ~kSCSIMsgIdentify;
888: fTag = kInvalidTag;
889: fBusState = SCS_RESELECTING;
890:
891: /* At this point, the chip is waiting for us to validate */
892: /* the Identify message. While we have a Target and LUN, */
893: /* we don't have a command to reconnect to. */
894: setCmdReg( cMsgAcep ); /* Accept the Identify message */
895: }
896:
897: if ( ioReturn != kIOReturnSuccess )
898: fsmStartErrorRecovery( ioReturn );
899:
900: return;
901: }/* end handleReselectionInterrupt */
902:
903:
904: /* Complete the processing of a reselection interrupt. */
905: /* We have just ACK'd the Identify message. Try to find the command */
906: /* that corresponds to this target.lun (without a queue tag). */
907: /* If we're successful, complete the reselection and start */
908: /* following phases by calling fsmPhaseChange directly. */
909: /* If the first disconnected command has a non-zero tag queue, we */
910: /* expect to be in messsage in phase, and will receive a tagged */
911: /* queue message eventually. */
912:
913: void CurioSCSIController::fsmReselecting()
914: {
915: ELG( fBusState, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'fRsl', "fsmReselecting" );
916:
917: reselectNexus();
918: if ( fCmd )
919: { /* We have successfully reselected this target. */
920: /* Wait until the target tells us what to do next. */
921: fBusState = SCS_INITIATOR;
922: return;
923: }
924:
925: /* We don't have a nexus yet. If we're in MSGI phase, */
926: /* continue grabbing message bytes until we receive */
927: /* a queue tag message (we might receive an SDTR), */
928: /* continuing at fsmReselecting to process interrupts. */
929:
930: quickCheckForInterrupt(); // clear pending interrupt(s) and update phase
931: fCurrentBusPhase = fSaveStatus & mPhase;
932: if ( fCurrentBusPhase == kBusPhaseMSGI )
933: {
934: if ( (fCurioAddr[ rFOS ] & kFIFOCountMask) == 0 )
935: {
936: if ( fMsgInState == kMsgInInit )
937: {
938: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit
939: setCmdReg( cIOXfer );
940: if ( !quickCheckForInterrupt() )
941: { fCkForAnotherInt = true;
942: return;
943: }
944: }
945: }
946: fsmGettingMsg();
947: }
948: else
949: { /* We're in the wrong phase. Bail out. */
950: fsmStartErrorRecovery( kIOReturnInternalError );
951: }
952: return;
953: }/* end fsmReselecting */
954:
955:
956:
957: /* Disconnected - only legal event here is reselection. */
958: /* handleReselectionInterrupt may set fBusState to SCS_INITIATOR */
959:
960: void CurioSCSIController::fsmDisconnected()
961: {
962: UInt8 selectByte, target;
963:
964:
965: ELG( 0, fSaveInterrupt, 'fDis', "fsmDisconnected" );
966:
967: if ( fSaveInterrupt & iReselected )
968: {
969: handleReselectionInterrupt();
970: return;
971: }
972:
973: /* See if some target trying to Select us - should never happen: */
974:
975: if ( fSaveInterrupt & (iSelected | iSelectWAtn) )
976: {
977: selectByte = fCurioAddr[ rFFO ];
978: selectByte &= ~fInitiatorIDMask;
979: for ( target = 0; target < 8; target++ )
980: {
981: if ( selectByte & (1 << target) )
982: break;
983: }
984: PAUSE( selectByte, target, 'Tar-', "fsmDisconnected - Selected by external target - not supported." );
985: setCmdReg( cDisconnect );
986: return;
987: }/* end IF bogus selection by target */
988:
989:
990: fCkForAnotherInt = false;
991:
992: if ( fBusBusy == false )
993: { /* disconnect interrupted while disconnected */
994: /* This always happens when we finish an IO request. */
995: /* fBusBusy is cleared when the "bus disconnected" bit */
996: /* is set in the NCR 53C96 interrupt register. */
997: ELG( 0, 0, 'Dis-', "fsmDisconnected - disconnect interrupted while disconnected" );
998: enableCommands();
999: return;
1000: }
1001:
1002: /* Since we're disconnected, just ignore the interrupt */
1003:
1004: if ( fCmd )
1005: {
1006: fCmdData->results.returnCode = kIOReturnSelectionError;
1007: completeCommand();
1008: }
1009:
1010: fCurrentBusPhase = kBusPhaseBusFree;
1011: return;
1012: }/* end fsmDisconnected */
1013:
1014:
1015: /* This state is called when we expect to disconnect from a */
1016: /* target after receiving a Command Complete, Disconnect, or */
1017: /* Abort message and the bus is still busy on exit from the */
1018: /* finite state automaton (because curioQuickCheckForBusFree */
1019: /* returned false). */
1020:
1021: void CurioSCSIController::fsmWaitForBusFree()
1022: {
1023: ELG( fBusBusy, fSaveInterrupt, 'fWBF', "fsmWaitForBusFree" );
1024:
1025: if ( fSaveInterrupt & (iReselected | iSelected | iSelectWAtn) )
1026: {
1027: /* We went straight from command completion to (presumably) */
1028: /* reselection. Treat it as a normal selection/reselection */
1029: /* interrupt from "disconnected" state. (This is an abuse of*/
1030: /* the finite-state automaton design.) */
1031: fsmDisconnected();
1032: }
1033: else if ( fBusBusy == false )
1034: {
1035: /* This is expected: the bus has just gone free after a */
1036: /* command completed. We can now safely try to start */
1037: /* another command. */
1038: fBusState = SCS_DISCONNECTED;
1039: fCkForAnotherInt = false;
1040: enableCommands();
1041: }
1042: else
1043: { /* This is strange. It may not be an error, but I don't know */
1044: /* if there are other legal bus states after disconnect. */
1045: /* (The one counter example would be after a linked command */
1046: /* when the target goes to Command phase, but we should have */
1047: /* rejected this at command complete.) */
1048: ELG( fCmd, 0, 'WBF-', "fsmWaitForBusFree - strangeness" );
1049: fsmStartErrorRecovery( kIOReturnInternalError );
1050: }
1051: return;
1052: }/* end fsmWaitForBusFree */
1053:
1054:
1055: /* fsmSelecting - One of three things can happen here: */
1056: /* the selection could succeed (though with possible */
1057: /* incomplete message out), */
1058: /* it could time out, or */
1059: /* we can be reselected. */
1060:
1061: void CurioSCSIController::fsmSelecting()
1062: {
1063: SCSICDBInfo scsiCDB;
1064: UInt8 fifoDepth;
1065: IOReturn ioReturn = kIOReturnSuccess;
1066:
1067:
1068: ELG( 0, fSaveInterrupt, 'fSel', "fsmSelecting" );
1069:
1070: fBusBusy = ((fSaveInterrupt & iDisconnect) == 0 );
1071: if ( fBusBusy == false )
1072: { /* Selection timed-out. Abort this request. */
1073: ELG( fCmd, 0, 'Tim-', "fsmSelecting - timeout" );
1074:
1075: setCmdReg( cFlshFFO );
1076: fBusState = SCS_DISCONNECTED;
1077: fCmdData->results.returnCode = kIOReturnNoDevice;
1078: completeCommand();
1079: return;
1080: }
1081:
1082: ELG( fSaveInterrupt, fSaveSeqStep, 'Sel-', "fsmSelecting - problem other than timeout" );
1083: fCmd->getCDB( &scsiCDB );
1084:
1085: if ( fSaveInterrupt == (iFuncComp | iBusService) )
1086: {
1087: switch ( fSaveSeqStep & INS_STATE_MASK )
1088: {
1089: case 0: /* No message phase. If we really wanted one, */
1090: /* this could be significant. */
1091: /* OK, let's try to continue following phase changes. */
1092: fBusState = SCS_INITIATOR;
1093: break;
1094:
1095: case 3: /* didn't complete cmd phase, parity? */
1096: case 4: /* everything worked */
1097: case 1: /* everything worked, SCMD_SELECT_ATN_STOP case */
1098: /* We're connected. Start following the target's phase changes. */
1099: /* If we're trying to do sync negotiation, */
1100: /* this is the place to do it. In that case, we */
1101: /* sent a SCMD_SELECT_ATN_STOP command, and */
1102: /* ATN is now asserted (and we're hopefully in */
1103: /* msgOut phase). We want to send 5 bytes. */
1104: /* Drop them into currMsgOut */
1105: fBusState = SCS_INITIATOR;
1106: break;
1107:
1108: case 2: /* Either no command phase, or incomplete message transfer. */
1109: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask;
1110: /* Spec says ATN is asserted if all message bytes were not sent. */
1111: if ( fifoDepth > scsiCDB.cdbLength )
1112: setCmdReg( cRstAtn );
1113:
1114: /* 970611: clear the FIFO. If we don't do this and the */
1115: /* target is entering MSGI phase (trying to send us a */
1116: /* Message Reject), it will sit on top of the FIFO, and */
1117: /* we'll read garbage from the FIFO. */
1118:
1119: setCmdReg( cFlshFFO ); /* The command is still in the FIFO */
1120: /* OK, let's try to continue following phase changes. */
1121: fBusState = SCS_INITIATOR;
1122: break;
1123:
1124: default: /* fBusBusy = true; -- Radar 1678545 */
1125: ioReturn = kIOReturnInternalError;
1126: break;
1127: }/* end SWITCH */
1128: }
1129: else if ( fSaveInterrupt & iReselected )
1130: {
1131: /* We were reselected while trying to do a selection. */
1132: /* Enqueue this cmdBuf on the HEAD of pendingQ, then deal */
1133: /* with the reselect. */
1134: /* Tricky case, we have to "deactivate" this command */
1135: /* since this hardwareStart attempt failed. */
1136:
1137: ELG( fCmd, fSaveInterrupt, 'Arb-', "fsmSelecting - Reselection interrupt while selecting" );
1138: disableCommands();
1139: rescheduleCommand( fCmd );
1140: fCmd = NULL;
1141:
1142: fBusState = SCS_DISCONNECTED;
1143: handleReselectionInterrupt(); /* Go deal with reselect. */
1144: }
1145: else
1146: {
1147: ioReturn = kIOReturnInternalError;
1148: PAUSE( 0, 0, 'int-', "Bogus select/reselect interrupt" );
1149: }
1150:
1151: if ( ioReturn != kIOReturnSuccess )
1152: fsmStartErrorRecovery( ioReturn );
1153:
1154: return;
1155: }/* end fsmSelecting */
1156:
1157:
1158: /* This is a dummy interrupt service state that we enter after selection */
1159: /* when the previous Curio operation has no interrupt-service completion */
1160: /* requirement. For example, we can get here after a Message Out or */
1161: /* reselection. Nothing happens here; we continue at fsmPhaseChange. */
1162:
1163: void CurioSCSIController::fsmInitiator()
1164: {
1165: ELG( 0, fSaveInterrupt, 'fIni', "fsmInitiator" );
1166: fBusState = SCS_INITIATOR;
1167: return;
1168: }/* end fsmInitiator */
1169:
1170:
1171: /* We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left */
1172: /* is to drop ACK. Command Complete message is handled in fscAcceptinfMsg. */
1173: /* We can't go to SCS_DISCONNECTED until the target disconnects. If we */
1174: /* go to "disconnected" state too soon, we'll encounter a load-dependent */
1175: /* race condition that causes us to start another command before we've */
1176: /* cleaned up from the last command. The actual state change is in */
1177: /* fsmProcessMessage. */
1178:
1179: void CurioSCSIController::fsmCompleting()
1180: {
1181: unsigned fifoDepth;
1182: IOReturn ioReturn = kIOReturnSuccess;
1183: UInt8 statusByte;
1184:
1185:
1186: ELG( 0, fSaveInterrupt, 'fCmp', "fsmCompleting" );
1187:
1188: if ( fSaveInterrupt & iDisconnect )
1189: {
1190: ioReturn = kIOReturnInternalError;
1191: PAUSE( 0, 0, ' BF-', "fsmCompleting - Bus free before target completion complete" );
1192: }
1193:
1194: if ( ioReturn == kIOReturnSuccess )
1195: {
1196: fifoDepth = fCurioAddr[ rFOS ] & kFIFOCountMask;
1197: if ( fSaveInterrupt & iFuncComp )
1198: { /* Got both Status and MsgIn in FIFO; ACK is still asserted. */
1199: if ( fifoDepth != 2 )
1200: { /* This is pretty bogus - we expect a status and msg in the FIFO. */
1201: PAUSE( 0, fifoDepth, 'ffc-', "fsmCompleting - FIFO problem with Status/MsgIn" );
1202: ioReturn = kIOReturnInternalError;
1203: }
1204:
1205: if ( ioReturn == kIOReturnSuccess )
1206: {
1207: statusByte = fCurioAddr[ rFFO ];
1208: fMsgInBuffer[0] = fCurioAddr[ rFFO ];
1209: fCmdData->results.scsiStatus = statusByte;
1210: fMsgInIndex = 1;
1211: ioReturn = fsmProcessMessage();
1212: }
1213: }
1214: else
1215: { /* We only received a status byte. */
1216: /* This can occur if we responded to the interrupt before */
1217: /* the device successfully transmitted the Command Complete */
1218: /* message. This is kind of weird, but let's try to handle it. */
1219: if ( fifoDepth != 1 )
1220: {
1221: ioReturn = kIOReturnInternalError;
1222: PAUSE( 0, fifoDepth, 'Cmp-', "IO complete: incorrect FIFO count (expecting one byte)" );
1223: }
1224:
1225: /* Back to watching phase changes. */
1226: /* Presumably, the target will switch to MSGI phase and */
1227: /* complete the command at its leisure. */
1228: fBusState = SCS_INITIATOR;
1229: }
1230: }
1231:
1232: if ( ioReturn != kIOReturnSuccess )
1233: fsmStartErrorRecovery( ioReturn );
1234:
1235: return;
1236: }/* end fsmCompleting */
1237:
1238:
1239: /* DMA Complete. */
1240:
1241: void CurioSCSIController::fsmDMAComplete()
1242: {
1243: UInt32 fifoResidualCount, actualTransferCount, dmaResidualCount;
1244: UInt8 residualByte;
1245:
1246:
1247: /* Stop the DMA engine and retrieve the total number of */
1248: /* bytes transferred. This will be */
1249: /* fCmd->thisTransferLength The number of bytes requested */
1250: /* - the current DMA residual count */
1251: /* - the current FIFO residual count */
1252: /* Note that there may still be bytes in the FIFO. */
1253:
1254: // IODBDMAReset( fDBDMAAddr );
1255: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
1256: SynchronizeIO();
1257: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit
1258: SynchronizeIO();
1259:
1260: /* Get residual count from DMA transfer. */
1261:
1262: dmaResidualCount = fCurioAddr[ rXCM ] << 8 | fCurioAddr[ rXCL ];
1263: actualTransferCount = fThisTransferLength - dmaResidualCount;
1264:
1265: ELG( dmaResidualCount, actualTransferCount, 'fDMA', "fsmDMAComplete" );
1266:
1267: /* Now, see if there are any bytes lurking in the FIFO: */
1268:
1269: fifoResidualCount = fCurioAddr[ rFOS ] & kFIFOCountMask;
1270:
1271: if ( fifoResidualCount > 0 )
1272: { /* Drain the FIFO after DMA for a normal transfer: */
1273: ELG( 0, fifoResidualCount, 'MTFF', "fsmDMAComplete - empty the FIFO" );
1274:
1275: if ( !fCmdData->isWrite )
1276: {
1277: while ( fifoResidualCount > 0 )
1278: { /* Try to move residual data from the FIFO into */
1279: /* the user's buffer. */
1280: residualByte = fCurioAddr[ rFFO ];
1281: fCmdData->mdp->writeBytes( fCmdData->results.bytesTransferred + actualTransferCount,
1282: &residualByte, 1 );
1283: ++actualTransferCount;
1284: }/* end WHILE bytes in FIFO */
1285: }
1286: else
1287: { /* Write command - just flush the data */
1288: setCmdReg( cFlshFFO );
1289: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit;
1290: actualTransferCount -= fifoResidualCount;
1291: }/* end IF Write */
1292: }/* end IF bytes left in FIFO */
1293:
1294: fCmdData->results.bytesTransferred += actualTransferCount;
1295:
1296: if ( fSaveStatus & sParityErr )
1297: {
1298: PAUSE( 0, 0, 'par-', "fsmDMAComplete - parity error" );
1299: fsmStartErrorRecovery( kIOReturnParityError );
1300: }
1301: else
1302: {
1303: fBusState = SCS_INITIATOR; /* Continue following phase changes. */
1304: }
1305:
1306: return;
1307: }/* end fsmDMAComplete */
1308:
1309:
1310: /* Just completed the SCMD_TRANSFER_INFO operation for message in. */
1311: /* ACK is not asserted (we have not ACK'ed this byte). */
1312: /* There is no parity error. */
1313: /* We will not have a command if we're reselecting. */
1314:
1315: void CurioSCSIController::fsmGettingMsg()
1316: {
1317: UInt32 fifoCount;
1318: UInt8 msgInByte;
1319: IOReturn ioReturn = kIOReturnSuccess;
1320:
1321:
1322: ELG( fBusBusy, fMsgInState<<16 | fCurioAddr[ rFOS ], 'fGtM', "fsmGettingMsg" );
1323:
1324: if ( fBusBusy == false )
1325: {
1326: /* This (non-fatal) error is handled on return... */
1327: ioReturn = kIOReturnInternalError; /* Any non-zero non-fatal error status */
1328: }
1329: else
1330: {
1331: fifoCount = fCurioAddr[ rFOS ] & kFIFOCountMask;
1332: if ( fifoCount != 1 )
1333: {
1334: PAUSE( 0, fifoCount, 'GtM-', "fsmGettingMsg - MsgIn FIFO count error" );
1335: ioReturn = kIOReturnInternalError;
1336: }
1337: }
1338:
1339: if ( ioReturn == kIOReturnSuccess )
1340: {
1341: msgInByte = fCurioAddr[ rFFO ];
1342: ELG( 0, msgInByte, '=Msg', "fsmGettingMsg - got a byte" );
1343: if ( fSaveStatus & sParityErr )
1344: {
1345: PAUSE( 0, fSaveStatus, 'Par-', "fsmGettingMsg - Parity error getting MsgIn" );
1346: ioReturn = kIOReturnParityError;
1347: }
1348: }
1349:
1350: if ( ioReturn == kIOReturnSuccess )
1351: {
1352: if ( fMsgInState == kMsgInInit )
1353: {
1354: fMsgInCount = 0;
1355: fMsgInIndex = 0;
1356: }
1357: if ( fMsgInIndex >= kMessageInBufferLength )
1358: {
1359: PAUSE( 0, fMsgInIndex, 'Par-', "fsmGettingMsg - too many bytes" );
1360: ioReturn = kIOReturnInternalError;
1361: }
1362: }
1363:
1364: if ( ioReturn == kIOReturnSuccess )
1365: {
1366: fMsgInBuffer[ fMsgInIndex++ ] = msgInByte;
1367: switch ( fMsgInState )
1368: {
1369: case kMsgInInit: /* This is the first message byte. */
1370: if ( (msgInByte == kSCSIMsgCmdComplete)
1371: || (msgInByte >= (UInt8)kSCSIMsgIdentify) )
1372: { /* This is 1-byte cmdComplete or Identify message. */
1373: fMsgInState = kMsgInReady;
1374: }
1375: else if ( msgInByte == kSCSIMsgExtended )
1376: { /* This is an extended message. The next byte has the count. */
1377: fMsgInState = kMsgInCounting;
1378: }
1379: else if ( msgInByte <= kSCSIMsgOneByteMax )
1380: { /* These are other 1-byte messages. */
1381: fMsgInState = kMsgInReady;
1382: }
1383: else if ( msgInByte >= kSCSIMsgTwoByteMin
1384: && msgInByte <= kSCSIMsgTwoByteMax )
1385: { /* This is a two-byte message. */
1386: /* Set the count and read the next byte. */
1387: fMsgInState = kMsgInReading; /* Need one more */
1388: fMsgInCount = 1;
1389: }
1390: else
1391: { /* This is an unknown message. */
1392: fMsgInState = kMsgInReady;
1393: }
1394: break;
1395:
1396: case kMsgInCounting: /* Count byte of multi-byte message: */
1397: fMsgInCount = msgInByte;
1398: fMsgInState = kMsgInReading;
1399: break;
1400:
1401: case kMsgInReading: /* Body of multi-byte message: */
1402: if ( --fMsgInCount <= 0 )
1403: fMsgInState = kMsgInReady;
1404: break;
1405:
1406: default:
1407: PAUSE( 0, 0, 'Msg-', "DoMessageInPhase - Bogus MSGI state!\n" );
1408: ioReturn = kIOReturnInternalError;
1409: }/* SWITCH on message state */
1410: }
1411:
1412: if ( ioReturn == kIOReturnSuccess )
1413: {
1414: switch ( fMsgInState )
1415: {
1416: case kMsgInReading:
1417: case kMsgInCounting: /* We have more message bytes to read. */
1418: /* Accept this byte (this sets ACK) and setup */
1419: /* to transfer the next byte. */
1420: setCmdReg( cMsgAcep );
1421: /* Since the message accept command sets "interrupt", */
1422: /* eat it here so we don't get a second interrupt. */
1423: quickCheckForInterrupt();
1424: setCmdReg( cNOP );
1425: setCmdReg( cIOXfer );
1426: if ( fBusState != SCS_RESELECTING )
1427: fBusState = SCS_GETTINGMSG;
1428: /* This would be a good place to spin-wait for completion, */
1429: /* continuing at the start of this method if there is */
1430: /* another byte (and we're still in message in phase). */
1431: /* Perhaps this method should return a "spinwait" status to */
1432: /* the mainline FSM. */
1433: break;
1434:
1435: case kMsgInReady:
1436: fMsgInState = kMsgInInit;
1437: ioReturn = fsmProcessMessage();
1438: break;
1439:
1440: case kMsgInInit:
1441: default:
1442: /* that's strange: we should never be in idle state */
1443: /* *after* successfully reading a message byte. */
1444: ioReturn = kIOReturnInternalError;
1445: break;
1446: }/* end SWITCH */
1447: }
1448:
1449: if ( ioReturn != kIOReturnSuccess )
1450: fsmStartErrorRecovery( ioReturn );
1451:
1452: return;
1453: }/* end fsmGettingMsg */
1454:
1455:
1456: /* Just read a message; ACK is false and the message */
1457: /* has been read into fMsgInBuffer[0..fMsgInIndex]. We have not */
1458: /* ACK'ed the last byte yet. */
1459: /* If we fail here, the caller will start error recovery. */
1460:
1461: IOReturn CurioSCSIController::fsmProcessMessage()
1462: {
1463: IOReturn ioReturn = kIOReturnSuccess;
1464: bool messageAckNeeded = true;
1465:
1466:
1467: ELG( fBusState, *(UInt32*)fMsgInBuffer, 'fMgI', "fsmProcessMessage" );
1468:
1469: /* Message-in complete. Handle message(s) in currMsgIn: */
1470:
1471: if ( fBusState == SCS_RESELECTING )
1472: {
1473: /* The only interesting message here is queue tag. */
1474: /* (What about target SDTR or Abort?) */
1475:
1476: switch ( fMsgInBuffer[0] )
1477: {
1478: case kSCSIMsgHeadOfQueueTag:
1479: case kSCSIMsgOrderedQueueTag:
1480: case kSCSIMsgSimpleQueueTag:
1481: if ( fMsgInIndex != 2 )
1482: {
1483: PAUSE( fMsgInBuffer[0], fMsgInIndex, 'Que-', "fsmProcessMessage - queue tag without tag value" );
1484: ioReturn = kIOReturnInternalError;
1485: }
1486: else
1487: { fTag = fMsgInBuffer[ 1 ];
1488: ELG( 0, fTag, '=Tag', "fsmProcessMessage - tag" );
1489: reselectNexus();
1490: if ( fCmd )
1491: {
1492: setCmdReg( cMsgAcep );
1493: fNeedAnotherInterrupt = true;
1494: fBusState = SCS_INITIATOR;
1495: return kIOReturnSuccess;
1496: }
1497: }
1498: break;
1499:
1500: default:
1501: ioReturn = kIOReturnInternalError;
1502: break;
1503: }/* end SWITCH on message */
1504:
1505: /* Since we process commands one by one, whack this */
1506: /* command so we fall through the regular message handler. */
1507: fMsgInBuffer[0] = kSCSIMsgNop;
1508: fMsgInIndex = 1;
1509: }
1510:
1511: fBusState = SCS_INITIATOR;
1512: fNeedAnotherInterrupt = true;
1513:
1514: switch ( fMsgInBuffer[0] )
1515: {
1516: case kSCSIMsgNop:
1517: break;
1518:
1519: case kSCSIMsgCmdComplete:
1520: /* Normally, we get here from fsmCommandComplete. */
1521: /* All we need to do is to Ack the message and complete the */
1522: /* command. Exit in a transitional bus state that becomes */
1523: /* SCS_DISCONNECTED when the bus is no longer busy. */
1524: fBusState = SCS_WAIT_FOR_BUS_FREE;
1525: completeCommand();
1526: break;
1527:
1528: case kSCSIMsgDisconnect:
1529: fCmd = NULL;
1530: /* Exit the interrupt service routine so */
1531: /* we don't miss a reselection interrupt. */
1532: fBusState = SCS_WAIT_FOR_BUS_FREE;
1533: fCkForAnotherInt = false;
1534: break;
1535:
1536: case kSCSIMsgSaveDataPointers:
1537: if ( fCmd )
1538: fCmdData->savedDataPosition = fCmdData->results.bytesTransferred;
1539: break;
1540:
1541: case kSCSIMsgRestorePointers:
1542: if ( fCmd )
1543: fCmdData->results.bytesTransferred = fCmdData->savedDataPosition;
1544: break;
1545:
1546: case kSCSIMsgRejectMsg:
1547: ioReturn = kIOReturnInternalError;
1548:
1549: // don't break - fall through to kSCSIMsgAbort */
1550:
1551: case kSCSIMsgAbort:
1552: case kSCSIMsgAbortTag:
1553: if ( fCmd )
1554: { /* Oops: something is terribly wrong with this command. */
1555: /* This can happen if we get a parity error, set ATN, */
1556: /* and send an inititor detected error to the target. */
1557: fCmdData->results.returnCode = kIOReturnInternalError;
1558: completeCommand();
1559: fCkForAnotherInt = false;
1560: }
1561: /* After receiving an Abort, the target will go free */
1562: fBusState = SCS_WAIT_FOR_BUS_FREE;
1563: break;
1564:
1565: case kSCSIMsgLinkedCmdComplete:
1566: case kSCSIMsgLinkedCmdCompleteFlag:
1567: /* These are impossible: we reject commands with the link bit set. */
1568: /* About all we can do is to fail the client's command and */
1569: /* stagger onwards. */
1570: PAUSE( fCmd, 0, 'Abo-', "fsmProcessMessage - recv'd Abort" );
1571: fCmdData->results.returnCode = kIOReturnInternalError;
1572: completeCommand();
1573: fBusState = SCS_WAIT_FOR_BUS_FREE;
1574: break;
1575:
1576: case kSCSIMsgExtended:
1577: /* The only expected extended message is */
1578: /* synchronous negotiation which isn't supported. */
1579: switch ( fMsgInBuffer[2] )
1580: {
1581: case kSCSIMsgSyncXferReq:
1582: /* We don't support SDTR (yet), so send a message reject */
1583: /* Perhaps it would be better to send an "async only" */
1584: /* response, but message reject is legal. */
1585: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg );
1586: setCmdReg( cSetAtn );
1587: messageAckNeeded = false;
1588: break;
1589:
1590: default:
1591: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg );
1592: setCmdReg( cSetAtn );
1593: messageAckNeeded = false;
1594: break;
1595: }
1596: break;
1597:
1598: default: /* all others are unacceptable. */
1599: WRITE_REGISTER( rFFO, kSCSIMsgRejectMsg );
1600: setCmdReg( cSetAtn );
1601: messageAckNeeded = false;
1602: }/* end SWITCH on Message byte */
1603:
1604: if ( messageAckNeeded )
1605: setCmdReg( cMsgAcep );
1606:
1607: return ioReturn;
1608: }/* end fsmProcessMessage */
1609:
1610:
1611: /* Just completed the SCMD_TRANSFER_INFO operation for command. */
1612: void CurioSCSIController::fsmSendingCmd()
1613: {
1614: fBusState = SCS_INITIATOR;
1615: return;
1616: }/* end fsmSendingCmd */
1617:
1618:
1619: /* Follow SCSI Phase change. Called while SCS_INITIATOR. */
1620:
1621: void CurioSCSIController::fsmPhaseChange()
1622: {
1623: int i;
1624:
1625:
1626: ELG( 0, fSaveStatus, 'fPhC', "fsmPhaseChange" );
1627:
1628: fCurrentBusPhase = fSaveStatus & mPhase;
1629:
1630: switch ( fCurrentBusPhase )
1631: {
1632: case kBusPhaseCMD:
1633: /* The normal case here is after a host-initiated SDTR sequence. */
1634: setCmdReg( cFlshFFO );
1635: putCDBIntoFIFO();
1636: setCmdReg( cIOXfer ); /* Start non-DMA xfer */
1637: fMsgInState = kMsgInInit;
1638: fBusState = SCS_SENDINGCMD;
1639: break;
1640:
1641: case kBusPhaseDATI: /* From target to Initiator (read) */
1642: case kBusPhaseDATO: /* To Target from Initiator (write) */
1643: fMsgInState = kMsgInInit;
1644: fsmStartDataPhase( fCurrentBusPhase == kBusPhaseDATI );
1645: fCkForAnotherInt = false;
1646: break;
1647:
1648: case kBusPhaseSTS: /* Status from Target to Initiator */
1649: /* fsmCompleting will collect the STATUS byte (and */
1650: /* hopefully a MSG) from the FIFO when this completes. */
1651: fMsgInState = kMsgInInit;
1652: fBusState = SCS_COMPLETING;
1653: setCmdReg( cFlshFFO );
1654: setCmdReg( cCmdComp );
1655: break;
1656:
1657: case kBusPhaseMSGI: /* Message from Target to Initiator */
1658: if ( fBusState != SCS_RESELECTING )
1659: fBusState = SCS_GETTINGMSG;
1660: setCmdReg( cNOP );
1661: setCmdReg( cIOXfer );
1662: break;
1663:
1664: case kBusPhaseMSGO: /* Message from Initiator to Target */
1665: fMsgInState = kMsgInInit;
1666: setCmdReg( cFlshFFO );
1667:
1668: if ( fpMsgPut == fpMsgOut )
1669: *fpMsgOut++ = kSCSIMsgNop; /* no message waiting to be sent. */
1670:
1671:
1672: for ( i = 0; i < 16 && fpMsgPut < fpMsgOut; i++ )
1673: { WRITE_REGISTER( rFFO , *fpMsgPut );
1674: fpMsgPut++;
1675: }
1676:
1677: if ( fpMsgPut == fpMsgOut )
1678: fpMsgPut = fpMsgOut = fMsgOutBuffer;
1679:
1680: fBusState = SCS_SENDINGMSG;
1681: /* ATN is automatically cleared when transfer info completes. */
1682: setCmdReg( cIOXfer ); /* Start non-DMA xfer */
1683: break;
1684:
1685: default:
1686: fsmStartErrorRecovery( kIOReturnInternalError );
1687: break;
1688: }
1689: return;
1690: }/* end fsmPhaseChange */
1691:
1692:
1693: void CurioSCSIController::fsmStartDataPhase( bool isDataInPhase )
1694: {
1695: IOReturn ioReturn = kIOReturnSuccess;
1696:
1697:
1698: ELG( fCmd, fThisTransferLength, 'fDat', "fsmStartDataPhase" );
1699:
1700: /* DataIn phase is legal if this is a read command: */
1701:
1702: if ( isDataInPhase != !fCmdData->isWrite )
1703: {
1704: ioReturn = kIOReturnInternalError;
1705: PAUSE( fCmd, isDataInPhase, 'Dir-', "fsmStartDataPhase - data direction" );
1706: }
1707:
1708: if ( ioReturn == kIOReturnSuccess )
1709: {
1710: ioReturn = generateCCL();
1711: }
1712:
1713: if ( ioReturn == kIOReturnSuccess )
1714: {
1715: if ( fThisTransferLength == 0 )
1716: {
1717: ioReturn = kIOReturnInternalError;
1718: PAUSE( fCmd, 0, 'Dat0', "fsmStartDataPhase - no data" );
1719: }
1720: }
1721:
1722: if ( ioReturn == kIOReturnSuccess )
1723: {
1724: // IOSetDBDMACommandPtr( fDBDMAAddr, fCCLPhysAddr );
1725: fDBDMAAddr->commandPtrLo = SWAP( fCCLPhysAddr );
1726: SynchronizeIO();
1727:
1728: // IOSetDBDMAChannelControl( fDBDMAAddr, kdbdmaRun * 0x1001 );
1729: // fDBDMAAddr->channelControl = SWAP( kdbdmaRun * 0x1001 );
1730: fDBDMAAddr->channelControl = SWAP( 0x80008000 ); // set RUN bit
1731: SynchronizeIO();
1732:
1733: WRITE_REGISTER( rXCM, fThisTransferLength >> 8 );
1734: WRITE_REGISTER( rXCL, fThisTransferLength & 0xFF );
1735: setCmdReg( cDMAXfer );
1736:
1737: fBusState = SCS_DMACOMPLETE;
1738: }
1739:
1740: if ( ioReturn != kIOReturnSuccess )
1741: {
1742: PAUSE( 0, 0, 'Dat-', "fsmStartDataPhase - data phase error" );
1743: fsmStartErrorRecovery( ioReturn );
1744: }
1745: return;
1746: }/* end fsmStartDataPhase */
1747:
1748:
1749: /* Start error recovery by doing something reasonable for the */
1750: /* current bus phase. This is called when we enter error recovery */
1751: /* (SCS_DEATH_MARCH) from an interrupt or other bus phase action handler. */
1752:
1753: void CurioSCSIController::fsmStartErrorRecovery( IOReturn status )
1754: {
1755:
1756: ELG( fCmd, 0, 'fSER', "fsmStartErrorRecovery" );
1757: killActiveCommand( status );
1758: /* Clean out the SCSI and DBDMA hardware */
1759: setCmdReg( cFlshFFO );
1760: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit
1761: // IODBDMAReset( fDBDMAAddr );
1762: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
1763: SynchronizeIO();
1764: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit
1765: SynchronizeIO();
1766:
1767: if ( fBusBusy == false )
1768: fBusState = SCS_DISCONNECTED;
1769: else fBusState = SCS_DEATH_MARCH;/* We will continue at fsmContinueErrorRecovery */
1770:
1771: fCkForAnotherInt = false;
1772: return;
1773: }/* end fsmStartErrorRecovery */
1774:
1775:
1776: /* Manage error recovery by responding to a target interrupt while in */
1777: /* an error recovery state. On exit, the bus state will be as follows: */
1778: /* SCS_DEATH_MARCH Still in error recovery. Call fsmContinueErrorRecovery */
1779: /* to continue processing target requests. */
1780: /* SCS_DISCONNECTED The target is finally off the bus. We can restart */
1781: /* normal operation. */
1782: /* Each bus phase requires a different action: */
1783: /* Data Out Clean up after DMA. */
1784: /* Data In Clean up after DMA. */
1785: /* Command Flush the FIFO */
1786: /* Status Drain the FIFO, if we get two bytes, just ACK the message */
1787: /* Message Out Do nothing */
1788: /* Message In Read the message byte, ACK it. */
1789:
1790: void CurioSCSIController::fsmErrorRecoveryInterruptService()
1791: {
1792: setCmdReg( cFlshFFO );
1793:
1794: switch ( fCurrentBusPhase )
1795: {
1796: case kBusPhaseDATO:
1797: case kBusPhaseDATI:
1798: // IODBDMAReset( fDBDMAAddr );
1799: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
1800: SynchronizeIO();
1801: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit
1802: SynchronizeIO();
1803: setCmdReg( cNOP | bDMAEnBit ); // clear TC zero bit
1804: break;
1805:
1806: case kBusPhaseCMD:
1807: break;
1808:
1809: case kBusPhaseSTS:
1810: if ( fSaveInterrupt & iFuncComp )
1811: {
1812: /* We got both bytes: ACK the command complete */
1813: setCmdReg( cMsgAcep );
1814: }
1815: break;
1816:
1817: case kBusPhaseMSGO:
1818: break;
1819:
1820: case kBusPhaseMSGI:
1821: setCmdReg( cMsgAcep );
1822: break;
1823:
1824: case kBusPhaseBusFree: /* Selecting */
1825: break;
1826:
1827: default:
1828: killActiveCommand( kIOReturnInternalError );
1829: resetBus();
1830: break;
1831: }
1832: return;
1833: }/* end fsmErrorRecoveryInterruptService */
1834:
1835:
1836: /* Continue to manage error recovery. We are here because the target */
1837: /* is still on the bus and doing strange bus phase things. Follow the */
1838: /* target bus phase (one phase at a time) until the target disconnects. */
1839: /* We just run bit-bucket commands until the target gives up. */
1840: /* (Note that this means that we might send a Command Complete message */
1841: /* to the target. We'll look for this case and send an Abort or */
1842: /* Abort Tag instead.) */
1843:
1844: void CurioSCSIController::fsmContinueErrorRecovery()
1845: {
1846: UInt8 msgByte;
1847:
1848:
1849: quickCheckForInterrupt();
1850:
1851:
1852: if ( fBusBusy )
1853: {
1854: interruptPending();
1855: if ( fSaveInterrupt & iDisconnect )
1856: fBusBusy = false;
1857: }
1858:
1859: if ( fBusBusy == false )
1860: {
1861: fBusState = SCS_DISCONNECTED;
1862: }
1863: else
1864: {
1865: fCurrentBusPhase = fSaveStatus & mPhase;
1866:
1867: switch ( fCurrentBusPhase )
1868: {
1869: case kBusPhaseMSGO:
1870: msgByte = kSCSIMsgAbort;
1871: WRITE_REGISTER( rFFO, msgByte );
1872: setCmdReg( cIOXfer ); /* Start non-DMA xfer */
1873: break;
1874:
1875: case kBusPhaseDATO:
1876: case kBusPhaseCMD:
1877: WRITE_REGISTER( rXCM, 0xFF );
1878: WRITE_REGISTER( rXCL, 0xFF );
1879: setCmdReg( cDMAXferPad ); /* DMA out pad */
1880: break;
1881:
1882: case kBusPhaseMSGI:
1883: case kBusPhaseDATI:
1884: case kBusPhaseSTS:
1885: WRITE_REGISTER( rXCM, 0xFF );
1886: WRITE_REGISTER( rXCL, 0xFF );
1887: setCmdReg( cXferPad ); /* non-DMA out pad */
1888: break;
1889:
1890: default:
1891: killActiveCommand( kIOReturnInternalError );
1892: resetBus();
1893: break;
1894: }
1895: }/* end SWITCH on current phase */
1896:
1897: return;
1898: }/* end fsmContinueErrorRecovery */
1899:
1900:
1901:
1902: IOReturn CurioSCSIController::getReselectionTargetID( UInt8 selectByte )
1903: {
1904: register UInt8 targetBits = selectByte;
1905: register UInt8 targetID = 0;
1906: register UInt8 bitValue; /* Supress warning */
1907:
1908:
1909: if ( (targetBits & fInitiatorIDMask) == 0 )
1910: {
1911: PAUSE( 0, selectByte, 'IId-', "getReselectionTargetID - Reselection failed: initiator ID bit not set" );
1912: return kIOReturnInternalError;
1913: }
1914:
1915: targetBits = selectByte;
1916: targetBits &= ~fInitiatorIDMask; /* Remove our bit */
1917: if ( targetBits == 0 )
1918: {
1919: PAUSE( 0, selectByte, 'TId-', "getReselectionTargetID - Reselection failed: Target ID bit not set" );
1920: return kIOReturnInternalError;
1921: }
1922:
1923: bitValue = targetBits;
1924:
1925: if ( bitValue > 0x0F ) { targetID += 4; bitValue >>= 4; }
1926: if ( bitValue > 0x03 ) { targetID += 2; bitValue >>= 2; }
1927: if ( bitValue > 0x01 ) targetID += 1;
1928:
1929: targetBits &= ~(1 << targetID); /* Remove the target mask */
1930: if ( targetBits != 0 )
1931: {
1932: PAUSE( 0, selectByte, 'TTT-', "getReselectionTargetID - Reselection failed: multiple targets" );
1933: return kIOReturnInternalError;
1934: }
1935:
1936: ELG( 0, targetID, '=Tar', "getReselectionTargetID" );
1937:
1938: fCurrentTargetLun.target = targetID; /* Save the current target */
1939: return kIOReturnSuccess;
1940: }/* end getReselectionTargetID */
1941:
1942:
1943: void CurioSCSIController::reselectNexus()
1944: {
1945: fCmd = findCommandWithNexus( fCurrentTargetLun, fTag );
1946: if ( fCmd )
1947: { fCmdData = (PrivCmdData*)fCmd->getCommandData();
1948: ELG( fCmd, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, '=Nex', "reselectNexus" );
1949: }
1950: else
1951: { if ( fTag != kInvalidTag )
1952: ELG( 0, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'Nex-', "reselectNexus" );
1953: }
1954:
1955: return;
1956: }/* end reselectNexus */
1957:
1958:
1959: /* Send a command to the MESH chip. This may cause an interrupt. */
1960:
1961: void CurioSCSIController::setCmdReg( UInt8 command )
1962: {
1963: ELG( 0, command, '=Cmd', "setCmdReg" );
1964:
1965: fCurioAddr[ rCMD ] = command; /***** DO IT *****/
1966: SynchronizeIO();
1967:
1968: return;
1969: }/* end setCmdReg */
1970:
1971:
1972:
1973: /* This spin-loop looks for another chip operation - it prevents */
1974: /* exiting the interrupt service routine if the chip presents */
1975: /* another operation within ten microseconds. Note that this */
1976: /* must be called from an IOThread, not from a "real" primary */
1977: /* interrupt service routine. */
1978: /* @return true if an interrupt is pending. */
1979:
1980: #define OVERTIME( now, end ) \
1981: ( ((now)->tv_sec > (end)->tv_sec) \
1982: || (((now)->tv_sec == (end)->tv_sec) && ((now)->tv_nsec > (end)->tv_nsec)) )
1983:
1984:
1985: bool CurioSCSIController::quickCheckForInterrupt()
1986: {
1987: mach_timespec_t thisTime, endTime;
1988:
1989:
1990: IOGetTime( &endTime ); // calc the omega
1991: endTime.tv_nsec += 10000; // 10 mikes from now
1992: if ( endTime.tv_nsec >= NSEC_PER_SEC )
1993: {
1994: endTime.tv_sec += 1;
1995: endTime.tv_nsec -= NSEC_PER_SEC;
1996: }
1997: /* whiz til interrupt or time's up: */
1998: do
1999: {
2000: if ( interruptPending() )
2001: return true;
2002:
2003: IOGetTime( &thisTime );
2004: } while ( OVERTIME( &thisTime, &endTime ) == false );
2005:
2006: return false;
2007: }/* end quickCheckForInterrupt */
2008:
2009:
2010: /* Determine if SCSI interrupt is pending. If so, store the current */
2011: /* chip state. Note that reading the interrupt register clears the */
2012: /* interrupt source, so this should be done once for each interrupt.*/
2013: /* @return true if an interrupt is pending. */
2014:
2015: bool CurioSCSIController::interruptPending()
2016: {
2017: bool result = false;
2018:
2019:
2020: /* mlj - use WHILE to check for double interrupts */
2021: /* and get get most recent conditions. */
2022:
2023: while ( (fSaveStatus = fCurioAddr[ rSTA ]) & sIntPend ) // ??? volatile
2024: {
2025: result = true;
2026: fSaveSeqStep = fCurioAddr[ rSQS ];
2027: fSaveInterrupt = fCurioAddr[ rINT ]; /* this clears rSTA and rSQS */
2028: ELG( fSaveSeqStep, fSaveStatus<<16 | fSaveInterrupt, 'Regs', "interruptPending" );
2029: }
2030: return result;
2031: }/* end interruptPending */
2032:
2033:
2034:
2035: void CurioSCSIController::putCDBIntoFIFO()
2036: {
2037: SCSICDBInfo scsiCDB;
2038: UInt32 i;
2039:
2040:
2041: fCmd->getCDB( &scsiCDB );
2042: for ( i = 0; i < scsiCDB.cdbLength; i++ )
2043: WRITE_REGISTER( rFFO, scsiCDB.cdb[ i ] );
2044:
2045: return;
2046: }/* end putCDBIntoFIFO */
2047:
2048:
2049: /* resetCurio - Reset the chip to hardware power on state. */
2050:
2051: void CurioSCSIController::resetCurio()
2052: {
2053: ELG( 0, 0, 'ResC', "resetCurio" );
2054: setCmdReg( cRstSChp ); /* Reset chip */
2055: IODelay( 50 ); /* Chip settle */
2056: setCmdReg( cNOP ); /* Re-enable chip */
2057: setCmdReg( cFlshFFO ); /* In a clean state */
2058: return;
2059: }/* end resetCurio */
2060:
2061:
2062: /* resetHardware - Reusable hardware initializer function. */
2063: /* if busReset is true, this includes a SCSI bus reset. */
2064:
2065: IOReturn CurioSCSIController::resetHardware( bool busReset )
2066: {
2067: IOReturn ioReturn = kIOReturnSuccess;
2068: UInt8 configValue;
2069: UInt8 clockConversionFactor;
2070: UInt8 defaultSelectionTimeout;
2071: UInt8 temp;
2072:
2073:
2074: /* Temp for debugging */
2075:
2076: fSCSIClockRate = kChipDefaultBusClockMHz;
2077:
2078: ELG( fSCSIClockRate, busReset, 'ResH', "resetHardware" );
2079:
2080: /* First of all, reset interrupts, the SCSI chip, and the DMA engine. */
2081:
2082: // resetCurio(); /* Clear out the chip */
2083:
2084: temp = fCurioAddr[ rINT ]; /* Clear pending interrupt */
2085:
2086: // IODBDMAReset( fDBDMAAddr ); /* Stop the DMA engine */
2087: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
2088: SynchronizeIO();
2089: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit
2090: SynchronizeIO();
2091:
2092: /* Initialize the chip: */
2093:
2094: WRITE_REGISTER( rCF2, CF2_EPL ); /* Enable Phase Latching */
2095: setCmdReg(cNOP | bDMAEnBit); /* DMA Nop */
2096:
2097: /* Init state variables: */
2098:
2099: fCkForAnotherInt = false;
2100: fBusState = SCS_DISCONNECTED;
2101: fBusBusy = false;
2102: fCurrentBusPhase = kBusPhaseBusFree;
2103:
2104: /* Smash all active command state (just in case). */
2105:
2106: fCmd = NULL;
2107: fMsgInState = kMsgInInit;
2108: fpMsgOut = fpMsgPut = fMsgOutBuffer;
2109:
2110: fCurrentTargetLun.target = kInvalidTarget;
2111: fCurrentTargetLun.lun = kInvalidLUN;
2112:
2113: /* Configuration Register 1 */
2114: /* Disable interrupt on initiator-instantiated bus reset */
2115: /* (is this correct?) */
2116: /* Enable parity. */
2117: /* Set default bus ID (7) (This should be overriden by the */
2118: /* Inspector) */
2119:
2120: fInitiatorID = kDefaultInitiatorID;
2121: configValue = CF1_SRD | CF1_ENABPAR | fInitiatorID;
2122:
2123: #define gOptionExtendTiming 0
2124: if ( gOptionExtendTiming )
2125: { /* Per instance table. This slows down transfers on the bus. */
2126: configValue |= CF1_SLOW;
2127: }
2128:
2129: WRITE_REGISTER( rCF1, configValue );
2130:
2131: /* Clock factor and select timeout. */
2132:
2133: /* Use the clock frequency (in MHz) to select the clock conversion */
2134: /* factor. According to the NCR53CF94/96 data manual, the conversion */
2135: /* factor is defined by the following table: Currently, we don't allow */
2136: /* the caller to change selection timeout from the ANSI standard */
2137: /* 250 Msec to avoid having to support floating-point register */
2138: /* manipulation */
2139:
2140: if ( fSCSIClockRate < 10) fSCSIClockRate = 10;
2141: if ( fSCSIClockRate > 40 ) fSCSIClockRate = 40;
2142:
2143: if ( fSCSIClockRate <= 10 )
2144: {
2145: clockConversionFactor = ccf10MHz;
2146: defaultSelectionTimeout = SelTO16Mhz;
2147: }
2148: else if ( fSCSIClockRate <= 15 )
2149: {
2150: clockConversionFactor = ccf11to15MHz;
2151: defaultSelectionTimeout = SelTO16Mhz;
2152: }
2153: else if ( fSCSIClockRate <= 20 )
2154: {
2155: clockConversionFactor = ccf16to20MHz;
2156: defaultSelectionTimeout = SelTO16Mhz;
2157: }
2158: else if ( fSCSIClockRate <= 25 )
2159: {
2160: clockConversionFactor = ccf21to25MHz;
2161: defaultSelectionTimeout = SelTO25Mhz;
2162: }
2163: else if ( fSCSIClockRate <= 30 )
2164: {
2165: clockConversionFactor = ccf26to30MHz;
2166: defaultSelectionTimeout = SelTO33Mhz;
2167: }
2168: else if ( fSCSIClockRate <= 35 )
2169: {
2170: clockConversionFactor = ccf31to35MHz;
2171: defaultSelectionTimeout = SelTO40Mhz;
2172: }
2173: else
2174: {
2175: clockConversionFactor = ccf31to35MHz;
2176: defaultSelectionTimeout = SelTO40Mhz;
2177: }
2178:
2179: WRITE_REGISTER( rCKF, clockConversionFactor );
2180:
2181: WRITE_REGISTER( rINT, defaultSelectionTimeout);
2182:
2183: /* Configuration Register 2 - enable extended features */
2184: /* - mainly, 24-bit transfer count. */
2185:
2186: WRITE_REGISTER( rCF2, CF2_EPL );
2187:
2188: /* Configuration Register 3 */
2189:
2190: configValue = 0;
2191:
2192: #define gOptionFastModeEnable 0
2193: #define gOptionFastModeSupportedByHardware 0
2194:
2195: if ( (gOptionFastModeEnable && gOptionFastModeSupportedByHardware)
2196: || fSCSIClockRate > 25 )
2197: {
2198: configValue |= CF3_FASTSCSI;
2199: }
2200:
2201: WRITE_REGISTER( rCF3, configValue );
2202:
2203: /* Configuration Register 4 - glitch eater, active negation. */
2204: /* Let's not worry about these whizzy features just yet. */
2205:
2206: WRITE_REGISTER( rCF4, 0 );
2207:
2208: /* Go to async xfer mode for now. */
2209:
2210: WRITE_REGISTER( rFOS, 0 );
2211:
2212: /* Reset SCSI bus, wait, clear possible interrupt. */
2213:
2214: if ( busReset )
2215: {
2216: setCmdReg( cRstSBus );
2217: IOSleep( kSCSIResetDelay );
2218: temp = fCurioAddr[ rINT ]; // clear the Interrupt register
2219: }
2220: return ioReturn;
2221: }/* end resetHardware */
2222:
2223:
2224: void CurioSCSIController::releaseHardwareMemoryMaps()
2225: {
2226: if ( fDBDMAMemoryMap )
2227: {
2228: fDBDMAMemoryMap->release();
2229: fDBDMAMemoryMap = NULL;
2230: }
2231:
2232: if ( fSCSIMemoryMap )
2233: {
2234: fSCSIMemoryMap->release();
2235: fSCSIMemoryMap = NULL;
2236: }
2237:
2238: if ( fCCL )
2239: {
2240: IOFree( fCCL, fCCLSize );
2241: }
2242:
2243: return;
2244: }/* end releaseHardwareMemoryMaps */
2245:
2246:
2247: /* When a legitimate data phase starts, this method */
2248: /* is called to configure the DBDMA Channel Command list. */
2249:
2250: IOReturn CurioSCSIController::generateCCL()
2251: {
2252: IODBDMADescriptor *dp; /* current descriptor */
2253: IODBDMADescriptor *dpMax; /* past the last descriptor */
2254: UInt32 dbdmaOp; /* DBDMA opcode */
2255: UInt32 rangeByteCount, actualRanges;
2256: UInt32 i;
2257: IOPhysicalSegment range[ kMaxMemoryCursorSegments ];
2258:
2259:
2260:
2261: // IODBDMAReset( fDBDMAAddr ); /* make sure that the DBDMA is idle. */
2262: fDBDMAAddr->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
2263: SynchronizeIO();
2264: fDBDMAAddr->channelControl = SWAP( 0x80000000 ); // clr RUN bit
2265: SynchronizeIO();
2266:
2267: if ( fCmdData->isWrite ) /* Select the correct DBDMA: */
2268: dbdmaOp = OUTPUT_MORE;
2269: else dbdmaOp = INPUT_MORE;
2270:
2271: /* How many descriptors can we store (need some slop for the */
2272: /* terminator commands). */
2273: /* Get a pointer to the first free descriptor and the total */
2274: /* number of bytes left to transfer in this I/O request. */
2275:
2276: dp = (IODBDMADescriptor*)fCCL;
2277: dpMax = (IODBDMADescriptor*)(fCCL + fCCLSize - 256);
2278:
2279: /* fThisTransferLength will contain the actual number */
2280: /* of bytes we intend to transfer in this DMA request, */
2281: /* which is needed when DMA completes to recover the */
2282: /* residual transfer length. */
2283: fThisTransferLength = 0;
2284:
2285: while ( (dp < dpMax) && (fThisTransferLength < kMaxDMATransfer) )
2286: {
2287: actualRanges = fMemoryCursor->getPhysicalSegments( fCmdData->mdp,
2288: fCmdData->results.bytesTransferred + fThisTransferLength,
2289: range,
2290: (unsigned int)kMaxMemoryCursorSegments,
2291: 0, &rangeByteCount );
2292: if ( actualRanges == 0 )
2293: break;
2294:
2295: for ( i = 0; i < actualRanges; i++ )
2296: {
2297: ELG( range[ i ].location, range[ i ].length, '=Rng', "generateCCL - range" );
2298: dp->operation = SWAP( dbdmaOp | range[ i ].length );
2299: dp->address = SWAP( (UInt32)range[ i ].location );
2300: dp->cmdDep = 0; // no branch address
2301: dp->result = 0;
2302: dp++;
2303: }/* end FOR each range */
2304:
2305: fThisTransferLength += rangeByteCount;
2306: }/* end WHILE there is data to xfer */
2307:
2308: if ( (UInt8*)dp > fCCL )
2309: {
2310: /* We stored at least one descriptor. */
2311: /* Change the last one so it is an INPUT_LAST or OUTPUT_LAST. */
2312:
2313: dp->operation |= SWAP( IO_LAST );
2314: }
2315:
2316: dp->operation = SWAP( STOP_CMD );
2317: dp->address = 0;
2318: dp->cmdDep = 0;
2319: dp->result = 0;
2320: dp++;
2321:
2322: if( dp >= dpMax )
2323: PAUSE( dpMax, dp, 'Big-', "InitCmdCCL - CCL overrun" );
2324:
2325: flush_dcache( (vm_offset_t)fCCL, (UInt32)dp - (UInt32)fCCL, false );
2326:
2327: return kIOReturnSuccess;
2328: }/* end generateCCL */
2329:
2330:
2331: void CurioSCSIController::killActiveCommand( IOReturn finalStatus )
2332: {
2333: if ( fCmd )
2334: {
2335: fCmdData->results.returnCode = finalStatus;
2336: completeCommand();
2337: }
2338: return;
2339: }/* end killActiveCommand */
2340:
2341:
2342: void CurioSCSIController::resetBus()
2343: {
2344: setCmdReg( cRstSBus );
2345: super::resetOccurred();
2346: IOSleep( kSCSIResetDelay );
2347: enableCommands();
2348: return;
2349: }/* end resetBus */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.