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