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