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