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