|
|
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: /**
24: * Copyright 1997-2000 Apple Computer Inc. All Rights Reserved.
25: * author Mike Johnson
26: *
27: * Set tabs every 4 characters.
28: *
29: * Edit History
30: * 25feb99 mlj Initial conversion from banana sources.
31: */
32:
33:
34: #include <IOKit/scsi/IOSCSIParallelInterface.h>
35: #include <IOKit/pci/IOPCIDevice.h>
36: #include <mach/clock_types.h>
37:
38: #include <IOKit/IOInterruptEventSource.h>
39: #include <IOKit/ppc/IODBDMA.h>
40:
41: #include "mesh.h"
42:
43: extern void IOGetTime( mach_timespec_t *clock_time );
44: extern void kprintf( const char *, ... );
45: extern void call_kdp(); // for debugging
46:
47:
48:
49: #define super IOSCSIParallelController
50:
51: OSDefineMetaClassAndStructors( meshSCSIController, IOSCSIParallelController ) ;
52:
53:
54:
55: static globals g; /**** Instantiate the globals ****/
56:
57:
58: /* Channel Program. Note that this script must match the offsets */
59: /* specified in mesh.h. This script is copied into the */
60: /* channel command area (with appropriate entries byte-swapped so */
61: /* it ends up with the correct endian-ness). */
62: /* Lines beginning with "slash, star, star, slash" are modified */
63: /* by the driver before it starts the Channel Program. */
64:
65: static const DBDMADescriptor gDescriptorList[] =
66: {
67: /* 0x00 kcclProblem - Branch here for anomalies */
68:
69: { MESH_REG( kMeshInterruptMask, kMeshIntrMask ) }, // Enable MESH interrupt
70: { STOP( kcclStageCCLx ) }, // anomaly
71:
72: /* 0x20 through 0x60 - Data for information phases: */
73:
74: { RESERVE }, // kcclCMDOdata - CDB ( 6,10,12,16 bytes)
75: { RESERVE }, // kcclMSGOdata - MSGO data (last byte @3F)
76: { RESERVE }, // kcclMSGIdata - MSGI data & STATUS
77: { RESERVE }, // kcclSenseCDB - CDB for (auto) Sense
78: { RESERVE }, // kcclBatchSize, kcclStageLabel
79:
80: /* 0x70 - kcclSense - AutoSense input: */
81:
82: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // set MESH xfer count to 255
83: { MESH_REG( kMeshTransferCount0, kMaxAutosenseByteCount & 0xFF )},
84: { MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )},// Data-In to Seq register
85: { SENSE( kMaxAutosenseByteCount ) }, // Sense INPUT
86: { BRANCH( kcclGetStatus ) }, // do finish sequence
87:
88: /* 0xC0 - kcclPrototype - Prototype MESH 4-command Transfer sequence: */
89:
90: { MOVE_4( kcclBatchSize, 0, kRelAddressCP ) }, // MESH batch size
91: { MESH_REG( kMeshTransferCount1, 0 ) }, // Set high order Transfer Count
92: { MESH_REG( kMeshTransferCount0, 0 ) }, // Set low order Transfer Count
93: { MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA )}, // Assume Data-In
94:
95: { RESERVE }, // kcclReadBuf8
96: { RESERVE }, // spare
97:
98: /* 0x120 kcclStart - Arbitrate (START CHANNEL PROGRAM HERE): */
99: /* 0x140 kcclBrProblem */
100:
101: { STAGE( kcclStageArb ) },
102: { MESH_REG( kMeshSequence, kMeshArbitrateCmd ) }, // issue Arbitrate
103: { BR_IF_PROBLEM }, // branch if exception or error
104:
105: /* 0x150 - Select with Attention: */
106:
107: { STAGE( kcclStageSelA ) },
108: { CLEAR_CMD_DONE },
109: { MESH_REG( kMeshSequence, kMeshSelectCmd | kMeshSeqAtn ) }, // select with attention
110: { BR_IF_PROBLEM }, // branch if failed
111:
112: /* 0x190 kcclMsgoStage - Message-Out: */
113:
114: { STAGE( kcclStageMsgO ) },
115: { CLEAR_CMD_DONE },
116:
117: /* 0x1B0 kcclMsgoBranch - modify this BRANCH to fall through for multibyte messages: */
118:
119: /**/{ BRANCH( kcclLastMsgo ) }, // kcclMsgoBranch - go do only byte of Msg
120:
121: /* 0x1C0 - do all but last byte of multibyte message: */
122:
123: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // count does include last byte
124: /**/{ MESH_REG( kMeshTransferCount0, 0xFF ) }, // kcclMsgoMTC - modify MESH xfer count here
125: { MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqAtn | kMeshSeqDMA ) }, // DMA MsgO with ATN
126: /**/{ MSGO( kcclMSGOdata, 255 ) }, // kcclMsgoDTC - output all but last byte
127: { CLEAR_CMD_DONE },
128:
129: /* 0x210 kcclLastMsgo - wait for REQ signal before dropping ATN: */
130:
131: { MESH_REG( kMeshInterruptMask, 0 ) }, // inhibit MESH interrupt
132: { MESH_REG_WAIT( kMeshSequence, kMeshStatusCmd | kMeshSeqAtn ) }, // gen PhaseMM
133: { CLEAR_INT_REG }, // clear PhaseMM & CmdDone
134: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints
135:
136: /* 0x250 - put out the last or only byte of Message-Out phase: */
137:
138: { MESH_REG( kMeshTransferCount1, 0x00 ) },
139: { MESH_REG( kMeshTransferCount0, 0x01 ) },
140: { MESH_REG( kMeshSequence, kMeshMessageOutCmd | kMeshSeqDMA ) },// no more ATN
141: { MSGO( kcclMSGOLast, 1 ) },
142:
143: /* 0x290 kcclCmdoStage - Command Out: */
144:
145: { STAGE( kcclStageCmdO ) },
146: { CLEAR_CMD_DONE },
147: { MESH_REG( kMeshTransferCount1, 0x00 ) },
148: /**/{ MESH_REG( kMeshTransferCount0, 0x06 ) }, // kcclCmdoMTC - Set MESH xfer count to 6
149: { MESH_REG( kMeshSequence, kMeshCommandCmd | kMeshSeqDMA )}, // Command phase with DMA on
150: /**/{ CMDO( 6 ) }, // kcclCmdoDTC - output the CDB
151:
152: /* 0x2F0 - DATA XFER - branch to the built CCL @ 0x05D0: */
153: /* also, kcclReselect - reselect code enters here: */
154:
155: { CLEAR_CMD_DONE },
156: { STAGE( kcclStageXfer ) },
157: { BRANCH( kcclDataXfer ) }, // go do Xfer CCL
158:
159: /* 0x320 kcclOverrun - dump excess data in the bit bucket: */
160: /* Exc and Err are still disabled. */
161:
162: { STAGE( kcclStageBucket ) },
163: { MESH_REG( kMeshTransferCount1, 0x00 ) }, // set MESH Transfer Count to max
164: { MESH_REG( kMeshTransferCount0, 0x00 ) },
165: { CLR_PHASEMM },
166: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints
167: /**/{ MESH_REG( kMeshSequence, kMeshDataInCmd | kMeshSeqDMA ) }, // set Seq Reg
168: /**/{ BUCKET }, // OUT/INPUT_LAST the bits
169: { BR_NO_PROBLEM( kcclOverrunDBDMA ) }, // loop til PhaseMismatch
170: { BR_IF_PROBLEM }, // take the interrupt now
171:
172: /* 0x3B0 kcclSyncCleanUp - clean up after Sync xfer: */
173: { CLEAR_INT_REG }, // clear PhaseMM & CmdDone (& Err?)
174: { MESH_REG( kMeshInterruptMask, kMeshIntrException | kMeshIntrError ) }, // re-enable ERR/EXC Ints
175:
176: /* 0x3D0 kcclGetStatus - setup CCL for status, command complete and bus free: */
177:
178: { STAGE( kcclStageStat ) },
179: { MESH_REG( kMeshTransferCount1, 0x00 ) },
180: { MESH_REG( kMeshTransferCount0, 0x01 ) }, // set MESH xfer count to 1
181: { MESH_REG( kMeshSequence, kMeshStatusCmd | kMeshSeqDMA )},// Status-in phase with DMA on
182: { STATUS_IN }, // input the status byte
183:
184: /* 0x420 - Message In: */
185:
186: { STAGE( kcclStageMsgI ) },
187: { CLEAR_CMD_DONE },
188: { MESH_REG( kMeshTransferCount1, 0x00 ) },
189: { MESH_REG( kMeshTransferCount0, 0x01 ) }, // set MESH xfer count to 1
190: { MESH_REG( kMeshSequence, kMeshMessageInCmd | kMeshSeqDMA )}, // Status-in phase with DMA on
191: { MSGI( 1 ) }, // get the Message-In byte
192:
193: /* 0x480 - Bus Free: */
194:
195: { STAGE( kcclStageFree ) },
196: { CLEAR_CMD_DONE },
197: { MESH_REG( kMeshSequence, kMeshEnableReselect ) }, // Enable Reselect
198: { MESH_REG( kMeshSequence, kMeshBusFreeCmd ) }, // Bus Free phase
199: { BR_IF_PROBLEM }, // branch if failed
200:
201: /* 0x4D0 kcclMESHintr - Good completion: */
202:
203: { STAGE( kcclStageGood ) },
204: { MESH_REG( kMeshInterruptMask, kMeshIntrMask ) }, // latch MESH interrupt
205: { STOP( kcclStageStop ) }, // Stop
206:
207: /* The rest of the Channel Program area is used for autosense */
208: /* and data transfer channel commands: */
209: /* kcclSenseBuffer Autosense area */
210: /* kcclDataXfer Start of data transfer channel commands */
211: /* kcclSenseResult Autosense result stored here */
212:
213: }; /* end gDescriptorList structure */
214:
215: const UInt32 gDescriptorListSize = sizeof( gDescriptorList );
216:
217:
218: /* MAX_DMA_XFER is set so that we don't have to worry about the */
219: /* ambiguous "zero" value in the MESH and DBDMA transfer registers */
220: /* that can mean either 65536 bytes or zero bytes. */
221:
222: #define MAX_DMA_XFER 0x0000F000 // round down to nearest page
223:
224:
225: enum /***** values for g.intLevel: *****/
226: {
227: kLevelISR = 0x80, /* In Interrupt Service Routine */
228: kLevelLocked = 0x40, /* MESH interrupts locked out */
229: kLevelSIH = 0x20, /* In Secondary Interrupt Handler */
230: kLevelLatched = 0x10 /* Interrupt latched */
231: };
232:
233:
234: #if USE_ELG
235: static void AllocateEventLog( UInt32 size )
236: {
237: if ( g.evLogBuf )
238: return;
239:
240: g.evLogFlag = 0; /* assume insufficient memory */
241: g.evLogBuf = (UInt8*)IOMalloc( size );
242: if ( !g.evLogBuf )
243: {
244: kprintf( "probe - MESH evLog allocation failed " );
245: return;
246: }
247:
248: bzero( g.evLogBuf, size );
249: g.evLogBufp = g.evLogBuf;
250: g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer?
251: g.evLogFlag = 0xFEEDBEEF; // continuous wraparound
252: // g.evLogFlag = 'step'; // stop at each ELG
253: // g.evLogFlag = 0x0333; // any nonzero - don't wrap - stop logging at buffer end
254: return;
255: }/* end AllocateEventLog */
256:
257:
258: static void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
259: {
260: register UInt32 *lp; /* Long pointer */
261: mach_timespec_t time;
262:
263: if ( g.evLogFlag == 0 )
264: return;
265:
266: IOGetTime( &time );
267:
268: lp = (UInt32*)g.evLogBufp;
269: g.evLogBufp += 0x10;
270:
271: if ( g.evLogBufp >= g.evLogBufe ) /* handle buffer wrap around if any */
272: { g.evLogBufp = g.evLogBuf;
273: if ( g.evLogFlag != 0xFEEDBEEF ) // make 0xFEEDBEEF a symbolic ???
274: g.evLogFlag = 0; /* stop tracing if wrap undesired */
275: }
276:
277: /* compose interrupt level with 3 byte time stamp: */
278:
279: *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); // ~ 1 microsec resolution
280: *lp++ = a;
281: *lp++ = b;
282: *lp = ascii;
283:
284: if( g.evLogFlag == 'step' )
285: { static char code[ 5 ] = {0,0,0,0,0};
286: *(UInt32*)&code = ascii;
287: // kprintf( "%8x mesh: %8x %8x %s %s\n", time.tv_nsec>>10, a, b, code, str );
288: kprintf( "%8x mesh: %8x %8x %s\n", time.tv_nsec>>10, a, b, code );
289: }
290:
291: return;
292: }/* end EvLog */
293:
294:
295: static void Pause( UInt32 a, UInt32 b, UInt32 ascii, char* str )
296: {
297: char work [ 256 ];
298: char name[] = "meshSCSIController:";
299: char *bp = work;
300: UInt8 x;
301: int i;
302:
303:
304: EvLog( a, b, ascii, str );
305: EvLog( '****', '** P', 'ause', "*** Pause" );
306:
307: bcopy( name, bp, sizeof( name ) );
308: bp += sizeof( name ) - 1;
309:
310: *bp++ = '{'; // prepend p1 in hex:
311: for ( i = 7; i >= 0; --i )
312: {
313: x = a & 0x0F;
314: if ( x < 10 )
315: x += '0';
316: else x += 'A' - 10;
317: bp[ i ] = x;
318: a >>= 4;
319: }
320: bp += 8;
321:
322: *bp++ = ' '; // prepend p2 in hex:
323:
324: for ( i = 7; i >= 0; --i )
325: {
326: x = b & 0x0F;
327: if ( x < 10 )
328: x += '0';
329: else x += 'A' - 10;
330: bp[ i ] = x;
331: b >>= 4;
332: }
333: bp += 8;
334: *bp++ = '}';
335:
336: *bp++ = ' ';
337:
338: for ( i = sizeof( work ) - (int)(bp - work); i && (*bp++ = *str++); --i ) ;
339:
340: // kprintf( work );
341: panic( work );
342: // call_kdp(); // ??? use kdp=3 in boot parameters
343: return;
344: }/* end Pause */
345: #endif // USE_ELG
346:
347:
348:
349: bool meshSCSIController::configure( IOService *provider,
350: SCSIControllerInfo *controllerInfo )
351: {
352: IOReturn ioReturn = kIOReturnInternalError;
353:
354:
355: g.intLevel = 0;
356: g.meshInstance = this;
357: #if USE_ELG
358: AllocateEventLog( kEvLogSize );
359: ELG( g.evLogBufp, &g.evLogFlag, 'MESH', "configure - event logging set up." );
360: #endif /* USE_ELG */
361:
362: ELG( this, provider, 'Cnfg', "configure" );
363:
364: fProvider = (IOPCIDevice*)provider;
365:
366: ioReturn = initializeHardware();
367: if ( ioReturn != kIOReturnSuccess )
368: return false;
369:
370: /* Register our interrupt handler routine: */
371:
372: fInterruptEvent = IOInterruptEventSource::interruptEventSource(
373: (OSObject*)this,
374: (IOInterruptEventAction)&meshSCSIController::interruptOccurred,
375: provider,
376: 0 );
377:
378: if ( fInterruptEvent == NULL )
379: {
380: PAUSE( 0, 0, 'IES-', "registerMESHInterrupt - can't register interrupt action" );
381: return false;
382: }
383:
384: getWorkLoop()->addEventSource( fInterruptEvent );
385: fInterruptEvent->enable();
386:
387: /* allocate a big-endian memory cursor: */
388:
389: fMemoryCursor = IOBigMemoryCursor::withSpecification( kMaxDMATransfer, kMaxDMATransfer );
390: if ( fMemoryCursor == NULL )
391: {
392: PAUSE( 0, kMaxDMATransfer, 'Mem-', "mesh::start - IOBigMemoryCursor::withSpecification NG" );
393: return false;
394: }
395:
396:
397: /* Fill in the SCSIControllerInfo structure and return: */
398:
399: controllerInfo->initiatorId = 7;
400:
401: controllerInfo->maxTargetsSupported = 8;
402: controllerInfo->maxLunsSupported = 8;
403:
404: controllerInfo->minTransferPeriodpS = 100000; /* picoSecs for 10 MHz */
405: controllerInfo->maxTransferOffset = 15;
406: controllerInfo->maxTransferWidth = 1;
407:
408: controllerInfo->maxCommandsPerController= 0;
409: controllerInfo->maxCommandsPerTarget = 8; // 0 is unlimited
410: controllerInfo->maxCommandsPerLun = 0;
411:
412: controllerInfo->tagAllocationMethod = kTagAllocationPerLun;
413: controllerInfo->maxTags = 256;
414:
415: controllerInfo->commandPrivateDataSize = sizeof( PrivCmdData );
416:
417: controllerInfo->disableCancelCommands = false;
418:
419: return true;
420: }/* end configure */
421:
422:
423: void meshSCSIController::executeCommand( IOSCSICommand *scsiCommand )
424: {
425: SCSICDBInfo scsiCDB;
426: SCSITargetParms targetParms;
427: UInt8 msgByte;
428: UInt8 rc;
429:
430:
431: if ( fCmd || (g.intLevel & kLevelLatched) )
432: {
433: disableCommands();
434: rescheduleCommand( scsiCommand );
435: ELG( fCmd, scsiCommand, 'Busy', "executeCommand - bus busy so bounce this cmd" );
436: return;
437: }
438:
439: fCmd = scsiCommand;
440: fCmdData = (PrivCmdData*)scsiCommand->getCommandData();
441: bzero( fCmdData, sizeof( fCmdData ) ); /// ??? unnecessary?
442:
443: scsiCommand->getTargetLun( &fCurrentTargetLun );
444: scsiCommand->getCDB( &scsiCDB );
445: scsiCommand->getDevice( kIOSCSIDevice )->getTargetParms( &targetParms );
446:
447: ELG( scsiCommand, *(UInt16*)&fCurrentTargetLun<<16 | (scsiCDB.cdbTag & 0xFFFF), 'Exec', "meshSCSIController::executeCommand" );
448: ELG( *(UInt32*)&scsiCDB.cdb[0], *(UInt32*)&scsiCDB.cdb[4] , '=CDB', "executeCommand - CDB" );
449:
450: fMsgOutFlag = 0;
451: fMsgOutPtr = &fCCL[ kcclMSGOdata ];
452:
453: /* Identify byte: */
454:
455: msgByte = kSCSIMsgIdentify | kSCSIMsgEnableDisconnectMask | fCurrentTargetLun.lun;
456: if ( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect )
457: msgByte &= ~kSCSIMsgEnableDisconnectMask;
458: *fMsgOutPtr++ = msgByte;
459:
460: /* Tag msg: */
461:
462: if ( scsiCDB.cdbTagMsg )
463: {
464: *fMsgOutPtr++ = scsiCDB.cdbTagMsg;
465: *fMsgOutPtr++ = scsiCDB.cdbTag;
466: ELG( 0, scsiCDB.cdbTagMsg<<16 | scsiCDB.cdbTag, ' tag', "meshSCSIController::executeCommand - tag" );
467: }
468:
469: /* Abort msg: */
470:
471: if ( scsiCDB.cdbAbortMsg )
472: {
473: ELG( scsiCommand->getOriginalCmd(), scsiCDB.cdbAbortMsg, 'Abor', "meshSCSIController::executeCommand - abort msg." );
474: *fMsgOutPtr++ = scsiCDB.cdbAbortMsg;
475: }
476:
477: /* Sync negotiation msg: */
478:
479: fNegotiatingSDTR = false;
480: if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateSDTR )
481: { fNegotiatingSDTR = true;
482: *fMsgOutPtr++ = kSCSIMsgExtended;
483: *fMsgOutPtr++ = 3;
484: *fMsgOutPtr++ = kSCSIMsgSyncXferReq;
485: *fMsgOutPtr++ = targetParms.transferPeriodpS / 4000;
486: *fMsgOutPtr++ = targetParms.transferOffset;
487: }
488:
489:
490: /***** Try to start the command on the hardware: *****/
491:
492: rc = startCommand(); /* Call the hardware layer. */
493:
494: if ( rc != kHardwareStartOK )
495: { /* Hardware can't start now */
496: ELG( fCmd, 0, 'Exe-', "meshSCSIController::executeCommand - command bounced back" );
497: rescheduleCommand( fCmd );
498: fCmd = NULL;
499: }
500:
501: return;
502: }/* end executeCommand */
503:
504:
505: void meshSCSIController::cancelCommand( IOSCSICommand *scsiCommand )
506: {
507: IOSCSICommand *origCmd;
508: PrivCmdData *origCmdData;
509: SCSIResults results;
510:
511: origCmd = scsiCommand->getOriginalCmd();
512:
513: ELG( scsiCommand, origCmd, 'Can-', "meshSCSIController::cancelCommand" );
514:
515: if ( origCmd ) /* if original command still around, complete it: */
516: {
517: origCmd->getResults( &results );
518: origCmdData = (PrivCmdData*)origCmd->getCommandData();
519: results.bytesTransferred = origCmdData->results.bytesTransferred;
520: origCmd->setResults( &results );
521: origCmd->complete();
522: }
523:
524: scsiCommand->complete();
525: return;
526: }/* end cancelCommand */
527:
528:
529: void meshSCSIController::resetCommand( IOSCSICommand *scsiCommand )
530: {
531: ELG( scsiCommand, 0, 'Rst-', "meshSCSIController::resetCommand" );
532: resetBus();
533: fCmdData = (PrivCmdData*)scsiCommand->getCommandData();
534: bzero( &fCmdData->results, sizeof( fCmdData->results ) );
535: scsiCommand->setResults( &fCmdData->results );
536: scsiCommand->complete();
537: return;
538: }/* end resetCommand */
539:
540:
541: /* Fetch the device's bus address and interrupt port number. */
542: /* Also, allocate one page of memory for the channel program. */
543:
544: IOReturn meshSCSIController::initializeHardware()
545: {
546: IOReturn ioReturn;
547: int i;
548:
549: ELG( 0, 0, 'IniH', "initializeHardware" );
550:
551:
552: fInitiatorID = kInitiatorIDDefault;
553: fInitiatorIDMask = 1 << kInitiatorIDDefault; /* BusID bitmask for reselection. */
554:
555: for ( i = 0; i < 8; ++i)
556: fSyncParms[ i ] = kSyncParmsAsync;
557:
558: ioReturn = getHardwareMemoryMaps();
559:
560: if ( ioReturn == kIOReturnSuccess )
561: ioReturn = allocHdwAndChanMem();
562:
563: if ( ioReturn == kIOReturnSuccess )
564: ioReturn = doHBASelfTest();
565:
566: if ( ioReturn == kIOReturnSuccess )
567: {
568: ioReturn = resetBus();
569: fMESHAddr->sourceID = fInitiatorID;
570: }
571:
572: return ioReturn;
573: }/* end initializeHardware */
574:
575:
576: IOReturn meshSCSIController::getHardwareMemoryMaps()
577: {
578:
579: if ( !fSCSIMemoryMap )
580: {
581: fSCSIMemoryMap = fProvider->mapDeviceMemoryWithIndex( kMESHRegisterBase );
582: if ( !fSCSIMemoryMap )
583: {
584: ELG( 0, 0, 'Map-', "getHardwareMemoryMaps - can't map MESH." );
585: return kIOReturnInternalError;
586: }
587:
588: fMESHPhysAddr = fSCSIMemoryMap->getPhysicalAddress();
589: fMESHAddr = (MeshRegister*)fSCSIMemoryMap->getVirtualAddress();
590: ELG( fMESHPhysAddr, fMESHAddr, '=MSH', "getHardwareMemoryMaps - MESH regs" );
591: g.meshAddr = (UInt32)fMESHAddr; // for debugging, miniMon ...
592: }
593:
594: if ( !fDBDMAMemoryMap )
595: {
596: fDBDMAMemoryMap = fProvider->mapDeviceMemoryWithIndex( kDBDMARegisterBase );
597: if ( !fDBDMAMemoryMap )
598: {
599: ELG( 0, 0, 'map-', "getHardwareMemoryMaps - can't map DBDMA." );
600: return kIOReturnInternalError;
601: }
602: dbdmaAddrPhys = fDBDMAMemoryMap->getPhysicalAddress();
603: dbdmaAddr = (UInt8*)fDBDMAMemoryMap->getVirtualAddress();
604: ELG( dbdmaAddrPhys, dbdmaAddr, '=DMA', "getHardwareMemoryMaps - DBDMA regs" );
605: #if CustomMiniMon
606: gMESH_DBDMA = (UInt32)dbdmaAddr;
607: gMESH_DBDMA_Phys = (UInt32)dbdmaAddrPhys;
608: #endif /* CustomMiniMon */
609: }
610:
611: return kIOReturnSuccess;
612: }/* end getHardwareMemoryMaps */
613:
614:
615:
616: /* Fetch the device's bus address and allocate one page of memory */
617: /* for the channel command. (Strictly speaking, we don't need an */
618: /* entire page, but we can use the rest of the page for a permanent */
619: /* status log). */
620: /* @param deviceDescription Specify the device to initialize. */
621: /* @return kIOReturnSuccess if successful, else an error status. */
622:
623: IOReturn meshSCSIController::allocHdwAndChanMem()
624: {
625: /* Set the default selection timeout to the MESH value (10 msec units). */
626:
627: fSelectionTimeout = 250 / 10; // ??? symbolic
628:
629: /* Allocate a page of wired-down memory in the kernel: */
630:
631: fCCLSize = page_size;
632: fCCL = (UInt8*)IOMallocContiguous( fCCLSize, page_size, &fCCLPhysAddr );
633: if ( !fCCL )
634: { PAUSE( 0, fCCLSize, 'CCA-', "allocHdwAndChanMem - can't allocate channel command area.\n" );
635: return kIOReturnNoMemory;
636: }
637:
638: /* Remember the number of DBDMA descriptors that */
639: /* can be used for data transfer channel commands. */
640:
641: fDBDMADescriptorMax = (fCCLSize - kcclDataXfer) / sizeof( DBDMADescriptor );
642:
643: g.cclPhysAddr = (UInt32)fCCLPhysAddr; // for debugging ease
644: g.cclLogAddr = (UInt32)fCCL;
645:
646: ELG( fCCLPhysAddr, fCCL, '=CCL', "allocHdwAndChanMem - CCL phys/logical addresses." );
647: initCP();
648:
649: /* What do we do on failure? Should we try to deallocate */
650: /* the stuff we created, or will the system do this for us? */
651:
652: return kIOReturnSuccess;
653: }/* end allocHdwAndChanMem */
654:
655:
656: /* Perform one-time-only channel command program initialization. */
657:
658: void meshSCSIController::initCP()
659: {
660: register DBDMADescriptor *dst = (DBDMADescriptor*)fCCL;
661: register const DBDMADescriptor *src = gDescriptorList;
662: UInt32 i;
663: UInt8 *bp;
664: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
665:
666:
667: ELG( src, dst, 'I CP', "initCP - Init the Channel Program" );
668:
669: /* Set the interrupt, branch, and wait DBDMA registers. */
670: /* Caution: the following MESH interrupt register bits are */
671: /* EndianSwapped, reverse polarity and in a different position. */
672: /* The pattern is: 0xvv00mm00, where mm is a mask byte */
673: /* and vv is a value byte to match. (After EndianSwapping). */
674: /* 0x80 means NO errors (kMeshIntrError) */
675: /* 0x40 means NO exceptions (kMeshIntrException) */
676: /* 0x20 means NO command done (kMeshIntrCmdDone) */
677: /* Branch Select is used with BRANCH_FALSE */
678:
679: // DBDMASetInterruptSelect( 0x00000000 ); /* Never let DBDMA interrupt */
680: // DBDMASetWaitSelect( 0x00200020 ); /* Wait until command done */
681: // DBDMASetBranchSelect( 0x00C000C0 ); /* Branch if exception or error */
682:
683: DBDMARegs->interruptSelect = 0x00000000; /* Never let DBDMA interrupt */
684: DBDMARegs->waitSelect = 0x20002000; /* Wait until command done */
685: DBDMARegs->branchSelect = 0xC000C000; /* Br if Exc or Err */
686: SynchronizeIO();
687:
688: /* Relocate and EndianSwap the global channel command list */
689: /* into the page that is shared with the DBDMA device. */
690:
691: for ( i = 0; i < gDescriptorListSize; i += sizeof( DBDMADescriptor ) )
692: {
693: dst->operation = SWAP( src->operation ); /* copy command with count */
694:
695: switch ( src->result & kRelAddress )
696: {
697: case kRelAddressMESH:
698: dst->address = SWAP( src->address + fMESHPhysAddr );
699: break;
700: case kRelAddressCP:
701: dst->address = SWAP( src->address + (UInt32)fCCLPhysAddr );
702: break;
703: case kRelAddressPhys:
704: dst->address = SWAP( src->address );
705: break;
706: default:
707: dst->address = SWAP( src->address );
708: break;
709: }
710:
711: switch ( src->result & kRelCmdDep )
712: {
713: case kRelCmdDepCP:
714: dst->cmdDep = SWAP( src->cmdDep + (UInt32)fCCLPhysAddr );
715: break;
716: case kRelCmdDepLabel:
717: dst->cmdDep = src->cmdDep;
718: break;
719: default:
720: dst->cmdDep = SWAP( src->cmdDep );
721: break;
722: }
723:
724: dst->result = 0;
725: src++;
726: dst++;
727: } /* FOR all elements in the descriptor list */
728:
729: /* Build a SCSI CDB for the autosense Request Sense command. */
730:
731: bp = &fCCL[ kcclSenseCDB ];
732: *bp++ = kSCSICmdRequestSense; /* Command */
733: *bp++ = 0; /* LUN to be filled in */
734: *bp++ = 0; /* reserved */
735: *bp++ = 0; /* reserved */
736: *bp++ = kMaxAutosenseByteCount; /* Allocation length - to be filled in */
737: *bp++ = 0; /* Control (flag) */
738: return;
739: }/* end initCP */
740:
741:
742: /* doHBASelfTest - MESH chip self-test. (Minimal: it could be extended.) */
743:
744: IOReturn meshSCSIController::doHBASelfTest()
745: {
746: IOReturn ioReturn = kIOReturnSuccess;
747: UInt8 tempByte;
748:
749:
750: ELG( fMESHPhysAddr, fMESHAddr, 'Test', "doHBASelfTest" );
751:
752: if ( ioReturn == kIOReturnSuccess )
753: {
754: tempByte = fMESHAddr->MESHID & 0x1F;
755: if ( tempByte < kMeshMESHID_Value )
756: {
757: PAUSE( 0, tempByte, 'hba-', "doHBASelfTest - Invalid MESH chip ID .\n" );
758: ioReturn = kIOReturnNoDevice;
759: }
760: }
761: return ioReturn;
762: }/* end doHBASelfTest */
763:
764:
765: void meshSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount )
766: {
767: // DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
768:
769:
770: // ELG( ies, intCount, 'Int+', "interruptOccurred" );
771: g.intLevel |= kLevelISR; /* set ISR flag */
772: g.intLevel &= ~kLevelLatched; /* clear latched */
773: // ELG( DBDMARegs->channelStatus, DBDMARegs->commandPtrLo, 'Int+', "interruptOccurred." );
774: ELG( fCmd, *(UInt32*)&fCCL[ kcclStageLabel ], 'Int+', "interruptOccurred." );
775: // ELG( *(UInt32*)0xF3000024, *(UInt32*)0xF300002C, 'Int ', "interruptOccurred." );
776:
777: doHardwareInterrupt(); /**** HANDLE THE INTERRUPT ****/
778:
779: // ELG( fCmd, *(UInt32*)0xF300002C, 'Intx', "interruptOccurred." );
780:
781: g.intLevel &= ~kLevelISR; /* clear ISR flag */
782: return;
783: }/* end interruptOccurred */
784:
785:
786: /* doHardwareInterrupt - called from Workloop in superclass */
787:
788: void meshSCSIController::doHardwareInterrupt()
789: {
790: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
791:
792:
793: getHBARegsAndClear( true ); /* get the MESH registers */
794: setIntMask( 0 ); /* Disable MESH interrupts */
795:
796: fFlagReselecting = false;
797:
798: if ( g.shadow.mesh.interrupt == 0 )
799: { /* Interrupts can occur with no bits set in the */
800: /* interrupt register one way: */
801: /* - Eating interrupts in the driver (the ASIC */
802: /* latches the interrupt even though the */
803: /* driver or Channel Program clears the MESH */
804: /* interrupt register). */
805: PAUSE( DBDMARegs->commandPtrLo,
806: (g.shadow.mesh.busStatus0 << 8) | g.shadow.mesh.busStatus1,
807: 'ISR?',
808: "doHardwareInterrupt - spurious interrupt" );
809:
810: if ( !fCmd )
811: { /* if no request: */
812: setIntMask( kMeshIntrMask ); /* Enable interrupts */
813: enableCommands(); /* let superclass issue another command */
814: }
815: return;
816: }/* end IF no bit set in interrupt register */
817:
818: /// dbdma_flush( DBDMA_MESH_SCSI ); /* DBDMA may be hung in */
819: /// dbdma_stop( DBDMA_MESH_SCSI ); /* middle of transfer. */
820: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
821: SynchronizeIO();
822: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit
823: SynchronizeIO();
824:
825: // invalidate_cache_v( (vm_offset_t)fCCL, fCCLSize );
826:
827: /* If the DBDMA was running a channel command, handle this */
828: /* (this could be done at a lower priority level). */
829:
830: if ( *(UInt32*)&fCCL[ kcclStageLabel ] )
831: {
832: processInterrupt();
833: return;
834: }
835:
836: /* This was not a DBDMA completion. */
837: /* See if the last MESH operation completed */
838: /* without errors or exceptions. */
839:
840: if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone )
841: {
842: /* This was presumably a Programmed IO completion. */
843:
844: if ( fCmd )
845: { /* The command has not completed yet. */
846: /* We need to wait for a phase stabilizing interrupt. */
847:
848: PAUSE( 0, 0, 'dhi-', "doHardwareInterrupt - MESH interrupt problem: need phase stabilizing wait.\n" );
849: return;
850: }
851: else
852: { /* There is no active command. */
853: /* This is presumably a bus-free completion. */
854: setIntMask( kMeshIntrMask ); /* Re-enable interrupts */
855: enableCommands(); /* let superclass issue another command */
856: return;
857: }
858: }/* end IF CmdDone without Err or Exc */
859:
860: /* None of the above "completion" states occurred. */
861: /* Either a command completed unsuccessfully, or we */
862: /* were reselected. First, check for phase mismatch. */
863: if ( g.shadow.mesh.interrupt == (kMeshIntrCmdDone | kMeshIntrException)
864: && g.shadow.mesh.exception == kMeshExcPhaseMM )
865: {
866: PAUSE( 0, 0, 'DHI-', "doHardwareInterrupt - MESH interrupt problem: phase mismatch interrupt.\n" );
867: }
868: else
869: { /* Handle reselection and all other problems separately. */
870: processInterrupt();
871: }
872: return;
873: }/* end doHardwareInterrupt */
874:
875:
876: /* Respond to a DBDMA channel command completion interrupt */
877: /* or some error or exception condition. */
878:
879: void meshSCSIController::processInterrupt()
880: {
881: UInt32 stage; /* Stage in the Channel Program */
882: UInt32 cclIndex; /* Index of CCL descriptor */
883: UInt32 count; /* transfer count */
884: UInt8 phase; /* Current bus phase */
885: IOReturn rc;
886:
887:
888: /* Get the state of the DBDMA: */
889:
890: stage = *(UInt32*)&fCCL[ kcclStageLabel ];
891: cclIndex = SWAP( ((DBDMAChannelRegisters*)dbdmaAddr)->commandPtrLo ) - (UInt32)fCCLPhysAddr;
892: *(UInt32*)&fCCL[ kcclStageLabel ] = 0;
893:
894: /* Check for SCSI Bus Reset Detected: */
895:
896: if ( g.shadow.mesh.error & kMeshErrSCSIRst )
897: {
898: ELG( fCmd, stage, 'BRst', "Process interrupt with no active request\n" );
899: fCmd = NULL;
900: super::resetOccurred();
901: setIntMask( kMeshIntrMask );
902: enableCommands(); /* let superclass issue another command */
903: return;
904: }
905:
906: if ( fCmd == NULL )
907: {
908: if ( g.shadow.mesh.exception & kMeshExcResel )
909: {
910: handleReselectionInterrupt();
911: return;
912: }
913: /* There is no active request and we are not reselecting. */
914: /* Can get here if Reject/Abort occurs or after a BusFree */
915: /* command is put in the Sequence register and we exit the */
916: /* interrupt. */
917: ELG( 0, 0, 'Int0', "Process interrupt with no active request\n" );
918: setIntMask( kMeshIntrException | kMeshIntrError );
919:
920: enableCommands(); /* let superclass issue another command */
921: return;
922: }/* end IF had no active command */
923:
924: /* There is an active request - switch on stage of the DBDMA: */
925:
926: switch ( stage )
927: {
928: case kcclStageGood: /* Normal completion */
929: doInterruptStageGood();
930: break;
931:
932: case kcclStageInit: /* Value before DBDMA runs */
933: case kcclStageArb: /* Arbitration anomaly */
934: doInterruptStageArb();
935: break;
936:
937: case kcclStageSelA: /* Selection anomaly */
938: doInterruptStageSelA();
939: break;
940:
941: case kcclStageMsgO: /* Message Out */
942: doInterruptStageMsgO();
943: break;
944:
945: case kcclStageCmdO: /* Command stage anomaly */
946: doInterruptStageCmdO();
947: break;
948:
949: case kcclStageXfer:
950: // if ( cmdBuf->resultFlags & scsiAutosenseStarted )
951: // doInterruptStageXferAutosense();
952: // else
953: doInterruptStageXfer(); /* DMA transfer complete */
954: break;
955:
956: case kcclStageStat: /* Synchronous, odd transfer, data-out */
957: /* OR no data, disconnect */
958:
959: /* Don't use updateCurrentIndex here because */
960: /* kcclStageStat destroys TC with a 1. */
961: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */
962: fCmdData->results.bytesTransferred += count; /* Increment data index */
963:
964: if ( fReadAlignmentCount ) // Hack for Radar 1670626
965: {
966: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount );
967: fReadAlignmentCount = 0;
968: }
969:
970: ELG( count, fCmdData->results.bytesTransferred, 'Uidx', "processInterrupt" );
971: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear our count */
972:
973: /* Analyze the current bus signals: */
974:
975: if ( !(g.shadow.mesh.busStatus0 & kMeshReq) )
976: { /* Get here if Sync Read or Write is too short as */
977: /* in reading 512 bytes from a 2K block of CD-ROM. */
978: startBucket();
979: return;
980: }/* end IF no REQ signal */
981:
982: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
983: switch ( phase )
984: {
985: case kBusPhaseMSGI:
986: rc = DoMessageInPhase();
987: break;
988:
989: case kBusPhaseDATO:
990: case kBusPhaseDATI:
991: /* Get here if Async Read or Write is too short as */
992: /* in reading 512 bytes from a 2K block of CD-ROM */
993: startBucket();
994: break;
995:
996: default:
997: PAUSE( 0, phase, 'pmm-', "processInterrupt - expected Status phase.\n" );
998: break;
999: }/* end SWITCH on phase */
1000: break;
1001:
1002: case kcclStageBucket:
1003: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */
1004: fCmdData->results.bytesTransferred += count; /* Increment data index */
1005: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear our count */
1006:
1007: ELG( count, fCmdData->results.bytesTransferred, 'Buck',
1008: "processInterrupt - bit bucket done.\n" );
1009:
1010: /* MESH doesn't always have a phase mismatch when completing a */
1011: /* synchronous data write. It may be that the drive is going to */
1012: /* MsgIn with SDP and/or disconnect instead of Status and the */
1013: /* timing is different. If the current phase is not a data phase, */
1014: /* AND the TC and FIFO count indicate no data overflowed AND */
1015: /* and all the data transferred, don't set an error condition. */
1016:
1017: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
1018:
1019: count = g.shadow.mesh.transferCount1 << 8 | g.shadow.mesh.transferCount0;
1020: count += g.shadow.mesh.FIFOCount;
1021: count &= 0xFFFF;
1022:
1023: if ( (count != 0)
1024: || (fCmdData->xferCount != fCmdData->results.bytesTransferred)
1025: || !(phase > kBusPhaseDATI) )
1026: {
1027: fCmdData->results.returnCode = kIOReturnOverrun;
1028: }
1029: setSeqReg( kMeshFlushFIFO ); /* flush the FIFO */
1030: runDBDMA( kcclGetStatus, kcclStageStat );
1031: break;
1032:
1033: case kcclStageMsgI: /* Message-in: */
1034: case kcclStageFree: /* Bus free: */
1035: default: /* Can't happen? */
1036: PAUSE( cclIndex, stage, 'P i-', "processInterrupt - strange or unknown interrupt for device.\n" );
1037: break;
1038: }/* end SWITCH on Channel Program stage */
1039:
1040: return;
1041: }/* end processInterrupt */
1042:
1043:
1044: /* Start a SCSI transaction for the specified command. */
1045:
1046: UInt8 meshSCSIController::startCommand()
1047: {
1048: fCmd->getPointers( &fCmdData->mdp, &fCmdData->xferCount, &fCmdData->isWrite );
1049:
1050: clearCPResults(); /* clear the result field in all the Channel Commands */
1051:
1052: {
1053: fCmdData->results.bytesTransferred = 0;
1054: fCmdData->savedDataPosition = 0;
1055: updateCP( false ); /* Update the DBDMA Channel Program */
1056: }
1057:
1058: /***** Can a caller override the default timeout? *****/
1059:
1060: fMESHAddr->selectionTimeOut = fSelectionTimeout;
1061: fMESHAddr->destinationID = fCurrentTargetLun.target;
1062: // fMESHAddr->syncParms = kSyncParmsAsync;
1063: fMESHAddr->syncParms = fSyncParms[ fCurrentTargetLun.target ];
1064: SynchronizeIO();
1065: runDBDMA( kcclStart, kcclStageInit );
1066: if ( g.intLevel & kLevelLatched ) /* return Busy if reselecting */
1067: return kHardwareStartBusy; /* or some other issue. */
1068: return kHardwareStartOK;
1069: }/* end startCommand */
1070:
1071:
1072: /* Initialize the data transfer channel command list for a normal SCSI */
1073: /* command. The channel command list has a complex structure of */
1074: /* transfer groups and items, where: */
1075: /* transfer group The number of bytes transferred by a single */
1076: /* MESH operation. This will be from 1 to */
1077: /* kMaxDMATransfer (65536 - 4096). */
1078: /* transfer item The number of bytes transferred by a single */
1079: /* DBDMA operation. These bytes are guaranteed */
1080: /* to be physically-contiguous. */
1081: /* Thus, the data transfer CCL looks like the following: */
1082: /* Prolog 1: Load MESH with the first group count. */
1083: /* Item 1.1: Load DBDMA with the first physical address and */
1084: /* item count. */
1085: /* Item 1.2 etc: Load DBDMA with the next physical address and */
1086: /* item count. */
1087: /* Prolog 2, etc. Load MESH with the next group count. */
1088: /* Item 2.1, etc. Load DBDMA with the next group of physical */
1089: /* addresses. */
1090: /* Stop/Branch If all of the data transfer commands fit in the */
1091: /* channel command list, branch to the Status phase*/
1092: /* channel command. Otherwise, stop transfer */
1093: /* (which stops in Data phase) and rebuild the */
1094: /* command list for the next set of data. */
1095: /* Note that the last DBDMA command must be INPUT_LAST or OUTPUT_LAST */
1096: /* to handle synchronous transfer odd-byte disconnect. */
1097:
1098: void meshSCSIController::updateCP( bool reselecting )
1099: {
1100: DBDMADescriptor *descProto = (DBDMADescriptor*)&fCCL[ kcclPrototype ];
1101: DBDMADescriptor *descriptorPtr; /* current data descriptor */
1102: DBDMADescriptor *descriptorMax; /* beyond the last data descriptor */
1103: DBDMADescriptor *preamblePtr; /* current prolog descriptor */
1104: SCSICDBInfo scsiCDB;
1105: UInt32 dbdmaOpProto; /* prototype Opcode for DBDMA */
1106: UInt32 dbdmaOp; /* Opcode for DBDMA */
1107: UInt32 meshSeq; /* Opcode for MESH request */
1108: SInt32 transferLength; /* Number of bytes left to transfer */
1109: UInt32 totalXferLen = 0; /* Total length of this transfer */
1110: UInt32 groupLength; /* Number of bytes in this group */
1111: UInt8 syncParms; /* Fast synchronous param value */
1112: UInt32 actualRanges;
1113: IOPhysicalSegment range[ kMaxMemCursorSegs ];
1114: DBDMADescriptor *dp;
1115: UInt32 rangeLength, rangeLocation;
1116: UInt32 i;
1117: IOReturn ioReturn = kIOReturnSuccess;
1118:
1119:
1120: fReadAlignmentCount = 0; /* Clear Read misalignment condition */
1121:
1122: /* How many descriptors can we store (need some slop for the */
1123: /* terminator commands). Get a pointer to the first free */
1124: /* descriptor and the total number of bytes left to transfer in */
1125: /* this IO request. */
1126:
1127: descriptorPtr = (DBDMADescriptor*)&fCCL[ kcclDataXfer ];
1128: descriptorMax = &descriptorPtr[ fDBDMADescriptorMax - 16 ];
1129: transferLength = fCmdData->xferCount - fCmdData->results.bytesTransferred;
1130: ELG( descriptorPtr, transferLength, 'UpCP', "updateCP" );
1131:
1132: if ( !reselecting )
1133: {
1134: setupMsgO(); /* Setup for Message Out phase. */
1135: fCmd->getCDB( &scsiCDB );
1136:
1137: /* Setup for Command phase: */
1138: fCCL[ kcclCmdoMTC ] = scsiCDB.cdbLength; /* MESH transfer count */
1139: fCCL[ kcclCmdoDTC ] = scsiCDB.cdbLength; /* DBDMA count */
1140: bcopy( &scsiCDB.cdb[0], &fCCL[ kcclCMDOdata ], scsiCDB.cdbLength );
1141: }/* end IF not reselecting */
1142:
1143: /* Generate MESH "sequence" & DBDMA "operation" for Input or Output: */
1144:
1145: if ( fCmdData->isWrite )
1146: { dbdmaOpProto = OUTPUT_MORE | kBranchIfFalse;
1147: meshSeq = kMeshDataOutCmd | kMeshSeqDMA;
1148: }
1149: else
1150: { dbdmaOpProto = INPUT_MORE | kBranchIfFalse;
1151: meshSeq = kMeshDataInCmd | kMeshSeqDMA;
1152: }
1153:
1154: *(UInt32*)&fCCL[ kcclBatchSize ] = 0;
1155:
1156: while ( ioReturn == kIOReturnSuccess
1157: && transferLength > 0
1158: && descriptorPtr < descriptorMax )
1159: {
1160: /* Do one group, ie, enough CCs to fill a MESH transfer count. */
1161: /* There are more data to be transferred, and CCL space to store*/
1162: /* another group of data. First, leave space for the preamble. */
1163:
1164: preamblePtr = descriptorPtr;
1165: groupLength = 0;
1166: descriptorPtr += 4; /* Preamble takes 4 descriptors */
1167:
1168: /* Do one group of pages: */
1169:
1170: actualRanges = fMemoryCursor->getPhysicalSegments(
1171: fCmdData->mdp,
1172: fCmdData->results.bytesTransferred + totalXferLen,
1173: range,
1174: kMaxMemCursorSegs );
1175: if ( actualRanges == 0 )
1176: break;
1177:
1178: ELG( range[0].length, range[0].location, 'Rng1', "updateCP - 1st range" );
1179:
1180: for ( i = 0; i < actualRanges; i++ )
1181: { rangeLocation = range[i].location;
1182: rangeLength = range[i].length;
1183: groupLength += rangeLength;
1184:
1185: // 29apr99 mlj Radar 1670626 - the DBDMAs in Grand Central (and
1186: // either Heathrow or O'Hare) have a bug. On the initial
1187: // data xfer of a Read, if the buffer is not aligned on an
1188: // 8-byte boundary, and the transfer ends before the boundary is
1189: // reached, then the memory in front of the buffer is trashed.
1190: // If these conditions apply, we read the misaligned bytes
1191: // into the CCL at kcclReadBuf8 now and copy them to the
1192: // user buffer later when we get an interrupt. The 1st range
1193: // is split and 2 DBDMA Channel Commands are generated.
1194:
1195: if ( (i == 0) // 1st range of group
1196: && (totalXferLen == 0) // 1st group of batch
1197: && (!fCmdData->isWrite) // READing
1198: && (rangeLocation & 0x07) ) // not 8-byte aligned
1199: {
1200: ELG( rangeLength, rangeLocation, 'Rd-8', "updateCP - non-8-byte-aligned read" );
1201: fReadAlignmentIndex = fCmdData->results.bytesTransferred;
1202: fReadAlignmentCount = 8 - (rangeLocation & 0x07);
1203: dbdmaOp = dbdmaOpProto | fReadAlignmentCount;
1204: rangeLength -= fReadAlignmentCount;
1205: transferLength -= fReadAlignmentCount;
1206: if ( transferLength <= 0 )
1207: dbdmaOp |= (INPUT_MORE ^ INPUT_LAST); /* add LAST to cmd */
1208:
1209: descriptorPtr->operation = SWAP( dbdmaOp );
1210: descriptorPtr->address = SWAP( (UInt32)fCCLPhysAddr + kcclReadBuf8 );
1211: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem );
1212: descriptorPtr->result = 0; // for debugging
1213:
1214: descriptorPtr++;
1215:
1216: if ( rangeLength == 0 )
1217: continue;
1218: rangeLocation += fReadAlignmentCount;
1219: }/* end IF READing and buffer is misaligned at batch start */
1220:
1221: dbdmaOp = dbdmaOpProto | rangeLength;
1222: transferLength -= rangeLength;
1223: if ( transferLength <= 0 )
1224: dbdmaOp |= (INPUT_MORE ^ INPUT_LAST); /* add LAST to cmd */
1225:
1226: descriptorPtr->operation = SWAP( dbdmaOp );
1227: descriptorPtr->address = SWAP( rangeLocation );
1228: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem );
1229: descriptorPtr->result = 0; // for debugging
1230:
1231: descriptorPtr++;
1232: }/* end FOR each range in this group */
1233:
1234: if ( groupLength == 0 )
1235: {
1236: /* Nothing was built - we apparently failed to get */
1237: /* a physical address. Note: there is a potential problem with */
1238: /* the following sequence as the *previous* DBDMA command, if */
1239: /* any, should be changed to set xxPUT_LAST. */
1240:
1241: ELG( 0, 0, 'Grp-', "updateCP - groupLength is 0" );
1242: preamblePtr->operation = SWAP( NOP_CMD | kBranchIfFalse | kWaitIfTrue );
1243: preamblePtr->address = 0;
1244: preamblePtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem );
1245: preamblePtr->result = 0;
1246: descriptorPtr = preamblePtr + 1;
1247: ioReturn = kIOReturnInvalid; /* Exit the outer loop */
1248: }
1249: else
1250: {
1251: totalXferLen += groupLength;
1252:
1253: /* This group is complete. Fill in the preamble. */
1254: /* The preamble consists of the following commands: */
1255: /* [0] Move <totalXferLen> to kcclBatchSize */
1256: /* [1] Store group length high-byte in MESH */
1257: /* transfer count 1 register */
1258: /* [2] Store group length low-byte in MESH */
1259: /* transfer count 1 register */
1260: /* [3] Store the input/output command in the MESH */
1261: /* sequence register. */
1262: /* If the command finishes prematurely (perhaps the */
1263: /* device wants to disconnect), the interrupt service */
1264: /* routine will use totalXferLen - the residual byte */
1265: /* count to determine the number of bytes xferred. */
1266:
1267: descProto[0].cmdDep = totalXferLen; // update batch size
1268: descProto[1].cmdDep = SWAP( groupLength >> 8 );
1269: descProto[2].cmdDep = SWAP( groupLength & 0xFF );
1270: descProto[3].cmdDep = SWAP( meshSeq );
1271: bcopy( descProto, preamblePtr, sizeof( DBDMADescriptor ) * 4 );
1272: ELG( preamblePtr, totalXferLen, '=Tot', "updateCP - set preamble" );
1273:
1274: /* If there is another group, wait for */
1275: /* cmdDone and clear it: */
1276: if ( transferLength > 0 )
1277: { /* Wait for CmdDone: */
1278: bcopy( &fCCL[ kcclBrProblem ], descriptorPtr, sizeof( DBDMADescriptor ) );
1279: ++descriptorPtr;
1280: /* Clear CmdDone: */
1281: /* HACK - if we reached the end of the CCL page, */
1282: /* we don't want to clear cmdDone because we will lose */
1283: /* an interrupt. So, this instruction may be deleted */
1284: /* down below. (Radar 2298440) */
1285: descriptorPtr->operation = SWAP( STORE_QUAD | KEY_SYSTEM | 1 );
1286: descriptorPtr->address = SWAP( fMESHPhysAddr + kMeshInterrupt );
1287: descriptorPtr->cmdDep = SWAP( kMeshIntrCmdDone );
1288: descriptorPtr->result = 0;
1289: ++descriptorPtr;
1290: }/* end IF not last group */
1291: }/* end if/ELSE a group was built */
1292: }/* end outer WHILE */
1293:
1294: /* All of the data have been transferred (or we ran off the end */
1295: /* of the CCL). Update the transfer start index to reflect on */
1296: /* what we attempt to transfer in this DATA operation. If */
1297: /* we completed DATA phase, branch to the Status Phase CCL; */
1298: /* if not, stop the channel command so we can reload the CCL */
1299: /* with the next big chunk. */
1300: /* When the transfer completes, the last prolog will have stored*/
1301: /* the total number of bytes transferred in a known location in */
1302: /* the CCL area. */
1303: /* Now, append the data transfer postamble to handle */
1304: /* synchronous odd-byte disconnect and jump to status phase */
1305: /* (or just stop if there's more DMA) */
1306:
1307:
1308: /* Do some synchronous data transfer cleanup: */
1309:
1310: syncParms = fSyncParms[ fCurrentTargetLun.target ];
1311: fMESHAddr->syncParms = syncParms;
1312: SynchronizeIO();
1313: ELG( fMsgOutFlag, syncParms, 'SynP', "updateCP - sync parms" );
1314:
1315: if ( ((syncParms & 0xF0) || (fMsgOutFlag & kFlagMsgOut_SDTR)) // Sync?
1316: && (totalXferLen > 0) // any data moving?
1317: && (transferLength == 0) ) // end of xfer?
1318: {
1319: fFlagIncompleteDBDMA = false; /* indicate complete xfer */
1320:
1321: /* MESH has a problem at the end of Synchronous transfers. */
1322: /* If the target is fast enough, it can move from data phase to */
1323: /* Status phase while MESH still has ACKed bytes in its FIFO and */
1324: /* the DBDMA is still running. MESH raises PhaseMismatch Exception */
1325: /* causing an interrupt in which we must empty the FIFO and move */
1326: /* the bytes to the user's buffer by programmed IO. */
1327: /* If the target is not fast enough, we can save the interrupt and */
1328: /* bypass the mess. */
1329: /* So, we do the following: */
1330: /* 1) Enable only MESH Err interrupts; disable Exc and CmdDone. */
1331: /* 2) Don't Wait; Branch if an interrupt may have already occurred.*/
1332: /* 3) Wait for cmdDone at least for TC = FIFO count = 0 and */
1333: /* maybe including PhaseMismatch. Branch to SyncCleanup if PMM. */
1334: /* 4) Assume an interphase condition as opposed to an */
1335: /* overrun condition and Branch Always to get Status. */
1336:
1337: /* If the Channel Program gets this far, the OUTPUT_LAST */
1338: /* has finished writing its data to the FIFO and MESH may still */
1339: /* be putting bytes on the bus OR the INPUT_LAST has read all */
1340: /* its data from the FIFO and MESH has already ACKed them. */
1341: /* There may be or not some time before REQ appears again, */
1342: /* either for data overrun or the next phase. */
1343:
1344: /* Disable Exc and CmdDone (leave Err enabled): */
1345:
1346: descriptorPtr->operation = SWAP( STORE_QUAD | KEY_SYSTEM | 1 );
1347: descriptorPtr->address = SWAP( fMESHPhysAddr + kMeshInterruptMask );
1348: descriptorPtr->cmdDep = SWAP( kMeshIntrError );
1349: descriptorPtr->result = 0;
1350: ++descriptorPtr;
1351:
1352: /* Take the interrupt if PhaseMismatch not definitely caught. */
1353: /* Branch (don't wait for cmdDone) if Exc may have already occurred: */
1354:
1355: descriptorPtr->operation = SWAP( NOP_CMD | kBranchIfFalse );
1356: descriptorPtr->address = 0;
1357: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclProblem );
1358: descriptorPtr->result = 0;
1359: /* Radar 2281306 ( and 2272931 ): */
1360: /* Output may completely fit in the FIFO and not make it out */
1361: /* to the SCSI bus if the target disconnects after the command. */
1362: /* If that's possible, wait here for cmdDone and */
1363: /* take the PhaseMismatch interrupt. This situation occurred on a */
1364: /* Mode Select with an output of 12 bytes. Do this to prevent */
1365: /* the Stage from advancing from kcclStageXfer so that proper */
1366: /* cleanup can take place. */
1367: if ( (totalXferLen <= 16) && fCmdData->isWrite )
1368: {
1369: descriptorPtr->operation = SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse );
1370: }
1371: ++descriptorPtr;
1372:
1373: /* Possible PhaseMisMatch caught after FIFO emptied. */
1374: /* Wait for cmdDone. If Exc, branch to SyncCleanUp: */
1375:
1376: descriptorPtr->operation = SWAP( NOP_CMD | kWaitIfTrue | kBranchIfFalse );
1377: descriptorPtr->address = 0;
1378: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclSyncCleanUp );
1379: descriptorPtr->result = 0;
1380: descriptorPtr++;
1381:
1382: /* Interphase condition or possible overrun. */
1383: /* 29sep98 PhaseMismatch occurred even after */
1384: /* CmdDone was set. */
1385:
1386:
1387: /* Branch Always to assume we will bit bucket some data: */
1388:
1389: descriptorPtr->operation = SWAP( NOP_CMD | kBranchAlways );
1390: descriptorPtr->address = 0;
1391: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclOverrun );
1392: descriptorPtr->result = 0;
1393: descriptorPtr++;
1394:
1395: /* Fix up the DataOverrun code just in case: */
1396:
1397: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunMESH ];
1398: if ( fCmdData->isWrite )
1399: { dp->cmdDep = SWAP( kMeshDataOutCmd | kMeshSeqDMA );
1400: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ];
1401: dp->operation = SWAP( OUTPUT_LAST | kBranchIfFalse | 8 );
1402: }
1403: else
1404: { dp->cmdDep = SWAP( kMeshDataInCmd | kMeshSeqDMA );
1405: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ];
1406: dp->operation = SWAP( INPUT_LAST | kBranchIfFalse | 8 );
1407: }
1408: }/* end IF last of Synchronous transfer */
1409: else
1410: {
1411: /* Async or incomplete Sync. Append Branches to finish this process: */
1412:
1413: /* If this is a partial transfer, set 'incomplete' flag. */
1414:
1415: if ( transferLength > 0 )
1416: fFlagIncompleteDBDMA = true; /* set incomplete */
1417: else fFlagIncompleteDBDMA = false; /* assume complete xfer */
1418:
1419:
1420: if ( fFlagIncompleteDBDMA )
1421: { /* Delete the ccl to clear cmdDone: */
1422: --descriptorPtr; /* see HACK note above. */
1423: }
1424: else if ( totalXferLen > 0 )
1425: { /* If something moved AND (Radar 2298440) xfer completed, */
1426: /* Wait & Branch if problem: */
1427: /* Radar 2272931 - If entire output fits in FIFO, then */
1428: /* the OUTPUT_LAST completes OK without a PhaseMismatch if */
1429: /* the target disconnects right after the command phase. */
1430: bcopy( &fCCL[ kcclBrProblem ], descriptorPtr, sizeof( DBDMADescriptor ) );
1431: descriptorPtr++;
1432: }
1433: /* Assume all's well - Branch to get status: */
1434: descriptorPtr->operation = SWAP( NOP_CMD | kBranchAlways );
1435: descriptorPtr->address = 0;
1436: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclGetStatus );
1437: descriptorPtr->result = 0;
1438:
1439: /* If this is a partial transfer, set 'incomplete' flag and */
1440: /* change the Branch from GetStatus to Good: */
1441:
1442: if ( fFlagIncompleteDBDMA )
1443: { /* change last Branch from Status to Good: */
1444: descriptorPtr->cmdDep = SWAP( (UInt32)fCCLPhysAddr + kcclMESHintr );
1445: ELG( descriptorPtr, transferLength, 'Part', "updateCP - built partial CCL." );
1446: }
1447: descriptorPtr++;
1448: }/* end if/ELSE Async or partial xfer */
1449: return;
1450: }/* end updateCP */
1451:
1452:
1453: void meshSCSIController::clearCPResults()
1454: {
1455: register DBDMADescriptor *dp = (DBDMADescriptor*)&fCCL[ kcclStart ];
1456: register int i;
1457:
1458:
1459: /* Don't clear the reserved areas or prototypes */
1460:
1461: for ( i = (gDescriptorListSize - kcclStart) / sizeof ( DBDMADescriptor ); i; --i )
1462: {
1463: dp->result = 0;
1464: dp++;
1465: }
1466:
1467: return;
1468: }/* end clearCPResults */
1469:
1470:
1471: /* Set up the channel commands for MsgO phase. */
1472:
1473: void meshSCSIController::setupMsgO()
1474: {
1475: UInt8 msgoSize;
1476:
1477:
1478: fMsgOutPtr--; /* treat the last or only byte special (drop ATN) */
1479: msgoSize = fMsgOutPtr - &fCCL[ kcclMSGOdata ];
1480: if( msgoSize == 0 )
1481: { /* Identify byte only: */
1482: *(UInt32*)&fCCL[ kcclMsgoBranch ] = SWAP( NOP_CMD | kBranchAlways );
1483: }
1484: else /* multibyte message - set counts for all but last byte: */
1485: { fCCL[ kcclMsgoMTC ] = msgoSize;
1486: fCCL[ kcclMsgoDTC ] = msgoSize;
1487: /* NOP the BRANCH: */
1488: *(UInt32*)&fCCL[ kcclMsgoBranch ] = SWAP( NOP_CMD );
1489: }
1490: fCCL[ kcclMSGOLast ] = *fMsgOutPtr; /* position last byte */
1491: return;
1492: }/* end setupMsgO */
1493:
1494:
1495: /* Start a Channel Program at the given offset */
1496: /* with the specified stage label. */
1497:
1498: void meshSCSIController::runDBDMA( UInt32 offset, UInt32 stageLabel )
1499: {
1500: register UInt8 intReg;
1501: mach_timespec_t arbEndTime, curTime;
1502: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
1503:
1504:
1505: fMsgInFlag = 0; /* clear message-in flags. */
1506:
1507: *(UInt32*)&fCCL[ kcclStageLabel ] = stageLabel; /* set the stage */
1508:
1509: /* Let MESH interrupt only for errors or exceptions, but not cmdDone */
1510: setIntMask( kMeshIntrException | kMeshIntrError );
1511:
1512: intReg = fMESHAddr->interrupt;
1513: switch ( intReg )
1514: {
1515: case kMeshIntrCmdDone:
1516: if ( !fFlagReselecting ) // ??? Don't drop ACK fm MSG-IN or Sync data flows
1517: /* clear any pending command interrupts (but not reselect et al) */
1518: fMESHAddr->interrupt = kMeshIntrCmdDone; SynchronizeIO();
1519: /***** fall through *****/
1520: case 0:
1521: /* This is a Go: */
1522: /* Flush any CCL and related data to the CCL physical page */
1523: /* that may still be sitting in cache: */
1524: flush_dcache( (vm_offset_t)fCCL, fCCLSize, false );
1525:
1526: // ELG( *(UInt32*)0xF3000020, *(UInt32*)0xF300002C, 'G C+', "runDBDMA." );
1527:
1528: if ( offset == kcclStart )
1529: {
1530: fFlagReselecting = false;
1531: setSeqReg( kMeshArbitrateCmd ); /* ARBITRATE */
1532:
1533: /* wait 50 mikes or cmdDone, whichever comes first: */
1534:
1535: IOGetTime( &arbEndTime );
1536: arbEndTime.tv_nsec += 50000;
1537: if ( arbEndTime.tv_nsec >= NSEC_PER_SEC )
1538: { arbEndTime.tv_nsec -= NSEC_PER_SEC;
1539: arbEndTime.tv_sec += 1;
1540: }
1541:
1542: while ( true )
1543: {
1544: getHBARegsAndClear( false ); /* get regs without hosing */
1545: IOGetTime( &curTime );
1546: if ( g.shadow.mesh.interrupt & kMeshIntrCmdDone )
1547: break;
1548: if ( curTime.tv_sec < arbEndTime.tv_sec ) continue;
1549: if ( curTime.tv_nsec >= arbEndTime.tv_nsec ) break;
1550: }/* end wait cmdDone or 50 mikes */
1551:
1552: if ( g.shadow.mesh.interrupt == kMeshIntrCmdDone )
1553: { /* No err, no exc: Arbitration won: */
1554: fMESHAddr->interrupt = kMeshIntrCmdDone;
1555: SynchronizeIO();
1556: setSeqReg( kMeshDisableReselect ); /* disable reselect */
1557: offset = 0x150; // ??? fix this. Point to Select/Atn
1558: *(UInt32*)&fCCL[ kcclStageLabel ] = kcclStageSelA; /* set stage to Select */
1559: }/* end IF won Arbitration */
1560: else /* Arbitration not won - CAUTION - HACK AHEAD. */
1561: { /* Sometimes, MESH does not return ArbLost as it says in */
1562: /* the documentation. Instead, it waits for the winner to */
1563: /* get off the bus (usually after the 250 ms timeout) and */
1564: /* then MESH continues its arbitration. This wastes 250 ms */
1565: /* of valuable bus time. Further, IOmega's Zip drive has a */
1566: /* nasty bug whereby if its reselection is snubbed and it */
1567: /* times out, it leaves the I/O signal asserted on the bus */
1568: /* even as other activity on the bus unrelated to the Zip */
1569: /* is ongoing. */
1570: /* We don't need to hack if ArbLost is indicated correctly */
1571: /* or Reselect is indicated. If either is true, don't bother*/
1572: /* starting the DBDMA; rather, let the interrupt already */
1573: /* latched handle the situation. */
1574:
1575: if ( !(g.shadow.mesh.exception & (kMeshExcArbLost | kMeshExcResel)) )
1576: {
1577: ELG( '****', '****', 'HACK', "runDBDMA - Arbitrate HACK." );
1578: // ??? check FIFO count for presence of Target ID ???
1579: setSeqReg( kMeshResetMESH ); /* hack it: whack it */
1580: getHBARegsAndClear( true ); /* get regs/clear */
1581: setSeqReg( kMeshEnableReselect ); /* Let reselect again */
1582: getHBARegsAndClear( false ); /* get regs/preserve */
1583: if ( g.shadow.mesh.interrupt == 0 )
1584: PAUSE( 0, 0, 'Arb*', "runDBDMA - Arbitrate/Reselect problem." );
1585: }
1586: if ( g.shadow.mesh.interrupt ) /* If Err or Exc set, */
1587: break; /* break SWITCH - Don't start the DBDMA. */
1588: }/* end ELSE lost Arbitration */
1589: }/* end IF DBDMA to start at Arbitrate */
1590:
1591: getHBARegsAndClear( false ); // ??? debug: see if ACK still set
1592: ELG( 0, offset<<16 | stageLabel, 'DMA+', "runDBDMA" );
1593: /// dbdma_start( DBDMA_MESH_SCSI, (dbdma_command_t*)((UInt32)fCCLPhysAddr + offset) );
1594: DBDMARegs->commandPtrLo = SWAP( (UInt32)fCCLPhysAddr + offset );
1595: SynchronizeIO();
1596: DBDMARegs->channelControl = SWAP( 0x80008000 ); // set RUN bit
1597: SynchronizeIO();
1598: return;
1599: }/* end SWITCH on interrupt register */
1600:
1601:
1602: ELG( 0, intReg, 'Pnd-', "runDBDMA - interrupt probably pending (reselect?)." );
1603: getHBARegsAndClear( false ); /* display regs without clearing */
1604: *(UInt32*)&fCCL[ kcclStageLabel ] = kcclStageIdle; /* set stage to none */
1605: g.intLevel |= kLevelLatched; /* set latched-interrupt flag. */
1606: setIntMask( kMeshIntrMask ); /* make sure MESH interrupts enabled */
1607: return;
1608: }/* end runDBDMA */
1609:
1610:
1611: void meshSCSIController::completeCommand()
1612: {
1613: ELG( fCmdData->results.bytesTransferred, fCmdData->results.scsiStatus, ' IOC', "meshSCSIController::completeCommand" );
1614:
1615: {
1616: switch ( fCmdData->results.scsiStatus )
1617: {
1618: case kSCSIStatusGood:
1619: if ( fCmdData->results.bytesTransferred != fCmdData->xferCount
1620: && fCmdData->results.returnCode == kIOReturnSuccess )
1621: {
1622: fCmdData->results.returnCode = kIOReturnUnderrun;
1623: }
1624: break;
1625:
1626: case kSCSIStatusCheckCondition:
1627:
1628: ELG( 0, 0, 'Chek', "meshSCSIController::completeCommand - Check Condition" );
1629: fCmdData->results.returnCode = kIOReturnError;
1630: break;
1631:
1632: case kSCSIStatusQueueFull:
1633: default:
1634: ELG( fCmd, fCmdData->results.scsiStatus, 'Sta?', "meshSCSIController::completeCommand - bad status" );
1635: fCmdData->results.returnCode = kIOReturnError;
1636: break;
1637: }/* end SWITCH on SCSI status */
1638: }/* end IF not autosense */
1639:
1640: fCmd->setResults( &fCmdData->results );
1641: fCmd->complete();
1642:
1643: fCmd = NULL;
1644: fCmdData = NULL;
1645: fCurrentTargetLun.target = kInvalidTarget;
1646: fCurrentTargetLun.lun = kInvalidLUN;
1647: return;
1648: }/* end completeCommand */
1649:
1650:
1651: void meshSCSIController::free()
1652: {
1653: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
1654:
1655:
1656: if ( fMESHAddr )
1657: {
1658: setSeqReg( kMeshResetMESH );
1659: }
1660:
1661: if ( DBDMARegs )
1662: {
1663: // dbdma_stop( DBDMA_MESH_SCSI );
1664: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
1665: SynchronizeIO();
1666: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit
1667: SynchronizeIO();
1668: }
1669:
1670: if ( fInterruptEvent )
1671: {
1672: fInterruptEvent->disable();
1673: fInterruptEvent->release();
1674: fInterruptEvent = 0;
1675: }
1676:
1677: if ( fCCL )
1678: {
1679: IOFreeContiguous( (void*)fCCL, fCCLSize );
1680: fCCL = NULL;
1681: }
1682:
1683: if ( fMemoryCursor )
1684: {
1685: fMemoryCursor->release();
1686: fMemoryCursor = 0;
1687: }
1688:
1689: if ( g.evLogBuf )
1690: {
1691: IOFree( (void*)g.evLogBuf, kEvLogSize );
1692: g.evLogBuf = 0;
1693: }
1694:
1695: super::free();
1696: return;
1697: }/* end free */
1698:
1699:
1700: /* startBucket - Start the channel commands to run the bit bucket. */
1701:
1702: void meshSCSIController::startBucket()
1703: {
1704: DBDMADescriptor *dp; /* current data descriptor */
1705: UInt32 dbdmaOp; /* Opcode for DBDMA */
1706: UInt32 meshSeq; /* Opcode for MESH request */
1707:
1708:
1709: ELG( fCmd, fCmdData, 'Bkt-', "startBucket" );
1710:
1711: /* Generate MESH "sequence" & DBDMA "operation" for Input or Output: */
1712:
1713: if ( fCmdData->isWrite )
1714: { dbdmaOp = OUTPUT_MORE | kBranchIfFalse | 8;
1715: meshSeq = kMeshDataOutCmd | kMeshSeqDMA;
1716: }
1717: else
1718: { dbdmaOp = INPUT_MORE | kBranchIfFalse | 8;
1719: meshSeq = kMeshDataInCmd | kMeshSeqDMA;
1720: }
1721:
1722: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunMESH ]; dp->cmdDep = meshSeq;
1723: dp = (DBDMADescriptor*)&fCCL[ kcclOverrunDBDMA ]; dp->operation = dbdmaOp;
1724:
1725: runDBDMA( kcclDataXfer, kcclStageBucket );
1726: return;
1727: }/* end startBucket */
1728:
1729:
1730: /* The Channel Program ran to completion without problems. */
1731:
1732: void meshSCSIController::doInterruptStageGood()
1733: {
1734: UInt32 totalXferLen;
1735:
1736:
1737: /* Retrieve the total number of bytes transferred */
1738: /* in the last data phase and reset it: */
1739: totalXferLen = *(UInt32*)&fCCL[ kcclBatchSize ];
1740: *(UInt32*)&fCCL[ kcclBatchSize ] = 0;
1741:
1742: ELG( fCmd, totalXferLen, 'Good', "doInterruptStageGood" );
1743:
1744: /* We are completing a normal command. */
1745: /* Update the transfer count and current data pointer. */
1746:
1747: fCmdData->results.bytesTransferred += totalXferLen;
1748:
1749: if ( fReadAlignmentCount ) // Hack for Radar 1670626
1750: {
1751: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount );
1752: fReadAlignmentCount = 0;
1753: }
1754:
1755: if ( fFlagIncompleteDBDMA == false )
1756: {
1757: /* Yes, the IO is really complete: */
1758:
1759: fCmdData->results.returnCode = kIOReturnSuccess;
1760: fCmdData->results.scsiStatus = fCCL[ kcclStatusData ];
1761: fCmd->setResults( &fCmdData->results );
1762:
1763: completeCommand();
1764: }
1765: else
1766: { /* The CCL ended, but the caller expected more data. */
1767: /* Restart the CCL. */
1768: /* Don't regenerate arbitration or command stuff. */
1769:
1770: updateCP( true );
1771: runDBDMA( kcclDataXfer, kcclStageXfer );
1772: return;
1773: }/* end ELSE need to continue Channel Program */
1774:
1775: /* Since IO completed (otherwise, we would have exited in the */
1776: /* "return" above), check whether a reselection attempt */
1777: /* is piggy-backed on top of the good DBDMA completion. */
1778:
1779: if ( g.shadow.mesh.exception & kMeshExcResel )
1780: handleReselectionInterrupt();
1781: else /* Nothing happening. Try to start another request. */
1782: {
1783: setIntMask( kMeshIntrException | kMeshIntrError ); /* Re-enable ints for reselect */
1784: enableCommands(); /* let superclass issue another cmd */
1785: }
1786:
1787: return;
1788: }/* end doInterruptStageGood */
1789:
1790:
1791: /* Process a normal data phase interrupt. IO is not complete. */
1792: /* There are several reasons why we might get here: */
1793: /* -- autosense completion (which could be a separate stage) */
1794: /* -- DMA completion with more DMA to do */
1795: /* -- Bus phase mismatch (short transfer or disconnect, MsgIn) */
1796: /* Note that we know that we are not in autosense. */
1797:
1798: void meshSCSIController::doInterruptStageXfer()
1799: {
1800: UInt32 count; /* DMA transfer count */
1801: UInt8 phase; /* Current bus phase */
1802: IOReturn rc;
1803: int goAround;
1804:
1805:
1806: count = fCmdData->results.bytesTransferred;
1807:
1808: updateCurrentIndex();
1809:
1810: do
1811: { goAround = false; /* assume loop not repeated */
1812: setSeqReg( kMeshFlushFIFO );
1813:
1814: /* We've cleaned up the mess from the previous data transfer. */
1815: /* Look at the current bus phase. The channel command waited */
1816: /* for REQ to be set before interrupting the processor. */
1817:
1818: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
1819: /* REQ is set, right? */
1820:
1821: switch ( phase )
1822: {
1823: case kBusPhaseSTS:
1824: fFlagIncompleteDBDMA = false; /* indicate no-more-data */
1825: runDBDMA( kcclGetStatus, kcclStageStat );
1826: break;
1827:
1828: case kBusPhaseMSGI:
1829: rc = DoMessageInPhase();
1830: if ( rc == kIOReturnSuccess && fCmd )
1831: goAround = true; /* msg ok & not disconnect */
1832: break;
1833:
1834: case kBusPhaseDATO:
1835: case kBusPhaseDATI:
1836: if ( count != fCmdData->results.bytesTransferred )
1837: { /* Data phase had already started: */
1838: PAUSE( 0, phase, 'dat-', "doInterruptStageXfer - unexpected Data phase.\n" );
1839: }
1840: else
1841: { /* try starting data phase again */
1842: runDBDMA( kcclDataXfer, kcclStageXfer );
1843: }
1844: break;
1845:
1846: default:
1847: PAUSE( 0, phase, 'Phs-', "doInterruptStageXfer - bogus phase.\n" );
1848: break;
1849: }/* end SWITCH on phase */
1850: } while ( goAround );
1851: return;
1852: }/* end doInterruptStageXfer */
1853:
1854:
1855: /* doInterruptStageArb - Process an anomaly during arbitration. */
1856:
1857: void meshSCSIController::doInterruptStageArb()
1858: {
1859: PAUSE( 0, 0, 'Arb-', "doInterruptStageArb - Lost arbitration.\n" );
1860:
1861: disableCommands();
1862: rescheduleCommand( fCmd );
1863: fCmd = 0;
1864:
1865: if ( g.shadow.mesh.exception & kMeshExcResel )
1866: { if ( g.shadow.mesh.error & kMeshErrDisconnected )
1867: {
1868: /* 18sep98 - Sometimes MESH gets real confused when its */
1869: /* arbitration loses to a target's reselect arbitration. */
1870: /* The registers show Exc:ArbLost, Resel and Err:UnExpDisc. */
1871: /* The FIFO count is 1 (should be SCSI ID bits) while the */
1872: /* BusStatus0,1 registers show IO and Sel both of which are */
1873: /* set by the reselecting Target. */
1874: /* The SCSI bus analyzer shows the following events occcurring */
1875: /* within a few microseconds of BSY being set by the target: */
1876: /* bus free for at least hundreds of microseconds */
1877: /* Target raises BSY along with its ID bit */
1878: /* Target raises SEL */
1879: /* Target raises IO to indicate reselection */
1880: /* Target adds MESH's ID bit */
1881: /* Target drops BSY */
1882: /* MESH raises BSY to accept reselection */
1883: /* **** MESH drops BSY **** here is where MESH is confused */
1884: /* Target stays on bus for 250 milliseconds. */
1885: /* To solve this problem, whack MESH with a RstMESH. */
1886:
1887: ELG( ' Rst', 'MESH', 'UEP-', "doInterruptStageArb - Resel/Unexpected Disconnect.\n" );
1888: setSeqReg( kMeshResetMESH ); /* completes quickly */
1889: getHBARegsAndClear( true ); /* clear cmdDone */
1890: setSeqReg( kMeshEnableReselect );
1891: setIntMask( kMeshIntrMask ); /* Enable Interrupts */
1892: return; /* now wait for another reselect interrupt */
1893: }
1894: handleReselectionInterrupt();
1895: }
1896: else
1897: { /* 22sep97 - lost arbitration without reselection. */
1898: /* Probably lost the reselect condition processing an */
1899: /* error or something. */
1900: ELG( 0, 0, 'ARB-', "doInterruptStageArb - Lost arbitration without reselect.\n" );
1901: }
1902: return;
1903: }/* end doInterruptStageArb */
1904:
1905:
1906: /* Process an anomaly during target selection. */
1907:
1908: void meshSCSIController::doInterruptStageSelA()
1909: {
1910: ELG( fCmd, 0, 'Sel-', "doInterruptStageSelA - Selection stage.\n" );
1911: if ( fCmd )
1912: { fCmdData->results.returnCode = kIOReturnNoDevice;
1913: completeCommand();
1914: }
1915: setSeqReg( kMeshEnableReselect );
1916: setSeqReg( kMeshBusFreeCmd ); /* clear ATN signal MESH left on */
1917: getHBARegsAndClear( false ); /* check MESH registers */
1918:
1919: if ( g.shadow.mesh.exception & kMeshExcResel )
1920: {
1921: handleReselectionInterrupt();
1922: }
1923: else
1924: { setIntMask( kMeshIntrMask ); /* Enable Interrupts */
1925: /* enableCommands on the Bus-Free interrupt. */
1926: /* If we do it here, we'll get a command, start the DBDMA, */
1927: /* and get the Bus-Free interrupt seeming to be spurious. */
1928: }
1929: return;
1930: }/* end doInterruptStageSelA */
1931:
1932:
1933: /* Process an anomaly during Message-Out phase. */
1934: /* Target probably doing Message Reject (0x07). */
1935:
1936: void meshSCSIController::doInterruptStageMsgO()
1937: {
1938: UInt8 phase;
1939: IOReturn rc;
1940:
1941:
1942: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; /* phase me */
1943: ELG( fCmd, phase, 'Mgo-', "doInterruptStageMsgO - error during msg-out phase.\n" );
1944:
1945: switch ( phase ) /* Probably negotiating Sync */
1946: {
1947: case kBusPhaseMSGI:
1948: rc = DoMessageInPhase();
1949: if ( rc != kIOReturnSuccess )
1950: {
1951: PAUSE( 0, rc, ' MI-',
1952: "doInterruptStageMsgO - MsgIn during MsgOut phase.\n" );
1953: // ??? need to get to bus-free from here
1954: // ??? need to blow off the IO
1955: }
1956: else
1957: { ELG( 0, fMsgInFlag, 'rej?', "doInterruptStageMsgO - got MsgIn.\n" );
1958: if ( fMsgInFlag & kFlagMsgIn_Reject )
1959: abortActiveCommand();
1960: }
1961: break;
1962:
1963: default:
1964: PAUSE( fMsgInFlag, phase, 'mgo-',
1965: "doInterruptStageMsgO - unknown phase during MsgOut phase.\n" );
1966: break;
1967: }
1968: return;
1969: }/* end doInterruptStageMsgO */
1970:
1971:
1972: /* doInterruptStageCmdO - Process an anomaly during command stage. */
1973:
1974: void meshSCSIController::doInterruptStageCmdO()
1975: {
1976: SCSICDBInfo scsiCDB;
1977: UInt8 phase;
1978: IOReturn rc;
1979:
1980:
1981: /* See if this is part of the normal AbortTag/BusDeviceReset process: */
1982:
1983: fCmd->getCDB( &scsiCDB );
1984: if ( scsiCDB.cdbAbortMsg )
1985: {
1986: setSeqReg( kMeshFlushFIFO ); /* flush the FIFO */
1987: getHBARegsAndClear( true ); /* clear cmdDone */
1988:
1989: ELG( fCmd, fCmd->getOriginalCmd(), 'Abo-', "doInterruptStageCmdO - Aborting." );
1990:
1991: completeCommand(); /* complete the cmd with Abort msg */
1992: setIntMask( kMeshIntrMask ); /* Re-enable interrupts */
1993: enableCommands(); /* let superclass issue another command */
1994: return;
1995: }
1996:
1997: /* Not aborting - something bad happened: */
1998:
1999: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask; /* phase me */
2000: ELG( fCmd, phase, 'CMD?', "doInterruptStageCmdO - anomaly during Cmd phase.\n" );
2001:
2002: if ( phase == kBusPhaseMSGI )
2003: { /* We are probably negotiating SDTR or */
2004: /* getting rejected on a nonzero LUN. */
2005: rc = DoMessageInPhase();
2006: if ( rc != kIOReturnSuccess )
2007: {
2008: PAUSE( 0, rc, ' mi-',
2009: "doInterruptStageCmdO - MsgIn during Cmd phase.\n" );
2010: }
2011: else
2012: { /* Message processed - where do we go from here? */
2013:
2014: if ( !fCmd ) /* if Rejected, */
2015: return; /* return */
2016:
2017: phase = g.shadow.mesh.busStatus0 & kMeshPhaseMask;
2018: switch ( phase )
2019: {
2020: case kBusPhaseSTS:
2021: runDBDMA( kcclCmdoStage, kcclStageInit );
2022: break;
2023:
2024: case kBusPhaseMSGO:
2025: fMsgOutPtr = &fCCL[ kcclMSGOdata ];
2026: setupMsgO();
2027: runDBDMA( kcclMsgoStage, kcclStageInit );
2028: break;
2029:
2030: case kBusPhaseCMD:
2031: runDBDMA( kcclCmdoStage, kcclStageInit );
2032: break;
2033: }
2034: }
2035: }
2036: else if ( phase == kBusPhaseSTS ) /* Probably Check Condition */
2037: { /* Perhaps block # invalid */
2038: fFlagIncompleteDBDMA = false; /* indicate no-more-data */
2039: runDBDMA( kcclGetStatus, kcclStageStat );
2040: }
2041: else
2042: {
2043: PAUSE( 0, phase, 'Phs?', "doInterruptStageCmdO - error during Command phase.\n" );
2044: }
2045: return;
2046: }/* end doInterruptStageCmdO */
2047:
2048:
2049: /* We are in MSGI phase. Read the bytes. Return true if an entire */
2050: /* message was read (we may still be in MSGI phase). Note that this */
2051: /* is done by programmed IO, which will fail (logging the error) if */
2052: /* the target sets MSGI but does not send us a message quickly enough. */
2053: /* This method is called from the normal data transfer interrupt when */
2054: /* the target enters message in phase, and from the reselection */
2055: /* interrupt handler when we read a valid reselection target ID. */
2056: /* Note that MESH interrupts are disabled on exit. */
2057: enum /// ??? header file
2058: {
2059: kSCSIMsgOneByteMax = 0x1Fu,
2060: kSCSIMsgTwoByteMin = 0x20u,
2061: kSCSIMsgTwoByteMax = 0x2Fu
2062: };
2063:
2064: IOReturn meshSCSIController::DoMessageInPhase()
2065: {
2066: register UInt8 messageByte;
2067: UInt32 index = 0;
2068: IOReturn ioReturn = kIOReturnSuccess;
2069:
2070:
2071: /* We do not necessarily have a valid command in this method. */
2072: /* While we're processing Message-In bytes, we don't want any */
2073: /* MESH hardware interrupts. */
2074:
2075: setIntMask( 0 ); /* no MESH interrupt latching */
2076: setSeqReg( kMeshFlushFIFO ); /* Flush the FIFO */
2077:
2078: fMsgInCount = 0;
2079: fMsgInState = kMsgInInit;
2080:
2081: while ( fMsgInState != kMsgInReady /* Disconnect makes fCmd */
2082: && ioReturn == kIOReturnSuccess ) /* go away */
2083: {
2084: fMESHAddr->transferCount1 = 0;
2085: fMESHAddr->transferCount0 = 1; /* get single byte */
2086: setSeqReg( kMeshMessageInCmd ); /* issue MsgIn */
2087:
2088: ioReturn = waitForMesh( true ); /* wait for cmdDone */
2089: if ( ioReturn != kIOReturnSuccess )
2090: {
2091: PAUSE( *(UInt32*)&fCurrentTargetLun, ioReturn, 'Mgi-', "DoMessageInPhase - Target hung: message in timeout.\n" );
2092: break; /* Bus reset here? */
2093: }
2094:
2095: if ( (g.shadow.mesh.exception & kMeshExcPhaseMM)
2096: || (g.shadow.mesh.busStatus0 & kMeshPhaseMask) != kBusPhaseMSGI )
2097: {
2098: break; /* exit loop if no longer in Msg-In phase */
2099: }
2100:
2101: if ( g.shadow.mesh.FIFOCount == 0 )
2102: {
2103: PAUSE( *(UInt16*)&fCurrentTargetLun, 0, 'mgi-', "DoMessageInPhase - no message byte.\n" );
2104: break;
2105: }
2106:
2107: fMsgInBuffer[ index++ ] = messageByte = fMESHAddr->xFIFO; /***** get msg byte *****/
2108:
2109: switch ( fMsgInState )
2110: {
2111: case kMsgInInit: /* This is the first message byte. */
2112: if ( (messageByte == kSCSIMsgCmdComplete)
2113: || (messageByte >= (UInt8)kSCSIMsgIdentify) )
2114: { /* This is 1-byte cmdComplete or Identify message. */
2115: fMsgInState = kMsgInReady;
2116: }
2117: else if ( messageByte == kSCSIMsgExtended )
2118: { /* This is an extended message. The next byte has the count. */
2119: fMsgInState = kMsgInCounting;
2120: }
2121: else if ( messageByte <= kSCSIMsgOneByteMax )
2122: { /* These are other 1-byte messages. */
2123: fMsgInState = kMsgInReady;
2124: }
2125: else if ( messageByte >= kSCSIMsgTwoByteMin
2126: && messageByte <= kSCSIMsgTwoByteMax )
2127: { /* This is a two-byte message. */
2128: /* Set the count and read the next byte. */
2129: fMsgInState = kMsgInReading; /* Need one more */
2130: fMsgInCount = 1;
2131: }
2132: else
2133: { /* This is an unknown message. */
2134: fMsgInState = kMsgInReady;
2135: }
2136: break;
2137:
2138: case kMsgInCounting: /* Count byte of multi-byte message: */
2139: fMsgInCount = messageByte;
2140: fMsgInState = kMsgInReading;
2141: break;
2142:
2143: case kMsgInReading: /* Body of multi-byte message: */
2144: if ( --fMsgInCount <= 0 )
2145: fMsgInState = kMsgInReady;
2146: break;
2147:
2148: default:
2149: PAUSE( 0, 0, 'Msg-', "DoMessageInPhase - Bogus MSGI state!\n" );
2150: fMsgInState = kMsgInReady;
2151: break;
2152: }/* end SWITCH on MSGI state */
2153:
2154: if ( fMsgInState == kMsgInReady )
2155: {
2156: ProcessMSGI();
2157: fMsgInState = kMsgInInit;
2158: index = 0;
2159: if ( fMsgInBuffer[0] == kSCSIMsgDisconnect )
2160: ioReturn = kIOReturnIOError; /* break out of WHILE loop */
2161:
2162: if ( fMsgInFlag & kFlagMsgIn_Reject )
2163: {
2164: abortActiveCommand();
2165: break;
2166: }
2167:
2168: if ( fFlagReselecting )
2169: break; /* Take Identify only - leave +ACK */
2170: }/* end IF have a complete message-in to process */
2171: }/* end WHILE there are more message bytes */
2172:
2173: /***** If the target switches out of MSGI phase without *****/
2174: /***** sending a complete message, we should do some *****/
2175: /***** sort of error recovery. *****/
2176:
2177: if ( fMsgInState != kMsgInInit )
2178: {
2179: PAUSE( *(UInt32*)&fCurrentTargetLun, fMsgInState, 'MGI-', "DoMessageInPhase - incomplete message.\n" );
2180: if ( ioReturn == kIOReturnSuccess )
2181: ioReturn = kIOReturnIOError; /* General IO error */
2182: }
2183:
2184: return ioReturn;
2185: }/* end DoMessageInPhase */
2186:
2187:
2188: /* ProcessMSGI - DoMessageInPhase has read a complete message. */
2189: /* Process it (this will probably change our internal state). */
2190:
2191: void meshSCSIController::ProcessMSGI()
2192: {
2193: /* Note that, during reselection, we may not have */
2194: /* a current target or LUN, nor possibly a valid command */
2195:
2196:
2197: UInt8 sdtr;
2198: UInt8 period, offset;
2199:
2200:
2201: ELG( fCmd, *(UInt32*)fMsgInBuffer, '<Msg', "ProcessMSGI" );
2202:
2203: switch ( fMsgInBuffer[0] )
2204: {
2205: case kSCSIMsgCmdComplete:
2206: if ( fCmd )
2207: {
2208: /* This command is complete. Clear interrupts and */
2209: /* allow subsequent MESH interrupts. Then tell the */
2210: /* MESH to wait for the target to release the bus. */
2211:
2212: setSeqReg( kMeshEnableReselect );
2213: setSeqReg( kMeshBusFreeCmd ); /* cause Int */
2214: completeCommand();
2215: }
2216: goto exit; /* Don't exit through the SWITCH end */
2217:
2218: case kSCSIMsgLinkedCmdComplete:
2219: case kSCSIMsgLinkedCmdCompleteFlag:
2220: PAUSE( *(UInt16*)&fCurrentTargetLun, 0, 'pmi-', "ProcessMSGI - linked command complete not supported.\n" );
2221: abortActiveCommand();
2222: break;
2223:
2224: case kSCSIMsgNop:
2225: break;
2226:
2227: case kSCSIMsgRestorePointers:
2228: if ( fCmd )
2229: fCmdData->results.bytesTransferred = fCmdData->savedDataPosition;
2230: break;
2231:
2232: case kSCSIMsgSaveDataPointers:
2233: if ( fCmd )
2234: fCmdData->savedDataPosition = fCmdData->results.bytesTransferred;
2235: break;
2236:
2237: case kSCSIMsgDisconnect:
2238: /* Move this request to the disconnect queue, enable reselection, */
2239: /* re-enable MESH interrupts, and wait (here) for bus free, but */
2240: /* don't eat the interrupt. */
2241:
2242: fMsgInFlag |= kFlagMsgIn_Disconnect;
2243: disconnect(); /* requeue active */
2244: setSeqReg( kMeshEnableReselect ); /* enable reselect */
2245: setIntMask( kMeshIntrMask ); /* Enable Ints */
2246: setSeqReg( kMeshBusFreeCmd ); /* issue BusFree */
2247:
2248: /* wait for Bus Free command to complete: */
2249:
2250: waitForMesh( false ); /* don't clear possible reselect */
2251:
2252: /* Interrupt for bus-free now latched. Prevent a double interrupt, */
2253: /* 1 from bus-free + 1 from reselect from occurring. */
2254: /* This fixes the following BADNESS: */
2255: /* Issue bus-free for disconnect. */
2256: /* Interrupt occurs in microseconds - even before exiting */
2257: /* "interruptOccurred" routine. */
2258: /* Mach queues message to driverKit. */
2259: /* Exit "interruptOccurred" routine. */
2260: /* DriverKit dequeues and starts handling 1st Mach message. */
2261: /* Interrupt occurs for reselect while driverKit running. */
2262: /* Mach queues 2nd message to driverKit. */
2263: /* DriverKit invokes MESH driver for 1st msg. */
2264: /* MESH driver sees cmdDone fm bus-free AND reselect exception.*/
2265: /* MESH driver handles reselect by setting up and running */
2266: /* DBDMA. MESH driver exits. */
2267: /* DriverKit invokes MESH driver with 2nd Mach message. */
2268: /* MESH driver handles this as a DBDMA completion and royally */
2269: /* messes up. */
2270:
2271: g.intLevel |= kLevelLatched; /* set latched-interrupt flag */
2272: setIntMask( 0 ); /* prevent multiple MESH ints */
2273: break;
2274:
2275: case kSCSIMsgRejectMsg:
2276: ELG( *(UInt16*)&fCurrentTargetLun, fMsgOutFlag, 'Rej-', "ProcessMSGI - Reject." );
2277: fMsgInFlag |= kFlagMsgIn_Reject;
2278: break;
2279:
2280: case kSCSIMsgSimpleQueueTag:
2281: fTagType = fMsgInBuffer[0];
2282: fTag = fMsgInBuffer[1];
2283: ELG( 0, fTag, '=Tag', "Simple Queue Tag" );
2284: break;
2285:
2286: case kSCSIMsgExtended:
2287:
2288: /* Multi-byte message, presumably Synchronous Negotiation: */
2289:
2290: switch ( fMsgInBuffer[ 2 ] ) /* switch on the msg code byte */
2291: {
2292: case kSCSIMsgSyncXferReq: /* handle sync negotiation: */
2293: /* Get period in nanoseconds */
2294: period = fMsgInBuffer[ 3 ] * 4; /* SCSI uses 4ns granularity */
2295:
2296: /* determine target responding or initiating? */
2297: if ( fNegotiatingSDTR )
2298: {
2299: if ( fMsgInBuffer[ 4 ] == 0 ) /* check offset */
2300: {
2301: sdtr = kSyncParmsAsync; /* Offset == 0 implies async */
2302: }
2303: else /* synchronous: */
2304: {
2305: if ( period == 100 ) /* special-case 100=FAST */
2306: {
2307: sdtr = kSyncParmsFast & 0x0F;
2308: }
2309: else /* Older CD-ROMs get here. */
2310: { /* The MESH manual says: */
2311: /* period = 4 * clk + 2 * clk * P */
2312: /* where: */
2313: /* period is the target nanoseconds */
2314: /* clk is the MESH clock rate which is */
2315: /* 20 nanoseconds for a 50 MHz clock */
2316: /* P is the 1-nibble period code we stuff */
2317: /* in the syncParms register */
2318: /* So: */
2319: /* period = 4 * 20 + 2 * 20 * P */
2320: /* period = 80 + 40 * P */
2321: /* P = (period - 80) / 40 */
2322: /* Since P must round up for safety: */
2323: /* P = ((period - 80) + 39) / 40 */
2324: /* P = (period - 41) / 40 */
2325: /* A value of P == 3 results in 5 MB/s */
2326: sdtr = (UInt8)((period - 41) / 40);
2327: }
2328: }/* end ELSE have offset ergo Synchronous */
2329:
2330: /* OR in the offset. */
2331: sdtr |= (fMsgInBuffer[ 4 ] << 4);
2332: }/* end IF Target is responding to negotiation */
2333:
2334: else /* target is initiating negotiation: */
2335: {
2336: fMsgOutPtr = &fCCL[ kcclMSGOdata ];
2337: *fMsgOutPtr++ = kSCSIMsgExtended; /* 0x01 Ext Msg */
2338: *fMsgOutPtr++ = 0x03; /* 0x03 Message Len */
2339: *fMsgOutPtr++ = kSCSIMsgSyncXferReq; /* 0x01 SDTR code */
2340: offset = fMsgInBuffer[ 4 ];
2341: if ( offset == 0 ) /* Offset == 0 means async: */
2342: {
2343: *fMsgOutPtr++ = 0; /* clear period byte */
2344: *fMsgOutPtr++ = 0; /* offset byte = 0 for async*/
2345: sdtr = kSyncParmsAsync; /* set value for MESH reg */
2346: }
2347: else /* have offset ergo sync: */
2348: {
2349: if ( offset > 15 )
2350: offset = 15; /* MESH can only handle 15 */
2351:
2352: if ( period <= 100 ) /* special-case 100=FAST */
2353: period = 100;
2354: else
2355: { /* round up to MESH's 40 ns granularity */
2356: period = ((period + 39) / 40) * 40;
2357: }
2358: *fMsgOutPtr++ = period / 4; /* SCSI 4ns granularity */
2359: *fMsgOutPtr++ = offset;
2360: sdtr = (offset << 8) | (UInt8)((period - 41) / 40);
2361: }/* end target is negotiating Sync */
2362: /* respond to target: */
2363: runDBDMA( kcclMsgoStage, kcclStageInit );
2364: }/* end ELSE target is initiating negotiation */
2365:
2366: fMESHAddr->syncParms = sdtr;
2367: SynchronizeIO();
2368: fSyncParms[ fCurrentTargetLun.target ] = sdtr;
2369: ELG( *(UInt32*)&fMsgInBuffer[0], fMsgInBuffer[4]<<24 | sdtr, 'SDTR', "ProcessMSGI - SDTR" );
2370: break;
2371:
2372: default:
2373: PAUSE( *(UInt16*)&fCurrentTargetLun, fMsgInBuffer[0], 'PMi-', "ProcessMSGI - unsupported extended message.\n" );
2374: abortActiveCommand();
2375: break;
2376: }/* end SWITCH on extended message code */
2377: break;
2378:
2379: default: /* Better be Identify with LUN: */
2380: if ( fMsgInBuffer[0] >= kSCSIMsgIdentify )
2381: {
2382: fCurrentTargetLun.lun = fMsgInBuffer[0] & 0x07;
2383: }
2384: else
2385: {
2386: PAUSE( *(UInt16*)&fCurrentTargetLun, fMsgInBuffer[0], 'mi -', "ProcessMSGI - unsupported message: rejected.\n" );
2387: abortActiveCommand();
2388: }
2389: }/* end SWITCH on message selection */
2390:
2391: exit:
2392: return;
2393: }/* end ProcessMSGI */
2394:
2395:
2396: /* Process a reselection interrupt. */
2397:
2398: void meshSCSIController::handleReselectionInterrupt()
2399: {
2400: IOReturn ioReturn;
2401:
2402:
2403: fFlagReselecting = true;
2404: disableCommands(); /* tell superclass we're busy */
2405:
2406: fMESHAddr->interrupt = kMeshIntrMask; /* clr Exc, Err regs to prevent SeqErr*/
2407:
2408: /* Sometimes MESH gives a bogus Disconnected error during Reselection. */
2409: /* 31mar98 - Issuing an Abort message, causes "unexpected disconnect". */
2410: /* When Err:UnexpDisc and Exc:Resel are simultaneously set, the */
2411: /* busStatus0,1 registers may not be current. */
2412: if ( g.shadow.mesh.error & kMeshErrDisconnected )
2413: {
2414: setSeqReg( kMeshBusFreeCmd );
2415: waitForMesh( true ); // now maybe busStatus0,1 are live
2416: PAUSE( 0, 0, 'Dsc-',
2417: "handleReselectionInterrupt: Caught disconnected glitch\n" );
2418: }/* End IF bus disconnect error */
2419:
2420: /* Read the target ID (which should be our initiator ID OR'd with the */
2421: /* Target and the Identify byte with the reselecting LUN. Store this */
2422: /* in fCurrentTargetLun. Note that, during reselection, we will */
2423: /* have a NULL gCurrentCommand and a valid fCurrentTargetLun. */
2424: /* If we get a valid reselection target, call the message in phase */
2425: /* directly to read the LUN byte. */
2426: /* @return true if successful. */
2427:
2428: if ( fMESHAddr->FIFOCount == 0 )
2429: {
2430: PAUSE( 0, 0, 'HRI-', "handleReselectionInterrupt - Empty FIFO in reselection.\n" );
2431: return;
2432: }
2433: else /* get the Target ID bit from the bus out of the FIFO */
2434: { /* then, get the msg-in Identify byte for the LUN. */
2435: if ( getReselectionTargetID() )
2436: {
2437: if ( DoMessageInPhase() != kIOReturnSuccess ) /* get Identify */
2438: {
2439: PAUSE( 0, 0, 'Id -', "handleReselectionInterrupt - Expected Identify byte after reselection.\n" );
2440: }
2441: }
2442: else return;
2443: }
2444:
2445: /* Try to find an untagged command for this Target/LUN: */
2446:
2447: fTag = kInvalidTag;
2448: ioReturn = reselectNexus();
2449:
2450: if ( ioReturn != kIOReturnSuccess )
2451: { /* No untagged command, try to get a Tag. Hope that */
2452: /* you're still in Message-In phase at this point. */
2453: if ( DoMessageInPhase() != kIOReturnSuccess ) /* get Tag msg */
2454: {
2455: PAUSE( 0, 0, 'tag-', "handleReselectionInterrupt - Expected tag message.\n" );
2456: /// need to bus device reset since it seems confused.
2457: }
2458: ioReturn = reselectNexus();
2459: }
2460:
2461: if ( ioReturn == kIOReturnSuccess )
2462: {
2463: ELG( fCmd,
2464: fTag<<16 | fCurrentTargetLun.lun<<8 | fCurrentTargetLun.target,
2465: 'Resl', "handleReselectionInterrupt" );
2466: /* If reselectNexus succeeded, fCmd is set to the command. */
2467: /* Clear out the channel command Results and build the channel */
2468: /* command to continue operation. */
2469:
2470: clearCPResults();
2471: updateCP( true ); /* Bypass arbitrate/select/command sequence */
2472: runDBDMA( kcclReselect, kcclStageInit );
2473: }
2474: else
2475: { /* There is no associated command. */
2476: /* Reject the reselection attempt. */
2477: PAUSE( *(UInt16*)&fCurrentTargetLun, fTag, 'Rsl-',
2478: "handleReselectionInterrupt - No command for reselection attempt.\n" );
2479: abortActiveCommand();
2480: }
2481: return;
2482: }/* end handleReselectionInterrupt */
2483:
2484:
2485: /* Validate the target's reselection byte (put on the bus before */
2486: /* reselecting us). Erase the initiator ID and convert the other */
2487: /* bit into an index. The algorithm should be faster than a */
2488: /* sequential search, but it probably doesn't matter much. */
2489: /* Return true if successful (fCurrentTarget is now valid). */
2490:
2491: bool meshSCSIController::getReselectionTargetID()
2492: {
2493: register UInt8 targetID = 0;
2494: register UInt8 bitValue = 0; /* Suppress warning */
2495: register UInt8 targetBits;
2496: bool success = false;
2497:
2498:
2499: targetBits = fMESHAddr->xFIFO; /***** Read the FIFO *****/
2500: targetBits &= ~fInitiatorIDMask; /* Remove our bit */
2501: if ( targetBits )
2502: { /* Is there another bit? */
2503: bitValue = targetBits;
2504: if ( bitValue > 0x0F )
2505: {
2506: targetID += 4;
2507: bitValue >>= 4;
2508: }
2509: if ( bitValue > 0x03 )
2510: {
2511: targetID += 2;
2512: bitValue >>= 2;
2513: }
2514: if ( bitValue > 0x01 )
2515: {
2516: targetID += 1;
2517: }
2518: targetBits &= ~(1 << targetID); /* Remove the target mask */
2519: if ( targetBits == 0 )
2520: { /* Was exactly one set? */
2521: success = true; /* Yes: success! */
2522: fCurrentTargetLun.target = targetID; /* Save the current target */
2523: }
2524: }
2525:
2526: if ( !success )
2527: PAUSE( targetID, targetBits, 'rsl-', "getReselectionTargetID - Expected Identify byte after reselection.\n" );
2528:
2529: return success;
2530: }/* end getReselectionTargetID */
2531:
2532:
2533:
2534: IOReturn meshSCSIController::resetBus()
2535: {
2536: UInt8 defaultSelectionTimeout = 25; // mlj ??? fix this value
2537: DBDMAChannelRegisters *DBDMARegs = (DBDMAChannelRegisters*)dbdmaAddr;
2538:
2539:
2540: ELG( 0, 0, 'RstB', "resetBus" );
2541:
2542: /* Stop the DBDMA: */
2543:
2544: DBDMARegs->channelControl = SWAP( 0x20002000 ); // set FLUSH bit
2545: SynchronizeIO();
2546: DBDMARegs->channelControl = SWAP( 0x80000000 ); // clr RUN bit
2547: SynchronizeIO();
2548:
2549: /* Reset interrupts, the MESH Hardware Bus Adapter, and the DMA engine. */
2550:
2551: setIntMask( 0 );
2552:
2553: setSeqReg( kMeshResetMESH ); /* completes quickly */
2554: getHBARegsAndClear( true ); /* clear cmdDone */
2555:
2556: /// dbdma_reset( DBDMA_MESH_SCSI );
2557:
2558: /* Init state variables: */
2559:
2560: fFlagIncompleteDBDMA = false;
2561:
2562: /* Smash all active command state (just in case): */
2563:
2564: fCmd = NULL;
2565: fCmdData = NULL;
2566: fCurrentTargetLun.target = kInvalidTarget;
2567: fCurrentTargetLun.lun = kInvalidLUN;
2568: fMsgInState = kMsgInInit;
2569: fMsgOutPtr = &fCCL[ kcclMSGOdata ];
2570:
2571: fMESHAddr->busStatus1 = kMeshRst; /***** ASSERT RESET SIGNAL *****/
2572: SynchronizeIO();
2573: IODelay( 25 ); /* leave asserted for 25 mikes */
2574: fMESHAddr->busStatus1 = 0; /***** CLEAR RESET SIGNAL *****/
2575: SynchronizeIO();
2576:
2577: /* Delay for 250 msec after resetting the bus. */
2578: /* This serves two purposes: it gives the MESH time to */
2579: /* stabilize (about 10 msec is sufficient) and gives */
2580: /* some devices time to re-initialize themselves. */
2581:
2582: IOSleep( APPLE_SCSI_RESET_DELAY ); /* Give Targets time to clean up */
2583: setSeqReg( kMeshResetMESH ); /* clear Err condition */
2584: getHBARegsAndClear( true ); /* check regs */
2585:
2586: fMESHAddr->selectionTimeOut = defaultSelectionTimeout;
2587: SynchronizeIO();
2588:
2589: enableCommands(); /* let superclass issue another command */
2590:
2591: return kIOReturnSuccess;
2592: }/* end resetBus */
2593:
2594:
2595: /* Wait for an immediate (non-interrupting) command to complete. */
2596: /* Note that it spins while waiting. It is timed to prevent a buggy */
2597: /* chip or target from hanging the system. */
2598:
2599: IOReturn meshSCSIController::waitForMesh( bool clearInterrupts )
2600: {
2601: mach_timespec_t time, startTime, endTime, waitTime;
2602: IOReturn ioReturn = kIOReturnSuccess;
2603:
2604:
2605: IOGetTime( &time );
2606: startTime = endTime = time;
2607: waitTime.tv_sec = 0;
2608: waitTime.tv_nsec = 250000000; // mlj - make it 250 milliseconds for SONY CD-ROM;
2609: ADD_MACH_TIMESPEC( &endTime, &waitTime );
2610:
2611: for ( g.shadow.mesh.interrupt = 0; g.shadow.mesh.interrupt == 0; )
2612: {
2613: getHBARegsAndClear( clearInterrupts );
2614:
2615: IOGetTime( &time );
2616: if ( time.tv_sec < endTime.tv_sec )
2617: continue;
2618: if ( time.tv_nsec > endTime.tv_nsec )
2619: { /* It took too long! We're dead. */
2620: PAUSE( 0, 0, 'WFM-', "waitForMesh - MESH chip does not respond to command.\n" );
2621: ioReturn = kIOReturnInternalError;
2622: break;
2623: }
2624: }/* end FOR */
2625: ELG( time.tv_sec - startTime.tv_sec, time.tv_nsec - startTime.tv_nsec, ' WFM', "waitForMesh" );
2626: return ioReturn;
2627: }/* end waitForMesh */
2628:
2629:
2630: /* Send a command to the MESH chip. This may cause an interrupt. */
2631:
2632: void meshSCSIController::setSeqReg( MeshCommand meshCommand )
2633: {
2634: ELG( (fMESHAddr->interruptMask<<16) | fMESHAddr->interrupt, meshCommand, '=Seq', "setSeqReg" );
2635:
2636: if ( fMESHAddr->interruptMask & kMeshIntrCmdDone
2637: && meshCommand <= kMeshBusFreeCmd )
2638: ELG( fMESHAddr->interrupt, fMESHAddr->interruptMask, 'Trig',
2639: "setSeqReg - may trigger interrupt." );
2640:
2641: fMESHAddr->sequence = (UInt8)meshCommand; /***** DO IT *****/
2642: SynchronizeIO();
2643: IODelay( 1 ); /* G3 is too fast */
2644:
2645: return;
2646: }/* end setSeqReg */
2647:
2648:
2649: /* Retrieve the MESH volatile register contents, */
2650: /* storing them in the global register shadow. */
2651: /* @param clearInts YES to clear MESH interrupts. */
2652:
2653: void meshSCSIController::getHBARegsAndClear( bool clearInts )
2654: {
2655: register MeshRegister *mesh = fMESHAddr;
2656:
2657:
2658: g.shadow.mesh.interrupt = mesh->interrupt;
2659: g.shadow.mesh.error = mesh->error;
2660: g.shadow.mesh.exception = mesh->exception;
2661: g.shadow.mesh.FIFOCount = mesh->FIFOCount;
2662:
2663: g.shadow.mesh.busStatus0 = mesh->busStatus0;
2664: g.shadow.mesh.busStatus1 = mesh->busStatus1;
2665: g.shadow.mesh.transferCount1 = mesh->transferCount1;
2666: g.shadow.mesh.transferCount0 = mesh->transferCount0;
2667:
2668: g.shadow.mesh.sequence = mesh->sequence; // debugging
2669: g.shadow.mesh.interruptMask = mesh->interruptMask; // debugging
2670: g.shadow.mesh.syncParms = mesh->syncParms; // debugging
2671: g.shadow.mesh.destinationID = mesh->destinationID; // debugging
2672:
2673: ELG( g.shadow.longWord[ 0 ], g.shadow.longWord[ 1 ], clearInts ? 'Regs' : 'regs', "getHBARegsAndClear." );
2674:
2675: if ( g.shadow.mesh.error ) // this occurs when DBDMA -> Seq while reselect
2676: { // OR Exc:reselect occurs just before busFree->Seq reg.
2677: ELG( g.shadow.mesh.interruptMask, g.shadow.mesh.sequence, 'Err-',
2678: "getHBARegsAndClear - MESH error detected" );
2679: mesh->interrupt = kMeshIntrError;
2680: SynchronizeIO();
2681: }
2682:
2683: /* It is possible to have the Reselected bit set in the Exception */
2684: /* register without an Exception bit in the interrupt register. */
2685: /* This may be caused by timing window where we clear the interrupt */
2686: /* register with the interrupt register instead of 0x07. */
2687: /* Handle this by faking an exception. */
2688: /* 04may98 - it is also possible to have PhaseMisMatch set in the */
2689: /* Exception register without Exception indicated in the Interrupt */
2690: /* register. This happened when a Synchronous output finished and */
2691: /* the target went to Message-In phase with Save-Data-Pointer. */
2692:
2693:
2694: if ( g.shadow.mesh.exception )
2695: g.shadow.mesh.interrupt |= kMeshIntrException;
2696:
2697: if ( clearInts && g.shadow.mesh.interrupt )
2698: {
2699: mesh->interrupt = g.shadow.mesh.interrupt;
2700: SynchronizeIO();
2701: }
2702: return;
2703: }/* end getHBARegsAndClear */
2704:
2705:
2706: void meshSCSIController::setIntMask( UInt8 mask )
2707: {
2708: ELG( (fMESHAddr->interrupt<<16) | fMESHAddr->interruptMask, mask, 'Mask', "setIntMask" );
2709: fMESHAddr->interruptMask = mask; /* enable whatever */
2710: SynchronizeIO();
2711: return;
2712: }/* end setIntMask */
2713:
2714:
2715: void meshSCSIController::abortActiveCommand()
2716: {
2717: IOReturn ioReturn;
2718:
2719:
2720: ELG( fCmd, 0, '-AB*', "abortActiveCommand" );
2721: if ( fCmd )
2722: {
2723: fCmdData->results.returnCode = kIOReturnError; // ??? use kIOAborted?
2724: completeCommand();
2725: }
2726:
2727: getHBARegsAndClear( true ); /* clear possible cmdDone et al */
2728: setIntMask( 0 ); /* Disable MESH interrupts */
2729:
2730: fMsgInFlag = 0; /* clear kFlagMsgIn_Reject et al */
2731:
2732: fMESHAddr->busStatus0 = kMeshAtn; /***** Raise ATN signal *****/
2733: SynchronizeIO();
2734:
2735: setSeqReg( kMeshBusFreeCmd ); /* clear ACK */
2736: waitForMesh( true ); /* wait for PhaseMM */
2737:
2738: if ( (g.shadow.mesh.busStatus0 & (kMeshPhaseMask | kMeshReq))
2739: == (kBusPhaseMSGO | kMeshReq) )
2740: { /* this is what we want: */
2741: setSeqReg( kMeshFlushFIFO ); /* Flush the FIFO */
2742: fMESHAddr->transferCount0 = 1; /* set TC low = 1 */
2743: fMESHAddr->transferCount1 = 0;
2744: fMESHAddr->busStatus0 = 0; /***** clear ATN signal *****/
2745: SynchronizeIO();
2746:
2747: /* Issue the Message Out sending the Abort on its way. */
2748: /* Note that this will cause an Unexpected-Disconnect. */
2749: setSeqReg( kMeshMessageOutCmd ); /* drop ATN signal */
2750: fMESHAddr->xFIFO = kSCSIMsgAbort; /* put out the Abort byte */
2751: ioReturn = waitForMesh( true ); /* wait for cmdDone */
2752: if ( ioReturn == kIOReturnSuccess )
2753: {
2754: setSeqReg( kMeshEnableReselect ); /* bus about to go free */
2755: setIntMask( kMeshIntrMask ); /* Enable interrupts */
2756: setSeqReg( kMeshBusFreeCmd ); /* Clr ACK & go Bus-Free */
2757: g.intLevel |= kLevelLatched; /* set latched-int flag */
2758: return;
2759: }
2760: }/* end IF MSGO phase and REQ is set */
2761:
2762: /***** USE THE HAMMER - NUKE THE BUS: *****/
2763:
2764: ELG( 0, 0, '-AB-', "abortActiveCommand - target refused to enter MSGO phase" );
2765: resetBus();
2766: super::resetOccurred();
2767: return;
2768: }/* end abortActiveCommand */
2769:
2770:
2771: /* IO associated with fCmd has disconnected. */
2772: /* Place it on the disconnected command queue and */
2773: /* enable another transaction. */
2774:
2775: void meshSCSIController::disconnect()
2776: {
2777: fCmd = NULL;
2778: fCmdData = NULL;
2779: fCurrentTargetLun.target = kInvalidTarget;
2780: fCurrentTargetLun.lun = kInvalidLUN;
2781:
2782: /* Since there is no active command, the caller */
2783: /* must configure the bus interface to wait for */
2784: /* bus free, then allow reselection. */
2785:
2786: return;
2787: }/* end disconnect */
2788:
2789:
2790: /* The specified target, LUN, and queueTag is trying to reselect. */
2791: /* If we have a xxxCommandBuffer for this TLQ nexus on disconnectQ, */
2792: /* remove it, make it the current fCmd, and return YES. */
2793: /* Else return NO. A value of zero for queueTag indicates a */
2794: /* nontagged command (zero is never used as the queue tag value for */
2795: /* a tagged command). */
2796:
2797: IOReturn meshSCSIController::reselectNexus()
2798: {
2799: fCmd = findCommandWithNexus( fCurrentTargetLun, fTag );
2800: if ( fCmd )
2801: { fCmdData = (PrivCmdData*)fCmd->getCommandData();
2802: ELG( fCmd, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, '=Nex', "reselectNexus" );
2803: return kIOReturnSuccess;
2804: }
2805: else
2806: { if ( fTag != kInvalidTag )
2807: PAUSE( 0, *(UInt16*)&fCurrentTargetLun<<16 | (UInt16)fTag, 'Nex-', "reselectNexus" );
2808: }
2809:
2810: return kIOReturnInternalError;
2811: }/* end reselectNexus */
2812:
2813:
2814: void meshSCSIController::updateCurrentIndex()
2815: {
2816: UInt32 count; /* DMA transfer count */
2817: UInt32 length = g.shadow.mesh.FIFOCount;
2818: UInt8 buffer[ 16 ];
2819: UInt32 i;
2820:
2821:
2822: /* Calculate the number of bytes xferred by this channel command. */
2823: /* We don't trust the DBDMA residual count. */
2824:
2825: count = *(UInt32*)&fCCL[ kcclBatchSize ]; /* Our transfer count */
2826: if ( count == 0 ) /* If batch is empty, */
2827: return; /* look at nothing else.*/
2828: count -= g.shadow.mesh.transferCount1 << 8; /* MESH residual high */
2829: count -= g.shadow.mesh.transferCount0; /* MESH residual low */
2830: fCmdData->results.bytesTransferred += count; /* Increment data index */
2831: *(UInt32*)&fCCL[ kcclBatchSize ] = 0; /* Clear DBDMA count */
2832:
2833: if ( fReadAlignmentCount ) // Hack for Radar 1670626
2834: {
2835: fCmdData->mdp->writeBytes( fReadAlignmentIndex, &fCCL[ kcclReadBuf8 ], fReadAlignmentCount );
2836: fReadAlignmentCount = 0;
2837: }
2838:
2839: /* Check the FIFO, if empty, increment the current data pointer. */
2840: /* If there is stuff in it, we have more work to do. */
2841:
2842: if ( g.shadow.mesh.FIFOCount ) /* If data in FIFO: */
2843: {
2844: /* We didn't process these bytes in the FIFO - adjust index */
2845: fCmdData->results.bytesTransferred -= g.shadow.mesh.FIFOCount;
2846:
2847: if ( fCmdData->isWrite ) /* If Writing: */
2848: {
2849: setSeqReg( kMeshFlushFIFO );
2850: }
2851: else /* Must be Reading: */
2852: { /* On a Read with data left in the FIFO, we must copy */
2853: /* the FIFO directly into the user's data buffer: */
2854:
2855: ELG( fCmdData->results.bytesTransferred, g.shadow.mesh.FIFOCount, 'FIFO',
2856: "updateCurrentIndex - copy FIFO to user buffer." );
2857: count = fCmdData->xferCount - fCmdData->results.bytesTransferred;
2858: if ( count > length )
2859: count = length;
2860:
2861: /* FYI - emptying the FIFO causes cmdDone to get set. */
2862:
2863: for ( i = 0; i < count; i++ )
2864: buffer[ i ] = fMESHAddr->xFIFO;
2865:
2866: fCmdData->mdp->writeBytes( fCmdData->results.bytesTransferred, buffer, count );
2867:
2868: fCmdData->results.bytesTransferred += count;
2869: }/* end if/ELSE must be Reading */
2870: }/* end IF FIFO was not empty */
2871:
2872: ELG( 0, fCmdData->results.bytesTransferred, 'UpIx', "updateCurrentIndex" );
2873: return;
2874: }/* end updateCurrentIndex */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.