1/* $NetBSD: ct.c,v 1.56 2008/06/17 19:46:23 he Exp $ */ 2 3/*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 1982, 1990, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)ct.c 8.2 (Berkeley) 1/12/94 61 */ 62 63/* 64 * CS80 cartridge tape driver (9144, 88140, 9145) 65 * 66 * Reminder: 67 * C_CC bit (character count option) when used in the CS/80 command 68 * 'set options' will cause the tape not to stream. 69 * 70 * TODO: 71 * make filesystem compatible 72 * make block mode work according to mtio(4) spec. (if possible) 73 * merge with cs80 disk driver 74 * finish support of 9145 75 */ 76 77#include <sys/cdefs.h> 78__KERNEL_RCSID(0, "$NetBSD: ct.c,v 1.56 2008/06/17 19:46:23 he Exp $"); 79 80#include <sys/param.h> 81#include <sys/systm.h> 82#include <sys/buf.h> 83#include <sys/bufq.h> 84#include <sys/conf.h> 85#include <sys/device.h> 86#include <sys/ioctl.h> 87#include <sys/mtio.h> 88#include <sys/proc.h> 89#include <sys/tprintf.h> 90 91#include <hp300/dev/hpibvar.h> 92 93#include <hp300/dev/ctreg.h> 94 95#include "ioconf.h" 96 97/* number of eof marks to remember */ 98#define EOFS 128 99 100struct ct_softc { 101 device_t sc_dev; 102 int sc_slave; /* HP-IB slave ID */ 103 int sc_punit; /* physical unit */ 104 struct ct_iocmd sc_ioc; 105 struct ct_rscmd sc_rsc; 106 struct ct_stat sc_stat; 107 struct ct_ssmcmd sc_ssmc; 108 struct ct_srcmd sc_src; 109 struct ct_soptcmd sc_soptc; 110 struct ct_ulcmd sc_ul; 111 struct ct_wfmcmd sc_wfm; 112 struct ct_clearcmd sc_clear; 113 struct bufq_state *sc_tab; 114 int sc_active; 115 struct buf *sc_bp; 116 struct buf sc_bufstore; /* XXX */ 117 int sc_blkno; 118 int sc_cmd; 119 int sc_resid; 120 char *sc_addr; 121 int sc_flags; 122 short sc_type; 123 tpr_t sc_tpr; 124 struct hpibqueue sc_hq; /* entry on hpib job queue */ 125 int sc_eofp; 126 int sc_eofs[EOFS]; 127}; 128 129/* flags */ 130#define CTF_OPEN 0x01 131#define CTF_ALIVE 0x02 132#define CTF_WRT 0x04 133#define CTF_CMD 0x08 134#define CTF_IO 0x10 135#define CTF_BEOF 0x20 136#define CTF_AEOF 0x40 137#define CTF_EOT 0x80 138#define CTF_STATWAIT 0x100 139#define CTF_CANSTREAM 0x200 140#define CTF_WRTTN 0x400 141 142static int ctmatch(device_t, cfdata_t, void *); 143static void ctattach(device_t, device_t, void *); 144 145CFATTACH_DECL_NEW(ct, sizeof(struct ct_softc), 146 ctmatch, ctattach, NULL, NULL); 147 148static dev_type_open(ctopen); 149static dev_type_close(ctclose); 150static dev_type_read(ctread); 151static dev_type_write(ctwrite); 152static dev_type_ioctl(ctioctl); 153static dev_type_strategy(ctstrategy); 154 155const struct bdevsw ct_bdevsw = { 156 ctopen, ctclose, ctstrategy, ctioctl, nodump, nosize, D_TAPE 157}; 158 159const struct cdevsw ct_cdevsw = { 160 ctopen, ctclose, ctread, ctwrite, ctioctl, 161 nostop, notty, nopoll, nommap, nokqfilter, D_TAPE 162}; 163 164static int ctident(device_t, struct ct_softc *, 165 struct hpibbus_attach_args *); 166 167static void ctreset(struct ct_softc *); 168static void ctaddeof(struct ct_softc *); 169static void ctustart(struct ct_softc *); 170static void cteof(struct ct_softc *, struct buf *); 171static void ctdone(struct ct_softc *, struct buf *); 172 173static void ctstart(void *); 174static void ctgo(void *); 175static void ctintr(void *); 176 177static void ctcommand(dev_t, int, int); 178 179static const struct ctinfo { 180 short hwid; 181 short punit; 182 const char *desc; 183} ctinfo[] = { 184 { CT7946ID, 1, "7946A" }, 185 { CT7912PID, 1, "7912P" }, 186 { CT7914PID, 1, "7914P" }, 187 { CT9144ID, 0, "9144" }, 188 { CT9145ID, 0, "9145" }, 189 { CT35401ID, 0, "35401A"}, 190}; 191static const int nctinfo = __arraycount(ctinfo); 192 193#define CT_NOREW 4 194#define CT_STREAM 8 195#define UNIT(x) (minor(x) & 3) 196#define ctpunit(x) ((x) & 7) 197 198#ifdef DEBUG 199int ctdebug = 0; 200#define CDB_FILES 0x01 201#define CT_BSF 0x02 202#endif 203 204static int 205ctmatch(device_t parent, cfdata_t cf, void *aux) 206{ 207 struct hpibbus_attach_args *ha = aux; 208 209 return ctident(parent, NULL, ha); 210} 211 212static void 213ctattach(device_t parent, device_t self, void *aux) 214{ 215 struct ct_softc *sc = device_private(self); 216 struct hpibbus_attach_args *ha = aux; 217 218 sc->sc_dev = self; 219 if (ctident(parent, sc, ha) == 0) { 220 aprint_error(": didn't respond to describe command!\n"); 221 return; 222 } 223 224 sc->sc_slave = ha->ha_slave; 225 sc->sc_punit = ha->ha_punit; 226 227 bufq_alloc(&sc->sc_tab, "fcfs", 0); 228 229 /* Initialize hpib job queue entry. */ 230 sc->sc_hq.hq_softc = sc; 231 sc->sc_hq.hq_slave = sc->sc_slave; 232 sc->sc_hq.hq_start = ctstart; 233 sc->sc_hq.hq_go = ctgo; 234 sc->sc_hq.hq_intr = ctintr; 235 236 ctreset(sc); 237 sc->sc_flags |= CTF_ALIVE; 238} 239 240static int 241ctident(device_t parent, struct ct_softc *sc, struct hpibbus_attach_args *ha) 242{ 243 struct ct_describe desc; 244 u_char stat, cmd[3]; 245 char name[7]; 246 int i, id, n, type, canstream; 247 248 type = canstream = 0; 249 250 /* Verify that we have a CS80 device. */ 251 if ((ha->ha_id & 0x200) == 0) 252 return 0; 253 254 /* Is it one of the tapes we support? */ 255 for (id = 0; id < nctinfo; id++) 256 if (ha->ha_id == ctinfo[id].hwid) 257 break; 258 if (id == nctinfo) 259 return 0; 260 261 ha->ha_punit = ctinfo[id].punit; 262 263 /* 264 * So far, so good. Get drive parameters. Note command 265 * is always issued to unit 0. 266 */ 267 cmd[0] = C_SUNIT(0); 268 cmd[1] = C_SVOL(0); 269 cmd[2] = C_DESC; 270 hpibsend(device_unit(parent), ha->ha_slave, C_CMD, cmd, sizeof(cmd)); 271 hpibrecv(device_unit(parent), ha->ha_slave, C_EXEC, &desc, 37); 272 hpibrecv(device_unit(parent), ha->ha_slave, C_QSTAT, &stat, 273 sizeof(stat)); 274 275 memset(name, 0, sizeof(name)); 276 if (stat == 0) { 277 n = desc.d_name; 278 for (i = 5; i >= 0; i--) { 279 name[i] = (n & 0xf) + '0'; 280 n >>= 4; 281 } 282 } 283 284 switch (ha->ha_id) { 285 case CT7946ID: 286 if (memcmp(name, "079450", 6) == 0) 287 return 0; /* not really a 7946 */ 288 /* fall into... */ 289 case CT9144ID: 290 case CT9145ID: 291 case CT35401ID: 292 type = CT9144; 293 canstream = 1; 294 break; 295 296 case CT7912PID: 297 case CT7914PID: 298 type = CT88140; 299 break; 300 } 301 302 if (sc != NULL) { 303 sc->sc_type = type; 304 sc->sc_flags = canstream ? CTF_CANSTREAM : 0; 305 aprint_normal(": %s %stape\n", ctinfo[id].desc, 306 canstream ? "streaming " : ""); 307 } 308 309 return 1; 310} 311 312static void 313ctreset(struct ct_softc *sc) 314{ 315 int ctlr, slave; 316 uint8_t stat; 317 318 ctlr = device_unit(device_parent(sc->sc_dev)); 319 slave = sc->sc_slave; 320 321 sc->sc_clear.unit = C_SUNIT(sc->sc_punit); 322 sc->sc_clear.cmd = C_CLEAR; 323 hpibsend(ctlr, slave, C_TCMD, &sc->sc_clear, sizeof(sc->sc_clear)); 324 hpibswait(ctlr, slave); 325 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 326 327 sc->sc_src.unit = C_SUNIT(CTCTLR); 328 sc->sc_src.nop = C_NOP; 329 sc->sc_src.cmd = C_SREL; 330 sc->sc_src.param = C_REL; 331 hpibsend(ctlr, slave, C_CMD, &sc->sc_src, sizeof(sc->sc_src)); 332 hpibswait(ctlr, slave); 333 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 334 335 sc->sc_ssmc.unit = C_SUNIT(sc->sc_punit); 336 sc->sc_ssmc.cmd = C_SSM; 337 sc->sc_ssmc.refm = REF_MASK; 338 sc->sc_ssmc.fefm = FEF_MASK; 339 sc->sc_ssmc.aefm = AEF_MASK; 340 sc->sc_ssmc.iefm = IEF_MASK; 341 hpibsend(ctlr, slave, C_CMD, &sc->sc_ssmc, sizeof(sc->sc_ssmc)); 342 hpibswait(ctlr, slave); 343 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 344 345 sc->sc_soptc.unit = C_SUNIT(sc->sc_punit); 346 sc->sc_soptc.nop = C_NOP; 347 sc->sc_soptc.cmd = C_SOPT; 348 sc->sc_soptc.opt = C_SPAR; 349 hpibsend(ctlr, slave, C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc)); 350 hpibswait(ctlr, slave); 351 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 352} 353 354/*ARGSUSED*/ 355static int 356ctopen(dev_t dev, int flag, int type, struct lwp *l) 357{ 358 struct ct_softc *sc; 359 uint8_t stat; 360 int cc, ctlr, slave; 361 362 sc = device_lookup_private(&ct_cd, UNIT(dev)); 363 if (sc == NULL) 364 return ENXIO; 365 366 if ((sc->sc_flags & CTF_ALIVE) == 0) 367 return ENXIO; 368 369 if (sc->sc_flags & CTF_OPEN) 370 return EBUSY; 371 372 ctlr = device_unit(device_parent(sc->sc_dev)); 373 slave = sc->sc_slave; 374 375 sc->sc_soptc.unit = C_SUNIT(sc->sc_punit); 376 sc->sc_soptc.nop = C_NOP; 377 sc->sc_soptc.cmd = C_SOPT; 378 if ((dev & CT_STREAM) && (sc->sc_flags & CTF_CANSTREAM)) 379 sc->sc_soptc.opt = C_SPAR | C_IMRPT; 380 else 381 sc->sc_soptc.opt = C_SPAR; 382 383 /* 384 * Check the return of hpibsend() and hpibswait(). 385 * Drive could be loading/unloading a tape. If not checked, 386 * driver hangs. 387 */ 388 cc = hpibsend(ctlr, slave, C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc)); 389 if (cc != sizeof(sc->sc_soptc)) 390 return EBUSY; 391 392 hpibswait(ctlr, slave); 393 cc = hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 394 if (cc != sizeof(stat)) 395 return EBUSY; 396 397 sc->sc_tpr = tprintf_open(l->l_proc); 398 sc->sc_flags |= CTF_OPEN; 399 return 0; 400} 401 402/*ARGSUSED*/ 403static int 404ctclose(dev_t dev, int flag, int fmt, struct lwp *l) 405{ 406 struct ct_softc *sc = device_lookup_private(&ct_cd,UNIT(dev)); 407 408 if ((sc->sc_flags & (CTF_WRT|CTF_WRTTN)) == (CTF_WRT|CTF_WRTTN) && 409 (sc->sc_flags & CTF_EOT) == 0 ) { /* XXX return error if EOT ?? */ 410 ctcommand(dev, MTWEOF, 2); 411 ctcommand(dev, MTBSR, 1); 412 if (sc->sc_eofp == EOFS - 1) 413 sc->sc_eofs[EOFS - 1]--; 414 else 415 sc->sc_eofp--; 416#ifdef DEBUG 417 if(ctdebug & CT_BSF) 418 printf("%s: ctclose backup eofs prt %d blk %d\n", 419 device_xname(sc->sc_dev), sc->sc_eofp, 420 sc->sc_eofs[sc->sc_eofp]); 421#endif 422 } 423 if ((minor(dev) & CT_NOREW) == 0) 424 ctcommand(dev, MTREW, 1); 425 sc->sc_flags &= ~(CTF_OPEN | CTF_WRT | CTF_WRTTN); 426 tprintf_close(sc->sc_tpr); 427#ifdef DEBUG 428 if (ctdebug & CDB_FILES) 429 printf("ctclose: flags %x\n", sc->sc_flags); 430#endif 431 return 0; /* XXX */ 432} 433 434static void 435ctcommand(dev_t dev, int cmd, int cnt) 436{ 437 struct ct_softc *sc = device_lookup_private(&ct_cd,UNIT(dev)); 438 struct buf *bp = &sc->sc_bufstore; 439 struct buf *nbp = 0; 440 441 if (cmd == MTBSF && sc->sc_eofp == EOFS - 1) { 442 cnt = sc->sc_eofs[EOFS - 1] - cnt; 443 ctcommand(dev, MTREW, 1); 444 ctcommand(dev, MTFSF, cnt); 445 cnt = 2; 446 cmd = MTBSR; 447 } 448 449 if (cmd == MTBSF && sc->sc_eofp - cnt < 0) { 450 cnt = 1; 451 cmd = MTREW; 452 } 453 454 sc->sc_flags |= CTF_CMD; 455 sc->sc_bp = bp; 456 sc->sc_cmd = cmd; 457 bp->b_dev = dev; 458 if (cmd == MTFSF) { 459 nbp = (struct buf *)geteblk(MAXBSIZE); 460 bp->b_data = nbp->b_data; 461 bp->b_bcount = MAXBSIZE; 462 } 463 464 while (cnt-- > 0) { 465 bp->b_cflags = BC_BUSY; 466 if (cmd == MTBSF) { 467 sc->sc_blkno = sc->sc_eofs[sc->sc_eofp]; 468 sc->sc_eofp--; 469#ifdef DEBUG 470 if (ctdebug & CT_BSF) 471 printf("%s: backup eof pos %d blk %d\n", 472 device_xname(sc->sc_dev), sc->sc_eofp, 473 sc->sc_eofs[sc->sc_eofp]); 474#endif 475 } 476 ctstrategy(bp); 477 biowait(bp); 478 } 479 bp->b_flags = 0; 480 sc->sc_flags &= ~CTF_CMD; 481 if (nbp) 482 brelse(nbp, 0); 483} 484 485static void 486ctstrategy(struct buf *bp) 487{ 488 int s; 489 struct ct_softc *sc; 490 491 sc = device_lookup_private(&ct_cd, UNIT(bp->b_dev)); 492 493 s = splbio(); 494 bufq_put(sc->sc_tab, bp); 495 if (sc->sc_active == 0) { 496 sc->sc_active = 1; 497 ctustart(sc); 498 } 499 splx(s); 500} 501 502static void 503ctustart(struct ct_softc *sc) 504{ 505 struct buf *bp; 506 507 bp = bufq_peek(sc->sc_tab); 508 sc->sc_addr = bp->b_data; 509 sc->sc_resid = bp->b_bcount; 510 if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq)) 511 ctstart(sc); 512} 513 514static void 515ctstart(void *arg) 516{ 517 struct ct_softc *sc = arg; 518 struct buf *bp; 519 int i, ctlr, slave; 520 521 ctlr = device_unit(device_parent(sc->sc_dev)); 522 slave = sc->sc_slave; 523 524 bp = bufq_peek(sc->sc_tab); 525 if ((sc->sc_flags & CTF_CMD) && sc->sc_bp == bp) { 526 switch(sc->sc_cmd) { 527 case MTFSF: 528 bp->b_flags |= B_READ; 529 goto mustio; 530 531 case MTBSF: 532 goto gotaddr; 533 534 case MTOFFL: 535 sc->sc_blkno = 0; 536 sc->sc_ul.unit = C_SUNIT(sc->sc_punit); 537 sc->sc_ul.cmd = C_UNLOAD; 538 hpibsend(ctlr, slave, C_CMD, &sc->sc_ul, 539 sizeof(sc->sc_ul)); 540 break; 541 542 case MTWEOF: 543 sc->sc_blkno++; 544 sc->sc_flags |= CTF_WRT; 545 sc->sc_wfm.unit = C_SUNIT(sc->sc_punit); 546 sc->sc_wfm.cmd = C_WFM; 547 hpibsend(ctlr, slave, C_CMD, &sc->sc_wfm, 548 sizeof(sc->sc_wfm)); 549 ctaddeof(sc); 550 break; 551 552 case MTBSR: 553 sc->sc_blkno--; 554 goto gotaddr; 555 556 case MTFSR: 557 sc->sc_blkno++; 558 goto gotaddr; 559 560 case MTREW: 561 sc->sc_blkno = 0; 562#ifdef DEBUG 563 if(ctdebug & CT_BSF) 564 printf("%s: clearing eofs\n", 565 device_xname(sc->sc_dev)); 566#endif 567 for (i=0; i<EOFS; i++) 568 sc->sc_eofs[i] = 0; 569 sc->sc_eofp = 0; 570 571gotaddr: 572 sc->sc_ioc.saddr = C_SADDR; 573 sc->sc_ioc.addr0 = 0; 574 sc->sc_ioc.addr = sc->sc_blkno; 575 sc->sc_ioc.unit = C_SUNIT(sc->sc_punit); 576 sc->sc_ioc.nop2 = C_NOP; 577 sc->sc_ioc.slen = C_SLEN; 578 sc->sc_ioc.len = 0; 579 sc->sc_ioc.nop3 = C_NOP; 580 sc->sc_ioc.cmd = C_READ; 581 hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc, 582 sizeof(sc->sc_ioc)); 583 break; 584 } 585 } else { 586mustio: 587 if ((bp->b_flags & B_READ) && 588 sc->sc_flags & (CTF_BEOF|CTF_EOT)) { 589#ifdef DEBUG 590 if (ctdebug & CDB_FILES) 591 printf("ctstart: before flags %x\n", 592 sc->sc_flags); 593#endif 594 if (sc->sc_flags & CTF_BEOF) { 595 sc->sc_flags &= ~CTF_BEOF; 596 sc->sc_flags |= CTF_AEOF; 597#ifdef DEBUG 598 if (ctdebug & CDB_FILES) 599 printf("ctstart: after flags %x\n", 600 sc->sc_flags); 601#endif 602 } 603 bp->b_resid = bp->b_bcount; 604 ctdone(sc, bp); 605 return; 606 } 607 sc->sc_flags |= CTF_IO; 608 sc->sc_ioc.unit = C_SUNIT(sc->sc_punit); 609 sc->sc_ioc.saddr = C_SADDR; 610 sc->sc_ioc.addr0 = 0; 611 sc->sc_ioc.addr = sc->sc_blkno; 612 sc->sc_ioc.nop2 = C_NOP; 613 sc->sc_ioc.slen = C_SLEN; 614 sc->sc_ioc.len = sc->sc_resid; 615 sc->sc_ioc.nop3 = C_NOP; 616 if (bp->b_flags & B_READ) 617 sc->sc_ioc.cmd = C_READ; 618 else { 619 sc->sc_ioc.cmd = C_WRITE; 620 sc->sc_flags |= (CTF_WRT | CTF_WRTTN); 621 } 622 hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc, sizeof(sc->sc_ioc)); 623 } 624 hpibawait(ctlr); 625} 626 627static void 628ctgo(void *arg) 629{ 630 struct ct_softc *sc = arg; 631 struct buf *bp; 632 int rw; 633 634 bp = bufq_peek(sc->sc_tab); 635 rw = bp->b_flags & B_READ; 636 hpibgo(device_unit(device_parent(sc->sc_dev)), sc->sc_slave, C_EXEC, 637 sc->sc_addr, sc->sc_resid, rw, rw != 0); 638} 639 640/* 641 * Hideous grue to handle EOF/EOT (mostly for reads) 642 */ 643static void 644cteof(struct ct_softc *sc, struct buf *bp) 645{ 646 long blks; 647 648 /* 649 * EOT on a write is an error. 650 */ 651 if ((bp->b_flags & B_READ) == 0) { 652 bp->b_resid = bp->b_bcount; 653 bp->b_error = ENOSPC; 654 sc->sc_flags |= CTF_EOT; 655 return; 656 } 657 /* 658 * Use returned block position to determine how many blocks 659 * we really read and update b_resid. 660 */ 661 blks = sc->sc_stat.c_blk - sc->sc_blkno - 1; 662#ifdef DEBUG 663 if (ctdebug & CDB_FILES) 664 printf("cteof: bc %d oblk %d nblk %ld read %ld, resid %ld\n", 665 bp->b_bcount, sc->sc_blkno, sc->sc_stat.c_blk, 666 blks, bp->b_bcount - CTKTOB(blks)); 667#endif 668 if (blks == -1) { /* 9145 on EOF does not change sc_stat.c_blk */ 669 blks = 0; 670 sc->sc_blkno++; 671 } 672 else { 673 sc->sc_blkno = sc->sc_stat.c_blk; 674 } 675 bp->b_resid = bp->b_bcount - CTKTOB(blks); 676 /* 677 * If we are at physical EOV or were after an EOF, 678 * we are now at logical EOT. 679 */ 680 if ((sc->sc_stat.c_aef & AEF_EOV) || 681 (sc->sc_flags & CTF_AEOF)) { 682 sc->sc_flags |= CTF_EOT; 683 sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF); 684 } 685 /* 686 * If we were before an EOF or we have just completed a FSF, 687 * we are now after EOF. 688 */ 689 else if ((sc->sc_flags & CTF_BEOF) || 690 ((sc->sc_flags & CTF_CMD) && sc->sc_cmd == MTFSF)) { 691 sc->sc_flags |= CTF_AEOF; 692 sc->sc_flags &= ~CTF_BEOF; 693 } 694 /* 695 * Otherwise if we read something we are now before EOF 696 * (and no longer after EOF). 697 */ 698 else if (blks) { 699 sc->sc_flags |= CTF_BEOF; 700 sc->sc_flags &= ~CTF_AEOF; 701 } 702 /* 703 * Finally, if we didn't read anything we just passed an EOF 704 */ 705 else 706 sc->sc_flags |= CTF_AEOF; 707#ifdef DEBUG 708 if (ctdebug & CDB_FILES) 709 printf("cteof: leaving flags %x\n", sc->sc_flags); 710#endif 711} 712 713/* ARGSUSED */ 714static void 715ctintr(void *arg) 716{ 717 struct ct_softc *sc = arg; 718 struct buf *bp; 719 uint8_t stat; 720 int ctlr, slave, unit; 721 722 ctlr = device_unit(device_parent(sc->sc_dev)); 723 slave = sc->sc_slave; 724 unit = device_unit(sc->sc_dev); 725 726 bp = bufq_peek(sc->sc_tab); 727 if (bp == NULL) { 728 printf("%s: bp == NULL\n", device_xname(sc->sc_dev)); 729 return; 730 } 731 if (sc->sc_flags & CTF_IO) { 732 sc->sc_flags &= ~CTF_IO; 733 if (hpibustart(ctlr)) 734 ctgo(sc); 735 return; 736 } 737 if ((sc->sc_flags & CTF_STATWAIT) == 0) { 738 if (hpibpptest(ctlr, slave) == 0) { 739 sc->sc_flags |= CTF_STATWAIT; 740 hpibawait(ctlr); 741 return; 742 } 743 } else 744 sc->sc_flags &= ~CTF_STATWAIT; 745 hpibrecv(ctlr, slave, C_QSTAT, &stat, 1); 746#ifdef DEBUG 747 if (ctdebug & CDB_FILES) 748 printf("ctintr: before flags %x\n", sc->sc_flags); 749#endif 750 if (stat) { 751 sc->sc_rsc.unit = C_SUNIT(sc->sc_punit); 752 sc->sc_rsc.cmd = C_STATUS; 753 hpibsend(ctlr, slave, C_CMD, &sc->sc_rsc, sizeof(sc->sc_rsc)); 754 hpibrecv(ctlr, slave, C_EXEC, &sc->sc_stat, 755 sizeof(sc->sc_stat)); 756 hpibrecv(ctlr, slave, C_QSTAT, &stat, 1); 757#ifdef DEBUG 758 if (ctdebug & CDB_FILES) 759 printf("ctintr: return stat 0x%x, A%x F%x blk %ld\n", 760 stat, sc->sc_stat.c_aef, 761 sc->sc_stat.c_fef, sc->sc_stat.c_blk); 762#endif 763 if (stat == 0) { 764 if (sc->sc_stat.c_aef & (AEF_EOF | AEF_EOV)) { 765 cteof(sc, bp); 766 ctaddeof(sc); 767 goto done; 768 } 769 if (sc->sc_stat.c_fef & FEF_PF) { 770 ctreset(sc); 771 ctstart(sc); 772 return; 773 } 774 if (sc->sc_stat.c_fef & FEF_REXMT) { 775 ctstart(sc); 776 return; 777 } 778 if (sc->sc_stat.c_aef & 0x5800) { 779 if (sc->sc_stat.c_aef & 0x4000) 780 tprintf(sc->sc_tpr, 781 "%s: uninitialized media\n", 782 device_xname(sc->sc_dev)); 783 if (sc->sc_stat.c_aef & 0x1000) 784 tprintf(sc->sc_tpr, 785 "%s: not ready\n", 786 device_xname(sc->sc_dev)); 787 if (sc->sc_stat.c_aef & 0x0800) 788 tprintf(sc->sc_tpr, 789 "%s: write protect\n", 790 device_xname(sc->sc_dev)); 791 } else { 792 printf("%s err: v%d u%d ru%d bn%ld, ", 793 device_xname(sc->sc_dev), 794 (sc->sc_stat.c_vu >> 4) & 0xF, 795 sc->sc_stat.c_vu & 0xF, 796 sc->sc_stat.c_pend, 797 sc->sc_stat.c_blk); 798 printf("R0x%x F0x%x A0x%x I0x%x\n", 799 sc->sc_stat.c_ref, 800 sc->sc_stat.c_fef, 801 sc->sc_stat.c_aef, 802 sc->sc_stat.c_ief); 803 } 804 } else 805 printf("%s: request status failed\n", 806 device_xname(sc->sc_dev)); 807 bp->b_error = EIO; 808 goto done; 809 } else 810 bp->b_resid = 0; 811 if (sc->sc_flags & CTF_CMD) { 812 switch (sc->sc_cmd) { 813 case MTFSF: 814 sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF); 815 sc->sc_blkno += CTBTOK(sc->sc_resid); 816 ctstart(sc); 817 return; 818 case MTBSF: 819 sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF|CTF_EOT); 820 break; 821 case MTBSR: 822 sc->sc_flags &= ~CTF_BEOF; 823 if (sc->sc_flags & CTF_EOT) { 824 sc->sc_flags |= CTF_AEOF; 825 sc->sc_flags &= ~CTF_EOT; 826 } else if (sc->sc_flags & CTF_AEOF) { 827 sc->sc_flags |= CTF_BEOF; 828 sc->sc_flags &= ~CTF_AEOF; 829 } 830 break; 831 case MTWEOF: 832 sc->sc_flags &= ~CTF_BEOF; 833 if (sc->sc_flags & (CTF_AEOF|CTF_EOT)) { 834 sc->sc_flags |= CTF_EOT; 835 sc->sc_flags &= ~CTF_AEOF; 836 } else 837 sc->sc_flags |= CTF_AEOF; 838 break; 839 case MTREW: 840 case MTOFFL: 841 sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF|CTF_EOT); 842 break; 843 } 844 } else { 845 sc->sc_flags &= ~CTF_AEOF; 846 sc->sc_blkno += CTBTOK(sc->sc_resid); 847 } 848done: 849#ifdef DEBUG 850 if (ctdebug & CDB_FILES) 851 printf("ctintr: after flags %x\n", sc->sc_flags); 852#endif 853 ctdone(sc, bp); 854} 855 856static void 857ctdone(struct ct_softc *sc, struct buf *bp) 858{ 859 860 (void)bufq_get(sc->sc_tab); 861 biodone(bp); 862 hpibfree(device_parent(sc->sc_dev), &sc->sc_hq); 863 if (bufq_peek(sc->sc_tab) == NULL) { 864 sc->sc_active = 0; 865 return; 866 } 867 ctustart(sc); 868} 869 870static int 871ctread(dev_t dev, struct uio *uio, int flags) 872{ 873 874 return physio(ctstrategy, NULL, dev, B_READ, minphys, uio); 875} 876 877static int 878ctwrite(dev_t dev, struct uio *uio, int flags) 879{ 880 881 /* XXX: check for hardware write-protect? */ 882 return physio(ctstrategy, NULL, dev, B_WRITE, minphys, uio); 883} 884 885/*ARGSUSED*/ 886static int 887ctioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 888{ 889 struct mtop *op; 890 int cnt; 891 892 switch (cmd) { 893 894 case MTIOCTOP: 895 op = (struct mtop *)data; 896 switch(op->mt_op) { 897 898 case MTWEOF: 899 case MTFSF: 900 case MTBSR: 901 case MTBSF: 902 case MTFSR: 903 cnt = op->mt_count; 904 break; 905 906 case MTREW: 907 case MTOFFL: 908 cnt = 1; 909 break; 910 911 default: 912 return EINVAL; 913 } 914 ctcommand(dev, op->mt_op, cnt); 915 break; 916 917 case MTIOCGET: 918 break; 919 920 default: 921 return EINVAL; 922 } 923 return 0; 924} 925 926static void 927ctaddeof(struct ct_softc *sc) 928{ 929 930 if (sc->sc_eofp == EOFS - 1) 931 sc->sc_eofs[EOFS - 1]++; 932 else { 933 sc->sc_eofp++; 934 if (sc->sc_eofp == EOFS - 1) 935 sc->sc_eofs[EOFS - 1] = EOFS; 936 else 937 /* save blkno */ 938 sc->sc_eofs[sc->sc_eofp] = sc->sc_blkno - 1; 939 } 940#ifdef DEBUG 941 if (ctdebug & CT_BSF) 942 printf("%s: add eof pos %d blk %d\n", 943 device_xname(sc->sc_dev), sc->sc_eofp, 944 sc->sc_eofs[sc->sc_eofp]); 945#endif 946} 947