|
|
1.1 root 1: /* Copyright (c) 1994 NeXT Computer, Inc. All rights reserved.
2: *
3: * AMD_ChipPrivate.m - methods used only by AMD_Chip module.
4: *
5: * HISTORY
6: * 2 Nov 94 Doug Mitchell at NeXT
7: * Created.
8: */
9:
10: #import "AMD_Chip.h"
11: #import "AMD_ChipPrivate.h"
12: #import "AMD_Private.h"
13: #import "AMD_x86.h"
14: #import "AMD_Regs.h"
15: #import "AMD_Types.h"
16: #import "AMD_ddm.h"
17: #import "bringup.h"
18: #import <driverkit/generalFuncs.h>
19: #import <kernserv/prototypes.h>
20:
21:
22: @implementation AMD_SCSI(ChipPrivate)
23:
24: /*
25: * Determine if SCSI interrupt is pending.
26: */
27: - (sintPending_t)scsiInterruptPending
28: {
29: unsigned char sstat;
30:
31: sstat = READ_REG(scsiStat);
32: if (sstat & SS_INTERRUPT) {
33: return SINT_DEVICE;
34: }
35: else {
36: return SINT_NONE;
37: }
38: }
39:
40: /*
41: * Methods invoked upon interrupt. One per legal scState. All assume that
42: * status and interrupt status have been captured in saveStatus and
43: * saveIntrStatus.
44: */
45:
46: /*
47: * Disconnected - only legal event here is reselection.
48: */
49: - (void)fsmDisconnected
50: {
51: ddm_chip("fsmDisconnected\n", 1,2,3,4,5);
52: ASSERT(activeCmd == NULL);
53: if(saveIntrStatus & IS_RESELECTED) {
54: /*
55: * We've been reselected.
56: */
57:
58: unsigned char selectByte;
59: unsigned fifoDepth;
60: unsigned char msg;
61:
62: /*
63: * Make sure there's a selection byte and an
64: * identify message in the fifo.
65: */
66: fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK;
67: ddm_chip("reselect: fifoDepth %d\n", fifoDepth, 2,3,4,5);
68: if(fifoDepth != 2) {
69: ddm_err("reselection, fifoDepth %d\n", fifoDepth,
70: 2,3,4,5);
71: IOLog("AMD53C974: Bad FIFO count (%d) on Reselect\n",
72: fifoDepth);
73: [self hwAbort:SR_IOST_HW
74: reason:NULL];
75: return;
76:
77: }
78:
79: /*
80: * make sure target set his bit.
81: */
82: if ((selectByte = READ_REG(scsiFifo) &~ (1 << hostId)) == 0) {
83: ddm_err("fsmDisconnected: reselection failed"
84: " - no target bit\n", 1,2,3,4,5);
85: [self hwAbort:SR_IOST_BV
86: reason:"No target bit on Reselect"];
87: return;
88: }
89:
90: /*
91: * figure out target from bit that's on.
92: */
93: for (reselTarget = 0;
94: (selectByte & 1) == 0;
95: reselTarget++, selectByte>>=1) {
96: continue;
97: }
98:
99: /*
100: * first message byte must be identify.
101: */
102: msg = READ_REG(scsiFifo);
103: if (saveStatus & SS_PARITYERROR) {
104: ddm_err("fsmDisconnected: reselected parity error\n",
105: 1,2,3,4,5);
106: [self hwAbort:SR_IOST_PARITY
107: reason:"Parity error on Reselect"];
108: return;
109: }
110: if ((msg & MSG_IDENTIFYMASK) == 0) {
111: ddm_err("fsmDisconnected: reselection failed - "
112: "bad msg byte (0x%x)\n", msg, 2,3,4,5);
113: [self hwAbort:SR_IOST_BV
114: reason:"Bad ID Message on Reselect"];
115: return;
116: }
117: reselLun = msg & MSG_ID_LUNMASK;
118: currMsgInCnt = 0;
119:
120: /*
121: * At this point, the chip is waiting for us to validate
122: * the identify message. If cmd queueing is enabled
123: * for this target, the target is waiting to send a queue
124: * tag message, so we have to tell the chip to
125: * drop ACK before we proceed with the reselection.
126: *
127: * In case of sync mode, we need to load target context right
128: * now, before dropping ACK, because the target might go
129: * straight to a data in or data out as soon as ACK drops.
130: */
131: [self targetContext:reselTarget];
132: scState = SCS_ACCEPTINGMSG;
133: reselPending = 1;
134: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
135: WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
136: ddm_chip("reselPending: target %d lun %d\n",
137: reselTarget, reselLun, 3,4,5);
138:
139: } else if(saveIntrStatus & IS_SCSIRESET) {
140: /*
141: * TBD - for now ignore, we get one of these by resetting the
142: * chip. If an I/O is pending, it'll probably time out.
143: * Maybe we want to return SR_IOST_RESET on the pending
144: * command...
145: */
146: ddm_chip("fsmDisconnected: ignoring reset interrupt\n",
147: 1,2,3,4,5);
148: } else {
149: /*
150: * I'm confused....
151: */
152: [self hwAbort:SR_IOST_BV
153: reason:"bad interrupt while disconnected"];
154: }
155: }
156:
157:
158: /*
159: * One of three things can happen here - the selection could succeed (though
160: * with possible imcomplete message out), it could time out, or we can be
161: * reselected.
162: */
163: #define CATCH_SELECT_TO 1
164:
165: - (void)fsmSelecting
166: {
167: unsigned char fifoDepth;
168: unsigned char phase;
169: IOSCSIRequest *scsiReq = activeCmd->scsiReq;
170:
171: ddm_chip("fsmSelecting\n", 1,2,3,4,5);
172: ASSERT(activeCmd != NULL);
173: if (saveIntrStatus & IS_DISCONNECT) {
174: /*
175: * selection timed-out. Abort this request.
176: */
177: #if CATCH_SELECT_TO
178: /* DEBUG ONLY */
179: if(scsiReq->cdb.cdb_opcode != C6OP_INQUIRY) {
180: IOLog("Unexpected Select Timeout\n");
181: }
182: #endif CATCH_SELECT_TO
183: ddm_chip("***SELECTION TIMEOUT for target %d\n",
184: activeCmd->scsiReq->target, 2,3,4,5);
185: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
186: scState = SCS_DISCONNECTED;
187: scsiReq->driverStatus = SR_IOST_SELTO;
188: [self ioComplete:activeCmd];
189: activeCmd = NULL;
190: }
191: else if(saveIntrStatus == (IS_SUCCESSFUL_OP|IS_SERVICE_REQ)) {
192:
193: ddm_chip("selection seqstep=%d\n",
194: saveSeqStep & INS_STATE_MASK, 2,3,4,5);
195:
196: switch (saveSeqStep & INS_STATE_MASK) {
197: case 0:
198: /*
199: * No message phase. If we really wanted one,
200: * this could be significant...
201: */
202: if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
203: /*
204: * This target can't do command queueing.
205: */
206: [self disableMode:AM_CmdQueue];
207: }
208: if(SDTR_State == SNS_HOST_INIT_NEEDED) {
209: /*
210: * We were trying to do an SDTR.
211: */
212: [self disableMode:AM_Sync];
213: SDTR_State = SNS_NONE;
214: }
215:
216: /*
217: * OK, let's try to continue following phase
218: * changes.
219: */
220: scState = SCS_INITIATOR;
221: break;
222:
223: case 3: /* didn't complete cmd phase, parity? */
224: case 4: /* everything worked */
225: case 1: /* everything worked, SCMD_SELECT_ATN_STOP
226: * case */
227:
228: /*
229: * We're connected. Start following the target's phase
230: * changes.
231: *
232: * If we're trying to do sync negotiation,
233: * this is the place to do it. In that case, we
234: * sent a SCMD_SELECT_ATN_STOP command, and
235: * ATN is now asserted (and we're hopefully in
236: * msg out phase). We want to send 5 bytes.
237: * Drop them into currMsgOut[] and prime the
238: * msgOutState machine.
239: */
240: if(SDTR_State == SNS_HOST_INIT_NEEDED) {
241: [self createSDTR:currMsgOut inboundMsg:NULL];
242: currMsgOutCnt = MSG_SDTR_LENGTH;
243: msgOutState = MOS_WAITING;
244: }
245: scState = SCS_INITIATOR;
246: break;
247:
248: case 2:
249: /*
250: * Either no command phase, or imcomplete message
251: * transfer.
252: */
253: fifoDepth = READ_REG(currFifoState) &
254: FS_FIFO_LEVEL_MASK;
255: phase = saveStatus & SS_PHASEMASK;
256: ddm_chip("INCOMPLETE SELECT; fifoDepth %d phase %s\n",
257: fifoDepth,
258: IOFindNameForValue(phase, scsiPhaseValues),
259: 3,4,5);
260: if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
261: /*
262: * This target can't do command queueing.
263: */
264: [self disableMode:AM_CmdQueue];
265: }
266:
267: /*
268: * Spec says ATN is asserted if all message bytes
269: * were not sent.
270: */
271: if(fifoDepth > activeCmd->cdbLength) {
272: WRITE_REG(scsiCmd, SCMD_CLR_ATN);
273: }
274:
275: /*
276: * OK, let's try to continue following phase
277: * changes.
278: */
279: scState = SCS_INITIATOR;
280: break;
281:
282: default:
283: [self hwAbort:SR_IOST_HW
284: reason:"Selection sequence Error"];
285: break;
286: }
287: }
288: else if(saveIntrStatus & IS_RESELECTED) {
289: /*
290: * We got reselected while trying to do a selection.
291: * Enqueue this cmdBuf on the HEAD of pendingQ, then deal
292: * with the reselect.
293: * Tricky case, we have to "deactivate" this command
294: * since this hwStart attempt failed.
295: */
296: queue_enter_first(&pendingQ, activeCmd, commandBuf *, link);
297: [self deactivateCmd:activeCmd];
298: ddm_chip("reselect while trying to select target %d\n",
299: activeCmd->scsiReq->target, 2,3,4,5);
300: activeCmd = NULL;
301: scState = SCS_DISCONNECTED;
302:
303: /*
304: * Go deal with reselect.
305: */
306: [self fsmDisconnected];
307: }
308: else {
309: ddm_err("fsmSelecting: Bogus select/reselect interrupt\n",
310: 1,2,3,4,5);
311: [self hwAbort:SR_IOST_HW
312: reason: "Bogus select/reselect interrupt"];
313: return;
314: }
315: return;
316: }
317:
318: /*
319: * This one is illegal.
320: */
321: - (void)fsmInitiator
322: {
323: ddm_chip("fsmInitiator\n", 1,2,3,4,5);
324: [self hwAbort:SR_IOST_HW reason:"Interrupt as Initiator"];
325: }
326:
327: /*
328: * We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left is
329: * to drop ACK. Command Complete message is handled in fscAcceptingMsg.
330: */
331: - (void)fsmCompleting
332: {
333: ddm_chip("fsmCompleting\n", 1,2,3,4,5);
334: ASSERT(activeCmd != NULL);
335: if(saveIntrStatus & IS_DISCONNECT) {
336: ddm_err("unexpected completing disconnect\n",
337: 1,2,3,4,5);
338: return;
339: }
340: if(saveIntrStatus & IS_SUCCESSFUL_OP) {
341: /*
342: * Got both status and msg in fifo; Ack is still true.
343: */
344: if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 2) {
345: /*
346: * This is pretty bogus - we expect a status and
347: * msg in the fifo.
348: */
349: [self hwAbort:SR_IOST_HW reason:"InitComplete fifo"
350: " level"];
351: return;
352: }
353: activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
354: currMsgInCnt = 1;
355: currMsgIn[0] = READ_REG(scsiFifo);
356: ddm_chip("fsmCompleting: status 0x%x msg 0x%x\n",
357: activeCmd->scsiReq->scsiStatus,
358: currMsgIn[0], 3,4,5);
359: if (saveStatus & SS_PARITYERROR) {
360: ddm_err("fsmCompleting: parity error on msg in\n",
361: 1,2,3,4,5);
362: [self hwAbort:SR_IOST_PARITY
363: reason:"Parity error on message in"];
364: return;
365: }
366: scState = SCS_ACCEPTINGMSG;
367: WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
368: return;
369: } else {
370: /*
371: * Must have just got a status byte only. This is kind of
372: * weird, but let's try to handle it.
373: */
374: ddm_err("fsmCompleting: status only on complete\n",
375: 1,2,3,4,5);
376: if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
377: [self hwAbort:SR_IOST_HW
378: reason:"Bad Fifo level on Cmd Complete"];
379: return;
380: }
381: activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
382: if(saveStatus & SS_PARITYERROR) {
383: ddm_err("fsmCompleting: parity error on status\n",
384: 1,2,3,4,5);
385: [self hwAbort:SR_IOST_PARITY
386: reason:"Parity Error on Cmd Complete"];
387: return;
388: }
389:
390: /*
391: * Back to watching phase changes. Why the target isn't in
392: * message in we have yet to find out.
393: */
394: scState = SCS_INITIATOR;
395: }
396: }
397:
398: /*
399: * DMA Complete.
400: */
401: - (void)fsmDMAing
402: {
403: u_int bytesMoved;
404:
405: ddm_chip("fsmDMAing\n", 1,2,3,4,5);
406: ASSERT(activeCmd != NULL);
407:
408: bytesMoved = [self dmaTerminate];
409: if(bytesMoved > activeCmd->currentByteCount) {
410: ddm_err("fsmDMAing: DMA transfer count exceeeded\n",
411: 1,2,3,4,5);
412: ddm_err(" expected %d, moved %d\n",
413: activeCmd->currentByteCount, bytesMoved, 3,4,5);
414: bytesMoved = activeCmd->currentByteCount;
415: }
416: ((char *)activeCmd->currentPtr) += bytesMoved;
417: activeCmd->currentByteCount -= bytesMoved;
418: if(saveStatus & SS_PARITYERROR) {
419: ddm_err("fsmDMAing: SCSI Data Parity Error\n", 1,2,3,4,5);
420: [self hwAbort:SR_IOST_PARITY reason:"SCSI Data Parity Error"];
421: return;
422: }
423: /*
424: * Back to watching phase changes.
425: */
426: scState = SCS_INITIATOR;
427: }
428:
429: /*
430: * Just completed the SCMD_TRANSFER_INFO operation for message in. ACK is
431: * still true. Stash the current message byte in currMsgIn[] and proceed to
432: * fsmAcceptingMsg after a SCMD_MSG_ACCEPTED.
433: */
434: - (void)fsmGettingMsg
435: {
436: BOOL setAtn = NO;
437:
438: ASSERT((activeCmd != NULL) || reselPending);
439: if(saveIntrStatus & IS_DISCONNECT) {
440: ddm_chip("fsmGettingMsg: message In Disconnect\n", 1,2,3,4,5);
441: /*
442: * This error is handled on return...
443: */
444: return;
445: }
446: if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
447: ddm_chip("Message In fifo error\n", 1,2,3,4,5);
448: [self hwAbort:SR_IOST_HW reason:"Message In fifo error"];
449: return;
450: }
451:
452: currMsgIn[currMsgInCnt++] = READ_REG(scsiFifo);
453: if(currMsgInCnt > AMD_MSG_SIZE) {
454: [self hwAbort:SR_IOST_BV
455: reason:"Too Many Message bytes received"];
456: }
457: if(saveStatus & SS_PARITYERROR) {
458: ddm_err("fsmGettingMsg: parity error on Message In\n",
459: 1,2,3,4,5);
460: [self hwAbort:SR_IOST_PARITY
461: reason:"parity error on Message In"];
462: return;
463: }
464: ddm_chip("fsmGettingMsg: currMsgIn[%d] = 0x%x (%s)\n", currMsgInCnt-1,
465: currMsgIn[currMsgInCnt-1],
466: IOFindNameForValue(currMsgIn[currMsgInCnt-1],
467: scsiMsgValues), 4,5);
468:
469: /*
470: * Handle special cases.
471: */
472:
473: /*
474: * 1. If this is the last byte of an unsolicited sync negotiation,
475: * we have to assert ATN right now. The message is actually
476: * fully parsed, and a response SDTR message created, in
477: * fsmAcceptingMsg.
478: *
479: * This parsing is pretty crude; if we come up with other special
480: * cases, we might rewrite this or come up with some state variables
481: * to help us.
482: */
483: if((currMsgInCnt >= MSG_SDTR_LENGTH) && (SDTR_State == SNS_NONE)) {
484:
485: int start = currMsgInCnt - MSG_SDTR_LENGTH;
486:
487: if((currMsgIn[start] == MSG_EXTENDED) &&
488: (currMsgIn[start+1] == (MSG_SDTR_LENGTH - 2)) &&
489: (currMsgIn[start+2] == MSG_SDTR)) {
490: ddm_chip("UNSOLICITED SDTR IN; setting ATN\n",
491: 1,2,3,4,5);
492: WRITE_REG(scsiCmd, SCMD_SET_ATN);
493: setAtn = YES;
494: SDTR_State = SNS_TARGET_INIT;
495: }
496: }
497:
498: /*
499: * 2. If this was a message reject, it's possible that an extended
500: * message out was prematurely aborted, with ATN still true.
501: * Clear it so we don't do another (needless) message out.
502: * Avoid this, of course, if we set ATN in this method for
503: * any reason.
504: */
505: if((currMsgIn[currMsgInCnt - 1] == MSG_MSGREJECT) &&
506: (currMsgOutCnt > 1) &&
507: !setAtn) {
508: ddm_chip("fsmGettingMsg: Message Reject; clearing ATN\n",
509: 1,2,3,4,5);
510: WRITE_REG(scsiCmd, SCMD_CLR_ATN);
511: }
512:
513: /*
514: * No need to clear FIFO; its depth was one on entry, and we read
515: * the byte. Note that clearing FIFO after the SCS_ACCEPTINGMSG
516: * might disturb possible sync data in transfer.
517: */
518: WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
519: scState = SCS_ACCEPTINGMSG;
520:
521: }
522:
523: /*
524: * Just finished a message in; Ack is false. If phase is still
525: * message in, we're in the midst of an extended message or additional
526: * message bytes on reselect. Otherwise, message in is complete;
527: * process currMsgIn[].
528: */
529: - (void)fsmAcceptingMsg
530: {
531: unsigned char phase = saveStatus & SS_PHASEMASK;
532: unsigned index;
533: perTargetData *perTargetPtr;
534:
535: ddm_chip("fsmAcceptingMsg: phase %s\n",
536: IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
537: if((phase == PHASE_MSGIN) && !(saveIntrStatus & IS_DISCONNECT)) {
538:
539: /*
540: * More message bytes to follow.
541: * We have to qualify with !IS_DISCONNECT to cover the
542: * case of some targets (like the Exabyte tape drive)
543: * which bogusly keep CD, IO, and MSG asserted after
544: * they drop BSY upon command complete.
545: */
546: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
547: WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
548: scState = SCS_GETTINGMSG;
549: return;
550: }
551:
552: /*
553: * Message in complete. Handle message(s) in currMsgIn[].
554: */
555: if(reselPending) {
556:
557: /*
558: * We're expecting either:
559: * -- no messages, or
560: * -- queue tag and/or Save Pointers.
561: */
562: unsigned char tag = QUEUE_TAG_NONTAGGED;
563:
564: ASSERT(activeCmd == NULL);
565: for(index=0; index<currMsgInCnt; index++) {
566: switch(currMsgIn[index]) {
567: case MSG_RESTOREPTRS:
568: ddm_chip("unnecessary restore pointers\n",
569: 1,2,3,4,5);
570: continue; /* to next message */
571:
572: case MSG_SIMPLE_QUEUE_TAG:
573: if(index == (currMsgInCnt-1)) {
574: [self hwAbort: SR_IOST_BV
575: reason:"Queue tag message, no tag"];
576: return;
577: }
578: tag = currMsgIn[++index];
579: break;
580:
581: /*
582: * handle others here...?
583: */
584: default:
585: IOLog("AMD53C974: bad msg (0x%x) after identify\n",
586: currMsgIn[index]);
587: [self hwAbort: SR_IOST_BV reason:NULL];
588: return;
589: }
590: }
591:
592: if([self reselect:reselTarget
593: lun:reselLun
594: queueTag:tag] == YES) {
595: /*
596: * Found a disconnected commandBuf to reconnect.
597: *
598: * IDENTIFY msg implies restore ptrs.
599: */
600: reselPending = 0;
601: ASSERT(activeCmd != NULL);
602: activeCmd->currentPtr = activeCmd->savedPtr;
603: activeCmd->currentByteCount =
604: activeCmd->savedByteCount;
605: scState = SCS_INITIATOR;
606: return;
607: }
608: else {
609: IOLog("AMD53C974: Illegal reselect (target %d lun "
610: "%d tag %d)\n", reselTarget, reselLun, tag);
611: [self hwAbort: SR_IOST_BV
612: reason:NULL];
613: return;
614: }
615: } /* reselect pending */
616:
617: /*
618: * Handle all other messages.
619: */
620: ASSERT(activeCmd != NULL);
621: perTargetPtr = &perTarget[activeCmd->scsiReq->target];
622: for(index=0; index<currMsgInCnt; index++) {
623: switch(currMsgIn[index]) {
624: case MSG_CMDCMPLT:
625: /*
626: * Bus really should be free; we came here from
627: * fsmCompleting.
628: */
629: if(!(saveIntrStatus & IS_DISCONNECT)) {
630: ddm_err("fsmAcceptingMsg: Command Complete"
631: " but no Disconnect\n", 1,2,3,4,5);
632: [self hwAbort:SR_IOST_BV
633: reason:"No Disconnect On Command"
634: " Complete"];
635: return;
636: }
637:
638: /*
639: * TA DA!
640: */
641: scState = SCS_DISCONNECTED;
642: activeCmd->scsiReq->driverStatus = SR_IOST_GOOD;
643: [self ioComplete:activeCmd];
644: activeCmd = NULL;
645: return;
646:
647: case MSG_DISCONNECT:
648: /*
649: * This could be in fsmGettingMsg, where we could
650: * handle it gracefully by doing a MSGREJ, but this
651: * is such a bogus error that we'll just reset the
652: * offender.
653: */
654: if(!activeCmd->discEnable) {
655: ddm_chip("***Illegal Disconnect attempt\n",
656: 1,2,3,4,5);
657: IOLog("AMD53C974: Illegal disconnect attempt"
658: " on target %d\n",
659: activeCmd->scsiReq->target);
660: [self hwAbort:SR_IOST_BV
661: reason:NULL];
662: return;
663: }
664: scState = SCS_DISCONNECTED;
665: [self disconnect];
666: return;
667:
668: case MSG_SAVEPTRS:
669: activeCmd->savedPtr = activeCmd->currentPtr;
670: activeCmd->savedByteCount =
671: activeCmd->currentByteCount;
672: break;
673:
674: case MSG_RESTOREPTRS:
675: activeCmd->currentPtr = activeCmd->savedPtr;
676: activeCmd->currentByteCount =
677: activeCmd->savedByteCount;
678: break;
679:
680: case MSG_MSGREJECT:
681: /*
682: * look at last message sent; may have to
683: * disable sync or cmd queue mode for this target.
684: * This assumes that we don't send SDTR and queue tag
685: * in the same message.
686: */
687: ddm_chip("fsmAcceptingMsg: MESSAGE REJECT RECEIVED "
688: "from target %d\n",
689: activeCmd->scsiReq->target, 2,3,4,5);
690: if(currMsgOutCnt == 0) {
691: /*
692: * Huh? We haven't sent a message recently...
693: */
694: [self hwAbort:SR_IOST_BV
695: reason:"Unexpected Message Reject"];
696: return;
697: }
698: switch(currMsgOut[0]) {
699: case MSG_SIMPLE_QUEUE_TAG:
700: [self disableMode:AM_CmdQueue];
701: break;
702: case MSG_EXTENDED:
703: /*
704: * Only one we ever send is sync negotiation..
705: */
706: if(currMsgOut[2] == MSG_SDTR) {
707: [self disableMode:AM_Sync];
708: SDTR_State = SNS_NONE;
709: break;
710: }
711: else {
712: [self hwAbort:SR_IOST_INT
713: reason:"Currupted Message Buffer"];
714: return;
715: }
716: default:
717: IOLog("AMD53C974: %s Message Rejected\n",
718: IOFindNameForValue(currMsgOut[0],
719: scsiMsgValues));
720: /* oh well... */
721: break;
722: }
723:
724: /*
725: * In any case, we're definitely thru with the
726: * outbound message buffer.
727: */
728: currMsgOutCnt = 0;
729: break;
730:
731: case MSG_LNKCMDCMPLT:
732: case MSG_LNKCMDCMPLTFLAG:
733: /*
734: * This should never happen, because hwStart trashes
735: * commands with the LINK bit on.
736: */
737: [self hwAbort:SR_IOST_BV reason:"Linked command"];
738: return;
739:
740: case MSG_EXTENDED:
741: /*
742: * The only valid one is sync negotiation....
743: */
744: switch(currMsgIn[index+2]) {
745: case MSG_SDTR:
746: if(currMsgIn[index+1] != (MSG_SDTR_LENGTH-2)) {
747: [self hwAbort:SR_IOST_BV
748: reason:"Bad Extended Msg Length"];
749: return;
750: }
751: switch(SDTR_State) {
752: case SNS_HOST_INIT:
753: /*
754: * Just completed SDTR that we initiated.
755: */
756: if([self parseSDTR:&currMsgIn[index]]
757: == NO) {
758: [self hwAbort:SR_IOST_HW
759: reason:"Bad SDTR Parameters"];
760: return;
761: }
762:
763: /*
764: * Successful SDTR.
765: */
766: ddm_chip("host-init SDTR COMPLETE\n",
767: 1,2,3,4,5);
768: SDTR_State = SNS_NONE;
769: break;
770:
771: case SNS_TARGET_INIT:
772: /*
773: * Target-initiated negotiaited. This
774: * was detected in fsmGettingMsg, where
775: * we set ATN true.
776: * Cons up a response and prime the message
777: * out state machine to send it.
778: */
779: [self createSDTR : currMsgOut
780: inboundMsg : &currMsgIn[index]];
781: currMsgOutCnt = MSG_SDTR_LENGTH;
782: msgOutState = MOS_WAITING;
783: break;
784:
785: default:
786: IOPanic("AMD53C974: Bad SDTR_State");
787: }
788:
789: /*
790: * Skip over the rest of this message; index
791: * should point to the last byte of this message.
792: */
793: index += (MSG_SDTR_LENGTH - 1);
794: break;
795:
796: default:
797: IOLog("AMD53C974: Unexpected Extended Message "
798: "(0x%x) Received\n",
799: currMsgIn[index+2]);
800: [self hwAbort:SR_IOST_BV reason:NULL];
801: return;
802: }
803: break;
804:
805: default:
806: /*
807: * all others are unacceptable.
808: */
809: IOLog("AMD53C974: Illegal message (0x%x)\n",
810: currMsgIn[index]);
811: [self messageOut:MSG_MSGREJECT];
812: }
813: } /* for index */
814:
815: /*
816: * Default case for 'break' from above switch - back to following
817: * phase changes.
818: */
819: scState = SCS_INITIATOR;
820: }
821:
822: /*
823: * Just completed the SCMD_TRANSFER_INFO operation for message out.
824: */
825: - (void)fsmSendingMsg
826: {
827: ddm_chip("fsmSendingMsg\n", 1,2,3,4,5);
828: ASSERT(activeCmd != NULL);
829: scState = SCS_INITIATOR;
830: if(SDTR_State == SNS_TARGET_INIT) {
831: /*
832: * If the message we just sent was a SDTR, we've just
833: * completed a target-initiated SDTR sequence.
834: * Note this assumes that an outbound SDTR in this
835: * situation is the only message in currMsgOut[].
836: * This will have to change if we send a queue tag and
837: * SDTR in the sqame message.
838: */
839: if((currMsgOutCnt == MSG_SDTR_LENGTH) &&
840: (currMsgOut[0] == MSG_EXTENDED) &&
841: (currMsgOut[1] == (MSG_SDTR_LENGTH - 2)) &&
842: (currMsgOut[2] == MSG_SDTR)) {
843:
844: ddm_chip("fsmSendingMsg: target-init SDTR complete\n",
845: 1,2,3,4,5);
846: if([self parseSDTR:currMsgOut] == NO) {
847: /*
848: * Shouldn't fail; we generated this
849: * message ourself...
850: */
851: IOPanic("AMD53C974: SDTR Problem\n");
852: }
853: SDTR_State = SNS_NONE;
854: }
855: }
856: }
857:
858:
859: /*
860: * Just completed the SCMD_TRANSFER_INFO operation for command.
861: */
862: - (void)fsmSendingCmd
863: {
864: ddm_chip("fsmSendingCmd\n", 1,2,3,4,5);
865: ASSERT(activeCmd != NULL);
866: scState = SCS_INITIATOR;
867: }
868:
869: /*
870: * Follow SCSI Phase change. Called while SCS_INITIATOR.
871: */
872: - (void)fsmPhaseChange
873: {
874: int phase;
875: char *cp;
876: cdb_t *cdbp;
877: int i;
878: sc_status_t rtn;
879:
880: ddm_chip("fsmPhaseChange\n", 1,2,3,4,5);
881: ASSERT(activeCmd != NULL);
882:
883: /*
884: * Advance msg out state machine -- SCSI spec says if
885: * we do a msg out phase and then see another phase
886: * we can assume msg was transmitted without error.
887: * However, if we're in msg in, we may have a message reject
888: * coming in, so we'll keep currMsgOut[] valid in that case.
889: *
890: * FIXME - one case which this would not cover is the queue tag
891: * message saved in currMsgOut[] during selection. We don't
892: * go to MOS_SAWMSGOUT in that case. problem?
893: */
894: phase = saveStatus & SS_PHASEMASK;
895: if ((phase != PHASE_MSGOUT) &&
896: (phase != PHASE_MSGIN) &&
897: (msgOutState == MOS_SAWMSGOUT)) {
898: msgOutState = MOS_NONE;
899: currMsgOutCnt = 0;
900: }
901:
902: /*
903: * If we just sent a host-initiated SDTR and the target went
904: * to something other than phase in, we assume that the negotiation
905: * failed. This is in violation of the spec, but the Sony CDROM
906: * does this.
907: */
908: if((SDTR_State == SNS_HOST_INIT) && (phase != PHASE_MSGIN)) {
909: ddm_chip("IMPLIED SNS_HOST_INIT Reject\n", 1,2,3,4,5);
910: [self disableMode:AM_Sync];
911: SDTR_State = SNS_NONE;
912: }
913:
914: /*
915: * make sure we start off with a clean slate.
916: *
917: * NO - this can disturb possible sync data in! We'll need to cover
918: * this in individual cases elsewhere...
919: */
920: /* WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO); */
921: ddm_chip("fsmPhaseChange: phase = %s\n",
922: IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
923:
924: switch (phase) {
925:
926: case PHASE_COMMAND:
927: /*
928: * The normal case here is after a host-initiated SDTR
929: * sequence.
930: */
931: ddm_chip("fsmPhaseChange: command phase\n", 1,2,3,4,5);
932: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
933: cdbp = &activeCmd->scsiReq->cdb;
934: cp = (char *)cdbp;
935: for(i=0; i<activeCmd->cdbLength; i++) {
936: WRITE_REG(scsiFifo, *cp++);
937: }
938:
939: #if 0
940: /*
941: * This causes extra bytes to sit around in the fifo
942: * if we go straight to data phase after this, and
943: * we can't clear the fifo at that time in case
944: * we're in sync data in...
945: */
946: /*
947: * fill fifo to avoid spurious command phase for target
948: * chips that try to get max command length
949: */
950: for (i = 12 - activeCmd->cdbLength; i > 0; i--)
951: WRITE_REG(scsiFifo, 0);
952: #endif 0
953: WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
954: scState = SCS_SENDINGCMD;
955: break;
956:
957: case PHASE_DATAOUT: /* To Target from Initiator (write) */
958: if(activeCmd->scsiReq->read) {
959: [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
960: break;
961: }
962: if(rtn = [self dmaStart]) {
963: [self hwAbort:rtn
964: reason: IOFindNameForValue(rtn,
965: IOScStatusStrings)];
966: break;
967: }
968: break;
969:
970: case PHASE_DATAIN: /* From Target to Initiator (read) */
971: if(!activeCmd->scsiReq->read) {
972: [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
973: break;
974: }
975: if(rtn = [self dmaStart]) {
976: [self hwAbort:rtn
977: reason: IOFindNameForValue(rtn,
978: IOScStatusStrings)];
979: break;
980: }
981: break;
982:
983: case PHASE_STATUS: /* Status from Target to Initiator */
984: /*
985: * fsmCompleting will collect the STATUS byte
986: * (and hopefully a MSG) from the fifo when this
987: * completes.
988: */
989: scState = SCS_COMPLETING;
990: currMsgInCnt = 0;
991: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
992: WRITE_REG(scsiCmd, SCMD_INIT_CMD_CMPLT);
993: break;
994:
995: case PHASE_MSGIN: /* Message from Target to Initiator */
996: scState = SCS_GETTINGMSG;
997: currMsgInCnt = 0;
998: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
999: WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
1000: break;
1001:
1002: case PHASE_MSGOUT: /* Message from Initiator to Target */
1003: WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
1004: if(msgOutState == MOS_WAITING) {
1005: int i;
1006:
1007: ASSERT(currMsgOutCnt != 0);
1008: for(i=0; i<currMsgOutCnt; i++) {
1009: ddm_chip("msg out: writing 0x%x\n",
1010: currMsgOut[i], 2,3,4,5);
1011: WRITE_REG(scsiFifo, currMsgOut[i]);
1012: }
1013: msgOutState = MOS_SAWMSGOUT;
1014: if(SDTR_State == SNS_HOST_INIT_NEEDED) {
1015: /*
1016: * sending SDTR message after select.
1017: */
1018: ASSERT(currMsgOut[0] == MSG_EXTENDED);
1019: ASSERT(currMsgOut[2] == MSG_SDTR);
1020: ASSERT(currMsgOutCnt == MSG_SDTR_LENGTH);
1021: ddm_chip("going to SNS_HOST_INIT\n",
1022: 1,2,3,4,5);
1023: SDTR_State = SNS_HOST_INIT;
1024: }
1025: } else {
1026: /*
1027: * Target went to msg out and we don't have
1028: * anything to send! Just give it a nop.
1029: */
1030: ddm_chip("msg out: sending MSG_NOP\n", 1,2,3,4,5);
1031: WRITE_REG(scsiFifo, MSG_NOP);
1032: }
1033:
1034: scState = SCS_SENDINGMSG;
1035: /*
1036: * ATN is automatically cleared when transfer info completes.
1037: */
1038: WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
1039: break;
1040:
1041: default:
1042: [self hwAbort:SR_IOST_HW reason:"Bad SCSI phase"];
1043: break;
1044: }
1045: }
1046:
1047: /*
1048: * Set up to send single-byte message.
1049: */
1050: - (void) messageOut : (u_char)msg
1051: {
1052: ddm_chip("messageOut (0x%x)\n", msg, 2,3,4,5);
1053: currMsgOut[0] = msg;
1054: currMsgOutCnt = 1;
1055: msgOutState = MOS_WAITING;
1056: WRITE_REG(scsiCmd, SCMD_SET_ATN);
1057: }
1058:
1059:
1060: /*
1061: * Load syncPeriod, syncOffset for activeCmd per perTarget values.
1062: */
1063: - (void)targetContext : (unsigned) target
1064: {
1065: perTargetData *perTargetPtr;
1066:
1067: perTargetPtr = &perTarget[target];
1068: if(!syncModeEnable ||
1069: perTargetPtr->syncDisable ||
1070: (perTargetPtr->syncXferOffset == 0)) {
1071: /*
1072: * Easy case, async.
1073: */
1074: WRITE_REG(syncOffset, 0);
1075: ddm_chip("targetContext(%d): ASYNC\n", target, 2,3,4,5);
1076: #ifdef DEBUG
1077: syncOffsetShadow = 0;
1078: #endif DEBUG
1079: }
1080: else {
1081: unsigned char periodReg;
1082: unsigned char offsetReg;
1083:
1084: periodReg = nsPeriodToSyncPeriodReg(
1085: perTargetPtr->syncXferPeriod,
1086: fastModeEnable, scsiClockRate);
1087: WRITE_REG(syncPeriod, periodReg);
1088:
1089: /*
1090: * FIXME - might eventually want to use non-default
1091: * values for RAD and RAA...
1092: */
1093: offsetReg = (perTargetPtr->syncXferOffset |
1094: SOR_RAD_DEFAULT | SOR_RAA_DEFAULT);
1095: WRITE_REG(syncOffset, offsetReg);
1096: ddm_chip("targetContext(%d): period 0x%x offset %d\n",
1097: target, periodReg, offsetReg, 4,5);
1098: #ifdef DEBUG
1099: syncOffsetShadow = offsetReg;
1100: syncPeriodShadow = periodReg;
1101: #endif DEBUG
1102: }
1103: }
1104:
1105: /*
1106: * Parse and validate 5-byte SDTR message. If valid, save in perTarget
1107: * and in hardware. Returns YES if valid, else NO.
1108: *
1109: * Specified message buffer could be from either currMsgIn[] or
1110: * currMsgOut[].
1111: */
1112: - (BOOL)parseSDTR : (unsigned char *)sdtrMessage
1113: {
1114: unsigned nsPeriod;
1115: unsigned char fastClock;
1116: unsigned minPeriod;
1117: perTargetData *perTargetPtr;
1118:
1119: ASSERT(activeCmd != NULL);
1120: perTargetPtr = &perTarget[activeCmd->scsiReq->target];
1121:
1122: if(sdtrMessage[0] != MSG_EXTENDED) {
1123: goto Bad;
1124: }
1125: if(sdtrMessage[1] != (MSG_SDTR_LENGTH - 2)) {
1126: goto Bad;
1127: }
1128: if(sdtrMessage[2] != MSG_SDTR) {
1129: goto Bad;
1130: }
1131:
1132: /*
1133: * period
1134: */
1135: nsPeriod = SDTR_TO_NS_PERIOD(sdtrMessage[3]);
1136: fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
1137: if(fastClock && fastModeEnable) {
1138: minPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
1139: }
1140: else {
1141: minPeriod = MIN_PERIOD_NORM;
1142: }
1143: if(nsPeriod < minPeriod) {
1144: goto Bad;
1145: }
1146: perTargetPtr->syncXferPeriod = nsPeriod;
1147:
1148: /*
1149: * Offset
1150: */
1151: if(sdtrMessage[4] > AMD_MAX_SYNC_OFFSET) {
1152: goto Bad;
1153: }
1154: perTargetPtr->syncXferOffset = sdtrMessage[4];
1155:
1156: /*
1157: * Success.
1158: */
1159: perTargetPtr->syncDisable = 0;
1160: perTargetPtr->syncNegotNeeded = 0;
1161: [self targetContext:activeCmd->scsiReq->target];
1162:
1163: ddm_chip("parseSDTR SUCCESS: %02x %02x %02x %02x %02x\n",
1164: sdtrMessage[0], sdtrMessage[1], sdtrMessage[2],
1165: sdtrMessage[3], sdtrMessage[4]);
1166: ddm_chip(" period %d offset %d\n", perTargetPtr->syncXferPeriod,
1167: perTargetPtr->syncXferOffset, 3,4,5);
1168: return YES;
1169:
1170: Bad:
1171: ddm_chip("parseSDTR FAIL: 02%x %02x %02x %02x %02x\n",
1172: sdtrMessage[0], sdtrMessage[1], sdtrMessage[2],
1173: sdtrMessage[3], sdtrMessage[4]);
1174: return NO;
1175: }
1176:
1177: /*
1178: * Cons up a SDTR message appropriate for both our hardware and a possible
1179: * target-generated SDTR message. If inboundMsg is NULL, we just use
1180: * the parameters we want.
1181: */
1182: - (void)createSDTR : (unsigned char *)outboundMsg // required
1183: inboundMsg : (unsigned char *)inboundMsg
1184: {
1185: unsigned desiredNsPeriod;
1186: unsigned inboundNsPeriod;
1187: unsigned offset = AMD_MAX_SYNC_OFFSET;
1188: unsigned char fastClock;
1189:
1190: outboundMsg[0] = MSG_EXTENDED;
1191: outboundMsg[1] = MSG_SDTR_LENGTH - 2;
1192: outboundMsg[2] = MSG_SDTR;
1193:
1194: /*
1195: * period
1196: */
1197: fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
1198: if(fastClock && fastModeEnable) {
1199: desiredNsPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
1200: }
1201: else {
1202: desiredNsPeriod = MIN_PERIOD_NORM;
1203: }
1204: if(inboundMsg) {
1205: inboundNsPeriod = SDTR_TO_NS_PERIOD(inboundMsg[3]);
1206: }
1207: else {
1208: inboundNsPeriod = desiredNsPeriod;
1209: }
1210: if(inboundNsPeriod > desiredNsPeriod) {
1211: /*
1212: * Target is slower than us
1213: */
1214: desiredNsPeriod = inboundNsPeriod;
1215: }
1216: outboundMsg[3] = NS_PERIOD_TO_SDTR(desiredNsPeriod);
1217:
1218: /*
1219: * Offset
1220: */
1221: if(inboundMsg) {
1222: offset = inboundMsg[4];
1223: if(offset > AMD_MAX_SYNC_OFFSET) {
1224: /*
1225: * target's buffer smaller than ours
1226: */
1227: offset = AMD_MAX_SYNC_OFFSET;
1228: }
1229: }
1230: outboundMsg[4] = offset;
1231:
1232: ddm_chip("createSDTR: %02x %02x %02x %02x %02x\n",
1233: outboundMsg[0], outboundMsg[1], outboundMsg[2],
1234: outboundMsg[3], outboundMsg[4]);
1235: ddm_chip(" period %d offset %d\n", desiredNsPeriod, offset, 3,4,5);
1236: }
1237:
1238: /*
1239: * Disable specified mode for activeCmd's target. If mode is currently
1240: * enabled, we'll log a message to the console.
1241: */
1242: - (void)disableMode : (AMD_Mode)mode
1243: {
1244: int target;
1245: perTargetData *perTargetPtr;
1246: const char *modeStr = NULL;
1247:
1248: ASSERT(activeCmd != NULL);
1249: target = activeCmd->scsiReq->target;
1250: perTargetPtr = &perTarget[target];
1251: switch(mode) {
1252: case AM_Sync:
1253: if(perTargetPtr->syncDisable == 0) {
1254: perTargetPtr->syncDisable = 1;
1255: modeStr = "Synchronous Transfer Mode";
1256: }
1257: [self targetContext:activeCmd->scsiReq->target];
1258: break;
1259: case AM_CmdQueue:
1260: if(perTargetPtr->cmdQueueDisable == 0) {
1261: perTargetPtr->cmdQueueDisable = 1;
1262: modeStr = "Command Queueing";
1263: }
1264: break;
1265: }
1266: ddm_chip("DISABLING %s for target %d\n", modeStr, target, 3,4,5);
1267: if(modeStr) {
1268: IOLog("AMD53C974: DISABLING %s for target %d\n",
1269: modeStr, target);
1270: }
1271: }
1272:
1273: @end /* AMD_SCSI(ChipPrivate) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.