summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/sd53c8xx.n
blob: 3f660abaf0e95f6845936177313f591ed5f0c4f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
// NCR 53c8xx driver for Plan 9
// Nigel Roles (nigel@9fs.org)
//
// Microcode
//
// 27/5/02	Fixed problems with transfers >= 256 * 512
//
// 13/3/01	Fixed microcode to support targets > 7
//

extern	scsi_id_buf
extern	msg_out_buf
extern	cmd_buf
extern	data_buf
extern	status_buf
extern	msgin_buf
extern	dsa_0
extern  dsa_1
extern	dsa_head
extern	ssid_mask

SIR_MSG_IO_COMPLETE = 0
error_not_cmd_complete = 1
error_disconnected = 2
error_reselected = 3
error_unexpected_phase = 4
error_weird_message = 5
SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT = 6
error_not_identify_after_reselect = 7
error_too_much_data = 8
error_too_little_data = 9
SIR_MSG_REJECT = 10
SIR_MSG_SDTR = 11
SIR_EV_RESPONSE_OK = 12
error_sigp_set = 13
SIR_EV_PHASE_SWITCH_AFTER_ID = 14
SIR_MSG_WDTR = 15
SIR_MSG_IGNORE_WIDE_RESIDUE = 16
SIR_NOTIFY_DISC = 100
SIR_NOTIFY_RESELECT = 101
SIR_NOTIFY_MSG_IN = 102
SIR_NOTIFY_STATUS = 103
SIR_NOTIFY_DUMP = 104
SIR_NOTIFY_DUMP2 = 105
SIR_NOTIFY_SIGP = 106
SIR_NOTIFY_ISSUE = 107
SIR_NOTIFY_WAIT_RESELECT = 108
SIR_NOTIFY_ISSUE_CHECK = 109
SIR_NOTIFY_DUMP_NEXT_CODE = 110
SIR_NOTIFY_COMMAND = 111
SIR_NOTIFY_DATA_IN = 112
SIR_NOTIFY_DATA_OUT = 113
SIR_NOTIFY_BLOCK_DATA_IN = 114
SIR_NOTIFY_WSR = 115
SIR_NOTIFY_LOAD_SYNC = 116
SIR_NOTIFY_RESELECTED_ON_SELECT = 117
SIR_NOTIFY_LOAD_STATE = 118

STATE_FREE = 0
STATE_ALLOCATED = 1
STATE_ISSUE = 2
STATE_DISCONNECTED = 3
STATE_DONE = 4
STATE_END = 5

RESULT_OK = 0
	
MSG_IDENTIFY = 0x80
MSG_DISCONNECT = 0x04
MSG_SAVE_DATA_POINTER = 0x02
MSG_RESTORE_POINTERS = 0x03
MSG_IGNORE_WIDE_RESIDUE = 0x23
X_MSG = 0x01
X_MSG_SDTR = 0x01
X_MSG_WDTR = 0x03
MSG_REJECT = 0x07

BSIZE = 512
//BSIZE=4096

 // idle:
	jump	wait_for_reselection	
start:
	call	load_sync
//	move	13 to ctest0
//	int	SIR_NOTIFY_ISSUE
	clear	target
	select	atn from scsi_id_buf, reselected_on_select // do I need to clear ATN here?
	jump	start1, when msg_in	// why is this here?
start1:
//	move	14 to ctest0
	move	from msg_out_buf, when msg_out
id_out_mismatch:
	jump	start1, when msg_out		// repeat on parity grounds
	jump	to_decisions, when not cmd
cmd_phase:
//	int	SIR_NOTIFY_COMMAND
	clear	atn
	move	from cmd_buf, when cmd
cmd_out_mismatch:
	jump	to_decisions, when not data_in
data_in_phase:
	move	memory 4, state, scratcha
	move	memory 4, dmaaddr, scratchb
//	int	SIR_NOTIFY_DATA_IN
data_in_block_loop:
	move	scratcha2 to sfbr
	jump	data_in_normal, if 0
//	int	SIR_NOTIFY_BLOCK_DATA_IN
	move	BSIZE, ptr dmaaddr, when data_in		// transfer BSIZE bytes
data_in_block_mismatch:
	move	scratchb1 + BSIZE / 256 to scratchb1		// add BSIZE to scratchb
	move	scratchb2 + 0 to scratchb2 with carry
	move	scratchb3 + 0 to scratchb3 with carry
	move	scratcha2 + 255 to scratcha2			// sub one from block count
	move	memory 4, scratchb, dmaaddr			// save latest dmaddr
	jump	data_in_block_loop, when data_in
	move	memory 4, scratcha, state			// save latest state
	call	save_state
	jump	to_decisions
data_block_mismatch_recover:
	move	memory 4, scratchb, dmaaddr			// save latest dmaddr
data_mismatch_recover:
	move	memory 4, scratcha, state			// save latest state
	jump	to_decisions					// no need to save
								// as interrupt routine
								// did this
data_in_normal:
	move	scratcha3 to sfbr
	int	error_too_much_data, if not 0
	move	from data_buf, when data_in
data_in_mismatch:
	move	2 to scratcha3
	move	memory 4, scratcha, state
	call	save_state
	jump	post_data_to_decisions
data_out_phase:
//	int	SIR_NOTIFY_DATA_OUT
	move	memory 4, state, scratcha
	move	memory 4, dmaaddr, scratchb
data_out_block_loop:
	move	scratcha2 to sfbr
	jump	data_out_normal, if 0
	move	memory 4, dmaaddr, scratchb
	move	BSIZE, ptr dmaaddr, when data_out		// transfer BSIZE bytes
data_out_block_mismatch:
	move	scratchb1 + BSIZE / 256 to scratchb1		// add BSIZE to scratchb
	move	scratchb2 + 0 to scratchb2 with carry
	move	scratchb3 + 0 to scratchb3 with carry
	move	scratcha2 + 255 to scratcha2			// sub one from block count
	move	memory 4, scratchb, dmaaddr			// save latest dmaddr
	jump	data_out_block_loop, when data_out
	move	memory 4, scratcha, state			// save latest state
	jump	to_decisions
data_out_normal:
	move	scratcha3 to sfbr
	int	error_too_little_data, if not 0
	move	from data_buf, when data_out
data_out_mismatch:
	move	2 to scratcha3
	move	memory 4, scratcha, state
	call	save_state
	jump	post_data_to_decisions
status_phase:
	move	from status_buf, when status
//	int	SIR_NOTIFY_STATUS
	int	error_unexpected_phase, when not msg_in
msg_in_phase:
	move	1, scratcha, when msg_in
//	int	SIR_NOTIFY_MSG_IN
	jump	rejected, if MSG_REJECT
msg_in_not_reject:
	jump	disconnected, if MSG_DISCONNECT
	jump	msg_in_skip, if MSG_SAVE_DATA_POINTER
	jump	msg_in_skip, if MSG_RESTORE_POINTERS
	jump	ignore_wide, if MSG_IGNORE_WIDE_RESIDUE
	jump	extended, if X_MSG
	int	error_not_cmd_complete, if not 0
	move	scntl2&0x7e to scntl2			// take care not to clear WSR
	clear	ack
	wait	disconnect
	// update state
	move	memory 4, state, scratcha
	move	STATE_DONE to scratcha0
	move	RESULT_OK to scratcha1
	move	memory 4, scratcha, state
	call	save_state
//	int	SIR_MSG_IO_COMPLETE
	intfly	0
	jump	issue_check

rejected:
	int	SIR_MSG_REJECT
	clear	ack
	jump	to_decisions
msg_in_skip:
	clear	ack
	jump	to_decisions
	
extended:
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha1, when msg_in
	jump	ext_3, if 3
	jump	ext_2, if 2
	int	error_weird_message, if not 1
ext_1:
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha1, when msg_in
	jump	ext_done

ext_3:	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha1, when msg_in
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha2, when msg_in
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha3, when msg_in
	move	scratcha1 to sfbr
	jump	ext_done, if not X_MSG_SDTR

// the target sent SDTR - leave ACK asserted and signal kernel
// kernel will either restart at reject, or continue
sdtr:	int	SIR_MSG_SDTR
	clear	ack
	jump	to_decisions

ext_2:	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha1, when msg_in
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha2, when msg_in
	move	scratcha1 to sfbr
	jump	ext_done, if not X_MSG_WDTR

wdtr:	int	SIR_MSG_WDTR
	clear	ack
	jump	to_decisions

ext_done:
//	ought to check message here, but instead reject all
//	NB ATN set
reject:
	set	atn					// get target's ATN
	clear	ack					// finish ACK
	move	MSG_REJECT to scratcha			// prepare message
	int	error_unexpected_phase, when not msg_out// didn't get ATN
	clear	atn					// last byte coming
	move	1, scratcha, when msg_out		// send byte
	clear	ack					// finish ACK
	jump	reject, when msg_out			// parity error
	jump	to_decisions
	
ignore_wide:
	clear	ack
	int	error_unexpected_phase, when not msg_in
	move	1, scratcha1, when msg_in
	int	SIR_MSG_IGNORE_WIDE_RESIDUE
	clear	ack
	jump	to_decisions

//	sends a response to a message
response:
	set	atn
	clear	ack
	int	error_unexpected_phase, when not msg_out
response_repeat:
	move	from msg_out_buf, when msg_out
	jump	response_repeat, when msg_out		// repeat on parity grounds
// now look for response
// msg_in could be a REJECT
// anything other message is something else so signal kernel first
	jump	response_msg_in, when msg_in
	int	SIR_EV_RESPONSE_OK			// not a MSG_IN so OK
	jump	to_decisions

response_msg_in:
	move	1, scratcha, when msg_in
	jump	rejected, if MSG_REJECT		// go and generate rej interrupt
	int	SIR_EV_RESPONSE_OK		// not a REJECT so OK
	jump	msg_in_not_reject		// try others

disconnected:
//	move	5 to ctest0
	move	scntl2&0x7e to scntl2			// don't clear WSR
	clear 	ack
	wait	disconnect
	// UPDATE state to disconnected
	move	memory 4, state, scratcha
	move	STATE_DISCONNECTED to scratcha0
	move	memory 4, scratcha, state
	call	save_state
wsr_check:
	move	scntl2&0x01 to sfbr
	int	SIR_NOTIFY_WSR, if not 0
//	int	SIR_NOTIFY_DISC
	jump	issue_check

reselected_on_select:
	int	SIR_NOTIFY_RESELECTED_ON_SELECT
	jump	reselected

wait_for_reselection:
//	move	11 to ctest0
//	int	SIR_NOTIFY_WAIT_RESELECT
	wait reselect sigp_set
reselected:
//	move	12 to ctest0
	clear	target
	int	SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT, when not msg_in
	move	1, scratchb, when msg_in
	int	error_not_identify_after_reselect, if not MSG_IDENTIFY and mask 0x1f
//	int	SIR_NOTIFY_RESELECT
	// now locate the right DSA - note do not clear ACK, so target doesn't start
	// synchronous transfer until we are ready
find_dsa:
//	move	6 to ctest0
 	move	memory 4, dsa_head, dsa
find_dsa_loop:
//	move	7 to ctest0
//	move	8 to ctest0
	// load state from DSA into dsa_copy
	call	load_state
	move	memory 4, state, scratcha		// get dsastate in scratcha
	move	scratcha0 to sfbr			// and state variable in sfbr
	jump	find_dsa_next, if not STATE_DISCONNECTED // wrong state
	int	error_reselected, if STATE_END
	move	ssid & ssid_mask to sfbr			// get target ID
	move	memory 1, targ, find_dsa_smc1		// forge target comparison instruction
find_dsa_smc1:
	jump	find_dsa_next, if not 255		// jump if not matched
	move	memory 1, lun, find_dsa_smc2		// forge lun comparison instruction
	move	scratchb0 to sfbr			// recover IDENTIFY message
find_dsa_smc2:
	jump	reload_sync, if 255 and mask ~7		// off we jolly well go
find_dsa_next:
	move	memory 4, next, dsa			// find next
	jump	find_dsa_loop

// id_out terminated early
// most likely the message wasn't recognised
// clear ATN and accept the message in
// called from sd53c8xx.c directly
id_out_mismatch_recover:
	clear	atn
        jump    msg_in_phase, when msg_in
        int     SIR_MSG_REJECT
        jump    to_decisions

// Reload synchronous registers after a reconnect. If the transfer is a synchronous read, then
// as soon as we clear ACK, the target will switch to data_in and start blasting data into the
// fifo. We need to be executing the 'jump when data_in' instruction before the target stops REQing
// since it is the REQ which latches the 'when'. The target will do 16 REQs before stopping, so
// we have 16 bytes (160uS) plus delays to do this after clearing ACK. Once the jump is executing,
// the target will wait, so as much debugging as you like can happen in data_in_phase, just don't
// stick any delays between 'clear ack' and 'jump data_in_phase, when data_in'.

reload_sync:
	call	load_sync
	clear	ack
to_decisions:
	jump	data_in_phase, when data_in
	jump	cmd_phase, if cmd
	jump	data_out_phase, if data_out
	jump	status_phase, if status
	jump	msg_in_phase, if msg_in
	int	error_unexpected_phase

post_data_to_decisions:
	jump	status_phase, when status
	jump	msg_in_phase, if msg_in
	int	error_unexpected_phase
	
//
// MULTI_TARGET
//
// following must mirror top of dsa structure
// the first section is loaded and saved, the
// second section loaded only
dsa_copy:
state:	defw	0			// a0 is state, a1 result, a2 dma block count
dmaaddr: defw	0			// dma address for block moves
dsa_save_end:
targ:	defw	0			// lsb is target
lun:	defw	0			// lsb is lun
sync:	defw	0			// lsb is scntl3, sxfer
next:	defw	0
dsa_load_end:
dsa_load_len = dsa_load_end - dsa_copy
dsa_save_len = dsa_save_end - dsa_copy

load_state:
//	int	SIR_NOTIFY_LOAD_STATE
	jump load_state_okay

	move	dsa0 to sfbr
	jump load_state_okay, if not 0
	move	dsa1 to sfbr
	jump load_state_okay, if not 0
	move	dsa2 to sfbr
	jump load_state_okay, if not 0
	move	dsa3 to sfbr
	jump load_state_okay, if not 0
	// dsa is 0
	move	memory 4, dsa, dmaaddr
	move	memory 4, dsa, targ
	move	memory 4, dsa, lun
	move	memory 4, dsa, sync
	move	memory 4, dsa, next
	move	memory 4, dsa, scratcha
	move	STATE_END to sfbr
	move	sfbr to scratcha0
	move	memory 4, scratcha, state
	return

load_state_okay:
	// load state from DSA into dsa_copy
//	move	9 to ctest0
	move	memory 4, dsa, load_state_smc0 + 4
load_state_smc0:
	move	memory dsa_load_len, 0, dsa_copy
//	move	20 to ctest0
	return
save_state:
	move	memory 4, dsa, save_state_smc0 + 8
save_state_smc0:
	move	memory dsa_save_len, dsa_copy, 0
	return

sigp_set:
//	int	SIR_NOTIFY_SIGP
	move	ctest2 to sfbr				// clear SIGP
issue_check:
//	int	SIR_NOTIFY_ISSUE_CHECK
//	move	1 to ctest0
	move	memory 4, dsa_head, dsa
issue_check_loop:
 	call	load_state
	move	memory 4, state, scratcha		// get dsastate in scratcha
	move	scratcha0 to sfbr			// and state variable in sfbr
	jump	start, if STATE_ISSUE			// right state
	jump	wait_for_reselection, if STATE_END
 //	move	4 to ctest0
	move	memory 4, next, dsa			// find next
	jump	issue_check_loop


load_sync:
	move	memory 4, sync, scratcha		// load the sync stuff
	move	scratcha0 to sfbr			// assuming load_state has been called
	move	sfbr to scntl3
	move	scratcha1 to sfbr
	move	sfbr to sxfer
 //	int	SIR_NOTIFY_LOAD_SYNC
	return