]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | |
2 | ; Copyright (c) 1997-1999 Apple Computer, Inc. All rights reserved. | |
3 | ; | |
4 | ; @APPLE_LICENSE_HEADER_START@ | |
5 | ; | |
6 | ; The contents of this file constitute Original Code as defined in and | |
7 | ; are subject to the Apple Public Source License Version 1.1 (the | |
8 | ; "License"). You may not use this file except in compliance with the | |
9 | ; License. Please obtain a copy of the License at | |
10 | ; http://www.apple.com/publicsource and read it before using this file. | |
11 | ; | |
12 | ; This Original Code and all software distributed under the License are | |
13 | ; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | ; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | ; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | ; FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | ; License for the specific language governing rights and limitations | |
18 | ; under the License. | |
19 | ; | |
20 | ; @APPLE_LICENSE_HEADER_END@ | |
21 | ; | |
22 | ; File Ownership: | |
23 | ; | |
24 | ; DRI: Mike Johnson | |
25 | ; | |
26 | ; Other Contact: Russ Berkoff | |
27 | ; | |
28 | ; Technology: SCSI | |
29 | ; | |
30 | ; Writers: | |
31 | ; | |
32 | ; (MLJ) Mike Johnson | |
33 | ; (RRA) Rick Auricchio | |
34 | ||
35 | ||
36 | ; NCR Errata Listing 125 Item 1 : Clear the SCNTL0 start bit | |
37 | ; when jump to reselect during select (try_reselect) | |
38 | ; | |
39 | ; NCR Errata Listing 117 Item 4 : Bad parity if odd bytes during | |
40 | ; wide transfer. Only for DATA OUT in Initiator mode. | |
41 | ; (Confirm by Manfred Eierle 3rd June 93 not during DATA IN) | |
42 | ||
43 | ARCH 825A ;specifically for 825a and 875 (new instructions) | |
44 | ||
45 | ||
46 | ;***************************************************************** | |
47 | ; | |
48 | ; Phase codes - These values represent which action is being handled | |
49 | ; | |
50 | ;***************************************************************** | |
51 | ||
52 | ABSOLUTE kphase_DATA_OUT = 0x00 | |
53 | ABSOLUTE kphase_DATA_IN = 0x01 | |
54 | ABSOLUTE kphase_COMMAND = 0x02 | |
55 | ABSOLUTE kphase_STATUS = 0x03 | |
56 | ABSOLUTE kphase_MSG_OUT = 0x06 | |
57 | ABSOLUTE kphase_MSG_IN = 0x07 | |
58 | ABSOLUTE kphase_SELECT = 0x08 | |
59 | ABSOLUTE kphase_RESELECT = 0x09 | |
60 | ABSOLUTE kphase_ABORT_CURRENT = 0x0A | |
61 | ABSOLUTE kphase_ABORT_MAILBOX = 0x0B | |
62 | ABSOLUTE kphase_CMD_COMPLETE = 0x0C | |
63 | ABSOLUTE kphase_DISCONNECT = 0x0D | |
64 | ABSOLUTE kphase_saveDataPointer = 0x0E ; ??? driver work to be done | |
65 | ABSOLUTE kphase_restoreDataPointer = 0x0F ; ??? driver work to be done | |
66 | ||
67 | ||
68 | ;***************************************************************** | |
69 | ; interrupt codes | |
70 | ;***************************************************************** | |
71 | ||
72 | ABSOLUTE unknown_phase = 0x00 ; A spurious phase on SCSI Bus | |
73 | ABSOLUTE status_error = 0x01 ; IO completes, but with status error | |
74 | ABSOLUTE unexpected_msg = 0x02 ; An 'unknown' message is in ld_message var | |
75 | ABSOLUTE unexpected_ext_msg = 0x03 ; An 'unknown' extended message in ld_message | |
76 | ABSOLUTE wide_32_not_supported = 0x04 ; The device wants 32 bits data phase | |
77 | ABSOLUTE no_msgin_after_reselect = 0x05 ; No message-in after reselection | |
78 | ABSOLUTE reqack_too_large = 0x06 ; The device answer ReqAck offset is greater than 8 | |
79 | ABSOLUTE unknown_reselect = 0x07 ; The valid bit in SFBR reg not set | |
80 | ABSOLUTE unallocated_nexus = 0x08 ; nexus index -> 0xFFFFFFFF | |
81 | ABSOLUTE abort_mailbox = 0x09 ; Abort/BDR mailbox completed | |
82 | ABSOLUTE abort_current = 0x0A ; Abort/BDR current op completed | |
83 | ABSOLUTE unknown_message_out = 0x0B ; Unknown phase before message out | |
84 | ABSOLUTE unknown_msg_reject = 0x0C ; Unknown message reject | |
85 | ABSOLUTE negotiateSDTR = 0x0D ; Sync negotiation rx'd | |
86 | ABSOLUTE negotiateWDTR = 0x0E ; Wide negotiation rx'd | |
87 | ABSOLUTE sglist_complete = 0x0F ; SGList complete | |
88 | ||
89 | ||
90 | ;***************************************************************** | |
91 | ; | |
92 | ; Data structure for T/L/Q Nexus: | |
93 | ; | |
94 | ;***************************************************************** | |
95 | ||
96 | ABSOLUTE TLQ_SCSI_ID = 0 ; 4 SCSI ID et al for SELECT instruction | |
97 | ABSOLUTE TLQ_xferAdr = 4 ; 4 Physical address of CHMOV instructions | |
98 | ABSOLUTE TLQ_MSGOp = 8 ; 8 Byte count, data adr -> TLQ_MSGO | |
99 | ABSOLUTE TLQ_CDBp = 16 ; 8 Byte count, data adr -> TLQ_CDB | |
100 | ABSOLUTE TLQ_CDP = 24 ; 4 Current Data Pointer | |
101 | ABSOLUTE TLQ_SDP = 28 ; 4 Saved Data Pointer | |
102 | ABSOLUTE TLQ_index = 32 ; 1 index into nexus array | |
103 | ABSOLUTE TLQ_xferStarted= 33 ; 1 transfer started flag | |
104 | ABSOLUTE TLQ_IWR = 34 ; 1 flag to Ignore Wide Residue | |
105 | ABSOLUTE TLQ_pad = 35 ; 1 pad byte | |
106 | ||
107 | ||
108 | ;***************************************************************** | |
109 | ; | |
110 | ; ENTRY declarations - Declare entry points for driver | |
111 | ; | |
112 | ;***************************************************************** | |
113 | ||
114 | ENTRY select_phase | |
115 | ENTRY phase_handler | |
116 | ENTRY issueMessageOut ; for negotiation and Reject messages | |
117 | ENTRY issueAbort_BDR ; to immediately Abort or Bus-Device-Reset | |
118 | ENTRY clearACK ; MsgIn done - clr ACK, jump to phase handler | |
119 | ||
120 | ||
121 | ;***************************************************************** | |
122 | ; | |
123 | ; Define local data structure at start of SCRIPTS. | |
124 | ; This structure is allocated by the following nops. | |
125 | ; | |
126 | ;***************************************************************** | |
127 | ; | |
128 | ||
129 | RELATIVE local_data \ | |
130 | ld_AbortCode = 4{??}\ ; 1 byte code to Abort or BDR | |
131 | ld_zeroes = 4{??}\ ; 4 bytes of 0 to clear registers | |
132 | ld_status = 4{??}\ ; Status byte from target | |
133 | ld_counter = 4{??}\ ; index into mailbox array | |
134 | ld_AbortBdr_mailbox = 4{??}\ ; Abort/BusDeviceReset mailbox | |
135 | ld_IOdone_mailbox = 4{??}\ ; [ nexus 0 0 semaphore ] | |
136 | ld_sched_mlbx_base_adr = 4{??}\ ; base addr of mailbox array | |
137 | ld_mailboxp = 4{??}\ ; address of current mailbox | |
138 | ld_scsi_id = 4{??}\ ; ptr to current mailbox | |
139 | ld_nexus_array_base = 4{??}\ ; base address of Nexus pointers | |
140 | ld_nexus_index = 4{??}\ ; index to Nexus pointer | |
141 | ld_nexus = 4{??}\ ; address of Nexus | |
142 | ld_phase_flag = 4{??}\ ; for debugging | |
143 | ld_device_table_base_adr = 4{??}\ ; device configuration table | |
144 | ld_scratch = 4{??}\ ; scratch memory | |
145 | ld_unused = 4{??}\ ; unused | |
146 | ld_message = 4{??}\ ; buffer for MsgIn bytes | |
147 | ld_message4 = 4{??}\ ; buffer continuation | |
148 | ld_pad = 4{??}\ ; padding | |
149 | ld_size = 4{??} ; size of this structure | |
150 | ||
151 | ||
152 | PROC BSC_SCRIPT: | |
153 | ||
154 | ; *** These NOPs must be at address 0. *** | |
155 | ; *** This is reserved space for the structure "local_data". *** | |
156 | ; *** The driver inits this area to zero. *** | |
157 | ||
158 | nop 0 ; ld_AbortCode, ld_zeroes | |
159 | nop 0 ; ld_status, ld_counter | |
160 | ||
161 | nop 0 ; ld_AbortBdr_mailbox, ld_IOdone_mailbox | |
162 | nop 0 ; ld_sched_mlbx_base_adr, ld_mailboxp | |
163 | ||
164 | nop 0 ; ld_scsi_id, ld_nexus_array_base | |
165 | nop 0 ; ld_nexus_index, ld_nexus | |
166 | ||
167 | nop 0 ; ld_phase_flag, ld_device_table_base_adr | |
168 | nop 0 ; ld_scratch, ld_unused | |
169 | ||
170 | nop 0 ; ld_message, ld_message4 | |
171 | nop ld_size ; ld_pad, ld_size (Use ld_size or lose it) | |
172 | ||
173 | nop sglist_complete ; use sglist_complete or lose it from gen'd output file | |
174 | ||
175 | ;**************************************************************************** | |
176 | ; | |
177 | ; findNexusFromIndex - load DSA with pointer to Nexus given a Nexus index: | |
178 | ; | |
179 | ;**************************************************************************** | |
180 | ||
181 | findNexusFromIndex: | |
182 | ||
183 | load SCRATCHA0, 4, ld_nexus_index ; load index and leading zeroes | |
184 | clear CARRY | |
185 | move SCRATCHA0 SHL 0 to SCRATCHA0 ; double the index | |
186 | move SCRATCHA1 SHL 0 to SCRATCHA1 | |
187 | move SCRATCHA0 SHL 0 to SCRATCHA0 ; double again | |
188 | move SCRATCHA1 SHL 0 to SCRATCHA1 ; A0 now has index to 4-byte address | |
189 | store SCRATCHA0, 4, patchArrayOffset+4 ; *** patch the code | |
190 | ||
191 | load DSA0, 4, ld_nexus_array_base ; load base address of array of Nexus pointers | |
192 | patchArrayOffset: | |
193 | load DSA0, 4, DSAREL( 0 ) ; *** patched offset. Load pointer. | |
194 | ||
195 | move DSA0 to SFBR ; Ensure pointer is not 0xFFFFFFFF | |
196 | int unallocated_nexus, if 0xFF ; Interrupt if NFG | |
197 | ||
198 | store DSA0, 4, ld_nexus ; Store the Nexus pointer | |
199 | return ; end findNexusFromIndex | |
200 | ||
201 | ||
202 | ;**************************************************************************** | |
203 | ; | |
204 | ; initContext - Initialize the registers for Sync and Wide using | |
205 | ; values stored in the device configuration table. | |
206 | ; Return with values in SCRATCHB for Select code. | |
207 | ; | |
208 | ;**************************************************************************** | |
209 | ||
210 | initContext: | |
211 | ||
212 | load SCRATCHB0, 4, ld_scsi_id ; load 4-bit SCSI ID and zeroes | |
213 | clear CARRY | |
214 | move SCRATCHB0 SHL SCRATCHB0 ; * 2 | |
215 | move SCRATCHB0 SHL SCRATCHB0 ; * 2 -> UInt32 index | |
216 | store SCRATCHB0, 4, patchGetDevConfigOffset+4 ; *** Patch load code | |
217 | ||
218 | load DSA0, 4, ld_device_table_base_adr ; load base physical addr of tables | |
219 | ||
220 | patchGetDevConfigOffset: | |
221 | load SCRATCHB0, 4, DSAREL( 0 ) ; *** Patched table offset *** | |
222 | ||
223 | ; SCRATCHB0 = 0 | |
224 | ; SCRATCHB1 = TP,MO (SXFER bits7-5 bits3-0) | |
225 | ; SCRATCHB2 = 0 (position for SCSI ID) | |
226 | ; SCRATCHB3 = SCCF,EWS (SCNTL3 bits6-4 bit 3) | |
227 | ||
228 | move SCRATCHB1 to SFBR ; init SXFER from B1 | |
229 | move SFBR to SXFER | |
230 | ; Init SCNTL3 from B3 | |
231 | move SCRATCHB3 to SFBR | |
232 | move SFBR to SCNTL3 | |
233 | return ; return with SCRATCHB intact. | |
234 | ||
235 | ||
236 | ;***************************************************************** | |
237 | ; | |
238 | ; Select_phase: | |
239 | ; Clear the SIGP bit. | |
240 | ; Check if any Abort/BusDeviceReset request waiting. | |
241 | ; Nexus is found in the list of 256 mailboxes. | |
242 | ; If current mailbox is empty, jump to reselect_phase. | |
243 | ; SCRIPTS tries to select device. | |
244 | ; If select fails due to reselect, jump to reselect_phase | |
245 | ; Select Timeout handled by driver. | |
246 | ; If select succeeds, clear the mailbox entry | |
247 | ; and increment the mailbox counter. | |
248 | ; Jump to the phase_handler (hopefully for MSG_OUT) | |
249 | ; | |
250 | ;***************************************************************** | |
251 | ||
252 | select_phase: | |
253 | ||
254 | move CTEST2 | 0x00 to CTEST2 ; Clear SIGP bit from ISTAT reg | |
255 | ||
256 | ; Check abort mailbox: | |
257 | ||
258 | load SCRATCHA0, 4, ld_AbortBdr_mailbox ; Get AbortBdr mailbox | |
259 | ; The Identify byte in byte 0 is also the semaphore | |
260 | ; A0 = Identify byte (0xC0 + LUN N.B. Disconnect allowed) | |
261 | ; A1 = Tag, if any | |
262 | ; A2 = SCSI ID | |
263 | ; A3 = Abort code Abort=0x06; Abort Tag=0D; Bus Device Reset=0x0C | |
264 | move SCRATCHA0 to SFBR ; test the semaphore/Identify | |
265 | jump rel( AbortMailbox ), if not 0 ; jump if aborting | |
266 | ||
267 | ||
268 | ; Get the next IO nexus in the mailboxes circular list. | |
269 | ; Calculate current mailbox address as so: | |
270 | ; counter byte index * 4 to get mailbox index | |
271 | ; add base physical address of mailboxes giving current mailbox address | |
272 | ||
273 | load SCRATCHA0, 4, ld_counter ; get 1-byte mailbox counter & 0s | |
274 | clear CARRY | |
275 | move SCRATCHA0 SHL 0 to SCRATCHA0 ; double it | |
276 | move SCRATCHA1 SHL 0 to SCRATCHA1 | |
277 | move SCRATCHA0 SHL 0 to SCRATCHA0 ; double it again | |
278 | move SCRATCHA1 SHL 0 to SCRATCHA1 ; now have a UInt32 index | |
279 | store SCRATCHA0, 4, fetchMailbox+4 ; *** patch the load DSA instruction | |
280 | store SCRATCHA0, 4, clear_mailbox+4 ; *** patch the store DSA instruction | |
281 | ||
282 | load DSA0, 4, ld_sched_mlbx_base_adr ; load base physical address of mailboxes | |
283 | ||
284 | fetchMailbox: | |
285 | load DSA0, 4, DSAREL( 0 ) ; *** Patched offset. Load Nexus address | |
286 | store DSA0, 4, ld_nexus ; save pointer to current Nexus | |
287 | load SCRATCHA0, 4, ld_nexus ; copy to A0 | |
288 | ||
289 | move SCRATCHA0 to SFBR ; | |
290 | jump rel( next_mailbox ), if 1 ; if low-byte == 0x01 then cancelled mailbox | |
291 | ||
292 | move SCRATCHA1 | SFBR to SFBR ; if non-zero, have implicit semaphore | |
293 | move SCRATCHA2 | SFBR to SFBR | |
294 | move SCRATCHA3 | SFBR to SFBR | |
295 | jump rel( reselect_phase ), if 0 ; go to reselect_phase if empty | |
296 | ||
297 | ;***************************************************************** | |
298 | ; | |
299 | ; Something in mailbox: we have work to do | |
300 | ; | |
301 | ;***************************************************************** | |
302 | ||
303 | move kphase_SELECT to SCRATCHB0 ; set phase indicator | |
304 | store SCRATCHB0, 1, ld_phase_flag | |
305 | ||
306 | load SCRATCHB0, 4, ld_zeroes ; clr the invalid-nexus-index flag | |
307 | load SCRATCHB0, 1, DSAREL( TLQ_index ) ; get index byte from nexus | |
308 | store SCRATCHB0, 4, ld_nexus_index ; save it in local data | |
309 | ||
310 | load DSA0, 4, ld_nexus ; restore DSA register | |
311 | load SCRATCHB2, 1, DSAREL( TLQ_SCSI_ID+2 ) ; get Target's SCSI ID | |
312 | move SCRATCHB2 to SFBR | |
313 | move SFBR to SCRATCHB0 ; position it | |
314 | store SCRATCHB0, 1, ld_scsi_id ; save it | |
315 | call rel( initContext ) ; setup Sync/Wide regs in SCRATCHB | |
316 | load DSA0, 4, ld_nexus ; restore DSA register | |
317 | store SCRATCHB1, 1, DSAREL( TLQ_SCSI_ID+1 ) ; SXFER | |
318 | store SCRATCHB3, 1, DSAREL( TLQ_SCSI_ID+3 ) ; SCNTL3 | |
319 | ||
320 | ;********************** select the device ******************************** | |
321 | SELECT ATN from TLQ_SCSI_ID, rel( try_reselect ) ; ************************ | |
322 | ;************************************************************************* | |
323 | ||
324 | ; looking good - clear the mailbox: | |
325 | ||
326 | next_mailbox: | |
327 | load SCRATCHA0, 4, ld_zeroes ; zero out scratch register A | |
328 | load DSA0, 4, ld_sched_mlbx_base_adr ; load base physical address of mailboxes | |
329 | clear_mailbox: | |
330 | store SCRATCHA0, 4, DSAREL( 0 ) ; *** Patched offset. Zero the mailbox | |
331 | ||
332 | ; Update the index to the mailbox circular list: | |
333 | load SCRATCHB0, 1, ld_counter ; get counter (mailbox index) | |
334 | move SCRATCHB0 + 1 to SCRATCHB0 ; add 1 | |
335 | store SCRATCHB0, 1, ld_counter ; put it back | |
336 | ||
337 | load SCRATCHB0, 1, ld_nexus ; if low-byte == 0x01 then cancelled mailbox | |
338 | move SCRATCHB0 to SFBR | |
339 | jump rel( select_phase ), if 1 | |
340 | ||
341 | ; *** FALL THROUGH TO phase_handler *** | |
342 | ||
343 | ||
344 | ;***************************************************************** | |
345 | ; | |
346 | ; Phase_handler | |
347 | ; The phase handler script is a dispatcher function of SCSI phase | |
348 | ; | |
349 | ;***************************************************************** | |
350 | ||
351 | phase_handler: | |
352 | load DSA0, 4, ld_nexus ; reload DSA | |
353 | jump rel( command_phase ), when CMD ; wait for REQ | |
354 | jump rel( data_out_phase ), if DATA_OUT ; already latched REQ signal | |
355 | jump rel( message_out_phase ), if MSG_OUT | |
356 | jump rel( data_in_phase ), if DATA_IN | |
357 | jump rel( status_phase ), if STATUS | |
358 | jump rel( message_in_phase ), if MSG_IN | |
359 | int unknown_phase | |
360 | ||
361 | ||
362 | ;***************************************************************** | |
363 | ; | |
364 | ; Message-Out phase | |
365 | ; | |
366 | ;***************************************************************** | |
367 | ||
368 | message_out_phase: | |
369 | move kphase_MSG_OUT to SCRATCHB0 ; Set phase indicator | |
370 | store SCRATCHB0, 1, ld_phase_flag | |
371 | ||
372 | move from TLQ_MSGOp, when MSG_OUT ; put out the message(s) | |
373 | jump rel( phase_handler ) | |
374 | ||
375 | ||
376 | ; issueMessageOut - Driver entry point for Sync/Wide negotiation and | |
377 | ; to issue message Reject: | |
378 | ||
379 | issueMessageOut: | |
380 | set ATN ; tell Target we have something to say | |
381 | clear ACK | |
382 | jump rel( message_out_phase ), when MSG_OUT ; wait for REQ. Jump if msg-out phase. | |
383 | jump rel( phase_handler ), if not MSG_IN ; jump if weird phase | |
384 | move 1, ld_scratch+1, when MSG_IN ; dump the msg byte | |
385 | clear ACK ; accept Target's last msg-in byte | |
386 | jump rel( issueMessageOut ) | |
387 | ||
388 | ||
389 | ;***************************************************************** | |
390 | ; | |
391 | ; Command phase | |
392 | ; | |
393 | ;***************************************************************** | |
394 | ||
395 | command_phase: | |
396 | move kphase_COMMAND to SCRATCHB0 ; Set phase indicator | |
397 | store SCRATCHB0, 1, ld_phase_flag | |
398 | ||
399 | clear ATN ; In case we missed the sending nego | |
400 | move FROM TLQ_CDBp, when CMD ; issue the CDB | |
401 | jump rel( phase_handler ) | |
402 | ||
403 | ||
404 | ;***************************************************************** | |
405 | ; | |
406 | ; Data_out_phase | |
407 | ; | |
408 | ;***************************************************************** | |
409 | ||
410 | data_out_phase: | |
411 | move kphase_DATA_OUT to SCRATCHB0 ; Set phase indicator | |
412 | store SCRATCHB0, 1, ld_phase_flag | |
413 | ||
414 | call rel( driverXfer ) ; call driver-built CHMOV instructions | |
415 | jump rel( phase_handler ) ; if all data xfer'd, get next phase | |
416 | ||
417 | driverXfer: ; get here from data-in code also | |
418 | load SCRATCHA0, 4, DSAREL( TLQ_xferAdr ) | |
419 | store SCRATCHA0, 4, doItPatch+4 ; *** patch the JUMP address | |
420 | move 0xFF to SCRATCHA1 | |
421 | store SCRATCHA1, 1, DSAREL( TLQ_xferStarted ) | |
422 | ||
423 | doItPatch: | |
424 | jump 0x0333 ; *** patched address | |
425 | ||
426 | ||
427 | ||
428 | ;***************************************************************** | |
429 | ; | |
430 | ; Data_in_phase | |
431 | ; 875 sets ATN if bad parity detected. | |
432 | ; Use of CHMOV instructions assures that we properly handle | |
433 | ; a leftover wide byte in the SWIDE or SODL register, depending | |
434 | ; on the data direction. This can happen in either of two conditions: | |
435 | ; 1. The Target disconnects at an odd boundary. This is | |
436 | ; extremely unlikely with disk devices. | |
437 | ; 2. The client passes either an odd buffer address or | |
438 | ; an odd transfer count. When the Target disconnects (at | |
439 | ; an even boundary, we end up with the extra wide | |
440 | ; byte in SWIDE or SODL. MacOS does this with VM on. | |
441 | ; | |
442 | ;***************************************************************** | |
443 | ||
444 | data_in_phase: | |
445 | move kphase_DATA_IN to SCRATCHB0 ; Set phase indicator | |
446 | store SCRATCHB0, 1, ld_phase_flag | |
447 | ||
448 | call rel( driverXfer ) ; call driver-built CHMOV instructions | |
449 | ||
450 | ; The driver gets interrupted if a phase mismatch occurs as when | |
451 | ; the Target goes MSG-IN with a Disconnect. | |
452 | ; The driver codes either a RETURN if the Scatter/Gather list is complete or | |
453 | ; an INT if more Scatter/Gather elements need to be generated. | |
454 | ; On the Macintosh, client programs expect extra incoming data to be dumped. | |
455 | ; For example, during boot the ROM reads 512 bytes from a 2K-byte-sector CD. | |
456 | ||
457 | bucket_loop: | |
458 | jump rel( phase_handler ), when not DATA_IN ; wait for phase, exit if changed | |
459 | CHMOV 1, ld_status, when DATA_IN ; eat a byte | |
460 | jump rel( bucket_loop ); ; keep dumping bytes | |
461 | ||
462 | ||
463 | ;***************************************************************** | |
464 | ; | |
465 | ; Status phase | |
466 | ; | |
467 | ;***************************************************************** | |
468 | ||
469 | status_phase: | |
470 | move kphase_STATUS to SCRATCHB0 ; Set phase indicator | |
471 | store SCRATCHB0, 1, ld_phase_flag | |
472 | ||
473 | move 1, ld_status, when STATUS ; Read Status byte from bus | |
474 | jump rel( phase_handler ) | |
475 | ||
476 | ||
477 | ;***************************************************************** | |
478 | ; | |
479 | ; Message-In phase | |
480 | ; | |
481 | ;***************************************************************** | |
482 | ||
483 | message_in_phase: | |
484 | move kphase_MSG_IN to SCRATCHB0 ; Set phase indicator | |
485 | store SCRATCHB0, 1, ld_phase_flag | |
486 | ||
487 | move 1, ld_message, when MSG_IN ; Read byte from bus | |
488 | ||
489 | jump rel( cmdComplete ), if 0x00 ; Command Complete | |
490 | jump rel( saveDataPointer ), if 0x02 ; Save Data Pointer | |
491 | jump rel( disconnect_msg ), if 0x04 ; Disconnect | |
492 | jump rel( ignoreWideResidue ), if 0x23 ; Ignore Wide Residue | |
493 | jump rel( restoreDataPointer ), if 0x03 ; Restore Data Pointer | |
494 | jump rel( extended_msg ), if 0x01 ; Extended message | |
495 | jump rel( msg_reject ), if 0x07 ; Message Reject | |
496 | ; Identify, if 0x80-FF ; Identify + LUN | |
497 | ; simple_queue_tag, if 0x20 ; Simple Queue Tag | |
498 | ; initiate_recovery, if 0x0F ; Initiate Recovery | |
499 | ; linked_cde_complete, if 0x0A/0x0B | |
500 | int unexpected_msg ; unknown | |
501 | ||
502 | msg_reject: | |
503 | int unknown_msg_reject | |
504 | ||
505 | clearACK: ; ENTRY point to end negotiation | |
506 | clear ACK | |
507 | jump rel( phase_handler ) | |
508 | ||
509 | ||
510 | ||
511 | ;***************************************************************** | |
512 | ; | |
513 | ; Ignore Wide Residue | |
514 | ; | |
515 | ;***************************************************************** | |
516 | ||
517 | ignoreWideResidue: ; this is a two byte message so snag the 2nd byte here | |
518 | clear ACK | |
519 | move 1, ld_message+1, when MSG_IN ; save residue count | |
520 | move SFBR to SCRATCHB2 ; byte is still in SFBR. Position it. | |
521 | store SCRATCHB2, 1, DSAREL( TLQ_IWR ) ; Store residue count in Nexus for driver. | |
522 | clear ACK | |
523 | jump rel( phase_handler ) | |
524 | ||
525 | ||
526 | ;***************************************************************** | |
527 | ; | |
528 | ; Extended message | |
529 | ; Accept Wide and Synchronous Data Transfer messages | |
530 | ; | |
531 | ;***************************************************************** | |
532 | ||
533 | extended_msg: | |
534 | clear ACK | |
535 | move 1, ld_message+1, when MSG_IN ; read msg length byte from bus | |
536 | clear ACK | |
537 | move 1, ld_message+2, when MSG_IN ; read ext msg code from bus | |
538 | clear ACK | |
539 | ; extended_identify, IF 0x02 | |
540 | ; modify_data_pointer, if 0x00 | |
541 | jump rel( sdtr ), if 0x01 ; jump if SDTR, sync negotiation msg | |
542 | jump rel( wdtr ), if 0x03 ; jump if WDTR, wide negotiation msg | |
543 | int unexpected_ext_msg ; let driver deal with unknown | |
544 | ||
545 | ||
546 | ;***************************************************************** | |
547 | ; | |
548 | ; Command complete | |
549 | ; The Command-Complete message is sent to indicate that the | |
550 | ; IO operation has completed and valid status has been sent. | |
551 | ; The Target should then disconnect. | |
552 | ; SCRIPTS must spin until the IOdone mailbox is empty. | |
553 | ; Then it sets the IOdone mailbox with the current Nexus. | |
554 | ; The status message is analyzed. | |
555 | ; If status is good, INTF the driver and jump to select_phase. | |
556 | ; If status is NG, save it in the NEXUS and INT the driver. | |
557 | ; | |
558 | ;***************************************************************** | |
559 | ||
560 | cmdComplete: | |
561 | move kphase_CMD_COMPLETE to SCRATCHB0 ; Set phase indicator | |
562 | store SCRATCHB0, 1, ld_phase_flag | |
563 | ||
564 | move SCNTL2 & 0X7F to SCNTL2 ; Clr SDU: SCSI Disconnect Unexpected | |
565 | clear ACK | |
566 | WAIT DISCONNECT | |
567 | ||
568 | testMbxLp: ; loop until IOdone mailbox empty | |
569 | load SCRATCHA0, 4, ld_IOdone_mailbox | |
570 | move SCRATCHA3 to SFBR ; A3 = semaphore | |
571 | jump rel( testMbxLp ), if not 0 | |
572 | ||
573 | ; Fill in the IOdone mailbox with the following: | |
574 | ; A0 = index to Nexus | |
575 | ; A1 = Status | |
576 | ; A2 = 0 | |
577 | ; A3 = semaphore (FF = set) | |
578 | load SCRATCHA0, 1, ld_nexus_index ; A0 = index to Nexus | |
579 | load SCRATCHB0, 1, ld_status | |
580 | move SCRATCHB0 to SFBR | |
581 | move SFBR to SCRATCHA1 ; A1 = Status | |
582 | move 0x00 to SCRATCHA2 ; A2 = 0 | |
583 | move 0xFF to SCRATCHA3 ; A3 = semaphore IOdone mailbox | |
584 | store SCRATCHA0, 4, ld_IOdone_mailbox | |
585 | ||
586 | move SCRATCHA1 to SFBR ; Test the Status of this IO | |
587 | ; SFBR = status msg | |
588 | ; Test status - If good, Interrupt on the fly and jump to select phase | |
589 | intfly 0xFF, if 0 and mask 0xC1 ; mask off reserved bits | |
590 | jump rel( select_phase ), if 0 and mask 0xC1 | |
591 | int status_error ; Status err. Interrupt driver & stop | |
592 | ||
593 | ||
594 | ;***************************************************************** | |
595 | ; | |
596 | ; Disconnect | |
597 | ; The 8xx Accepts the disconnection and jumps to the select_phase | |
598 | ; to check for another IO | |
599 | ; | |
600 | ;***************************************************************** | |
601 | ||
602 | disconnect_msg: | |
603 | load SCRATCHB0, 1, ld_phase_flag | |
604 | move SCRATCHB0 to SFBR | |
605 | ; If we got here from reselect just bailout since ld_nexus is | |
606 | ; not setup and the code using it is not needed anyway (no data xfer) | |
607 | jump rel( bailout ), if kphase_RESELECT | |
608 | ||
609 | move kphase_DISCONNECT to SCRATCHB0 | |
610 | store SCRATCHB0, 1, ld_phase_flag | |
611 | ||
612 | bailout: | |
613 | move 0xFF to SCRATCHB3 ; invalidate nexus index for driver | |
614 | store SCRATCHB3, 1, ld_nexus_index+3 | |
615 | move SCNTL2 & 0x7F to SCNTL2 ; Clr SDU: SCSI Disconnect Unexpected | |
616 | clear ACK | |
617 | WAIT DISCONNECT ; wait for bus-free | |
618 | jump rel( select_phase ) ; go see if more to do | |
619 | ||
620 | ||
621 | ;****************************************************************** | |
622 | ; | |
623 | ; ??? mlj - saveDataPointer and restoreDataPointer are incorrect. | |
624 | ; ??? They basically do nothing. | |
625 | ; Save Data Pointer | |
626 | ; | |
627 | ;***************************************************************** | |
628 | ||
629 | saveDataPointer: | |
630 | move kphase_saveDataPointer to SCRATCHB0 | |
631 | store SCRATCHB0, 1, ld_phase_flag | |
632 | clear ACK | |
633 | jump rel( phase_handler ) | |
634 | ||
635 | ||
636 | ;****************************************************************** | |
637 | ; | |
638 | ; ??? mlj - saveDataPointer and restoreDataPointer are incorrect. | |
639 | ; ??? They basically do nothing. | |
640 | ; Restore Data Pointer | |
641 | ; The local values still blocks, still bytes and data address | |
642 | ; must be loaded from the corresponding NEXUS data set. | |
643 | ; This message should followed an IDE (parity error) | |
644 | ; | |
645 | ;***************************************************************** | |
646 | ||
647 | restoreDataPointer: | |
648 | move kphase_restoreDataPointer to SCRATCHB0 | |
649 | store SCRATCHB0, 1, ld_phase_flag | |
650 | clear ACK | |
651 | jump rel( phase_handler ) | |
652 | ||
653 | ||
654 | ;***************************************************************** | |
655 | ; | |
656 | ; Synchronous data transfer request or response | |
657 | ; | |
658 | ;***************************************************************** | |
659 | sdtr: | |
660 | move 2, ld_message+3, when MSG_IN ; Read period & offset from bus | |
661 | int negotiateSDTR | |
662 | ||
663 | ||
664 | ;*************************************************************************** | |
665 | ; | |
666 | ; Wide Data Transfer request or response | |
667 | ; | |
668 | ;*************************************************************************** | |
669 | wdtr: | |
670 | move 1, ld_message+3, when MSG_IN ; get Transfer Width Exponent fm bus | |
671 | int negotiateWDTR | |
672 | ||
673 | ||
674 | ;***************************************************************** | |
675 | ; | |
676 | ; Reselect phase | |
677 | ; The chip waits here either for a Reselection from a Target or | |
678 | ; a SIGP from the driver indicating something in the mailbox. | |
679 | ; If reselected, the script uses the Nexus value which is either | |
680 | ; a Tag or a SCSI ID/LUN combo to lookup the Nexus. | |
681 | ; Then init the SXFER and SCNTL3 registers from the device config table. | |
682 | ; | |
683 | ;***************************************************************** | |
684 | ||
685 | try_reselect: ; Select failed - probably reselecting | |
686 | ; Cf NCR Errata Listing 117 Item 1: | |
687 | move SCNTL0 & 0xDF to SCNTL0 ; clr Start bit | |
688 | move CTEST2 | 0x00 to CTEST2 ; Clear SIGP bit from ISTAT reg | |
689 | ||
690 | reselect_phase: | |
691 | move kphase_RESELECT to SCRATCHB0 ; Set phase indicator | |
692 | store SCRATCHB0, 1, ld_phase_flag | |
693 | ||
694 | move 0xFF to SCRATCHB3 ; invalidate nexus index for driver | |
695 | store SCRATCHB3, 1, ld_nexus_index+3 | |
696 | ||
697 | ; wait here for reselect from a Target | |
698 | ; or SIGP from the driver | |
699 | ||
700 | WAIT RESELECT REL( select_phase ) ; jump if SIGP | |
701 | ||
702 | ; Reselected: | |
703 | ||
704 | move SSID to SFBR ; SSID = [ Valxxx Scsi_id ] | |
705 | int unknown_reselect, if 0 and mask 0x7F; Interrupt if VAL bit not set | |
706 | move SFBR & 0x0F to SCRATCHB0 ; B0 = Target ID | |
707 | store SCRATCHB0, 1, ld_scsi_id ; save it | |
708 | ||
709 | call rel( initContext ) ; setup sync regs here | |
710 | ||
711 | int no_msgin_after_reselect, when not MSG_IN | |
712 | ||
713 | move 1, ld_message, when MSG_IN ; Read Identify byte from bus | |
714 | ||
715 | ; if another REQ is asserted, a SimpleQueueTag message should be next | |
716 | ||
717 | clear ACK ; notify Target: msg byte rx'd | |
718 | jump rel( getNextMsg ), when MSG_IN ; jump if SimpleQueueTag coming | |
719 | ||
720 | ; untagged operation: | |
721 | ||
722 | move SFBR & 0x07 to SCRATCHA0 ; isolate LUN from Identify byte | |
723 | ||
724 | load SCRATCHB0, 1, ld_scsi_id ; B0 = Target ID | |
725 | clear CARRY | |
726 | move SCRATCHB0 SHL SFBR ; shift left #1 | |
727 | move SFBR SHL SCRATCHB0 ; shift left #2 | |
728 | move SCRATCHB0 SHL SFBR ; shift left #3 | |
729 | move SCRATCHA0 | SFBR to SCRATCHA0 ; form Nexus index = 0b0TTTTLLL | |
730 | ||
731 | store SCRATCHA0, 1, ld_nexus_index ; store as index to Nexus | |
732 | jump rel( haveNexusIndex ) | |
733 | ||
734 | ; should be tagged operation: | |
735 | ||
736 | getNextMsg: | |
737 | move 1, ld_message, when MSG_IN ; read message byte from bus | |
738 | jump rel( disconnect_msg ), if 0x04 ; if Disconnect, oh well. | |
739 | clear ACK | |
740 | jump rel( phase_handler ), if not 0x20; Branch if not Queue tag code | |
741 | ; get the Queue Tag and save as the nexus index | |
742 | move 1, ld_nexus_index, when MSG_IN ; Nexus index <- Tag from bus | |
743 | clear ACK ; acknowledge it | |
744 | ||
745 | haveNexusIndex: | |
746 | move 0x00 to SCRATCHB3 ; clear invalid-nexus-index flag | |
747 | store SCRATCHB3, 1, ld_nexus_index+3 | |
748 | call rel( findNexusFromIndex ) ; set DSA <- Nexus pointer | |
749 | jump rel( phase_handler ) ; start handling phases. | |
750 | ||
751 | ||
752 | ;***************************************************************** | |
753 | ; | |
754 | ; AbortMailbox - Abort (or BusDeviceReset) the mailbox entry. | |
755 | ; This is a queued operation - not an immediate | |
756 | ; operation as is issueAbort_BDR. | |
757 | ; The Abort message clears all IO processes for the | |
758 | ; selecting Initiator on the specified LUN. | |
759 | ; | |
760 | ; The Bus Device Reset message clears all IO processes for | |
761 | ; all Initiators on all LUNs of selected Target. | |
762 | ; It forces a hard reset condition to the selected SCSI device. | |
763 | ; | |
764 | ; A0 = Identify byte (0xC0 + LUN N.B. Disconnect allowed) | |
765 | ; A1 = Tag, if any | |
766 | ; A2 = SCSI ID | |
767 | ; A3 = Abort code Abort=0x06; Abort Tag=0D; Bus Device Reset=0x0C | |
768 | ; | |
769 | ; Mailbox not cleared by SCRIPTS so that driver can find SCSI ID when done | |
770 | ; N.B.: Device is Async and Narrow after BDR!!! | |
771 | ; Driver must set the device config table values accordingly. | |
772 | ;***************************************************************** | |
773 | ||
774 | AbortMailbox: | |
775 | move kphase_ABORT_MAILBOX to SCRATCHB0 ; Set phase code | |
776 | store SCRATCHB0, 1, ld_phase_flag | |
777 | ||
778 | move 0xFF to SCRATCHB3 ; invalidate nexus index for driver | |
779 | store SCRATCHB3, 1, ld_nexus_index+3 | |
780 | ||
781 | load SCRATCHB2, 1, ld_AbortBdr_mailbox+2 ; get SCSI ID | |
782 | store SCRATCHB2, 1, AbortSelect+2 ; *** Patch the Select/ATN instruction | |
783 | ||
784 | AbortSelect: | |
785 | SELECT ATN 0, REL( try_reselect ) ; *** Patched SCSI ID | |
786 | ||
787 | move SCRATCHA1 to SFBR ; check for Tag | |
788 | jump rel( taggedAbort ) if not 0x00 ; jump if tagged abort | |
789 | ||
790 | ; untagged Abort or BusDeviceReset: | |
791 | ||
792 | move SCRATCHA3 to SFBR ; position the abort code | |
793 | move SFBR to SCRATCHA1 | |
794 | store SCRATCHA0, 2, ld_scratch ; Store Identify and Abort msgs | |
795 | move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected | |
796 | move 2, ld_scratch , when MSG_OUT ; emit Identify and Abort messages | |
797 | WAIT DISCONNECT | |
798 | int abort_mailbox | |
799 | ||
800 | ; AbortTag: | |
801 | ||
802 | taggedAbort: | |
803 | move SCRATCHA1 to SFBR ; position the Tag | |
804 | move SFBR to SCRATCHA2 | |
805 | move 0x20 to SCRATCHA1 ; gen SimpleQueueTag code | |
806 | store SCRATCHA0, 4, ld_scratch ; store Identify, SQT, Tag, AbortTag | |
807 | move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected | |
808 | move 4, ld_scratch, when MSG_OUT ; emit all 4 bytes | |
809 | WAIT DISCONNECT | |
810 | int abort_mailbox | |
811 | ||
812 | ||
813 | ;***************************************************************** | |
814 | ; | |
815 | ; issueAbort_BDR - Abort (or BusDeviceReset) the current operation. | |
816 | ; This is an immediate operation - not a queued operation | |
817 | ; as is AbortMailbox. | |
818 | ; The Abort message clears all IO processes for the | |
819 | ; selecting Initiator on the specified LUN. | |
820 | ; | |
821 | ; The Bus Device Reset message clears all IO processes for | |
822 | ; all Initiators on all LUNs of selected Target. | |
823 | ; It forces a hard reset condition to the selected SCSI device. | |
824 | ; | |
825 | ;***************************************************************** | |
826 | ||
827 | issueAbort_BDR: | |
828 | move kphase_ABORT_CURRENT to SCRATCHB0 ; Set phase code | |
829 | store SCRATCHB0, 1, ld_phase_flag | |
830 | ||
831 | move ISTAT & 0x08 to SFBR ; see if Target connected to bus | |
832 | int abort_current, if 0 ; interrupt driver if not connected | |
833 | ||
834 | SET ATN ; get Target's attention | |
835 | load DSA0, 4, ld_nexus ; load pointer to Nexus | |
836 | ||
837 | bucketLoop: | |
838 | clear ACK | |
839 | jump rel( sendAbortBDR ), when MSG_OUT ; wait for REQ. Jump if OK. | |
840 | ||
841 | jump rel( BucketInStatus ), if STATUS ; bit bucket in | |
842 | jump rel( BucketInMsg ), if MSG_IN ; bit bucket in | |
843 | jump rel( BucketInData ), if DATA_IN ; bit bucket in | |
844 | ||
845 | move 0xAD to SCRATCHA0 | |
846 | jump rel( BucketOutData ), if DATA_OUT ; bit bucket out | |
847 | jump rel( BucketOutCmd ), if CMD ; bit bucket out | |
848 | int unknown_phase ; back to driver for harsher measures | |
849 | ||
850 | ||
851 | BucketInStatus: | |
852 | move 1, ld_scratch, when STATUS ; eat the Status byte | |
853 | jump rel( bucketLoop ); ; keep bit-bucketing bytes | |
854 | ||
855 | BucketInMsg: | |
856 | move 1, ld_scratch, when MSG_IN ; eat a message byte | |
857 | jump rel( bucketLoop ); ; keep bit-bucketing bytes | |
858 | ||
859 | BucketInData: | |
860 | move 1, ld_scratch, when DATA_IN ; eat a data byte | |
861 | jump rel( bucketLoop ); ; keep bit-bucketing bytes | |
862 | ||
863 | BucketOutData: | |
864 | move SCRATCHA0 xor 0x73 to SCRATCHA0 ; gen 0xDEAD ... | |
865 | store SCRATCHA0, 1, ld_scratch | |
866 | move 1, ld_scratch, when DATA_OUT ; pad a byte out | |
867 | jump rel( bucketLoop ); ; keep bit-bucketing bytes | |
868 | ||
869 | BucketOutCmd: | |
870 | move 0x00 to SCRATCHA0 ; load Null, TestUnitReady, whatever | |
871 | store SCRATCHA0, 1, ld_scratch | |
872 | move 1, ld_scratch, when CMD ; pad a byte out | |
873 | jump rel( bucketLoop ); ; keep bit-bucketing bytes | |
874 | ||
875 | ||
876 | sendAbortBDR: | |
877 | move 0x00 to SCNTL2 ; Clr SDU SCSI Disconnect Unexpected | |
878 | move 1, ld_AbortCode, when MSG_OUT ; Send Abort(06) or BDR(0C) message | |
879 | load SCRATCHA0, 4, ld_zeroes ; load 0's | |
880 | store SCRATCHA0, 4, ld_AbortCode ; clear the Abort code | |
881 | WAIT DISCONNECT | |
882 | int abort_current ; went BusFree - tell Driver |