1 /* pdp11_rq.c: MSCP disk controller simulator
3 Copyright (c) 2002-2007, Robert M Supnik
4 Derived from work by Stephen F. Shirron
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:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
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.
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.
27 rq RQDX3 disk controller
29 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
30 31-Oct-05 RMS Fixed address width for large files
31 16-Aug-05 RMS Fixed C++ declaration and cast problems
32 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
33 17-Jan-05 RMS Added more RA and RD disks
34 31-Oct-04 RMS Added -L switch (LBNs) to RAUSER size specification
35 01-Oct-04 RMS Revised Unibus interface
36 Changed to identify as UDA50 in Unibus configurations
37 Changed width to be 16b in all configurations
38 Changed default timing for VAX
39 24-Jul-04 RMS VAX controllers luns start with 0 (from Andreas Cejna)
40 05-Feb-04 RMS Revised for file I/O library
41 25-Jan-04 RMS Revised for device debug support
42 12-Jan-04 RMS Fixed bug in interrupt control (found by Tom Evans)
43 07-Oct-03 RMS Fixed problem with multiple RAUSER drives
44 17-Sep-03 RMS Fixed MB to LBN conversion to be more accurate
45 11-Jul-03 RMS Fixed bug in user disk size (found by Chaskiel M Grundman)
46 19-May-03 RMS Revised for new conditional compilation scheme
47 25-Apr-03 RMS Revised for extended file support
48 14-Mar-03 RMS Fixed variable size interaction with save/restore
49 27-Feb-03 RMS Added user-defined drive support
50 26-Feb-03 RMS Fixed bug in vector calculation for VAXen
51 22-Feb-03 RMS Fixed ordering bug in queue process
52 12-Oct-02 RMS Added multicontroller support
53 29-Sep-02 RMS Changed addressing to 18b in Unibus mode
54 Added variable address support to bootstrap
55 Added vector display support
56 Fixed status code in HBE error log
57 Consolidated MSCP/TMSCP header file
59 16-Aug-02 RMS Removed unused variables (found by David Hittner)
60 04-May-02 RMS Fixed bug in polling loop for queued operations
61 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH
62 09-Mar-02 RMS Adjusted delays for M+ timing bugs
63 04-Mar-02 RMS Added delays to initialization for M+, RSTS/E
64 16-Feb-02 RMS Fixed bugs in host timeout logic, boot
65 26-Jan-02 RMS Revised bootstrap to conform to M9312
66 06-Jan-02 RMS Revised enable/disable support
67 30-Dec-01 RMS Revised show routines
68 19-Dec-01 RMS Added bigger drives
69 17-Dec-01 RMS Added queue process
72 #if defined (VM_PDP10) /* PDP10 version */
73 #error "RQDX3 not supported on PDP-10!"
75 #elif defined (VM_VAX) /* VAX version */
79 #define OLDPC fault_PC
80 extern int32 fault_PC
;
82 #else /* PDP-11 version */
83 #include "pdp11_defs.h"
91 #if !defined (RQ_NUMCT)
94 #error "Assertion failure: RQ_NUMCT exceeds 4"
97 #include "pdp11_uqssp.h"
98 #include "pdp11_mscp.h"
100 #define UF_MSK (UF_CMR|UF_CMW) /* settable flags */
102 #define RQ_SH_MAX 24 /* max display wds */
103 #define RQ_SH_PPL 8 /* wds per line */
104 #define RQ_SH_DPL 4 /* desc per line */
105 #define RQ_SH_RI 001 /* show rings */
106 #define RQ_SH_FR 002 /* show free q */
107 #define RQ_SH_RS 004 /* show resp q */
108 #define RQ_SH_UN 010 /* show unit q's */
109 #define RQ_SH_ALL 017 /* show all */
111 #define RQ_CLASS 1 /* RQ class */
112 #define RQU_UQPM 6 /* UB port model */
113 #define RQQ_UQPM 19 /* QB port model */
114 #define RQ_UQPM (UNIBUS? RQU_UQPM: RQQ_UQPM)
115 #define RQU_MODEL 6 /* UB MSCP ctrl model */
116 #define RQQ_MODEL 19 /* QB MSCP ctrl model */
117 #define RQ_MODEL (UNIBUS? RQU_MODEL: RQQ_MODEL)
118 #define RQ_HVER 1 /* hardware version */
119 #define RQ_SVER 3 /* software version */
120 #define RQ_DHTMO 60 /* def host timeout */
121 #define RQ_DCTMO 120 /* def ctrl timeout */
122 #define RQ_NUMDR 4 /* # drives */
123 #define RQ_NUMBY 512 /* bytes per block */
124 #define RQ_MAXFR (1 << 16) /* max xfer */
126 #define UNIT_V_ONL (UNIT_V_UF + 0) /* online */
127 #define UNIT_V_WLK (UNIT_V_UF + 1) /* hwre write lock */
128 #define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */
129 #define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */
130 #define UNIT_M_DTYPE 0xF
131 #define UNIT_ONL (1 << UNIT_V_ONL)
132 #define UNIT_WLK (1 << UNIT_V_WLK)
133 #define UNIT_ATP (1 << UNIT_V_ATP)
134 #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
135 #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
136 #define cpkt u3 /* current packet */
137 #define pktq u4 /* packet queue */
138 #define uf buf /* settable unit flags */
139 #define cnum wait /* controller index */
140 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
141 #define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \
143 #define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \
144 (u->flags & UNIT_WPRT))? UF_WPH: 0)
146 #define CST_S1 0 /* init stage 1 */
147 #define CST_S1_WR 1 /* stage 1 wrap */
148 #define CST_S2 2 /* init stage 2 */
149 #define CST_S3 3 /* init stage 3 */
150 #define CST_S3_PPA 4 /* stage 3 sa wait */
151 #define CST_S3_PPB 5 /* stage 3 ip wait */
152 #define CST_S4 6 /* stage 4 */
153 #define CST_UP 7 /* online */
154 #define CST_DEAD 8 /* fatal error */
156 #define ERR 0 /* must be SCPE_OK! */
159 #define RQ_TIMER (RQ_NUMDR)
160 #define RQ_QUEUE (RQ_TIMER + 1)
162 /* Internal packet management. The real RQDX3 manages its packets as true
163 linked lists. However, use of actual addresses in structures won't work
164 with save/restore. Accordingly, the packets are an arrayed structure,
165 and links are actually subscripts. To minimize complexity, packet[0]
166 is not used (0 = end of list), and the number of packets must be a power
170 #define RQ_NPKTS 32 /* # packets (pwr of 2) */
171 #define RQ_M_NPKTS (RQ_NPKTS - 1) /* mask */
172 #define RQ_PKT_SIZE_W 32 /* payload size (wds) */
173 #define RQ_PKT_SIZE (RQ_PKT_SIZE_W * sizeof (int16))
176 int16 link
; /* link to next */
177 uint16 d
[RQ_PKT_SIZE_W
]; /* data */
180 /* Packet payload extraction and insertion; cp defines controller */
182 #define GETP(p,w,f) ((cp->pak[p].d[w] >> w##_V_##f) & w##_M_##f)
183 #define GETP32(p,w) (((uint32) cp->pak[p].d[w]) | \
184 (((uint32) cp->pak[p].d[(w)+1]) << 16))
185 #define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \
186 cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF
188 /* Disk formats. An RQDX3 disk consists of the following regions:
190 XBNs Extended blocks - contain information about disk format,
191 also holds track being reformatted during bad block repl.
192 Size = sectors/track + 1, replicated 3 times.
193 DBNs Diagnostic blocks - used by diagnostics. Sized to pad
194 out the XBNs to a cylinder boundary.
195 LBNs Logical blocks - contain user information.
196 RCT Replacement control table - first block contains status,
197 second contains data from block being replaced, remaining
198 contain information about replaced bad blocks.
199 Size = RBNs/128 + 3, replicated 4-8 times.
200 RBNs Replacement blocks - used to replace bad blocks.
202 The simulator does not need to perform bad block replacement; the
203 information below is for simulating RCT reads, if required.
205 Note that an RA drive has a different order: LBNs, RCT, XBN, DBN;
206 the RBNs are spare blocks at the end of every track.
209 #define RCT_OVHD 2 /* #ovhd blks */
210 #define RCT_ENTB 128 /* entries/blk */
211 #define RCT_END 0x80000000 /* marks RCT end */
213 /* The RQDX3 supports multiple disk drive types (x = not implemented):
215 type sec surf cyl tpg gpc RCT LBNs
217 RX50 10 1 80 5 16 - 800
218 RX33 15 2 80 2 1 - 2400
219 RD51 18 4 306 4 1 36*4 21600
220 RD31 17 4 615 4 1 3*8 41560
221 RD52 17 8 512 8 1 4*8 60480
222 x RD32 17 6 820 ? ? ? 83236
223 x RD33 17 7 1170 ? ? ? 138565
224 RD53 17 7 1024 7 1 5*8 138672
225 RD54 17 15 1225 15 1 7*8 311200
227 The simulator also supports larger drives that only existed
230 RA60 42(+1) 6 1600 6 1 1008 400176
231 x RA70 33(+1) 11 1507+ 11 1 ? 547041
232 RA81 51(+1) 14 1258 14 1 2856 891072
233 RA82 57(+1) 15 1435 15 1 3420 1216665
234 RA71 51(+1) 14 1921 14 1 1428 1367310
235 RA72 51(+1) 20 1921 20 1 2040 1953300
236 RA90 69(+1) 13 2656 13 1 1794 2376153
237 RA92 73(+1) 13 3101 13 1 949 2940951
238 x RA73 70(+1) 21 2667+ 21 1 ? 3920490
240 Each drive can be a different type. The drive field in the
241 unit flags specified the drive type and thus, indirectly,
245 #define RQDF_RMV 01 /* removable */
246 #define RQDF_RO 02 /* read only */
247 #define RQDF_SDI 04 /* SDI drive */
262 #define RX50_MED 0x25658032
263 #define RX50_FLGS RQDF_RMV
273 #define RX33_LBN 2400
278 #define RX33_MED 0x25658021
279 #define RX33_FLGS RQDF_RMV
289 #define RD51_LBN 21600
294 #define RD51_MED 0x25644033
300 #define RD31_CYL 615 /* last unused */
301 #define RD31_TPG RD31_SURF
305 #define RD31_LBN 41560
310 #define RD31_MED 0x2564401F
313 #define RD52_DTYPE 4 /* Quantum params */
317 #define RD52_TPG RD52_SURF
321 #define RD52_LBN 60480
326 #define RD52_MED 0x25644034
332 #define RD53_CYL 1024 /* last unused */
333 #define RD53_TPG RD53_SURF
337 #define RD53_LBN 138672
342 #define RD53_MED 0x25644035
348 #define RD54_CYL 1225 /* last unused */
349 #define RD54_TPG RD54_SURF
353 #define RD54_LBN 311200
358 #define RD54_MED 0x25644036
361 #define RA82_DTYPE 7 /* SDI drive */
362 #define RA82_SECT 57 /* +1 spare/track */
364 #define RA82_CYL 1435 /* 0-1422 user */
365 #define RA82_TPG RA82_SURF
367 #define RA82_XBN 3480 /* cyl 1427-1430 */
368 #define RA82_DBN 3480 /* cyl 1431-1434 */
369 #define RA82_LBN 1216665 /* 57*15*1423 */
370 #define RA82_RCTS 3420 /* cyl 1423-1426 */
372 #define RA82_RBN 21345 /* 1 *15*1423 */
374 #define RA82_MED 0x25641052
375 #define RA82_FLGS RQDF_SDI
377 #define RRD40_DTYPE 8
378 #define RRD40_SECT 128
380 #define RRD40_CYL 10400
381 #define RRD40_TPG RRD40_SURF
385 #define RRD40_LBN 1331200
390 #define RRD40_MED 0x25652228
391 #define RRD40_FLGS (RQDF_RMV | RQDF_RO)
393 #define RA72_DTYPE 9 /* SDI drive */
394 #define RA72_SECT 51 /* +1 spare/trk */
396 #define RA72_CYL 1921 /* 0-1914 user */
397 #define RA72_TPG RA72_SURF
399 #define RA72_XBN 2080 /* cyl 1917-1918? */
400 #define RA72_DBN 2080 /* cyl 1920-1921? */
401 #define RA72_LBN 1953300 /* 51*20*1915 */
402 #define RA72_RCTS 2040 /* cyl 1915-1916? */
404 #define RA72_RBN 38300 /* 1 *20*1915 */
406 #define RA72_MED 0x25641048
407 #define RA72_FLGS RQDF_SDI
409 #define RA90_DTYPE 10 /* SDI drive */
410 #define RA90_SECT 69 /* +1 spare/trk */
412 #define RA90_CYL 2656 /* 0-2648 user */
413 #define RA90_TPG RA90_SURF
415 #define RA90_XBN 1820 /* cyl 2651-2652? */
416 #define RA90_DBN 1820 /* cyl 2653-2654? */
417 #define RA90_LBN 2376153 /* 69*13*2649 */
418 #define RA90_RCTS 1794 /* cyl 2649-2650? */
420 #define RA90_RBN 34437 /* 1 *13*2649 */
422 #define RA90_MED 0x2564105A
423 #define RA90_FLGS RQDF_SDI
425 #define RA92_DTYPE 11 /* SDI drive */
426 #define RA92_SECT 73 /* +1 spare/trk */
428 #define RA92_CYL 3101 /* 0-3098 user */
429 #define RA92_TPG RA92_SURF
431 #define RA92_XBN 174 /* cyl 3100? */
433 #define RA92_LBN 2940951 /* 73*13*3099 */
434 #define RA92_RCTS 949 /* cyl 3099? */
436 #define RA92_RBN 40287 /* 1 *13*3099 */
438 #define RA92_MED 0x2564105C
439 #define RA92_FLGS RQDF_SDI
441 #define RA8U_DTYPE 12 /* user defined */
442 #define RA8U_SECT 57 /* from RA82 */
444 #define RA8U_CYL 1435 /* from RA82 */
445 #define RA8U_TPG RA8U_SURF
449 #define RA8U_LBN 1216665 /* from RA82 */
450 #define RA8U_RCTS 400
452 #define RA8U_RBN 21345
453 #define RA8U_MOD 11 /* RA82 */
454 #define RA8U_MED 0x25641052 /* RA82 */
455 #define RA8U_FLGS RQDF_SDI
456 #define RA8U_MINC 10000 /* min cap LBNs */
457 #define RA8U_MAXC 4000000 /* max cap LBNs */
458 #define RA8U_EMAXC 2000000000 /* ext max cap */
460 #define RA60_DTYPE 13 /* SDI drive */
461 #define RA60_SECT 42 /* +1 spare/track */
463 #define RA60_CYL 1600 /* 0-1587 user */
464 #define RA60_TPG RA60_SURF
466 #define RA60_XBN 1032 /* cyl 1592-1595 */
467 #define RA60_DBN 1032 /* cyl 1596-1599 */
468 #define RA60_LBN 400176 /* 42*6*1588 */
469 #define RA60_RCTS 1008 /* cyl 1588-1591 */
471 #define RA60_RBN 9528 /* 1 *6*1588 */
473 #define RA60_MED 0x22A4103C
474 #define RA60_FLGS (RQDF_RMV | RQDF_SDI)
476 #define RA81_DTYPE 14 /* SDI drive */
477 #define RA81_SECT 51 /* +1 spare/track */
479 #define RA81_CYL 1258 /* 0-1247 user */
480 #define RA81_TPG RA81_SURF
482 #define RA81_XBN 2436 /* cyl 1252-1254? */
483 #define RA81_DBN 2436 /* cyl 1255-1256? */
484 #define RA81_LBN 891072 /* 51*14*1248 */
485 #define RA81_RCTS 2856 /* cyl 1248-1251? */
487 #define RA81_RBN 17472 /* 1 *14*1248 */
489 #define RA81_MED 0x25641051
490 #define RA81_FLGS RQDF_SDI
492 #define RA71_DTYPE 15 /* SDI drive */
493 #define RA71_SECT 51 /* +1 spare/track */
495 #define RA71_CYL 1921 /* 0-1914 user */
496 #define RA71_TPG RA71_SURF
498 #define RA71_XBN 1456 /* cyl 1917-1918? */
499 #define RA71_DBN 1456 /* cyl 1919-1920? */
500 #define RA71_LBN 1367310 /* 51*14*1915 */
501 #define RA71_RCTS 1428 /* cyl 1915-1916? */
503 #define RA71_RBN 26810 /* 1 *14*1915 */
505 #define RA71_MED 0x25641047
506 #define RA71_FLGS RQDF_SDI
509 int32 sect
; /* sectors */
510 int32 surf
; /* surfaces */
511 int32 cyl
; /* cylinders */
512 int32 tpg
; /* trk/grp */
513 int32 gpc
; /* grp/cyl */
514 int32 xbn
; /* XBN size */
515 int32 dbn
; /* DBN size */
516 uint32 lbn
; /* LBN size */
517 int32 rcts
; /* RCT size */
518 int32 rctc
; /* RCT copies */
519 int32 rbn
; /* RBNs */
520 int32 mod
; /* MSCP model */
521 int32 med
; /* MSCP media */
522 int32 flgs
; /* flags */
523 char *name
; /* name */
527 d##_SECT, d##_SURF, d##_CYL, d##_TPG, \
528 d##_GPC, d##_XBN, d##_DBN, d##_LBN, \
529 d##_RCTS, d##_RCTC, d##_RBN, d##_MOD, \
531 #define RQ_SIZE(d) (d##_LBN * RQ_NUMBY)
533 static struct drvtyp drv_tab
[] = {
534 { RQ_DRV (RX50
), "RX50" }, { RQ_DRV (RX33
), "RX33" },
535 { RQ_DRV (RD51
), "RD51" }, { RQ_DRV (RD31
), "RD31" },
536 { RQ_DRV (RD52
), "RD52" }, { RQ_DRV (RD53
), "RD53" },
537 { RQ_DRV (RD54
), "RD54" }, { RQ_DRV (RA82
), "RA82" },
538 { RQ_DRV (RRD40
), "RRD40" }, { RQ_DRV (RA72
), "RA72" },
539 { RQ_DRV (RA90
), "RA90" }, { RQ_DRV (RA92
), "RA92" },
540 { RQ_DRV (RA8U
), "RAUSER" }, { RQ_DRV (RA60
), "RA60" },
541 { RQ_DRV (RA81
), "RA81" }, { RQ_DRV (RA71
), "RA71" },
545 extern int32 int_req
[IPL_HLVL
];
546 extern int32 tmr_poll
, clk_tps
;
547 extern UNIT cpu_unit
;
548 extern FILE *sim_deb
;
549 extern uint32 sim_taddr_64
;
550 extern int32 sim_switches
;
552 uint16
*rqxb
= NULL
; /* xfer buffer */
553 int32 rq_itime
= 200; /* init time, except */
554 int32 rq_itime4
= 10; /* stage 4 */
555 int32 rq_qtime
= RQ_QTIME
; /* queue time */
556 int32 rq_xtime
= RQ_XTIME
; /* transfer time */
559 uint32 cnum
; /* ctrl number */
560 uint32 ubase
; /* unit base */
561 uint32 sa
; /* status, addr */
562 uint32 saw
; /* written data */
563 uint32 s1dat
; /* S1 data */
564 uint32 comm
; /* comm region */
565 uint32 csta
; /* ctrl state */
566 uint32 perr
; /* last error */
567 uint32 cflgs
; /* ctrl flags */
568 uint32 irq
; /* intr request */
569 uint32 prgi
; /* purge int */
570 uint32 pip
; /* poll in progress */
571 int32 freq
; /* free list */
572 int32 rspq
; /* resp list */
573 uint32 pbsy
; /* #busy pkts */
574 uint32 credits
; /* credits */
575 uint32 hat
; /* host timer */
576 uint32 htmo
; /* host timeout */
577 struct uq_ring cq
; /* cmd ring */
578 struct uq_ring rq
; /* rsp ring */
579 struct rqpkt pak
[RQ_NPKTS
]; /* packet queue */
582 DEVICE rq_dev
, rqb_dev
, rqc_dev
,rqd_dev
;
584 t_stat
rq_rd (int32
*data
, int32 PA
, int32 access
);
585 t_stat
rq_wr (int32 data
, int32 PA
, int32 access
);
586 t_stat
rq_svc (UNIT
*uptr
);
587 t_stat
rq_tmrsvc (UNIT
*uptr
);
588 t_stat
rq_quesvc (UNIT
*uptr
);
589 t_stat
rq_reset (DEVICE
*dptr
);
590 t_stat
rq_attach (UNIT
*uptr
, char *cptr
);
591 t_stat
rq_detach (UNIT
*uptr
);
592 t_stat
rq_boot (int32 unitno
, DEVICE
*dptr
);
593 t_stat
rq_set_wlk (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
594 t_stat
rq_set_type (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
595 t_stat
rq_show_type (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
596 t_stat
rq_show_wlk (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
597 t_stat
rq_show_ctrl (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
598 t_stat
rq_show_unitq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
600 t_bool
rq_step4 (MSC
*cp
);
601 t_bool
rq_mscp (MSC
*cp
, int32 pkt
, t_bool q
);
602 t_bool
rq_abo (MSC
*cp
, int32 pkt
, t_bool q
);
603 t_bool
rq_avl (MSC
*cp
, int32 pkt
, t_bool q
);
604 t_bool
rq_fmt (MSC
*cp
, int32 pkt
, t_bool q
);
605 t_bool
rq_gcs (MSC
*cp
, int32 pkt
, t_bool q
);
606 t_bool
rq_gus (MSC
*cp
, int32 pkt
, t_bool q
);
607 t_bool
rq_onl (MSC
*cp
, int32 pkt
, t_bool q
);
608 t_bool
rq_rw (MSC
*cp
, int32 pkt
, t_bool q
);
609 t_bool
rq_scc (MSC
*cp
, int32 pkt
, t_bool q
);
610 t_bool
rq_suc (MSC
*cp
, int32 pkt
, t_bool q
);
611 t_bool
rq_plf (MSC
*cp
, uint32 err
);
612 t_bool
rq_dte (MSC
*cp
, UNIT
*uptr
, uint32 err
);
613 t_bool
rq_hbe (MSC
*cp
, UNIT
*uptr
);
614 t_bool
rq_una (MSC
*cp
, int32 un
);
615 t_bool
rq_deqf (MSC
*cp
, int32
*pkt
);
616 int32
rq_deqh (MSC
*cp
, int32
*lh
);
617 void rq_enqh (MSC
*cp
, int32
*lh
, int32 pkt
);
618 void rq_enqt (MSC
*cp
, int32
*lh
, int32 pkt
);
619 t_bool
rq_getpkt (MSC
*cp
, int32
*pkt
);
620 t_bool
rq_putpkt (MSC
*cp
, int32 pkt
, t_bool qt
);
621 t_bool
rq_getdesc (MSC
*cp
, struct uq_ring
*ring
, uint32
*desc
);
622 t_bool
rq_putdesc (MSC
*cp
, struct uq_ring
*ring
, uint32 desc
);
623 int32
rq_rw_valid (MSC
*cp
, int32 pkt
, UNIT
*uptr
, uint32 cmd
);
624 t_bool
rq_rw_end (MSC
*cp
, UNIT
*uptr
, uint32 flg
, uint32 sts
);
625 void rq_putr (MSC
*cp
, int32 pkt
, uint32 cmd
, uint32 flg
,
626 uint32 sts
, uint32 lnt
, uint32 typ
);
627 void rq_putr_unit (MSC
*cp
, int32 pkt
, UNIT
*uptr
, uint32 lu
, t_bool all
);
628 void rq_setf_unit (MSC
*cp
, int32 pkt
, UNIT
*uptr
);
629 void rq_init_int (MSC
*cp
);
630 void rq_ring_int (MSC
*cp
, struct uq_ring
*ring
);
631 t_bool
rq_fatal (MSC
*cp
, uint32 err
);
632 UNIT
*rq_getucb (MSC
*cp
, uint32 lu
);
633 int32
rq_map_pa (uint32 pa
);
634 void rq_setint (MSC
*cp
);
635 void rq_clrint (MSC
*cp
);
636 int32
rq_inta (void);
638 /* RQ data structures
640 rq_dev RQ device descriptor
642 rq_reg RQ register list
643 rq_mod RQ modifier list
649 IOBA_RQ
, IOLN_RQ
, &rq_rd
, &rq_wr
,
650 1, IVCL (RQ
), 0, { &rq_inta
}
654 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
655 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
656 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
657 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
658 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
659 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
660 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
661 (RX50_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RX50
)) },
662 { UDATA (&rq_tmrsvc
, UNIT_IDLE
|UNIT_DIS
, 0) },
663 { UDATA (&rq_quesvc
, UNIT_DIS
, 0) }
667 { GRDATA (SA
, rq_ctx
.sa
, DEV_RDX
, 16, 0) },
668 { GRDATA (SAW
, rq_ctx
.saw
, DEV_RDX
, 16, 0) },
669 { GRDATA (S1DAT
, rq_ctx
.s1dat
, DEV_RDX
, 16, 0) },
670 { GRDATA (COMM
, rq_ctx
.comm
, DEV_RDX
, 22, 0) },
671 { GRDATA (CQBA
, rq_ctx
.cq
.ba
, DEV_RDX
, 22, 0) },
672 { GRDATA (CQLNT
, rq_ctx
.cq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
673 { GRDATA (CQIDX
, rq_ctx
.cq
.idx
, DEV_RDX
, 8, 2) },
674 { GRDATA (RQBA
, rq_ctx
.rq
.ba
, DEV_RDX
, 22, 0) },
675 { GRDATA (RQLNT
, rq_ctx
.rq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
676 { GRDATA (RQIDX
, rq_ctx
.rq
.idx
, DEV_RDX
, 8, 2) },
677 { DRDATA (FREE
, rq_ctx
.freq
, 5) },
678 { DRDATA (RESP
, rq_ctx
.rspq
, 5) },
679 { DRDATA (PBSY
, rq_ctx
.pbsy
, 5) },
680 { GRDATA (CFLGS
, rq_ctx
.cflgs
, DEV_RDX
, 16, 0) },
681 { GRDATA (CSTA
, rq_ctx
.csta
, DEV_RDX
, 4, 0) },
682 { GRDATA (PERR
, rq_ctx
.perr
, DEV_RDX
, 9, 0) },
683 { DRDATA (CRED
, rq_ctx
.credits
, 5) },
684 { DRDATA (HAT
, rq_ctx
.hat
, 17) },
685 { DRDATA (HTMO
, rq_ctx
.htmo
, 17) },
686 { FLDATA (PRGI
, rq_ctx
.prgi
, 0), REG_HIDDEN
},
687 { FLDATA (PIP
, rq_ctx
.pip
, 0), REG_HIDDEN
},
688 { FLDATA (INT
, rq_ctx
.irq
, 0) },
689 { DRDATA (ITIME
, rq_itime
, 24), PV_LEFT
+ REG_NZ
},
690 { DRDATA (I4TIME
, rq_itime4
, 24), PV_LEFT
+ REG_NZ
},
691 { DRDATA (QTIME
, rq_qtime
, 24), PV_LEFT
+ REG_NZ
},
692 { DRDATA (XTIME
, rq_xtime
, 24), PV_LEFT
+ REG_NZ
},
693 { BRDATA (PKTS
, rq_ctx
.pak
, DEV_RDX
, 16, RQ_NPKTS
* (RQ_PKT_SIZE_W
+ 1)) },
694 { URDATA (CPKT
, rq_unit
[0].cpkt
, 10, 5, 0, RQ_NUMDR
, 0) },
695 { URDATA (PKTQ
, rq_unit
[0].pktq
, 10, 5, 0, RQ_NUMDR
, 0) },
696 { URDATA (UFLG
, rq_unit
[0].uf
, DEV_RDX
, 16, 0, RQ_NUMDR
, 0) },
697 { URDATA (CAPAC
, rq_unit
[0].capac
, 10, T_ADDR_W
, 0, RQ_NUMDR
, PV_LEFT
| REG_HRO
) },
698 { GRDATA (DEVADDR
, rq_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
699 { GRDATA (DEVVEC
, rq_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
700 { DRDATA (DEVLBN
, drv_tab
[RA8U_DTYPE
].lbn
, 22), REG_HRO
},
705 { UNIT_WLK
, 0, NULL
, "WRITEENABLED", &rq_set_wlk
},
706 { UNIT_WLK
, UNIT_WLK
, NULL
, "LOCKED", &rq_set_wlk
},
707 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, RQ_SH_RI
, "RINGS", NULL
,
708 NULL
, &rq_show_ctrl
, 0 },
709 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, RQ_SH_FR
, "FREEQ", NULL
,
710 NULL
, &rq_show_ctrl
, 0 },
711 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, RQ_SH_RS
, "RESPQ", NULL
,
712 NULL
, &rq_show_ctrl
, 0 },
713 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, RQ_SH_UN
, "UNITQ", NULL
,
714 NULL
, &rq_show_ctrl
, 0 },
715 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, RQ_SH_ALL
, "ALL", NULL
,
716 NULL
, &rq_show_ctrl
, 0 },
717 { MTAB_XTD
| MTAB_VUN
| MTAB_NMO
, 0, "UNITQ", NULL
,
718 NULL
, &rq_show_unitq
, 0 },
719 { MTAB_XTD
| MTAB_VUN
, 0, "WRITE", NULL
,
720 NULL
, &rq_show_wlk
, NULL
},
721 { MTAB_XTD
| MTAB_VUN
, RX50_DTYPE
, NULL
, "RX50",
722 &rq_set_type
, NULL
, NULL
},
723 { MTAB_XTD
| MTAB_VUN
, RX33_DTYPE
, NULL
, "RX33",
724 &rq_set_type
, NULL
, NULL
},
725 { MTAB_XTD
| MTAB_VUN
, RD31_DTYPE
, NULL
, "RD31",
726 &rq_set_type
, NULL
, NULL
},
727 { MTAB_XTD
| MTAB_VUN
, RD51_DTYPE
, NULL
, "RD51",
728 &rq_set_type
, NULL
, NULL
},
729 { MTAB_XTD
| MTAB_VUN
, RD52_DTYPE
, NULL
, "RD52",
730 &rq_set_type
, NULL
, NULL
},
731 { MTAB_XTD
| MTAB_VUN
, RD53_DTYPE
, NULL
, "RD53",
732 &rq_set_type
, NULL
, NULL
},
733 { MTAB_XTD
| MTAB_VUN
, RD54_DTYPE
, NULL
, "RD54",
734 &rq_set_type
, NULL
, NULL
},
735 { MTAB_XTD
| MTAB_VUN
, RA60_DTYPE
, NULL
, "RA60",
736 &rq_set_type
, NULL
, NULL
},
737 { MTAB_XTD
| MTAB_VUN
, RA81_DTYPE
, NULL
, "RA81",
738 &rq_set_type
, NULL
, NULL
},
739 { MTAB_XTD
| MTAB_VUN
, RA82_DTYPE
, NULL
, "RA82",
740 &rq_set_type
, NULL
, NULL
},
741 { MTAB_XTD
| MTAB_VUN
, RRD40_DTYPE
, NULL
, "RRD40",
742 &rq_set_type
, NULL
, NULL
},
743 { MTAB_XTD
| MTAB_VUN
, RRD40_DTYPE
, NULL
, "CDROM",
744 &rq_set_type
, NULL
, NULL
},
745 { MTAB_XTD
| MTAB_VUN
, RA71_DTYPE
, NULL
, "RA71",
746 &rq_set_type
, NULL
, NULL
},
747 { MTAB_XTD
| MTAB_VUN
, RA72_DTYPE
, NULL
, "RA72",
748 &rq_set_type
, NULL
, NULL
},
749 { MTAB_XTD
| MTAB_VUN
, RA90_DTYPE
, NULL
, "RA90",
750 &rq_set_type
, NULL
, NULL
},
751 { MTAB_XTD
| MTAB_VUN
, RA92_DTYPE
, NULL
, "RA92",
752 &rq_set_type
, NULL
, NULL
},
753 { MTAB_XTD
| MTAB_VUN
, RA8U_DTYPE
, NULL
, "RAUSER",
754 &rq_set_type
, NULL
, NULL
},
755 { MTAB_XTD
| MTAB_VUN
, 0, "TYPE", NULL
,
756 NULL
, &rq_show_type
, NULL
},
757 #if defined (VM_PDP11)
758 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", "ADDRESS",
759 &set_addr
, &show_addr
, NULL
},
761 { MTAB_XTD
|MTAB_VDV
, 004, "ADDRESS", NULL
,
762 NULL
, &show_addr
, NULL
},
764 { MTAB_XTD
|MTAB_VDV
, 0, "VECTOR", NULL
,
765 NULL
, &show_vec
, NULL
},
766 { MTAB_XTD
| MTAB_VDV
, 0, NULL
, "AUTOCONFIGURE",
767 &set_addr_flt
, NULL
, NULL
},
772 "RQ", rq_unit
, rq_reg
, rq_mod
,
773 RQ_NUMDR
+ 2, DEV_RDX
, T_ADDR_W
, 2, DEV_RDX
, 16,
774 NULL
, NULL
, &rq_reset
,
775 &rq_boot
, &rq_attach
, &rq_detach
,
776 &rq_dib
, DEV_FLTA
| DEV_DISABLE
| DEV_UBUS
| DEV_QBUS
| DEV_DEBUG
779 /* RQB data structures
781 rqb_dev RQB device descriptor
782 rqb_unit RQB unit list
783 rqb_reg RQB register list
784 rqb_mod RQB modifier list
790 IOBA_RQB
, IOLN_RQB
, &rq_rd
, &rq_wr
,
791 1, IVCL (RQ
), 0, { &rq_inta
}
795 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
796 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
797 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
798 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
799 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
800 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
801 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
802 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
803 { UDATA (&rq_tmrsvc
, UNIT_DIS
, 0) },
804 { UDATA (&rq_quesvc
, UNIT_DIS
, 0) }
808 { GRDATA (SA
, rqb_ctx
.sa
, DEV_RDX
, 16, 0) },
809 { GRDATA (SAW
, rqb_ctx
.saw
, DEV_RDX
, 16, 0) },
810 { GRDATA (S1DAT
, rqb_ctx
.s1dat
, DEV_RDX
, 16, 0) },
811 { GRDATA (COMM
, rqb_ctx
.comm
, DEV_RDX
, 22, 0) },
812 { GRDATA (CQBA
, rqb_ctx
.cq
.ba
, DEV_RDX
, 22, 0) },
813 { GRDATA (CQLNT
, rqb_ctx
.cq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
814 { GRDATA (CQIDX
, rqb_ctx
.cq
.idx
, DEV_RDX
, 8, 2) },
815 { GRDATA (RQBA
, rqb_ctx
.rq
.ba
, DEV_RDX
, 22, 0) },
816 { GRDATA (RQLNT
, rqb_ctx
.rq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
817 { GRDATA (RQIDX
, rqb_ctx
.rq
.idx
, DEV_RDX
, 8, 2) },
818 { DRDATA (FREE
, rqb_ctx
.freq
, 5) },
819 { DRDATA (RESP
, rqb_ctx
.rspq
, 5) },
820 { DRDATA (PBSY
, rqb_ctx
.pbsy
, 5) },
821 { GRDATA (CFLGS
, rqb_ctx
.cflgs
, DEV_RDX
, 16, 0) },
822 { GRDATA (CSTA
, rqb_ctx
.csta
, DEV_RDX
, 4, 0) },
823 { GRDATA (PERR
, rqb_ctx
.perr
, DEV_RDX
, 9, 0) },
824 { DRDATA (CRED
, rqb_ctx
.credits
, 5) },
825 { DRDATA (HAT
, rqb_ctx
.hat
, 17) },
826 { DRDATA (HTMO
, rqb_ctx
.htmo
, 17) },
827 { FLDATA (PRGI
, rqb_ctx
.prgi
, 0), REG_HIDDEN
},
828 { FLDATA (PIP
, rqb_ctx
.pip
, 0), REG_HIDDEN
},
829 { FLDATA (INT
, rqb_ctx
.irq
, 0) },
830 { BRDATA (PKTS
, rqb_ctx
.pak
, DEV_RDX
, 16, RQ_NPKTS
* (RQ_PKT_SIZE_W
+ 1)) },
831 { URDATA (CPKT
, rqb_unit
[0].cpkt
, 10, 5, 0, RQ_NUMDR
, 0) },
832 { URDATA (PKTQ
, rqb_unit
[0].pktq
, 10, 5, 0, RQ_NUMDR
, 0) },
833 { URDATA (UFLG
, rqb_unit
[0].uf
, DEV_RDX
, 16, 0, RQ_NUMDR
, 0) },
834 { URDATA (CAPAC
, rqb_unit
[0].capac
, 10, 31, 0, RQ_NUMDR
, PV_LEFT
| REG_HRO
) },
835 { GRDATA (DEVADDR
, rqb_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
836 { GRDATA (DEVVEC
, rqb_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
841 "RQB", rqb_unit
, rqb_reg
, rq_mod
,
842 RQ_NUMDR
+ 2, DEV_RDX
, T_ADDR_W
, 2, DEV_RDX
, 16,
843 NULL
, NULL
, &rq_reset
,
844 &rq_boot
, &rq_attach
, &rq_detach
,
845 &rqb_dib
, DEV_FLTA
| DEV_DISABLE
| DEV_DIS
| DEV_UBUS
| DEV_QBUS
| DEV_DEBUG
848 /* RQC data structures
850 rqc_dev RQC device descriptor
851 rqc_unit RQC unit list
852 rqc_reg RQC register list
853 rqc_mod RQC modifier list
859 IOBA_RQC
, IOLN_RQC
, &rq_rd
, &rq_wr
,
860 1, IVCL (RQ
), 0, { &rq_inta
}
864 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
865 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
866 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
867 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
868 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
869 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
870 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
871 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
872 { UDATA (&rq_tmrsvc
, UNIT_DIS
, 0) },
873 { UDATA (&rq_quesvc
, UNIT_DIS
, 0) }
877 { GRDATA (SA
, rqc_ctx
.sa
, DEV_RDX
, 16, 0) },
878 { GRDATA (SAW
, rqc_ctx
.saw
, DEV_RDX
, 16, 0) },
879 { GRDATA (S1DAT
, rqc_ctx
.s1dat
, DEV_RDX
, 16, 0) },
880 { GRDATA (COMM
, rqc_ctx
.comm
, DEV_RDX
, 22, 0) },
881 { GRDATA (CQBA
, rqc_ctx
.cq
.ba
, DEV_RDX
, 22, 0) },
882 { GRDATA (CQLNT
, rqc_ctx
.cq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
883 { GRDATA (CQIDX
, rqc_ctx
.cq
.idx
, DEV_RDX
, 8, 2) },
884 { GRDATA (RQBA
, rqc_ctx
.rq
.ba
, DEV_RDX
, 22, 0) },
885 { GRDATA (RQLNT
, rqc_ctx
.rq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
886 { GRDATA (RQIDX
, rqc_ctx
.rq
.idx
, DEV_RDX
, 8, 2) },
887 { DRDATA (FREE
, rqc_ctx
.freq
, 5) },
888 { DRDATA (RESP
, rqc_ctx
.rspq
, 5) },
889 { DRDATA (PBSY
, rqc_ctx
.pbsy
, 5) },
890 { GRDATA (CFLGS
, rqc_ctx
.cflgs
, DEV_RDX
, 16, 0) },
891 { GRDATA (CSTA
, rqc_ctx
.csta
, DEV_RDX
, 4, 0) },
892 { GRDATA (PERR
, rqc_ctx
.perr
, DEV_RDX
, 9, 0) },
893 { DRDATA (CRED
, rqc_ctx
.credits
, 5) },
894 { DRDATA (HAT
, rqc_ctx
.hat
, 17) },
895 { DRDATA (HTMO
, rqc_ctx
.htmo
, 17) },
896 { FLDATA (PRGI
, rqc_ctx
.prgi
, 0), REG_HIDDEN
},
897 { FLDATA (PIP
, rqc_ctx
.pip
, 0), REG_HIDDEN
},
898 { FLDATA (INT
, rqc_ctx
.irq
, 0) },
899 { BRDATA (PKTS
, rqc_ctx
.pak
, DEV_RDX
, 16, RQ_NPKTS
* (RQ_PKT_SIZE_W
+ 1)) },
900 { URDATA (CPKT
, rqc_unit
[0].cpkt
, 10, 5, 0, RQ_NUMDR
, 0) },
901 { URDATA (PKTQ
, rqc_unit
[0].pktq
, 10, 5, 0, RQ_NUMDR
, 0) },
902 { URDATA (UFLG
, rqc_unit
[0].uf
, DEV_RDX
, 16, 0, RQ_NUMDR
, 0) },
903 { URDATA (CAPAC
, rqc_unit
[0].capac
, 10, 31, 0, RQ_NUMDR
, PV_LEFT
| REG_HRO
) },
904 { GRDATA (DEVADDR
, rqc_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
905 { GRDATA (DEVVEC
, rqc_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
910 "RQC", rqc_unit
, rqc_reg
, rq_mod
,
911 RQ_NUMDR
+ 2, DEV_RDX
, T_ADDR_W
, 2, DEV_RDX
, 16,
912 NULL
, NULL
, &rq_reset
,
913 &rq_boot
, &rq_attach
, &rq_detach
,
914 &rqc_dib
, DEV_FLTA
| DEV_DISABLE
| DEV_DIS
| DEV_UBUS
| DEV_QBUS
| DEV_DEBUG
917 /* RQD data structures
919 rqd_dev RQ device descriptor
920 rqd_unit RQ unit list
921 rqd_reg RQ register list
922 rqd_mod RQ modifier list
928 IOBA_RQD
, IOLN_RQD
, &rq_rd
, &rq_wr
,
929 1, IVCL (RQ
), 0, { &rq_inta
}
933 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
934 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
935 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
936 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
937 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
938 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
939 { UDATA (&rq_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
+UNIT_ROABLE
+
940 (RD54_DTYPE
<< UNIT_V_DTYPE
), RQ_SIZE (RD54
)) },
941 { UDATA (&rq_tmrsvc
, UNIT_DIS
, 0) },
942 { UDATA (&rq_quesvc
, UNIT_DIS
, 0) }
946 { GRDATA (SA
, rqd_ctx
.sa
, DEV_RDX
, 16, 0) },
947 { GRDATA (SAW
, rqd_ctx
.saw
, DEV_RDX
, 16, 0) },
948 { GRDATA (S1DAT
, rqd_ctx
.s1dat
, DEV_RDX
, 16, 0) },
949 { GRDATA (COMM
, rqd_ctx
.comm
, DEV_RDX
, 22, 0) },
950 { GRDATA (CQBA
, rqd_ctx
.cq
.ba
, DEV_RDX
, 22, 0) },
951 { GRDATA (CQLNT
, rqd_ctx
.cq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
952 { GRDATA (CQIDX
, rqd_ctx
.cq
.idx
, DEV_RDX
, 8, 2) },
953 { GRDATA (RQBA
, rqd_ctx
.rq
.ba
, DEV_RDX
, 22, 0) },
954 { GRDATA (RQLNT
, rqd_ctx
.rq
.lnt
, DEV_RDX
, 8, 2), REG_NZ
},
955 { GRDATA (RQIDX
, rqd_ctx
.rq
.idx
, DEV_RDX
, 8, 2) },
956 { DRDATA (FREE
, rqd_ctx
.freq
, 5) },
957 { DRDATA (RESP
, rqd_ctx
.rspq
, 5) },
958 { DRDATA (PBSY
, rqd_ctx
.pbsy
, 5) },
959 { GRDATA (CFLGS
, rqd_ctx
.cflgs
, DEV_RDX
, 16, 0) },
960 { GRDATA (CSTA
, rqd_ctx
.csta
, DEV_RDX
, 4, 0) },
961 { GRDATA (PERR
, rqd_ctx
.perr
, DEV_RDX
, 9, 0) },
962 { DRDATA (CRED
, rqd_ctx
.credits
, 5) },
963 { DRDATA (HAT
, rqd_ctx
.hat
, 17) },
964 { DRDATA (HTMO
, rqd_ctx
.htmo
, 17) },
965 { FLDATA (PRGI
, rqd_ctx
.prgi
, 0), REG_HIDDEN
},
966 { FLDATA (PIP
, rqd_ctx
.pip
, 0), REG_HIDDEN
},
967 { FLDATA (INT
, rqd_ctx
.irq
, 0) },
968 { BRDATA (PKTS
, rqd_ctx
.pak
, DEV_RDX
, 16, RQ_NPKTS
* (RQ_PKT_SIZE_W
+ 1)) },
969 { URDATA (CPKT
, rqd_unit
[0].cpkt
, 10, 5, 0, RQ_NUMDR
, 0) },
970 { URDATA (PKTQ
, rqd_unit
[0].pktq
, 10, 5, 0, RQ_NUMDR
, 0) },
971 { URDATA (UFLG
, rqd_unit
[0].uf
, DEV_RDX
, 16, 0, RQ_NUMDR
, 0) },
972 { URDATA (CAPAC
, rqd_unit
[0].capac
, 10, 31, 0, RQ_NUMDR
, PV_LEFT
| REG_HRO
) },
973 { GRDATA (DEVADDR
, rqd_dib
.ba
, DEV_RDX
, 32, 0), REG_HRO
},
974 { GRDATA (DEVVEC
, rqd_dib
.vec
, DEV_RDX
, 16, 0), REG_HRO
},
979 "RQD", rqd_unit
, rqd_reg
, rq_mod
,
980 RQ_NUMDR
+ 2, DEV_RDX
, T_ADDR_W
, 2, DEV_RDX
, 16,
981 NULL
, NULL
, &rq_reset
,
982 &rq_boot
, &rq_attach
, &rq_detach
,
983 &rqd_dib
, DEV_FLTA
| DEV_DISABLE
| DEV_DIS
| DEV_UBUS
| DEV_QBUS
| DEV_DEBUG
986 static DEVICE
*rq_devmap
[RQ_NUMCT
] = {
987 &rq_dev
, &rqb_dev
, &rqc_dev
, &rqd_dev
990 static MSC
*rq_ctxmap
[RQ_NUMCT
] = {
991 &rq_ctx
, &rqb_ctx
, &rqc_ctx
, &rqd_ctx
994 /* I/O dispatch routines, I/O addresses 17772150 - 17772152
996 base + 0 IP read/write
997 base + 2 SA read/write
1000 t_stat
rq_rd (int32
*data
, int32 PA
, int32 access
)
1002 int32 cidx
= rq_map_pa ((uint32
) PA
);
1003 MSC
*cp
= rq_ctxmap
[cidx
];
1004 DEVICE
*dptr
= rq_devmap
[cidx
];
1006 if (cidx
< 0) return SCPE_IERR
;
1007 switch ((PA
>> 1) & 01) { /* decode PA<1> */
1010 *data
= 0; /* reads zero */
1011 if (cp
->csta
== CST_S3_PPB
) rq_step4 (cp
); /* waiting for poll? */
1012 else if (cp
->csta
== CST_UP
) { /* if up */
1013 if (DEBUG_PRD (dptr
)) fprintf (sim_deb
,
1014 ">>RQ%c: poll started, PC=%X\n", 'A' + cp
->cnum
, OLDPC
);
1015 cp
->pip
= 1; /* poll host */
1016 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_qtime
);
1028 t_stat
rq_wr (int32 data
, int32 PA
, int32 access
)
1030 int32 cidx
= rq_map_pa ((uint32
) PA
);
1031 MSC
*cp
= rq_ctxmap
[cidx
];
1032 DEVICE
*dptr
= rq_devmap
[cidx
];
1034 if (cidx
< 0) return SCPE_IERR
;
1035 switch ((PA
>> 1) & 01) { /* decode PA<1> */
1038 rq_reset (rq_devmap
[cidx
]); /* init device */
1039 if (DEBUG_PRD (dptr
)) fprintf (sim_deb
,
1040 ">>RQ%c: initialization started\n", 'A' + cp
->cnum
);
1045 if (cp
->csta
< CST_S4
) /* stages 1-3 */
1046 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_itime
);
1047 else if (cp
->csta
== CST_S4
) /* stage 4 (fast) */
1048 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_itime4
);
1055 /* Map physical address to device context */
1057 int32
rq_map_pa (uint32 pa
)
1063 for (i
= 0; i
< RQ_NUMCT
; i
++) { /* loop thru ctrls */
1064 dptr
= rq_devmap
[i
]; /* get device */
1065 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
1066 if ((pa
>= dibp
->ba
) && /* in range? */
1067 (pa
< (dibp
->ba
+ dibp
->lnt
)))
1068 return i
; /* return ctrl idx */
1073 /* Transition to step 4 - init communications region */
1075 t_bool
rq_step4 (MSC
*cp
)
1079 uint16 zero
[SA_COMM_MAX
>> 1];
1081 cp
->rq
.ioff
= SA_COMM_RI
; /* set intr offset */
1082 cp
->rq
.ba
= cp
->comm
; /* set rsp q base */
1083 cp
->rq
.lnt
= SA_S1H_RQ (cp
->s1dat
) << 2; /* get resp q len */
1084 cp
->cq
.ioff
= SA_COMM_CI
; /* set intr offset */
1085 cp
->cq
.ba
= cp
->comm
+ cp
->rq
.lnt
; /* set cmd q base */
1086 cp
->cq
.lnt
= SA_S1H_CQ (cp
->s1dat
) << 2; /* get cmd q len */
1087 cp
->cq
.idx
= cp
->rq
.idx
= 0; /* clear q idx's */
1088 if (cp
->prgi
) base
= cp
->comm
+ SA_COMM_QQ
;
1089 else base
= cp
->comm
+ SA_COMM_CI
;
1090 lnt
= cp
->comm
+ cp
->cq
.lnt
+ cp
->rq
.lnt
- base
; /* comm lnt */
1091 if (lnt
> SA_COMM_MAX
) lnt
= SA_COMM_MAX
; /* paranoia */
1092 for (i
= 0; i
< (lnt
>> 1); i
++) zero
[i
] = 0; /* clr buffer */
1093 if (Map_WriteW (base
, lnt
, zero
)) /* zero comm area */
1094 return rq_fatal (cp
, PE_QWE
); /* error? */
1095 cp
->sa
= SA_S4
| (RQ_UQPM
<< SA_S4C_V_MOD
) | /* send step 4 */
1096 (RQ_SVER
<< SA_S4C_V_VER
);
1097 cp
->csta
= CST_S4
; /* set step 4 */
1098 rq_init_int (cp
); /* poke host */
1102 /* Queue service - invoked when any of the queues (host queue, unit
1103 queues, response queue) require servicing. Also invoked during
1104 initialization to provide some delay to the next step.
1106 Process at most one item off each unit queue
1107 If the unit queues were empty, process at most one item off the host queue
1108 Process at most one item off the response queue
1110 If all queues are idle, terminate thread
1113 t_stat
rq_quesvc (UNIT
*uptr
)
1118 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
1119 DEVICE
*dptr
= rq_devmap
[uptr
->cnum
];
1120 DIB
*dibp
= (DIB
*) dptr
->ctxt
;
1122 if (cp
->csta
< CST_UP
) { /* still init? */
1123 switch (cp
->csta
) { /* controller state? */
1125 case CST_S1
: /* need S1 reply */
1126 if (cp
->saw
& SA_S1H_VL
) { /* valid? */
1127 if (cp
->saw
& SA_S1H_WR
) { /* wrap? */
1128 cp
->sa
= cp
->saw
; /* echo data */
1129 cp
->csta
= CST_S1_WR
; /* endless loop */
1132 cp
->s1dat
= cp
->saw
; /* save data */
1133 dibp
->vec
= (cp
->s1dat
& SA_S1H_VEC
) << 2; /* get vector */
1134 if (dibp
->vec
) dibp
->vec
= dibp
->vec
+ VEC_Q
; /* if nz, bias */
1135 cp
->sa
= SA_S2
| SA_S2C_PT
| SA_S2C_EC (cp
->s1dat
);
1136 cp
->csta
= CST_S2
; /* now in step 2 */
1137 rq_init_int (cp
); /* intr if req */
1139 } /* end if valid */
1142 case CST_S1_WR
: /* wrap mode */
1143 cp
->sa
= cp
->saw
; /* echo data */
1146 case CST_S2
: /* need S2 reply */
1147 cp
->comm
= cp
->saw
& SA_S2H_CLO
; /* get low addr */
1148 cp
->prgi
= cp
->saw
& SA_S2H_PI
; /* get purge int */
1149 cp
->sa
= SA_S3
| SA_S3C_EC (cp
->s1dat
);
1150 cp
->csta
= CST_S3
; /* now in step 3 */
1151 rq_init_int (cp
); /* intr if req */
1154 case CST_S3
: /* need S3 reply */
1155 cp
->comm
= ((cp
->saw
& SA_S3H_CHI
) << 16) | cp
->comm
;
1156 if (cp
->saw
& SA_S3H_PP
) { /* purge/poll test? */
1157 cp
->sa
= 0; /* put 0 */
1158 cp
->csta
= CST_S3_PPA
; /* wait for 0 write */
1160 else rq_step4 (cp
); /* send step 4 */
1163 case CST_S3_PPA
: /* need purge test */
1164 if (cp
->saw
) rq_fatal (cp
, PE_PPF
); /* data not zero? */
1165 else cp
->csta
= CST_S3_PPB
; /* wait for poll */
1168 case CST_S4
: /* need S4 reply */
1169 if (cp
->saw
& SA_S4H_GO
) { /* go set? */
1170 if (DEBUG_PRD (dptr
)) fprintf (sim_deb
,
1171 ">>RQ%c: initialization complete\n", 'A' + cp
->cnum
);
1172 cp
->csta
= CST_UP
; /* we're up */
1173 cp
->sa
= 0; /* clear SA */
1174 sim_activate (dptr
->units
+ RQ_TIMER
, tmr_poll
* clk_tps
);
1175 if ((cp
->saw
& SA_S4H_LF
) && cp
->perr
) rq_plf (cp
, cp
->perr
);
1184 for (i
= 0; i
< RQ_NUMDR
; i
++) { /* chk unit q's */
1185 nuptr
= dptr
->units
+ i
; /* ptr to unit */
1186 if (nuptr
->cpkt
|| (nuptr
->pktq
== 0)) continue;
1187 pkt
= rq_deqh (cp
, &nuptr
->pktq
); /* get top of q */
1188 if (!rq_mscp (cp
, pkt
, FALSE
)) return SCPE_OK
; /* process */
1190 if ((pkt
== 0) && cp
->pip
) { /* polling? */
1191 if (!rq_getpkt (cp
, &pkt
)) return SCPE_OK
; /* get host pkt */
1192 if (pkt
) { /* got one? */
1193 if (DEBUG_PRD (dptr
)) {
1194 fprintf (sim_deb
, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ",
1195 'A' + cp
->cnum
, cp
->pak
[pkt
].d
[CMD_OPC
],
1196 cp
->pak
[pkt
].d
[CMD_MOD
], cp
->pak
[pkt
].d
[CMD_UN
]);
1197 fprintf (sim_deb
, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n",
1198 cp
->pak
[pkt
].d
[RW_BCH
], cp
->pak
[pkt
].d
[RW_BCL
],
1199 cp
->pak
[pkt
].d
[RW_BAH
], cp
->pak
[pkt
].d
[RW_BAL
],
1200 cp
->pak
[pkt
].d
[RW_LBNH
], cp
->pak
[pkt
].d
[RW_LBNL
]);
1202 if (GETP (pkt
, UQ_HCTC
, TYP
) != UQ_TYP_SEQ
) /* seq packet? */
1203 return rq_fatal (cp
, PE_PIE
); /* no, term thread */
1204 cnid
= GETP (pkt
, UQ_HCTC
, CID
); /* get conn ID */
1205 if (cnid
== UQ_CID_MSCP
) { /* MSCP packet? */
1206 if (!rq_mscp (cp
, pkt
, TRUE
)) return SCPE_OK
; /* proc, q non-seq */
1208 else if (cnid
== UQ_CID_DUP
) { /* DUP packet? */
1209 rq_putr (cp
, pkt
, OP_END
, 0, ST_CMD
| I_OPCD
, RSP_LNT
, UQ_TYP_SEQ
);
1210 if (!rq_putpkt (cp
, pkt
, TRUE
)) return SCPE_OK
; /* ill cmd */
1212 else return rq_fatal (cp
, PE_ICI
); /* no, term thread */
1214 else cp
->pip
= 0; /* discontinue poll */
1216 if (cp
->rspq
) { /* resp q? */
1217 pkt
= rq_deqh (cp
, &cp
->rspq
); /* get top of q */
1218 if (!rq_putpkt (cp
, pkt
, FALSE
)) return SCPE_OK
; /* send to host */
1219 } /* end if resp q */
1220 if (pkt
) sim_activate (uptr
, rq_qtime
); /* more to do? */
1221 return SCPE_OK
; /* done */
1224 /* Clock service (roughly once per second) */
1226 t_stat
rq_tmrsvc (UNIT
*uptr
)
1230 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
1231 DEVICE
*dptr
= rq_devmap
[uptr
->cnum
];
1233 sim_activate (uptr
, tmr_poll
* clk_tps
); /* reactivate */
1234 for (i
= 0; i
< RQ_NUMDR
; i
++) { /* poll */
1235 nuptr
= dptr
->units
+ i
;
1236 if ((nuptr
->flags
& UNIT_ATP
) && /* ATN pending? */
1237 (nuptr
->flags
& UNIT_ATT
) && /* still online? */
1238 (cp
->cflgs
& CF_ATN
)) { /* wanted? */
1239 if (!rq_una (cp
, i
)) return SCPE_OK
;
1241 nuptr
->flags
= nuptr
->flags
& ~UNIT_ATP
;
1243 if ((cp
->hat
> 0) && (--cp
->hat
== 0)) /* host timeout? */
1244 rq_fatal (cp
, PE_HAT
); /* fatal err */
1248 /* MSCP packet handling */
1250 t_bool
rq_mscp (MSC
*cp
, int32 pkt
, t_bool q
)
1252 uint32 sts
, cmd
= GETP (pkt
, CMD_OPC
, OPC
);
1256 case OP_ABO
: /* abort */
1257 return rq_abo (cp
, pkt
, q
);
1259 case OP_AVL
: /* avail */
1260 return rq_avl (cp
, pkt
, q
);
1262 case OP_FMT
: /* format */
1263 return rq_fmt (cp
, pkt
, q
);
1265 case OP_GCS
: /* get cmd status */
1266 return rq_gcs (cp
, pkt
, q
);
1268 case OP_GUS
: /* get unit status */
1269 return rq_gus (cp
, pkt
, q
);
1271 case OP_ONL
: /* online */
1272 return rq_onl (cp
, pkt
, q
);
1274 case OP_SCC
: /* set ctrl char */
1275 return rq_scc (cp
, pkt
, q
);
1277 case OP_SUC
: /* set unit char */
1278 return rq_suc (cp
, pkt
, q
);
1280 case OP_ACC
: /* access */
1281 case OP_CMP
: /* compare */
1282 case OP_ERS
: /* erase */
1283 case OP_RD
: /* read */
1284 case OP_WR
: /* write */
1285 return rq_rw (cp
, pkt
, q
);
1287 case OP_CCD
: /* nops */
1290 cmd
= cmd
| OP_END
; /* set end flag */
1291 sts
= ST_SUC
; /* success */
1295 cmd
= OP_END
; /* set end op */
1296 sts
= ST_CMD
| I_OPCD
; /* ill op */
1300 rq_putr (cp
, pkt
, cmd
, 0, sts
, RSP_LNT
, UQ_TYP_SEQ
);
1301 return rq_putpkt (cp
, pkt
, TRUE
);
1304 /* Abort a command - 1st parameter is ref # of cmd to abort */
1306 t_bool
rq_abo (MSC
*cp
, int32 pkt
, t_bool q
)
1308 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1309 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1310 uint32 ref
= GETP32 (pkt
, ABO_REFL
); /* cmd ref # */
1313 DEVICE
*dptr
= rq_devmap
[cp
->cnum
];
1315 tpkt
= 0; /* set no mtch */
1316 if (uptr
= rq_getucb (cp
, lu
)) { /* get unit */
1317 if (uptr
->cpkt
&& /* curr pkt? */
1318 (GETP32 (uptr
->cpkt
, CMD_REFL
) == ref
)) { /* match ref? */
1319 tpkt
= uptr
->cpkt
; /* save match */
1320 uptr
->cpkt
= 0; /* gonzo */
1321 sim_cancel (uptr
); /* cancel unit */
1322 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_qtime
);
1324 else if (uptr
->pktq
&& /* head of q? */
1325 (GETP32 (uptr
->pktq
, CMD_REFL
) == ref
)) { /* match ref? */
1326 tpkt
= uptr
->pktq
; /* save match */
1327 uptr
->pktq
= cp
->pak
[tpkt
].link
; /* unlink */
1329 else if (prv
= uptr
->pktq
) { /* srch pkt q */
1330 while (tpkt
= cp
->pak
[prv
].link
) { /* walk list */
1331 if (GETP32 (tpkt
, RSP_REFL
) == ref
) { /* match? unlink */
1332 cp
->pak
[prv
].link
= cp
->pak
[tpkt
].link
;
1337 if (tpkt
) { /* found target? */
1338 uint32 tcmd
= GETP (tpkt
, CMD_OPC
, OPC
); /* get opcode */
1339 rq_putr (cp
, tpkt
, tcmd
| OP_END
, 0, ST_ABO
, RSP_LNT
, UQ_TYP_SEQ
);
1340 if (!rq_putpkt (cp
, tpkt
, TRUE
)) return ERR
;
1343 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, ST_SUC
, ABO_LNT
, UQ_TYP_SEQ
);
1344 return rq_putpkt (cp
, pkt
, TRUE
);
1347 /* Unit available - set unit status to available - defer if q'd cmds */
1349 t_bool
rq_avl (MSC
*cp
, int32 pkt
, t_bool q
)
1351 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1352 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1356 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1357 if (q
&& uptr
->cpkt
) { /* need to queue? */
1358 rq_enqt (cp
, &uptr
->pktq
, pkt
); /* do later */
1361 uptr
->flags
= uptr
->flags
& ~UNIT_ONL
; /* not online */
1362 uptr
->uf
= 0; /* clr flags */
1363 sts
= ST_SUC
; /* success */
1365 else sts
= ST_OFL
; /* offline */
1366 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, AVL_LNT
, UQ_TYP_SEQ
);
1367 return rq_putpkt (cp
, pkt
, TRUE
);
1370 /* Get command status - only interested in active xfr cmd */
1372 t_bool
rq_gcs (MSC
*cp
, int32 pkt
, t_bool q
)
1374 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1375 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1376 uint32 ref
= GETP32 (pkt
, GCS_REFL
); /* ref # */
1380 if ((uptr
= rq_getucb (cp
, lu
)) && /* valid lu? */
1381 (tpkt
= uptr
->cpkt
) && /* queued pkt? */
1382 (GETP32 (tpkt
, CMD_REFL
) == ref
) && /* match ref? */
1383 (GETP (tpkt
, CMD_OPC
, OPC
) >= OP_ACC
)) { /* rd/wr cmd? */
1384 cp
->pak
[pkt
].d
[GCS_STSL
] = cp
->pak
[tpkt
].d
[RW_WBCL
];
1385 cp
->pak
[pkt
].d
[GCS_STSH
] = cp
->pak
[tpkt
].d
[RW_WBCH
];
1388 cp
->pak
[pkt
].d
[GCS_STSL
] = 0; /* return 0 */
1389 cp
->pak
[pkt
].d
[GCS_STSH
] = 0;
1391 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, ST_SUC
, GCS_LNT
, UQ_TYP_SEQ
);
1392 return rq_putpkt (cp
, pkt
, TRUE
);
1395 /* Get unit status */
1397 t_bool
rq_gus (MSC
*cp
, int32 pkt
, t_bool q
)
1399 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1400 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1401 uint32 dtyp
, sts
, rbpar
;
1404 if (cp
->pak
[pkt
].d
[CMD_MOD
] & MD_NXU
) { /* next unit? */
1405 if (lu
>= (cp
->ubase
+ RQ_NUMDR
)) { /* end of range? */
1406 lu
= 0; /* reset to 0 */
1407 cp
->pak
[pkt
].d
[RSP_UN
] = lu
;
1410 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1411 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
1412 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
1413 else if (uptr
->flags
& UNIT_ONL
) sts
= ST_SUC
; /* online */
1414 else sts
= ST_AVL
; /* avail */
1415 rq_putr_unit (cp
, pkt
, uptr
, lu
, FALSE
); /* fill unit fields */
1416 dtyp
= GET_DTYPE (uptr
->flags
); /* get drive type */
1417 if (drv_tab
[dtyp
].rcts
) rbpar
= 1; /* ctrl bad blk? */
1418 else rbpar
= 0; /* fill geom, bblk */
1419 cp
->pak
[pkt
].d
[GUS_TRK
] = drv_tab
[dtyp
].sect
;
1420 cp
->pak
[pkt
].d
[GUS_GRP
] = drv_tab
[dtyp
].tpg
;
1421 cp
->pak
[pkt
].d
[GUS_CYL
] = drv_tab
[dtyp
].gpc
;
1422 cp
->pak
[pkt
].d
[GUS_UVER
] = 0;
1423 cp
->pak
[pkt
].d
[GUS_RCTS
] = drv_tab
[dtyp
].rcts
;
1424 cp
->pak
[pkt
].d
[GUS_RBSC
] =
1425 (rbpar
<< GUS_RB_V_RBNS
) | (rbpar
<< GUS_RB_V_RCTC
);
1427 else sts
= ST_OFL
; /* offline */
1428 cp
->pak
[pkt
].d
[GUS_SHUN
] = lu
; /* shadowing */
1429 cp
->pak
[pkt
].d
[GUS_SHST
] = 0;
1430 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, GUS_LNT_D
, UQ_TYP_SEQ
);
1431 return rq_putpkt (cp
, pkt
, TRUE
);
1434 /* Unit online - defer if q'd commands */
1436 t_bool
rq_onl (MSC
*cp
, int32 pkt
, t_bool q
)
1438 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1439 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1443 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1444 if (q
&& uptr
->cpkt
) { /* need to queue? */
1445 rq_enqt (cp
, &uptr
->pktq
, pkt
); /* do later */
1448 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
1449 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
1450 else if (uptr
->flags
& UNIT_ONL
) /* already online? */
1451 sts
= ST_SUC
| SB_SUC_ON
;
1452 else { /* mark online */
1454 uptr
->flags
= uptr
->flags
| UNIT_ONL
;
1455 rq_setf_unit (cp
, pkt
, uptr
); /* hack flags */
1457 rq_putr_unit (cp
, pkt
, uptr
, lu
, TRUE
); /* set fields */
1459 else sts
= ST_OFL
; /* offline */
1460 cp
->pak
[pkt
].d
[ONL_SHUN
] = lu
; /* shadowing */
1461 cp
->pak
[pkt
].d
[ONL_SHST
] = 0;
1462 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, ONL_LNT
, UQ_TYP_SEQ
);
1463 return rq_putpkt (cp
, pkt
, TRUE
);
1466 /* Set controller characteristics */
1468 t_bool
rq_scc (MSC
*cp
, int32 pkt
, t_bool q
)
1472 if (cp
->pak
[pkt
].d
[SCC_MSV
]) { /* MSCP ver = 0? */
1473 sts
= ST_CMD
| I_VRSN
; /* no, lose */
1477 sts
= ST_SUC
; /* success */
1478 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* get opcode */
1479 cp
->cflgs
= (cp
->cflgs
& CF_RPL
) | /* hack ctrl flgs */
1480 cp
->pak
[pkt
].d
[SCC_CFL
];
1481 if (cp
->htmo
= cp
->pak
[pkt
].d
[SCC_TMO
]) /* set timeout */
1482 cp
->htmo
= cp
->htmo
+ 2; /* if nz, round up */
1483 cp
->pak
[pkt
].d
[SCC_CFL
] = cp
->cflgs
; /* return flags */
1484 cp
->pak
[pkt
].d
[SCC_TMO
] = RQ_DCTMO
; /* ctrl timeout */
1485 cp
->pak
[pkt
].d
[SCC_VER
] = (RQ_HVER
<< SCC_VER_V_HVER
) |
1486 (RQ_SVER
<< SCC_VER_V_SVER
);
1487 cp
->pak
[pkt
].d
[SCC_CIDA
] = 0; /* ctrl ID */
1488 cp
->pak
[pkt
].d
[SCC_CIDB
] = 0;
1489 cp
->pak
[pkt
].d
[SCC_CIDC
] = 0;
1490 cp
->pak
[pkt
].d
[SCC_CIDD
] = (RQ_CLASS
<< SCC_CIDD_V_CLS
) |
1491 (RQ_MODEL
<< SCC_CIDD_V_MOD
);
1492 cp
->pak
[pkt
].d
[SCC_MBCL
] = 0; /* max bc */
1493 cp
->pak
[pkt
].d
[SCC_MBCH
] = 0;
1495 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, SCC_LNT
, UQ_TYP_SEQ
);
1496 return rq_putpkt (cp
, pkt
, TRUE
);
1499 /* Set unit characteristics - defer if q'd commands */
1501 t_bool
rq_suc (MSC
*cp
, int32 pkt
, t_bool q
)
1503 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1504 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1508 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1509 if (q
&& uptr
->cpkt
) { /* need to queue? */
1510 rq_enqt (cp
, &uptr
->pktq
, pkt
); /* do later */
1513 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
1514 sts
= ST_OFL
| SB_OFL_NV
; /* offl no vol */
1515 else { /* avail or onl */
1517 rq_setf_unit (cp
, pkt
, uptr
); /* hack flags */
1519 rq_putr_unit (cp
, pkt
, uptr
, lu
, TRUE
); /* set fields */
1521 else sts
= ST_OFL
; /* offline */
1522 cp
->pak
[pkt
].d
[ONL_SHUN
] = lu
; /* shadowing */
1523 cp
->pak
[pkt
].d
[ONL_SHST
] = 0;
1524 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, SUC_LNT
, UQ_TYP_SEQ
);
1525 return rq_putpkt (cp
, pkt
, TRUE
);
1528 /* Format command - floppies only */
1530 t_bool
rq_fmt (MSC
*cp
, int32 pkt
, t_bool q
)
1532 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1533 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1537 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1538 if (q
&& uptr
->cpkt
) { /* need to queue? */
1539 rq_enqt (cp
, &uptr
->pktq
, pkt
); /* do later */
1542 if (GET_DTYPE (uptr
->flags
) != RX33_DTYPE
) /* RX33? */
1543 sts
= ST_CMD
| I_OPCD
; /* no, err */
1544 else if ((cp
->pak
[pkt
].d
[FMT_IH
] & 0100000) == 0) /* magic bit set? */
1545 sts
= ST_CMD
| I_FMTI
; /* no, err */
1546 else if ((uptr
->flags
& UNIT_ATT
) == 0) /* offline? */
1547 sts
= ST_OFL
| SB_OFL_NV
; /* no vol */
1548 else if (uptr
->flags
& UNIT_ONL
) { /* online? */
1549 uptr
->flags
= uptr
->flags
& ~UNIT_ONL
;
1550 uptr
->uf
= 0; /* clear flags */
1551 sts
= ST_AVL
| SB_AVL_INU
; /* avail, in use */
1553 else if (RQ_WPH (uptr
)) /* write prot? */
1554 sts
= ST_WPR
| SB_WPR_HW
; /* can't fmt */
1555 else sts
= ST_SUC
; /*** for now ***/
1557 else sts
= ST_OFL
; /* offline */
1558 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, FMT_LNT
, UQ_TYP_SEQ
);
1559 return rq_putpkt (cp
, pkt
, TRUE
);
1562 /* Data transfer commands */
1564 t_bool
rq_rw (MSC
*cp
, int32 pkt
, t_bool q
)
1566 uint32 lu
= cp
->pak
[pkt
].d
[CMD_UN
]; /* unit # */
1567 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* opcode */
1571 if (uptr
= rq_getucb (cp
, lu
)) { /* unit exist? */
1572 if (q
&& uptr
->cpkt
) { /* need to queue? */
1573 rq_enqt (cp
, &uptr
->pktq
, pkt
); /* do later */
1576 sts
= rq_rw_valid (cp
, pkt
, uptr
, cmd
); /* validity checks */
1577 if (sts
== 0) { /* ok? */
1578 uptr
->cpkt
= pkt
; /* op in progress */
1579 cp
->pak
[pkt
].d
[RW_WBAL
] = cp
->pak
[pkt
].d
[RW_BAL
];
1580 cp
->pak
[pkt
].d
[RW_WBAH
] = cp
->pak
[pkt
].d
[RW_BAH
];
1581 cp
->pak
[pkt
].d
[RW_WBCL
] = cp
->pak
[pkt
].d
[RW_BCL
];
1582 cp
->pak
[pkt
].d
[RW_WBCH
] = cp
->pak
[pkt
].d
[RW_BCH
];
1583 cp
->pak
[pkt
].d
[RW_WBLL
] = cp
->pak
[pkt
].d
[RW_LBNL
];
1584 cp
->pak
[pkt
].d
[RW_WBLH
] = cp
->pak
[pkt
].d
[RW_LBNH
];
1585 sim_activate (uptr
, rq_xtime
); /* activate */
1586 return OK
; /* done */
1589 else sts
= ST_OFL
; /* offline */
1590 cp
->pak
[pkt
].d
[RW_BCL
] = cp
->pak
[pkt
].d
[RW_BCH
] = 0; /* bad packet */
1591 rq_putr (cp
, pkt
, cmd
| OP_END
, 0, sts
, RW_LNT_D
, UQ_TYP_SEQ
);
1592 return rq_putpkt (cp
, pkt
, TRUE
);
1595 /* Validity checks */
1597 int32
rq_rw_valid (MSC
*cp
, int32 pkt
, UNIT
*uptr
, uint32 cmd
)
1599 uint32 dtyp
= GET_DTYPE (uptr
->flags
); /* get drive type */
1600 uint32 lbn
= GETP32 (pkt
, RW_LBNL
); /* get lbn */
1601 uint32 bc
= GETP32 (pkt
, RW_BCL
); /* get byte cnt */
1602 uint32 maxlbn
= (uint32
) (uptr
->capac
/ RQ_NUMBY
); /* get max lbn */
1604 if ((uptr
->flags
& UNIT_ATT
) == 0) /* not attached? */
1605 return (ST_OFL
| SB_OFL_NV
); /* offl no vol */
1606 if ((uptr
->flags
& UNIT_ONL
) == 0) /* not online? */
1607 return ST_AVL
; /* only avail */
1608 if ((cmd
!= OP_ACC
) && (cmd
!= OP_ERS
) && /* 'real' xfer */
1609 (cp
->pak
[pkt
].d
[RW_BAL
] & 1)) /* odd address? */
1610 return (ST_HST
| SB_HST_OA
); /* host buf odd */
1611 if (bc
& 1) return (ST_HST
| SB_HST_OC
); /* odd byte cnt? */
1612 if (bc
& 0xF0000000) return (ST_CMD
| I_BCNT
); /* 'reasonable' bc? */
1613 /* if (lbn & 0xF0000000) return (ST_CMD | I_LBN); /* 'reasonable' lbn? */
1614 if (lbn
>= maxlbn
) { /* accessing RCT? */
1615 if (lbn
>= (maxlbn
+ drv_tab
[dtyp
].rcts
)) /* beyond copy 1? */
1616 return (ST_CMD
| I_LBN
); /* lbn err */
1617 if (bc
!= RQ_NUMBY
) return (ST_CMD
| I_BCNT
); /* bc must be 512 */
1619 else if ((lbn
+ ((bc
+ (RQ_NUMBY
- 1)) / RQ_NUMBY
)) > maxlbn
)
1620 return (ST_CMD
| I_BCNT
); /* spiral to RCT */
1621 if ((cmd
== OP_WR
) || (cmd
== OP_ERS
)) { /* write op? */
1622 if (lbn
>= maxlbn
) /* accessing RCT? */
1623 return (ST_CMD
| I_LBN
); /* lbn err */
1624 if (uptr
->uf
& UF_WPS
) /* swre wlk? */
1625 return (ST_WPR
| SB_WPR_SW
);
1626 if (RQ_WPH (uptr
)) /* hwre wlk? */
1627 return (ST_WPR
| SB_WPR_HW
);
1629 return 0; /* success! */
1632 /* Unit service for data transfer commands */
1634 t_stat
rq_svc (UNIT
*uptr
)
1636 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
1638 uint32 i
, t
, tbc
, abc
, wwc
;
1640 int32 pkt
= uptr
->cpkt
; /* get packet */
1641 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* get cmd */
1642 uint32 ba
= GETP32 (pkt
, RW_WBAL
); /* buf addr */
1643 uint32 bc
= GETP32 (pkt
, RW_WBCL
); /* byte count */
1644 uint32 bl
= GETP32 (pkt
, RW_WBLL
); /* block addr */
1645 t_addr da
= ((t_addr
) bl
) * RQ_NUMBY
; /* disk addr */
1647 if ((cp
== NULL
) || (pkt
== 0)) return STOP_RQ
; /* what??? */
1648 tbc
= (bc
> RQ_MAXFR
)? RQ_MAXFR
: bc
; /* trim cnt to max */
1650 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* not attached? */
1651 rq_rw_end (cp
, uptr
, 0, ST_OFL
| SB_OFL_NV
); /* offl no vol */
1654 if (bc
== 0) { /* no xfer? */
1655 rq_rw_end (cp
, uptr
, 0, ST_SUC
); /* ok by me... */
1659 if ((cmd
== OP_ERS
) || (cmd
== OP_WR
)) { /* write op? */
1660 if (RQ_WPH (uptr
)) {
1661 rq_rw_end (cp
, uptr
, 0, ST_WPR
| SB_WPR_HW
);
1664 if (uptr
->uf
& UF_WPS
) {
1665 rq_rw_end (cp
, uptr
, 0, ST_WPR
| SB_WPR_SW
);
1670 if (cmd
== OP_ERS
) { /* erase? */
1671 wwc
= ((tbc
+ (RQ_NUMBY
- 1)) & ~(RQ_NUMBY
- 1)) >> 1;
1672 for (i
= 0; i
< wwc
; i
++) rqxb
[i
] = 0; /* clr buf */
1673 err
= sim_fseek (uptr
->fileref
, da
, SEEK_SET
); /* set pos */
1674 if (!err
) sim_fwrite (rqxb
, sizeof (int16
), wwc
, uptr
->fileref
);
1675 err
= ferror (uptr
->fileref
); /* end if erase */
1678 else if (cmd
== OP_WR
) { /* write? */
1679 t
= Map_ReadW (ba
, tbc
, rqxb
); /* fetch buffer */
1680 if (abc
= tbc
- t
) { /* any xfer? */
1681 wwc
= ((abc
+ (RQ_NUMBY
- 1)) & ~(RQ_NUMBY
- 1)) >> 1;
1682 for (i
= (abc
>> 1); i
< wwc
; i
++) rqxb
[i
] = 0;
1683 err
= sim_fseek (uptr
->fileref
, da
, SEEK_SET
);
1684 if (!err
) sim_fwrite (rqxb
, sizeof (int16
), wwc
, uptr
->fileref
);
1685 err
= ferror (uptr
->fileref
);
1688 PUTP32 (pkt
, RW_WBCL
, bc
- abc
); /* adj bc */
1689 PUTP32 (pkt
, RW_WBAL
, ba
+ abc
); /* adj ba */
1690 if (rq_hbe (cp
, uptr
)) /* post err log */
1691 rq_rw_end (cp
, uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
);
1692 return SCPE_OK
; /* end else wr */
1697 err
= sim_fseek (uptr
->fileref
, da
, SEEK_SET
); /* set pos */
1699 i
= sim_fread (rqxb
, sizeof (int16
), tbc
>> 1, uptr
->fileref
);
1700 for ( ; i
< (tbc
>> 1); i
++) rqxb
[i
] = 0; /* fill */
1701 err
= ferror (uptr
->fileref
);
1703 if ((cmd
== OP_RD
) && !err
) { /* read? */
1704 if (t
= Map_WriteW (ba
, tbc
, rqxb
)) { /* store, nxm? */
1705 PUTP32 (pkt
, RW_WBCL
, bc
- (tbc
- t
)); /* adj bc */
1706 PUTP32 (pkt
, RW_WBAL
, ba
+ (tbc
- t
)); /* adj ba */
1707 if (rq_hbe (cp
, uptr
)) /* post err log */
1708 rq_rw_end (cp
, uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
);
1712 else if ((cmd
== OP_CMP
) && !err
) { /* compare? */
1714 for (i
= 0; i
< tbc
; i
++) { /* loop */
1715 if (Map_ReadB (ba
+ i
, 1, &mby
)) { /* fetch, nxm? */
1716 PUTP32 (pkt
, RW_WBCL
, bc
- i
); /* adj bc */
1717 PUTP32 (pkt
, RW_WBAL
, bc
- i
); /* adj ba */
1718 if (rq_hbe (cp
, uptr
)) /* post err log */
1719 rq_rw_end (cp
, uptr
, EF_LOG
, ST_HST
| SB_HST_NXM
);
1722 dby
= (rqxb
[i
>> 1] >> ((i
& 1)? 8: 0)) & 0xFF;
1723 if (mby
!= dby
) { /* cmp err? */
1724 PUTP32 (pkt
, RW_WBCL
, bc
- i
); /* adj bc */
1725 rq_rw_end (cp
, uptr
, 0, ST_CMP
); /* done */
1726 return SCPE_OK
; /* exit */
1730 } /* end else read */
1731 if (err
!= 0) { /* error? */
1732 if (rq_dte (cp
, uptr
, ST_DRV
)) /* post err log */
1733 rq_rw_end (cp
, uptr
, EF_LOG
, ST_DRV
); /* if ok, report err */
1734 perror ("RQ I/O error");
1735 clearerr (uptr
->fileref
);
1738 ba
= ba
+ tbc
; /* incr bus addr */
1739 bc
= bc
- tbc
; /* decr byte cnt */
1740 bl
= bl
+ ((tbc
+ (RQ_NUMBY
- 1)) / RQ_NUMBY
); /* incr blk # */
1741 PUTP32 (pkt
, RW_WBAL
, ba
); /* update pkt */
1742 PUTP32 (pkt
, RW_WBCL
, bc
);
1743 PUTP32 (pkt
, RW_WBLL
, bl
);
1744 if (bc
) sim_activate (uptr
, rq_xtime
); /* more? resched */
1745 else rq_rw_end (cp
, uptr
, 0, ST_SUC
); /* done! */
1749 /* Transfer command complete */
1751 t_bool
rq_rw_end (MSC
*cp
, UNIT
*uptr
, uint32 flg
, uint32 sts
)
1753 int32 pkt
= uptr
->cpkt
; /* packet */
1754 uint32 cmd
= GETP (pkt
, CMD_OPC
, OPC
); /* get cmd */
1755 uint32 bc
= GETP32 (pkt
, RW_BCL
); /* init bc */
1756 uint32 wbc
= GETP32 (pkt
, RW_WBCL
); /* work bc */
1757 DEVICE
*dptr
= rq_devmap
[uptr
->cnum
];
1759 uptr
->cpkt
= 0; /* done */
1760 PUTP32 (pkt
, RW_BCL
, bc
- wbc
); /* bytes processed */
1761 cp
->pak
[pkt
].d
[RW_WBAL
] = 0; /* clear temps */
1762 cp
->pak
[pkt
].d
[RW_WBAH
] = 0;
1763 cp
->pak
[pkt
].d
[RW_WBCL
] = 0;
1764 cp
->pak
[pkt
].d
[RW_WBCH
] = 0;
1765 cp
->pak
[pkt
].d
[RW_WBLL
] = 0;
1766 cp
->pak
[pkt
].d
[RW_WBLH
] = 0;
1767 rq_putr (cp
, pkt
, cmd
| OP_END
, flg
, sts
, RW_LNT_D
, UQ_TYP_SEQ
); /* fill pkt */
1768 if (!rq_putpkt (cp
, pkt
, TRUE
)) return ERR
; /* send pkt */
1769 if (uptr
->pktq
) /* more to do? */
1770 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_qtime
); /* activate thread */
1774 /* Data transfer error log packet */
1776 t_bool
rq_dte (MSC
*cp
, UNIT
*uptr
, uint32 err
)
1779 uint32 lu
, dtyp
, lbn
, ccyl
, csurf
, csect
, t
;
1781 if ((cp
->cflgs
& CF_THS
) == 0) return OK
; /* logging? */
1782 if (!rq_deqf (cp
, &pkt
)) return ERR
; /* get log pkt */
1783 tpkt
= uptr
->cpkt
; /* rw pkt */
1784 lu
= cp
->pak
[tpkt
].d
[CMD_UN
]; /* unit # */
1785 lbn
= GETP32 (tpkt
, RW_WBLL
); /* recent LBN */
1786 dtyp
= GET_DTYPE (uptr
->flags
); /* drv type */
1787 if (drv_tab
[dtyp
].flgs
& RQDF_SDI
) t
= 0; /* SDI? ovhd @ end */
1788 else t
= (drv_tab
[dtyp
].xbn
+ drv_tab
[dtyp
].dbn
) / /* ovhd cylinders */
1789 (drv_tab
[dtyp
].sect
* drv_tab
[dtyp
].surf
);
1790 ccyl
= t
+ (lbn
/ drv_tab
[dtyp
].cyl
); /* curr real cyl */
1791 t
= lbn
% drv_tab
[dtyp
].cyl
; /* trk relative blk */
1792 csurf
= t
/ drv_tab
[dtyp
].surf
; /* curr surf */
1793 csect
= t
% drv_tab
[dtyp
].surf
; /* curr sect */
1795 cp
->pak
[pkt
].d
[ELP_REFL
] = cp
->pak
[tpkt
].d
[CMD_REFL
]; /* copy cmd ref */
1796 cp
->pak
[pkt
].d
[ELP_REFH
] = cp
->pak
[tpkt
].d
[CMD_REFH
];
1797 cp
->pak
[pkt
].d
[ELP_UN
] = lu
; /* copy unit */
1798 cp
->pak
[pkt
].d
[ELP_SEQ
] = 0; /* clr seq # */
1799 cp
->pak
[pkt
].d
[DTE_CIDA
] = 0; /* ctrl ID */
1800 cp
->pak
[pkt
].d
[DTE_CIDB
] = 0;
1801 cp
->pak
[pkt
].d
[DTE_CIDC
] = 0;
1802 cp
->pak
[pkt
].d
[DTE_CIDD
] = (RQ_CLASS
<< DTE_CIDD_V_CLS
) |
1803 (RQ_MODEL
<< DTE_CIDD_V_MOD
);
1804 cp
->pak
[pkt
].d
[DTE_VER
] = (RQ_HVER
<< DTE_VER_V_HVER
) |
1805 (RQ_SVER
<< DTE_VER_V_SVER
);
1806 cp
->pak
[pkt
].d
[DTE_MLUN
] = lu
; /* MLUN */
1807 cp
->pak
[pkt
].d
[DTE_UIDA
] = lu
; /* unit ID */
1808 cp
->pak
[pkt
].d
[DTE_UIDB
] = 0;
1809 cp
->pak
[pkt
].d
[DTE_UIDC
] = 0;
1810 cp
->pak
[pkt
].d
[DTE_UIDD
] = (UID_DISK
<< DTE_UIDD_V_CLS
) |
1811 (drv_tab
[dtyp
].mod
<< DTE_UIDD_V_MOD
);
1812 cp
->pak
[pkt
].d
[DTE_UVER
] = 0; /* unit versn */
1813 cp
->pak
[pkt
].d
[DTE_SCYL
] = ccyl
; /* cylinder */
1814 cp
->pak
[pkt
].d
[DTE_VSNL
] = 01234 + lu
; /* vol ser # */
1815 cp
->pak
[pkt
].d
[DTE_VSNH
] = 0;
1816 cp
->pak
[pkt
].d
[DTE_D1
] = 0;
1817 cp
->pak
[pkt
].d
[DTE_D2
] = csect
<< DTE_D2_V_SECT
; /* geometry */
1818 cp
->pak
[pkt
].d
[DTE_D3
] = (ccyl
<< DTE_D3_V_CYL
) |
1819 (csurf
<< DTE_D3_V_SURF
);
1820 rq_putr (cp
, pkt
, FM_SDE
, LF_SNR
, err
, DTE_LNT
, UQ_TYP_DAT
);
1821 return rq_putpkt (cp
, pkt
, TRUE
);
1824 /* Host bus error log packet */
1826 t_bool
rq_hbe (MSC
*cp
, UNIT
*uptr
)
1830 if ((cp
->cflgs
& CF_THS
) == 0) return OK
; /* logging? */
1831 if (!rq_deqf (cp
, &pkt
)) return ERR
; /* get log pkt */
1832 tpkt
= uptr
->cpkt
; /* rw pkt */
1833 cp
->pak
[pkt
].d
[ELP_REFL
] = cp
->pak
[tpkt
].d
[CMD_REFL
]; /* copy cmd ref */
1834 cp
->pak
[pkt
].d
[ELP_REFH
] = cp
->pak
[tpkt
].d
[CMD_REFH
];
1835 cp
->pak
[pkt
].d
[ELP_UN
] = cp
->pak
[tpkt
].d
[CMD_UN
]; /* copy unit */
1836 cp
->pak
[pkt
].d
[ELP_SEQ
] = 0; /* clr seq # */
1837 cp
->pak
[pkt
].d
[HBE_CIDA
] = 0; /* ctrl ID */
1838 cp
->pak
[pkt
].d
[HBE_CIDB
] = 0;
1839 cp
->pak
[pkt
].d
[HBE_CIDC
] = 0;
1840 cp
->pak
[pkt
].d
[HBE_CIDD
] = (RQ_CLASS
<< DTE_CIDD_V_CLS
) |
1841 (RQ_MODEL
<< DTE_CIDD_V_MOD
);
1842 cp
->pak
[pkt
].d
[HBE_VER
] = (RQ_HVER
<< HBE_VER_V_HVER
) | /* versions */
1843 (RQ_SVER
<< HBE_VER_V_SVER
);
1844 cp
->pak
[pkt
].d
[HBE_RSV
] = 0;
1845 cp
->pak
[pkt
].d
[HBE_BADL
] = cp
->pak
[tpkt
].d
[RW_WBAL
]; /* bad addr */
1846 cp
->pak
[pkt
].d
[HBE_BADH
] = cp
->pak
[tpkt
].d
[RW_WBAH
];
1847 rq_putr (cp
, pkt
, FM_BAD
, LF_SNR
, ST_HST
| SB_HST_NXM
, HBE_LNT
, UQ_TYP_DAT
);
1848 return rq_putpkt (cp
, pkt
, TRUE
);
1851 /* Port last failure error log packet */
1853 t_bool
rq_plf (MSC
*cp
, uint32 err
)
1857 if (!rq_deqf (cp
, &pkt
)) return ERR
; /* get log pkt */
1858 cp
->pak
[pkt
].d
[ELP_REFL
] = 0; /* ref = 0 */
1859 cp
->pak
[pkt
].d
[ELP_REFH
] = 0;
1860 cp
->pak
[pkt
].d
[ELP_UN
] = 0; /* no unit */
1861 cp
->pak
[pkt
].d
[ELP_SEQ
] = 0; /* no seq */
1862 cp
->pak
[pkt
].d
[PLF_CIDA
] = 0; /* cntl ID */
1863 cp
->pak
[pkt
].d
[PLF_CIDB
] = 0;
1864 cp
->pak
[pkt
].d
[PLF_CIDC
] = 0;
1865 cp
->pak
[pkt
].d
[PLF_CIDD
] = (RQ_CLASS
<< PLF_CIDD_V_CLS
) |
1866 (RQ_MODEL
<< PLF_CIDD_V_MOD
);
1867 cp
->pak
[pkt
].d
[PLF_VER
] = (RQ_SVER
<< PLF_VER_V_SVER
) |
1868 (RQ_HVER
<< PLF_VER_V_HVER
);
1869 cp
->pak
[pkt
].d
[PLF_ERR
] = err
;
1870 rq_putr (cp
, pkt
, FM_CNT
, LF_SNR
, ST_CNT
, PLF_LNT
, UQ_TYP_DAT
);
1871 cp
->pak
[pkt
].d
[UQ_HCTC
] |= (UQ_CID_DIAG
<< UQ_HCTC_V_CID
);
1872 return rq_putpkt (cp
, pkt
, TRUE
);
1875 /* Unit now available attention packet */
1877 int32
rq_una (MSC
*cp
, int32 un
)
1880 uint32 lu
= cp
->ubase
+ un
;
1881 UNIT
*uptr
= rq_getucb (cp
, lu
);
1883 if (uptr
== NULL
) return OK
; /* huh? */
1884 if (!rq_deqf (cp
, &pkt
)) return ERR
; /* get log pkt */
1885 cp
->pak
[pkt
].d
[RSP_REFL
] = 0; /* ref = 0 */
1886 cp
->pak
[pkt
].d
[RSP_REFH
] = 0;
1887 cp
->pak
[pkt
].d
[RSP_UN
] = lu
;
1888 cp
->pak
[pkt
].d
[RSP_RSV
] = 0;
1889 rq_putr_unit (cp
, pkt
, uptr
, lu
, FALSE
); /* fill unit fields */
1890 rq_putr (cp
, pkt
, OP_AVA
, 0, 0, UNA_LNT
, UQ_TYP_SEQ
); /* fill std fields */
1891 return rq_putpkt (cp
, pkt
, TRUE
);
1896 rq_deqf - dequeue head of free list (fatal err if none)
1897 rq_deqh - dequeue head of list
1898 rq_enqh - enqueue at head of list
1899 rq_enqt - enqueue at tail of list
1902 t_bool
rq_deqf (MSC
*cp
, int32
*pkt
)
1904 if (cp
->freq
== 0) return rq_fatal (cp
, PE_NSR
); /* no free pkts?? */
1905 cp
->pbsy
= cp
->pbsy
+ 1; /* cnt busy pkts */
1906 *pkt
= cp
->freq
; /* head of list */
1907 cp
->freq
= cp
->pak
[cp
->freq
].link
; /* next */
1911 int32
rq_deqh (MSC
*cp
, int32
*lh
)
1913 int32 ptr
= *lh
; /* head of list */
1915 if (ptr
) *lh
= cp
->pak
[ptr
].link
; /* next */
1919 void rq_enqh (MSC
*cp
, int32
*lh
, int32 pkt
)
1921 if (pkt
== 0) return; /* any pkt? */
1922 cp
->pak
[pkt
].link
= *lh
; /* link is old lh */
1923 *lh
= pkt
; /* pkt is new lh */
1927 void rq_enqt (MSC
*cp
, int32
*lh
, int32 pkt
)
1929 if (pkt
== 0) return; /* any pkt? */
1930 cp
->pak
[pkt
].link
= 0; /* it will be tail */
1931 if (*lh
== 0) *lh
= pkt
; /* if empty, enqh */
1933 uint32 ptr
= *lh
; /* chase to end */
1934 while (cp
->pak
[ptr
].link
) ptr
= cp
->pak
[ptr
].link
;
1935 cp
->pak
[ptr
].link
= pkt
; /* enq at tail */
1940 /* Packet and descriptor handling */
1942 /* Get packet from command ring */
1944 t_bool
rq_getpkt (MSC
*cp
, int32
*pkt
)
1948 if (!rq_getdesc (cp
, &cp
->cq
, &desc
)) return ERR
; /* get cmd desc */
1949 if ((desc
& UQ_DESC_OWN
) == 0) { /* none */
1950 *pkt
= 0; /* pkt = 0 */
1951 return OK
; /* no error */
1953 if (!rq_deqf (cp
, pkt
)) return ERR
; /* get cmd pkt */
1954 cp
->hat
= 0; /* dsbl hst timer */
1955 addr
= desc
& UQ_ADDR
; /* get Q22 addr */
1956 if (Map_ReadW (addr
+ UQ_HDR_OFF
, RQ_PKT_SIZE
, cp
->pak
[*pkt
].d
))
1957 return rq_fatal (cp
, PE_PRE
); /* read pkt */
1958 return rq_putdesc (cp
, &cp
->cq
, desc
); /* release desc */
1961 /* Put packet to response ring - note the clever hack about credits.
1962 The controller sends all its credits to the host. Thereafter, it
1963 supplies one credit for every response packet sent over. Simple!
1966 t_bool
rq_putpkt (MSC
*cp
, int32 pkt
, t_bool qt
)
1968 uint32 addr
, desc
, lnt
, cr
;
1969 DEVICE
*dptr
= rq_devmap
[cp
->cnum
];
1971 if (pkt
== 0) return OK
; /* any packet? */
1972 if (DEBUG_PRD (dptr
)) fprintf (sim_deb
,
1973 ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp
->cnum
,
1974 cp
->pak
[pkt
].d
[RSP_OPF
], cp
->pak
[pkt
].d
[RSP_STS
]);
1975 if (!rq_getdesc (cp
, &cp
->rq
, &desc
)) return ERR
; /* get rsp desc */
1976 if ((desc
& UQ_DESC_OWN
) == 0) { /* not valid? */
1977 if (qt
) rq_enqt (cp
, &cp
->rspq
, pkt
); /* normal? q tail */
1978 else rq_enqh (cp
, &cp
->rspq
, pkt
); /* resp q call */
1979 sim_activate (dptr
->units
+ RQ_QUEUE
, rq_qtime
); /* activate q thrd */
1982 addr
= desc
& UQ_ADDR
; /* get Q22 addr */
1983 lnt
= cp
->pak
[pkt
].d
[UQ_HLNT
] - UQ_HDR_OFF
; /* size, with hdr */
1984 if ((GETP (pkt
, UQ_HCTC
, TYP
) == UQ_TYP_SEQ
) && /* seq packet? */
1985 (GETP (pkt
, CMD_OPC
, OPC
) & OP_END
)) { /* end packet? */
1986 cr
= (cp
->credits
>= 14)? 14: cp
->credits
; /* max 14 credits */
1987 cp
->credits
= cp
->credits
- cr
; /* decr credits */
1988 cp
->pak
[pkt
].d
[UQ_HCTC
] |= ((cr
+ 1) << UQ_HCTC_V_CR
);
1990 if (Map_WriteW (addr
+ UQ_HDR_OFF
, lnt
, cp
->pak
[pkt
].d
))
1991 return rq_fatal (cp
, PE_PWE
); /* write pkt */
1992 rq_enqh (cp
, &cp
->freq
, pkt
); /* pkt is free */
1993 cp
->pbsy
= cp
->pbsy
- 1; /* decr busy cnt */
1994 if (cp
->pbsy
== 0) cp
->hat
= cp
->htmo
; /* idle? strt hst tmr */
1995 return rq_putdesc (cp
, &cp
->rq
, desc
); /* release desc */
1998 /* Get a descriptor from the host */
2000 t_bool
rq_getdesc (MSC
*cp
, struct uq_ring
*ring
, uint32
*desc
)
2002 uint32 addr
= ring
->ba
+ ring
->idx
;
2005 if (Map_ReadW (addr
, 4, d
)) /* fetch desc */
2006 return rq_fatal (cp
, PE_QRE
); /* err? dead */
2007 *desc
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
2011 /* Return a descriptor to the host, clearing owner bit
2012 If rings transitions from "empty" to "not empty" or "full" to
2013 "not full", and interrupt bit was set, interrupt the host.
2014 Actually, test whether previous ring entry was owned by host.
2017 t_bool
rq_putdesc (MSC
*cp
, struct uq_ring
*ring
, uint32 desc
)
2019 uint32 prvd
, newd
= (desc
& ~UQ_DESC_OWN
) | UQ_DESC_F
;
2020 uint32 prva
, addr
= ring
->ba
+ ring
->idx
;
2023 d
[0] = newd
& 0xFFFF; /* 32b to 16b */
2024 d
[1] = (newd
>> 16) & 0xFFFF;
2025 if (Map_WriteW (addr
, 4, d
)) /* store desc */
2026 return rq_fatal (cp
, PE_QWE
); /* err? dead */
2027 if (desc
& UQ_DESC_F
) { /* was F set? */
2028 if (ring
->lnt
<= 4) rq_ring_int (cp
, ring
); /* lnt = 1? intr */
2029 else { /* prv desc */
2030 prva
= ring
->ba
+ ((ring
->idx
- 4) & (ring
->lnt
- 1));
2031 if (Map_ReadW (prva
, 4, d
)) /* read prv */
2032 return rq_fatal (cp
, PE_QRE
);
2033 prvd
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
2034 if (prvd
& UQ_DESC_OWN
) rq_ring_int (cp
, ring
);
2037 ring
->idx
= (ring
->idx
+ 4) & (ring
->lnt
- 1);
2041 /* Get unit descriptor for logical unit */
2043 UNIT
*rq_getucb (MSC
*cp
, uint32 lu
)
2045 DEVICE
*dptr
= rq_devmap
[cp
->cnum
];
2048 if ((lu
< cp
->ubase
) || (lu
>= (cp
->ubase
+ RQ_NUMDR
)))
2050 uptr
= dptr
->units
+ (lu
% RQ_NUMDR
);
2051 if (uptr
->flags
& UNIT_DIS
) return NULL
;
2055 /* Hack unit flags */
2057 void rq_setf_unit (MSC
*cp
, int32 pkt
, UNIT
*uptr
)
2059 uptr
->uf
= cp
->pak
[pkt
].d
[ONL_UFL
] & UF_MSK
; /* settable flags */
2060 if ((cp
->pak
[pkt
].d
[CMD_MOD
] & MD_SWP
) && /* swre wrp enb? */
2061 (cp
->pak
[pkt
].d
[ONL_UFL
] & UF_WPS
)) /* swre wrp on? */
2062 uptr
->uf
= uptr
->uf
| UF_WPS
; /* simon says... */
2066 /* Unit response fields */
2068 void rq_putr_unit (MSC
*cp
, int32 pkt
, UNIT
*uptr
, uint32 lu
, t_bool all
)
2070 uint32 dtyp
= GET_DTYPE (uptr
->flags
); /* get drive type */
2071 uint32 maxlbn
= (uint32
) (uptr
->capac
/ RQ_NUMBY
); /* get max lbn */
2073 cp
->pak
[pkt
].d
[ONL_MLUN
] = lu
; /* unit */
2074 cp
->pak
[pkt
].d
[ONL_UFL
] = uptr
->uf
| UF_RPL
| RQ_WPH (uptr
) | RQ_RMV (uptr
);
2075 cp
->pak
[pkt
].d
[ONL_RSVL
] = 0; /* reserved */
2076 cp
->pak
[pkt
].d
[ONL_RSVH
] = 0;
2077 cp
->pak
[pkt
].d
[ONL_UIDA
] = lu
; /* UID low */
2078 cp
->pak
[pkt
].d
[ONL_UIDB
] = 0;
2079 cp
->pak
[pkt
].d
[ONL_UIDC
] = 0;
2080 cp
->pak
[pkt
].d
[ONL_UIDD
] = (UID_DISK
<< ONL_UIDD_V_CLS
) |
2081 (drv_tab
[dtyp
].mod
<< ONL_UIDD_V_MOD
); /* UID hi */
2082 PUTP32 (pkt
, ONL_MEDL
, drv_tab
[dtyp
].med
); /* media type */
2083 if (all
) { /* if long form */
2084 PUTP32 (pkt
, ONL_SIZL
, maxlbn
); /* user LBNs */
2085 cp
->pak
[pkt
].d
[ONL_VSNL
] = 01234 + lu
; /* vol serial # */
2086 cp
->pak
[pkt
].d
[ONL_VSNH
] = 0;
2091 /* UQ_HDR and RSP_OP fields */
2093 void rq_putr (MSC
*cp
, int32 pkt
, uint32 cmd
, uint32 flg
,
2094 uint32 sts
, uint32 lnt
, uint32 typ
)
2096 cp
->pak
[pkt
].d
[RSP_OPF
] = (cmd
<< RSP_OPF_V_OPC
) | /* set cmd, flg */
2097 (flg
<< RSP_OPF_V_FLG
);
2098 cp
->pak
[pkt
].d
[RSP_STS
] = sts
;
2099 cp
->pak
[pkt
].d
[UQ_HLNT
] = lnt
; /* length */
2100 cp
->pak
[pkt
].d
[UQ_HCTC
] = (typ
<< UQ_HCTC_V_TYP
) | /* type, cid */
2101 (UQ_CID_MSCP
<< UQ_HCTC_V_CID
); /* clr credits */
2105 /* Post interrupt during init */
2107 void rq_init_int (MSC
*cp
)
2109 if ((cp
->s1dat
& SA_S1H_IE
) && /* int enab & */
2110 (cp
->s1dat
& SA_S1H_VEC
)) rq_setint (cp
); /* ved set? int */
2114 /* Post interrupt during putpkt - note that NXMs are ignored! */
2116 void rq_ring_int (MSC
*cp
, struct uq_ring
*ring
)
2118 uint32 iadr
= cp
->comm
+ ring
->ioff
; /* addr intr wd */
2121 Map_WriteW (iadr
, 2, &flag
); /* write flag */
2122 if (cp
->s1dat
& SA_S1H_VEC
) rq_setint (cp
); /* if enb, intr */
2126 /* Set RQ interrupt */
2128 void rq_setint (MSC
*cp
)
2130 cp
->irq
= 1; /* set ctrl int */
2131 SET_INT (RQ
); /* set master int */
2135 /* Clear RQ interrupt */
2137 void rq_clrint (MSC
*cp
)
2142 cp
->irq
= 0; /* clr ctrl int */
2143 for (i
= 0; i
< RQ_NUMCT
; i
++) { /* loop thru ctrls */
2144 ncp
= rq_ctxmap
[i
]; /* get context */
2145 if (ncp
->irq
) { /* other interrupt? */
2146 SET_INT (RQ
); /* yes, set master */
2150 CLR_INT (RQ
); /* no, clr master */
2154 /* Return interrupt vector */
2156 int32
rq_inta (void)
2163 for (i
= 0; i
< RQ_NUMCT
; i
++) { /* loop thru ctrl */
2164 ncp
= rq_ctxmap
[i
]; /* get context */
2165 if (ncp
->irq
) { /* ctrl int set? */
2166 dptr
= rq_devmap
[i
]; /* get device */
2167 dibp
= (DIB
*) dptr
->ctxt
; /* get DIB */
2168 rq_clrint (ncp
); /* clear int req */
2169 return dibp
->vec
; /* return vector */
2172 return 0; /* no intr req */
2177 t_bool
rq_fatal (MSC
*cp
, uint32 err
)
2179 DEVICE
*dptr
= rq_devmap
[cp
->cnum
];
2181 if (DEBUG_PRD (dptr
))
2182 fprintf (sim_deb
, ">>RQ%c: fatal err=%X\n", 'A' + cp
->cnum
, err
);
2183 rq_reset (rq_devmap
[cp
->cnum
]); /* reset device */
2184 cp
->sa
= SA_ER
| err
; /* SA = dead code */
2185 cp
->csta
= CST_DEAD
; /* state = dead */
2186 cp
->perr
= err
; /* save error */
2190 /* Set/clear hardware write lock */
2192 t_stat
rq_set_wlk (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2194 uint32 dtyp
= GET_DTYPE (uptr
->flags
); /* get drive type */
2196 if (drv_tab
[dtyp
].flgs
& RQDF_RO
) return SCPE_NOFNC
; /* not on read only */
2200 /* Show write lock status */
2202 t_stat
rq_show_wlk (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2204 uint32 dtyp
= GET_DTYPE (uptr
->flags
); /* get drive type */
2206 if (drv_tab
[dtyp
].flgs
& RQDF_RO
) fprintf (st
, "read only");
2207 else if (uptr
->flags
& UNIT_WPRT
) fprintf (st
, "write locked");
2208 else fprintf (st
, "write enabled");
2212 /* Set unit type (and capacity if user defined) */
2214 t_stat
rq_set_type (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
2217 uint32 max
= sim_taddr_64
? RA8U_EMAXC
: RA8U_MAXC
;
2220 if ((val
< 0) || ((val
!= RA8U_DTYPE
) && cptr
))
2222 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
2224 cap
= (uint32
) get_uint (cptr
, 10, 0xFFFFFFFF, &r
);
2225 if ((sim_switches
& SWMASK ('L')) == 0) cap
= cap
* 1954;
2226 if ((r
!= SCPE_OK
) || (cap
< RA8U_MINC
) || (cap
>= max
)) return SCPE_ARG
;
2227 drv_tab
[val
].lbn
= cap
;
2229 uptr
->flags
= (uptr
->flags
& ~UNIT_DTYPE
) | (val
<< UNIT_V_DTYPE
);
2230 uptr
->capac
= ((t_addr
) drv_tab
[val
].lbn
) * RQ_NUMBY
;
2234 /* Show unit type */
2236 t_stat
rq_show_type (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2238 fprintf (st
, "%s", drv_tab
[GET_DTYPE (uptr
->flags
)].name
);
2244 t_stat
rq_attach (UNIT
*uptr
, char *cptr
)
2246 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
2249 r
= attach_unit (uptr
, cptr
);
2250 if (r
!= SCPE_OK
) return r
;
2251 if (cp
->csta
== CST_UP
) uptr
->flags
= uptr
->flags
| UNIT_ATP
;
2257 t_stat
rq_detach (UNIT
*uptr
)
2261 r
= detach_unit (uptr
); /* detach unit */
2262 if (r
!= SCPE_OK
) return r
;
2263 uptr
->flags
= uptr
->flags
& ~(UNIT_ONL
| UNIT_ATP
); /* clr onl, atn pend */
2264 uptr
->uf
= 0; /* clr unit flgs */
2270 t_stat
rq_reset (DEVICE
*dptr
)
2275 DIB
*dibp
= (DIB
*) dptr
->ctxt
;
2277 for (i
= 0, cidx
= -1; i
< RQ_NUMCT
; i
++) { /* find ctrl num */
2278 if (rq_devmap
[i
] == dptr
) cidx
= i
;
2280 if (cidx
< 0) return SCPE_IERR
; /* not found??? */
2281 cp
= rq_ctxmap
[cidx
]; /* get context */
2282 cp
->cnum
= cidx
; /* init index */
2284 #if defined (VM_VAX) /* VAX */
2285 cp
->ubase
= 0; /* unit base = 0 */
2287 cp
->ubase
= cidx
* RQ_NUMDR
; /* init unit base */
2290 cp
->csta
= CST_S1
; /* init stage 1 */
2291 cp
->s1dat
= 0; /* no S1 data */
2292 dibp
->vec
= 0; /* no vector */
2293 cp
->comm
= 0; /* no comm region */
2294 if (UNIBUS
) cp
->sa
= SA_S1
| SA_S1C_DI
| SA_S1C_MP
; /* Unibus? */
2295 else cp
->sa
= SA_S1
| SA_S1C_Q22
| SA_S1C_DI
| SA_S1C_MP
; /* init SA val */
2296 cp
->cflgs
= CF_RPL
; /* ctrl flgs off */
2297 cp
->htmo
= RQ_DHTMO
; /* default timeout */
2298 cp
->hat
= cp
->htmo
; /* default timer */
2299 cp
->cq
.ba
= cp
->cq
.lnt
= cp
->cq
.idx
= 0; /* clr cmd ring */
2300 cp
->rq
.ba
= cp
->rq
.lnt
= cp
->rq
.idx
= 0; /* clr rsp ring */
2301 cp
->credits
= (RQ_NPKTS
/ 2) - 1; /* init credits */
2302 cp
->freq
= 1; /* init free list */
2303 for (i
= 0; i
< RQ_NPKTS
; i
++) { /* all pkts free */
2304 if (i
) cp
->pak
[i
].link
= (i
+ 1) & RQ_M_NPKTS
;
2305 else cp
->pak
[i
].link
= 0;
2306 for (j
= 0; j
< RQ_PKT_SIZE_W
; j
++) cp
->pak
[i
].d
[j
] = 0;
2308 cp
->rspq
= 0; /* no q'd rsp pkts */
2309 cp
->pbsy
= 0; /* all pkts free */
2310 cp
->pip
= 0; /* not polling */
2311 rq_clrint (cp
); /* clr intr req */
2312 for (i
= 0; i
< (RQ_NUMDR
+ 2); i
++) { /* init units */
2313 uptr
= dptr
->units
+ i
;
2314 sim_cancel (uptr
); /* clr activity */
2315 uptr
->cnum
= cidx
; /* set ctrl index */
2316 uptr
->flags
= uptr
->flags
& ~(UNIT_ONL
| UNIT_ATP
);
2317 uptr
->uf
= 0; /* clr unit flags */
2318 uptr
->cpkt
= uptr
->pktq
= 0; /* clr pkt q's */
2320 if (rqxb
== NULL
) rqxb
= (uint16
*) calloc (RQ_MAXFR
>> 1, sizeof (uint16
));
2321 if (rqxb
== NULL
) return SCPE_MEM
;
2322 return auto_config (0, 0); /* run autoconfig */
2325 /* Device bootstrap */
2327 #if defined (VM_PDP11)
2329 #define BOOT_START 016000 /* start */
2330 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
2331 #define BOOT_UNIT (BOOT_START + 010) /* unit number */
2332 #define BOOT_CSR (BOOT_START + 014) /* CSR */
2333 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
2335 static const uint16 boot_rom
[] = {
2337 0042125, /* st: "UD" */
2339 /* Four step init process */
2341 0012706, 0016000, /* mov #st,sp */
2342 0012700, 0000000, /* mov #unit,r0 */
2343 0012701, 0172150, /* mov #172150, r1 ; ip addr */
2344 0012704, 0016162, /* mov #it, r4 */
2345 0012705, 0004000, /* mov #4000,r5 ; s1 mask */
2346 0010102, /* mov r1,r2 */
2347 0005022, /* clr (r2)+ ; init */
2348 0005712, /* 10$: tst (r2) ; err? */
2349 0100001, /* bpl 20$ */
2351 0030512, /* 20$: bit r5,(r2) ; step set? */
2352 0001773, /* beq 10$ ; wait */
2353 0012412, /* mov (r4)+,(r2) ; send next */
2354 0006305, /* asl r5 ; next mask */
2355 0100370, /* bpl 10$ ; s4 done? */
2357 /* Send ONL, READ commands */
2359 0105714, /* 30$: tstb (r4) ; end tbl? */
2360 0001434, /* beq done ; 0 = yes */
2361 0012702, 0007000, /* mov #rpkt-4,r2 ; clr pkts */
2362 0005022, /* 40$: clr (r2)+ */
2363 0020227, 0007204, /* cmp r2,#comm */
2364 0103774, /* blo 40$ */
2365 0112437, 0007100, /* movb (r4)+,cpkt-4 ; set lnt */
2366 0110037, 0007110, /* movb r0,cpkt+4 ; set unit */
2367 0112437, 0007114, /* movb (r4)+,cpkt+10 ; set op */
2368 0112437, 0007121, /* movb (r4)+,cpkt+15 ; set param */
2369 0012722, 0007004, /* mov #rpkt,(r2)+ ; rq desc */
2370 0010522, /* mov r5,(r2)+ ; rq own */
2371 0012722, 0007104, /* mov #ckpt,(r2)+ ; cq desc */
2372 0010512, /* mov r5,(r2) ; cq own */
2373 0024242, /* cmp -(r2),-(r2) ; back up */
2374 0005711, /* tst (r1) ; wake ctrl */
2375 0005712, /* 50$: tst (r2) ; rq own clr? */
2376 0100776, /* bmi 50$ ; wait */
2377 0005737, 0007016, /* tst rpkt+12 ; stat ok? */
2378 0001743, /* beq 30$ ; next cmd */
2381 /* Boot block read in, jump to 0 */
2383 0005011, /* done: clr (r1) ; for M+ */
2384 0005003, /* clr r3 */
2385 0012704, BOOT_START
+020, /* mov #st+020,r4 */
2386 0005005, /* clr r5 */
2387 0005007, /* clr pc */
2391 0100000, /* it: no ints, ring sz = 1 */
2392 0007204, /* .word comm */
2393 0000000, /* .word 0 */
2394 0000001, /* .word 1 */
2395 0004420, /* .byte 20,11 */
2396 0020000, /* .byte 0,40 */
2397 0001041, /* .byte 41,2 */
2401 t_stat
rq_boot (int32 unitno
, DEVICE
*dptr
)
2404 extern int32 saved_PC
;
2406 DIB
*dibp
= (DIB
*) dptr
->ctxt
;
2408 for (i
= 0; i
< BOOT_LEN
; i
++) M
[(BOOT_START
>> 1) + i
] = boot_rom
[i
];
2409 M
[BOOT_UNIT
>> 1] = unitno
& 3;
2410 M
[BOOT_CSR
>> 1] = dibp
->ba
& DMASK
;
2411 saved_PC
= BOOT_ENTRY
;
2417 t_stat
rq_boot (int32 unitno
, DEVICE
*dptr
)
2423 /* Special show commands */
2425 void rq_show_ring (FILE *st
, struct uq_ring
*rp
)
2430 #if defined (VM_PDP11)
2431 fprintf (st
, "ring, base = %o, index = %d, length = %d\n",
2432 rp
->ba
, rp
->idx
>> 2, rp
->lnt
>> 2);
2434 fprintf (st
, "ring, base = %x, index = %d, length = %d\n",
2435 rp
->ba
, rp
->idx
>> 2, rp
->lnt
>> 2);
2437 for (i
= 0; i
< (rp
->lnt
>> 2); i
++) {
2438 if (Map_ReadW (rp
->ba
+ (i
<< 2), 4, d
)) {
2439 fprintf (st
, " %3d: non-existent memory\n", i
);
2442 desc
= ((uint32
) d
[0]) | (((uint32
) d
[1]) << 16);
2443 #if defined (VM_PDP11)
2444 fprintf (st
, " %3d: %011o\n", i
, desc
);
2446 fprintf (st
, " %3d: %08x\n", i
, desc
);
2452 void rq_show_pkt (FILE *st
, MSC
*cp
, int32 pkt
)
2455 uint32 cr
= GETP (pkt
, UQ_HCTC
, CR
);
2456 uint32 typ
= GETP (pkt
, UQ_HCTC
, TYP
);
2457 uint32 cid
= GETP (pkt
, UQ_HCTC
, CID
);
2459 fprintf (st
, "packet %d, credits = %d, type = %d, cid = %d\n",
2461 for (i
= 0; i
< RQ_SH_MAX
; i
= i
+ RQ_SH_PPL
) {
2462 fprintf (st
, " %2d:", i
);
2463 for (j
= i
; j
< (i
+ RQ_SH_PPL
); j
++)
2464 #if defined (VM_PDP11)
2465 fprintf (st
, " %06o", cp
->pak
[pkt
].d
[j
]);
2467 fprintf (st
, " %04x", cp
->pak
[pkt
].d
[j
]);
2474 t_stat
rq_show_unitq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2476 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
2477 DEVICE
*dptr
= rq_devmap
[uptr
->cnum
];
2480 u
= (int32
) (uptr
- dptr
->units
);
2481 if (cp
->csta
!= CST_UP
) {
2482 fprintf (st
, "Controller is not initialized\n");
2485 if ((uptr
->flags
& UNIT_ONL
) == 0) {
2486 if (uptr
->flags
& UNIT_ATT
)
2487 fprintf (st
, "Unit %d is available\n", u
);
2488 else fprintf (st
, "Unit %d is offline\n", u
);
2492 fprintf (st
, "Unit %d current ", u
);
2493 rq_show_pkt (st
, cp
, uptr
->cpkt
);
2494 if (pkt
= uptr
->pktq
) {
2496 fprintf (st
, "Unit %d queued ", u
);
2497 rq_show_pkt (st
, cp
, pkt
);
2498 } while (pkt
= cp
->pak
[pkt
].link
);
2501 else fprintf (st
, "Unit %d queues are empty\n", u
);
2505 t_stat
rq_show_ctrl (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
2507 MSC
*cp
= rq_ctxmap
[uptr
->cnum
];
2508 DEVICE
*dptr
= rq_devmap
[uptr
->cnum
];
2511 if (cp
->csta
!= CST_UP
) {
2512 fprintf (st
, "Controller is not initialized\n");
2515 if (val
& RQ_SH_RI
) {
2516 if (cp
->pip
) fprintf (st
, "Polling in progress, host timer = %d\n", cp
->hat
);
2517 else fprintf (st
, "Host timer = %d\n", cp
->hat
);
2518 fprintf (st
, "Command ");
2519 rq_show_ring (st
, &cp
->cq
);
2520 fprintf (st
, "Response ");
2521 rq_show_ring (st
, &cp
->rq
);
2523 if (val
& RQ_SH_FR
) {
2524 if (pkt
= cp
->freq
) {
2525 for (i
= 0; pkt
!= 0; i
++, pkt
= cp
->pak
[pkt
].link
) {
2526 if (i
== 0) fprintf (st
, "Free queue = %d", pkt
);
2527 else if ((i
% 16) == 0) fprintf (st
, ",\n %d", pkt
);
2528 else fprintf (st
, ", %d", pkt
);
2532 else fprintf (st
, "Free queue is empty\n");
2534 if (val
& RQ_SH_RS
) {
2535 if (pkt
= cp
->rspq
) {
2537 fprintf (st
, "Response ");
2538 rq_show_pkt (st
, cp
, pkt
);
2539 } while (pkt
= cp
->pak
[pkt
].link
);
2541 else fprintf (st
, "Response queue is empty\n");
2543 if (val
& RQ_SH_UN
) {
2544 for (i
= 0; i
< RQ_NUMDR
; i
++)
2545 rq_show_unitq (st
, dptr
->units
+ i
, 0, desc
);