1 /* $NetBSD: ctu.c,v 1.39 2023/12/20 15:34:45 thorpej Exp $ */
2 /*
3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * Device driver for 11/750 Console TU58.
29 *
30 * Writing of tapes does not work, by some unknown reason so far.
31 * It is almost useless to try to use this driver when running
32 * multiuser, because the serial device don't have any buffers
33 * so we will lose interrupts.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ctu.c,v 1.39 2023/12/20 15:34:45 thorpej Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/buf.h>
42 #include <sys/bufq.h>
43 #include <sys/callout.h>
44 #include <sys/conf.h>
45 #include <sys/cpu.h>
46 #include <sys/device.h>
47 #include <sys/fcntl.h>
48 #include <sys/ioctl.h>
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51
52 #include <machine/rsp.h>
53 #include <machine/scb.h>
54
55 #undef TUDEBUG
56
57 #define TU_IDLE 0
58 #define TU_RESET 1
59 #define TU_RUNNING 2
60 #define TU_WORKING 3
61 #define TU_READING 4
62 #define TU_WRITING 5
63 #define TU_ENDPACKET 6
64 #define TU_RESTART 7
65
66 struct tu_softc {
67 int sc_state;
68 int sc_step;
69 char sc_rsp[15]; /* Should be struct rsb; but don't work */
70 int sc_tpblk; /* Start block number */
71 int sc_wto; /* Timeout counter */
72 int sc_xbytes; /* Number of xfer'd bytes */
73 int sc_op; /* Read/write */
74 struct bufq_state *sc_bufq; /* pending I/O requests */
75 } tu_sc;
76
77 struct ivec_dsp tu_recv, tu_xmit;
78
79 void ctuattach(void);
80 static void ctutintr(void *);
81 static void cturintr(void *);
82 static void ctustart(void);
83 static void ctuwatch(void *);
84 static u_short ctu_cksum(unsigned short *, int);
85
86 dev_type_open(ctuopen);
87 dev_type_close(ctuclose);
88 #if 0 /* not yet */
89 dev_type_read(cturead);
90 dev_type_write(ctuwrite);
91 #endif
92 dev_type_strategy(ctustrategy);
93
94 const struct bdevsw ctu_bdevsw = {
95 .d_open = ctuopen,
96 .d_close = ctuclose,
97 .d_strategy = ctustrategy,
98 .d_ioctl = noioctl,
99 .d_dump = nodump,
100 .d_psize = nosize,
101 .d_discard = nodiscard,
102 .d_flag = D_TAPE
103 };
104
105 #if 0 /* not yet */
106 const struct cdevsw ctu_cdevsw = {
107 .d_open = ctuopen,
108 .d_close = ctuclose,
109 .d_read = cturead,
110 .d_write = ctuwrite,
111 .d_ioctl = noioctl,
112 .d_stop = nostop,
113 .d_tty = notty,
114 .d_poll = nopoll,
115 .d_mmap = nommap,
116 .d_kqfilter = nokqfilter,
117 .d_discard = nodiscard,
118 .d_flag = D_TAPE
119 };
120 #endif
121
122 static callout_t ctu_watch_ch;
123
124 void
ctuattach(void)125 ctuattach(void)
126 {
127
128 callout_init(&ctu_watch_ch, 0);
129 bufq_alloc(&tu_sc.sc_bufq, "fcfs", 0);
130
131 tu_recv = idsptch;
132 tu_recv.hoppaddr = cturintr;
133 scb->scb_csrint = (void *)&tu_recv;
134
135 tu_xmit = idsptch;
136 tu_xmit.hoppaddr = ctutintr;
137 scb->scb_cstint = (void *)&tu_xmit;
138 }
139
140 static void
ctuinit(void)141 ctuinit(void)
142 {
143 int s = spl7();
144 #define WAIT while ((mfpr(PR_CSTS) & 0x80) == 0)
145
146 /*
147 * Do a reset as described in the
148 * "TU58 DECtape II Users Guide".
149 */
150 mtpr(0101, PR_CSTS); /* Enable transmit interrupt + send break */
151 WAIT;
152 mtpr(0, PR_CSTD); WAIT;
153 mtpr(0, PR_CSTD); WAIT;
154 mtpr(RSP_TYP_INIT, PR_CSTD); WAIT;
155 mtpr(RSP_TYP_INIT, PR_CSTD); WAIT;
156 #undef WAIT
157 splx(s);
158 }
159
160 int
ctuopen(dev_t dev,int oflags,int devtype,struct lwp * l)161 ctuopen(dev_t dev, int oflags, int devtype, struct lwp *l)
162 {
163 int error;
164
165 if (minor(dev))
166 return ENXIO;
167
168 if (tu_sc.sc_state != TU_IDLE)
169 return EBUSY;
170
171 tu_sc.sc_state = TU_RESET;
172 tu_sc.sc_step = 0;
173 mtpr(0100, PR_CSRS); /* Enable receive interrupt */
174 mtpr(0101, PR_CSTS); /* Enable transmit interrupt + send break */
175 if ((error = tsleep((void *)&tu_sc, (PZERO + 10)|PCATCH, "reset", 0)))
176 return error;
177
178 #ifdef TUDEBUG
179 printf("ctuopen: running\n");
180 #endif
181 tu_sc.sc_state = TU_RUNNING;
182 callout_reset(&ctu_watch_ch, hz, ctuwatch, NULL);
183 return 0;
184
185 }
186
187 int
ctuclose(dev_t dev,int oflags,int devtype,struct lwp * l)188 ctuclose(dev_t dev, int oflags, int devtype, struct lwp *l)
189 {
190 struct buf *bp;
191 int s = spl7();
192 while ((bp = bufq_get(tu_sc.sc_bufq)))
193 ;
194 splx(s);
195
196 mtpr(0, PR_CSRS);
197 mtpr(0, PR_CSTS);
198 tu_sc.sc_state = TU_IDLE;
199 callout_stop(&ctu_watch_ch);
200 return 0;
201 }
202
203 void
ctustrategy(struct buf * bp)204 ctustrategy(struct buf *bp)
205 {
206 int s, empty;
207
208 #ifdef TUDEBUG
209 printf("ctustrategy: bcount %ld blkno %d\n", bp->b_bcount, bp->b_blkno);
210 printf("ctustrategy: bp %p\n", bp);
211 #endif
212 s = spl7();
213 if (bp->b_blkno >= 512) {
214 bp->b_resid = bp->b_bcount;
215 biodone(bp);
216 splx(s);
217 return;
218 }
219
220 empty = (bufq_peek(tu_sc.sc_bufq) == NULL);
221 bufq_put(tu_sc.sc_bufq, bp);
222 if (empty)
223 ctustart();
224 splx(s);
225 }
226
227 void
ctustart(void)228 ctustart(void)
229 {
230 struct rsp *rsp = (struct rsp *)tu_sc.sc_rsp;
231 struct buf *bp;
232
233 bp = bufq_peek(tu_sc.sc_bufq);
234 if (bp == NULL)
235 return;
236 #ifdef TUDEBUG
237 printf("ctustart: %s\n", bp->b_flags & B_READ ? "READING":"WRITING");
238 #endif
239 tu_sc.sc_tpblk = bp->b_blkno;
240 tu_sc.sc_xbytes = 0;
241 tu_sc.sc_op = bp->b_flags & B_READ ? RSP_OP_READ : RSP_OP_WRITE;
242 tu_sc.sc_step = 0;
243 bp->b_resid = bp->b_bcount;
244 tu_sc.sc_wto = 0;
245
246 rsp->rsp_typ = RSP_TYP_COMMAND;
247 rsp->rsp_sz = 012;
248 rsp->rsp_op = tu_sc.sc_op;
249 rsp->rsp_mod = 0;
250 rsp->rsp_drv = 0;
251 rsp->rsp_sw = rsp->rsp_xx1 = rsp->rsp_xx2 = 0;
252 rsp->rsp_cnt = bp->b_bcount;
253 rsp->rsp_blk = tu_sc.sc_tpblk;
254 rsp->rsp_sum = ctu_cksum((unsigned short *)rsp, 6);
255 tu_sc.sc_state = TU_WORKING;
256 ctutintr(NULL);
257 }
258
259 static int
readchr(void)260 readchr(void)
261 {
262 int i;
263
264 for (i = 0; i < 5000; i++)
265 if ((mfpr(PR_CSRS) & 0x80))
266 break;
267 if (i == 5000)
268 return -1;
269 return mfpr(PR_CSRD);
270 }
271
272 /*
273 * Loop in a tight (busy-wait-)loop when receiving packets, this is
274 * the only way to avoid loosing characters.
275 */
276 void
cturintr(void * arg)277 cturintr(void *arg)
278 {
279 int status = mfpr(PR_CSRD);
280 struct buf *bp;
281 int i, c, tck;
282 unsigned short ck = 0;
283 char *buf;
284
285 bp = bufq_peek(tu_sc.sc_bufq);
286 buf = bp->b_data;
287 switch (tu_sc.sc_state) {
288 case TU_RESET:
289 if (status != RSP_TYP_CONTINUE)
290 printf("Bad response %d\n", status);
291 wakeup(&tu_sc);
292 return;
293
294 case TU_READING:
295 if (status != RSP_TYP_DATA)
296 bp->b_error = EIO;
297 tu_sc.sc_wto = 0;
298 for (i = 0; i < 131; i++) {
299 if ((c = readchr()) < 0) {
300 #ifdef TUDEBUG
301 printf("Timeout...%d\n", i);
302 #endif
303 goto bad;
304 }
305 if ((i > 0) && (i < 129))
306 buf[tu_sc.sc_xbytes++] = c;
307 if (i == 129)
308 ck = (c & 0xff);
309 if (i == 130)
310 ck |= ((c & 0xff) << 8);
311 }
312 tck = ctu_cksum((void *)&buf[tu_sc.sc_xbytes-128], 64);
313 tck += 0x8001; if (tck > 0xffff) tck -= 0xffff;
314 if (tck != ck) {
315 #ifdef TUDEBUG
316 int i;
317 printf("Bad cksum: tck %x != ck %x\n", tck, ck);
318 printf("block %d\n", tu_sc.sc_xbytes/128-1);
319 for (i = -128; i < 0; i+=16)
320 printf("%x %x %x %x\n",
321 *(int *)&bp->b_data[tu_sc.sc_xbytes+i],
322 *(int *)&bp->b_data[tu_sc.sc_xbytes+i+4],
323 *(int *)&bp->b_data[tu_sc.sc_xbytes+i+8],
324 *(int *)&bp->b_data[tu_sc.sc_xbytes+i+12]);
325 #endif
326 goto bad;
327 }
328 bp->b_resid = 0;
329 if (bp->b_bcount == tu_sc.sc_xbytes)
330 tu_sc.sc_state = TU_ENDPACKET;
331 return;
332
333 case TU_ENDPACKET:
334 if (status != RSP_TYP_COMMAND) {
335 #ifdef TUDEBUG
336 int g[14], j;
337 g[0] = status;
338 for (i = 1; i < 14; i++)
339 if ((g[i] = readchr()) < 0)
340 break;
341 j=0; while (readchr() >= 0)
342 j++;
343 for (i = 0; i < 14; i++)
344 printf("%d: %x\n", i, g[i]);
345 printf("Got %d char more\n", j);
346 printf("error: state %d xbytes %d status %d\n",
347 tu_sc.sc_state, tu_sc.sc_xbytes, status);
348 #endif
349
350 bp->b_error = EIO;
351 }
352 tu_sc.sc_wto = 0;
353 for (i = 0; i < 13; i++) {
354 if ((c = readchr()) < 0) {
355 #ifdef TUDEBUG
356 printf("Timeout epack %d\n", i);
357 #endif
358 goto bad;
359 }
360 if ((i == 2) &&
361 ((c != RSP_MOD_OK) && (c != RSP_MOD_RETR))) {
362 #ifdef TUDEBUG
363 printf("end packet status bad: %d\n", c);
364 #endif
365 bp->b_error = EIO;
366 }
367 }
368 break;
369
370 case TU_WRITING:
371 #define WAIT while ((mfpr(PR_CSTS) & 0x80) == 0)
372
373 if (status != RSP_TYP_CONTINUE)
374 goto bad;
375 #ifdef TUDEBUG
376 printf("Writing byte %d\n", tu_sc.sc_xbytes);
377 #endif
378 WAIT;
379 mtpr(RSP_TYP_DATA, PR_CSTD);
380 WAIT;
381 mtpr(128, PR_CSTD);
382 for (i = 0; i < 128; i++) {
383 WAIT;
384 mtpr(buf[tu_sc.sc_xbytes++], PR_CSTD);
385 }
386 tck = ctu_cksum((void *)&buf[tu_sc.sc_xbytes-128], 64);
387 tck += 0x8001; if (tck > 0xffff) tck -= 0xffff;
388 WAIT;
389 mtpr(tck & 0xff, PR_CSTD);
390 WAIT;
391 mtpr((tck >> 8) & 0xff, PR_CSTD);
392 bp->b_resid = 0;
393 if (tu_sc.sc_xbytes == bp->b_bcount)
394 tu_sc.sc_state = TU_ENDPACKET;
395 return;
396 #undef WAIT
397
398 case TU_RESTART:
399 if (status != RSP_TYP_CONTINUE)
400 goto bad;
401 ctustart();
402 return;
403
404 default:
405 printf("bad rx state %d char %d\n", tu_sc.sc_state, status);
406 return;
407 }
408 if (bp->b_error == 0) {
409 (void)bufq_get(tu_sc.sc_bufq);
410 biodone(bp);
411 #ifdef TUDEBUG
412 printf("biodone %p\n", bp);
413 #endif
414 }
415 #ifdef TUDEBUG
416 else {
417 printf("error: state %d xbytes %d status %d\n",
418 tu_sc.sc_state, tu_sc.sc_xbytes, status);
419 }
420 #endif
421 bp->b_error = 0;
422 tu_sc.sc_state = TU_IDLE;
423 ctustart();
424 return;
425
426 bad: tu_sc.sc_state = TU_RESTART;
427 ctuinit();
428 }
429
430 void
ctutintr(void * arg)431 ctutintr(void *arg)
432 {
433 while ((mfpr(PR_CSTS) & 0x80) == 0)
434 ;
435 switch (tu_sc.sc_state) {
436 case TU_RESET:
437 switch (tu_sc.sc_step) {
438 case 0:
439 case 1:
440 mtpr(0, PR_CSTD);
441 break;
442 case 2:
443 case 3:
444 mtpr(RSP_TYP_INIT, PR_CSTD);
445 break;
446 default:
447 break;
448 }
449 tu_sc.sc_step++;
450 return;
451
452 case TU_WORKING:
453 if (tu_sc.sc_step == 14) {
454 if (tu_sc.sc_op == RSP_OP_READ)
455 tu_sc.sc_state = TU_READING;
456 else
457 tu_sc.sc_state = TU_WRITING;
458 } else
459 mtpr(tu_sc.sc_rsp[tu_sc.sc_step++], PR_CSTD);
460 return;
461
462 case TU_IDLE:
463 printf("Idle interrupt\n");
464 return;
465
466 case TU_ENDPACKET:
467 case TU_WRITING:
468 case TU_RESTART:
469 return;
470
471 default:
472 printf("bad tx state %d\n", tu_sc.sc_state);
473 }
474 }
475
476 unsigned short
ctu_cksum(unsigned short * buf,int words)477 ctu_cksum(unsigned short *buf, int words)
478 {
479 int i, cksum;
480
481 for (i = cksum = 0; i < words; i++)
482 cksum += buf[i];
483
484 hej: if (cksum > 65535) {
485 cksum = (cksum & 65535) + (cksum >> 16);
486 goto hej;
487 }
488 return cksum;
489 }
490
491 int oldtp;
492
493 /*
494 * Watch so that we don't get blocked unnecessary due to lost int's.
495 */
496 void
ctuwatch(void * arg)497 ctuwatch(void *arg)
498 {
499
500 callout_reset(&ctu_watch_ch, hz, ctuwatch, NULL);
501
502 if (tu_sc.sc_state == TU_WORKING) {
503 /*
504 * Died in sending command.
505 * Wait 5 secs.
506 */
507 if (tu_sc.sc_wto++ > 5) {
508 #ifdef TUDEBUG
509 printf("Died in sending command\n");
510 #endif
511 tu_sc.sc_state = TU_RESTART;
512 ctuinit();
513 }
514 }
515 if (tu_sc.sc_state == TU_READING || tu_sc.sc_state == TU_WRITING) {
516 /*
517 * Positioning, may take long time.
518 * Wait one minute.
519 */
520 if (tu_sc.sc_wto++ > 60) {
521 #ifdef TUDEBUG
522 printf("Died in Positioning, wto %d\n", tu_sc.sc_wto);
523 #endif
524 tu_sc.sc_state = TU_RESTART;
525 ctuinit();
526 }
527 }
528 }
529