Home | History | Annotate | Line # | Download | only in vax
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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