Annotation of sys/arch/vax/mscp/mscp_tape.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: mscp_tape.c,v 1.10 2007/06/06 17:15:13 deraadt Exp $ */
! 2: /* $NetBSD: mscp_tape.c,v 1.16 2001/11/13 07:38:28 lukem Exp $ */
! 3: /*
! 4: * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed at Ludd, University of
! 18: * Lule}, Sweden and its contributors.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34:
! 35: /*
! 36: * MSCP tape device driver
! 37: */
! 38:
! 39: /*
! 40: * TODO
! 41: * Write status handling code.
! 42: */
! 43:
! 44: #include <sys/cdefs.h>
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/device.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/buf.h>
! 50: #include <sys/ioccom.h>
! 51: #include <sys/mtio.h>
! 52: #include <sys/fcntl.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/systm.h>
! 55: #include <sys/proc.h>
! 56:
! 57: #include <machine/bus.h>
! 58: #include <machine/cpu.h>
! 59:
! 60: #include <arch/vax/mscp/mscp.h>
! 61: #include <arch/vax/mscp/mscpreg.h>
! 62: #include <arch/vax/mscp/mscpvar.h>
! 63:
! 64: /*
! 65: * Drive status, per drive
! 66: */
! 67: struct mt_softc {
! 68: struct device mt_dev; /* Autoconf struct */
! 69: int mt_state; /* open/closed state */
! 70: int mt_hwunit; /* Hardware unit number */
! 71: int mt_inuse; /* Locks the tape drive for others */
! 72: int mt_waswrite; /* Last operation was a write op */
! 73: int mt_serex; /* Got serious exception */
! 74: int mt_ioctlerr; /* Error after last ioctl */
! 75: };
! 76:
! 77: #define MT_OFFLINE 0
! 78: #define MT_ONLINE 1
! 79:
! 80: int mtmatch(struct device *, struct cfdata *, void *);
! 81: void mtattach(struct device *, struct device *, void *);
! 82: void mtdgram(struct device *, struct mscp *, struct mscp_softc *);
! 83: void mtiodone(struct device *, struct buf *);
! 84: int mtonline(struct device *, struct mscp *);
! 85: int mtgotstatus(struct device *, struct mscp *);
! 86: int mtioerror(struct device *, struct mscp *, struct buf *);
! 87: void mtfillin(struct buf *, struct mscp *);
! 88: int mtopen(dev_t, int, int, struct proc *);
! 89: int mtclose(dev_t, int, int, struct proc *);
! 90: void mtstrategy(struct buf *);
! 91: int mtread(dev_t, struct uio *);
! 92: int mtwrite(dev_t, struct uio *);
! 93: int mtioctl(dev_t, int, caddr_t, int, struct proc *);
! 94: int mtdump(dev_t, daddr64_t, caddr_t, size_t);
! 95: int mtcmd(struct mt_softc *, int, int, int);
! 96: void mtcmddone(struct device *, struct mscp *);
! 97: int mt_putonline(struct mt_softc *);
! 98:
! 99: struct mscp_device mt_device = {
! 100: mtdgram,
! 101: mtiodone,
! 102: mtonline,
! 103: mtgotstatus,
! 104: 0,
! 105: mtioerror,
! 106: 0,
! 107: mtfillin,
! 108: mtcmddone,
! 109: };
! 110:
! 111: /* This is not good, should allow more than 4 tapes/device type */
! 112: #define mtunit(dev) (minor(dev) & T_UNIT)
! 113: #define mtnorewind(dev) (dev & T_NOREWIND)
! 114: #define mthdensity(dev) (dev & T_1600BPI)
! 115:
! 116: struct cfattach mt_ca = {
! 117: sizeof(struct mt_softc), (cfmatch_t)mtmatch, mtattach
! 118: };
! 119:
! 120: struct cfdriver mt_cd = {
! 121: NULL, "mt", DV_TAPE
! 122: };
! 123:
! 124: /*
! 125: * More driver definitions, for generic MSCP code.
! 126: */
! 127:
! 128: int
! 129: mtmatch(parent, cf, aux)
! 130: struct device *parent;
! 131: struct cfdata *cf;
! 132: void *aux;
! 133: {
! 134: struct drive_attach_args *da = aux;
! 135: struct mscp *mp = da->da_mp;
! 136:
! 137: if ((da->da_typ & MSCPBUS_TAPE) == 0)
! 138: return 0;
! 139: if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != mp->mscp_unit)
! 140: return 0;
! 141: return 1;
! 142: }
! 143:
! 144: /*
! 145: * The attach routine only checks and prints drive type.
! 146: */
! 147: void
! 148: mtattach(parent, self, aux)
! 149: struct device *parent, *self;
! 150: void *aux;
! 151: {
! 152: struct mt_softc *mt = (void *)self;
! 153: struct drive_attach_args *da = aux;
! 154: struct mscp *mp = da->da_mp;
! 155: struct mscp_softc *mi = (void *)parent;
! 156:
! 157: mt->mt_hwunit = mp->mscp_unit;
! 158: mi->mi_dp[mp->mscp_unit] = self;
! 159:
! 160: disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
! 161: }
! 162:
! 163: /*
! 164: * (Try to) put the drive online. This is done the first time the
! 165: * drive is opened, or if it has fallen offline.
! 166: */
! 167: int
! 168: mt_putonline(mt)
! 169: struct mt_softc *mt;
! 170: {
! 171: struct mscp *mp;
! 172: struct mscp_softc *mi = (struct mscp_softc *)mt->mt_dev.dv_parent;
! 173: volatile int i;
! 174:
! 175: (volatile int)mt->mt_state = MT_OFFLINE;
! 176: mp = mscp_getcp(mi, MSCP_WAIT);
! 177: mp->mscp_opcode = M_OP_ONLINE;
! 178: mp->mscp_unit = mt->mt_hwunit;
! 179: mp->mscp_cmdref = (long)&mt->mt_state;
! 180: *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
! 181:
! 182: /* Poll away */
! 183: i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
! 184: if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz))
! 185: return MSCP_FAILED;
! 186:
! 187: if ((volatile int)mt->mt_state != MT_ONLINE)
! 188: return MSCP_FAILED;
! 189:
! 190: return MSCP_DONE;
! 191: }
! 192: /*
! 193: * Open a drive.
! 194: */
! 195: /*ARGSUSED*/
! 196: int
! 197: mtopen(dev, flag, fmt, p)
! 198: dev_t dev;
! 199: int flag, fmt;
! 200: struct proc *p;
! 201: {
! 202: struct mt_softc *mt;
! 203: int unit;
! 204:
! 205: /*
! 206: * Make sure this is a reasonable open request.
! 207: */
! 208: unit = mtunit(dev);
! 209: if (unit >= mt_cd.cd_ndevs)
! 210: return ENXIO;
! 211: mt = mt_cd.cd_devs[unit];
! 212: if (mt == 0)
! 213: return ENXIO;
! 214:
! 215: if (mt->mt_inuse)
! 216: return EBUSY;
! 217: mt->mt_inuse = 1;
! 218:
! 219: if (mt_putonline(mt) == MSCP_FAILED) {
! 220: mt->mt_inuse = 0;
! 221: return EIO;
! 222: }
! 223:
! 224: return 0;
! 225: }
! 226:
! 227: /* ARGSUSED */
! 228: int
! 229: mtclose(dev, flags, fmt, p)
! 230: dev_t dev;
! 231: int flags, fmt;
! 232: struct proc *p;
! 233: {
! 234: int unit = mtunit(dev);
! 235: struct mt_softc *mt = mt_cd.cd_devs[unit];
! 236:
! 237: /*
! 238: * If we just have finished a writing, write EOT marks.
! 239: */
! 240: if ((flags & FWRITE) && mt->mt_waswrite) {
! 241: mtcmd(mt, MTWEOF, 0, 0);
! 242: mtcmd(mt, MTWEOF, 0, 0);
! 243: mtcmd(mt, MTBSR, 1, 0);
! 244: }
! 245: if (mtnorewind(dev) == 0)
! 246: mtcmd(mt, MTREW, 0, 1);
! 247: if (mt->mt_serex)
! 248: mtcmd(mt, -1, 0, 0);
! 249:
! 250: mt->mt_inuse = 0; /* Release the tape */
! 251: return 0;
! 252: }
! 253:
! 254: void
! 255: mtstrategy(bp)
! 256: struct buf *bp;
! 257: {
! 258: int unit;
! 259: struct mt_softc *mt;
! 260: int s;
! 261:
! 262: /*
! 263: * Make sure this is a reasonable drive to use.
! 264: */
! 265: unit = mtunit(bp->b_dev);
! 266: if (unit >= mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == NULL) {
! 267: bp->b_error = ENXIO;
! 268: goto bad;
! 269: }
! 270:
! 271: mt->mt_waswrite = bp->b_flags & B_READ ? 0 : 1;
! 272: mscp_strategy(bp, mt->mt_dev.dv_parent);
! 273: return;
! 274:
! 275: bad:
! 276: bp->b_flags |= B_ERROR;
! 277: s = splbio();
! 278: biodone(bp);
! 279: splx(s);
! 280: }
! 281:
! 282: int
! 283: mtread(dev, uio)
! 284: dev_t dev;
! 285: struct uio *uio;
! 286: {
! 287:
! 288: return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio));
! 289: }
! 290:
! 291: int
! 292: mtwrite(dev, uio)
! 293: dev_t dev;
! 294: struct uio *uio;
! 295: {
! 296:
! 297: return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio));
! 298: }
! 299:
! 300: void
! 301: mtiodone(usc, bp)
! 302: struct device *usc;
! 303: struct buf *bp;
! 304: {
! 305: int s;
! 306:
! 307: s = splbio();
! 308: biodone(bp);
! 309: splx(s);
! 310: }
! 311:
! 312: /*
! 313: * Fill in drive addresses in a mscp packet waiting for transfer.
! 314: */
! 315: void
! 316: mtfillin(bp, mp)
! 317: struct buf *bp;
! 318: struct mscp *mp;
! 319: {
! 320: int unit = mtunit(bp->b_dev);
! 321: struct mt_softc *mt = mt_cd.cd_devs[unit];
! 322:
! 323: mp->mscp_unit = mt->mt_hwunit;
! 324: if (mt->mt_serex == 2) {
! 325: mp->mscp_modifier = M_MD_CLSEX;
! 326: mt->mt_serex = 0;
! 327: } else
! 328: mp->mscp_modifier = 0;
! 329:
! 330: mp->mscp_seq.seq_bytecount = bp->b_bcount;
! 331: }
! 332:
! 333: /*
! 334: * Handle an error datagram.
! 335: */
! 336: void
! 337: mtdgram(usc, mp, mi)
! 338: struct device *usc;
! 339: struct mscp *mp;
! 340: struct mscp_softc *mi;
! 341: {
! 342: if (mscp_decodeerror(usc == NULL?"unconf mt" : usc->dv_xname, mp, mi))
! 343: return;
! 344: }
! 345:
! 346: /*
! 347: * A drive came on line, make sure it really _is_ on line before
! 348: * trying to use it.
! 349: */
! 350: int
! 351: mtonline(usc, mp)
! 352: struct device *usc;
! 353: struct mscp *mp;
! 354: {
! 355: struct mt_softc *mt = (void *)usc;
! 356:
! 357: wakeup((caddr_t)&mt->mt_state);
! 358: if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)
! 359: mt->mt_state = MT_ONLINE;
! 360:
! 361: return (MSCP_DONE);
! 362: }
! 363:
! 364: /*
! 365: * We got some (configured) unit's status. Return DONE.
! 366: */
! 367: int
! 368: mtgotstatus(usc, mp)
! 369: struct device *usc;
! 370: struct mscp *mp;
! 371: {
! 372: return (MSCP_DONE);
! 373: }
! 374:
! 375: static char *mt_ioerrs[] = {
! 376: "invalid command", /* 1 M_ST_INVALCMD */
! 377: "command aborted", /* 2 M_ST_ABORTED */
! 378: "unit offline", /* 3 M_ST_OFFLINE */
! 379: "unknown", /* 4 M_ST_AVAILABLE */
! 380: "unknown", /* 5 M_ST_MFMTERR */
! 381: "unit write protected", /* 6 M_ST_WRPROT */
! 382: "compare error", /* 7 M_ST_COMPERR */
! 383: "data error", /* 8 M_ST_DATAERR */
! 384: "host buffer access error", /* 9 M_ST_HOSTBUFERR */
! 385: "controller error", /* 10 M_ST_CTLRERR */
! 386: "drive error", /* 11 M_ST_DRIVEERR */
! 387: "formatter error", /* 12 M_ST_FORMATTERR */
! 388: "BOT encountered", /* 13 M_ST_BOT */
! 389: "tape mark encountered",/* 14 M_ST_TAPEMARK */
! 390: "unknown", /* 15 */
! 391: "record data truncated",/* 16 M_ST_RDTRUNC */
! 392: };
! 393:
! 394: /*
! 395: * An I/O error, may be because of a tapemark encountered.
! 396: * Check that before failing.
! 397: */
! 398: /*ARGSUSED*/
! 399: int
! 400: mtioerror(usc, mp, bp)
! 401: struct device *usc;
! 402: struct mscp *mp;
! 403: struct buf *bp;
! 404: {
! 405: struct mt_softc *mt = (void *)usc;
! 406: int st = mp->mscp_status & M_ST_MASK;
! 407:
! 408: if (mp->mscp_flags & M_EF_SEREX)
! 409: mt->mt_serex = 1;
! 410: if (st == M_ST_TAPEMARK)
! 411: mt->mt_serex = 2;
! 412: else {
! 413: if (st && st < 17)
! 414: printf("%s: error %d (%s)\n", mt->mt_dev.dv_xname, st,
! 415: mt_ioerrs[st-1]);
! 416: else
! 417: printf("%s: error %d\n", mt->mt_dev.dv_xname, st);
! 418: bp->b_flags |= B_ERROR;
! 419: bp->b_error = EROFS;
! 420: }
! 421:
! 422: return (MSCP_DONE);
! 423: }
! 424:
! 425: /*
! 426: * I/O controls.
! 427: */
! 428: int
! 429: mtioctl(dev, cmd, data, flag, p)
! 430: dev_t dev;
! 431: int cmd;
! 432: caddr_t data;
! 433: int flag;
! 434: struct proc *p;
! 435: {
! 436: int unit = mtunit(dev);
! 437: struct mt_softc *mt = mt_cd.cd_devs[unit];
! 438: struct mtop *mtop;
! 439: struct mtget *mtget;
! 440: int error = 0, count;
! 441:
! 442: count = mtop->mt_count;
! 443:
! 444: switch (cmd) {
! 445:
! 446: case MTIOCTOP:
! 447: mtop = (void *)data;
! 448: if (mtop->mt_op == MTWEOF) {
! 449: while (mtop->mt_count-- > 0)
! 450: if ((error = mtcmd(mt, mtop->mt_op, 0, 0)))
! 451: break;
! 452: } else
! 453: error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0);
! 454:
! 455: case MTIOCGET:
! 456: mtget = (void *)data;
! 457: mtget->mt_type = MT_ISTMSCP;
! 458: /* XXX we need to fill in more fields here */
! 459: break;
! 460:
! 461: default:
! 462: error = ENXIO;
! 463: break;
! 464: }
! 465: return (error);
! 466: }
! 467:
! 468: /*
! 469: * No crash dump support...
! 470: */
! 471: int
! 472: mtdump(dev, blkno, va, size)
! 473: dev_t dev;
! 474: daddr64_t blkno;
! 475: caddr_t va;
! 476: size_t size;
! 477: {
! 478: return -1;
! 479: }
! 480:
! 481: /*
! 482: * Send a command to the tape drive. Wait until the command is
! 483: * finished before returning.
! 484: * This routine must only be called when there are no data transfer
! 485: * active on this device. Can we be sure of this? Or does the ctlr
! 486: * queue up all command packets and take them in sequential order?
! 487: * It sure would be nice if my manual stated this... /ragge
! 488: */
! 489: int
! 490: mtcmd(mt, cmd, count, complete)
! 491: struct mt_softc *mt;
! 492: int cmd, count, complete;
! 493: {
! 494: struct mscp *mp;
! 495: struct mscp_softc *mi = (void *)mt->mt_dev.dv_parent;
! 496: volatile int i;
! 497:
! 498: mp = mscp_getcp(mi, MSCP_WAIT);
! 499:
! 500: mt->mt_ioctlerr = 0;
! 501: mp->mscp_unit = mt->mt_hwunit;
! 502: mp->mscp_cmdref = -1;
! 503: *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
! 504:
! 505: switch (cmd) {
! 506: case MTWEOF:
! 507: mp->mscp_opcode = M_OP_WRITM;
! 508: break;
! 509:
! 510: case MTBSF:
! 511: mp->mscp_modifier = M_MD_REVERSE;
! 512: case MTFSF:
! 513: mp->mscp_opcode = M_OP_POS;
! 514: mp->mscp_seq.seq_buffer = count;
! 515: break;
! 516:
! 517: case MTBSR:
! 518: mp->mscp_modifier = M_MD_REVERSE;
! 519: case MTFSR:
! 520: mp->mscp_opcode = M_OP_POS;
! 521: mp->mscp_modifier |= M_MD_OBJCOUNT;
! 522: mp->mscp_seq.seq_bytecount = count;
! 523: break;
! 524:
! 525: case MTREW:
! 526: mp->mscp_opcode = M_OP_POS;
! 527: mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX;
! 528: if (complete)
! 529: mp->mscp_modifier |= M_MD_IMMEDIATE;
! 530: mt->mt_serex = 0;
! 531: break;
! 532:
! 533: case MTOFFL:
! 534: mp->mscp_opcode = M_OP_AVAILABLE;
! 535: mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX;
! 536: mt->mt_serex = 0;
! 537: break;
! 538:
! 539: case MTNOP:
! 540: mp->mscp_opcode = M_OP_GETUNITST;
! 541: break;
! 542:
! 543: case -1: /* Clear serious exception only */
! 544: mp->mscp_opcode = M_OP_POS;
! 545: mp->mscp_modifier = M_MD_CLSEX;
! 546: mt->mt_serex = 0;
! 547: break;
! 548:
! 549: default:
! 550: printf("Bad ioctl %x\n", cmd);
! 551: mp->mscp_opcode = M_OP_POS;
! 552: break;
! 553: }
! 554:
! 555: i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
! 556: tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0);
! 557: return mt->mt_ioctlerr;
! 558: }
! 559:
! 560: /*
! 561: * Called from bus routines whenever a non-data transfer is finished.
! 562: */
! 563: void
! 564: mtcmddone(usc, mp)
! 565: struct device *usc;
! 566: struct mscp *mp;
! 567: {
! 568: struct mt_softc *mt = (void *)usc;
! 569:
! 570: if (mp->mscp_status) {
! 571: mt->mt_ioctlerr = EIO;
! 572: printf("%s: bad status %x\n", mt->mt_dev.dv_xname,
! 573: mp->mscp_status);
! 574: }
! 575: wakeup(&mt->mt_inuse);
! 576: }
CVSweb