First Commit of my working state
[simh.git] / PDP11 / pdp11_tq.c
CommitLineData
196ba1fc
PH
1/* pdp11_tq.c: TMSCP tape controller simulator\r
2\r
3 Copyright (c) 2002-2007, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 tq TQK50 tape controller\r
27\r
28 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread\r
29 16-Feb-06 RMS Revised for new magtape capacity checking\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 30-Sep-04 RMS Revised Unibus interface\r
34 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley)\r
35 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath)\r
36 26-Mar-04 RMS Fixed warnings with -std=c99\r
37 25-Jan-04 RMS Revised for device debug support\r
38 19-May-03 RMS Revised for new conditional compilation scheme\r
39 25-Apr-03 RMS Revised for extended file support\r
40 28-Mar-03 RMS Added multiformat support\r
41 28-Feb-03 RMS Added variable controller, user-defined drive support\r
42 26-Feb-03 RMS Fixed bug in vector calculation for VAXen\r
43 22-Feb-03 RMS Fixed ordering bug in queue process\r
44 Fixed flags table to allow MD_CSE everywhere\r
45 09-Jan-03 RMS Fixed bug in transfer end packet status\r
46 17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal)\r
47*/\r
48\r
49#if defined (VM_PDP10) /* PDP10 version */\r
50#error "TQK50 not supported on PDP-10!"\r
51\r
52#elif defined (VM_VAX) /* VAX version */\r
53#include "vax_defs.h"\r
54#if (UNIBUS)\r
55#define INIT_TYPE TQ8_TYPE\r
56#define INIT_CAP TQ8_CAP\r
57#else\r
58#define INIT_TYPE TQ5_TYPE\r
59#define INIT_CAP TQ5_CAP\r
60#endif\r
61\r
62#else /* PDP-11 version */\r
63#include "pdp11_defs.h"\r
64#define INIT_TYPE TQ5_TYPE\r
65#define INIT_CAP TQ5_CAP\r
66extern int32 cpu_opt;\r
67#endif\r
68\r
69#include "pdp11_uqssp.h"\r
70#include "pdp11_mscp.h"\r
71#include "sim_tape.h"\r
72\r
73#define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */\r
74\r
75#define TQ_SH_MAX 24 /* max display wds */\r
76#define TQ_SH_PPL 8 /* wds per line */\r
77#define TQ_SH_DPL 4 /* desc per line */\r
78#define TQ_SH_RI 001 /* show rings */\r
79#define TQ_SH_FR 002 /* show free q */\r
80#define TQ_SH_RS 004 /* show resp q */\r
81#define TQ_SH_UN 010 /* show unit q's */\r
82#define TQ_SH_ALL 017 /* show all */\r
83\r
84#define TQ_CLASS 1 /* TQK50 class */\r
85#define TQ_DHTMO 0 /* def host timeout */\r
86#define TQ_DCTMO 120 /* def ctrl timeout */\r
87#define TQ_NUMDR 4 /* # drives */\r
88#define TQ_MAXFR (1 << 16) /* max xfer */\r
89\r
90#define UNIT_V_ONL (MTUF_V_UF + 0) /* online */\r
91#define UNIT_V_ATP (MTUF_V_UF + 1) /* attn pending */\r
92#define UNIT_V_SXC (MTUF_V_UF + 2) /* serious exc */\r
93#define UNIT_V_POL (MTUF_V_UF + 3) /* position lost */\r
94#define UNIT_V_TMK (MTUF_V_UF + 4) /* tape mark seen */\r
95#define UNIT_ONL (1 << UNIT_V_ONL)\r
96#define UNIT_ATP (1 << UNIT_V_ATP)\r
97#define UNIT_SXC (1 << UNIT_V_SXC)\r
98#define UNIT_POL (1 << UNIT_V_POL)\r
99#define UNIT_TMK (1 << UNIT_V_TMK)\r
100#define cpkt u3 /* current packet */\r
101#define pktq u4 /* packet queue */\r
102#define uf buf /* settable unit flags */\r
103#define objp wait /* object position */\r
104#define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0)\r
105\r
106#define CST_S1 0 /* init stage 1 */\r
107#define CST_S1_WR 1 /* stage 1 wrap */\r
108#define CST_S2 2 /* init stage 2 */\r
109#define CST_S3 3 /* init stage 3 */\r
110#define CST_S3_PPA 4 /* stage 3 sa wait */\r
111#define CST_S3_PPB 5 /* stage 3 ip wait */\r
112#define CST_S4 6 /* stage 4 */\r
113#define CST_UP 7 /* online */\r
114#define CST_DEAD 8 /* fatal error */\r
115\r
116#define tq_comm tq_rq.ba\r
117\r
118#define ERR 0 /* must be SCPE_OK! */\r
119#define OK 1\r
120\r
121#define CMF_IMM 0x10000 /* immediate */\r
122#define CMF_SEQ 0x20000 /* sequential */\r
123#define CMF_WR 0x40000 /* write */\r
124#define CMF_RW 0x80000 /* resp to GCS */\r
125\r
126/* Internal packet management */\r
127\r
128#define TQ_NPKTS 32 /* # packets (pwr of 2) */\r
129#define TQ_M_NPKTS (TQ_NPKTS - 1) /* mask */\r
130#define TQ_PKT_SIZE_W 32 /* payload size (wds) */\r
131#define TQ_PKT_SIZE (TQ_PKT_SIZE_W * sizeof (int16))\r
132\r
133struct tqpkt {\r
134 int16 link; /* link to next */\r
135 uint16 d[TQ_PKT_SIZE_W]; /* data */\r
136 };\r
137\r
138/* Packet payload extraction and insertion */\r
139\r
140#define GETP(p,w,f) ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f)\r
141#define GETP32(p,w) (((uint32) tq_pkt[p].d[w]) | \\r
142 (((uint32) tq_pkt[p].d[(w)+1]) << 16))\r
143#define PUTP32(p,w,x) tq_pkt[p].d[w] = (x) & 0xFFFF; \\r
144 tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF\r
145\r
146/* Controller and device types - TQK50 must be swre rev 5 or later */\r
147\r
148#define TQ5_TYPE 0 /* TK50 */\r
149#define TQ5_UQPM 3 /* UQ port ID */\r
150#define TQ5_CMOD 9 /* ctrl ID */\r
151#define TQ5_UMOD 3 /* unit ID */\r
152#define TQ5_MED 0x6D68B032 /* media ID */\r
153#define TQ5_CREV ((1 << 8) | 5) /* ctrl revs */ \r
154#define TQ5_FREV 0 /* formatter revs */\r
155#define TQ5_UREV 0 /* unit revs */\r
156#define TQ5_CAP (94 * (1 << 20)) /* capacity */\r
157#define TQ5_FMT (TF_CTP|TF_CTP_LO) /* menu */\r
158\r
159#define TQ7_TYPE 1 /* TK70 */\r
160#define TQ7_UQPM 14 /* UQ port ID */\r
161#define TQ7_CMOD 14 /* ctrl ID */\r
162#define TQ7_UMOD 14 /* unit ID */\r
163#define TQ7_MED 0x6D68B046 /* media ID */\r
164#define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */ \r
165#define TQ7_FREV 0 /* formatter revs */\r
166#define TQ7_UREV 0 /* unit revs */\r
167#define TQ7_CAP (300 * (1 << 20)) /* capacity */\r
168#define TQ7_FMT (TF_CTP|TF_CTP_LO) /* menu */\r
169\r
170#define TQ8_TYPE 2 /* TU81 */\r
171#define TQ8_UQPM 5 /* UQ port ID */\r
172#define TQ8_CMOD 5 /* ctrl ID */\r
173#define TQ8_UMOD 2 /* unit ID */\r
174#define TQ8_MED 0x6D695051 /* media ID */\r
175#define TQ8_CREV ((1 << 8) | 5) /* ctrl revs */ \r
176#define TQ8_FREV 0 /* formatter revs */\r
177#define TQ8_UREV 0 /* unit revs */\r
178#define TQ8_CAP (180 * (1 << 20)) /* capacity */\r
179#define TQ8_FMT (TF_9TK|TF_9TK_GRP) /* menu */\r
180\r
181#define TQU_TYPE 3 /* TKuser defined */\r
182#define TQU_UQPM 3 /* UQ port ID */\r
183#define TQU_CMOD 9 /* ctrl ID */\r
184#define TQU_UMOD 3 /* unit ID */\r
185#define TQU_MED 0x6D68B032 /* media ID */\r
186#define TQU_CREV ((1 << 8) | 5) /* ctrl revs */ \r
187#define TQU_FREV 0 /* formatter revs */\r
188#define TQU_UREV 0 /* unit revs */\r
189#define TQU_CAP (94 * (1 << 20)) /* capacity */\r
190#define TQU_FMT (TF_CTP|TF_CTP_LO) /* menu */\r
191#define TQU_MINC 30 /* min cap MB */\r
192#define TQU_MAXC 2000 /* max cap MB */\r
193#define TQU_EMAXC 2000000000 /* ext max cap MB */\r
194\r
195#define TQ_DRV(d) \\r
196 d##_UQPM, \\r
197 d##_CMOD, d##_MED, d##_FMT, d##_CAP, \\r
198 d##_UMOD, d##_CREV, d##_FREV, d##_UREV\r
199\r
200#define TEST_EOT(u) (sim_tape_eot (u))\r
201\r
202struct drvtyp {\r
203 uint32 uqpm; /* UQ port model */\r
204 uint32 cmod; /* ctrl model */\r
205 uint32 med; /* MSCP media */\r
206 uint32 fmt; /* flags */\r
207 t_addr cap; /* capacity */\r
208 uint32 umod; /* unit model */\r
209 uint32 cver;\r
210 uint32 fver;\r
211 uint32 uver;\r
212 char *name;\r
213 };\r
214\r
215static struct drvtyp drv_tab[] = {\r
216 { TQ_DRV (TQ5), "TK50" },\r
217 { TQ_DRV (TQ7), "TK70" },\r
218 { TQ_DRV (TQ8), "TU81" },\r
219 { TQ_DRV (TQU), "TKUSER" },\r
220 };\r
221\r
222/* Data */\r
223\r
224extern int32 int_req[IPL_HLVL];\r
225extern int32 tmr_poll, clk_tps;\r
226extern UNIT cpu_unit;\r
227extern FILE *sim_deb;\r
228extern uint32 sim_taddr_64;\r
229\r
230uint8 *tqxb = NULL; /* xfer buffer */\r
231uint32 tq_sa = 0; /* status, addr */\r
232uint32 tq_saw = 0; /* written data */\r
233uint32 tq_s1dat = 0; /* S1 data */\r
234uint32 tq_csta = 0; /* ctrl state */\r
235uint32 tq_perr = 0; /* last error */\r
236uint32 tq_cflgs = 0; /* ctrl flags */\r
237uint32 tq_prgi = 0; /* purge int */\r
238uint32 tq_pip = 0; /* poll in progress */\r
239struct uq_ring tq_cq = { 0 }; /* cmd ring */\r
240struct uq_ring tq_rq = { 0 }; /* rsp ring */\r
241struct tqpkt tq_pkt[TQ_NPKTS]; /* packet queue */\r
242int32 tq_freq = 0; /* free list */\r
243int32 tq_rspq = 0; /* resp list */\r
244uint32 tq_pbsy = 0; /* #busy pkts */\r
245uint32 tq_credits = 0; /* credits */\r
246uint32 tq_hat = 0; /* host timer */\r
247uint32 tq_htmo = TQ_DHTMO; /* host timeout */\r
248int32 tq_itime = 200; /* init time, except */\r
249int32 tq_itime4 = 10; /* stage 4 */\r
250int32 tq_qtime = 200; /* queue time */\r
251int32 tq_xtime = 500; /* transfer time */\r
252int32 tq_typ = INIT_TYPE; /* device type */\r
253\r
254/* Command table - legal modifiers (low 16b) and flags (high 16b) */\r
255\r
256static uint32 tq_cmf[64] = {\r
257 0, /* 0 */\r
258 CMF_IMM, /* abort */\r
259 CMF_IMM|MD_CSE, /* get cmd status */\r
260 CMF_IMM|MD_CSE|MD_NXU, /* get unit status */\r
261 CMF_IMM|MD_CSE, /* set ctrl char */\r
262 0, 0, 0, /* 5-7 */\r
263 CMF_SEQ|MD_ACL|MD_CDL|MD_CSE|MD_EXA|MD_UNL, /* available */\r
264 CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* online */\r
265 CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* set unit char */\r
266 CMF_IMM, /* define acc paths */\r
267 0, 0, 0, 0, /* 12-15 */\r
268 CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* access */\r
269 MD_SCH|MD_SEC|MD_SER,\r
270 0, /* 17 */\r
271 CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase */\r
272 CMF_SEQ|CMF_WR|MD_CDL|MD_CSE, /* flush */\r
273 0, 0, /* 20-21 */\r
274 CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase gap */\r
275 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22-31 */\r
276 CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* compare */\r
277 MD_SCH|MD_SEC|MD_SER,\r
278 CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|MD_CMP| /* read */\r
279 MD_SCH|MD_SEC|MD_SER,\r
280 CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */\r
281 MD_CMP|MD_ERW|MD_SEC|MD_SER,\r
282 0, /* 35 */\r
283 CMF_SEQ|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */\r
284 CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */\r
285 MD_REV|MD_RWD|MD_DLE|\r
286 MD_SCH|MD_SEC|MD_SER,\r
287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38-47 */\r
288 0, 0, 0, 0, 0, 0, 0, 0,\r
289 0, 0, 0, 0, 0, 0, 0, 0\r
290 }; \r
291\r
292/* Forward references */\r
293\r
294DEVICE tq_dev;\r
295\r
296t_stat tq_rd (int32 *data, int32 PA, int32 access);\r
297t_stat tq_wr (int32 data, int32 PA, int32 access);\r
298t_stat tq_inta (void);\r
299t_stat tq_svc (UNIT *uptr);\r
300t_stat tq_tmrsvc (UNIT *uptr);\r
301t_stat tq_quesvc (UNIT *uptr);\r
302t_stat tq_reset (DEVICE *dptr);\r
303t_stat tq_attach (UNIT *uptr, char *cptr);\r
304t_stat tq_detach (UNIT *uptr);\r
305t_stat tq_boot (int32 unitno, DEVICE *dptr);\r
306t_stat tq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc);\r
307t_stat tq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
308t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc);\r
309t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc);\r
310t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);\r
311t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);\r
312\r
313t_bool tq_step4 (void);\r
314t_bool tq_mscp (int32 pkt, t_bool q);\r
315t_bool tq_abo (int32 pkt);\r
316t_bool tq_avl (int32 pkt);\r
317t_bool tq_erase (int32 pkt);\r
318t_bool tq_flu (int32 pkt);\r
319t_bool tq_gcs (int32 pkt);\r
320t_bool tq_gus (int32 pkt);\r
321t_bool tq_onl (int32 pkt);\r
322t_bool tq_pos (int32 pkt);\r
323t_bool tq_rw (int32 pkt);\r
324t_bool tq_scc (int32 pkt);\r
325t_bool tq_suc (int32 pkt);\r
326t_bool tq_wtm (int32 pkt);\r
327t_bool tq_plf (uint32 err);\r
328t_bool tq_dte (UNIT *uptr, uint32 err);\r
329t_bool tq_hbe (UNIT *uptr, uint32 ba);\r
330t_bool tq_una (UNIT *uptr);\r
331uint32 tq_map_status (UNIT *uptr, t_stat st);\r
332uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);\r
333uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped);\r
334uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc);\r
335uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);\r
336uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped);\r
337uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc);\r
338t_bool tq_deqf (int32 *pkt);\r
339int32 tq_deqh (int32 *lh);\r
340void tq_enqh (int32 *lh, int32 pkt);\r
341void tq_enqt (int32 *lh, int32 pkt);\r
342t_bool tq_getpkt (int32 *pkt);\r
343t_bool tq_putpkt (int32 pkt, t_bool qt);\r
344t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc);\r
345t_bool tq_putdesc (struct uq_ring *ring, uint32 desc);\r
346int32 tq_mot_valid (UNIT *uptr, uint32 cmd);\r
347t_stat tq_mot_err (UNIT *uptr, uint32 rsiz);\r
348t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz);\r
349void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ);\r
350void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all);\r
351void tq_setf_unit (int32 pkt, UNIT *uptr);\r
352uint32 tq_efl (UNIT *uptr);\r
353void tq_init_int (void);\r
354void tq_ring_int (struct uq_ring *ring);\r
355t_bool tq_fatal (uint32 err);\r
356UNIT *tq_getucb (uint32 lu);\r
357\r
358/* TQ data structures\r
359\r
360 tq_dev TQ device descriptor\r
361 tq_unit TQ unit list\r
362 tq_reg TQ register list\r
363 tq_mod TQ modifier list\r
364*/\r
365\r
366DIB tq_dib = {\r
367 IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr,\r
368 1, IVCL (TQ), 0, { &tq_inta }\r
369 };\r
370\r
371UNIT tq_unit[] = {\r
372 { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r
373 { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r
374 { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r
375 { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r
376 { UDATA (&tq_tmrsvc, UNIT_DIS, 0) },\r
377 { UDATA (&tq_quesvc, UNIT_DIS, 0) }\r
378 };\r
379\r
380#define TQ_TIMER (TQ_NUMDR)\r
381#define TQ_QUEUE (TQ_TIMER + 1)\r
382\r
383REG tq_reg[] = {\r
384 { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) },\r
385 { GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) },\r
386 { GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) },\r
387 { GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) },\r
388 { GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ },\r
389 { GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) },\r
390 { GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) },\r
391 { GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ },\r
392 { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) },\r
393 { DRDATA (FREE, tq_freq, 5) },\r
394 { DRDATA (RESP, tq_rspq, 5) },\r
395 { DRDATA (PBSY, tq_pbsy, 5) },\r
396 { GRDATA (CFLGS, tq_cflgs, DEV_RDX, 16, 0) },\r
397 { GRDATA (CSTA, tq_csta, DEV_RDX, 4, 0) },\r
398 { GRDATA (PERR, tq_perr, DEV_RDX, 9, 0) },\r
399 { DRDATA (CRED, tq_credits, 5) },\r
400 { DRDATA (HAT, tq_hat, 17) },\r
401 { DRDATA (HTMO, tq_htmo, 17) },\r
402 { URDATA (CPKT, tq_unit[0].cpkt, 10, 5, 0, TQ_NUMDR, 0) },\r
403 { URDATA (PKTQ, tq_unit[0].pktq, 10, 5, 0, TQ_NUMDR, 0) },\r
404 { URDATA (UFLG, tq_unit[0].uf, DEV_RDX, 16, 0, TQ_NUMDR, 0) },\r
405 { URDATA (POS, tq_unit[0].pos, 10, T_ADDR_W, 0, TQ_NUMDR, 0) },\r
406 { URDATA (OBJP, tq_unit[0].objp, 10, 32, 0, TQ_NUMDR, 0) },\r
407 { FLDATA (PRGI, tq_prgi, 0), REG_HIDDEN },\r
408 { FLDATA (PIP, tq_pip, 0), REG_HIDDEN },\r
409 { FLDATA (INT, IREQ (TQ), INT_V_TQ) },\r
410 { DRDATA (ITIME, tq_itime, 24), PV_LEFT + REG_NZ },\r
411 { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ },\r
412 { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ },\r
413 { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ },\r
414 { BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) },\r
415 { DRDATA (DEVTYPE, tq_typ, 2), REG_HRO },\r
416 { DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO },\r
417 { GRDATA (DEVADDR, tq_dib.ba, DEV_RDX, 32, 0), REG_HRO },\r
418 { GRDATA (DEVVEC, tq_dib.vec, DEV_RDX, 16, 0), REG_HRO },\r
419 { NULL }\r
420 };\r
421\r
422MTAB tq_mod[] = {\r
423 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
424 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r
425 { MTAB_XTD | MTAB_VDV, TQ5_TYPE, NULL, "TK50",\r
426 &tq_set_type, NULL, NULL },\r
427 { MTAB_XTD | MTAB_VDV, TQ7_TYPE, NULL, "TK70",\r
428 &tq_set_type, NULL, NULL },\r
429 { MTAB_XTD | MTAB_VDV, TQ8_TYPE, NULL, "TU81",\r
430 &tq_set_type, NULL, NULL },\r
431 { MTAB_XTD | MTAB_VDV, TQU_TYPE, NULL, "TKUSER",\r
432 &tq_set_type, NULL, NULL },\r
433 { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,\r
434 NULL, &tq_show_type, NULL },\r
435 { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RI, "RINGS", NULL,\r
436 NULL, &tq_show_ctrl, NULL },\r
437 { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_FR, "FREEQ", NULL,\r
438 NULL, &tq_show_ctrl, NULL },\r
439 { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RS, "RESPQ", NULL,\r
440 NULL, &tq_show_ctrl, NULL },\r
441 { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_UN, "UNITQ", NULL,\r
442 NULL, &tq_show_ctrl, NULL },\r
443 { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_ALL, "ALL", NULL,\r
444 NULL, &tq_show_ctrl, NULL },\r
445 { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL,\r
446 NULL, &tq_show_unitq, NULL },\r
447 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r
448 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r
449#if defined (VM_PDP11)\r
450 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",\r
451 &set_addr, &show_addr, NULL },\r
452#else\r
453 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,\r
454 NULL, &show_addr, NULL },\r
455#endif\r
456 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,\r
457 NULL, &show_vec, NULL },\r
458 { 0 }\r
459 };\r
460\r
461DEVICE tq_dev = {\r
462 "TQ", tq_unit, tq_reg, tq_mod,\r
463 TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8,\r
464 NULL, NULL, &tq_reset,\r
465 &tq_boot, &tq_attach, &tq_detach,\r
466 &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG\r
467 };\r
468\r
469/* I/O dispatch routines, I/O addresses 17772150 - 17772152\r
470\r
471 17772150 IP read/write\r
472 17772152 SA read/write\r
473*/\r
474\r
475t_stat tq_rd (int32 *data, int32 PA, int32 access)\r
476{\r
477switch ((PA >> 1) & 01) { /* decode PA<1> */\r
478 case 0: /* IP */\r
479 *data = 0; /* reads zero */\r
480 if (tq_csta == CST_S3_PPB) tq_step4 (); /* waiting for poll? */\r
481 else if (tq_csta == CST_UP) { /* if up */\r
482 tq_pip = 1; /* poll host */\r
483 sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);\r
484 }\r
485 break;\r
486\r
487 case 1: /* SA */\r
488 *data = tq_sa;\r
489 break;\r
490 }\r
491\r
492return SCPE_OK;\r
493}\r
494\r
495t_stat tq_wr (int32 data, int32 PA, int32 access)\r
496{\r
497switch ((PA >> 1) & 01) { /* decode PA<1> */\r
498\r
499 case 0: /* IP */\r
500 tq_reset (&tq_dev); /* init device */\r
501 if (DEBUG_PRS (tq_dev)) fprintf (sim_deb,\r
502 ">>TQ: initialization started, time=%.0f\n", sim_gtime ());\r
503 break;\r
504\r
505 case 1: /* SA */\r
506 tq_saw = data;\r
507 if (tq_csta < CST_S4) /* stages 1-3 */\r
508 sim_activate (&tq_unit[TQ_QUEUE], tq_itime);\r
509 else if (tq_csta == CST_S4) /* stage 4 (fast) */\r
510 sim_activate (&tq_unit[TQ_QUEUE], tq_itime4);\r
511 break;\r
512 }\r
513\r
514return SCPE_OK;\r
515}\r
516\r
517/* Transition to step 4 - init communications region */\r
518\r
519t_bool tq_step4 (void)\r
520{\r
521int32 i, lnt;\r
522uint32 base;\r
523uint16 zero[SA_COMM_MAX >> 1];\r
524\r
525tq_rq.ioff = SA_COMM_RI; /* set intr offset */\r
526tq_rq.ba = tq_comm; /* set rsp q base */\r
527tq_rq.lnt = SA_S1H_RQ (tq_s1dat) << 2; /* get resp q len */\r
528tq_cq.ioff = SA_COMM_CI; /* set intr offset */\r
529tq_cq.ba = tq_comm + tq_rq.lnt; /* set cmd q base */\r
530tq_cq.lnt = SA_S1H_CQ (tq_s1dat) << 2; /* get cmd q len */\r
531tq_cq.idx = tq_rq.idx = 0; /* clear q idx's */\r
532if (tq_prgi) base = tq_comm + SA_COMM_QQ;\r
533else base = tq_comm + SA_COMM_CI;\r
534lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */\r
535if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */\r
536for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */\r
537if (Map_WriteW (base, lnt, zero)) /* zero comm area */\r
538 return tq_fatal (PE_QWE); /* error? */\r
539tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */\r
540 ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER);\r
541tq_csta = CST_S4; /* set step 4 */\r
542tq_init_int (); /* poke host */\r
543return OK;\r
544}\r
545\r
546/* Queue service - invoked when any of the queues (host queue, unit\r
547 queues, response queue) require servicing. Also invoked during\r
548 initialization to provide some delay to the next step.\r
549\r
550 Process at most one item off each unit queue\r
551 If the unit queues were empty, process at most one item off the host queue\r
552 Process at most one item off the response queue\r
553\r
554 If all queues are idle, terminate thread\r
555*/\r
556\r
557t_stat tq_quesvc (UNIT *uptr)\r
558{\r
559int32 i, cnid;\r
560int32 pkt = 0;\r
561UNIT *nuptr;\r
562\r
563if (tq_csta < CST_UP) { /* still init? */\r
564 switch (tq_csta) { /* controller state? */\r
565\r
566 case CST_S1: /* need S1 reply */\r
567 if (tq_saw & SA_S1H_VL) { /* valid? */\r
568 if (tq_saw & SA_S1H_WR) { /* wrap? */\r
569 tq_sa = tq_saw; /* echo data */\r
570 tq_csta = CST_S1_WR; /* endless loop */\r
571 }\r
572 else {\r
573 tq_s1dat = tq_saw; /* save data */\r
574 tq_dib.vec = (tq_s1dat & SA_S1H_VEC) << 2; /* get vector */\r
575 if (tq_dib.vec) tq_dib.vec = tq_dib.vec + VEC_Q; /* if nz, bias */\r
576 tq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (tq_s1dat);\r
577 tq_csta = CST_S2; /* now in step 2 */\r
578 tq_init_int (); /* intr if req */\r
579 }\r
580 } /* end if valid */\r
581 break;\r
582\r
583 case CST_S1_WR: /* wrap mode */\r
584 tq_sa = tq_saw; /* echo data */\r
585 break;\r
586\r
587 case CST_S2: /* need S2 reply */\r
588 tq_comm = tq_saw & SA_S2H_CLO; /* get low addr */\r
589 tq_prgi = tq_saw & SA_S2H_PI; /* get purge int */\r
590 tq_sa = SA_S3 | SA_S3C_EC (tq_s1dat);\r
591 tq_csta = CST_S3; /* now in step 3 */\r
592 tq_init_int (); /* intr if req */\r
593 break;\r
594\r
595 case CST_S3: /* need S3 reply */\r
596 tq_comm = ((tq_saw & SA_S3H_CHI) << 16) | tq_comm;\r
597 if (tq_saw & SA_S3H_PP) { /* purge/poll test? */\r
598 tq_sa = 0; /* put 0 */\r
599 tq_csta = CST_S3_PPA; /* wait for 0 write */\r
600 }\r
601 else tq_step4 (); /* send step 4 */\r
602 break;\r
603\r
604 case CST_S3_PPA: /* need purge test */\r
605 if (tq_saw) tq_fatal (PE_PPF); /* data not zero? */\r
606 else tq_csta = CST_S3_PPB; /* wait for poll */\r
607 break;\r
608\r
609 case CST_S4: /* need S4 reply */\r
610 if (tq_saw & SA_S4H_GO) { /* go set? */\r
611 if (DEBUG_PRS (tq_dev)) fprintf (sim_deb,\r
612 ">>TQ: initialization complete\n");\r
613 tq_csta = CST_UP; /* we're up */\r
614 tq_sa = 0; /* clear SA */\r
615 sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps);\r
616 if ((tq_saw & SA_S4H_LF) && tq_perr) tq_plf (tq_perr);\r
617 tq_perr = 0;\r
618 }\r
619 break;\r
620 } /* end switch */ \r
621 return SCPE_OK;\r
622 } /* end if */\r
623\r
624for (i = 0; i < TQ_NUMDR; i++) { /* chk unit q's */\r
625 nuptr = tq_dev.units + i; /* ptr to unit */\r
626 if (nuptr->cpkt || (nuptr->pktq == 0)) continue;\r
627 pkt = tq_deqh (&nuptr->pktq); /* get top of q */\r
628 if (!tq_mscp (pkt, FALSE)) return SCPE_OK; /* process */\r
629 }\r
630if ((pkt == 0) && tq_pip) { /* polling? */\r
631 if (!tq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */\r
632 if (pkt) { /* got one? */\r
633 if (DEBUG_PRS (tq_dev)) {\r
634 UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);\r
635 fprintf (sim_deb, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ",\r
636 tq_pkt[pkt].d[CMD_OPC], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]);\r
637 fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X",\r
638 tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],\r
639 tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]);\r
640 if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);\r
641 else fprintf (sim_deb, "\n");\r
642 fflush (sim_deb);\r
643 }\r
644 if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */\r
645 return tq_fatal (PE_PIE); /* no, term thread */\r
646 cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */\r
647 if (cnid == UQ_CID_TMSCP) { /* TMSCP packet? */\r
648 if (!tq_mscp (pkt, TRUE)) return SCPE_OK; /* proc, q non-seq */\r
649 }\r
650 else if (cnid == UQ_CID_DUP) { /* DUP packet? */\r
651 tq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ);\r
652 if (!tq_putpkt (pkt, TRUE)) return SCPE_OK; /* ill cmd */\r
653 }\r
654 else return tq_fatal (PE_ICI); /* no, term thread */\r
655 } /* end if pkt */\r
656 else tq_pip = 0; /* discontinue poll */\r
657 } /* end if pip */\r
658if (tq_rspq) { /* resp q? */\r
659 pkt = tq_deqh (&tq_rspq); /* get top of q */\r
660 if (!tq_putpkt (pkt, FALSE)) return SCPE_OK; /* send to host */\r
661 } /* end if resp q */\r
662if (pkt) sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* more to do? */\r
663return SCPE_OK; /* done */\r
664}\r
665\r
666/* Clock service (roughly once per second) */\r
667\r
668t_stat tq_tmrsvc (UNIT *uptr)\r
669{\r
670int32 i;\r
671UNIT *nuptr;\r
672\r
673sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */\r
674for (i = 0; i < TQ_NUMDR; i++) { /* poll */\r
675 nuptr = tq_dev.units + i;\r
676 if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */\r
677 (nuptr->flags & UNIT_ATT) && /* still online? */\r
678 (tq_cflgs & CF_ATN)) { /* wanted? */\r
679 if (!tq_una (nuptr)) return SCPE_OK;\r
680 }\r
681 nuptr->flags = nuptr->flags & ~UNIT_ATP;\r
682 }\r
683if ((tq_hat > 0) && (--tq_hat == 0)) /* host timeout? */\r
684 tq_fatal (PE_HAT); /* fatal err */ \r
685return SCPE_OK;\r
686}\r
687\r
688/* MSCP packet handling */\r
689\r
690t_bool tq_mscp (int32 pkt, t_bool q)\r
691{\r
692uint32 sts;\r
693uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* command */\r
694uint32 flg = GETP (pkt, CMD_OPC, FLG); /* flags */\r
695uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */\r
696uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
697UNIT *uptr;\r
698\r
699if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */\r
700 cmd = OP_END; /* set end op */\r
701 sts = ST_CMD | I_OPCD; /* ill op */\r
702 }\r
703else if (flg) { /* flags? */\r
704 cmd = cmd | OP_END; /* set end flag */\r
705 sts = ST_CMD | I_FLAG; /* ill flags */\r
706 }\r
707else if (mdf & ~tq_cmf[cmd]) { /* invalid mod? */\r
708 cmd = cmd | OP_END; /* set end flag */\r
709 sts = ST_CMD | I_MODF; /* ill mods */\r
710 }\r
711else { /* valid cmd */\r
712 if (uptr = tq_getucb (lu)) { /* valid unit? */\r
713 if (q && (tq_cmf[cmd] & CMF_SEQ) && /* queueing, seq, */\r
714 (uptr->cpkt || uptr->pktq)) { /* and active? */\r
715 tq_enqt (&uptr->pktq, pkt); /* do later */\r
716 return OK;\r
717 }\r
718/* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */\r
719/* uptr->flags = uptr->flags & ~UNIT_CDL; */\r
720 if (tq_cmf[cmd] & MD_CSE) /* clr ser exc? */\r
721 uptr->flags = uptr->flags & ~UNIT_SXC;\r
722 }\r
723 switch (cmd) {\r
724\r
725 case OP_ABO: /* abort */\r
726 return tq_abo (pkt);\r
727\r
728 case OP_AVL: /* avail */\r
729 return tq_avl (pkt);\r
730\r
731 case OP_GCS: /* get cmd status */\r
732 return tq_gcs (pkt);\r
733\r
734 case OP_GUS: /* get unit status */\r
735 return tq_gus (pkt);\r
736\r
737 case OP_ONL: /* online */\r
738 return tq_onl (pkt);\r
739\r
740 case OP_SCC: /* set ctrl char */\r
741 return tq_scc (pkt);\r
742\r
743 case OP_SUC: /* set unit char */\r
744 return tq_suc (pkt);\r
745\r
746 case OP_ERS: /* erase */\r
747 case OP_ERG: /* erase gap */\r
748 return tq_erase (pkt);\r
749\r
750 case OP_FLU: /* flush */\r
751 return tq_flu (pkt);\r
752\r
753 case OP_POS: /* position */\r
754 return tq_pos (pkt);\r
755\r
756 case OP_WTM: /* write tape mark */\r
757 return tq_wtm (pkt);\r
758\r
759 case OP_ACC: /* access */\r
760 case OP_CMP: /* compare */\r
761 case OP_RD: /* read */\r
762 case OP_WR: /* write */\r
763 return tq_rw (pkt);\r
764\r
765 case OP_DAP:\r
766 cmd = cmd | OP_END; /* set end flag */\r
767 sts = ST_SUC; /* success */\r
768 break;\r
769\r
770 default:\r
771 cmd = OP_END; /* set end op */\r
772 sts = ST_CMD | I_OPCD; /* ill op */\r
773 break;\r
774 } /* end switch */\r
775 } /* end else */\r
776tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ);\r
777return tq_putpkt (pkt, TRUE);\r
778}\r
779\r
780/* Abort a command - 1st parameter is ref # of cmd to abort */\r
781\r
782t_bool tq_abo (int32 pkt)\r
783{\r
784uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
785uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */\r
786int32 tpkt, prv;\r
787UNIT *uptr;\r
788\r
789tpkt = 0; /* set no mtch */\r
790if (uptr = tq_getucb (lu)) { /* get unit */\r
791 if (uptr->cpkt && /* curr pkt? */\r
792 (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */\r
793 tpkt = uptr->cpkt; /* save match */\r
794 uptr->cpkt = 0; /* gonzo */\r
795 sim_cancel (uptr); /* cancel unit */\r
796 sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);\r
797 }\r
798 else if (uptr->pktq && /* head of q? */\r
799 (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */\r
800 tpkt = uptr->pktq; /* save match */\r
801 uptr->pktq = tq_pkt[tpkt].link; /* unlink */\r
802 }\r
803 else if (prv = uptr->pktq) { /* srch pkt q */\r
804 while (tpkt = tq_pkt[prv].link) { /* walk list */\r
805 if (GETP32 (tpkt, RSP_REFL) == ref) { /* match ref? */\r
806 tq_pkt[prv].link = tq_pkt[tpkt].link; /* unlink */\r
807 break;\r
808 }\r
809 }\r
810 }\r
811 if (tpkt) { /* found target? */\r
812 uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */\r
813 tq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ);\r
814 if (!tq_putpkt (tpkt, TRUE)) return ERR;\r
815 }\r
816 } /* end if unit */\r
817tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ);\r
818return tq_putpkt (pkt, TRUE);\r
819}\r
820\r
821/* Unit available - set unit status to available\r
822 Deferred if q'd cmds, bypassed if ser exc */\r
823\r
824t_bool tq_avl (int32 pkt)\r
825{\r
826uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
827uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */\r
828uint32 sts;\r
829UNIT *uptr;\r
830\r
831if (uptr = tq_getucb (lu)) { /* unit exist? */\r
832 if (uptr->flags & UNIT_SXC) sts = ST_SXC; /* ser exc pending? */\r
833 else {\r
834 uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_TMK | UNIT_POL);\r
835 sim_tape_rewind (uptr); /* rewind */\r
836 uptr->uf = uptr->objp = 0; /* clr flags */\r
837 if (uptr->flags & UNIT_ATT) { /* attached? */\r
838 sts = ST_SUC; /* success */\r
839 if (mdf & MD_UNL) tq_detach (uptr); /* unload? */\r
840 }\r
841 else sts = ST_OFL | SB_OFL_NV; /* no, offline */\r
842 }\r
843 }\r
844else sts = ST_OFL; /* offline */\r
845tq_putr (pkt, OP_AVL | OP_END, tq_efl (uptr), sts, AVL_LNT, UQ_TYP_SEQ);\r
846return tq_putpkt (pkt, TRUE);\r
847}\r
848\r
849/* Get command status - only interested in active xfr cmd */\r
850\r
851t_bool tq_gcs (int32 pkt)\r
852{\r
853uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
854uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */\r
855int32 tpkt;\r
856UNIT *uptr;\r
857\r
858if ((uptr = tq_getucb (lu)) && /* valid lu? */\r
859 (tpkt = uptr->cpkt) && /* queued pkt? */\r
860 (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */\r
861 (tq_cmf[GETP (tpkt, CMD_OPC, OPC)] & CMF_RW)) { /* rd/wr cmd? */\r
862 tq_pkt[pkt].d[GCS_STSL] = tq_pkt[tpkt].d[RW_BCL];\r
863 tq_pkt[pkt].d[GCS_STSH] = tq_pkt[tpkt].d[RW_BCH];\r
864 }\r
865else tq_pkt[pkt].d[GCS_STSL] = tq_pkt[pkt].d[GCS_STSH] = 0;\r
866tq_putr (pkt, OP_GCS | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ);\r
867return tq_putpkt (pkt, TRUE);\r
868}\r
869\r
870/* Get unit status */\r
871\r
872t_bool tq_gus (int32 pkt)\r
873{\r
874uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
875uint32 sts;\r
876UNIT *uptr;\r
877\r
878if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */\r
879 if (lu >= TQ_NUMDR) { /* end of range? */\r
880 lu = 0; /* reset to 0 */\r
881 tq_pkt[pkt].d[RSP_UN] = lu;\r
882 }\r
883 }\r
884if (uptr = tq_getucb (lu)) { /* unit exist? */\r
885 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r
886 sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r
887 else if (uptr->flags & UNIT_ONL) sts = ST_SUC; /* online */\r
888 else sts = ST_AVL; /* avail */\r
889 tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */\r
890 tq_pkt[pkt].d[GUS_MENU] = drv_tab[tq_typ].fmt; /* format menu */\r
891 tq_pkt[pkt].d[GUS_CAP] = 0; /* free capacity */\r
892 tq_pkt[pkt].d[GUS_FVER] = drv_tab[tq_typ].fver; /* formatter version */\r
893 tq_pkt[pkt].d[GUS_UVER] = drv_tab[tq_typ].uver; /* unit version */\r
894 }\r
895else sts = ST_OFL; /* offline */\r
896tq_putr (pkt, OP_GUS | OP_END, tq_efl (uptr), sts, GUS_LNT_T, UQ_TYP_SEQ);\r
897return tq_putpkt (pkt, TRUE);\r
898}\r
899\r
900/* Unit online - deferred if q'd commands */\r
901\r
902t_bool tq_onl (int32 pkt)\r
903{\r
904uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
905uint32 sts;\r
906UNIT *uptr;\r
907\r
908if (uptr = tq_getucb (lu)) { /* unit exist? */\r
909 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r
910 sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r
911 else if (uptr->flags & UNIT_ONL) /* already online? */\r
912 sts = ST_SUC | SB_SUC_ON;\r
913 else {\r
914 sts = ST_SUC; /* mark online */\r
915 sim_tape_rewind (uptr); /* rewind */\r
916 uptr->objp = 0; /* clear flags */\r
917 uptr->flags = (uptr->flags | UNIT_ONL) &\r
918 ~(UNIT_TMK | UNIT_POL); /* onl, pos ok */\r
919 tq_setf_unit (pkt, uptr); /* hack flags */\r
920 }\r
921 tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */\r
922 }\r
923else sts = ST_OFL; /* offline */\r
924tq_putr (pkt, OP_ONL | OP_END, tq_efl (uptr), sts, ONL_LNT, UQ_TYP_SEQ);\r
925return tq_putpkt (pkt, TRUE);\r
926}\r
927\r
928/* Set controller characteristics */\r
929\r
930t_bool tq_scc (int32 pkt)\r
931{\r
932if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */\r
933 tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ);\r
934else {\r
935 tq_cflgs = (tq_cflgs & CF_RPL) | /* hack ctrl flgs */\r
936 tq_pkt[pkt].d[SCC_CFL];\r
937 if (tq_htmo = tq_pkt[pkt].d[SCC_TMO]) /* set timeout */\r
938 tq_htmo = tq_htmo + 2; /* if nz, round up */\r
939 tq_pkt[pkt].d[SCC_CFL] = tq_cflgs; /* return flags */\r
940 tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO; /* ctrl timeout */\r
941 tq_pkt[pkt].d[SCC_VER] = drv_tab[tq_typ].cver; /* ctrl version */\r
942 tq_pkt[pkt].d[SCC_CIDA] = 0; /* ctrl ID */\r
943 tq_pkt[pkt].d[SCC_CIDB] = 0;\r
944 tq_pkt[pkt].d[SCC_CIDC] = 0;\r
945 tq_pkt[pkt].d[SCC_CIDD] = (TQ_CLASS << SCC_CIDD_V_CLS) |\r
946 (drv_tab[tq_typ].cmod << SCC_CIDD_V_MOD);\r
947 PUTP32 (pkt, SCC_MBCL, TQ_MAXFR); /* max bc */\r
948 tq_putr (pkt, OP_SCC | OP_END, 0, ST_SUC, SCC_LNT, UQ_TYP_SEQ);\r
949 }\r
950return tq_putpkt (pkt, TRUE);\r
951}\r
952 \r
953/* Set unit characteristics - defer if q'd commands */\r
954\r
955t_bool tq_suc (int32 pkt)\r
956{\r
957uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
958uint32 sts;\r
959UNIT *uptr;\r
960\r
961if (uptr = tq_getucb (lu)) { /* unit exist? */\r
962 if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r
963 sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r
964 else {\r
965 sts = ST_SUC; /* avail or onl */\r
966 tq_setf_unit (pkt, uptr); /* hack flags */\r
967 }\r
968 tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */\r
969 }\r
970else sts = ST_OFL; /* offline */\r
971tq_putr (pkt, OP_SUC | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ);\r
972return tq_putpkt (pkt, TRUE);\r
973}\r
974\r
975/* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */\r
976\r
977t_bool tq_flu (int32 pkt)\r
978{\r
979uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
980uint32 sts;\r
981UNIT *uptr;\r
982\r
983if (uptr = tq_getucb (lu)) /* unit exist? */\r
984 sts = tq_mot_valid (uptr, OP_FLU); /* validate req */\r
985else sts = ST_OFL; /* offline */\r
986tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ);\r
987return tq_putpkt (pkt, TRUE);\r
988}\r
989\r
990/* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */\r
991\r
992t_bool tq_erase (int32 pkt)\r
993{\r
994uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
995uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */\r
996uint32 sts;\r
997UNIT *uptr;\r
998\r
999if (uptr = tq_getucb (lu)) { /* unit exist? */\r
1000 sts = tq_mot_valid (uptr, cmd); /* validity checks */\r
1001 if (sts == ST_SUC) { /* ok? */\r
1002 uptr->cpkt = pkt; /* op in progress */\r
1003 sim_activate (uptr, tq_xtime); /* activate */\r
1004 return OK; /* done */\r
1005 }\r
1006 }\r
1007else sts = ST_OFL; /* offline */\r
1008tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, ERS_LNT, UQ_TYP_SEQ);\r
1009return tq_putpkt (pkt, TRUE);\r
1010}\r
1011\r
1012/* Write tape mark - deferred if q'd cmds, bypassed if ser exc */\r
1013\r
1014t_bool tq_wtm (int32 pkt)\r
1015{\r
1016uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
1017uint32 sts, objp = 0;\r
1018UNIT *uptr;\r
1019\r
1020if (uptr = tq_getucb (lu)) { /* unit exist? */\r
1021 objp = uptr->objp; /* position op */\r
1022 sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */\r
1023 if (sts == ST_SUC) { /* ok? */\r
1024 uptr->cpkt = pkt; /* op in progress */\r
1025 sim_activate (uptr, tq_xtime); /* activate */\r
1026 return OK; /* done */\r
1027 }\r
1028 }\r
1029else sts = ST_OFL; /* offline */\r
1030PUTP32 (pkt, WTM_POSL, objp); /* set obj pos */\r
1031tq_putr (pkt, OP_WTM | OP_END, tq_efl (uptr), sts, WTM_LNT, UQ_TYP_SEQ);\r
1032return tq_putpkt (pkt, TRUE);\r
1033}\r
1034\r
1035/* Position - deferred if q'd cmds, bypassed if ser exc */\r
1036\r
1037t_bool tq_pos (int32 pkt)\r
1038{\r
1039uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
1040uint32 sts, objp = 0;\r
1041UNIT *uptr;\r
1042\r
1043if (uptr = tq_getucb (lu)) { /* unit exist? */\r
1044 objp = uptr->objp; /* position op */\r
1045 sts = tq_mot_valid (uptr, OP_POS); /* validity checks */\r
1046 if (sts == ST_SUC) { /* ok? */\r
1047 uptr->cpkt = pkt; /* op in progress */\r
1048 sim_activate (uptr, tq_xtime); /* activate */\r
1049 return OK; /* done */\r
1050 }\r
1051 }\r
1052else sts = ST_OFL; /* offline */\r
1053PUTP32 (pkt, POS_RCL, 0); /* clear #skipped */\r
1054PUTP32 (pkt, POS_TMCL, 0);\r
1055PUTP32 (pkt, POS_POSL, objp); /* set obj pos */\r
1056tq_putr (pkt, OP_POS | OP_END, tq_efl (uptr), sts, POS_LNT, UQ_TYP_SEQ);\r
1057return tq_putpkt (pkt, TRUE);\r
1058}\r
1059\r
1060/* Data transfer commands - deferred if q'd commands, bypassed if ser exc */\r
1061\r
1062t_bool tq_rw (int32 pkt)\r
1063{\r
1064uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r
1065uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */\r
1066uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */\r
1067uint32 sts, objp = 0;\r
1068UNIT *uptr;\r
1069\r
1070if (uptr = tq_getucb (lu)) { /* unit exist? */\r
1071 objp = uptr->objp; /* position op */\r
1072 sts = tq_mot_valid (uptr, cmd); /* validity checks */\r
1073 if (sts == ST_SUC) { /* ok? */\r
1074 if ((bc == 0) || (bc > TQ_MAXFR)) { /* invalid? */\r
1075 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r
1076 sts = ST_CMD | I_BCNT;\r
1077 }\r
1078 else {\r
1079 uptr->cpkt = pkt; /* op in progress */\r
1080 sim_activate (uptr, tq_xtime); /* activate */\r
1081 return OK; /* done */\r
1082 }\r
1083 }\r
1084 }\r
1085else sts = ST_OFL; /* offline */\r
1086PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r
1087PUTP32 (pkt, RW_POSL, objp); /* set obj pos */\r
1088PUTP32 (pkt, RW_RSZL, 0); /* clr rec size */\r
1089tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT_T, UQ_TYP_SEQ);\r
1090return tq_putpkt (pkt, TRUE);\r
1091}\r
1092\r
1093/* Validity checks */\r
1094\r
1095int32 tq_mot_valid (UNIT *uptr, uint32 cmd)\r
1096{\r
1097if (uptr->flags & UNIT_SXC) return ST_SXC; /* ser exc pend? */\r
1098if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r
1099 return (ST_OFL | SB_OFL_NV); /* offl no vol */\r
1100if ((uptr->flags & UNIT_ONL) == 0) /* not online? */\r
1101 return ST_AVL; /* only avail */\r
1102if (tq_cmf[cmd] & CMF_WR) { /* write op? */\r
1103 if (uptr->uf & UF_WPS) { /* swre wlk? */\r
1104 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r
1105 return (ST_WPR | SB_WPR_SW);\r
1106 }\r
1107 if (TQ_WPH (uptr)) { /* hwre wlk? */\r
1108 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r
1109 return (ST_WPR | SB_WPR_HW);\r
1110 }\r
1111 }\r
1112return ST_SUC; /* success! */\r
1113}\r
1114\r
1115/* Unit service for motion commands */\r
1116\r
1117t_stat tq_svc (UNIT *uptr)\r
1118{\r
1119uint32 t, sts, sktmk, skrec;\r
1120t_mtrlnt i, tbc, wbc;\r
1121int32 pkt = uptr->cpkt; /* get packet */\r
1122uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */\r
1123uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */\r
1124uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */\r
1125t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */\r
1126uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */\r
1127uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */\r
1128\r
1129if (pkt == 0) return SCPE_IERR; /* what??? */\r
1130if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
1131 tq_mot_end (uptr, 0, ST_OFL | SB_OFL_NV, 0); /* offl no vol */\r
1132 return SCPE_OK;\r
1133 }\r
1134\r
1135if (tq_cmf[cmd] & CMF_WR) { /* write op? */\r
1136 if (TQ_WPH (uptr)) { /* hwre write prot? */\r
1137 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r
1138 tq_mot_end (uptr, 0, ST_WPR | SB_WPR_HW, 0);\r
1139 return SCPE_OK;\r
1140 }\r
1141 if (uptr->uf & UF_WPS) { /* swre write prot? */\r
1142 uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r
1143 tq_mot_end (uptr, 0, ST_WPR | SB_WPR_SW, 0);\r
1144 return SCPE_OK;\r
1145 }\r
1146 }\r
1147sts = ST_SUC; /* assume success */\r
1148tbc = 0; /* assume zero rec */\r
1149switch (cmd) { /* case on command */\r
1150\r
1151 case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */\r
1152 if (mdf & MD_REV) sts = tq_rdbufr (uptr, &tbc); /* read record */\r
1153 else sts = tq_rdbuff (uptr, &tbc);\r
1154 if (sts == ST_DRV) { /* read error? */\r
1155 PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r
1156 return tq_mot_err (uptr, tbc); /* log, done */\r
1157 }\r
1158 if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */\r
1159 PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r
1160 break;\r
1161 }\r
1162 if (tbc > bc) { /* tape rec > buf? */\r
1163 uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */\r
1164 sts = ST_RDT; /* data truncated */\r
1165 wbc = bc; /* set working bc */\r
1166 }\r
1167 else wbc = tbc;\r
1168 if (cmd == OP_RD) { /* read? */\r
1169 if (t = Map_WriteB (ba, wbc, tqxb)) { /* store, nxm? */\r
1170 PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */\r
1171 if (tq_hbe (uptr, ba + wbc - t)) /* post err log */\r
1172 tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); \r
1173 return SCPE_OK; /* end if nxm */\r
1174 }\r
1175 } /* end if read */\r
1176 else { /* compare */\r
1177 uint8 mby, dby;\r
1178 uint32 mba;\r
1179 for (i = 0; i < wbc; i++) { /* loop */\r
1180 if (mdf & MD_REV) { /* reverse? */\r
1181 mba = ba + bc - 1 - i; /* mem addr */\r
1182 dby = tqxb[tbc - 1 - i]; /* byte */\r
1183 }\r
1184 else {\r
1185 mba = ba + i;\r
1186 dby = tqxb[i];\r
1187 }\r
1188 if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */\r
1189 PUTP32 (pkt, RW_BCL, i); /* adj bc */\r
1190 if (tq_hbe (uptr, mba)) /* post err log */\r
1191 tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);\r
1192 return SCPE_OK;\r
1193 }\r
1194 if (mby != dby) { /* cmp err? */\r
1195 uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */\r
1196 PUTP32 (pkt, RW_BCL, i); /* adj bc */\r
1197 tq_mot_end (uptr, 0, ST_CMP, tbc);\r
1198 return SCPE_OK; /* exit */\r
1199 }\r
1200 } /* end for */\r
1201 } /* end if compare */\r
1202 PUTP32 (pkt, RW_BCL, wbc); /* bytes read/cmp'd */\r
1203 break;\r
1204\r
1205 case OP_WR: /* write */\r
1206 if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */\r
1207 PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */\r
1208 if (tq_hbe (uptr, ba + bc - t)) /* post err log */\r
1209 tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); \r
1210 return SCPE_OK; /* end else wr */\r
1211 }\r
1212 if (sim_tape_wrrecf (uptr, tqxb, bc)) /* write rec fwd, err? */\r
1213 return tq_mot_err (uptr, bc); /* log, end */\r
1214 uptr->objp = uptr->objp + 1; /* upd obj pos */\r
1215 if (TEST_EOT (uptr)) /* EOT on write? */\r
1216 uptr->flags = uptr->flags | UNIT_SXC;\r
1217 uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */\r
1218 tbc = bc; /* RW_BC is ok */\r
1219 break;\r
1220\r
1221 case OP_WTM: /* write tape mark */\r
1222 if (sim_tape_wrtmk (uptr)) /* write tmk, err? */\r
1223 return tq_mot_err (uptr, 0); /* log, end */\r
1224 uptr->objp = uptr->objp + 1; /* incr obj cnt */\r
1225 case OP_ERG: /* erase gap */\r
1226 if (TEST_EOT (uptr)) /* EOT on write? */\r
1227 uptr->flags = uptr->flags | UNIT_SXC;\r
1228 uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */\r
1229 break;\r
1230\r
1231 case OP_ERS: /* erase */\r
1232 if (sim_tape_wreom (uptr)) /* write eom, err? */\r
1233 return tq_mot_err (uptr, 0); /* log, end */\r
1234 sim_tape_rewind (uptr); /* rewind */\r
1235 uptr->objp = 0;\r
1236 uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);\r
1237 break;\r
1238\r
1239 case OP_POS: /* position */\r
1240 sktmk = skrec = 0; /* clr skipped */\r
1241 if (mdf & MD_RWD) { /* rewind? */\r
1242 sim_tape_rewind (uptr);\r
1243 uptr->objp = 0; /* clr flags */\r
1244 uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);\r
1245 }\r
1246 if (mdf & MD_OBC) { /* skip obj? */\r
1247 if (mdf & MD_REV) /* reverse? */\r
1248 sts = tq_spacer (uptr, nrec, &skrec, FALSE);\r
1249 else sts = tq_spacef (uptr, nrec, &skrec, FALSE);\r
1250 } \r
1251 else { /* skip tmk, rec */\r
1252 if (mdf & MD_REV) sts = tq_skipfr (uptr, ntmk, &sktmk);\r
1253 else sts = tq_skipff (uptr, ntmk, &sktmk); \r
1254 if (sts == ST_SUC) { /* tmk succeed? */\r
1255 if (mdf & MD_REV) /* reverse? */\r
1256 sts = tq_spacer (uptr, nrec, &skrec, TRUE);\r
1257 else sts = tq_spacef (uptr, nrec, &skrec, TRUE);\r
1258 if (sts == ST_TMK) sktmk = sktmk + 1;\r
1259 }\r
1260 }\r
1261 PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */\r
1262 PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */\r
1263 break;\r
1264\r
1265 default:\r
1266 return SCPE_IERR;\r
1267 }\r
1268\r
1269tq_mot_end (uptr, 0, sts, tbc); /* done */\r
1270return SCPE_OK;\r
1271}\r
1272\r
1273/* Motion command drive error */\r
1274\r
1275t_stat tq_mot_err (UNIT *uptr, uint32 rsiz)\r
1276{\r
1277uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_TMK; /* serious exception */\r
1278if (tq_dte (uptr, ST_DRV)) /* post err log */\r
1279 tq_mot_end (uptr, EF_LOG, ST_DRV, rsiz); /* if ok, report err */\r
1280perror ("TQ I/O error");\r
1281clearerr (uptr->fileref);\r
1282return SCPE_IOERR;\r
1283}\r
1284\r
1285/* Motion command complete */\r
1286\r
1287t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz)\r
1288{\r
1289int32 pkt = uptr->cpkt; /* packet */\r
1290uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */\r
1291uint32 lnt = RW_LNT_T; /* assume rw */\r
1292\r
1293if (cmd == OP_ERG) lnt = ERG_LNT; /* set pkt lnt */\r
1294else if (cmd == OP_ERS) lnt = ERS_LNT;\r
1295else if (cmd == OP_WTM) lnt = WTM_LNT;\r
1296else if (cmd == OP_POS) lnt = POS_LNT;\r
1297\r
1298uptr->cpkt = 0; /* done */\r
1299if (lnt > ERG_LNT) { /* xfer cmd? */\r
1300 PUTP32 (pkt, RW_POSL, uptr->objp); /* position */\r
1301 PUTP32 (pkt, RW_RSZL, rsiz); /* record size */\r
1302 }\r
1303tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ);\r
1304if (!tq_putpkt (pkt, TRUE)) return ERR; /* send pkt */\r
1305if (uptr->pktq) /* more to do? */\r
1306 sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate thread */\r
1307return OK;\r
1308}\r
1309\r
1310/* Tape motion routines */\r
1311\r
1312uint32 tq_map_status (UNIT *uptr, t_stat st)\r
1313{\r
1314switch (st) {\r
1315\r
1316 case MTSE_OK:\r
1317 break;\r
1318\r
1319 case MTSE_UNATT:\r
1320 uptr->flags = uptr->flags | UNIT_SXC;\r
1321 return (ST_OFL | SB_OFL_NV);\r
1322\r
1323 case MTSE_FMT:\r
1324 uptr->flags = uptr->flags | UNIT_SXC;\r
1325 return ST_MFE;\r
1326\r
1327 case MTSE_TMK:\r
1328 uptr->flags = uptr->flags | UNIT_SXC;\r
1329 return ST_TMK;\r
1330\r
1331 case MTSE_INVRL:\r
1332 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r
1333 return ST_FMT;\r
1334\r
1335 case MTSE_RECE:\r
1336 case MTSE_IOERR:\r
1337 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r
1338 return ST_DRV;\r
1339\r
1340 case MTSE_EOM:\r
1341 uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r
1342 return ST_DAT;\r
1343\r
1344 case MTSE_BOT:\r
1345 uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL;\r
1346 return ST_BOT;\r
1347\r
1348 case MTSE_WRP:\r
1349 uptr->flags = uptr->flags | UNIT_SXC;\r
1350 return ST_WPR;\r
1351 }\r
1352\r
1353return ST_SUC;\r
1354}\r
1355\r
1356uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)\r
1357{\r
1358t_stat st;\r
1359t_mtrlnt tbc;\r
1360\r
1361*skipped = 0;\r
1362while (*skipped < cnt) { /* loop */\r
1363 st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */\r
1364 if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */\r
1365 return tq_map_status (uptr, st); /* map status */\r
1366 uptr->objp = uptr->objp + 1; /* upd obj cnt */\r
1367 if (st == MTSE_TMK) { /* tape mark? */\r
1368 int32 pkt = uptr->cpkt; /* get pkt */\r
1369 if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) && /* LEOT? */\r
1370 (uptr->flags & UNIT_TMK)) {\r
1371 sim_tape_sprecr (uptr, &tbc); /* rev over tmk */\r
1372 uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ \r
1373 return ST_LED;\r
1374 }\r
1375 uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */\r
1376 if (qrec) return ST_TMK; /* rec spc? stop */\r
1377 }\r
1378 else uptr->flags = uptr->flags & ~UNIT_TMK; /* clr TM seen */\r
1379 *skipped = *skipped + 1; /* # obj skipped */\r
1380 }\r
1381return ST_SUC;\r
1382}\r
1383\r
1384uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped)\r
1385{\r
1386uint32 st, skrec;\r
1387\r
1388*skipped = 0;\r
1389while (*skipped < cnt) { /* loop */\r
1390 st = tq_spacef (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc fwd */\r
1391 if (st == ST_TMK) *skipped = *skipped + 1; /* count files */\r
1392 else if (st != ST_SUC) return st;\r
1393 }\r
1394return ST_SUC;\r
1395}\r
1396\r
1397uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)\r
1398{\r
1399t_stat st;\r
1400t_mtrlnt tbc;\r
1401\r
1402*skipped = 0;\r
1403while (*skipped < cnt) { /* loop */\r
1404 st = sim_tape_sprecr (uptr, &tbc); /* spc rec rev */\r
1405 if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */\r
1406 return tq_map_status (uptr, st); /* map status */\r
1407 uptr->objp = uptr->objp - 1; /* upd obj cnt */\r
1408 if ((st == MTSE_TMK) && qrec) return ST_TMK; /* tape mark, stop? */\r
1409 *skipped = *skipped + 1; /* # obj skipped */\r
1410 }\r
1411return ST_SUC;\r
1412}\r
1413\r
1414uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped)\r
1415{\r
1416uint32 st, skrec;\r
1417\r
1418*skipped = 0;\r
1419while (*skipped < cnt) { /* loopo */\r
1420 st = tq_spacer (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc rev */\r
1421 if (st == ST_TMK) *skipped = *skipped + 1; /* tape mark? */\r
1422 else if (st != 0) return st; /* error? */\r
1423 }\r
1424return ST_SUC;\r
1425}\r
1426\r
1427/* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */\r
1428\r
1429uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc)\r
1430{\r
1431t_stat st;\r
1432\r
1433st = sim_tape_rdrecf (uptr, tqxb, tbc, MT_MAXFR); /* read rec fwd */\r
1434if (st == MTSE_TMK) { /* tape mark? */\r
1435 uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */\r
1436 uptr->objp = uptr->objp + 1; /* update obj cnt */\r
1437 return ST_TMK;\r
1438 }\r
1439if (st != MTSE_OK) return tq_map_status (uptr, st); /* other error? */\r
1440uptr->flags = uptr->flags & ~UNIT_TMK; /* clr tape mark */\r
1441uptr->objp = uptr->objp + 1; /* upd obj cnt */\r
1442return ST_SUC;\r
1443}\r
1444\r
1445uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc)\r
1446{\r
1447t_stat st;\r
1448\r
1449st = sim_tape_rdrecr (uptr, tqxb, tbc, MT_MAXFR); /* read rec rev */\r
1450if (st == MTSE_TMK) { /* tape mark? */\r
1451 uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */\r
1452 uptr->objp = uptr->objp - 1; /* update obj cnt */\r
1453 return ST_TMK;\r
1454 }\r
1455if (st != MTSE_OK) return tq_map_status (uptr, st); /* other error? */\r
1456uptr->objp = uptr->objp - 1; /* upd obj cnt */\r
1457return ST_SUC;\r
1458}\r
1459\r
1460/* Data transfer error log packet */\r
1461\r
1462t_bool tq_dte (UNIT *uptr, uint32 err)\r
1463{\r
1464int32 pkt, tpkt;\r
1465uint32 lu;\r
1466\r
1467if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */\r
1468if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r
1469tpkt = uptr->cpkt; /* rw pkt */\r
1470lu = tq_pkt[tpkt].d[CMD_UN]; /* unit # */\r
1471\r
1472tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */\r
1473tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */\r
1474tq_pkt[pkt].d[ELP_UN] = lu; /* copy unit */\r
1475tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */\r
1476tq_pkt[pkt].d[DTE_CIDA] = 0; /* ctrl ID */\r
1477tq_pkt[pkt].d[DTE_CIDB] = 0;\r
1478tq_pkt[pkt].d[DTE_CIDC] = 0;\r
1479tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |\r
1480 (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);\r
1481tq_pkt[pkt].d[DTE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */\r
1482tq_pkt[pkt].d[DTE_MLUN] = lu; /* MLUN */\r
1483tq_pkt[pkt].d[DTE_UIDA] = lu; /* unit ID */\r
1484tq_pkt[pkt].d[DTE_UIDB] = 0;\r
1485tq_pkt[pkt].d[DTE_UIDC] = 0;\r
1486tq_pkt[pkt].d[DTE_UIDD] = (UID_TAPE << DTE_UIDD_V_CLS) |\r
1487 (drv_tab[tq_typ].umod << DTE_UIDD_V_MOD);\r
1488tq_pkt[pkt].d[DTE_UVER] = drv_tab[tq_typ].uver; /* unit ver */\r
1489PUTP32 (pkt, DTE_POSL, uptr->objp); /* position */\r
1490tq_pkt[pkt].d[DTE_FVER] = drv_tab[tq_typ].fver; /* fmtr ver */\r
1491tq_putr (pkt, FM_TAP, LF_SNR, err, DTE_LNT, UQ_TYP_DAT);\r
1492return tq_putpkt (pkt, TRUE);\r
1493}\r
1494\r
1495/* Host bus error log packet */\r
1496\r
1497t_bool tq_hbe (UNIT *uptr, uint32 ba)\r
1498{\r
1499int32 pkt, tpkt;\r
1500\r
1501if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */\r
1502if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r
1503tpkt = uptr->cpkt; /* rw pkt */\r
1504tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */\r
1505tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */\r
1506tq_pkt[pkt].d[ELP_UN] = tq_pkt[tpkt].d[CMD_UN]; /* copy unit */\r
1507tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */\r
1508tq_pkt[pkt].d[HBE_CIDA] = 0; /* ctrl ID */\r
1509tq_pkt[pkt].d[HBE_CIDB] = 0;\r
1510tq_pkt[pkt].d[HBE_CIDC] = 0;\r
1511tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |\r
1512 (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);\r
1513tq_pkt[pkt].d[HBE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */\r
1514tq_pkt[pkt].d[HBE_RSV] = 0;\r
1515PUTP32 (pkt, HBE_BADL, ba); /* bad addr */\r
1516tq_putr (pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT);\r
1517return tq_putpkt (pkt, TRUE);\r
1518}\r
1519\r
1520/* Port last failure error log packet */\r
1521\r
1522t_bool tq_plf (uint32 err)\r
1523{\r
1524int32 pkt;\r
1525\r
1526if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r
1527tq_pkt[pkt].d[ELP_REFL] = tq_pkt[pkt].d[ELP_REFH] = 0; /* ref = 0 */\r
1528tq_pkt[pkt].d[ELP_UN] = tq_pkt[pkt].d[ELP_SEQ] = 0; /* no unit, seq */\r
1529tq_pkt[pkt].d[PLF_CIDA] = 0; /* cntl ID */\r
1530tq_pkt[pkt].d[PLF_CIDB] = 0;\r
1531tq_pkt[pkt].d[PLF_CIDC] = 0;\r
1532tq_pkt[pkt].d[PLF_CIDD] = (TQ_CLASS << PLF_CIDD_V_CLS) |\r
1533 (drv_tab[tq_typ].cmod << PLF_CIDD_V_MOD);\r
1534tq_pkt[pkt].d[PLF_VER] = drv_tab[tq_typ].cver;\r
1535tq_pkt[pkt].d[PLF_ERR] = err;\r
1536tq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT);\r
1537tq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID);\r
1538return tq_putpkt (pkt, TRUE);\r
1539}\r
1540\r
1541/* Unit now available attention packet */\r
1542\r
1543int32 tq_una (UNIT *uptr)\r
1544{\r
1545int32 pkt;\r
1546uint32 lu;\r
1547\r
1548if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r
1549lu = (uint32) (uptr - tq_dev.units); /* get unit */\r
1550tq_pkt[pkt].d[RSP_REFL] = tq_pkt[pkt].d[RSP_REFH] = 0; /* ref = 0 */\r
1551tq_pkt[pkt].d[RSP_UN] = lu;\r
1552tq_pkt[pkt].d[RSP_RSV] = 0;\r
1553tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */\r
1554tq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */\r
1555return tq_putpkt (pkt, TRUE);\r
1556}\r
1557\r
1558/* List handling\r
1559\r
1560 tq_deqf - dequeue head of free list (fatal err if none)\r
1561 tq_deqh - dequeue head of list\r
1562 tq_enqh - enqueue at head of list\r
1563 tq_enqt - enqueue at tail of list\r
1564*/\r
1565\r
1566t_bool tq_deqf (int32 *pkt)\r
1567{\r
1568if (tq_freq == 0) return tq_fatal (PE_NSR); /* no free pkts?? */\r
1569tq_pbsy = tq_pbsy + 1; /* cnt busy pkts */\r
1570*pkt = tq_freq; /* head of list */\r
1571tq_freq = tq_pkt[tq_freq].link; /* next */\r
1572return OK;\r
1573}\r
1574\r
1575int32 tq_deqh (int32 *lh)\r
1576{\r
1577int32 ptr = *lh; /* head of list */\r
1578\r
1579if (ptr) *lh = tq_pkt[ptr].link; /* next */\r
1580return ptr;\r
1581}\r
1582\r
1583void tq_enqh (int32 *lh, int32 pkt)\r
1584{\r
1585if (pkt == 0) return; /* any pkt? */\r
1586tq_pkt[pkt].link = *lh; /* link is old lh */\r
1587*lh = pkt; /* pkt is new lh */\r
1588return;\r
1589}\r
1590\r
1591void tq_enqt (int32 *lh, int32 pkt)\r
1592{\r
1593if (pkt == 0) return; /* any pkt? */\r
1594tq_pkt[pkt].link = 0; /* it will be tail */\r
1595if (*lh == 0) *lh = pkt; /* if empty, enqh */\r
1596else {\r
1597 uint32 ptr = *lh; /* chase to end */\r
1598 while (tq_pkt[ptr].link) ptr = tq_pkt[ptr].link;\r
1599 tq_pkt[ptr].link = pkt; /* enq at tail */\r
1600 }\r
1601return;\r
1602}\r
1603\r
1604/* Packet and descriptor handling */\r
1605\r
1606/* Get packet from command ring */\r
1607\r
1608t_bool tq_getpkt (int32 *pkt)\r
1609{\r
1610uint32 addr, desc;\r
1611\r
1612if (!tq_getdesc (&tq_cq, &desc)) return ERR; /* get cmd desc */\r
1613if ((desc & UQ_DESC_OWN) == 0) { /* none */\r
1614 *pkt = 0; /* pkt = 0 */\r
1615 return OK; /* no error */\r
1616 }\r
1617if (!tq_deqf (pkt)) return ERR; /* get cmd pkt */\r
1618tq_hat = 0; /* dsbl hst timer */\r
1619addr = desc & UQ_ADDR; /* get Q22 addr */\r
1620if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d))\r
1621 return tq_fatal (PE_PRE); /* read pkt */\r
1622return tq_putdesc (&tq_cq, desc); /* release desc */\r
1623}\r
1624\r
1625/* Put packet to response ring - note the clever hack about credits.\r
1626 The controller sends all its credits to the host. Thereafter, it\r
1627 supplies one credit for every response packet sent over. Simple!\r
1628*/\r
1629\r
1630t_bool tq_putpkt (int32 pkt, t_bool qt)\r
1631{\r
1632uint32 addr, desc, lnt, cr;\r
1633\r
1634if (pkt == 0) return OK; /* any packet? */\r
1635if (DEBUG_PRS (tq_dev)) {\r
1636 UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);\r
1637 fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X",\r
1638 tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]);\r
1639 if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);\r
1640 else fprintf (sim_deb, "\n");\r
1641 fflush (sim_deb);\r
1642 }\r
1643if (!tq_getdesc (&tq_rq, &desc)) return ERR; /* get rsp desc */\r
1644if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */\r
1645 if (qt) tq_enqt (&tq_rspq, pkt); /* normal? q tail */\r
1646 else tq_enqh (&tq_rspq, pkt); /* resp q call */\r
1647 sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate q thrd */\r
1648 return OK;\r
1649 }\r
1650addr = desc & UQ_ADDR; /* get Q22 addr */\r
1651lnt = tq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */\r
1652if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */\r
1653 (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */\r
1654 cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */\r
1655 tq_credits = tq_credits - cr; /* decr credits */\r
1656 tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR);\r
1657 }\r
1658if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d))\r
1659 return tq_fatal (PE_PWE); /* write pkt */\r
1660tq_enqh (&tq_freq, pkt); /* pkt is free */\r
1661tq_pbsy = tq_pbsy - 1; /* decr busy cnt */\r
1662if (tq_pbsy == 0) tq_hat = tq_htmo; /* idle? strt hst tmr */\r
1663return tq_putdesc (&tq_rq, desc); /* release desc */\r
1664}\r
1665\r
1666/* Get a descriptor from the host */\r
1667\r
1668t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc)\r
1669{\r
1670uint32 addr = ring->ba + ring->idx;\r
1671uint16 d[2];\r
1672\r
1673if (Map_ReadW (addr, 4, d)) /* fetch desc */\r
1674 return tq_fatal (PE_QRE); /* err? dead */\r
1675*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r
1676return OK;\r
1677}\r
1678\r
1679/* Return a descriptor to the host, clearing owner bit\r
1680 If rings transitions from "empty" to "not empty" or "full" to\r
1681 "not full", and interrupt bit was set, interrupt the host.\r
1682 Actually, test whether previous ring entry was owned by host.\r
1683*/\r
1684\r
1685t_bool tq_putdesc (struct uq_ring *ring, uint32 desc)\r
1686{\r
1687uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F;\r
1688uint32 prva, addr = ring->ba + ring->idx;\r
1689uint16 d[2];\r
1690\r
1691d[0] = newd & 0xFFFF; /* 32b to 16b */\r
1692d[1] = (newd >> 16) & 0xFFFF;\r
1693if (Map_WriteW (addr, 4, d)) /* store desc */\r
1694 return tq_fatal (PE_QWE); /* err? dead */\r
1695if (desc & UQ_DESC_F) { /* was F set? */\r
1696 if (ring->lnt <= 4) tq_ring_int (ring); /* lnt = 1? intr */\r
1697 else {\r
1698 prva = ring->ba + /* prv desc */\r
1699 ((ring->idx - 4) & (ring->lnt - 1));\r
1700 if (Map_ReadW (prva, 4, d)) /* read prv */\r
1701 return tq_fatal (PE_QRE);\r
1702 prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r
1703 if (prvd & UQ_DESC_OWN) tq_ring_int (ring);\r
1704 }\r
1705 }\r
1706ring->idx = (ring->idx + 4) & (ring->lnt - 1);\r
1707return OK;\r
1708}\r
1709\r
1710/* Get unit descriptor for logical unit - trivial now,\r
1711 but eventually, hide multiboard complexities here */\r
1712\r
1713UNIT *tq_getucb (uint32 lu)\r
1714{\r
1715UNIT *uptr;\r
1716\r
1717if (lu >= TQ_NUMDR) return NULL;\r
1718uptr = tq_dev.units + lu;\r
1719if (uptr->flags & UNIT_DIS) return NULL;\r
1720return uptr;\r
1721}\r
1722\r
1723/* Hack unit flags */\r
1724\r
1725void tq_setf_unit (int32 pkt, UNIT *uptr)\r
1726{\r
1727uptr->uf = tq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */\r
1728if ((tq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */\r
1729 (tq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */\r
1730 uptr->uf = uptr->uf | UF_WPS; /* simon says... */\r
1731return;\r
1732}\r
1733\r
1734/* Hack end flags */\r
1735\r
1736uint32 tq_efl (UNIT *uptr)\r
1737{\r
1738uint32 t = 0;\r
1739\r
1740if (uptr) { /* any unit? */\r
1741 if (uptr->flags & UNIT_POL) t = t | EF_PLS; /* note pos lost */\r
1742 if (uptr->flags & UNIT_SXC) t = t | EF_SXC; /* note ser exc */\r
1743 if (TEST_EOT (uptr)) t = t | EF_EOT; /* note EOT */\r
1744 }\r
1745return t;\r
1746}\r
1747\r
1748/* Unit response fields */\r
1749\r
1750void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all)\r
1751{\r
1752tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */\r
1753tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */\r
1754tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */\r
1755tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */\r
1756tq_pkt[pkt].d[ONL_UIDB] = 0;\r
1757tq_pkt[pkt].d[ONL_UIDC] = 0;\r
1758tq_pkt[pkt].d[ONL_UIDD] = (UID_TAPE << ONL_UIDD_V_CLS) |\r
1759 (drv_tab[tq_typ].umod << ONL_UIDD_V_MOD); /* UID hi */\r
1760PUTP32 (pkt, ONL_MEDL, drv_tab[tq_typ].med); /* media type */\r
1761if (all) { /* if long form */\r
1762 tq_pkt[pkt].d[ONL_FMT] = drv_tab[tq_typ].fmt; /* format */\r
1763 tq_pkt[pkt].d[ONL_SPD] = 0; /* speed */\r
1764 PUTP32 (pkt, ONL_MAXL, TQ_MAXFR); /* max xfr */\r
1765 tq_pkt[pkt].d[ONL_NREC] = 0; /* noise rec */\r
1766 tq_pkt[pkt].d[ONL_RSVE] = 0; /* reserved */\r
1767 }\r
1768return;\r
1769}\r
1770\r
1771/* UQ_HDR and RSP_OP fields */\r
1772\r
1773void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ)\r
1774{\r
1775tq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */\r
1776 (flg << RSP_OPF_V_FLG);\r
1777tq_pkt[pkt].d[RSP_STS] = sts;\r
1778tq_pkt[pkt].d[UQ_HLNT] = lnt; /* length */\r
1779tq_pkt[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */\r
1780 (UQ_CID_TMSCP << UQ_HCTC_V_CID); /* clr credits */\r
1781return;\r
1782}\r
1783\r
1784/* Post interrupt during init */\r
1785\r
1786void tq_init_int (void)\r
1787{\r
1788if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec) SET_INT (TQ);\r
1789return;\r
1790}\r
1791\r
1792/* Post interrupt during putpkt - note that NXMs are ignored! */\r
1793\r
1794void tq_ring_int (struct uq_ring *ring)\r
1795{\r
1796uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */\r
1797uint16 flag = 1;\r
1798\r
1799Map_WriteW (iadr, 2, &flag); /* write flag */\r
1800if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */\r
1801return;\r
1802}\r
1803\r
1804/* Return interrupt vector */\r
1805\r
1806int32 tq_inta (void)\r
1807{\r
1808return tq_dib.vec; /* prog vector */\r
1809}\r
1810\r
1811/* Fatal error */\r
1812\r
1813t_bool tq_fatal (uint32 err)\r
1814{\r
1815if (DEBUG_PRS (tq_dev)) fprintf (sim_deb, ">>TQ: fatal err=%X\n", err);\r
1816tq_reset (&tq_dev); /* reset device */\r
1817tq_sa = SA_ER | err; /* SA = dead code */\r
1818tq_csta = CST_DEAD; /* state = dead */\r
1819tq_perr = err; /* save error */\r
1820return ERR;\r
1821}\r
1822\r
1823/* Device attach */\r
1824\r
1825t_stat tq_attach (UNIT *uptr, char *cptr)\r
1826{\r
1827t_stat r;\r
1828\r
1829r = sim_tape_attach (uptr, cptr);\r
1830if (r != SCPE_OK) return r;\r
1831if (tq_csta == CST_UP) uptr->flags = (uptr->flags | UNIT_ATP) &\r
1832 ~(UNIT_SXC | UNIT_POL | UNIT_TMK);\r
1833return SCPE_OK;\r
1834}\r
1835\r
1836/* Device detach */\r
1837\r
1838t_stat tq_detach (UNIT *uptr)\r
1839{\r
1840t_stat r;\r
1841\r
1842r = sim_tape_detach (uptr); /* detach unit */\r
1843if (r != SCPE_OK) return r;\r
1844uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP | UNIT_SXC | UNIT_POL | UNIT_TMK);\r
1845uptr->uf = 0; /* clr unit flgs */\r
1846return SCPE_OK;\r
1847} \r
1848\r
1849/* Device reset */\r
1850\r
1851t_stat tq_reset (DEVICE *dptr)\r
1852{\r
1853int32 i, j;\r
1854UNIT *uptr;\r
1855\r
1856tq_csta = CST_S1; /* init stage 1 */\r
1857tq_s1dat = 0; /* no S1 data */\r
1858tq_dib.vec = 0; /* no vector */\r
1859if (UNIBUS) tq_sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; /* Unibus? */\r
1860else tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */\r
1861tq_cflgs = CF_RPL; /* ctrl flgs off */\r
1862tq_htmo = TQ_DHTMO; /* default timeout */\r
1863tq_hat = tq_htmo; /* default timer */\r
1864tq_cq.ba = tq_cq.lnt = tq_cq.idx = 0; /* clr cmd ring */\r
1865tq_rq.ba = tq_rq.lnt = tq_rq.idx = 0; /* clr rsp ring */\r
1866tq_credits = (TQ_NPKTS / 2) - 1; /* init credits */\r
1867tq_freq = 1; /* init free list */\r
1868for (i = 0; i < TQ_NPKTS; i++) { /* all pkts free */\r
1869 if (i) tq_pkt[i].link = (i + 1) & TQ_M_NPKTS;\r
1870 else tq_pkt[i].link = 0;\r
1871 for (j = 0; j < TQ_PKT_SIZE_W; j++) tq_pkt[i].d[j] = 0;\r
1872 }\r
1873tq_rspq = 0; /* no q'd rsp pkts */\r
1874tq_pbsy = 0; /* all pkts free */\r
1875tq_pip = 0; /* not polling */\r
1876CLR_INT (TQ); /* clr intr req */\r
1877for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */\r
1878 uptr = tq_dev.units + i;\r
1879 sim_cancel (uptr); /* clr activity */\r
1880 sim_tape_reset (uptr);\r
1881 uptr->flags = uptr->flags & /* not online */\r
1882 ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK);\r
1883 uptr->uf = 0; /* clr unit flags */\r
1884 uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */\r
1885 }\r
1886if (tqxb == NULL) tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8));\r
1887if (tqxb == NULL) return SCPE_MEM;\r
1888return SCPE_OK;\r
1889}\r
1890\r
1891/* Device bootstrap */\r
1892\r
1893#if defined (VM_PDP11)\r
1894\r
1895#define BOOT_START 016000 /* start */\r
1896#define BOOT_ENTRY (BOOT_START + 002) /* entry */\r
1897#define BOOT_UNIT (BOOT_START + 010) /* unit number */\r
1898#define BOOT_CSR (BOOT_START + 014) /* CSR */\r
1899#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))\r
1900\r
1901/* Data structure definitions */\r
1902\r
1903#define B_CMDINT (BOOT_START - 01000) /* cmd int */\r
1904#define B_RSPINT (B_CMDINT + 002) /* rsp int */\r
1905#define B_RING (B_RSPINT + 002) /* ring base */\r
1906#define B_RSPH (B_RING + 010) /* resp pkt hdr */\r
1907#define B_TKRSP (B_RSPH + 004) /* resp pkt */\r
1908#define B_CMDH (B_TKRSP + 060) /* cmd pkt hdr */\r
1909#define B_TKCMD (B_CMDH + 004) /* cmd pkt */\r
1910#define B_UNIT (B_TKCMD + 004) /* unit # */\r
1911\r
1912static const uint16 boot_rom[] = {\r
1913\r
1914 0046525, /* ST: "UM" */\r
1915\r
1916 0012706, 0016000, /* mov #st,sp */\r
1917 0012700, 0000000, /* mov #unitno,r0 */\r
1918 0012701, 0174500, /* mov #174500,r1 ; ip addr */\r
1919 0005021, /* clr (r1)+ ; init */\r
1920 0012704, 0004000, /* mov #4000,r4 ; s1 mask */\r
1921 0005002, /* clr r2 */\r
1922 0005022, /* 10$: clr (r2)+ ; clr up to boot */\r
1923 0020237, BOOT_START - 2, /* cmp r2,#st-2 */\r
1924 0103774, /* blo 10$ */\r
1925 0012705, BOOT_START+0312, /* mov #cmdtbl,r5 ; addr of tbl */\r
1926\r
1927 /* Four step init process */\r
1928\r
1929 0005711, /* 20$: tst (r1) ; err? */\r
1930 0100001, /* bpl 30$ */\r
1931 0000000, /* halt */\r
1932 0030411, /* 30$: bit r4,(r1) ; step set? */\r
1933 0001773, /* beq 20$ ; wait */\r
1934 0012511, /* mov (r5)+,(r1) ; send next */\r
1935 0006304, /* asl r4 ; next mask */\r
1936 0100370, /* bpl 20$ ; s4 done? */\r
1937\r
1938 /* Set up rings, issue ONLINE, REWIND, READ */\r
1939\r
1940 0012737, 0000400, B_CMDH + 2, /* mov #400,cmdh+2 ; VCID = 1 */\r
1941 0012737, 0000044, B_CMDH, /* mov #36.,cmdh ; cmd pkt lnt */\r
1942 0010037, B_UNIT, /* mov r0,unit ; unit # */\r
1943 0012737, 0000011, B_TKCMD + 8, /* mov #11,tkcmd+8. ; online op */\r
1944 0012737, 0020000, B_TKCMD + 10, /* mov #20000,tkcmd+10. ; clr ser ex */\r
1945 0012702, B_RING, /* mov #ring,r2 ; init rings */\r
1946 0012722, B_TKRSP, /* mov #tkrsp,(r2)+ ; rsp pkt addr */\r
1947 0010203, /* mov r2,r3 ; save ring+2 */\r
1948 0010423, /* mov r4,(r3)+ ; set TK own */\r
1949 0012723, B_TKCMD, /* mov #tkcmd,(r3)+ ; cmd pkt addr */\r
1950 0010423, /* mov r4,(r3)+ ; set TK own */\r
1951 0005741, /* tst -(r1) ; start poll */\r
1952 0005712, /* 40$: tst (r2) ; wait for resp */\r
1953 0100776, /* bmi 40$ */\r
1954 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r
1955 0001401, /* beq 50$ */\r
1956 0000000, /* halt */\r
1957 0012703, B_TKCMD + 8, /* 50$: mov #tkcmd+8.,r3 */\r
1958 0012723, 0000045, /* mov #45,(r3)+ ; reposition */\r
1959 0012723, 0020002, /* mov #20002,(r3)+ ; rew, clr exc */\r
1960 0012723, 0000001, /* mov #1,(r3)+ ; lo rec skp */\r
1961 0005023, /* clr (r3)+ ; hi rec skp */\r
1962 0005023, /* clr (r3)+ ; lo tmk skp */\r
1963 0005023, /* clr (r3)+ ; hi tmk skp */\r
1964 0010412, /* mov r4,(r2) ; TK own rsp */\r
1965 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */\r
1966 0005711, /* tst (r1) ; start poll */\r
1967 0005712, /* 60$: tst (r2) ; wait for resp */\r
1968 0100776, /* bmi 60$ */\r
1969 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r
1970 0001401, /* beq 70$ */\r
1971 0000000, /* halt */\r
1972 0012703, B_TKCMD + 8, /* 70$: mov #tkcmd+8.,r3 */\r
1973 0012723, 0000041, /* mov #41,(r3)+ ; read */\r
1974 0012723, 0020000, /* mov #20000,(r3)+ ; clr exc */\r
1975 0012723, 0001000, /* mov #512.,(r3)+ ; bc = 512 */\r
1976 0005023, /* clr (r3)+ ; clr args */\r
1977 0005023, /* clr (r3)+ ; ba = 0 */\r
1978 0010412, /* mov r4,(r2) ; TK own rsp */\r
1979 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */\r
1980 0005711, /* tst (r1) ; start poll */\r
1981 0005712, /* 80$: tst (r2) ; wait for resp */\r
1982 0100776, /* bmi 80$ */\r
1983 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r
1984 0001401, /* beq 90$ */\r
1985 0000000, /* halt */\r
1986\r
1987 /* Boot block read in, jump to 0 - leave controller init'd */\r
1988\r
1989 0005003, /* clr r3 */\r
1990 0012704, BOOT_START+020, /* mov #st+020,r4 */\r
1991 0005005, /* clr r5 */\r
1992 0005007, /* clr pc */\r
1993\r
1994 0100000, /* cmdtbl: init step 1 */\r
1995 B_RING, /* ring base */\r
1996 0000000, /* high ring base */\r
1997 0000001 /* go */\r
1998 };\r
1999\r
2000t_stat tq_boot (int32 unitno, DEVICE *dptr)\r
2001{\r
2002int32 i;\r
2003extern int32 saved_PC;\r
2004extern uint16 *M;\r
2005\r
2006for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r
2007M[BOOT_UNIT >> 1] = unitno & 3;\r
2008M[BOOT_CSR >> 1] = tq_dib.ba & DMASK;\r
2009saved_PC = BOOT_ENTRY;\r
2010return SCPE_OK;\r
2011}\r
2012\r
2013#else\r
2014\r
2015t_stat tq_boot (int32 unitno, DEVICE *dptr)\r
2016{\r
2017return SCPE_NOFNC;\r
2018}\r
2019\r
2020#endif\r
2021\r
2022/* Special show commands */\r
2023\r
2024void tq_show_ring (FILE *st, struct uq_ring *rp)\r
2025{\r
2026uint32 i, desc;\r
2027uint16 d[2];\r
2028\r
2029#if defined (VM_PDP11)\r
2030fprintf (st, "ring, base = %o, index = %d, length = %d\n",\r
2031 rp->ba, rp->idx >> 2, rp->lnt >> 2);\r
2032#else\r
2033fprintf (st, "ring, base = %x, index = %d, length = %d\n",\r
2034 rp->ba, rp->idx >> 2, rp->lnt >> 2);\r
2035#endif\r
2036for (i = 0; i < (rp->lnt >> 2); i++) {\r
2037 if (Map_ReadW (rp->ba + (i << 2), 4, d)) {\r
2038 fprintf (st, " %3d: non-existent memory\n", i);\r
2039 break;\r
2040 }\r
2041 desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r
2042#if defined (VM_PDP11)\r
2043 fprintf (st, " %3d: %011o\n", i, desc);\r
2044#else\r
2045 fprintf (st, " %3d: %08x\n", i, desc);\r
2046#endif\r
2047 }\r
2048return;\r
2049}\r
2050\r
2051void tq_show_pkt (FILE *st, int32 pkt)\r
2052{\r
2053int32 i, j;\r
2054uint32 cr = GETP (pkt, UQ_HCTC, CR);\r
2055uint32 typ = GETP (pkt, UQ_HCTC, TYP);\r
2056uint32 cid = GETP (pkt, UQ_HCTC, CID);\r
2057\r
2058fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n",\r
2059 pkt, cr, typ, cid);\r
2060for (i = 0; i < TQ_SH_MAX; i = i + TQ_SH_PPL) {\r
2061 fprintf (st, " %2d:", i);\r
2062 for (j = i; j < (i + TQ_SH_PPL); j++)\r
2063#if defined (VM_PDP11)\r
2064 fprintf (st, " %06o", tq_pkt[pkt].d[j]);\r
2065#else\r
2066 fprintf (st, " %04x", tq_pkt[pkt].d[j]);\r
2067#endif\r
2068 fprintf (st, "\n");\r
2069 }\r
2070return;\r
2071}\r
2072\r
2073t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2074{\r
2075int32 pkt, u = uptr - tq_dev.units;\r
2076\r
2077if (tq_csta != CST_UP) {\r
2078 fprintf (st, "Controller is not initialized\n");\r
2079 return SCPE_OK;\r
2080 }\r
2081if ((uptr->flags & UNIT_ONL) == 0) {\r
2082 if (uptr->flags & UNIT_ATT)\r
2083 fprintf (st, "Unit %d is available\n", u);\r
2084 else fprintf (st, "Unit %d is offline\n", u);\r
2085 return SCPE_OK;\r
2086 }\r
2087if (uptr->cpkt) {\r
2088 fprintf (st, "Unit %d current ", u);\r
2089 tq_show_pkt (st, uptr->cpkt);\r
2090 if (pkt = uptr->pktq) {\r
2091 do {\r
2092 fprintf (st, "Unit %d queued ", u);\r
2093 tq_show_pkt (st, pkt);\r
2094 } while (pkt = tq_pkt[pkt].link);\r
2095 }\r
2096 }\r
2097else fprintf (st, "Unit %d queues are empty\n", u);\r
2098return SCPE_OK;\r
2099}\r
2100\r
2101t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2102{\r
2103int32 i, pkt;\r
2104\r
2105if (tq_csta != CST_UP) {\r
2106 fprintf (st, "Controller is not initialized\n");\r
2107 return SCPE_OK;\r
2108 }\r
2109if (val & TQ_SH_RI) {\r
2110 if (tq_pip) fprintf (st, "Polling in progress, host timer = %d\n", tq_hat);\r
2111 else fprintf (st, "Host timer = %d\n", tq_hat);\r
2112 fprintf (st, "Command ");\r
2113 tq_show_ring (st, &tq_cq);\r
2114 fprintf (st, "Response ");\r
2115 tq_show_ring (st, &tq_rq);\r
2116 }\r
2117if (val & TQ_SH_FR) {\r
2118 if (pkt = tq_freq) {\r
2119 for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) {\r
2120 if (i == 0) fprintf (st, "Free queue = %d", pkt);\r
2121 else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt);\r
2122 else fprintf (st, ", %d", pkt);\r
2123 }\r
2124 fprintf (st, "\n");\r
2125 }\r
2126 else fprintf (st, "Free queue is empty\n");\r
2127 }\r
2128if (val & TQ_SH_RS) {\r
2129 if (pkt = tq_rspq) {\r
2130 do {\r
2131 fprintf (st, "Response ");\r
2132 tq_show_pkt (st, pkt);\r
2133 } while (pkt = tq_pkt[pkt].link);\r
2134 }\r
2135 else fprintf (st, "Response queue is empty\n");\r
2136 }\r
2137if (val & TQ_SH_UN) {\r
2138 for (i = 0; i < TQ_NUMDR; i++)\r
2139 tq_show_unitq (st, &tq_unit[i], 0, NULL);\r
2140 }\r
2141return SCPE_OK;\r
2142}\r
2143\r
2144/* Set controller type (and capacity for user-defined type) */\r
2145\r
2146t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)\r
2147{\r
2148uint32 i, cap;\r
2149uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC;\r
2150t_stat r;\r
2151\r
2152if ((val < 0) || (val > TQU_TYPE) || ((val != TQU_TYPE) && cptr))\r
2153 return SCPE_ARG;\r
2154for (i = 0; i < TQ_NUMDR; i++) {\r
2155 if (tq_unit[i].flags & UNIT_ATT) return SCPE_ALATT;\r
2156 }\r
2157if (cptr) {\r
2158 cap = (uint32) get_uint (cptr, 10, max, &r);\r
2159 if ((r != SCPE_OK) || (cap < TQU_MINC)) return SCPE_ARG;\r
2160 drv_tab[TQU_TYPE].cap = ((t_addr) cap) << 20;\r
2161 }\r
2162tq_typ = val;\r
2163for (i = 0; i < TQ_NUMDR; i++)\r
2164 tq_unit[i].capac = drv_tab[tq_typ].cap;\r
2165return SCPE_OK;\r
2166}\r
2167\r
2168/* Show controller type and capacity */\r
2169\r
2170t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)\r
2171{\r
2172fprintf (st, "%s (%dMB)", drv_tab[tq_typ].name, (uint32) (drv_tab[tq_typ].cap >> 20));\r
2173return SCPE_OK;\r
2174}\r