|
|
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 (c) 1994-1996 NeXT Software, Inc. All rights reserved.
27: * Copyright 1997 Apple Computer Inc. All Rights Reserved.
28: * @author Martin Minow mailto:[email protected]
29: * @revision 1997.02.17 Initial conversion from AMDPCSCSIDriver sources.
30: *
31: * Set tabs every 4 characters.
32: *
33: * Apple96Chip.m - Chip-specific methods for Apple96 SCSI driver.
34: *
35: * Edit History
36: * 1997.02.18 MM Initial conversion from AMDPCSCSIDriver sources.
37: * 1997.04.17 MM Removed SCS_PHASECHANGE (not needed)
38: */
39: #import "Apple96SCSI.h"
40: #import "Apple96ISR.h"
41: #import "Apple96BusState.h"
42: #import "Apple96Curio.h"
43: #import "Apple96CurioPublic.h"
44: #import "Apple96CurioPrivate.h"
45: #import "Apple96SCSIPrivate.h"
46: #import "MacSCSICommand.h"
47: #import "bringup.h"
48: #import <driverkit/generalFuncs.h>
49: #import <kernserv/prototypes.h>
50:
51: IONamedValue scsiMsgValues[] = {
52: { kScsiMsgCmdComplete, "Command Complete" },
53: { kScsiMsgExtended, "Extended Message" },
54: { kScsiMsgSaveDataPointers, "Save Pointers" },
55: { kScsiMsgRestorePointers, "Restore Pointers" },
56: { kScsiMsgDisconnect, "Disconnect" },
57: { kScsiMsgInitiatorDetectedErr, "Initiator Det Error" },
58: { kScsiMsgAbort, "Abort" },
59: { kScsiMsgRejectMsg, "Message Reject" },
60: { kScsiMsgNop, "Nop" },
61: { kScsiMsgParityErr, "Message parity Error" },
62: { 0, NULL }
63: };
64:
65: IONamedValue scsiPhaseValues[] = {
66: { kBusPhaseDATO, "data out" },
67: { kBusPhaseDATI, "data in" },
68: { kBusPhaseCMD, "command" },
69: { kBusPhaseSTS, "status" },
70: { kBusPhaseMSGO, "message out" },
71: { kBusPhaseMSGI, "message in" },
72: { kBusPhaseBusFree, "bus free" },
73: { 0, NULL }
74: };
75:
76: /*
77: * For IOFindNameForValue() and ddm's.
78: */
79: IONamedValue gAutomatonStateValues[] = {
80: {SCS_UNINITIALIZED, "uninitialized" },
81: {SCS_DISCONNECTED, "disconnected" },
82: {SCS_SELECTING, "selecting" },
83: {SCS_RESELECTING, "reselection in progress" },
84: {SCS_INITIATOR, "in progress, initiator" },
85: {SCS_COMPLETING, "completing command" },
86: {SCS_WAIT_FOR_BUS_FREE, "waiting for bus free" },
87: {SCS_DMACOMPLETE, "waiting for dma completion" },
88: {SCS_SENDINGMSG, "sending message bytes" },
89: {SCS_GETTINGMSG, "receiving message bytes" },
90: {SCS_SENDINGCMD, "sending command bytes" },
91: {SCS_DEATH_MARCH, "error recovery" },
92: {0, NULL },
93: };
94:
95: @implementation Apple96_SCSI(InterruptService)
96:
97: /*
98: * SCSI device interrupt handler. We are called with interrupts disabled.
99: * ** ** ** Check whether interrupts are actually disabled!
100: */
101: - (void) hardwareInterrupt
102: {
103: ENTRY("Hin hardwareInterrupt");
104: if (CURIOinterruptPending()) {
105: ddmChip("hardwareInterrupt entry: cmd %08x [%02x],"
106: " status %02x, intr %02x, bus state: %s\n",
107: gActiveCommand,
108: (gCurrentTarget << 4) | gCurrentLUN,
109: gSaveStatus,
110: gSaveInterrupt,
111: IOFindNameForValue(gBusState, gAutomatonStateValues)
112: );
113: /*
114: * There is an interrupt pending for this device. Note:
115: * because we can cycle through this sequence, it must
116: * be executed from a (high-priority) I/O thread, and not
117: * from a primary interrupt service routine.
118: */
119: gFlagCheckForAnotherInterrupt = TRUE;
120: do {
121: gFlagNeedAnotherInterrupt = FALSE;
122: ddmChip("hardwareInterrupt loop: cmd %08x [%02x],"
123: " status %02x, intr %02x, bus state: %s\n",
124: gActiveCommand,
125: (gCurrentTarget << 4) | gCurrentLUN,
126: gSaveStatus,
127: gSaveInterrupt,
128: IOFindNameForValue(gBusState, gAutomatonStateValues)
129: );
130: if ((gSaveInterrupt & sGrossErr) != 0) {
131: /*
132: * Gross error is set incorrectly (according to
133: * Clinton Bauder).
134: */
135: ddmChip("Gross error: ignored, sts %02x, int %02x\n",
136: gSaveStatus, gSaveInterrupt, 3, 4, 5);
137: gSaveInterrupt &= ~sGrossErr;
138: }
139: if ((gSaveInterrupt & iIlegalCmd) != 0) {
140: /*
141: * Software screwup (gross error). Start over from scratch.
142: * We can get this if we write too many commands into the register.
143: */
144: [self logRegisters : FALSE reason : "Illegal command interrupt"];
145: if (gBusState != SCS_DEATH_MARCH) {
146: [self fsmStartErrorRecovery
147: : SR_IOST_INT
148: reason : "Illegal command interrupt"
149: ];
150: }
151: gFlagCheckForAnotherInterrupt = FALSE;
152: } /* If chip error */
153: if ((gSaveInterrupt & iDisconnect) != 0) {
154: ddmChip("hardwareInterrupt: enabling reselection\n", 1,2,3,4,5);
155: CURIOenableSelectionOrReselection();
156: /*
157: * Radar 1678545: this is the only (normal) place
158: * that gFlagBusBusy is cleared. (It's also cleared by
159: * bus reset and driver initialization.)
160: */
161: gFlagBusBusy = FALSE;
162: }
163: if ((gSaveInterrupt & iResetDetect) != 0) {
164: IOLog("%s: SCSI Bus Reset\n", [self name]);
165: /*
166: * While we would like to abort all pending and active commands,
167: * we can't do this without taking the pending command lock,
168: * which can, conceivably, lead to a race condition. If this
169: * (quick and dirty) analysis is incorrect, enable the following:
170: * [self abortAllCommands : SR_IOST_RESET];
171: */
172: [self curioHardwareReset
173: : FALSE
174: reason : "SCSI Bus Reset"
175: ];
176: gFlagCheckForAnotherInterrupt = FALSE;
177: } /* If bus reset */
178: else if ((gSaveStatus & sParityErr) != 0 && gFlagBusBusy) {
179: [self fsmStartErrorRecovery
180: : SR_IOST_PARITY
181: reason : "SCSI bus parity error"
182: ];
183: gFlagCheckForAnotherInterrupt = FALSE;
184: } /* If device parity error and not disconnected */
185: else {
186: /*
187: * Only certain states are legal if the bus is busy.
188: */
189: if (gFlagBusBusy) {
190: /*
191: * This is a legitimate interrupt (parity error and bus reset
192: * have already been handled). The entity that started the
193: * chip action that caused the interrupt (deep breath)
194: * set gBusState to indicate why the interrupt happened.
195: * Call the proper finite-state machine function. On return,
196: * gBusState will be set to one of the following values:
197: * SCS_INITIATOR Start an action on the current phase.
198: * SCS_DISCONNECT The bus is free.
199: * SCS_WAIT_FOR_BUS_FREE The bus should go free shortly.
200: * Note that SCS_WAIT_FOR_BUS_FREE and fsmWaitForBusFree
201: * short-circuit some of the automaton to avoid unnecessary
202: * interrupt events.
203: */
204: switch (gBusState) {
205: case SCS_DISCONNECTED: [self fsmDisconnected]; break;
206: case SCS_SELECTING: [self fsmSelecting]; break;
207: case SCS_RESELECTING: [self fsmReselecting]; break;
208: case SCS_INITIATOR: [self fsmInitiator]; break;
209: case SCS_COMPLETING: [self fsmCompleting]; break;
210: case SCS_DMACOMPLETE: [self fsmDMAComplete]; break;
211: case SCS_SENDINGMSG: [self fsmSendingMsg]; break;
212: case SCS_GETTINGMSG: [self fsmGettingMsg]; break;
213: case SCS_SENDINGCMD: [self fsmSendingCmd]; break;
214: case SCS_WAIT_FOR_BUS_FREE: [self fsmWaitForBusFree]; break;
215: case SCS_DEATH_MARCH: [self fsmErrorRecoveryInterruptService]; break;
216: case SCS_UNINITIALIZED: /* Illegal here */
217: default:
218: IOLog("%s: Bug: illegal interrupt state: %s\n",
219: [self name],
220: IOFindNameForValue(gSaveStatus & mPhase, scsiPhaseValues)
221: );
222: IOPanic("Apple96 SCSI: Illegal bus automaton state.");
223: } /* switch gBusState */
224: }
225: else {
226: /*
227: * The bus is (or just went) free. We only allow selection, reselection,
228: * wait for disconnect, or death march interrupts.
229: */
230: switch (gBusState) {
231: case SCS_DISCONNECTED: [self fsmDisconnected]; break;
232: case SCS_SELECTING: [self fsmSelecting]; break;
233: case SCS_WAIT_FOR_BUS_FREE: [self fsmWaitForBusFree]; break;
234: case SCS_DEATH_MARCH: [self fsmErrorRecoveryInterruptService]; break;
235: default:
236: [self fsmStartErrorRecovery
237: : SR_IOST_HW
238: reason : "Strange SCSI state when bus free"
239: ];
240: gFlagCheckForAnotherInterrupt = FALSE;
241: } /* switch gBusState */
242: }
243: }
244: /*
245: * We have (presumably) completely handled the previous interrupt.
246: * At this point, there are five legitimate gBusState values:
247: * SCS_RESELECTING Just got a reselection interrupt
248: * SCS_INITIATOR Continue operation for this target.
249: * SCS_DISCONNECTED Enable selection/reselection
250: * SCS_WAIT_FOR_BUS_FREE Command completion transition
251: * SCS_DEATH_MARCH Error recovery
252: * Handle a SCSI Phase change if necessary. This will leave
253: * the bus state in the "expected" state for the next operation.
254: */
255: switch (gBusState) {
256: case SCS_DEATH_MARCH:
257: gFlagCheckForAnotherInterrupt = FALSE;
258: break;
259: case SCS_RESELECTING:
260: [self fsmReselectionAction];
261: break;
262: case SCS_INITIATOR:
263: if ( gFlagNeedAnotherInterrupt ) // from tagged reselect
264: {
265: gFlagNeedAnotherInterrupt = FALSE;
266: if ( [ self curioQuickCheckForChipInterrupt ] )
267: [ self fsmPhaseChange ];
268: }
269: else
270: {
271: [ self fsmPhaseChange ];
272: }
273: break;
274: case SCS_WAIT_FOR_BUS_FREE:
275: break;
276: default:
277: break;
278: }
279: /*
280: * This is the final check: if we determine that the previous action will
281: * complete quickly (for example, it's a message in byte), we'll spin for
282: * up to ten microseconds to see if the chip is ready for another operation.
283: */
284: } while (gFlagCheckForAnotherInterrupt && CURIOquickCheckForChipInterrupt());
285: if (gBusState == SCS_DEATH_MARCH) {
286: [self fsmContinueErrorRecovery];
287: }
288: if (gBusState == SCS_DISCONNECTED) {
289: [self busFree];
290: }
291: ddmChip("hardwareInterrupt: DONE; state: %s, phase %s\n",
292: IOFindNameForValue(gBusState, gAutomatonStateValues),
293: IOFindNameForValue(gCurrentBusPhase, scsiPhaseValues),
294: 3,4,5
295: );
296: }
297: EXIT();
298: }
299:
300: @end /* Apple96_SCSI(InterruptService) */
301:
302: /* end of Apple96_Chip.m */
303:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.