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