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