xref: /netbsd-src/sys/arch/vax/vax/ctu.c (revision e5fbc36ada28f9b9a5836ecffaf4a06aa1ebb687)
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