xref: /netbsd/sys/arch/vax/vax/ctu.c (revision bf9ec67e)
1 /*	$NetBSD: ctu.c,v 1.14 2001/05/14 14:43:45 ragge 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/param.h>
43 #include <sys/systm.h>
44 #include <sys/callout.h>
45 #include <sys/kernel.h>
46 #include <sys/buf.h>
47 #include <sys/fcntl.h>
48 #include <sys/malloc.h>
49 #include <sys/ioctl.h>
50 #include <sys/device.h>
51 #include <sys/proc.h>
52 #include <sys/conf.h>
53 
54 #include <machine/mtpr.h>
55 #include <machine/rsp.h>
56 #include <machine/scb.h>
57 #include <machine/trap.h>
58 
59 #undef TUDEBUG
60 
61 #define	TU_IDLE		0
62 #define	TU_RESET	1
63 #define	TU_RUNNING	2
64 #define	TU_WORKING	3
65 #define TU_READING	4
66 #define TU_WRITING	5
67 #define	TU_ENDPACKET	6
68 #define	TU_RESTART	7
69 
70 struct tu_softc {
71 	int	sc_state;
72 	int	sc_step;
73 	char	sc_rsp[15];	/* Should be struct rsb; but don't work */
74 	int	sc_tpblk;	/* Start block number */
75 	int 	sc_wto;		/* Timeout counter */
76 	int	sc_xbytes;	/* Number of xfer'd bytes */
77 	int	sc_op;		/* Read/write */
78 	struct	buf_queue sc_bufq;	/* pending I/O requests */
79 } tu_sc;
80 
81 struct	ivec_dsp tu_recv, tu_xmit;
82 
83 	void ctuattach(void);
84 static	void ctutintr(void *);
85 static	void cturintr(void *);
86 static	void ctustart(void);
87 static	void ctuwatch(void *);
88 static	u_short ctu_cksum(unsigned short *, int);
89 
90 bdev_decl(ctu);
91 
92 static struct callout ctu_watch_ch = CALLOUT_INITIALIZER;
93 
94 void
95 ctuattach()
96 {
97 	BUFQ_INIT(&tu_sc.sc_bufq);
98 
99 	tu_recv = idsptch;
100 	tu_recv.hoppaddr = cturintr;
101 	scb->scb_csrint = (void *)&tu_recv;
102 
103 	tu_xmit = idsptch;
104 	tu_xmit.hoppaddr = ctutintr;
105 	scb->scb_cstint = (void *)&tu_xmit;
106 }
107 
108 static void
109 ctuinit(void)
110 {
111 	int s = spl7();
112 #define	WAIT	while ((mfpr(PR_CSTS) & 0x80) == 0)
113 
114 	/*
115 	 * Do a reset as described in the
116 	 * "TU58 DECtape II Users Guide".
117 	 */
118 	mtpr(0101, PR_CSTS);	/* Enable transmit interrupt + send break */
119 	WAIT;
120 	mtpr(0, PR_CSTD); WAIT;
121 	mtpr(0, PR_CSTD); WAIT;
122 	mtpr(RSP_TYP_INIT, PR_CSTD); WAIT;
123 	mtpr(RSP_TYP_INIT, PR_CSTD); WAIT;
124 #undef	WAIT
125 	splx(s);
126 }
127 
128 int
129 ctuopen(dev_t dev, int oflags, int devtype, struct proc *p)
130 {
131 	int error;
132 
133 	if (minor(dev))
134 		return ENXIO;
135 
136 	if (tu_sc.sc_state != TU_IDLE)
137 		return EBUSY;
138 
139 	tu_sc.sc_state = TU_RESET;
140 	tu_sc.sc_step = 0;
141 	mtpr(0100, PR_CSRS);	/* Enable receive interrupt */
142 	mtpr(0101, PR_CSTS);	/* Enable transmit interrupt + send break */
143 	if ((error = tsleep((caddr_t)&tu_sc, (PZERO + 10)|PCATCH, "reset", 0)))
144 		return error;
145 
146 #ifdef TUDEBUG
147 	printf("ctuopen: running\n");
148 #endif
149 	tu_sc.sc_state = TU_RUNNING;
150 	callout_reset(&ctu_watch_ch, hz, ctuwatch, NULL);
151 	return 0;
152 
153 }
154 
155 int
156 ctuclose(dev_t dev, int oflags, int devtype, struct proc *p)
157 {
158 	struct buf *bp;
159 	int s = spl7();
160 	while ((bp = BUFQ_FIRST(&tu_sc.sc_bufq)))
161 		BUFQ_REMOVE(&tu_sc.sc_bufq, bp);
162 	splx(s);
163 
164 	mtpr(0, PR_CSRS);
165 	mtpr(0, PR_CSTS);
166 	tu_sc.sc_state = TU_IDLE;
167 	callout_stop(&ctu_watch_ch);
168 	return 0;
169 }
170 
171 void
172 ctustrategy(struct buf *bp)
173 {
174 	int s, empty;
175 
176 #ifdef TUDEBUG
177 	printf("ctustrategy: bcount %ld blkno %d\n", bp->b_bcount, bp->b_blkno);
178 	printf("ctustrategy: bp %p\n", bp);
179 #endif
180 	if (bp->b_blkno >= 512) {
181 		bp->b_resid = bp->b_bcount;
182 		return biodone(bp);
183 	}
184 
185 	s = spl7();
186 	empty = TAILQ_EMPTY(&tu_sc.sc_bufq.bq_head);
187 	BUFQ_INSERT_TAIL(&tu_sc.sc_bufq, bp);
188 	if (empty)
189 		ctustart();
190 	splx(s);
191 }
192 
193 void
194 ctustart()
195 {
196 	struct rsp *rsp = (struct rsp *)tu_sc.sc_rsp;
197 	struct buf *bp;
198 
199 	bp = BUFQ_FIRST(&tu_sc.sc_bufq);
200 	if (bp == NULL)
201 		return;
202 #ifdef TUDEBUG
203 	printf("ctustart: %s\n", bp->b_flags & B_READ ? "READING":"WRITING");
204 #endif
205 	tu_sc.sc_tpblk = bp->b_blkno;
206 	tu_sc.sc_xbytes = 0;
207 	tu_sc.sc_op = bp->b_flags & B_READ ? RSP_OP_READ : RSP_OP_WRITE;
208 	tu_sc.sc_step = 0;
209 	bp->b_resid = bp->b_bcount;
210 	tu_sc.sc_wto = 0;
211 
212 	rsp->rsp_typ = RSP_TYP_COMMAND;
213 	rsp->rsp_sz = 012;
214 	rsp->rsp_op = tu_sc.sc_op;
215 	rsp->rsp_mod = 0;
216 	rsp->rsp_drv = 0;
217 	rsp->rsp_sw = rsp->rsp_xx1 = rsp->rsp_xx2 = 0;
218 	rsp->rsp_cnt = bp->b_bcount;
219 	rsp->rsp_blk = tu_sc.sc_tpblk;
220 	rsp->rsp_sum = ctu_cksum((unsigned short *)rsp, 6);
221 	tu_sc.sc_state = TU_WORKING;
222 	ctutintr(NULL);
223 }
224 
225 int
226 ctuioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
227 {
228 	return ENOTTY;
229 }
230 
231 /*
232  * Not bloody likely...
233  */
234 int
235 ctudump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
236 {
237 	return 0;
238 }
239 
240 static int
241 readchr(void)
242 {
243 	int i;
244 
245 	for (i = 0; i < 5000; i++)
246 		if ((mfpr(PR_CSRS) & 0x80))
247 			break;
248 	if (i == 5000)
249 		return -1;
250 	return mfpr(PR_CSRD);
251 }
252 
253 /*
254  * Loop in a tight (busy-wait-)loop when receiving packets, this is
255  * the only way to avoid loosing characters.
256  */
257 void
258 cturintr(void *arg)
259 {
260 	int status = mfpr(PR_CSRD);
261 	struct	buf *bp;
262 	int i, c, tck;
263 	unsigned short ck;
264 
265 	bp = BUFQ_FIRST(&tu_sc.sc_bufq);
266 	switch (tu_sc.sc_state) {
267 	case TU_RESET:
268 		if (status != RSP_TYP_CONTINUE)
269 			printf("Bad response %d\n", status);
270 		wakeup(&tu_sc);
271 		return;
272 
273 	case TU_READING:
274 		if (status != RSP_TYP_DATA)
275 			bp->b_flags |= B_ERROR;
276 		tu_sc.sc_wto = 0;
277 		for (i = 0; i < 131; i++) {
278 			if ((c = readchr()) < 0) {
279 #ifdef TUDEBUG
280 				printf("Timeout...%d\n", i);
281 #endif
282 				goto bad;
283 			}
284 			if ((i > 0) && (i < 129))
285 				bp->b_data[tu_sc.sc_xbytes++] = c;
286 			if (i == 129)
287 				ck = (c & 0xff);
288 			if (i == 130)
289 				ck |= ((c & 0xff) << 8);
290 		}
291 		tck = ctu_cksum((void *)&bp->b_data[tu_sc.sc_xbytes-128], 64);
292 		tck += 0x8001; if (tck > 0xffff) tck -= 0xffff;
293 		if (tck != ck) {
294 #ifdef TUDEBUG
295 			int i;
296 			printf("Bad cksum: tck %x != ck %x\n", tck, ck);
297 			printf("block %d\n", tu_sc.sc_xbytes/128-1);
298 			for (i = -128; i < 0; i+=16)
299 				printf("%x %x %x %x\n",
300 				    *(int *)&bp->b_data[tu_sc.sc_xbytes+i],
301 				    *(int *)&bp->b_data[tu_sc.sc_xbytes+i+4],
302 				    *(int *)&bp->b_data[tu_sc.sc_xbytes+i+8],
303 				    *(int *)&bp->b_data[tu_sc.sc_xbytes+i+12]);
304 #endif
305 			goto bad;
306 		}
307 		bp->b_resid = 0;
308 		if (bp->b_bcount == tu_sc.sc_xbytes)
309 			tu_sc.sc_state = TU_ENDPACKET;
310 		return;
311 
312 	case TU_ENDPACKET:
313 		if (status != RSP_TYP_COMMAND) {
314 #ifdef TUDEBUG
315 			int g[14], j;
316 			g[0] = status;
317 			for (i = 1; i < 14; i++)
318 				if ((g[i] = readchr()) < 0)
319 					break;
320 			j=0; while (readchr() >= 0)
321 				j++;
322 			for (i = 0; i < 14; i++)
323 				printf("%d: %x\n", i, g[i]);
324 			printf("Got %d char more\n", j);
325 			printf("error: state %d xbytes %d status %d\n",
326 			    tu_sc.sc_state, tu_sc.sc_xbytes, status);
327 #endif
328 
329 			bp->b_flags |= B_ERROR;
330 		}
331 		tu_sc.sc_wto = 0;
332 		for (i = 0; i < 13; i++) {
333 			if ((c = readchr()) < 0) {
334 #ifdef TUDEBUG
335 				printf("Timeout epack %d\n", i);
336 #endif
337 				goto bad;
338 			}
339 			if ((i == 2) &&
340 			    ((c != RSP_MOD_OK) && (c != RSP_MOD_RETR))) {
341 #ifdef TUDEBUG
342 				printf("end packet status bad: %d\n", c);
343 #endif
344 				bp->b_flags |= B_ERROR;
345 			}
346 		}
347 		break;
348 
349 	case TU_WRITING:
350 #define	WAIT	while ((mfpr(PR_CSTS) & 0x80) == 0)
351 
352 		if (status != RSP_TYP_CONTINUE)
353 			goto bad;
354 #ifdef TUDEBUG
355 		printf("Writing byte %d\n", tu_sc.sc_xbytes);
356 #endif
357 		WAIT; mtpr(RSP_TYP_DATA, PR_CSTD);
358 		WAIT; mtpr(128, PR_CSTD);
359 		for (i = 0; i < 128; i++) {
360 			WAIT;
361 			mtpr(bp->b_data[tu_sc.sc_xbytes++], PR_CSTD);
362 		}
363 		tck = ctu_cksum((void *)&bp->b_data[tu_sc.sc_xbytes-128], 64);
364 		tck += 0x8001; if (tck > 0xffff) tck -= 0xffff;
365 		WAIT; mtpr(tck & 0xff, PR_CSTD);
366 		WAIT; mtpr((tck >> 8) & 0xff, PR_CSTD);
367 		bp->b_resid = 0;
368 		if (tu_sc.sc_xbytes == bp->b_bcount)
369 			tu_sc.sc_state = TU_ENDPACKET;
370 		return;
371 #undef WAIT
372 
373 	case TU_RESTART:
374 		if (status != RSP_TYP_CONTINUE)
375 			goto bad;
376 		ctustart();
377 		return;
378 
379 	default:
380 		printf("bad rx state %d char %d\n", tu_sc.sc_state, status);
381 		return;
382 	}
383 	if ((bp->b_flags & B_ERROR) == 0) {
384 		BUFQ_REMOVE(&tu_sc.sc_bufq, bp);
385 		biodone(bp);
386 #ifdef TUDEBUG
387 		printf("biodone %p\n", bp);
388 #endif
389 	}
390 #ifdef TUDEBUG
391 	  else {
392 		printf("error: state %d xbytes %d status %d\n",
393 		    tu_sc.sc_state, tu_sc.sc_xbytes, status);
394 	}
395 #endif
396 	bp->b_flags &= ~B_ERROR;
397 	tu_sc.sc_state = TU_IDLE;
398 	ctustart();
399 	return;
400 
401 bad:	tu_sc.sc_state = TU_RESTART;
402 	ctuinit();
403 }
404 
405 void
406 ctutintr(void *arg)
407 {
408 	while ((mfpr(PR_CSTS) & 0x80) == 0)
409 		;
410 	switch (tu_sc.sc_state) {
411 	case TU_RESET:
412 		switch (tu_sc.sc_step) {
413 		case 0:
414 		case 1:
415 			mtpr(0, PR_CSTD);
416 			break;
417 		case 2:
418 		case 3:
419 			mtpr(RSP_TYP_INIT, PR_CSTD);
420 			break;
421 		default:
422 			break;
423 		}
424 		tu_sc.sc_step++;
425 		return;
426 
427 	case TU_WORKING:
428 		if (tu_sc.sc_step == 14) {
429 			if (tu_sc.sc_op == RSP_OP_READ)
430 				tu_sc.sc_state = TU_READING;
431 			else
432 				tu_sc.sc_state = TU_WRITING;
433 		} else
434 			mtpr(tu_sc.sc_rsp[tu_sc.sc_step++], PR_CSTD);
435 		return;
436 
437 	case TU_IDLE:
438 		printf("Idle interrupt\n");
439 		return;
440 
441 	case TU_ENDPACKET:
442 	case TU_WRITING:
443 	case TU_RESTART:
444 		return;
445 
446 	default:
447 		printf("bad tx state %d\n", tu_sc.sc_state);
448 	}
449 }
450 
451 unsigned short
452 ctu_cksum(unsigned short *buf, int words)
453 {
454 	int i, cksum;
455 
456 	for (i = cksum = 0; i < words; i++)
457 		cksum += buf[i];
458 
459 hej:	if (cksum > 65535) {
460 		cksum = (cksum & 65535) + (cksum >> 16);
461 		goto hej;
462 	}
463 	return cksum;
464 }
465 
466 int	oldtp;
467 
468 /*
469  * Watch so that we don't get blocked unnecessary due to lost int's.
470  */
471 void
472 ctuwatch(void *arg)
473 {
474 
475 	callout_reset(&ctu_watch_ch, hz, ctuwatch, NULL);
476 
477 	if (tu_sc.sc_state == TU_WORKING) {
478 		/*
479 		 * Died in sending command.
480 		 * Wait 5 secs.
481 		 */
482 		if (tu_sc.sc_wto++ > 5) {
483 #ifdef TUDEBUG
484 			printf("Died in sending command\n");
485 #endif
486 			tu_sc.sc_state = TU_RESTART;
487 			ctuinit();
488 		}
489 	}
490 	if (tu_sc.sc_state == TU_READING || tu_sc.sc_state == TU_WRITING) {
491 		/*
492 		 * Positioning, may take long time.
493 		 * Wait one minute.
494 		 */
495 		if (tu_sc.sc_wto++ > 60) {
496 #ifdef TUDEBUG
497 			printf("Died in Positioning, wto %d\n", tu_sc.sc_wto);
498 #endif
499 			tu_sc.sc_state = TU_RESTART;
500 			ctuinit();
501 		}
502 	}
503 }
504