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