First Commit of my working state
[simh.git] / PDP11 / pdp11_rq.c
1 /* pdp11_rq.c: MSCP disk controller simulator
2
3 Copyright (c) 2002-2007, Robert M Supnik
4 Derived from work by Stephen F. Shirron
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of Robert M Supnik shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from Robert M Supnik.
26
27 rq RQDX3 disk controller
28
29 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
30 31-Oct-05 RMS Fixed address width for large files
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
33 17-Jan-05 RMS Added more RA and RD disks
34 31-Oct-04 RMS Added -L switch (LBNs) to RAUSER size specification
35 01-Oct-04 RMS Revised Unibus interface
36 Changed to identify as UDA50 in Unibus configurations
37 Changed width to be 16b in all configurations
38 Changed default timing for VAX
39 24-Jul-04 RMS VAX controllers luns start with 0 (from Andreas Cejna)
40 05-Feb-04 RMS Revised for file I/O library
41 25-Jan-04 RMS Revised for device debug support
42 12-Jan-04 RMS Fixed bug in interrupt control (found by Tom Evans)
43 07-Oct-03 RMS Fixed problem with multiple RAUSER drives
44 17-Sep-03 RMS Fixed MB to LBN conversion to be more accurate
45 11-Jul-03 RMS Fixed bug in user disk size (found by Chaskiel M Grundman)
46 19-May-03 RMS Revised for new conditional compilation scheme
47 25-Apr-03 RMS Revised for extended file support
48 14-Mar-03 RMS Fixed variable size interaction with save/restore
49 27-Feb-03 RMS Added user-defined drive support
50 26-Feb-03 RMS Fixed bug in vector calculation for VAXen
51 22-Feb-03 RMS Fixed ordering bug in queue process
52 12-Oct-02 RMS Added multicontroller support
53 29-Sep-02 RMS Changed addressing to 18b in Unibus mode
54 Added variable address support to bootstrap
55 Added vector display support
56 Fixed status code in HBE error log
57 Consolidated MSCP/TMSCP header file
58 New data structures
59 16-Aug-02 RMS Removed unused variables (found by David Hittner)
60 04-May-02 RMS Fixed bug in polling loop for queued operations
61 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH
62 09-Mar-02 RMS Adjusted delays for M+ timing bugs
63 04-Mar-02 RMS Added delays to initialization for M+, RSTS/E
64 16-Feb-02 RMS Fixed bugs in host timeout logic, boot
65 26-Jan-02 RMS Revised bootstrap to conform to M9312
66 06-Jan-02 RMS Revised enable/disable support
67 30-Dec-01 RMS Revised show routines
68 19-Dec-01 RMS Added bigger drives
69 17-Dec-01 RMS Added queue process
70 */
71
72 #if defined (VM_PDP10) /* PDP10 version */
73 #error "RQDX3 not supported on PDP-10!"
74
75 #elif defined (VM_VAX) /* VAX version */
76 #include "vax_defs.h"
77 #define RQ_QTIME 100
78 #define RQ_XTIME 200
79 #define OLDPC fault_PC
80 extern int32 fault_PC;
81
82 #else /* PDP-11 version */
83 #include "pdp11_defs.h"
84 #define RQ_QTIME 200
85 #define RQ_XTIME 500
86 #define OLDPC MMR2
87 extern int32 MMR2;
88 extern int32 cpu_opt;
89 #endif
90
91 #if !defined (RQ_NUMCT)
92 #define RQ_NUMCT 4
93 #elif (RQ_NUMCT > 4)
94 #error "Assertion failure: RQ_NUMCT exceeds 4"
95 #endif
96
97 #include "pdp11_uqssp.h"
98 #include "pdp11_mscp.h"
99
100 #define UF_MSK (UF_CMR|UF_CMW) /* settable flags */
101
102 #define RQ_SH_MAX 24 /* max display wds */
103 #define RQ_SH_PPL 8 /* wds per line */
104 #define RQ_SH_DPL 4 /* desc per line */
105 #define RQ_SH_RI 001 /* show rings */
106 #define RQ_SH_FR 002 /* show free q */
107 #define RQ_SH_RS 004 /* show resp q */
108 #define RQ_SH_UN 010 /* show unit q's */
109 #define RQ_SH_ALL 017 /* show all */
110
111 #define RQ_CLASS 1 /* RQ class */
112 #define RQU_UQPM 6 /* UB port model */
113 #define RQQ_UQPM 19 /* QB port model */
114 #define RQ_UQPM (UNIBUS? RQU_UQPM: RQQ_UQPM)
115 #define RQU_MODEL 6 /* UB MSCP ctrl model */
116 #define RQQ_MODEL 19 /* QB MSCP ctrl model */
117 #define RQ_MODEL (UNIBUS? RQU_MODEL: RQQ_MODEL)
118 #define RQ_HVER 1 /* hardware version */
119 #define RQ_SVER 3 /* software version */
120 #define RQ_DHTMO 60 /* def host timeout */
121 #define RQ_DCTMO 120 /* def ctrl timeout */
122 #define RQ_NUMDR 4 /* # drives */
123 #define RQ_NUMBY 512 /* bytes per block */
124 #define RQ_MAXFR (1 << 16) /* max xfer */
125
126 #define UNIT_V_ONL (UNIT_V_UF + 0) /* online */
127 #define UNIT_V_WLK (UNIT_V_UF + 1) /* hwre write lock */
128 #define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */
129 #define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */
130 #define UNIT_M_DTYPE 0xF
131 #define UNIT_ONL (1 << UNIT_V_ONL)
132 #define UNIT_WLK (1 << UNIT_V_WLK)
133 #define UNIT_ATP (1 << UNIT_V_ATP)
134 #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
135 #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
136 #define cpkt u3 /* current packet */
137 #define pktq u4 /* packet queue */
138 #define uf buf /* settable unit flags */
139 #define cnum wait /* controller index */
140 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
141 #define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \
142 UF_RMV: 0)
143 #define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \
144 (u->flags & UNIT_WPRT))? UF_WPH: 0)
145
146 #define CST_S1 0 /* init stage 1 */
147 #define CST_S1_WR 1 /* stage 1 wrap */
148 #define CST_S2 2 /* init stage 2 */
149 #define CST_S3 3 /* init stage 3 */
150 #define CST_S3_PPA 4 /* stage 3 sa wait */
151 #define CST_S3_PPB 5 /* stage 3 ip wait */
152 #define CST_S4 6 /* stage 4 */
153 #define CST_UP 7 /* online */
154 #define CST_DEAD 8 /* fatal error */
155
156 #define ERR 0 /* must be SCPE_OK! */
157 #define OK 1
158
159 #define RQ_TIMER (RQ_NUMDR)
160 #define RQ_QUEUE (RQ_TIMER + 1)
161
162 /* Internal packet management. The real RQDX3 manages its packets as true
163 linked lists. However, use of actual addresses in structures won't work
164 with save/restore. Accordingly, the packets are an arrayed structure,
165 and links are actually subscripts. To minimize complexity, packet[0]
166 is not used (0 = end of list), and the number of packets must be a power
167 of two.
168 */
169
170 #define RQ_NPKTS 32 /* # packets (pwr of 2) */
171 #define RQ_M_NPKTS (RQ_NPKTS - 1) /* mask */
172 #define RQ_PKT_SIZE_W 32 /* payload size (wds) */
173 #define RQ_PKT_SIZE (RQ_PKT_SIZE_W * sizeof (int16))
174
175 struct rqpkt {
176 int16 link; /* link to next */
177 uint16 d[RQ_PKT_SIZE_W]; /* data */
178 };
179
180 /* Packet payload extraction and insertion; cp defines controller */
181
182 #define GETP(p,w,f) ((cp->pak[p].d[w] >> w##_V_##f) & w##_M_##f)
183 #define GETP32(p,w) (((uint32) cp->pak[p].d[w]) | \
184 (((uint32) cp->pak[p].d[(w)+1]) << 16))
185 #define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \
186 cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF
187
188 /* Disk formats. An RQDX3 disk consists of the following regions:
189
190 XBNs Extended blocks - contain information about disk format,
191 also holds track being reformatted during bad block repl.
192 Size = sectors/track + 1, replicated 3 times.
193 DBNs Diagnostic blocks - used by diagnostics. Sized to pad
194 out the XBNs to a cylinder boundary.
195 LBNs Logical blocks - contain user information.
196 RCT Replacement control table - first block contains status,
197 second contains data from block being replaced, remaining
198 contain information about replaced bad blocks.
199 Size = RBNs/128 + 3, replicated 4-8 times.
200 RBNs Replacement blocks - used to replace bad blocks.
201
202 The simulator does not need to perform bad block replacement; the
203 information below is for simulating RCT reads, if required.
204
205 Note that an RA drive has a different order: LBNs, RCT, XBN, DBN;
206 the RBNs are spare blocks at the end of every track.
207 */
208
209 #define RCT_OVHD 2 /* #ovhd blks */
210 #define RCT_ENTB 128 /* entries/blk */
211 #define RCT_END 0x80000000 /* marks RCT end */
212
213 /* The RQDX3 supports multiple disk drive types (x = not implemented):
214
215 type sec surf cyl tpg gpc RCT LBNs
216
217 RX50 10 1 80 5 16 - 800
218 RX33 15 2 80 2 1 - 2400
219 RD51 18 4 306 4 1 36*4 21600
220 RD31 17 4 615 4 1 3*8 41560
221 RD52 17 8 512 8 1 4*8 60480
222 x RD32 17 6 820 ? ? ? 83236
223 x RD33 17 7 1170 ? ? ? 138565
224 RD53 17 7 1024 7 1 5*8 138672
225 RD54 17 15 1225 15 1 7*8 311200
226
227 The simulator also supports larger drives that only existed
228 on SDI controllers.
229
230 RA60 42(+1) 6 1600 6 1 1008 400176
231 x RA70 33(+1) 11 1507+ 11 1 ? 547041
232 RA81 51(+1) 14 1258 14 1 2856 891072
233 RA82 57(+1) 15 1435 15 1 3420 1216665
234 RA71 51(+1) 14 1921 14 1 1428 1367310
235 RA72 51(+1) 20 1921 20 1 2040 1953300
236 RA90 69(+1) 13 2656 13 1 1794 2376153
237 RA92 73(+1) 13 3101 13 1 949 2940951
238 x RA73 70(+1) 21 2667+ 21 1 ? 3920490
239
240 Each drive can be a different type. The drive field in the
241 unit flags specified the drive type and thus, indirectly,
242 the drive size.
243 */
244
245 #define RQDF_RMV 01 /* removable */
246 #define RQDF_RO 02 /* read only */
247 #define RQDF_SDI 04 /* SDI drive */
248
249 #define RX50_DTYPE 0
250 #define RX50_SECT 10
251 #define RX50_SURF 1
252 #define RX50_CYL 80
253 #define RX50_TPG 5
254 #define RX50_GPC 16
255 #define RX50_XBN 0
256 #define RX50_DBN 0
257 #define RX50_LBN 800
258 #define RX50_RCTS 0
259 #define RX50_RCTC 0
260 #define RX50_RBN 0
261 #define RX50_MOD 7
262 #define RX50_MED 0x25658032
263 #define RX50_FLGS RQDF_RMV
264
265 #define RX33_DTYPE 1
266 #define RX33_SECT 15
267 #define RX33_SURF 2
268 #define RX33_CYL 80
269 #define RX33_TPG 2
270 #define RX33_GPC 1
271 #define RX33_XBN 0
272 #define RX33_DBN 0
273 #define RX33_LBN 2400
274 #define RX33_RCTS 0
275 #define RX33_RCTC 0
276 #define RX33_RBN 0
277 #define RX33_MOD 10
278 #define RX33_MED 0x25658021
279 #define RX33_FLGS RQDF_RMV
280
281 #define RD51_DTYPE 2
282 #define RD51_SECT 18
283 #define RD51_SURF 4
284 #define RD51_CYL 306
285 #define RD51_TPG 4
286 #define RD51_GPC 1
287 #define RD51_XBN 57
288 #define RD51_DBN 87
289 #define RD51_LBN 21600
290 #define RD51_RCTS 36
291 #define RD51_RCTC 4
292 #define RD51_RBN 144
293 #define RD51_MOD 6
294 #define RD51_MED 0x25644033
295 #define RD51_FLGS 0
296
297 #define RD31_DTYPE 3
298 #define RD31_SECT 17
299 #define RD31_SURF 4
300 #define RD31_CYL 615 /* last unused */
301 #define RD31_TPG RD31_SURF
302 #define RD31_GPC 1
303 #define RD31_XBN 54
304 #define RD31_DBN 14
305 #define RD31_LBN 41560
306 #define RD31_RCTS 3
307 #define RD31_RCTC 8
308 #define RD31_RBN 100
309 #define RD31_MOD 12
310 #define RD31_MED 0x2564401F
311 #define RD31_FLGS 0
312
313 #define RD52_DTYPE 4 /* Quantum params */
314 #define RD52_SECT 17
315 #define RD52_SURF 8
316 #define RD52_CYL 512
317 #define RD52_TPG RD52_SURF
318 #define RD52_GPC 1
319 #define RD52_XBN 54
320 #define RD52_DBN 82
321 #define RD52_LBN 60480
322 #define RD52_RCTS 4
323 #define RD52_RCTC 8
324 #define RD52_RBN 168
325 #define RD52_MOD 8
326 #define RD52_MED 0x25644034
327 #define RD52_FLGS 0
328
329 #define RD53_DTYPE 5
330 #define RD53_SECT 17
331 #define RD53_SURF 8
332 #define RD53_CYL 1024 /* last unused */
333 #define RD53_TPG RD53_SURF
334 #define RD53_GPC 1
335 #define RD53_XBN 54
336 #define RD53_DBN 82
337 #define RD53_LBN 138672
338 #define RD53_RCTS 5
339 #define RD53_RCTC 8
340 #define RD53_RBN 280
341 #define RD53_MOD 9
342 #define RD53_MED 0x25644035
343 #define RD53_FLGS 0
344
345 #define RD54_DTYPE 6
346 #define RD54_SECT 17
347 #define RD54_SURF 15
348 #define RD54_CYL 1225 /* last unused */
349 #define RD54_TPG RD54_SURF
350 #define RD54_GPC 1
351 #define RD54_XBN 54
352 #define RD54_DBN 201
353 #define RD54_LBN 311200
354 #define RD54_RCTS 7
355 #define RD54_RCTC 8
356 #define RD54_RBN 609
357 #define RD54_MOD 13
358 #define RD54_MED 0x25644036
359 #define RD54_FLGS 0
360
361 #define RA82_DTYPE 7 /* SDI drive */
362 #define RA82_SECT 57 /* +1 spare/track */
363 #define RA82_SURF 15
364 #define RA82_CYL 1435 /* 0-1422 user */
365 #define RA82_TPG RA82_SURF
366 #define RA82_GPC 1
367 #define RA82_XBN 3480 /* cyl 1427-1430 */
368 #define RA82_DBN 3480 /* cyl 1431-1434 */
369 #define RA82_LBN 1216665 /* 57*15*1423 */
370 #define RA82_RCTS 3420 /* cyl 1423-1426 */
371 #define RA82_RCTC 1
372 #define RA82_RBN 21345 /* 1 *15*1423 */
373 #define RA82_MOD 11
374 #define RA82_MED 0x25641052
375 #define RA82_FLGS RQDF_SDI
376
377 #define RRD40_DTYPE 8
378 #define RRD40_SECT 128
379 #define RRD40_SURF 1
380 #define RRD40_CYL 10400
381 #define RRD40_TPG RRD40_SURF
382 #define RRD40_GPC 1
383 #define RRD40_XBN 0
384 #define RRD40_DBN 0
385 #define RRD40_LBN 1331200
386 #define RRD40_RCTS 0
387 #define RRD40_RCTC 0
388 #define RRD40_RBN 0
389 #define RRD40_MOD 26
390 #define RRD40_MED 0x25652228
391 #define RRD40_FLGS (RQDF_RMV | RQDF_RO)
392
393 #define RA72_DTYPE 9 /* SDI drive */
394 #define RA72_SECT 51 /* +1 spare/trk */
395 #define RA72_SURF 20
396 #define RA72_CYL 1921 /* 0-1914 user */
397 #define RA72_TPG RA72_SURF
398 #define RA72_GPC 1
399 #define RA72_XBN 2080 /* cyl 1917-1918? */
400 #define RA72_DBN 2080 /* cyl 1920-1921? */
401 #define RA72_LBN 1953300 /* 51*20*1915 */
402 #define RA72_RCTS 2040 /* cyl 1915-1916? */
403 #define RA72_RCTC 1
404 #define RA72_RBN 38300 /* 1 *20*1915 */
405 #define RA72_MOD 37
406 #define RA72_MED 0x25641048
407 #define RA72_FLGS RQDF_SDI
408
409 #define RA90_DTYPE 10 /* SDI drive */
410 #define RA90_SECT 69 /* +1 spare/trk */
411 #define RA90_SURF 13
412 #define RA90_CYL 2656 /* 0-2648 user */
413 #define RA90_TPG RA90_SURF
414 #define RA90_GPC 1
415 #define RA90_XBN 1820 /* cyl 2651-2652? */
416 #define RA90_DBN 1820 /* cyl 2653-2654? */
417 #define RA90_LBN 2376153 /* 69*13*2649 */
418 #define RA90_RCTS 1794 /* cyl 2649-2650? */
419 #define RA90_RCTC 1
420 #define RA90_RBN 34437 /* 1 *13*2649 */
421 #define RA90_MOD 19
422 #define RA90_MED 0x2564105A
423 #define RA90_FLGS RQDF_SDI
424
425 #define RA92_DTYPE 11 /* SDI drive */
426 #define RA92_SECT 73 /* +1 spare/trk */
427 #define RA92_SURF 13
428 #define RA92_CYL 3101 /* 0-3098 user */
429 #define RA92_TPG RA92_SURF
430 #define RA92_GPC 1
431 #define RA92_XBN 174 /* cyl 3100? */
432 #define RA92_DBN 788
433 #define RA92_LBN 2940951 /* 73*13*3099 */
434 #define RA92_RCTS 949 /* cyl 3099? */
435 #define RA92_RCTC 1
436 #define RA92_RBN 40287 /* 1 *13*3099 */
437 #define RA92_MOD 29
438 #define RA92_MED 0x2564105C
439 #define RA92_FLGS RQDF_SDI
440
441 #define RA8U_DTYPE 12 /* user defined */
442 #define RA8U_SECT 57 /* from RA82 */
443 #define RA8U_SURF 15
444 #define RA8U_CYL 1435 /* from RA82 */
445 #define RA8U_TPG RA8U_SURF
446 #define RA8U_GPC 1
447 #define RA8U_XBN 0
448 #define RA8U_DBN 0
449 #define RA8U_LBN 1216665 /* from RA82 */
450 #define RA8U_RCTS 400
451 #define RA8U_RCTC 8
452 #define RA8U_RBN 21345
453 #define RA8U_MOD 11 /* RA82 */
454 #define RA8U_MED 0x25641052 /* RA82 */
455 #define RA8U_FLGS RQDF_SDI
456 #define RA8U_MINC 10000 /* min cap LBNs */
457 #define RA8U_MAXC 4000000 /* max cap LBNs */
458 #define RA8U_EMAXC 2000000000 /* ext max cap */
459
460 #define RA60_DTYPE 13 /* SDI drive */
461 #define RA60_SECT 42 /* +1 spare/track */
462 #define RA60_SURF 6
463 #define RA60_CYL 1600 /* 0-1587 user */
464 #define RA60_TPG RA60_SURF
465 #define RA60_GPC 1
466 #define RA60_XBN 1032 /* cyl 1592-1595 */
467 #define RA60_DBN 1032 /* cyl 1596-1599 */
468 #define RA60_LBN 400176 /* 42*6*1588 */
469 #define RA60_RCTS 1008 /* cyl 1588-1591 */
470 #define RA60_RCTC 1
471 #define RA60_RBN 9528 /* 1 *6*1588 */
472 #define RA60_MOD 4
473 #define RA60_MED 0x22A4103C
474 #define RA60_FLGS (RQDF_RMV | RQDF_SDI)
475
476 #define RA81_DTYPE 14 /* SDI drive */
477 #define RA81_SECT 51 /* +1 spare/track */
478 #define RA81_SURF 14
479 #define RA81_CYL 1258 /* 0-1247 user */
480 #define RA81_TPG RA81_SURF
481 #define RA81_GPC 1
482 #define RA81_XBN 2436 /* cyl 1252-1254? */
483 #define RA81_DBN 2436 /* cyl 1255-1256? */
484 #define RA81_LBN 891072 /* 51*14*1248 */
485 #define RA81_RCTS 2856 /* cyl 1248-1251? */
486 #define RA81_RCTC 1
487 #define RA81_RBN 17472 /* 1 *14*1248 */
488 #define RA81_MOD 5
489 #define RA81_MED 0x25641051
490 #define RA81_FLGS RQDF_SDI
491
492 #define RA71_DTYPE 15 /* SDI drive */
493 #define RA71_SECT 51 /* +1 spare/track */
494 #define RA71_SURF 14
495 #define RA71_CYL 1921 /* 0-1914 user */
496 #define RA71_TPG RA71_SURF
497 #define RA71_GPC 1
498 #define RA71_XBN 1456 /* cyl 1917-1918? */
499 #define RA71_DBN 1456 /* cyl 1919-1920? */
500 #define RA71_LBN 1367310 /* 51*14*1915 */
501 #define RA71_RCTS 1428 /* cyl 1915-1916? */
502 #define RA71_RCTC 1
503 #define RA71_RBN 26810 /* 1 *14*1915 */
504 #define RA71_MOD 40
505 #define RA71_MED 0x25641047
506 #define RA71_FLGS RQDF_SDI
507
508 struct drvtyp {
509 int32 sect; /* sectors */
510 int32 surf; /* surfaces */
511 int32 cyl; /* cylinders */
512 int32 tpg; /* trk/grp */
513 int32 gpc; /* grp/cyl */
514 int32 xbn; /* XBN size */
515 int32 dbn; /* DBN size */
516 uint32 lbn; /* LBN size */
517 int32 rcts; /* RCT size */
518 int32 rctc; /* RCT copies */
519 int32 rbn; /* RBNs */
520 int32 mod; /* MSCP model */
521 int32 med; /* MSCP media */
522 int32 flgs; /* flags */
523 char *name; /* name */
524 };
525
526 #define RQ_DRV(d) \
527 d##_SECT, d##_SURF, d##_CYL, d##_TPG, \
528 d##_GPC, d##_XBN, d##_DBN, d##_LBN, \
529 d##_RCTS, d##_RCTC, d##_RBN, d##_MOD, \
530 d##_MED, d##_FLGS
531 #define RQ_SIZE(d) (d##_LBN * RQ_NUMBY)
532
533 static struct drvtyp drv_tab[] = {
534 { RQ_DRV (RX50), "RX50" }, { RQ_DRV (RX33), "RX33" },
535 { RQ_DRV (RD51), "RD51" }, { RQ_DRV (RD31), "RD31" },
536 { RQ_DRV (RD52), "RD52" }, { RQ_DRV (RD53), "RD53" },
537 { RQ_DRV (RD54), "RD54" }, { RQ_DRV (RA82), "RA82" },
538 { RQ_DRV (RRD40), "RRD40" }, { RQ_DRV (RA72), "RA72" },
539 { RQ_DRV (RA90), "RA90" }, { RQ_DRV (RA92), "RA92" },
540 { RQ_DRV (RA8U), "RAUSER" }, { RQ_DRV (RA60), "RA60" },
541 { RQ_DRV (RA81), "RA81" }, { RQ_DRV (RA71), "RA71" },
542 { 0 }
543 };
544
545 extern int32 int_req[IPL_HLVL];
546 extern int32 tmr_poll, clk_tps;
547 extern UNIT cpu_unit;
548 extern FILE *sim_deb;
549 extern uint32 sim_taddr_64;
550 extern int32 sim_switches;
551
552 uint16 *rqxb = NULL; /* xfer buffer */
553 int32 rq_itime = 200; /* init time, except */
554 int32 rq_itime4 = 10; /* stage 4 */
555 int32 rq_qtime = RQ_QTIME; /* queue time */
556 int32 rq_xtime = RQ_XTIME; /* transfer time */
557
558 typedef struct {
559 uint32 cnum; /* ctrl number */
560 uint32 ubase; /* unit base */
561 uint32 sa; /* status, addr */
562 uint32 saw; /* written data */
563 uint32 s1dat; /* S1 data */
564 uint32 comm; /* comm region */
565 uint32 csta; /* ctrl state */
566 uint32 perr; /* last error */
567 uint32 cflgs; /* ctrl flags */
568 uint32 irq; /* intr request */
569 uint32 prgi; /* purge int */
570 uint32 pip; /* poll in progress */
571 int32 freq; /* free list */
572 int32 rspq; /* resp list */
573 uint32 pbsy; /* #busy pkts */
574 uint32 credits; /* credits */
575 uint32 hat; /* host timer */
576 uint32 htmo; /* host timeout */
577 struct uq_ring cq; /* cmd ring */
578 struct uq_ring rq; /* rsp ring */
579 struct rqpkt pak[RQ_NPKTS]; /* packet queue */
580 } MSC;
581
582 DEVICE rq_dev, rqb_dev, rqc_dev,rqd_dev;
583
584 t_stat rq_rd (int32 *data, int32 PA, int32 access);
585 t_stat rq_wr (int32 data, int32 PA, int32 access);
586 t_stat rq_svc (UNIT *uptr);
587 t_stat rq_tmrsvc (UNIT *uptr);
588 t_stat rq_quesvc (UNIT *uptr);
589 t_stat rq_reset (DEVICE *dptr);
590 t_stat rq_attach (UNIT *uptr, char *cptr);
591 t_stat rq_detach (UNIT *uptr);
592 t_stat rq_boot (int32 unitno, DEVICE *dptr);
593 t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc);
594 t_stat rq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
595 t_stat rq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);
596 t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc);
597 t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc);
598 t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc);
599
600 t_bool rq_step4 (MSC *cp);
601 t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q);
602 t_bool rq_abo (MSC *cp, int32 pkt, t_bool q);
603 t_bool rq_avl (MSC *cp, int32 pkt, t_bool q);
604 t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q);
605 t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q);
606 t_bool rq_gus (MSC *cp, int32 pkt, t_bool q);
607 t_bool rq_onl (MSC *cp, int32 pkt, t_bool q);
608 t_bool rq_rw (MSC *cp, int32 pkt, t_bool q);
609 t_bool rq_scc (MSC *cp, int32 pkt, t_bool q);
610 t_bool rq_suc (MSC *cp, int32 pkt, t_bool q);
611 t_bool rq_plf (MSC *cp, uint32 err);
612 t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err);
613 t_bool rq_hbe (MSC *cp, UNIT *uptr);
614 t_bool rq_una (MSC *cp, int32 un);
615 t_bool rq_deqf (MSC *cp, int32 *pkt);
616 int32 rq_deqh (MSC *cp, int32 *lh);
617 void rq_enqh (MSC *cp, int32 *lh, int32 pkt);
618 void rq_enqt (MSC *cp, int32 *lh, int32 pkt);
619 t_bool rq_getpkt (MSC *cp, int32 *pkt);
620 t_bool rq_putpkt (MSC *cp, int32 pkt, t_bool qt);
621 t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc);
622 t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc);
623 int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd);
624 t_bool rq_rw_end (MSC *cp, UNIT *uptr, uint32 flg, uint32 sts);
625 void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg,
626 uint32 sts, uint32 lnt, uint32 typ);
627 void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all);
628 void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr);
629 void rq_init_int (MSC *cp);
630 void rq_ring_int (MSC *cp, struct uq_ring *ring);
631 t_bool rq_fatal (MSC *cp, uint32 err);
632 UNIT *rq_getucb (MSC *cp, uint32 lu);
633 int32 rq_map_pa (uint32 pa);
634 void rq_setint (MSC *cp);
635 void rq_clrint (MSC *cp);
636 int32 rq_inta (void);
637
638 /* RQ data structures
639
640 rq_dev RQ device descriptor
641 rq_unit RQ unit list
642 rq_reg RQ register list
643 rq_mod RQ modifier list
644 */
645
646 MSC rq_ctx = { 0 };
647
648 DIB rq_dib = {
649 IOBA_RQ, IOLN_RQ, &rq_rd, &rq_wr,
650 1, IVCL (RQ), 0, { &rq_inta }
651 };
652
653 UNIT rq_unit[] = {
654 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
655 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
656 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
657 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
658 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
659 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
660 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
661 (RX50_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RX50)) },
662 { UDATA (&rq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) },
663 { UDATA (&rq_quesvc, UNIT_DIS, 0) }
664 };
665
666 REG rq_reg[] = {
667 { GRDATA (SA, rq_ctx.sa, DEV_RDX, 16, 0) },
668 { GRDATA (SAW, rq_ctx.saw, DEV_RDX, 16, 0) },
669 { GRDATA (S1DAT, rq_ctx.s1dat, DEV_RDX, 16, 0) },
670 { GRDATA (COMM, rq_ctx.comm, DEV_RDX, 22, 0) },
671 { GRDATA (CQBA, rq_ctx.cq.ba, DEV_RDX, 22, 0) },
672 { GRDATA (CQLNT, rq_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
673 { GRDATA (CQIDX, rq_ctx.cq.idx, DEV_RDX, 8, 2) },
674 { GRDATA (RQBA, rq_ctx.rq.ba, DEV_RDX, 22, 0) },
675 { GRDATA (RQLNT, rq_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
676 { GRDATA (RQIDX, rq_ctx.rq.idx, DEV_RDX, 8, 2) },
677 { DRDATA (FREE, rq_ctx.freq, 5) },
678 { DRDATA (RESP, rq_ctx.rspq, 5) },
679 { DRDATA (PBSY, rq_ctx.pbsy, 5) },
680 { GRDATA (CFLGS, rq_ctx.cflgs, DEV_RDX, 16, 0) },
681 { GRDATA (CSTA, rq_ctx.csta, DEV_RDX, 4, 0) },
682 { GRDATA (PERR, rq_ctx.perr, DEV_RDX, 9, 0) },
683 { DRDATA (CRED, rq_ctx.credits, 5) },
684 { DRDATA (HAT, rq_ctx.hat, 17) },
685 { DRDATA (HTMO, rq_ctx.htmo, 17) },
686 { FLDATA (PRGI, rq_ctx.prgi, 0), REG_HIDDEN },
687 { FLDATA (PIP, rq_ctx.pip, 0), REG_HIDDEN },
688 { FLDATA (INT, rq_ctx.irq, 0) },
689 { DRDATA (ITIME, rq_itime, 24), PV_LEFT + REG_NZ },
690 { DRDATA (I4TIME, rq_itime4, 24), PV_LEFT + REG_NZ },
691 { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ },
692 { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ },
693 { BRDATA (PKTS, rq_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) },
694 { URDATA (CPKT, rq_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
695 { URDATA (PKTQ, rq_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
696 { URDATA (UFLG, rq_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
697 { URDATA (CAPAC, rq_unit[0].capac, 10, T_ADDR_W, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
698 { GRDATA (DEVADDR, rq_dib.ba, DEV_RDX, 32, 0), REG_HRO },
699 { GRDATA (DEVVEC, rq_dib.vec, DEV_RDX, 16, 0), REG_HRO },
700 { DRDATA (DEVLBN, drv_tab[RA8U_DTYPE].lbn, 22), REG_HRO },
701 { NULL }
702 };
703
704 MTAB rq_mod[] = {
705 { UNIT_WLK, 0, NULL, "WRITEENABLED", &rq_set_wlk },
706 { UNIT_WLK, UNIT_WLK, NULL, "LOCKED", &rq_set_wlk },
707 { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RI, "RINGS", NULL,
708 NULL, &rq_show_ctrl, 0 },
709 { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_FR, "FREEQ", NULL,
710 NULL, &rq_show_ctrl, 0 },
711 { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RS, "RESPQ", NULL,
712 NULL, &rq_show_ctrl, 0 },
713 { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_UN, "UNITQ", NULL,
714 NULL, &rq_show_ctrl, 0 },
715 { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_ALL, "ALL", NULL,
716 NULL, &rq_show_ctrl, 0 },
717 { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL,
718 NULL, &rq_show_unitq, 0 },
719 { MTAB_XTD | MTAB_VUN, 0, "WRITE", NULL,
720 NULL, &rq_show_wlk, NULL },
721 { MTAB_XTD | MTAB_VUN, RX50_DTYPE, NULL, "RX50",
722 &rq_set_type, NULL, NULL },
723 { MTAB_XTD | MTAB_VUN, RX33_DTYPE, NULL, "RX33",
724 &rq_set_type, NULL, NULL },
725 { MTAB_XTD | MTAB_VUN, RD31_DTYPE, NULL, "RD31",
726 &rq_set_type, NULL, NULL },
727 { MTAB_XTD | MTAB_VUN, RD51_DTYPE, NULL, "RD51",
728 &rq_set_type, NULL, NULL },
729 { MTAB_XTD | MTAB_VUN, RD52_DTYPE, NULL, "RD52",
730 &rq_set_type, NULL, NULL },
731 { MTAB_XTD | MTAB_VUN, RD53_DTYPE, NULL, "RD53",
732 &rq_set_type, NULL, NULL },
733 { MTAB_XTD | MTAB_VUN, RD54_DTYPE, NULL, "RD54",
734 &rq_set_type, NULL, NULL },
735 { MTAB_XTD | MTAB_VUN, RA60_DTYPE, NULL, "RA60",
736 &rq_set_type, NULL, NULL },
737 { MTAB_XTD | MTAB_VUN, RA81_DTYPE, NULL, "RA81",
738 &rq_set_type, NULL, NULL },
739 { MTAB_XTD | MTAB_VUN, RA82_DTYPE, NULL, "RA82",
740 &rq_set_type, NULL, NULL },
741 { MTAB_XTD | MTAB_VUN, RRD40_DTYPE, NULL, "RRD40",
742 &rq_set_type, NULL, NULL },
743 { MTAB_XTD | MTAB_VUN, RRD40_DTYPE, NULL, "CDROM",
744 &rq_set_type, NULL, NULL },
745 { MTAB_XTD | MTAB_VUN, RA71_DTYPE, NULL, "RA71",
746 &rq_set_type, NULL, NULL },
747 { MTAB_XTD | MTAB_VUN, RA72_DTYPE, NULL, "RA72",
748 &rq_set_type, NULL, NULL },
749 { MTAB_XTD | MTAB_VUN, RA90_DTYPE, NULL, "RA90",
750 &rq_set_type, NULL, NULL },
751 { MTAB_XTD | MTAB_VUN, RA92_DTYPE, NULL, "RA92",
752 &rq_set_type, NULL, NULL },
753 { MTAB_XTD | MTAB_VUN, RA8U_DTYPE, NULL, "RAUSER",
754 &rq_set_type, NULL, NULL },
755 { MTAB_XTD | MTAB_VUN, 0, "TYPE", NULL,
756 NULL, &rq_show_type, NULL },
757 #if defined (VM_PDP11)
758 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
759 &set_addr, &show_addr, NULL },
760 #else
761 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
762 NULL, &show_addr, NULL },
763 #endif
764 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
765 NULL, &show_vec, NULL },
766 { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
767 &set_addr_flt, NULL, NULL },
768 { 0 }
769 };
770
771 DEVICE rq_dev = {
772 "RQ", rq_unit, rq_reg, rq_mod,
773 RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
774 NULL, NULL, &rq_reset,
775 &rq_boot, &rq_attach, &rq_detach,
776 &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG
777 };
778
779 /* RQB data structures
780
781 rqb_dev RQB device descriptor
782 rqb_unit RQB unit list
783 rqb_reg RQB register list
784 rqb_mod RQB modifier list
785 */
786
787 MSC rqb_ctx = { 1 };
788
789 DIB rqb_dib = {
790 IOBA_RQB, IOLN_RQB, &rq_rd, &rq_wr,
791 1, IVCL (RQ), 0, { &rq_inta }
792 };
793
794 UNIT rqb_unit[] = {
795 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
796 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
797 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
798 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
799 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
800 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
801 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
802 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
803 { UDATA (&rq_tmrsvc, UNIT_DIS, 0) },
804 { UDATA (&rq_quesvc, UNIT_DIS, 0) }
805 };
806
807 REG rqb_reg[] = {
808 { GRDATA (SA, rqb_ctx.sa, DEV_RDX, 16, 0) },
809 { GRDATA (SAW, rqb_ctx.saw, DEV_RDX, 16, 0) },
810 { GRDATA (S1DAT, rqb_ctx.s1dat, DEV_RDX, 16, 0) },
811 { GRDATA (COMM, rqb_ctx.comm, DEV_RDX, 22, 0) },
812 { GRDATA (CQBA, rqb_ctx.cq.ba, DEV_RDX, 22, 0) },
813 { GRDATA (CQLNT, rqb_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
814 { GRDATA (CQIDX, rqb_ctx.cq.idx, DEV_RDX, 8, 2) },
815 { GRDATA (RQBA, rqb_ctx.rq.ba, DEV_RDX, 22, 0) },
816 { GRDATA (RQLNT, rqb_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
817 { GRDATA (RQIDX, rqb_ctx.rq.idx, DEV_RDX, 8, 2) },
818 { DRDATA (FREE, rqb_ctx.freq, 5) },
819 { DRDATA (RESP, rqb_ctx.rspq, 5) },
820 { DRDATA (PBSY, rqb_ctx.pbsy, 5) },
821 { GRDATA (CFLGS, rqb_ctx.cflgs, DEV_RDX, 16, 0) },
822 { GRDATA (CSTA, rqb_ctx.csta, DEV_RDX, 4, 0) },
823 { GRDATA (PERR, rqb_ctx.perr, DEV_RDX, 9, 0) },
824 { DRDATA (CRED, rqb_ctx.credits, 5) },
825 { DRDATA (HAT, rqb_ctx.hat, 17) },
826 { DRDATA (HTMO, rqb_ctx.htmo, 17) },
827 { FLDATA (PRGI, rqb_ctx.prgi, 0), REG_HIDDEN },
828 { FLDATA (PIP, rqb_ctx.pip, 0), REG_HIDDEN },
829 { FLDATA (INT, rqb_ctx.irq, 0) },
830 { BRDATA (PKTS, rqb_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) },
831 { URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
832 { URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
833 { URDATA (UFLG, rqb_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
834 { URDATA (CAPAC, rqb_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
835 { GRDATA (DEVADDR, rqb_dib.ba, DEV_RDX, 32, 0), REG_HRO },
836 { GRDATA (DEVVEC, rqb_dib.vec, DEV_RDX, 16, 0), REG_HRO },
837 { NULL }
838 };
839
840 DEVICE rqb_dev = {
841 "RQB", rqb_unit, rqb_reg, rq_mod,
842 RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
843 NULL, NULL, &rq_reset,
844 &rq_boot, &rq_attach, &rq_detach,
845 &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG
846 };
847
848 /* RQC data structures
849
850 rqc_dev RQC device descriptor
851 rqc_unit RQC unit list
852 rqc_reg RQC register list
853 rqc_mod RQC modifier list
854 */
855
856 MSC rqc_ctx = { 2 };
857
858 DIB rqc_dib = {
859 IOBA_RQC, IOLN_RQC, &rq_rd, &rq_wr,
860 1, IVCL (RQ), 0, { &rq_inta }
861 };
862
863 UNIT rqc_unit[] = {
864 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
865 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
866 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
867 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
868 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
869 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
870 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
871 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
872 { UDATA (&rq_tmrsvc, UNIT_DIS, 0) },
873 { UDATA (&rq_quesvc, UNIT_DIS, 0) }
874 };
875
876 REG rqc_reg[] = {
877 { GRDATA (SA, rqc_ctx.sa, DEV_RDX, 16, 0) },
878 { GRDATA (SAW, rqc_ctx.saw, DEV_RDX, 16, 0) },
879 { GRDATA (S1DAT, rqc_ctx.s1dat, DEV_RDX, 16, 0) },
880 { GRDATA (COMM, rqc_ctx.comm, DEV_RDX, 22, 0) },
881 { GRDATA (CQBA, rqc_ctx.cq.ba, DEV_RDX, 22, 0) },
882 { GRDATA (CQLNT, rqc_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
883 { GRDATA (CQIDX, rqc_ctx.cq.idx, DEV_RDX, 8, 2) },
884 { GRDATA (RQBA, rqc_ctx.rq.ba, DEV_RDX, 22, 0) },
885 { GRDATA (RQLNT, rqc_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
886 { GRDATA (RQIDX, rqc_ctx.rq.idx, DEV_RDX, 8, 2) },
887 { DRDATA (FREE, rqc_ctx.freq, 5) },
888 { DRDATA (RESP, rqc_ctx.rspq, 5) },
889 { DRDATA (PBSY, rqc_ctx.pbsy, 5) },
890 { GRDATA (CFLGS, rqc_ctx.cflgs, DEV_RDX, 16, 0) },
891 { GRDATA (CSTA, rqc_ctx.csta, DEV_RDX, 4, 0) },
892 { GRDATA (PERR, rqc_ctx.perr, DEV_RDX, 9, 0) },
893 { DRDATA (CRED, rqc_ctx.credits, 5) },
894 { DRDATA (HAT, rqc_ctx.hat, 17) },
895 { DRDATA (HTMO, rqc_ctx.htmo, 17) },
896 { FLDATA (PRGI, rqc_ctx.prgi, 0), REG_HIDDEN },
897 { FLDATA (PIP, rqc_ctx.pip, 0), REG_HIDDEN },
898 { FLDATA (INT, rqc_ctx.irq, 0) },
899 { BRDATA (PKTS, rqc_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) },
900 { URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
901 { URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
902 { URDATA (UFLG, rqc_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
903 { URDATA (CAPAC, rqc_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
904 { GRDATA (DEVADDR, rqc_dib.ba, DEV_RDX, 32, 0), REG_HRO },
905 { GRDATA (DEVVEC, rqc_dib.vec, DEV_RDX, 16, 0), REG_HRO },
906 { NULL }
907 };
908
909 DEVICE rqc_dev = {
910 "RQC", rqc_unit, rqc_reg, rq_mod,
911 RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
912 NULL, NULL, &rq_reset,
913 &rq_boot, &rq_attach, &rq_detach,
914 &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG
915 };
916
917 /* RQD data structures
918
919 rqd_dev RQ device descriptor
920 rqd_unit RQ unit list
921 rqd_reg RQ register list
922 rqd_mod RQ modifier list
923 */
924
925 MSC rqd_ctx = { 3 };
926
927 DIB rqd_dib = {
928 IOBA_RQD, IOLN_RQD, &rq_rd, &rq_wr,
929 1, IVCL (RQ), 0, { &rq_inta }
930 };
931
932 UNIT rqd_unit[] = {
933 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
934 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
935 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
936 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
937 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
938 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
939 { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+
940 (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) },
941 { UDATA (&rq_tmrsvc, UNIT_DIS, 0) },
942 { UDATA (&rq_quesvc, UNIT_DIS, 0) }
943 };
944
945 REG rqd_reg[] = {
946 { GRDATA (SA, rqd_ctx.sa, DEV_RDX, 16, 0) },
947 { GRDATA (SAW, rqd_ctx.saw, DEV_RDX, 16, 0) },
948 { GRDATA (S1DAT, rqd_ctx.s1dat, DEV_RDX, 16, 0) },
949 { GRDATA (COMM, rqd_ctx.comm, DEV_RDX, 22, 0) },
950 { GRDATA (CQBA, rqd_ctx.cq.ba, DEV_RDX, 22, 0) },
951 { GRDATA (CQLNT, rqd_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
952 { GRDATA (CQIDX, rqd_ctx.cq.idx, DEV_RDX, 8, 2) },
953 { GRDATA (RQBA, rqd_ctx.rq.ba, DEV_RDX, 22, 0) },
954 { GRDATA (RQLNT, rqd_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
955 { GRDATA (RQIDX, rqd_ctx.rq.idx, DEV_RDX, 8, 2) },
956 { DRDATA (FREE, rqd_ctx.freq, 5) },
957 { DRDATA (RESP, rqd_ctx.rspq, 5) },
958 { DRDATA (PBSY, rqd_ctx.pbsy, 5) },
959 { GRDATA (CFLGS, rqd_ctx.cflgs, DEV_RDX, 16, 0) },
960 { GRDATA (CSTA, rqd_ctx.csta, DEV_RDX, 4, 0) },
961 { GRDATA (PERR, rqd_ctx.perr, DEV_RDX, 9, 0) },
962 { DRDATA (CRED, rqd_ctx.credits, 5) },
963 { DRDATA (HAT, rqd_ctx.hat, 17) },
964 { DRDATA (HTMO, rqd_ctx.htmo, 17) },
965 { FLDATA (PRGI, rqd_ctx.prgi, 0), REG_HIDDEN },
966 { FLDATA (PIP, rqd_ctx.pip, 0), REG_HIDDEN },
967 { FLDATA (INT, rqd_ctx.irq, 0) },
968 { BRDATA (PKTS, rqd_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) },
969 { URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
970 { URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
971 { URDATA (UFLG, rqd_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
972 { URDATA (CAPAC, rqd_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
973 { GRDATA (DEVADDR, rqd_dib.ba, DEV_RDX, 32, 0), REG_HRO },
974 { GRDATA (DEVVEC, rqd_dib.vec, DEV_RDX, 16, 0), REG_HRO },
975 { NULL }
976 };
977
978 DEVICE rqd_dev = {
979 "RQD", rqd_unit, rqd_reg, rq_mod,
980 RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
981 NULL, NULL, &rq_reset,
982 &rq_boot, &rq_attach, &rq_detach,
983 &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG
984 };
985
986 static DEVICE *rq_devmap[RQ_NUMCT] = {
987 &rq_dev, &rqb_dev, &rqc_dev, &rqd_dev
988 };
989
990 static MSC *rq_ctxmap[RQ_NUMCT] = {
991 &rq_ctx, &rqb_ctx, &rqc_ctx, &rqd_ctx
992 };
993
994 /* I/O dispatch routines, I/O addresses 17772150 - 17772152
995
996 base + 0 IP read/write
997 base + 2 SA read/write
998 */
999
1000 t_stat rq_rd (int32 *data, int32 PA, int32 access)
1001 {
1002 int32 cidx = rq_map_pa ((uint32) PA);
1003 MSC *cp = rq_ctxmap[cidx];
1004 DEVICE *dptr = rq_devmap[cidx];
1005
1006 if (cidx < 0) return SCPE_IERR;
1007 switch ((PA >> 1) & 01) { /* decode PA<1> */
1008
1009 case 0: /* IP */
1010 *data = 0; /* reads zero */
1011 if (cp->csta == CST_S3_PPB) rq_step4 (cp); /* waiting for poll? */
1012 else if (cp->csta == CST_UP) { /* if up */
1013 if (DEBUG_PRD (dptr)) fprintf (sim_deb,
1014 ">>RQ%c: poll started, PC=%X\n", 'A' + cp->cnum, OLDPC);
1015 cp->pip = 1; /* poll host */
1016 sim_activate (dptr->units + RQ_QUEUE, rq_qtime);
1017 }
1018 break;
1019
1020 case 1: /* SA */
1021 *data = cp->sa;
1022 break;
1023 }
1024
1025 return SCPE_OK;
1026 }
1027
1028 t_stat rq_wr (int32 data, int32 PA, int32 access)
1029 {
1030 int32 cidx = rq_map_pa ((uint32) PA);
1031 MSC *cp = rq_ctxmap[cidx];
1032 DEVICE *dptr = rq_devmap[cidx];
1033
1034 if (cidx < 0) return SCPE_IERR;
1035 switch ((PA >> 1) & 01) { /* decode PA<1> */
1036
1037 case 0: /* IP */
1038 rq_reset (rq_devmap[cidx]); /* init device */
1039 if (DEBUG_PRD (dptr)) fprintf (sim_deb,
1040 ">>RQ%c: initialization started\n", 'A' + cp->cnum);
1041 break;
1042
1043 case 1: /* SA */
1044 cp->saw = data;
1045 if (cp->csta < CST_S4) /* stages 1-3 */
1046 sim_activate (dptr->units + RQ_QUEUE, rq_itime);
1047 else if (cp->csta == CST_S4) /* stage 4 (fast) */
1048 sim_activate (dptr->units + RQ_QUEUE, rq_itime4);
1049 break;
1050 }
1051
1052 return SCPE_OK;
1053 }
1054
1055 /* Map physical address to device context */
1056
1057 int32 rq_map_pa (uint32 pa)
1058 {
1059 int32 i;
1060 DEVICE *dptr;
1061 DIB *dibp;
1062
1063 for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */
1064 dptr = rq_devmap[i]; /* get device */
1065 dibp = (DIB *) dptr->ctxt; /* get DIB */
1066 if ((pa >= dibp->ba) && /* in range? */
1067 (pa < (dibp->ba + dibp->lnt)))
1068 return i; /* return ctrl idx */
1069 }
1070 return -1;
1071 }
1072
1073 /* Transition to step 4 - init communications region */
1074
1075 t_bool rq_step4 (MSC *cp)
1076 {
1077 int32 i, lnt;
1078 uint32 base;
1079 uint16 zero[SA_COMM_MAX >> 1];
1080
1081 cp->rq.ioff = SA_COMM_RI; /* set intr offset */
1082 cp->rq.ba = cp->comm; /* set rsp q base */
1083 cp->rq.lnt = SA_S1H_RQ (cp->s1dat) << 2; /* get resp q len */
1084 cp->cq.ioff = SA_COMM_CI; /* set intr offset */
1085 cp->cq.ba = cp->comm + cp->rq.lnt; /* set cmd q base */
1086 cp->cq.lnt = SA_S1H_CQ (cp->s1dat) << 2; /* get cmd q len */
1087 cp->cq.idx = cp->rq.idx = 0; /* clear q idx's */
1088 if (cp->prgi) base = cp->comm + SA_COMM_QQ;
1089 else base = cp->comm + SA_COMM_CI;
1090 lnt = cp->comm + cp->cq.lnt + cp->rq.lnt - base; /* comm lnt */
1091 if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */
1092 for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */
1093 if (Map_WriteW (base, lnt, zero)) /* zero comm area */
1094 return rq_fatal (cp, PE_QWE); /* error? */
1095 cp->sa = SA_S4 | (RQ_UQPM << SA_S4C_V_MOD) | /* send step 4 */
1096 (RQ_SVER << SA_S4C_V_VER);
1097 cp->csta = CST_S4; /* set step 4 */
1098 rq_init_int (cp); /* poke host */
1099 return OK;
1100 }
1101
1102 /* Queue service - invoked when any of the queues (host queue, unit
1103 queues, response queue) require servicing. Also invoked during
1104 initialization to provide some delay to the next step.
1105
1106 Process at most one item off each unit queue
1107 If the unit queues were empty, process at most one item off the host queue
1108 Process at most one item off the response queue
1109
1110 If all queues are idle, terminate thread
1111 */
1112
1113 t_stat rq_quesvc (UNIT *uptr)
1114 {
1115 int32 i, cnid;
1116 int32 pkt = 0;
1117 UNIT *nuptr;
1118 MSC *cp = rq_ctxmap[uptr->cnum];
1119 DEVICE *dptr = rq_devmap[uptr->cnum];
1120 DIB *dibp = (DIB *) dptr->ctxt;
1121
1122 if (cp->csta < CST_UP) { /* still init? */
1123 switch (cp->csta) { /* controller state? */
1124
1125 case CST_S1: /* need S1 reply */
1126 if (cp->saw & SA_S1H_VL) { /* valid? */
1127 if (cp->saw & SA_S1H_WR) { /* wrap? */
1128 cp->sa = cp->saw; /* echo data */
1129 cp->csta = CST_S1_WR; /* endless loop */
1130 }
1131 else {
1132 cp->s1dat = cp->saw; /* save data */
1133 dibp->vec = (cp->s1dat & SA_S1H_VEC) << 2; /* get vector */
1134 if (dibp->vec) dibp->vec = dibp->vec + VEC_Q; /* if nz, bias */
1135 cp->sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (cp->s1dat);
1136 cp->csta = CST_S2; /* now in step 2 */
1137 rq_init_int (cp); /* intr if req */
1138 }
1139 } /* end if valid */
1140 break;
1141
1142 case CST_S1_WR: /* wrap mode */
1143 cp->sa = cp->saw; /* echo data */
1144 break;
1145
1146 case CST_S2: /* need S2 reply */
1147 cp->comm = cp->saw & SA_S2H_CLO; /* get low addr */
1148 cp->prgi = cp->saw & SA_S2H_PI; /* get purge int */
1149 cp->sa = SA_S3 | SA_S3C_EC (cp->s1dat);
1150 cp->csta = CST_S3; /* now in step 3 */
1151 rq_init_int (cp); /* intr if req */
1152 break;
1153
1154 case CST_S3: /* need S3 reply */
1155 cp->comm = ((cp->saw & SA_S3H_CHI) << 16) | cp->comm;
1156 if (cp->saw & SA_S3H_PP) { /* purge/poll test? */
1157 cp->sa = 0; /* put 0 */
1158 cp->csta = CST_S3_PPA; /* wait for 0 write */
1159 }
1160 else rq_step4 (cp); /* send step 4 */
1161 break;
1162
1163 case CST_S3_PPA: /* need purge test */
1164 if (cp->saw) rq_fatal (cp, PE_PPF); /* data not zero? */
1165 else cp->csta = CST_S3_PPB; /* wait for poll */
1166 break;
1167
1168 case CST_S4: /* need S4 reply */
1169 if (cp->saw & SA_S4H_GO) { /* go set? */
1170 if (DEBUG_PRD (dptr)) fprintf (sim_deb,
1171 ">>RQ%c: initialization complete\n", 'A' + cp->cnum);
1172 cp->csta = CST_UP; /* we're up */
1173 cp->sa = 0; /* clear SA */
1174 sim_activate (dptr->units + RQ_TIMER, tmr_poll * clk_tps);
1175 if ((cp->saw & SA_S4H_LF) && cp->perr) rq_plf (cp, cp->perr);
1176 cp->perr = 0;
1177 }
1178 break;
1179 } /* end switch */
1180
1181 return SCPE_OK;
1182 } /* end if */
1183
1184 for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */
1185 nuptr = dptr->units + i; /* ptr to unit */
1186 if (nuptr->cpkt || (nuptr->pktq == 0)) continue;
1187 pkt = rq_deqh (cp, &nuptr->pktq); /* get top of q */
1188 if (!rq_mscp (cp, pkt, FALSE)) return SCPE_OK; /* process */
1189 }
1190 if ((pkt == 0) && cp->pip) { /* polling? */
1191 if (!rq_getpkt (cp, &pkt)) return SCPE_OK; /* get host pkt */
1192 if (pkt) { /* got one? */
1193 if (DEBUG_PRD (dptr)) {
1194 fprintf (sim_deb, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ",
1195 'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC],
1196 cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN]);
1197 fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n",
1198 cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL],
1199 cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL],
1200 cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]);
1201 }
1202 if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */
1203 return rq_fatal (cp, PE_PIE); /* no, term thread */
1204 cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */
1205 if (cnid == UQ_CID_MSCP) { /* MSCP packet? */
1206 if (!rq_mscp (cp, pkt, TRUE)) return SCPE_OK; /* proc, q non-seq */
1207 }
1208 else if (cnid == UQ_CID_DUP) { /* DUP packet? */
1209 rq_putr (cp, pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ);
1210 if (!rq_putpkt (cp, pkt, TRUE)) return SCPE_OK; /* ill cmd */
1211 }
1212 else return rq_fatal (cp, PE_ICI); /* no, term thread */
1213 } /* end if pkt */
1214 else cp->pip = 0; /* discontinue poll */
1215 } /* end if pip */
1216 if (cp->rspq) { /* resp q? */
1217 pkt = rq_deqh (cp, &cp->rspq); /* get top of q */
1218 if (!rq_putpkt (cp, pkt, FALSE)) return SCPE_OK; /* send to host */
1219 } /* end if resp q */
1220 if (pkt) sim_activate (uptr, rq_qtime); /* more to do? */
1221 return SCPE_OK; /* done */
1222 }
1223
1224 /* Clock service (roughly once per second) */
1225
1226 t_stat rq_tmrsvc (UNIT *uptr)
1227 {
1228 int32 i;
1229 UNIT *nuptr;
1230 MSC *cp = rq_ctxmap[uptr->cnum];
1231 DEVICE *dptr = rq_devmap[uptr->cnum];
1232
1233 sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */
1234 for (i = 0; i < RQ_NUMDR; i++) { /* poll */
1235 nuptr = dptr->units + i;
1236 if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */
1237 (nuptr->flags & UNIT_ATT) && /* still online? */
1238 (cp->cflgs & CF_ATN)) { /* wanted? */
1239 if (!rq_una (cp, i)) return SCPE_OK;
1240 }
1241 nuptr->flags = nuptr->flags & ~UNIT_ATP;
1242 }
1243 if ((cp->hat > 0) && (--cp->hat == 0)) /* host timeout? */
1244 rq_fatal (cp, PE_HAT); /* fatal err */
1245 return SCPE_OK;
1246 }
1247
1248 /* MSCP packet handling */
1249
1250 t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q)
1251 {
1252 uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC);
1253
1254 switch (cmd) {
1255
1256 case OP_ABO: /* abort */
1257 return rq_abo (cp, pkt, q);
1258
1259 case OP_AVL: /* avail */
1260 return rq_avl (cp, pkt, q);
1261
1262 case OP_FMT: /* format */
1263 return rq_fmt (cp, pkt, q);
1264
1265 case OP_GCS: /* get cmd status */
1266 return rq_gcs (cp, pkt, q);
1267
1268 case OP_GUS: /* get unit status */
1269 return rq_gus (cp, pkt, q);
1270
1271 case OP_ONL: /* online */
1272 return rq_onl (cp, pkt, q);
1273
1274 case OP_SCC: /* set ctrl char */
1275 return rq_scc (cp, pkt, q);
1276
1277 case OP_SUC: /* set unit char */
1278 return rq_suc (cp, pkt, q);
1279
1280 case OP_ACC: /* access */
1281 case OP_CMP: /* compare */
1282 case OP_ERS: /* erase */
1283 case OP_RD: /* read */
1284 case OP_WR: /* write */
1285 return rq_rw (cp, pkt, q);
1286
1287 case OP_CCD: /* nops */
1288 case OP_DAP:
1289 case OP_FLU:
1290 cmd = cmd | OP_END; /* set end flag */
1291 sts = ST_SUC; /* success */
1292 break;
1293
1294 default:
1295 cmd = OP_END; /* set end op */
1296 sts = ST_CMD | I_OPCD; /* ill op */
1297 break;
1298 }
1299
1300 rq_putr (cp, pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ);
1301 return rq_putpkt (cp, pkt, TRUE);
1302 }
1303
1304 /* Abort a command - 1st parameter is ref # of cmd to abort */
1305
1306 t_bool rq_abo (MSC *cp, int32 pkt, t_bool q)
1307 {
1308 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1309 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1310 uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */
1311 int32 tpkt, prv;
1312 UNIT *uptr;
1313 DEVICE *dptr = rq_devmap[cp->cnum];
1314
1315 tpkt = 0; /* set no mtch */
1316 if (uptr = rq_getucb (cp, lu)) { /* get unit */
1317 if (uptr->cpkt && /* curr pkt? */
1318 (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */
1319 tpkt = uptr->cpkt; /* save match */
1320 uptr->cpkt = 0; /* gonzo */
1321 sim_cancel (uptr); /* cancel unit */
1322 sim_activate (dptr->units + RQ_QUEUE, rq_qtime);
1323 }
1324 else if (uptr->pktq && /* head of q? */
1325 (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */
1326 tpkt = uptr->pktq; /* save match */
1327 uptr->pktq = cp->pak[tpkt].link; /* unlink */
1328 }
1329 else if (prv = uptr->pktq) { /* srch pkt q */
1330 while (tpkt = cp->pak[prv].link) { /* walk list */
1331 if (GETP32 (tpkt, RSP_REFL) == ref) { /* match? unlink */
1332 cp->pak[prv].link = cp->pak[tpkt].link;
1333 break;
1334 }
1335 }
1336 }
1337 if (tpkt) { /* found target? */
1338 uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */
1339 rq_putr (cp, tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ);
1340 if (!rq_putpkt (cp, tpkt, TRUE)) return ERR;
1341 }
1342 } /* end if unit */
1343 rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ);
1344 return rq_putpkt (cp, pkt, TRUE);
1345 }
1346
1347 /* Unit available - set unit status to available - defer if q'd cmds */
1348
1349 t_bool rq_avl (MSC *cp, int32 pkt, t_bool q)
1350 {
1351 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1352 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1353 uint32 sts;
1354 UNIT *uptr;
1355
1356 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1357 if (q && uptr->cpkt) { /* need to queue? */
1358 rq_enqt (cp, &uptr->pktq, pkt); /* do later */
1359 return OK;
1360 }
1361 uptr->flags = uptr->flags & ~UNIT_ONL; /* not online */
1362 uptr->uf = 0; /* clr flags */
1363 sts = ST_SUC; /* success */
1364 }
1365 else sts = ST_OFL; /* offline */
1366 rq_putr (cp, pkt, cmd | OP_END, 0, sts, AVL_LNT, UQ_TYP_SEQ);
1367 return rq_putpkt (cp, pkt, TRUE);
1368 }
1369
1370 /* Get command status - only interested in active xfr cmd */
1371
1372 t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q)
1373 {
1374 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1375 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1376 uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */
1377 int32 tpkt;
1378 UNIT *uptr;
1379
1380 if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */
1381 (tpkt = uptr->cpkt) && /* queued pkt? */
1382 (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */
1383 (GETP (tpkt, CMD_OPC, OPC) >= OP_ACC)) { /* rd/wr cmd? */
1384 cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL];
1385 cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH];
1386 }
1387 else {
1388 cp->pak[pkt].d[GCS_STSL] = 0; /* return 0 */
1389 cp->pak[pkt].d[GCS_STSH] = 0;
1390 }
1391 rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ);
1392 return rq_putpkt (cp, pkt, TRUE);
1393 }
1394
1395 /* Get unit status */
1396
1397 t_bool rq_gus (MSC *cp, int32 pkt, t_bool q)
1398 {
1399 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1400 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1401 uint32 dtyp, sts, rbpar;
1402 UNIT *uptr;
1403
1404 if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */
1405 if (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */
1406 lu = 0; /* reset to 0 */
1407 cp->pak[pkt].d[RSP_UN] = lu;
1408 }
1409 }
1410 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1411 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
1412 sts = ST_OFL | SB_OFL_NV; /* offl no vol */
1413 else if (uptr->flags & UNIT_ONL) sts = ST_SUC; /* online */
1414 else sts = ST_AVL; /* avail */
1415 rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */
1416 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
1417 if (drv_tab[dtyp].rcts) rbpar = 1; /* ctrl bad blk? */
1418 else rbpar = 0; /* fill geom, bblk */
1419 cp->pak[pkt].d[GUS_TRK] = drv_tab[dtyp].sect;
1420 cp->pak[pkt].d[GUS_GRP] = drv_tab[dtyp].tpg;
1421 cp->pak[pkt].d[GUS_CYL] = drv_tab[dtyp].gpc;
1422 cp->pak[pkt].d[GUS_UVER] = 0;
1423 cp->pak[pkt].d[GUS_RCTS] = drv_tab[dtyp].rcts;
1424 cp->pak[pkt].d[GUS_RBSC] =
1425 (rbpar << GUS_RB_V_RBNS) | (rbpar << GUS_RB_V_RCTC);
1426 }
1427 else sts = ST_OFL; /* offline */
1428 cp->pak[pkt].d[GUS_SHUN] = lu; /* shadowing */
1429 cp->pak[pkt].d[GUS_SHST] = 0;
1430 rq_putr (cp, pkt, cmd | OP_END, 0, sts, GUS_LNT_D, UQ_TYP_SEQ);
1431 return rq_putpkt (cp, pkt, TRUE);
1432 }
1433
1434 /* Unit online - defer if q'd commands */
1435
1436 t_bool rq_onl (MSC *cp, int32 pkt, t_bool q)
1437 {
1438 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1439 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1440 uint32 sts;
1441 UNIT *uptr;
1442
1443 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1444 if (q && uptr->cpkt) { /* need to queue? */
1445 rq_enqt (cp, &uptr->pktq, pkt); /* do later */
1446 return OK;
1447 }
1448 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
1449 sts = ST_OFL | SB_OFL_NV; /* offl no vol */
1450 else if (uptr->flags & UNIT_ONL) /* already online? */
1451 sts = ST_SUC | SB_SUC_ON;
1452 else { /* mark online */
1453 sts = ST_SUC;
1454 uptr->flags = uptr->flags | UNIT_ONL;
1455 rq_setf_unit (cp, pkt, uptr); /* hack flags */
1456 }
1457 rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */
1458 }
1459 else sts = ST_OFL; /* offline */
1460 cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */
1461 cp->pak[pkt].d[ONL_SHST] = 0;
1462 rq_putr (cp, pkt, cmd | OP_END, 0, sts, ONL_LNT, UQ_TYP_SEQ);
1463 return rq_putpkt (cp, pkt, TRUE);
1464 }
1465
1466 /* Set controller characteristics */
1467
1468 t_bool rq_scc (MSC *cp, int32 pkt, t_bool q)
1469 {
1470 int32 sts, cmd;
1471
1472 if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */
1473 sts = ST_CMD | I_VRSN; /* no, lose */
1474 cmd = 0;
1475 }
1476 else {
1477 sts = ST_SUC; /* success */
1478 cmd = GETP (pkt, CMD_OPC, OPC); /* get opcode */
1479 cp->cflgs = (cp->cflgs & CF_RPL) | /* hack ctrl flgs */
1480 cp->pak[pkt].d[SCC_CFL];
1481 if (cp->htmo = cp->pak[pkt].d[SCC_TMO]) /* set timeout */
1482 cp->htmo = cp->htmo + 2; /* if nz, round up */
1483 cp->pak[pkt].d[SCC_CFL] = cp->cflgs; /* return flags */
1484 cp->pak[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */
1485 cp->pak[pkt].d[SCC_VER] = (RQ_HVER << SCC_VER_V_HVER) |
1486 (RQ_SVER << SCC_VER_V_SVER);
1487 cp->pak[pkt].d[SCC_CIDA] = 0; /* ctrl ID */
1488 cp->pak[pkt].d[SCC_CIDB] = 0;
1489 cp->pak[pkt].d[SCC_CIDC] = 0;
1490 cp->pak[pkt].d[SCC_CIDD] = (RQ_CLASS << SCC_CIDD_V_CLS) |
1491 (RQ_MODEL << SCC_CIDD_V_MOD);
1492 cp->pak[pkt].d[SCC_MBCL] = 0; /* max bc */
1493 cp->pak[pkt].d[SCC_MBCH] = 0;
1494 }
1495 rq_putr (cp, pkt, cmd | OP_END, 0, sts, SCC_LNT, UQ_TYP_SEQ);
1496 return rq_putpkt (cp, pkt, TRUE);
1497 }
1498
1499 /* Set unit characteristics - defer if q'd commands */
1500
1501 t_bool rq_suc (MSC *cp, int32 pkt, t_bool q)
1502 {
1503 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1504 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1505 uint32 sts;
1506 UNIT *uptr;
1507
1508 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1509 if (q && uptr->cpkt) { /* need to queue? */
1510 rq_enqt (cp, &uptr->pktq, pkt); /* do later */
1511 return OK;
1512 }
1513 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
1514 sts = ST_OFL | SB_OFL_NV; /* offl no vol */
1515 else { /* avail or onl */
1516 sts = ST_SUC;
1517 rq_setf_unit (cp, pkt, uptr); /* hack flags */
1518 }
1519 rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */
1520 }
1521 else sts = ST_OFL; /* offline */
1522 cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */
1523 cp->pak[pkt].d[ONL_SHST] = 0;
1524 rq_putr (cp, pkt, cmd | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ);
1525 return rq_putpkt (cp, pkt, TRUE);
1526 }
1527
1528 /* Format command - floppies only */
1529
1530 t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q)
1531 {
1532 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1533 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1534 uint32 sts;
1535 UNIT *uptr;
1536
1537 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1538 if (q && uptr->cpkt) { /* need to queue? */
1539 rq_enqt (cp, &uptr->pktq, pkt); /* do later */
1540 return OK;
1541 }
1542 if (GET_DTYPE (uptr->flags) != RX33_DTYPE) /* RX33? */
1543 sts = ST_CMD | I_OPCD; /* no, err */
1544 else if ((cp->pak[pkt].d[FMT_IH] & 0100000) == 0) /* magic bit set? */
1545 sts = ST_CMD | I_FMTI; /* no, err */
1546 else if ((uptr->flags & UNIT_ATT) == 0) /* offline? */
1547 sts = ST_OFL | SB_OFL_NV; /* no vol */
1548 else if (uptr->flags & UNIT_ONL) { /* online? */
1549 uptr->flags = uptr->flags & ~UNIT_ONL;
1550 uptr->uf = 0; /* clear flags */
1551 sts = ST_AVL | SB_AVL_INU; /* avail, in use */
1552 }
1553 else if (RQ_WPH (uptr)) /* write prot? */
1554 sts = ST_WPR | SB_WPR_HW; /* can't fmt */
1555 else sts = ST_SUC; /*** for now ***/
1556 }
1557 else sts = ST_OFL; /* offline */
1558 rq_putr (cp, pkt, cmd | OP_END, 0, sts, FMT_LNT, UQ_TYP_SEQ);
1559 return rq_putpkt (cp, pkt, TRUE);
1560 }
1561
1562 /* Data transfer commands */
1563
1564 t_bool rq_rw (MSC *cp, int32 pkt, t_bool q)
1565 {
1566 uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
1567 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
1568 uint32 sts;
1569 UNIT *uptr;
1570
1571 if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
1572 if (q && uptr->cpkt) { /* need to queue? */
1573 rq_enqt (cp, &uptr->pktq, pkt); /* do later */
1574 return OK;
1575 }
1576 sts = rq_rw_valid (cp, pkt, uptr, cmd); /* validity checks */
1577 if (sts == 0) { /* ok? */
1578 uptr->cpkt = pkt; /* op in progress */
1579 cp->pak[pkt].d[RW_WBAL] = cp->pak[pkt].d[RW_BAL];
1580 cp->pak[pkt].d[RW_WBAH] = cp->pak[pkt].d[RW_BAH];
1581 cp->pak[pkt].d[RW_WBCL] = cp->pak[pkt].d[RW_BCL];
1582 cp->pak[pkt].d[RW_WBCH] = cp->pak[pkt].d[RW_BCH];
1583 cp->pak[pkt].d[RW_WBLL] = cp->pak[pkt].d[RW_LBNL];
1584 cp->pak[pkt].d[RW_WBLH] = cp->pak[pkt].d[RW_LBNH];
1585 sim_activate (uptr, rq_xtime); /* activate */
1586 return OK; /* done */
1587 }
1588 }
1589 else sts = ST_OFL; /* offline */
1590 cp->pak[pkt].d[RW_BCL] = cp->pak[pkt].d[RW_BCH] = 0; /* bad packet */
1591 rq_putr (cp, pkt, cmd | OP_END, 0, sts, RW_LNT_D, UQ_TYP_SEQ);
1592 return rq_putpkt (cp, pkt, TRUE);
1593 }
1594
1595 /* Validity checks */
1596
1597 int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd)
1598 {
1599 uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
1600 uint32 lbn = GETP32 (pkt, RW_LBNL); /* get lbn */
1601 uint32 bc = GETP32 (pkt, RW_BCL); /* get byte cnt */
1602 uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */
1603
1604 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
1605 return (ST_OFL | SB_OFL_NV); /* offl no vol */
1606 if ((uptr->flags & UNIT_ONL) == 0) /* not online? */
1607 return ST_AVL; /* only avail */
1608 if ((cmd != OP_ACC) && (cmd != OP_ERS) && /* 'real' xfer */
1609 (cp->pak[pkt].d[RW_BAL] & 1)) /* odd address? */
1610 return (ST_HST | SB_HST_OA); /* host buf odd */
1611 if (bc & 1) return (ST_HST | SB_HST_OC); /* odd byte cnt? */
1612 if (bc & 0xF0000000) return (ST_CMD | I_BCNT); /* 'reasonable' bc? */
1613 /* if (lbn & 0xF0000000) return (ST_CMD | I_LBN); /* 'reasonable' lbn? */
1614 if (lbn >= maxlbn) { /* accessing RCT? */
1615 if (lbn >= (maxlbn + drv_tab[dtyp].rcts)) /* beyond copy 1? */
1616 return (ST_CMD | I_LBN); /* lbn err */
1617 if (bc != RQ_NUMBY) return (ST_CMD | I_BCNT); /* bc must be 512 */
1618 }
1619 else if ((lbn + ((bc + (RQ_NUMBY - 1)) / RQ_NUMBY)) > maxlbn)
1620 return (ST_CMD | I_BCNT); /* spiral to RCT */
1621 if ((cmd == OP_WR) || (cmd == OP_ERS)) { /* write op? */
1622 if (lbn >= maxlbn) /* accessing RCT? */
1623 return (ST_CMD | I_LBN); /* lbn err */
1624 if (uptr->uf & UF_WPS) /* swre wlk? */
1625 return (ST_WPR | SB_WPR_SW);
1626 if (RQ_WPH (uptr)) /* hwre wlk? */
1627 return (ST_WPR | SB_WPR_HW);
1628 }
1629 return 0; /* success! */
1630 }
1631
1632 /* Unit service for data transfer commands */
1633
1634 t_stat rq_svc (UNIT *uptr)
1635 {
1636 MSC *cp = rq_ctxmap[uptr->cnum];
1637
1638 uint32 i, t, tbc, abc, wwc;
1639 uint32 err = 0;
1640 int32 pkt = uptr->cpkt; /* get packet */
1641 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
1642 uint32 ba = GETP32 (pkt, RW_WBAL); /* buf addr */
1643 uint32 bc = GETP32 (pkt, RW_WBCL); /* byte count */
1644 uint32 bl = GETP32 (pkt, RW_WBLL); /* block addr */
1645 t_addr da = ((t_addr) bl) * RQ_NUMBY; /* disk addr */
1646
1647 if ((cp == NULL) || (pkt == 0)) return STOP_RQ; /* what??? */
1648 tbc = (bc > RQ_MAXFR)? RQ_MAXFR: bc; /* trim cnt to max */
1649
1650 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
1651 rq_rw_end (cp, uptr, 0, ST_OFL | SB_OFL_NV); /* offl no vol */
1652 return SCPE_OK;
1653 }
1654 if (bc == 0) { /* no xfer? */
1655 rq_rw_end (cp, uptr, 0, ST_SUC); /* ok by me... */
1656 return SCPE_OK;
1657 }
1658
1659 if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */
1660 if (RQ_WPH (uptr)) {
1661 rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_HW);
1662 return SCPE_OK;
1663 }
1664 if (uptr->uf & UF_WPS) {
1665 rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_SW);
1666 return SCPE_OK;
1667 }
1668 }
1669
1670 if (cmd == OP_ERS) { /* erase? */
1671 wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1;
1672 for (i = 0; i < wwc; i++) rqxb[i] = 0; /* clr buf */
1673 err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */
1674 if (!err) sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref);
1675 err = ferror (uptr->fileref); /* end if erase */
1676 }
1677
1678 else if (cmd == OP_WR) { /* write? */
1679 t = Map_ReadW (ba, tbc, rqxb); /* fetch buffer */
1680 if (abc = tbc - t) { /* any xfer? */
1681 wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1;
1682 for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0;
1683 err = sim_fseek (uptr->fileref, da, SEEK_SET);
1684 if (!err) sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref);
1685 err = ferror (uptr->fileref);
1686 }
1687 if (t) { /* nxm? */
1688 PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */
1689 PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */
1690 if (rq_hbe (cp, uptr)) /* post err log */
1691 rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM);
1692 return SCPE_OK; /* end else wr */
1693 }
1694 }
1695
1696 else {
1697 err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */
1698 if (!err) {
1699 i = sim_fread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref);
1700 for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */
1701 err = ferror (uptr->fileref);
1702 }
1703 if ((cmd == OP_RD) && !err) { /* read? */
1704 if (t = Map_WriteW (ba, tbc, rqxb)) { /* store, nxm? */
1705 PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */
1706 PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */
1707 if (rq_hbe (cp, uptr)) /* post err log */
1708 rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM);
1709 return SCPE_OK;
1710 }
1711 }
1712 else if ((cmd == OP_CMP) && !err) { /* compare? */
1713 uint8 dby, mby;
1714 for (i = 0; i < tbc; i++) { /* loop */
1715 if (Map_ReadB (ba + i, 1, &mby)) { /* fetch, nxm? */
1716 PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */
1717 PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */
1718 if (rq_hbe (cp, uptr)) /* post err log */
1719 rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM);
1720 return SCPE_OK;
1721 }
1722 dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF;
1723 if (mby != dby) { /* cmp err? */
1724 PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */
1725 rq_rw_end (cp, uptr, 0, ST_CMP); /* done */
1726 return SCPE_OK; /* exit */
1727 } /* end if */
1728 } /* end for */
1729 } /* end else if */
1730 } /* end else read */
1731 if (err != 0) { /* error? */
1732 if (rq_dte (cp, uptr, ST_DRV)) /* post err log */
1733 rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */
1734 perror ("RQ I/O error");
1735 clearerr (uptr->fileref);
1736 return SCPE_IOERR;
1737 }
1738 ba = ba + tbc; /* incr bus addr */
1739 bc = bc - tbc; /* decr byte cnt */
1740 bl = bl + ((tbc + (RQ_NUMBY - 1)) / RQ_NUMBY); /* incr blk # */
1741 PUTP32 (pkt, RW_WBAL, ba); /* update pkt */
1742 PUTP32 (pkt, RW_WBCL, bc);
1743 PUTP32 (pkt, RW_WBLL, bl);
1744 if (bc) sim_activate (uptr, rq_xtime); /* more? resched */
1745 else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */
1746 return SCPE_OK;
1747 }
1748
1749 /* Transfer command complete */
1750
1751 t_bool rq_rw_end (MSC *cp, UNIT *uptr, uint32 flg, uint32 sts)
1752 {
1753 int32 pkt = uptr->cpkt; /* packet */
1754 uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
1755 uint32 bc = GETP32 (pkt, RW_BCL); /* init bc */
1756 uint32 wbc = GETP32 (pkt, RW_WBCL); /* work bc */
1757 DEVICE *dptr = rq_devmap[uptr->cnum];
1758
1759 uptr->cpkt = 0; /* done */
1760 PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */
1761 cp->pak[pkt].d[RW_WBAL] = 0; /* clear temps */
1762 cp->pak[pkt].d[RW_WBAH] = 0;
1763 cp->pak[pkt].d[RW_WBCL] = 0;
1764 cp->pak[pkt].d[RW_WBCH] = 0;
1765 cp->pak[pkt].d[RW_WBLL] = 0;
1766 cp->pak[pkt].d[RW_WBLH] = 0;
1767 rq_putr (cp, pkt, cmd | OP_END, flg, sts, RW_LNT_D, UQ_TYP_SEQ); /* fill pkt */
1768 if (!rq_putpkt (cp, pkt, TRUE)) return ERR; /* send pkt */
1769 if (uptr->pktq) /* more to do? */
1770 sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate thread */
1771 return OK;
1772 }
1773
1774 /* Data transfer error log packet */
1775
1776 t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err)
1777 {
1778 int32 pkt, tpkt;
1779 uint32 lu, dtyp, lbn, ccyl, csurf, csect, t;
1780
1781 if ((cp->cflgs & CF_THS) == 0) return OK; /* logging? */
1782 if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */
1783 tpkt = uptr->cpkt; /* rw pkt */
1784 lu = cp->pak[tpkt].d[CMD_UN]; /* unit # */
1785 lbn = GETP32 (tpkt, RW_WBLL); /* recent LBN */
1786 dtyp = GET_DTYPE (uptr->flags); /* drv type */
1787 if (drv_tab[dtyp].flgs & RQDF_SDI) t = 0; /* SDI? ovhd @ end */
1788 else t = (drv_tab[dtyp].xbn + drv_tab[dtyp].dbn) / /* ovhd cylinders */
1789 (drv_tab[dtyp].sect * drv_tab[dtyp].surf);
1790 ccyl = t + (lbn / drv_tab[dtyp].cyl); /* curr real cyl */
1791 t = lbn % drv_tab[dtyp].cyl; /* trk relative blk */
1792 csurf = t / drv_tab[dtyp].surf; /* curr surf */
1793 csect = t % drv_tab[dtyp].surf; /* curr sect */
1794
1795 cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */
1796 cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH];
1797 cp->pak[pkt].d[ELP_UN] = lu; /* copy unit */
1798 cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */
1799 cp->pak[pkt].d[DTE_CIDA] = 0; /* ctrl ID */
1800 cp->pak[pkt].d[DTE_CIDB] = 0;
1801 cp->pak[pkt].d[DTE_CIDC] = 0;
1802 cp->pak[pkt].d[DTE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) |
1803 (RQ_MODEL << DTE_CIDD_V_MOD);
1804 cp->pak[pkt].d[DTE_VER] = (RQ_HVER << DTE_VER_V_HVER) |
1805 (RQ_SVER << DTE_VER_V_SVER);
1806 cp->pak[pkt].d[DTE_MLUN] = lu; /* MLUN */
1807 cp->pak[pkt].d[DTE_UIDA] = lu; /* unit ID */
1808 cp->pak[pkt].d[DTE_UIDB] = 0;
1809 cp->pak[pkt].d[DTE_UIDC] = 0;
1810 cp->pak[pkt].d[DTE_UIDD] = (UID_DISK << DTE_UIDD_V_CLS) |
1811 (drv_tab[dtyp].mod << DTE_UIDD_V_MOD);
1812 cp->pak[pkt].d[DTE_UVER] = 0; /* unit versn */
1813 cp->pak[pkt].d[DTE_SCYL] = ccyl; /* cylinder */
1814 cp->pak[pkt].d[DTE_VSNL] = 01234 + lu; /* vol ser # */
1815 cp->pak[pkt].d[DTE_VSNH] = 0;
1816 cp->pak[pkt].d[DTE_D1] = 0;
1817 cp->pak[pkt].d[DTE_D2] = csect << DTE_D2_V_SECT; /* geometry */
1818 cp->pak[pkt].d[DTE_D3] = (ccyl << DTE_D3_V_CYL) |
1819 (csurf << DTE_D3_V_SURF);
1820 rq_putr (cp, pkt, FM_SDE, LF_SNR, err, DTE_LNT, UQ_TYP_DAT);
1821 return rq_putpkt (cp, pkt, TRUE);
1822 }
1823
1824 /* Host bus error log packet */
1825
1826 t_bool rq_hbe (MSC *cp, UNIT *uptr)
1827 {
1828 int32 pkt, tpkt;
1829
1830 if ((cp->cflgs & CF_THS) == 0) return OK; /* logging? */
1831 if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */
1832 tpkt = uptr->cpkt; /* rw pkt */
1833 cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */
1834 cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH];
1835 cp->pak[pkt].d[ELP_UN] = cp->pak[tpkt].d[CMD_UN]; /* copy unit */
1836 cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */
1837 cp->pak[pkt].d[HBE_CIDA] = 0; /* ctrl ID */
1838 cp->pak[pkt].d[HBE_CIDB] = 0;
1839 cp->pak[pkt].d[HBE_CIDC] = 0;
1840 cp->pak[pkt].d[HBE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) |
1841 (RQ_MODEL << DTE_CIDD_V_MOD);
1842 cp->pak[pkt].d[HBE_VER] = (RQ_HVER << HBE_VER_V_HVER) | /* versions */
1843 (RQ_SVER << HBE_VER_V_SVER);
1844 cp->pak[pkt].d[HBE_RSV] = 0;
1845 cp->pak[pkt].d[HBE_BADL] = cp->pak[tpkt].d[RW_WBAL]; /* bad addr */
1846 cp->pak[pkt].d[HBE_BADH] = cp->pak[tpkt].d[RW_WBAH];
1847 rq_putr (cp, pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT);
1848 return rq_putpkt (cp, pkt, TRUE);
1849 }
1850
1851 /* Port last failure error log packet */
1852
1853 t_bool rq_plf (MSC *cp, uint32 err)
1854 {
1855 int32 pkt;
1856
1857 if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */
1858 cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */
1859 cp->pak[pkt].d[ELP_REFH] = 0;
1860 cp->pak[pkt].d[ELP_UN] = 0; /* no unit */
1861 cp->pak[pkt].d[ELP_SEQ] = 0; /* no seq */
1862 cp->pak[pkt].d[PLF_CIDA] = 0; /* cntl ID */
1863 cp->pak[pkt].d[PLF_CIDB] = 0;
1864 cp->pak[pkt].d[PLF_CIDC] = 0;
1865 cp->pak[pkt].d[PLF_CIDD] = (RQ_CLASS << PLF_CIDD_V_CLS) |
1866 (RQ_MODEL << PLF_CIDD_V_MOD);
1867 cp->pak[pkt].d[PLF_VER] = (RQ_SVER << PLF_VER_V_SVER) |
1868 (RQ_HVER << PLF_VER_V_HVER);
1869 cp->pak[pkt].d[PLF_ERR] = err;
1870 rq_putr (cp, pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT);
1871 cp->pak[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID);
1872 return rq_putpkt (cp, pkt, TRUE);
1873 }
1874
1875 /* Unit now available attention packet */
1876
1877 int32 rq_una (MSC *cp, int32 un)
1878 {
1879 int32 pkt;
1880 uint32 lu = cp->ubase + un;
1881 UNIT *uptr = rq_getucb (cp, lu);
1882
1883 if (uptr == NULL) return OK; /* huh? */
1884 if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */
1885 cp->pak[pkt].d[RSP_REFL] = 0; /* ref = 0 */
1886 cp->pak[pkt].d[RSP_REFH] = 0;
1887 cp->pak[pkt].d[RSP_UN] = lu;
1888 cp->pak[pkt].d[RSP_RSV] = 0;
1889 rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */
1890 rq_putr (cp, pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */
1891 return rq_putpkt (cp, pkt, TRUE);
1892 }
1893
1894 /* List handling
1895
1896 rq_deqf - dequeue head of free list (fatal err if none)
1897 rq_deqh - dequeue head of list
1898 rq_enqh - enqueue at head of list
1899 rq_enqt - enqueue at tail of list
1900 */
1901
1902 t_bool rq_deqf (MSC *cp, int32 *pkt)
1903 {
1904 if (cp->freq == 0) return rq_fatal (cp, PE_NSR); /* no free pkts?? */
1905 cp->pbsy = cp->pbsy + 1; /* cnt busy pkts */
1906 *pkt = cp->freq; /* head of list */
1907 cp->freq = cp->pak[cp->freq].link; /* next */
1908 return OK;
1909 }
1910
1911 int32 rq_deqh (MSC *cp, int32 *lh)
1912 {
1913 int32 ptr = *lh; /* head of list */
1914
1915 if (ptr) *lh = cp->pak[ptr].link; /* next */
1916 return ptr;
1917 }
1918
1919 void rq_enqh (MSC *cp, int32 *lh, int32 pkt)
1920 {
1921 if (pkt == 0) return; /* any pkt? */
1922 cp->pak[pkt].link = *lh; /* link is old lh */
1923 *lh = pkt; /* pkt is new lh */
1924 return;
1925 }
1926
1927 void rq_enqt (MSC *cp, int32 *lh, int32 pkt)
1928 {
1929 if (pkt == 0) return; /* any pkt? */
1930 cp->pak[pkt].link = 0; /* it will be tail */
1931 if (*lh == 0) *lh = pkt; /* if empty, enqh */
1932 else {
1933 uint32 ptr = *lh; /* chase to end */
1934 while (cp->pak[ptr].link) ptr = cp->pak[ptr].link;
1935 cp->pak[ptr].link = pkt; /* enq at tail */
1936 }
1937 return;
1938 }
1939
1940 /* Packet and descriptor handling */
1941
1942 /* Get packet from command ring */
1943
1944 t_bool rq_getpkt (MSC *cp, int32 *pkt)
1945 {
1946 uint32 addr, desc;
1947
1948 if (!rq_getdesc (cp, &cp->cq, &desc)) return ERR; /* get cmd desc */
1949 if ((desc & UQ_DESC_OWN) == 0) { /* none */
1950 *pkt = 0; /* pkt = 0 */
1951 return OK; /* no error */
1952 }
1953 if (!rq_deqf (cp, pkt)) return ERR; /* get cmd pkt */
1954 cp->hat = 0; /* dsbl hst timer */
1955 addr = desc & UQ_ADDR; /* get Q22 addr */
1956 if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, cp->pak[*pkt].d))
1957 return rq_fatal (cp, PE_PRE); /* read pkt */
1958 return rq_putdesc (cp, &cp->cq, desc); /* release desc */
1959 }
1960
1961 /* Put packet to response ring - note the clever hack about credits.
1962 The controller sends all its credits to the host. Thereafter, it
1963 supplies one credit for every response packet sent over. Simple!
1964 */
1965
1966 t_bool rq_putpkt (MSC *cp, int32 pkt, t_bool qt)
1967 {
1968 uint32 addr, desc, lnt, cr;
1969 DEVICE *dptr = rq_devmap[cp->cnum];
1970
1971 if (pkt == 0) return OK; /* any packet? */
1972 if (DEBUG_PRD (dptr)) fprintf (sim_deb,
1973 ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp->cnum,
1974 cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]);
1975 if (!rq_getdesc (cp, &cp->rq, &desc)) return ERR; /* get rsp desc */
1976 if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */
1977 if (qt) rq_enqt (cp, &cp->rspq, pkt); /* normal? q tail */
1978 else rq_enqh (cp, &cp->rspq, pkt); /* resp q call */
1979 sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate q thrd */
1980 return OK;
1981 }
1982 addr = desc & UQ_ADDR; /* get Q22 addr */
1983 lnt = cp->pak[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */
1984 if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */
1985 (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */
1986 cr = (cp->credits >= 14)? 14: cp->credits; /* max 14 credits */
1987 cp->credits = cp->credits - cr; /* decr credits */
1988 cp->pak[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR);
1989 }
1990 if (Map_WriteW (addr + UQ_HDR_OFF, lnt, cp->pak[pkt].d))
1991 return rq_fatal (cp, PE_PWE); /* write pkt */
1992 rq_enqh (cp, &cp->freq, pkt); /* pkt is free */
1993 cp->pbsy = cp->pbsy - 1; /* decr busy cnt */
1994 if (cp->pbsy == 0) cp->hat = cp->htmo; /* idle? strt hst tmr */
1995 return rq_putdesc (cp, &cp->rq, desc); /* release desc */
1996 }
1997
1998 /* Get a descriptor from the host */
1999
2000 t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc)
2001 {
2002 uint32 addr = ring->ba + ring->idx;
2003 uint16 d[2];
2004
2005 if (Map_ReadW (addr, 4, d)) /* fetch desc */
2006 return rq_fatal (cp, PE_QRE); /* err? dead */
2007 *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
2008 return OK;
2009 }
2010
2011 /* Return a descriptor to the host, clearing owner bit
2012 If rings transitions from "empty" to "not empty" or "full" to
2013 "not full", and interrupt bit was set, interrupt the host.
2014 Actually, test whether previous ring entry was owned by host.
2015 */
2016
2017 t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc)
2018 {
2019 uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F;
2020 uint32 prva, addr = ring->ba + ring->idx;
2021 uint16 d[2];
2022
2023 d[0] = newd & 0xFFFF; /* 32b to 16b */
2024 d[1] = (newd >> 16) & 0xFFFF;
2025 if (Map_WriteW (addr, 4, d)) /* store desc */
2026 return rq_fatal (cp, PE_QWE); /* err? dead */
2027 if (desc & UQ_DESC_F) { /* was F set? */
2028 if (ring->lnt <= 4) rq_ring_int (cp, ring); /* lnt = 1? intr */
2029 else { /* prv desc */
2030 prva = ring->ba + ((ring->idx - 4) & (ring->lnt - 1));
2031 if (Map_ReadW (prva, 4, d)) /* read prv */
2032 return rq_fatal (cp, PE_QRE);
2033 prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);
2034 if (prvd & UQ_DESC_OWN) rq_ring_int (cp, ring);
2035 }
2036 }
2037 ring->idx = (ring->idx + 4) & (ring->lnt - 1);
2038 return OK;
2039 }
2040
2041 /* Get unit descriptor for logical unit */
2042
2043 UNIT *rq_getucb (MSC *cp, uint32 lu)
2044 {
2045 DEVICE *dptr = rq_devmap[cp->cnum];
2046 UNIT *uptr;
2047
2048 if ((lu < cp->ubase) || (lu >= (cp->ubase + RQ_NUMDR)))
2049 return NULL;
2050 uptr = dptr->units + (lu % RQ_NUMDR);
2051 if (uptr->flags & UNIT_DIS) return NULL;
2052 return uptr;
2053 }
2054
2055 /* Hack unit flags */
2056
2057 void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr)
2058 {
2059 uptr->uf = cp->pak[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */
2060 if ((cp->pak[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */
2061 (cp->pak[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */
2062 uptr->uf = uptr->uf | UF_WPS; /* simon says... */
2063 return;
2064 }
2065
2066 /* Unit response fields */
2067
2068 void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
2069 {
2070 uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
2071 uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */
2072
2073 cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */
2074 cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr);
2075 cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */
2076 cp->pak[pkt].d[ONL_RSVH] = 0;
2077 cp->pak[pkt].d[ONL_UIDA] = lu; /* UID low */
2078 cp->pak[pkt].d[ONL_UIDB] = 0;
2079 cp->pak[pkt].d[ONL_UIDC] = 0;
2080 cp->pak[pkt].d[ONL_UIDD] = (UID_DISK << ONL_UIDD_V_CLS) |
2081 (drv_tab[dtyp].mod << ONL_UIDD_V_MOD); /* UID hi */
2082 PUTP32 (pkt, ONL_MEDL, drv_tab[dtyp].med); /* media type */
2083 if (all) { /* if long form */
2084 PUTP32 (pkt, ONL_SIZL, maxlbn); /* user LBNs */
2085 cp->pak[pkt].d[ONL_VSNL] = 01234 + lu; /* vol serial # */
2086 cp->pak[pkt].d[ONL_VSNH] = 0;
2087 }
2088 return;
2089 }
2090
2091 /* UQ_HDR and RSP_OP fields */
2092
2093 void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg,
2094 uint32 sts, uint32 lnt, uint32 typ)
2095 {
2096 cp->pak[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */
2097 (flg << RSP_OPF_V_FLG);
2098 cp->pak[pkt].d[RSP_STS] = sts;
2099 cp->pak[pkt].d[UQ_HLNT] = lnt; /* length */
2100 cp->pak[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */
2101 (UQ_CID_MSCP << UQ_HCTC_V_CID); /* clr credits */
2102 return;
2103 }
2104
2105 /* Post interrupt during init */
2106
2107 void rq_init_int (MSC *cp)
2108 {
2109 if ((cp->s1dat & SA_S1H_IE) && /* int enab & */
2110 (cp->s1dat & SA_S1H_VEC)) rq_setint (cp); /* ved set? int */
2111 return;
2112 }
2113
2114 /* Post interrupt during putpkt - note that NXMs are ignored! */
2115
2116 void rq_ring_int (MSC *cp, struct uq_ring *ring)
2117 {
2118 uint32 iadr = cp->comm + ring->ioff; /* addr intr wd */
2119 uint16 flag = 1;
2120
2121 Map_WriteW (iadr, 2, &flag); /* write flag */
2122 if (cp->s1dat & SA_S1H_VEC) rq_setint (cp); /* if enb, intr */
2123 return;
2124 }
2125
2126 /* Set RQ interrupt */
2127
2128 void rq_setint (MSC *cp)
2129 {
2130 cp->irq = 1; /* set ctrl int */
2131 SET_INT (RQ); /* set master int */
2132 return;
2133 }
2134
2135 /* Clear RQ interrupt */
2136
2137 void rq_clrint (MSC *cp)
2138 {
2139 int32 i;
2140 MSC *ncp;
2141
2142 cp->irq = 0; /* clr ctrl int */
2143 for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */
2144 ncp = rq_ctxmap[i]; /* get context */
2145 if (ncp->irq) { /* other interrupt? */
2146 SET_INT (RQ); /* yes, set master */
2147 return;
2148 }
2149 }
2150 CLR_INT (RQ); /* no, clr master */
2151 return;
2152 }
2153
2154 /* Return interrupt vector */
2155
2156 int32 rq_inta (void)
2157 {
2158 int32 i;
2159 MSC *ncp;
2160 DEVICE *dptr;
2161 DIB *dibp;
2162
2163 for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrl */
2164 ncp = rq_ctxmap[i]; /* get context */
2165 if (ncp->irq) { /* ctrl int set? */
2166 dptr = rq_devmap[i]; /* get device */
2167 dibp = (DIB *) dptr->ctxt; /* get DIB */
2168 rq_clrint (ncp); /* clear int req */
2169 return dibp->vec; /* return vector */
2170 }
2171 }
2172 return 0; /* no intr req */
2173 }
2174
2175 /* Fatal error */
2176
2177 t_bool rq_fatal (MSC *cp, uint32 err)
2178 {
2179 DEVICE *dptr = rq_devmap[cp->cnum];
2180
2181 if (DEBUG_PRD (dptr))
2182 fprintf (sim_deb, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err);
2183 rq_reset (rq_devmap[cp->cnum]); /* reset device */
2184 cp->sa = SA_ER | err; /* SA = dead code */
2185 cp->csta = CST_DEAD; /* state = dead */
2186 cp->perr = err; /* save error */
2187 return ERR;
2188 }
2189
2190 /* Set/clear hardware write lock */
2191
2192 t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc)
2193 {
2194 uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
2195
2196 if (drv_tab[dtyp].flgs & RQDF_RO) return SCPE_NOFNC; /* not on read only */
2197 return SCPE_OK;
2198 }
2199
2200 /* Show write lock status */
2201
2202 t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc)
2203 {
2204 uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
2205
2206 if (drv_tab[dtyp].flgs & RQDF_RO) fprintf (st, "read only");
2207 else if (uptr->flags & UNIT_WPRT) fprintf (st, "write locked");
2208 else fprintf (st, "write enabled");
2209 return SCPE_OK;
2210 }
2211
2212 /* Set unit type (and capacity if user defined) */
2213
2214 t_stat rq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)
2215 {
2216 uint32 cap;
2217 uint32 max = sim_taddr_64? RA8U_EMAXC: RA8U_MAXC;
2218 t_stat r;
2219
2220 if ((val < 0) || ((val != RA8U_DTYPE) && cptr))
2221 return SCPE_ARG;
2222 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
2223 if (cptr) {
2224 cap = (uint32) get_uint (cptr, 10, 0xFFFFFFFF, &r);
2225 if ((sim_switches & SWMASK ('L')) == 0) cap = cap * 1954;
2226 if ((r != SCPE_OK) || (cap < RA8U_MINC) || (cap >= max)) return SCPE_ARG;
2227 drv_tab[val].lbn = cap;
2228 }
2229 uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE);
2230 uptr->capac = ((t_addr) drv_tab[val].lbn) * RQ_NUMBY;
2231 return SCPE_OK;
2232 }
2233
2234 /* Show unit type */
2235
2236 t_stat rq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)
2237 {
2238 fprintf (st, "%s", drv_tab[GET_DTYPE (uptr->flags)].name);
2239 return SCPE_OK;
2240 }
2241
2242 /* Device attach */
2243
2244 t_stat rq_attach (UNIT *uptr, char *cptr)
2245 {
2246 MSC *cp = rq_ctxmap[uptr->cnum];
2247 t_stat r;
2248
2249 r = attach_unit (uptr, cptr);
2250 if (r != SCPE_OK) return r;
2251 if (cp->csta == CST_UP) uptr->flags = uptr->flags | UNIT_ATP;
2252 return SCPE_OK;
2253 }
2254
2255 /* Device detach */
2256
2257 t_stat rq_detach (UNIT *uptr)
2258 {
2259 t_stat r;
2260
2261 r = detach_unit (uptr); /* detach unit */
2262 if (r != SCPE_OK) return r;
2263 uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */
2264 uptr->uf = 0; /* clr unit flgs */
2265 return SCPE_OK;
2266 }
2267
2268 /* Device reset */
2269
2270 t_stat rq_reset (DEVICE *dptr)
2271 {
2272 int32 i, j, cidx;
2273 UNIT *uptr;
2274 MSC *cp;
2275 DIB *dibp = (DIB *) dptr->ctxt;
2276
2277 for (i = 0, cidx = -1; i < RQ_NUMCT; i++) { /* find ctrl num */
2278 if (rq_devmap[i] == dptr) cidx = i;
2279 }
2280 if (cidx < 0) return SCPE_IERR; /* not found??? */
2281 cp = rq_ctxmap[cidx]; /* get context */
2282 cp->cnum = cidx; /* init index */
2283
2284 #if defined (VM_VAX) /* VAX */
2285 cp->ubase = 0; /* unit base = 0 */
2286 #else /* PDP-11 */
2287 cp->ubase = cidx * RQ_NUMDR; /* init unit base */
2288 #endif
2289
2290 cp->csta = CST_S1; /* init stage 1 */
2291 cp->s1dat = 0; /* no S1 data */
2292 dibp->vec = 0; /* no vector */
2293 cp->comm = 0; /* no comm region */
2294 if (UNIBUS) cp->sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; /* Unibus? */
2295 else cp->sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */
2296 cp->cflgs = CF_RPL; /* ctrl flgs off */
2297 cp->htmo = RQ_DHTMO; /* default timeout */
2298 cp->hat = cp->htmo; /* default timer */
2299 cp->cq.ba = cp->cq.lnt = cp->cq.idx = 0; /* clr cmd ring */
2300 cp->rq.ba = cp->rq.lnt = cp->rq.idx = 0; /* clr rsp ring */
2301 cp->credits = (RQ_NPKTS / 2) - 1; /* init credits */
2302 cp->freq = 1; /* init free list */
2303 for (i = 0; i < RQ_NPKTS; i++) { /* all pkts free */
2304 if (i) cp->pak[i].link = (i + 1) & RQ_M_NPKTS;
2305 else cp->pak[i].link = 0;
2306 for (j = 0; j < RQ_PKT_SIZE_W; j++) cp->pak[i].d[j] = 0;
2307 }
2308 cp->rspq = 0; /* no q'd rsp pkts */
2309 cp->pbsy = 0; /* all pkts free */
2310 cp->pip = 0; /* not polling */
2311 rq_clrint (cp); /* clr intr req */
2312 for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */
2313 uptr = dptr->units + i;
2314 sim_cancel (uptr); /* clr activity */
2315 uptr->cnum = cidx; /* set ctrl index */
2316 uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP);
2317 uptr->uf = 0; /* clr unit flags */
2318 uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */
2319 }
2320 if (rqxb == NULL) rqxb = (uint16 *) calloc (RQ_MAXFR >> 1, sizeof (uint16));
2321 if (rqxb == NULL) return SCPE_MEM;
2322 return auto_config (0, 0); /* run autoconfig */
2323 }
2324
2325 /* Device bootstrap */
2326
2327 #if defined (VM_PDP11)
2328
2329 #define BOOT_START 016000 /* start */
2330 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
2331 #define BOOT_UNIT (BOOT_START + 010) /* unit number */
2332 #define BOOT_CSR (BOOT_START + 014) /* CSR */
2333 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
2334
2335 static const uint16 boot_rom[] = {
2336
2337 0042125, /* st: "UD" */
2338
2339 /* Four step init process */
2340
2341 0012706, 0016000, /* mov #st,sp */
2342 0012700, 0000000, /* mov #unit,r0 */
2343 0012701, 0172150, /* mov #172150, r1 ; ip addr */
2344 0012704, 0016162, /* mov #it, r4 */
2345 0012705, 0004000, /* mov #4000,r5 ; s1 mask */
2346 0010102, /* mov r1,r2 */
2347 0005022, /* clr (r2)+ ; init */
2348 0005712, /* 10$: tst (r2) ; err? */
2349 0100001, /* bpl 20$ */
2350 0000000, /* halt */
2351 0030512, /* 20$: bit r5,(r2) ; step set? */
2352 0001773, /* beq 10$ ; wait */
2353 0012412, /* mov (r4)+,(r2) ; send next */
2354 0006305, /* asl r5 ; next mask */
2355 0100370, /* bpl 10$ ; s4 done? */
2356
2357 /* Send ONL, READ commands */
2358
2359 0105714, /* 30$: tstb (r4) ; end tbl? */
2360 0001434, /* beq done ; 0 = yes */
2361 0012702, 0007000, /* mov #rpkt-4,r2 ; clr pkts */
2362 0005022, /* 40$: clr (r2)+ */
2363 0020227, 0007204, /* cmp r2,#comm */
2364 0103774, /* blo 40$ */
2365 0112437, 0007100, /* movb (r4)+,cpkt-4 ; set lnt */
2366 0110037, 0007110, /* movb r0,cpkt+4 ; set unit */
2367 0112437, 0007114, /* movb (r4)+,cpkt+10 ; set op */
2368 0112437, 0007121, /* movb (r4)+,cpkt+15 ; set param */
2369 0012722, 0007004, /* mov #rpkt,(r2)+ ; rq desc */
2370 0010522, /* mov r5,(r2)+ ; rq own */
2371 0012722, 0007104, /* mov #ckpt,(r2)+ ; cq desc */
2372 0010512, /* mov r5,(r2) ; cq own */
2373 0024242, /* cmp -(r2),-(r2) ; back up */
2374 0005711, /* tst (r1) ; wake ctrl */
2375 0005712, /* 50$: tst (r2) ; rq own clr? */
2376 0100776, /* bmi 50$ ; wait */
2377 0005737, 0007016, /* tst rpkt+12 ; stat ok? */
2378 0001743, /* beq 30$ ; next cmd */
2379 0000000, /* halt */
2380
2381 /* Boot block read in, jump to 0 */
2382
2383 0005011, /* done: clr (r1) ; for M+ */
2384 0005003, /* clr r3 */
2385 0012704, BOOT_START+020, /* mov #st+020,r4 */
2386 0005005, /* clr r5 */
2387 0005007, /* clr pc */
2388
2389 /* Data */
2390
2391 0100000, /* it: no ints, ring sz = 1 */
2392 0007204, /* .word comm */
2393 0000000, /* .word 0 */
2394 0000001, /* .word 1 */
2395 0004420, /* .byte 20,11 */
2396 0020000, /* .byte 0,40 */
2397 0001041, /* .byte 41,2 */
2398 0000000
2399 };
2400
2401 t_stat rq_boot (int32 unitno, DEVICE *dptr)
2402 {
2403 int32 i;
2404 extern int32 saved_PC;
2405 extern uint16 *M;
2406 DIB *dibp = (DIB *) dptr->ctxt;
2407
2408 for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
2409 M[BOOT_UNIT >> 1] = unitno & 3;
2410 M[BOOT_CSR >> 1] = dibp->ba & DMASK;
2411 saved_PC = BOOT_ENTRY;
2412 return SCPE_OK;
2413 }
2414
2415 #else
2416
2417 t_stat rq_boot (int32 unitno, DEVICE *dptr)
2418 {
2419 return SCPE_NOFNC;
2420 }
2421 #endif
2422
2423 /* Special show commands */
2424
2425 void rq_show_ring (FILE *st, struct uq_ring *rp)
2426 {
2427 uint32 i, desc;
2428 uint16 d[2];
2429
2430 #if defined (VM_PDP11)
2431 fprintf (st, "ring, base = %o, index = %d, length = %d\n",
2432 rp->ba, rp->idx >> 2, rp->lnt >> 2);
2433 #else
2434 fprintf (st, "ring, base = %x, index = %d, length = %d\n",
2435 rp->ba, rp->idx >> 2, rp->lnt >> 2);
2436 #endif
2437 for (i = 0; i < (rp->lnt >> 2); i++) {
2438 if (Map_ReadW (rp->ba + (i << 2), 4, d)) {
2439 fprintf (st, " %3d: non-existent memory\n", i);
2440 break;
2441 }
2442 desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
2443 #if defined (VM_PDP11)
2444 fprintf (st, " %3d: %011o\n", i, desc);
2445 #else
2446 fprintf (st, " %3d: %08x\n", i, desc);
2447 #endif
2448 }
2449 return;
2450 }
2451
2452 void rq_show_pkt (FILE *st, MSC *cp, int32 pkt)
2453 {
2454 int32 i, j;
2455 uint32 cr = GETP (pkt, UQ_HCTC, CR);
2456 uint32 typ = GETP (pkt, UQ_HCTC, TYP);
2457 uint32 cid = GETP (pkt, UQ_HCTC, CID);
2458
2459 fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n",
2460 pkt, cr, typ, cid);
2461 for (i = 0; i < RQ_SH_MAX; i = i + RQ_SH_PPL) {
2462 fprintf (st, " %2d:", i);
2463 for (j = i; j < (i + RQ_SH_PPL); j++)
2464 #if defined (VM_PDP11)
2465 fprintf (st, " %06o", cp->pak[pkt].d[j]);
2466 #else
2467 fprintf (st, " %04x", cp->pak[pkt].d[j]);
2468 #endif
2469 fprintf (st, "\n");
2470 }
2471 return;
2472 }
2473
2474 t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc)
2475 {
2476 MSC *cp = rq_ctxmap[uptr->cnum];
2477 DEVICE *dptr = rq_devmap[uptr->cnum];
2478 int32 pkt, u;
2479
2480 u = (int32) (uptr - dptr->units);
2481 if (cp->csta != CST_UP) {
2482 fprintf (st, "Controller is not initialized\n");
2483 return SCPE_OK;
2484 }
2485 if ((uptr->flags & UNIT_ONL) == 0) {
2486 if (uptr->flags & UNIT_ATT)
2487 fprintf (st, "Unit %d is available\n", u);
2488 else fprintf (st, "Unit %d is offline\n", u);
2489 return SCPE_OK;
2490 }
2491 if (uptr->cpkt) {
2492 fprintf (st, "Unit %d current ", u);
2493 rq_show_pkt (st, cp, uptr->cpkt);
2494 if (pkt = uptr->pktq) {
2495 do {
2496 fprintf (st, "Unit %d queued ", u);
2497 rq_show_pkt (st, cp, pkt);
2498 } while (pkt = cp->pak[pkt].link);
2499 }
2500 }
2501 else fprintf (st, "Unit %d queues are empty\n", u);
2502 return SCPE_OK;
2503 }
2504
2505 t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)
2506 {
2507 MSC *cp = rq_ctxmap[uptr->cnum];
2508 DEVICE *dptr = rq_devmap[uptr->cnum];
2509 int32 i, pkt;
2510
2511 if (cp->csta != CST_UP) {
2512 fprintf (st, "Controller is not initialized\n");
2513 return SCPE_OK;
2514 }
2515 if (val & RQ_SH_RI) {
2516 if (cp->pip) fprintf (st, "Polling in progress, host timer = %d\n", cp->hat);
2517 else fprintf (st, "Host timer = %d\n", cp->hat);
2518 fprintf (st, "Command ");
2519 rq_show_ring (st, &cp->cq);
2520 fprintf (st, "Response ");
2521 rq_show_ring (st, &cp->rq);
2522 }
2523 if (val & RQ_SH_FR) {
2524 if (pkt = cp->freq) {
2525 for (i = 0; pkt != 0; i++, pkt = cp->pak[pkt].link) {
2526 if (i == 0) fprintf (st, "Free queue = %d", pkt);
2527 else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt);
2528 else fprintf (st, ", %d", pkt);
2529 }
2530 fprintf (st, "\n");
2531 }
2532 else fprintf (st, "Free queue is empty\n");
2533 }
2534 if (val & RQ_SH_RS) {
2535 if (pkt = cp->rspq) {
2536 do {
2537 fprintf (st, "Response ");
2538 rq_show_pkt (st, cp, pkt);
2539 } while (pkt = cp->pak[pkt].link);
2540 }
2541 else fprintf (st, "Response queue is empty\n");
2542 }
2543 if (val & RQ_SH_UN) {
2544 for (i = 0; i < RQ_NUMDR; i++)
2545 rq_show_unitq (st, dptr->units + i, 0, desc);
2546 }
2547 return SCPE_OK;
2548 }