|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /**
26: * Copyright 1997 Apple Computer Inc. All Rights Reserved.
27: * @revision 1997.02.17 Initial conversion from AMDPCSCSIDriver sources.
28: *
29: * Set tabs every 4 characters.
30: *
31: * Apple96Chip.m - Chip-specific methods for Apple96 SCSI driver.
32: *
33: * Edit History
34: * 1997.02.18 MM Initial conversion from AMDPCSCSIDriver sources.
35: * 1997.04.17 MM Removed SCS_PHASECHANGE (not needed)
36: * 1997.06.24 MM Radar 1669736 - correctly store autosense status
37: * 1997.09.10 MM Radar 1678545 - Don't clear the gBusBusy flag until we
38: * get a "disconnected" interrupt.
39: */
40: #import "Apple96SCSI.h"
41: #import "Apple96BusState.h"
42: #import "Apple96SCSIPrivate.h"
43: #import "Apple96CurioPublic.h"
44: #import "Apple96CurioPrivate.h"
45: #import "Apple96CurioDBDMA.h"
46: #import "Apple96HWPrivate.h"
47: #import "Apple96ISR.h"
48: #import "MacSCSICommand.h"
49: #import "bringup.h"
50: #import <driverkit/generalFuncs.h>
51: #import <kernserv/prototypes.h>
52:
53: #define IO_R_BV 0xDEADBEEF /* TEMP */
54:
55: extern IONamedValue scsiMsgValues[]; /* In Apple96ISR.m */
56:
57: @implementation Apple96_SCSI(BusState)
58: /*
59: * Disconnected - only legal event here is reselection.
60: * [self fsmHandleReselectionInterrupt] may set gBusState to SCS_INITIATOR
61: */
62: - (void) fsmDisconnected
63: {
64: UInt8 selectByte;
65: UInt8 target;
66:
67: ENTRY("Bdi fsmDisconnected");
68: ddmChip("fsmDisconnected\n", 1,2,3,4,5);
69: if ((gSaveInterrupt & iReselected) != 0) {
70: [self fsmHandleReselectionInterrupt];
71: }
72: else if ((gSaveInterrupt & (iSelected | iSelectWAtn)) != 0) {
73: /*
74: * To do: allow selection by an external target and support
75: * a few mandatory commands:
76: * (PowerUp: gPendingTargetError = Unit Attention)
77: * Inquiry We're a CPU
78: * Test Unit Ready:
79: * if (gPendingTargetError == Unit Attention)
80: * Check Condition
81: * else {
82: * Success
83: * }
84: * All others gPendingTargetError := Illegal Command.
85: * Check Condition
86: * Request Sense: Send current error, clear current error.
87: */
88: SynchronizeIO();
89: selectByte = CURIOgetFifoByte();
90: selectByte &= ~gInitiatorIDMask;
91: for (target = 0; target < 8; target++) {
92: if ((selectByte & (1 << target)) != 0) {
93: break;
94: }
95: }
96: IOLog("%s: Selected by external target %d -- not supported\n",
97: [self name],
98: target
99: );
100: CURIOdisconnect();
101: }
102: else if (gFlagBusBusy == FALSE) {
103: /*
104: * disconnect interrupted while disconnected
105: * This always happens when we finish an I/O request.
106: * gFlagBusBusy is cleared when the "bus disconnected" bit
107: * is set in the NCR 53C96 interrupt register.
108: */
109: }
110: else {
111: /*
112: * Since we're disconnected, just ignore the interrupt
113: */
114: if (gActiveCommand != NULL
115: && gActiveCommand->scsiReq != NULL
116: && gActiveCommand->scsiReq->driverStatus == SR_IOST_INVALID) {
117: #if 0 /* Radar 1678545 */
118: IOLog("fsmDisconnected: timeout, target %d, int %02x, status %02x, step %02x\n",
119: gActiveCommand->scsiReq->target,
120: gSaveInterrupt & 0xFF,
121: gSaveStatus & 0xFF,
122: gSaveSeqStep & 0xFF
123: );
124: #endif
125: gActiveCommand->scsiReq->driverStatus = SR_IOST_SELTO;
126: }
127: if (gActiveCommand != NULL) {
128: [self ioComplete
129: : gActiveCommand
130: finalStatus : SR_IOST_INVALID
131: ];
132: }
133: gCurrentBusPhase = kBusPhaseBusFree;
134: }
135: EXIT();
136: }
137:
138: /*
139: * This state is called when we expect to disconnect from a target after
140: * receiving a Command Complete, Disconnect, or Abort message and the bus
141: * is still busy on exit from the finite state automaton (because
142: * curioQuickCheckForBusFree returned false).
143: */
144: - (void) fsmWaitForBusFree
145: {
146: if ((gSaveInterrupt & (iReselected | iSelected | iSelectWAtn)) != 0) {
147: /*
148: * Hmm, we went straight from command completion to (presumably)
149: * reselection. Treat it as a normal selection/reselection
150: * interrupt from "disconnected" state. (This is an abuse of
151: * the finite-state automaton design.)
152: */
153: [self fsmDisconnected];
154: }
155: else if (gFlagBusBusy == FALSE) {
156: /*
157: * This is expected: the bus has just gone free after a command
158: * completed. We can now safely try to start another command.
159: */
160: gBusState = SCS_DISCONNECTED;
161: }
162: else {
163: /*
164: * This is strange. It may not be an error, but I don't know
165: * if there are other legal bus states after disconnect
166: * (the one counter example would be after a linked command
167: * when the target goes to Command phase, but we should have
168: * rejected this at command complete.
169: */
170: [self fsmStartErrorRecovery
171: : SR_IOST_HW
172: reason : "Unexpected interrupt when disconnecting"
173: ];
174: }
175: }
176:
177: /*
178: * This is called from fsmDisconnected when we receive a reselected interrupt.
179: */
180: - (void) fsmHandleReselectionInterrupt
181: {
182: UInt8 selectByte;
183: UInt32 fifoDepth;
184: UInt8 msgByte;
185: IOReturn ioReturn;
186: const char *reason = NULL;
187:
188: ENTRY("Bre fsmHandleReselectionInterrupt");
189: /*
190: * Make sure there's a selection byte and an identify message in the fifo.
191: */
192: ioReturn = IO_R_SUCCESS;
193: gFlagBusBusy = ((gSaveInterrupt & iDisconnect) == 0); /* Radar 1678545 */
194: SynchronizeIO();
195: fifoDepth = CURIOgetFifoCount();
196: ddmChip("reselect: fifoDepth %d\n", fifoDepth, 2,3,4,5);
197: if (fifoDepth != 2) {
198: ddmError("reselection, fifoDepth %d\n", fifoDepth,
199: 2,3,4,5);
200: #if LOG_ERROR_RECOVERY
201: IOLog("%s: Bad FIFO count (%d) (expect 2) on Reselect\n",
202: [self name],
203: fifoDepth
204: );
205: #endif /* LOG_ERROR_RECOVERY */
206: ioReturn = SR_IOST_HW;
207: reason = "Bad FIFO count on reselect";
208: }
209: if (ioReturn == IO_R_SUCCESS) {
210: SynchronizeIO();
211: selectByte = CURIOgetFifoByte();
212: ddmChip("reselection: select byte %02x\n", selectByte, 2, 3, 4, 5);
213: ioReturn = [self getReselectionTargetID : selectByte];
214: if (ioReturn != IO_R_SUCCESS) {
215: reason = "Bad selection value on reselect";
216: }
217: }
218: if (ioReturn == IO_R_SUCCESS) {
219: /*
220: * gCurrentTarget has the bus ID of the target that is reselecting.
221: * The first message byte must be an Identify with the LUN.
222: */
223: SynchronizeIO();
224: msgByte = CURIOgetFifoByte();
225: if ((gSaveStatus & sParityErr) != 0) {
226: ioReturn = SR_IOST_PARITY;
227: reason = "Parity error on reselect";
228: }
229: }
230: if (ioReturn == IO_R_SUCCESS) {
231: if ((msgByte & kScsiMsgIdentify) == 0) {
232: ioReturn = SR_IOST_BV;
233: reason = "Bad ID Message (no identify) on reselect";
234: }
235: gCurrentLUN = msgByte & ~kScsiMsgIdentify;
236: /* gFlagBusBusy = TRUE; -- Radar 1678545: move to method start */
237: gBusState = SCS_RESELECTING;
238: /*
239: * At this point, the chip is waiting for us to validate
240: * the identify message. While we have a target and LUN,
241: * we don't have a command to reconnect to (that's the
242: * job of fsmReselectionAction).
243: *
244: * In case of sync mode, we need to load target context right
245: * now, before dropping ACK, because the target might go
246: * straight to a data in or data out as soon as ACK drops.
247: */
248: CURIOmessageAccept(); /* Accept the identify message */
249: ddmChip("Successful reselect from %d.%d\n",
250: gCurrentTarget,
251: gCurrentLUN,
252: 3, 4, 5
253: );
254: }
255: if (ioReturn != IO_R_SUCCESS) {
256: [self fsmStartErrorRecovery
257: : ioReturn
258: reason : reason
259: ];
260: }
261: EXIT();
262: }
263:
264: /*
265: * One of three things can happen here - the selection could succeed (though
266: * with possible incomplete message out), it could time out, or we can be
267: * reselected.
268: */
269: - (void) fsmSelecting
270: {
271: IOReturn ioReturn;
272: UInt8 fifoDepth;
273: CommandBuffer *cmdBuf;
274: IOSCSIRequest *scsiReq = NULL;
275: const char *reason = NULL;
276:
277: ENTRY("Bse fsmSelecting");
278: ddmChip("fsmSelecting\n", 1,2,3,4,5);
279: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
280: scsiReq = gActiveCommand->scsiReq;
281: ioReturn = IO_R_SUCCESS;
282: gFlagBusBusy = ((gSaveInterrupt & iDisconnect) == 0);
283: if (gFlagBusBusy == FALSE) {
284: /*
285: * selection timed-out. Abort this request.
286: */
287: ddmChip("***SELECTION TIMEOUT for target %d.%d\n",
288: scsiReq->target,
289: scsiReq->lun,
290: 3,4,5
291: );
292: CURIOflushFifo();
293: gBusState = SCS_DISCONNECTED;
294: #if 0 /* Radar 1678545 */
295: IOLog("fsmSelecting: timeout, target %d, int %02x, status %02x, step %02x\n",
296: gActiveCommand->scsiReq->target,
297: gSaveInterrupt & 0xFF,
298: gSaveStatus & 0xFF,
299: gSaveSeqStep & 0xFF
300: );
301: #endif
302: [self ioComplete
303: : gActiveCommand
304: finalStatus : SR_IOST_SELTO
305: ];
306: gActiveCommand = NULL;
307: }
308: else if (gSaveInterrupt == (iFuncComp | iBusService)) {
309: ddmChip("selection seqstep=%d\n",
310: gSaveSeqStep & INS_STATE_MASK, 2,3,4,5);
311: switch (gSaveSeqStep & INS_STATE_MASK) {
312: case 0:
313: /*
314: * No message phase. If we really wanted one,
315: * this could be significant...
316: */
317: if (gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) {
318: /*
319: * This target can't do command queueing.
320: */
321: [self disableMode : kTargetModeCmdQueue];
322: /*
323: * Clear the queue tag so we don't get here on
324: * an eventual autosense.
325: */
326: gActiveCommand->queueTag = QUEUE_TAG_NONTAGGED;
327: }
328: /*
329: * OK, let's try to continue following phase changes.
330: */
331: gBusState = SCS_INITIATOR;
332: break;
333: case 3: /* didn't complete cmd phase, parity? */
334: case 4: /* everything worked */
335: case 1: /* everything worked, SCMD_SELECT_ATN_STOP case */
336: /*
337: * We're connected. Start following the target's phase
338: * changes.
339: *
340: * If we're trying to do sync negotiation,
341: * this is the place to do it. In that case, we
342: * sent a SCMD_SELECT_ATN_STOP command, and
343: * ATN is now asserted (and we're hopefully in
344: * msg out phase). We want to send 5 bytes.
345: * Drop them into currMsgOut[] and prime the
346: * msgOutState machine.
347: */
348: gBusState = SCS_INITIATOR;
349: break;
350: case 2:
351: /*
352: * Either no command phase, or incomplete message
353: * transfer.
354: */
355: SynchronizeIO();
356: fifoDepth = CURIOgetFifoCount();
357: #if LOG_ERROR_RECOVERY
358: IOLog("%s: Incomplete select (step 2); fifoDepth %d phase %s\n",
359: [self name],
360: fifoDepth,
361: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues)
362: );
363: #endif /* LOG_ERROR_RECOVERY */
364: if (gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) {
365: /*
366: * This target can't do command queueing.
367: */
368: [self disableMode : kTargetModeCmdQueue];
369: }
370: /*
371: * Spec says ATN is asserted if all message bytes
372: * were not sent.
373: */
374: if (fifoDepth > gActiveCommand->cdbLength) {
375: CURIOclearATN();
376: }
377: /*
378: * 970611: clear the fifo. If we don't do this and the
379: * target is entering MSGI phase (trying to send us a
380: * Message Reject), it will sit on top of the fifo, and
381: * we'll read garbage from the fifo.
382: */
383: CURIOflushFifo(); /* The command is still in the fifo */
384: /*
385: * OK, let's try to continue following phase changes.
386: */
387: gBusState = SCS_INITIATOR;
388: break;
389: default:
390: /* gFlagBusBusy = TRUE; -- Radar 1678545 */
391: ioReturn = SR_IOST_HW;
392: reason = "Selection sequence Error (strange state)";
393: break;
394: }
395: }
396: else if ((gSaveInterrupt & iReselected) != 0) {
397: /*
398: * We were reselected while trying to do a selection.
399: * Enqueue this cmdBuf on the HEAD of pendingQ, then deal
400: * with the reselect.
401: * Tricky case, we have to "deactivate" this command
402: * since this hardwareStart attempt failed.
403: */
404: cmdBuf = gActiveCommand;
405: // [ self deactivateCmd ]; // mlj - done by pushbackCurrentRequest
406: [self pushbackCurrentRequest : cmdBuf];
407: ddmChip("reselect while trying to select target %d.%d\n",
408: scsiReq->target,
409: scsiReq->lun,
410: 3,4,5
411: );
412: gBusState = SCS_DISCONNECTED;
413: /*
414: * Go deal with reselect.
415: */
416: [self fsmDisconnected];
417: }
418: else if (gSaveInterrupt == iFuncComp
419: && (gSaveSeqStep & INS_STATE_MASK) == 2
420: && (gSaveStatus & mPhase) == kBusPhaseMSGI
421: && (gLastMsgOut[0] & kScsiMsgIdentify) == kScsiMsgIdentify
422: && (gLastMsgOut[0] & 0x07) != 0) {
423: /*
424: * This shouldn't happen according to the NCR documentation,
425: * but we saw it if the bus scanner executes INQUIRY on
426: * a non-zero LUN on an Apple CD-300. The CD is sending a
427: * Message Reject to our Identify message byte. We'll
428: * handle this in the Message In code.
429: */
430: gBusState = SCS_INITIATOR;
431: }
432: else {
433: ioReturn = SR_IOST_HW;
434: reason = "Bogus select/reselect interrupt";
435: }
436: if (ioReturn != IO_R_SUCCESS) {
437: [self fsmStartErrorRecovery
438: : ioReturn
439: reason : "Error selecting target"
440: ];
441: }
442: EXIT();
443: }
444:
445: /*
446: * This is a dummy interrupt service state that we enter after selection
447: * when the previous Curio operation has no interrupt-service completion
448: * requirement. For example, we can get here after a Message Out or
449: * reselection. Nothing happens here; we continue at fsmPhaseChange.
450: */
451: - (void) fsmInitiator
452: {
453: ENTRY("Bin fsmInitiator");
454: ddmChip("fsmInitiator\n", 1,2,3,4,5);
455: gBusState = SCS_INITIATOR;
456: EXIT();
457: }
458:
459: /*
460: * We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left is
461: * to drop ACK. Command Complete message is handled in fscAcceptingMsg.
462: * We can't go to SCS_DISCONNECTED until the target disconnects. If we
463: * go to "disconnected" state too soon, we'll encounter a load-dependent
464: * race condition that causes us to start another command before we've
465: * cleaned up from the last command. The actual state change is in
466: * fsmProcessMessage.
467: */
468: - (void) fsmCompleting
469: {
470: unsigned fifoDepth;
471: IOReturn ioReturn;
472: UInt8 statusByte;
473: const char *reason = NULL;
474:
475: ENTRY("Bco fsmCompleting");
476: ddmChip("fsmCompleting\n", 1,2,3,4,5);
477: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
478: ioReturn = IO_R_SUCCESS;
479: if ((gSaveInterrupt & iDisconnect) != 0) {
480: ddmError("unexpected disconnect\n", 1,2,3,4,5);
481: ioReturn = SR_IOST_HW;
482: reason = "I/O complete, bus free before target completion complete";
483: }
484: if (ioReturn == IO_R_SUCCESS) {
485: SynchronizeIO();
486: fifoDepth = CURIOgetFifoCount();
487: if ((gSaveInterrupt & iFuncComp) != 0) {
488: /*
489: * Got both status and msg in fifo; ACK is still asserted.
490: */
491: if (fifoDepth != 2) {
492: /*
493: * This is pretty bogus - we expect a status and
494: * msg in the fifo.
495: */
496: ioReturn = SR_IOST_HW;
497: reason = "I/O complete, incorrect fifo count (expecting two bytes)";
498: }
499: if (ioReturn == IO_R_SUCCESS) {
500: SynchronizeIO();
501: statusByte = CURIOgetFifoByte();
502: if (gActiveCommand->flagIsAutosense) { /* Radar 1669736 */
503: gActiveCommand->autosenseStatus = statusByte;
504: }
505: else {
506: gActiveCommand->scsiReq->scsiStatus = statusByte;
507: }
508: SynchronizeIO();
509: gMsgInBuffer[0] = CURIOgetFifoByte();
510: gMsgInIndex = 1;
511: ioReturn = [self fsmProcessMessage];
512: reason = "Message in failed";
513: }
514: }
515: else {
516: /*
517: * We only received a status byte. This can occur
518: * if we responded to the interrupt before the device
519: * successfully transmitted the Command Complete message.
520: * This is kind of weird, but let's try to handle it.
521: */
522: ddmError("fsmCompleting: status only on complete\n",
523: 1,2,3,4,5);
524: if (fifoDepth != 1) {
525: ioReturn = SR_IOST_HW;
526: reason = "I/O complete: incorrect fifo count (expecting one byte)";
527: }
528: if (gActiveCommand->flagIsAutosense) { /* Radar 1669736 */
529: SynchronizeIO();
530: gActiveCommand->autosenseStatus = CURIOgetFifoByte();
531: }
532: else {
533: SynchronizeIO();
534: gActiveCommand->scsiReq->scsiStatus = CURIOgetFifoByte();
535: }
536: /*
537: * Back to watching phase changes. Presumably, the target
538: * will switch to MSGI phase and complete the command
539: * at its leasure.
540: */
541: gBusState = SCS_INITIATOR;
542: }
543: }
544: if (ioReturn != IO_R_SUCCESS) {
545: [self fsmStartErrorRecovery
546: : ioReturn
547: reason : reason
548: ];
549: }
550: EXIT();
551: }
552:
553: /*
554: * DMA Complete.
555: */
556: - (void) fsmDMAComplete
557: {
558: unsigned bytesMoved;
559:
560: ENTRY("Bdc fsmDMAComplete");
561: ddmChip("fsmDMAComplete\n", 1,2,3,4,5);
562: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
563: /*
564: * Stop the dma engine and retrieve the total number of
565: * bytes transferred. This will be
566: * gActiveCommand->thisTransferLength The number of bytes requested
567: * - the current DMA residual count
568: * - the current FIFO residual count
569: * Note that there may still be bytes in the fifo.
570: */
571: bytesMoved = [self curioDMAComplete];
572: if ((gSaveStatus & sParityErr) != 0) {
573: [self fsmStartErrorRecovery
574: : SR_IOST_PARITY
575: reason : "SCSI Data Parity Error"
576: ];
577: }
578: else {
579: /*
580: * Continue following phase changes.
581: */
582: gBusState = SCS_INITIATOR;
583: }
584: EXIT();
585: }
586:
587: /*
588: * Just completed the SCMD_TRANSFER_INFO operation for message in. ACK is
589: * not asserted (we have not ACK'ed this byte). There is no parity error.
590: * We will not have a command if we're reselecting.
591: */
592: - (void) fsmGettingMsg
593: {
594: IOReturn ioReturn;
595: const char *reason = NULL;
596: UInt32 fifoCount;
597: UInt8 msgInByte;
598:
599: ENTRY("Bmi fsmGettingMsg");
600: ioReturn = IO_R_SUCCESS;
601: if (gFlagBusBusy == FALSE) {
602: ddmChip("fsmGettingMsg: message In Disconnect\n", 1,2,3,4,5);
603: /*
604: * This (non-fatal) error is handled on return...
605: */
606: ioReturn = IO_R_INTERNAL; /* Any non-zero non-fatal error status */
607: }
608: else {
609: SynchronizeIO();
610: fifoCount = CURIOgetFifoCount();
611: if (fifoCount != 1) {
612: ddmChip("Message in fifo count error, count = %d\n",
613: fifoCount,
614: 2, 3, 4, 5
615: );
616: ioReturn = SR_IOST_HW;
617: reason = "Message in fifo count error";
618: }
619: }
620: if (ioReturn == IO_R_SUCCESS) {
621: SynchronizeIO();
622: msgInByte = CURIOgetFifoByte();
623: if ((gSaveStatus & sParityErr) != 0) {
624: ioReturn = SR_IOST_PARITY;
625: reason = "Parity error getting Command Complete message";
626: }
627: }
628: if (ioReturn == IO_R_SUCCESS) {
629: if (gMsgInState == kMsgInIdle) {
630: gMsgInCount = 0;
631: gMsgInIndex = 0;
632: }
633: if (gMsgInIndex >= kMessageInBufferLength) {
634: ioReturn = SR_IOST_HW;
635: reason = "Message in too many bytes";
636: }
637: }
638: if (ioReturn == IO_R_SUCCESS) {
639: gMsgInBuffer[gMsgInIndex++] = msgInByte;
640: switch (gMsgInState) {
641: case kMsgInIdle:
642: /*
643: * This is the first message byte. Check for 1-byte codes.
644: */
645: ddmChip("fsmGettingMsg: msgByte = 0x%x (%s)\n",
646: msgInByte,
647: IOFindNameForValue(msgInByte, scsiMsgValues),
648: 3, 4, 5
649: );
650: if ((/* msgInByte >= kScsiMsgOneByteMin && */ msgInByte <= kScsiMsgOneByteMax)
651: || msgInByte >= kScsiMsgIdentify) {
652: gMsgInState = kMsgInReady;
653: }
654: else if (msgInByte >= kScsiMsgTwoByteMin
655: && msgInByte <= kScsiMsgTwoByteMax) {
656: /*
657: * This is a two-byte message. Set the count and
658: * read the next byte.
659: */
660: gMsgInState = kMsgInReading; /* Need one more */
661: gMsgInCount = 1;
662: }
663: else {
664: /*
665: * This is an extended message. The next byte has the count.
666: */
667: gMsgInState = kMsgInCounting;
668: }
669: break;
670: case kMsgInCounting:
671: /*
672: * Read the count byte of an extended message.
673: */
674: gMsgInCount = msgInByte;
675: gMsgInState = kMsgInReading;
676: break;
677: case kMsgInReading:
678: if (--gMsgInCount <= 0) {
679: gMsgInState = kMsgInReady;
680: }
681: break;
682: default:
683: ASSERT(gMsgInState != 0xDEADBEEF /* Bogus state */);
684: ioReturn = SR_IOST_BV;
685: reason = "Message in bogus state";
686: } /* Switch on message state */
687: }
688: if (ioReturn == IO_R_SUCCESS) {
689: switch (gMsgInState) {
690: case kMsgInReading:
691: case kMsgInCounting:
692: /*
693: * We have more message bytes to read. Accept this byte
694: * (this sets ACK) and setup to transfer the next byte.
695: */
696: CURIOmessageAccept();
697: /*
698: * Since the message accept command sets "interrupt", eat
699: * it here so we don't get a second interrupt.
700: */
701: CURIOquickCheckForChipInterrupt();
702: CURIOstartMSGIAction();
703: gBusState = SCS_GETTINGMSG;
704: /*
705: * This would be a good place to spin-wait for
706: * completion, continuing at the start of this
707: * method if there is another byte (and we're still
708: * in message in phase). Perhaps this method should
709: * return a "spinwait" status to the mainline FSM.
710: */
711: break;
712: case kMsgInReady:
713: gMsgInState = kMsgInIdle;
714: ioReturn = [self fsmProcessMessage];
715: if (ioReturn != IO_R_SUCCESS) {
716: reason = "Can't process received message";
717: }
718: break;
719: case kMsgInIdle:
720: default:
721: /*
722: * Hmm, that's strange: we should never be in idle state
723: * *after* successfully reading a message byte.
724: */
725: ioReturn = SR_IOST_BV;
726: reason = "Getting message: bogus idle state";
727: break;
728: }
729: }
730: if (ioReturn != IO_R_SUCCESS) {
731: [self fsmStartErrorRecovery
732: : ioReturn
733: reason : reason
734: ];
735: }
736: EXIT();
737: }
738:
739: /*
740: * Just finished a message in; ACK is false and the message has been read
741: * into gMsgInBuffer[0..gMsgInIndex]. We have not ACK'ed the last byte yet.
742: * If we fail here, the caller will start error recovery.
743: */
744: - (IOReturn) fsmProcessMessage
745: {
746: IOReturn ioReturn = IO_R_SUCCESS;
747: const char *reason = "(Unknown)";
748: UInt8 queueTag = QUEUE_TAG_NONTAGGED;
749: Boolean messageAckNeeded = TRUE;
750:
751: ENTRY("Bmp fsmProcessMessage");
752: RAW_TAG(OSTag('*', "msg"), gMsgInBuffer[0]);
753: /*
754: * Message in complete. Handle message(s) in currMsgIn[].
755: */
756: if (gBusState == SCS_RESELECTING) {
757: /*
758: * The only interesting message here is queue tag.
759: * (Hmm, what about target SDTR or Abort?)
760: */
761: ASSERT(gActiveCommand == NULL);
762: ASSERT(gCurrentTarget != kInvalidTarget && gCurrentLUN != kInvalidLUN);
763: ASSERT(gMsgInIndex > 0);
764: switch (gMsgInBuffer[0]) {
765: case kScsiMsgHeadOfQueueTag:
766: case kScsiMsgOrderedQueueTag:
767: case kScsiMsgSimpleQueueTag:
768: if (gMsgInIndex != 2) {
769: ioReturn = SR_IOST_HW;
770: reason = "Queue tag message: queue tag without tag value";
771: }
772: else {
773: ioReturn = [self reselectNexusWithTag : gMsgInBuffer[1]];
774: if (ioReturn != IO_R_SUCCESS) {
775: reason = "Tagged queue reselection failed to locate command";
776: }
777: }
778: break;
779: default:
780: ddmError("Strange message byte %02x from %d.%d while reselecting (expect tag)\n",
781: gMsgInBuffer[0],
782: gCurrentTarget,
783: gCurrentLUN,
784: 4, 5
785: );
786: ioReturn = SR_IOST_HW;
787: reason = "Reselection failed (expecting queue tag message)";
788: break;
789: }
790: if (ioReturn == IO_R_SUCCESS) {
791: ASSERT(gActiveCommand != NULL);
792: gActiveCommand->currentDataIndex = gActiveCommand->savedDataIndex;
793: if (gActiveCommand->mem != NULL) {
794: [gActiveCommand->mem setState : &gActiveCommand->savedDataState];
795: }
796: }
797: /*
798: * Since we process commands one by one, whack this command
799: * so we fall through the regular message handler.
800: */
801: gMsgInBuffer[0] = kScsiMsgNop;
802: gMsgInIndex = 1;
803: }
804: gBusState = SCS_INITIATOR;
805: gFlagNeedAnotherInterrupt = TRUE;
806:
807: switch (gMsgInBuffer[0]) {
808: case kScsiMsgNop:
809: break;
810: case kScsiMsgCmdComplete:
811: /*
812: * Normally, we get here from fsmCommandComplete. All we need
813: * to do is to ack the message and complete the command. Exit
814: * in a transitional bus state that becomes SCS_DISCONNECTED
815: * when the bus is no longer busy.
816: */
817: gBusState = SCS_WAIT_FOR_BUS_FREE;
818: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */
819: if (gActiveCommand != NULL) {
820: [self ioComplete
821: : gActiveCommand
822: finalStatus : SR_IOST_GOOD
823: ];
824: }
825: ASSERT(gActiveCommand == NULL);
826: break;
827:
828: case kScsiMsgDisconnect:
829: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
830: if (gActiveCommand->scsiReq->disconnect == FALSE) {
831: /*
832: * This is bogus; we could do a message reject, but
833: * ignoring it is simpler and, probably better.
834: */
835: ddmChip("Illegal disconnect for %d.%d\n",
836: gActiveCommand->scsiReq->target,
837: gActiveCommand->scsiReq->lun,
838: 3, 4, 5
839: );
840: #if LOG_ERROR_RECOVERY
841: IOLog("%s: Unexpected disconnect attempt from target %d.%d\n",
842: [self name],
843: gActiveCommand->scsiReq->target,
844: gActiveCommand->scsiReq->lun
845: );
846: #endif /* LOG_ERROR_RECOVERY */
847: }
848: else {
849: /*
850: * Some targets fail to do a restore pointers before
851: * disconnect if all requested data has been transferred.
852: * Do an implied save pointers if this is the case.
853: */
854: if ( gActiveCommand->currentDataIndex >= gActiveCommand->scsiReq->maxTransfer )
855: gActiveCommand->savedDataIndex = gActiveCommand->currentDataIndex;
856:
857: if ( gActiveCommand->mem != NULL )
858: [ gActiveCommand->mem state : &gActiveCommand->savedDataState ];
859: [ self disconnect ];
860: }
861: /*
862: * Exit the interrupt service routine so we don't miss a reselection interrupt.
863: */
864: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */
865: gBusState = SCS_WAIT_FOR_BUS_FREE;
866: gFlagCheckForAnotherInterrupt = FALSE;
867: break;
868: case kScsiMsgSaveDataPointers:
869: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
870: gActiveCommand->savedDataIndex = gActiveCommand->currentDataIndex;
871: if (gActiveCommand->mem != NULL) {
872: [gActiveCommand->mem state : &gActiveCommand->savedDataState];
873: }
874: break;
875: case kScsiMsgRestorePointers:
876: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
877: gActiveCommand->currentDataIndex = gActiveCommand->savedDataIndex;
878: if (gActiveCommand->mem != NULL) {
879: [gActiveCommand->mem setState : &gActiveCommand->savedDataState];
880: }
881: break;
882: case kScsiMsgRejectMsg:
883: /*
884: * Hmm, the only message reject we should see would have to be
885: * a queue tag (to a device that doesn't do queuing).
886: */
887: switch (gLastMsgOut[0]) {
888: case kScsiMsgHeadOfQueueTag:
889: case kScsiMsgOrderedQueueTag:
890: case kScsiMsgSimpleQueueTag:
891: [self disableMode : kTargetModeCmdQueue];
892: break;
893: default:
894: if (gLastMsgOut[0] >= kScsiMsgIdentify
895: && (gLastMsgOut[0] & 0x07) != 0) {
896: ddmError("Target %d.%d rejected Identify message %02x\n",
897: gCurrentTarget,
898: gCurrentLUN,
899: gLastMsgOut[0],
900: 4, 5
901: );
902: #if LOG_ERROR_RECOVERY
903: /*
904: * The target rejected an identify message for a non-zero
905: * LUN. We treat this as a selection failure and tell the
906: * target to get off the bus.
907: */
908: IOLog("%s: Target %d.%d rejected Identify message %02x\n",
909: [self name],
910: gCurrentTarget,
911: gCurrentLUN,
912: gLastMsgOut[0]
913: );
914: #endif /* LOG_ERROR_RECOVERY */
915: /*
916: * When we send an Abort to a target, we expect that it
917: * will immediately go to bus free. Unfortunately, some
918: * targets go to MSGI and send us an Abort, too.
919: */
920: if (gActiveCommand != NULL) {
921: if (gActiveCommand->scsiReq != NULL
922: && gActiveCommand->scsiReq->driverStatus == SR_IOST_INVALID) {
923: #if 0
924: IOLog("fsmProcessMsg abort: timeout, target %d, int %02x, status %02x, step %02x\n",
925: gActiveCommand->scsiReq->target,
926: gSaveInterrupt & 0xFF,
927: gSaveStatus & 0xFF,
928: gSaveSeqStep & 0xFF
929: );
930: #endif
931: gActiveCommand->scsiReq->driverStatus = SR_IOST_SELTO;
932: }
933: /* [self ioComplete : gActiveCommand]; 970610 */
934: }
935: }
936: else {
937: ddmError("%s Message rejected from target %d.%d\n",
938: IOFindNameForValue(gLastMsgOut[0], scsiMsgValues),
939: gCurrentTarget,
940: gCurrentLUN,
941: 4, 5
942: );
943: #if LOG_ERROR_RECOVERY
944: IOLog("%s: %s Message Rejected, that's strange.\n",
945: [self name],
946: IOFindNameForValue(gLastMsgOut[0], scsiMsgValues)
947: );
948: #endif /* LOG_ERROR_RECOVERY */
949: ioReturn = SR_IOST_HW; /* 970610 */
950: }
951: /* ioReturn = SR_IOST_HW; 970610 */
952: break;
953: }
954: case kScsiMsgAbort:
955: case kScsiMsgAbortTag:
956: if (gActiveCommand != NULL && gActiveCommand->scsiReq != NULL) {
957: /*
958: * Oops: something is terribly wrong with this command.
959: * This can happen if we get a parity error, set ATN,
960: * and send an inititor detected error to the target.
961: */
962: if (gCurrentTarget != kInvalidTarget) {
963: ddmError("Target %d.%d aborted request\n",
964: gCurrentTarget,
965: gCurrentLUN,
966: 3, 4, 5
967: );
968: #if LOG_ERROR_RECOVERY
969: IOLog("%s: Target %d.%d aborted request\n",
970: [self name],
971: gCurrentTarget,
972: gCurrentLUN
973: );
974: #endif /* LOG_ERROR_RECOVERY */
975: }
976: [self ioComplete
977: : gActiveCommand
978: finalStatus : SR_IOST_HW
979: ];
980: gFlagCheckForAnotherInterrupt = FALSE;
981: ASSERT(gActiveCommand == NULL);
982: }
983: /*
984: * After receiving an Abort, the target will go free
985: */
986: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */
987: gBusState = SCS_WAIT_FOR_BUS_FREE;
988: break;
989: case kScsiMsgLinkedCmdComplete:
990: case kScsiMsgLinkedCmdCompleteFlag:
991: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
992: /*
993: * These are impossible: we reject commands with the link bit set.
994: * About all we can do is to fail the client's command and
995: * stagger onwards.
996: */
997: IOLog("%s: Target %d.%d terminated with unexpected linked command complete\n",
998: [self name],
999: gActiveCommand->scsiReq->target,
1000: gActiveCommand->scsiReq->lun
1001: );
1002: [self ioComplete
1003: : gActiveCommand
1004: finalStatus : SR_IOST_HW
1005: ];
1006: ASSERT(gActiveCommand == NULL);
1007: /* gFlagBusBusy = FALSE; -- Radar 1678545: wait for interrupt */
1008: gBusState = SCS_WAIT_FOR_BUS_FREE;
1009: break;
1010: case kScsiMsgExtended:
1011: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1012: /*
1013: * The only expected extended message is synchronous negotiation.
1014: * We don't support this yet.
1015: */
1016: switch (gMsgInBuffer[2]) {
1017: case kScsiMsgSyncXferReq:
1018: /*
1019: * We don't support SDTR (yet), so send a message reject
1020: * (Perhaps it would be better to send an "async only" response,
1021: * but message reject is legal.)
1022: */
1023: CURIOmessageReject();
1024: messageAckNeeded = FALSE;
1025: break;
1026: default:
1027: ddmError("Unexpected Extended Message (0x%x) received"
1028: "from target %d.%d\n",
1029: gMsgInBuffer[2],
1030: gActiveCommand->scsiReq->target,
1031: gActiveCommand->scsiReq->lun,
1032: 4, 5
1033: );
1034: CURIOmessageReject();
1035: messageAckNeeded = FALSE;
1036: break;
1037: }
1038: break;
1039: default:
1040: /*
1041: * all others are unacceptable.
1042: */
1043: ddmError("Unsupported message (0x%x) received"
1044: " from target %d.%d \n",
1045: gMsgInBuffer[0],
1046: gCurrentTarget,
1047: gCurrentLUN,
1048: 4, 5
1049: );
1050: CURIOmessageReject();
1051: messageAckNeeded = FALSE;
1052: } /* Message byte switch */
1053: if (messageAckNeeded) {
1054: CURIOmessageAccept();
1055: }
1056: if (ioReturn != IO_R_SUCCESS && gCurrentTarget != kInvalidTarget) {
1057: ddmError("Message from target %d.%d failed: %s\n",
1058: gCurrentTarget,
1059: gCurrentLUN,
1060: reason,
1061: 4, 5
1062: );
1063: }
1064: RESULT(ioReturn);
1065: return (ioReturn);
1066: }
1067:
1068: /*
1069: * This writes the message byte into the staging buffer. When the target
1070: * cycles to MSGO phase, we will send the message from the state automaton.
1071: */
1072: - (void) putMessageOutByte
1073: : (UInt8) messageByte
1074: setATN : (Boolean) setATN
1075: {
1076: ENTRY("Bmo putMessageOutByte");
1077: ASSERT(gMsgOutPtr < &gMsgOutBuffer[kMessageOutBufferLength]);
1078: ASSERT(gMsgPutPtr <= gMsgOutPtr);
1079: *gMsgOutPtr++ = messageByte;
1080: if (setATN) {
1081: CURIOsetATN();
1082: }
1083: EXIT();
1084: }
1085:
1086: /*
1087: * Just completed the SCMD_TRANSFER_INFO operation for message out.
1088: */
1089: - (void) fsmSendingMsg
1090: {
1091: ENTRY("Bms fsmSendingMsg");
1092: ddmChip("fsmSendingMsg\n", 1,2,3,4,5);
1093: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1094: EXIT();
1095: }
1096:
1097: /*
1098: * Just completed the SCMD_TRANSFER_INFO operation for command.
1099: */
1100: - (void) fsmSendingCmd
1101: {
1102: ENTRY("Bmc fsmSendingCmd");
1103: ddmChip("fsmSendingCmd\n", 1,2,3,4,5);
1104: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1105: gBusState = SCS_INITIATOR;
1106: EXIT();
1107: }
1108:
1109: /*
1110: * Continue to process reselection interrupts. We expect to be in
1111: * message in phase in order to get the tagged queue message. Anything
1112: * else is an error.
1113: */
1114: - (void) fsmReselecting
1115: {
1116: ENTRY("Bre fsmReselecting");
1117:
1118: [self fsmGettingMsg];
1119: if (gBusState == SCS_GETTINGMSG) {
1120: gBusState = SCS_RESELECTING; /* continue at fsmReselectinAction */
1121: }
1122: EXIT();
1123: }
1124:
1125: /*
1126: * Complete the processing of a reselection interrupt. We have just ack'ed
1127: * the identify message. Try to find the command that corresponds to this
1128: * target.lun (without a queue tag). If we're successful, complete the
1129: * reselection and start following phases by calling fsmPhaseChange directly.
1130: * If the first disconnected command has a non-zero tag queue, we expect to
1131: * be in messsage in phase, and will receive a tagged queue message in the
1132: * fullness of time.
1133: */
1134: - (void) fsmReselectionAction
1135: {
1136: IOReturn ioReturn;
1137:
1138: ENTRY("Bra fsmReselectionAction");
1139: ioReturn = [self reselectNexusWithoutTag];
1140: if (ioReturn == IO_R_SUCCESS) {
1141: /*
1142: * We have successfully reselected this target.
1143: * Vamp until the target tells us what to do next.
1144: */
1145: // [self fsmPhaseChange]; // mlj ???
1146: gBusState = SCS_INITIATOR;
1147: }
1148: else {
1149: /*
1150: * We don't have a nexus yet. If we're in MSGI phase,
1151: * continue grabbing message bytes until we receive
1152: * a queue tag message (we might receive an SDTR),
1153: * continuing at fsmReselecting to process interrupts.
1154: */
1155: gCurrentBusPhase = gSaveStatus & mPhase;
1156: // [curioQuickCheckForChipInterrupt];
1157: if (gCurrentBusPhase == kBusPhaseMSGI) {
1158: CURIOstartMSGIAction();
1159: }
1160: else {
1161: /*
1162: * We're in the wrong phase. Bail out.
1163: */
1164: [self fsmStartErrorRecovery
1165: : ioReturn
1166: reason : "Unexpected SCSI bus phase while reselecting"
1167: ];
1168: }
1169: }
1170: EXIT();
1171: }
1172:
1173:
1174: /*
1175: * Follow SCSI Phase change. Called while SCS_INITIATOR.
1176: */
1177: - (void) fsmPhaseChange
1178: {
1179: int i;
1180:
1181: ENTRY("Bph fsmPhaseChange");
1182: ddmChip("fsmPhaseChange, target %d.%d\n",
1183: gCurrentTarget,
1184: gCurrentLUN,
1185: 3, 4, 5
1186: );
1187: gCurrentBusPhase = gSaveStatus & mPhase;
1188: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1189: ASSERT(gCurrentTarget == gActiveCommand->scsiReq->target);
1190: ASSERT(gCurrentLUN == gActiveCommand->scsiReq->lun);
1191: ddmChip("fsmPhaseChange: phase = %s\n",
1192: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues),
1193: 2,3,4,5
1194: );
1195: switch (gCurrentBusPhase) {
1196: case kBusPhaseCMD:
1197: /*
1198: * The normal case here is after a host-initiated SDTR sequence.
1199: */
1200: CURIOflushFifo();
1201: CURIOputCommandIntoFifo();
1202: CURIOstartNonDMATransfer();
1203: gMsgInState = kMsgInIdle;
1204: gBusState = SCS_SENDINGCMD;
1205: break;
1206: case kBusPhaseDATI: /* From target to Initiator (read) */
1207: case kBusPhaseDATO: /* To Target from Initiator (write) */
1208: gMsgInState = kMsgInIdle;
1209: [self fsmStartDataPhase];
1210: gFlagCheckForAnotherInterrupt = FALSE;
1211: break;
1212: case kBusPhaseSTS: /* Status from Target to Initiator */
1213: /*
1214: * fsmCompleting will collect the STATUS byte (and hopefully
1215: * a MSG) from the fifo when this completes.
1216: */
1217: gMsgInState = kMsgInIdle;
1218: gBusState = SCS_COMPLETING;
1219: CURIOflushFifo();
1220: CURIOinitiatorCommandComplete();
1221: break;
1222: case kBusPhaseMSGI: /* Message from Target to Initiator */
1223: gBusState = SCS_GETTINGMSG;
1224: CURIOstartMSGIAction();
1225: break;
1226: case kBusPhaseMSGO: /* Message from Initiator to Target */
1227: gMsgInState = kMsgInIdle;
1228: CURIOflushFifo();
1229: if (gMsgPutPtr == gMsgOutPtr) {
1230: /*
1231: * Hmm, there is no message waiting to be sent.
1232: */
1233: *gMsgOutPtr++ = kScsiMsgNop;
1234: ddmChip("msg out (%d.%d): forced nop\n",
1235: gCurrentTarget,
1236: gCurrentLUN,
1237: 3, 4, 5
1238: );
1239: }
1240: for (i = 0; i < 16 && gMsgPutPtr < gMsgOutPtr; i++) {
1241: ddmChip("msg out[%d] = %02x\n", i, *gMsgPutPtr, 3, 4, 5);
1242: CURIOputByteIntoFifo(*gMsgPutPtr);
1243: gMsgPutPtr++;
1244: }
1245: if (gMsgPutPtr == gMsgOutPtr) {
1246: gMsgPutPtr = gMsgOutPtr = gMsgOutBuffer;
1247: }
1248: gBusState = SCS_SENDINGMSG;
1249: /*
1250: * ATN is automatically cleared when transfer info completes.
1251: */
1252: CURIOstartNonDMATransfer();
1253: break;
1254: default:
1255: [self fsmStartErrorRecovery
1256: : SR_IOST_HW
1257: reason : "Strange bus phase"
1258: ];
1259: break;
1260: }
1261: EXIT();
1262: }
1263:
1264: - (void) fsmStartDataPhase
1265: {
1266: UInt32 phase;
1267: IOReturn ioReturn = IO_R_SUCCESS;
1268: const char *reason = NULL;
1269: Boolean isReadOK;
1270:
1271:
1272: ENTRY("Bdp startDataPhase");
1273: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1274: phase = gSaveStatus & mPhase;
1275: /*
1276: * Data in phase is legal if this is a read command or we're
1277: * doing autosense.
1278: */
1279: isReadOK = (gActiveCommand->scsiReq->read || gActiveCommand->flagIsAutosense);
1280: if ((phase == kBusPhaseDATI) != isReadOK) {
1281: ioReturn = SR_IOST_BV;
1282: reason = "bad I/O direction";
1283: }
1284: if (ioReturn == IO_R_SUCCESS) {
1285: ioReturn = [self hardwareInitializeCCL];
1286: if (ioReturn != IO_R_SUCCESS) {
1287: reason = "Cannot setup DBDMA Channel Command area";
1288: }
1289: }
1290: if (ioReturn == IO_R_SUCCESS) {
1291: if (gActiveCommand->thisTransferLength == 0) {
1292: ioReturn = IO_R_BV;
1293: reason = "No data for transfer";
1294: }
1295: }
1296: if (ioReturn == IO_R_SUCCESS) {
1297: DBDMASetCommandPtr((UInt32) gDBDMAChannelAddress);
1298: DBDMAstartTransfer();
1299: CURIOstartDMATransfer(gActiveCommand->thisTransferLength);
1300: gBusState = SCS_DMACOMPLETE;
1301: }
1302: if (ioReturn != IO_R_SUCCESS) {
1303: [self fsmStartErrorRecovery
1304: : ioReturn
1305: reason : "Illegal Data Phase (wrong direction or length error)"
1306: ];
1307: }
1308: EXIT();
1309: }
1310:
1311: /*
1312: * Start error recovery by doing something reasonable for the current bus
1313: * phase. This is called when we enter error recovery (SCS_DEATH_MARCH)
1314: * from an interrupt or other bus phase action handler.
1315: */
1316: - (void) fsmStartErrorRecovery
1317: : (sc_status_t) status
1318: reason : (const char *) reason
1319: {
1320: ENTRY("Bes fsmStartErrorRecovery");
1321: TAG(__tag__, status);
1322: ddmChip("fsmStartErrorRecovery for %d.%d, phase \"%s\", status \"%s\": %s\n",
1323: gCurrentTarget,
1324: gCurrentLUN,
1325: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues),
1326: IOFindNameForValue(status, IOScStatusStrings),
1327: (reason == NULL) ? "unspecified" : reason
1328: );
1329: #if LOG_ERROR_RECOVERY
1330: if (gActiveCommand != NULL
1331: && gActiveCommand->scsiReq != NULL
1332: && gActiveCommand->scsiReq->target == gCurrentTarget
1333: && gActiveCommand->scsiReq->lun == gCurrentLUN) {
1334: IOLog("%s: Error recovery: active target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n",
1335: [self name],
1336: gCurrentTarget,
1337: gCurrentLUN,
1338: IOFindNameForValue(status, IOScStatusStrings),
1339: (reason == NULL) ? "no further explanation" : reason,
1340: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues)
1341: );
1342: }
1343: else if (gActiveCommand != NULL && gActiveCommand->scsiReq != NULL) {
1344: IOLog("%s: Error recovery: command target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n",
1345: [self name],
1346: gActiveCommand->scsiReq->target,
1347: gActiveCommand->scsiReq->lun,
1348: IOFindNameForValue(status, IOScStatusStrings),
1349: (reason == NULL) ? "no further explanation" : reason,
1350: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues)
1351: );
1352: }
1353: else if (gCurrentTarget != kInvalidTarget && gCurrentLUN != kInvalidLUN) {
1354: IOLog("%s: Error Recovery: expected target %d.%d, error \"%s\" (\"%s\"), bus phase %s\n",
1355: [self name],
1356: gCurrentTarget,
1357: gCurrentLUN,
1358: IOFindNameForValue(status, IOScStatusStrings),
1359: (reason == NULL) ? "no further explanation" : reason,
1360: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues)
1361: );
1362: }
1363: else if (gCurrentTarget != kInvalidTarget && gCurrentLUN == kInvalidLUN) {
1364: IOLog("%s: Error recovery: command target %d.[no lun], error \"%s\" (\"%s\"), bus phase %s\n",
1365: [self name],
1366: gCurrentTarget,
1367: IOFindNameForValue(status, IOScStatusStrings),
1368: (reason == NULL) ? "no further explanation" : reason,
1369: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues)
1370: );
1371: }
1372: else {
1373: IOLog("%s: Error recovery: no current target, error \"%s\" (\"%s\"), bus phase %s\n",
1374: [self name],
1375: IOFindNameForValue(status, IOScStatusStrings),
1376: (reason == NULL) ? "no further explanation" : reason,
1377: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues)
1378: );
1379: }
1380: [self logRegisters : FALSE reason : "At error recovery start"];
1381: #endif /* LOG_ERROR_RECOVERY */
1382: [self killActiveCommand : status];
1383: /*
1384: * Clean out the scsi and dbdma chips
1385: */
1386: CURIOflushFifo();
1387: CURIOclearTransferCountZeroBit();
1388: DBDMAreset();
1389: if (gFlagBusBusy == FALSE) {
1390: gBusState = SCS_DISCONNECTED;
1391: }
1392: else {
1393: /*
1394: * We will continue at fsmContinueErrorRecovery
1395: */
1396: gBusState = SCS_DEATH_MARCH;
1397: }
1398: gFlagCheckForAnotherInterrupt = FALSE;
1399: EXIT();
1400: }
1401:
1402: /*
1403: * Manage error recovery by responding to a target interrupt while in
1404: * an error recovery state. On exit, the bus state will be as follows:
1405: * SCS_DEATH_MARCH Still in error recovery. Call fsmContinueErrorRecovery
1406: * to continue processing target requests.
1407: * SCS_DISCONNECTED The target is finally off the bus. We can restart
1408: * normal operation.
1409: * Each bus phase requires a different action:
1410: * Data Out Clean up after DMA.
1411: * Data In Clean up after DMA.
1412: * Command Flush the fifo
1413: * Status Drain the fifo, if we get two bytes, just ACK the message
1414: * Message Out Do nothing
1415: * Message In Read the message byte, ACK it.
1416: */
1417: - (void) fsmErrorRecoveryInterruptService
1418: {
1419: ENTRY("Bei fsmErrorRecoveryInterruptService");
1420: #if LOG_ERROR_RECOVERY
1421: [self logRegisters : FALSE reason : "At error recovery interrupt"];
1422: IOLog("%s: Error recovery interrupt in bus phase %s, sts %02x, int %02x\n",
1423: [self name],
1424: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues),
1425: gSaveStatus,
1426: gSaveInterrupt
1427: );
1428: #endif
1429: CURIOflushFifo();
1430: switch (gCurrentBusPhase) {
1431: case kBusPhaseDATO:
1432: case kBusPhaseDATI:
1433: #if LOG_ERROR_RECOVERY
1434: IOLog("%s: Error recovery interrupt in data in/out phase\n", [self name]);
1435: #endif
1436: DBDMAreset();
1437: CURIOclearTransferCountZeroBit();
1438: break;
1439: case kBusPhaseCMD:
1440: #if LOG_ERROR_RECOVERY
1441: IOLog("%s: Error recovery interrupt in command phase\n", [self name]);
1442: #endif
1443: break;
1444: case kBusPhaseSTS:
1445: #if LOG_ERROR_RECOVERY
1446: IOLog("%s: Error recovery interrupt in status phase\n", [self name]);
1447: #endif
1448: if ((gSaveInterrupt & iFuncComp) != 0) {
1449: #if LOG_ERROR_RECOVERY
1450: IOLog("%s: Error recovery interrupt in status phase with complete msg\n",
1451: [self name]
1452: );
1453: #endif
1454: /*
1455: * We got both bytes: ACK the command complete
1456: */
1457: CURIOmessageAccept();
1458: }
1459: break;
1460: case kBusPhaseMSGO:
1461: #if LOG_ERROR_RECOVERY
1462: IOLog("%s: Error recovery interrupt in message out phase\n", [self name]);
1463: #endif
1464: break;
1465: case kBusPhaseMSGI:
1466: #if LOG_ERROR_RECOVERY
1467: IOLog("%s: Error recovery interrupt in message in phase\n", [self name]);
1468: #endif
1469: CURIOmessageAccept();
1470: break;
1471: case kBusPhaseBusFree: /* Selecting */
1472: #if LOG_ERROR_RECOVERY
1473: IOLog("%s: Error recovery interrupt at bus free\n", [self name]);
1474: #endif
1475: break;
1476: default:
1477: #if LOG_ERROR_RECOVERY
1478: IOLog("%s: Strange bus phase %d in error recovery\n",
1479: [self name],
1480: gCurrentBusPhase
1481: );
1482: #endif
1483: [self killActiveCommandAndResetBus
1484: : SR_IOST_HW
1485: reason : "Strange SCSI phase in error recovery interrupt"
1486: ];
1487: break;
1488: }
1489: EXIT();
1490: }
1491:
1492: /*
1493: * Continue to manage error recovery. We are here because the target
1494: * is still on the bus and doing strange bus phase things. Follow
1495: * the target bus phase (one phase at a time) until the target
1496: * disconnects. We just run bit-bucket commands until the target
1497: * gives up. (Note that this means that we might send a Command Complete
1498: * message to the target. We'll look for this case and send an Abort
1499: * or Abort Tag instead.)
1500: */
1501: - (void) fsmContinueErrorRecovery
1502: {
1503: UInt8 msgByte;
1504:
1505: ENTRY("Bec fsmContinueErrorRecovery");
1506: CURIOquickCheckForChipInterrupt();
1507: #if LOG_ERROR_RECOVERY
1508: IOLog("%s: Error recovery continues in bus phase %s, sts %02x, int %02x\n",
1509: [self name],
1510: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues),
1511: gSaveStatus,
1512: gSaveInterrupt
1513: );
1514: #endif
1515: if (gFlagBusBusy) {
1516: (void) CURIOinterruptPending();
1517: if ((gSaveInterrupt & iDisconnect) != 0) {
1518: gFlagBusBusy = FALSE;
1519: }
1520: }
1521: if (gFlagBusBusy == FALSE) {
1522: gBusState = SCS_DISCONNECTED;
1523: }
1524: else {
1525: gCurrentBusPhase = gSaveStatus & mPhase;
1526: switch (gCurrentBusPhase) {
1527: case kBusPhaseMSGO:
1528: msgByte = kScsiMsgAbort;
1529: if (gActiveCommand != NULL
1530: && gActiveCommand->queueTag != QUEUE_TAG_NONTAGGED) {
1531: msgByte = kScsiMsgAbortTag;
1532: }
1533: CURIOputByteIntoFifo(msgByte);
1534: CURIOstartNonDMATransfer();
1535: break;
1536: case kBusPhaseDATO:
1537: case kBusPhaseCMD:
1538: CURIOtransferPad(TRUE); /* Output pad */
1539: break;
1540: case kBusPhaseMSGI:
1541: case kBusPhaseDATI:
1542: case kBusPhaseSTS:
1543: CURIOtransferPad(FALSE); /* Input pad */
1544: break;
1545: default:
1546: [self killActiveCommandAndResetBus
1547: : SR_IOST_HW
1548: reason : "Strange SCSI phase in error recovery"
1549: ];
1550: break;
1551: }
1552: }
1553: #if LOG_ERROR_RECOVERY
1554: [self logRegisters : FALSE reason : "Registers at error recovery action exit"];
1555: #endif /* -Debug */
1556: EXIT();
1557: }
1558:
1559: /*
1560: * Disable specified mode for gActiveCommand's target. If mode is currently
1561: * enabled, we'll log a message to the console.
1562: */
1563: - (void) disableMode : (TargetMode) mode
1564: {
1565: int target;
1566: PerTargetData *perTargetPtr;
1567: const char *modeStr = NULL;
1568:
1569: ENTRY("Bdm disableMode");
1570: ASSERT(gActiveCommand != NULL && gActiveCommand->scsiReq != NULL);
1571: target = gActiveCommand->scsiReq->target;
1572: perTargetPtr = &gPerTargetData[target];
1573: switch (mode) {
1574: case kTargetModeCmdQueue:
1575: if (perTargetPtr->cmdQueueDisable == 0) {
1576: perTargetPtr->cmdQueueDisable = 1;
1577: modeStr = "Command Queueing";
1578: }
1579: break;
1580: default:
1581: IOLog("%s: Bogus target mode %d for target %d\n",
1582: [self name],
1583: mode,
1584: target
1585: );
1586: break;
1587: }
1588: ddmChip("DISABLING %s for target %d\n", modeStr, target, 3,4,5);
1589: if (modeStr != NULL) {
1590: IOLog("%s: DISABLING %s for target %d\n",
1591: [self name],
1592: modeStr,
1593: target
1594: );
1595: }
1596: EXIT();
1597: }
1598:
1599: /**
1600: * Validate the target's reselection byte (put on the bus before
1601: * reselecting us). Erase the initiator ID and convert the other
1602: * bit into an index. The algorithm should be faster than a
1603: * sequential search, but it probably doesn't matter much.
1604: * @return TRUE if successful (gCurrentTarget is now valid).
1605: * This function does not check whether there actually
1606: * is a command pending for this target.
1607: */
1608: - (IOReturn) getReselectionTargetID
1609: : (UInt8) selectByte
1610: {
1611: IOReturn ioReturn = SR_IOST_BV;
1612: register UInt8 targetBits = selectByte;
1613: register UInt8 targetID = 0;
1614: register UInt8 bitValue = 0; /* Supress warning */
1615:
1616: ENTRY("Brt getReselectionTargetID");
1617: if ((targetBits & gInitiatorIDMask) == 0) {
1618: IOLog("%s: Reselection failed: initiator ID bit not set, got %02x\n",
1619: [self name],
1620: selectByte
1621: );
1622: }
1623: else {
1624: targetBits &= ~gInitiatorIDMask; /* Remove our bit */
1625: if (targetBits == 0) {
1626: IOLog("%s: Reselection failed: target ID bit not set, got %02x\n",
1627: [self name],
1628: selectByte
1629: );
1630: }
1631: else {
1632: bitValue = targetBits;
1633: if ((bitValue > 0x0F) != 0) {
1634: targetID += 4;
1635: bitValue >>= 4;
1636: }
1637: if ((bitValue > 0x03) != 0) {
1638: targetID += 2;
1639: bitValue >>= 2;
1640: }
1641: if ((bitValue > 0x01) != 0) {
1642: targetID += 1;
1643: }
1644: targetBits &= ~(1 << targetID); /* Remove the target mask */
1645: if (targetBits == 0) { /* Was exactly one set? */
1646: ioReturn = IO_R_SUCCESS; /* Yes: success! */
1647: gCurrentTarget = targetID; /* Save the current target */
1648: ddmChip("Reselection from target %d\n",
1649: gCurrentTarget,
1650: 2, 3, 4, 5
1651: );
1652: }
1653: else {
1654: IOLog("%s: Reselection failed, multiple targets, got %02x\n",
1655: [self name],
1656: selectByte
1657: );
1658: }
1659: }
1660: }
1661: RESULT(ioReturn);
1662: return (ioReturn);
1663: }
1664:
1665: @end /* Apple96_SCSI(BusState) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.