Annotation of sys/arch/vax/mba/hp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hp.c,v 1.18 2007/06/07 05:22:32 deraadt Exp $ */
! 2: /* $NetBSD: hp.c,v 1.22 2000/02/12 16:09:33 ragge 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: * Simple device driver routine for massbuss disks.
! 36: * TODO:
! 37: * Fix support for Standard DEC BAD144 bad block forwarding.
! 38: * Be able to to handle soft/hard transfer errors.
! 39: * Handle non-data transfer interrupts.
! 40: * Autoconfiguration of disk drives 'on the fly'.
! 41: * Handle disk media changes.
! 42: * Dual-port operations should be supported.
! 43: */
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/device.h>
! 47: #include <sys/disklabel.h>
! 48: #include <sys/disk.h>
! 49: #include <sys/dkio.h>
! 50: #include <sys/buf.h>
! 51: #include <sys/stat.h>
! 52: #include <sys/ioccom.h>
! 53: #include <sys/fcntl.h>
! 54: #include <sys/syslog.h>
! 55: #include <sys/reboot.h>
! 56:
! 57: #include <machine/trap.h>
! 58: #include <machine/pte.h>
! 59: #include <machine/mtpr.h>
! 60: #include <machine/cpu.h>
! 61: #include <machine/rpb.h>
! 62:
! 63: #include <vax/mba/mbavar.h>
! 64: #include <vax/mba/mbareg.h>
! 65: #include <vax/mba/hpreg.h>
! 66:
! 67: #define HPMASK 0xffff
! 68:
! 69: struct hp_softc {
! 70: struct device sc_dev;
! 71: struct disk sc_disk;
! 72: struct mba_device sc_md; /* Common struct used by mbaqueue. */
! 73: int sc_wlabel; /* Disklabel area is writable */
! 74: int sc_physnr; /* Physical disk number */
! 75: };
! 76:
! 77: int hpmatch(struct device *, struct cfdata *, void *);
! 78: void hpattach(struct device *, struct device *, void *);
! 79: void hpstrategy(struct buf *);
! 80: void hpstart(struct mba_device *);
! 81: int hpattn(struct mba_device *);
! 82: enum xfer_action hpfinish(struct mba_device *, int, int *);
! 83: int hpopen(dev_t, int, int);
! 84: int hpclose(dev_t, int, int);
! 85: int hpioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 86: int hpdump(dev_t, daddr64_t, caddr_t, size_t);
! 87: int hpread(dev_t, struct uio *);
! 88: int hpwrite(dev_t, struct uio *);
! 89: daddr64_t hpsize(dev_t);
! 90:
! 91: struct cfattach hp_ca = {
! 92: sizeof(struct hp_softc), hpmatch, hpattach
! 93: };
! 94:
! 95: extern struct cfdriver hp_cd;
! 96:
! 97: /*
! 98: * Check if this is a disk drive; done by checking type from mbaattach.
! 99: */
! 100: int
! 101: hpmatch(parent, cf, aux)
! 102: struct device *parent;
! 103: struct cfdata *cf;
! 104: void *aux;
! 105: {
! 106: struct mba_attach_args *ma = aux;
! 107:
! 108: if (cf->cf_loc[MBACF_DRIVE] != MBACF_DRIVE_DEFAULT &&
! 109: cf->cf_loc[MBACF_DRIVE] != ma->unit)
! 110: return 0;
! 111:
! 112: if (ma->devtyp != MB_RP)
! 113: return 0;
! 114:
! 115: return 1;
! 116: }
! 117:
! 118: /*
! 119: * Disk drive found; fake a disklabel and try to read the real one.
! 120: * If the on-disk label can't be read; we lose.
! 121: */
! 122: void
! 123: hpattach(parent, self, aux)
! 124: struct device *parent, *self;
! 125: void *aux;
! 126: {
! 127: struct hp_softc *sc = (void *)self;
! 128: struct mba_softc *ms = (void *)parent;
! 129: struct disklabel *dl;
! 130: struct mba_attach_args *ma = aux;
! 131: char *msg;
! 132:
! 133: /*
! 134: * Init the common struct for both the adapter and its slaves.
! 135: */
! 136: BUFQ_INIT(&sc->sc_md.md_q);
! 137: sc->sc_md.md_softc = (void *)sc; /* Pointer to this softc */
! 138: sc->sc_md.md_mba = (void *)parent; /* Pointer to parent softc */
! 139: sc->sc_md.md_start = hpstart; /* Disk start routine */
! 140: sc->sc_md.md_attn = hpattn; /* Disk attention routine */
! 141: sc->sc_md.md_finish = hpfinish; /* Disk xfer finish routine */
! 142:
! 143: ms->sc_md[ma->unit] = &sc->sc_md; /* Per-unit backpointer */
! 144:
! 145: sc->sc_physnr = ma->unit;
! 146: /*
! 147: * Init and attach the disk structure.
! 148: */
! 149: sc->sc_disk.dk_name = sc->sc_dev.dv_xname;
! 150: disk_attach(&sc->sc_disk);
! 151:
! 152: /*
! 153: * Fake a disklabel to be able to read in the real label.
! 154: */
! 155: dl = sc->sc_disk.dk_label;
! 156:
! 157: dl->d_secsize = DEV_BSIZE;
! 158: dl->d_ntracks = 1;
! 159: dl->d_nsectors = 32;
! 160: dl->d_secpercyl = 32;
! 161:
! 162: /*
! 163: * Read in label.
! 164: */
! 165: if ((msg = readdisklabel(makedev(0, self->dv_unit * 8), hpstrategy,
! 166: dl, NULL)) != NULL) {
! 167: /*printf(": %s", msg);*/
! 168: }
! 169: printf(": %.*s, size = %d sectors\n",
! 170: (int)sizeof(dl->d_typename), dl->d_typename, DL_GETDSIZE(dl));
! 171: /*
! 172: * check if this was what we booted from.
! 173: */
! 174: if ((B_TYPE(bootdev) == BDEV_HP) && (ma->unit == B_UNIT(bootdev)) &&
! 175: (ms->sc_physnr == B_ADAPTOR(bootdev)))
! 176: booted_from = self;
! 177: }
! 178:
! 179:
! 180: void
! 181: hpstrategy(bp)
! 182: struct buf *bp;
! 183: {
! 184: struct hp_softc *sc;
! 185: struct buf *gp;
! 186: int unit, s;
! 187: struct disklabel *lp;
! 188:
! 189: unit = DISKUNIT(bp->b_dev);
! 190: sc = hp_cd.cd_devs[unit];
! 191: lp = sc->sc_disk.dk_label;
! 192:
! 193: if (bounds_check_with_label(bp, lp, sc->sc_wlabel) <= 0)
! 194: goto done;
! 195:
! 196: bp->b_rawblkno =
! 197: bp->b_blkno + DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
! 198: bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
! 199:
! 200: s = splbio();
! 201:
! 202: gp = BUFQ_FIRST(&sc->sc_md.md_q);
! 203: disksort_cylinder(&sc->sc_md.md_q, bp);
! 204: if (gp == 0)
! 205: mbaqueue(&sc->sc_md);
! 206:
! 207: splx(s);
! 208: return;
! 209:
! 210: done:
! 211: bp->b_resid = bp->b_bcount;
! 212: s = splbio();
! 213: biodone(bp);
! 214: splx(s);
! 215: }
! 216:
! 217: /*
! 218: * Start transfer on given disk. Called from mbastart().
! 219: */
! 220: void
! 221: hpstart(md)
! 222: struct mba_device *md;
! 223: {
! 224: struct hp_softc *sc = md->md_softc;
! 225: struct mba_regs *mr = md->md_mba->sc_mbareg;
! 226: volatile struct hp_regs *hr;
! 227: struct disklabel *lp = sc->sc_disk.dk_label;
! 228: struct buf *bp = BUFQ_FIRST(&md->md_q);
! 229: unsigned bn, cn, sn, tn;
! 230:
! 231: /*
! 232: * Collect statistics.
! 233: */
! 234: disk_busy(&sc->sc_disk);
! 235: sc->sc_disk.dk_seek++;
! 236:
! 237: hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
! 238:
! 239: bn = bp->b_rawblkno;
! 240: if (bn) {
! 241: cn = bn / lp->d_secpercyl;
! 242: sn = bn % lp->d_secpercyl;
! 243: tn = sn / lp->d_nsectors;
! 244: sn = sn % lp->d_nsectors;
! 245: } else
! 246: cn = sn = tn = 0;
! 247:
! 248: hr->hp_dc = cn;
! 249: hr->hp_da = (tn << 8) | sn;
! 250: if (bp->b_flags & B_READ)
! 251: hr->hp_cs1 = HPCS_READ; /* GO */
! 252: else
! 253: hr->hp_cs1 = HPCS_WRITE;
! 254: }
! 255:
! 256: int
! 257: hpopen(dev, flag, fmt)
! 258: dev_t dev;
! 259: int flag, fmt;
! 260: {
! 261: struct hp_softc *sc;
! 262: int unit, part;
! 263:
! 264: unit = DISKUNIT(dev);
! 265: if (unit >= hp_cd.cd_ndevs)
! 266: return ENXIO;
! 267: sc = hp_cd.cd_devs[unit];
! 268: if (sc == 0)
! 269: return ENXIO;
! 270:
! 271: part = DISKPART(dev);
! 272:
! 273: if (part >= sc->sc_disk.dk_label->d_npartitions)
! 274: return ENXIO;
! 275:
! 276: switch (fmt) {
! 277: case S_IFCHR:
! 278: sc->sc_disk.dk_copenmask |= (1 << part);
! 279: break;
! 280:
! 281: case S_IFBLK:
! 282: sc->sc_disk.dk_bopenmask |= (1 << part);
! 283: break;
! 284: }
! 285: sc->sc_disk.dk_openmask =
! 286: sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
! 287:
! 288: return 0;
! 289: }
! 290:
! 291: int
! 292: hpclose(dev, flag, fmt)
! 293: dev_t dev;
! 294: int flag, fmt;
! 295: {
! 296: struct hp_softc *sc;
! 297: int unit, part;
! 298:
! 299: unit = DISKUNIT(dev);
! 300: sc = hp_cd.cd_devs[unit];
! 301:
! 302: part = DISKPART(dev);
! 303:
! 304: switch (fmt) {
! 305: case S_IFCHR:
! 306: sc->sc_disk.dk_copenmask &= ~(1 << part);
! 307: break;
! 308:
! 309: case S_IFBLK:
! 310: sc->sc_disk.dk_bopenmask &= ~(1 << part);
! 311: break;
! 312: }
! 313: sc->sc_disk.dk_openmask =
! 314: sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
! 315:
! 316: return 0;
! 317: }
! 318:
! 319: int
! 320: hpioctl(dev, cmd, addr, flag, p)
! 321: dev_t dev;
! 322: u_long cmd;
! 323: caddr_t addr;
! 324: int flag;
! 325: struct proc *p;
! 326: {
! 327: struct hp_softc *sc = hp_cd.cd_devs[DISKUNIT(dev)];
! 328: struct disklabel *lp = sc->sc_disk.dk_label;
! 329: int error;
! 330:
! 331: switch (cmd) {
! 332: case DIOCGDINFO:
! 333: bcopy(lp, addr, sizeof (struct disklabel));
! 334: return 0;
! 335:
! 336: case DIOCGPART:
! 337: ((struct partinfo *)addr)->disklab = lp;
! 338: ((struct partinfo *)addr)->part =
! 339: &lp->d_partitions[DISKPART(dev)];
! 340: break;
! 341:
! 342: case DIOCSDINFO:
! 343: if ((flag & FWRITE) == 0)
! 344: return EBADF;
! 345:
! 346: return setdisklabel(lp, (struct disklabel *)addr, 0, 0);
! 347:
! 348: case DIOCWDINFO:
! 349: if ((flag & FWRITE) == 0)
! 350: error = EBADF;
! 351: else {
! 352: sc->sc_wlabel = 1;
! 353: error = writedisklabel(dev, hpstrategy, lp, 0);
! 354: sc->sc_wlabel = 0;
! 355: }
! 356: return error;
! 357: case DIOCWLABEL:
! 358: if ((flag & FWRITE) == 0)
! 359: return EBADF;
! 360: sc->sc_wlabel = 1;
! 361: break;
! 362:
! 363: default:
! 364: printf("hpioctl: command %x\n", (unsigned int)cmd);
! 365: return ENOTTY;
! 366: }
! 367: return 0;
! 368: }
! 369:
! 370: /*
! 371: * Called when a transfer is finished. Check if transfer went OK,
! 372: * Return info about what-to-do-now.
! 373: */
! 374: enum xfer_action
! 375: hpfinish(md, mbasr, attn)
! 376: struct mba_device *md;
! 377: int mbasr, *attn;
! 378: {
! 379: struct hp_softc *sc = md->md_softc;
! 380: struct buf *bp = BUFQ_FIRST(&md->md_q);
! 381: volatile struct mba_regs *mr = md->md_mba->sc_mbareg;
! 382: volatile struct hp_regs *hr = (void *)&mr->mba_md[DISKUNIT(bp->b_dev)];
! 383: int er1, er2;
! 384: volatile int bc; /* to get GCC read whole longword */
! 385: unsigned byte;
! 386:
! 387: er1 = hr->hp_er1 & HPMASK;
! 388: er2 = hr->hp_er2 & HPMASK;
! 389: hr->hp_er1 = hr->hp_er2 = 0;
! 390: hper1:
! 391: switch (ffs(er1) - 1) {
! 392: case -1:
! 393: hr->hp_er1 = 0;
! 394: goto hper2;
! 395:
! 396: case HPER1_DCK: /* Corrected? data read. Just notice. */
! 397: bc = mr->mba_bc;
! 398: byte = ~(bc >> 16);
! 399: diskerr(buf, hp_cd.cd_name, "soft ecc", LOG_PRINTF,
! 400: btodb(bp->b_bcount - byte), sc->sc_disk.dk_label);
! 401: er1 &= ~(1<<HPER1_DCK);
! 402: er1 &= HPMASK;
! 403: break;
! 404:
! 405: default:
! 406: printf("drive error :%s er1 %x er2 %x\n",
! 407: sc->sc_dev.dv_xname, er1, er2);
! 408: hr->hp_er1 = hr->hp_er2 = 0;
! 409: goto hper2;
! 410: }
! 411: goto hper1;
! 412:
! 413: hper2:
! 414: mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN);
! 415: if (mbasr)
! 416: printf("massbuss error :%s %x\n",
! 417: sc->sc_dev.dv_xname, mbasr);
! 418:
! 419: BUFQ_FIRST(&md->md_q)->b_resid = 0;
! 420: disk_unbusy(&sc->sc_disk, BUFQ_FIRST(&md->md_q)->b_bcount,
! 421: (BUFQ_FIRST(&md->md_q)->b_flags & B_READ));
! 422: return XFER_FINISH;
! 423: }
! 424:
! 425: /*
! 426: * Non-data transfer interrupt; like volume change.
! 427: */
! 428: int
! 429: hpattn(md)
! 430: struct mba_device *md;
! 431: {
! 432: struct hp_softc *sc = md->md_softc;
! 433: struct mba_softc *ms = (void *)sc->sc_dev.dv_parent;
! 434: struct mba_regs *mr = ms->sc_mbareg;
! 435: struct hp_regs *hr = (void *)&mr->mba_md[sc->sc_dev.dv_unit];
! 436: int er1, er2;
! 437:
! 438: er1 = hr->hp_er1 & HPMASK;
! 439: er2 = hr->hp_er2 & HPMASK;
! 440:
! 441: printf("%s: Attention! er1 %x er2 %x\n",
! 442: sc->sc_dev.dv_xname, er1, er2);
! 443: return 0;
! 444: }
! 445:
! 446:
! 447: daddr64_t
! 448: hpsize(dev)
! 449: dev_t dev;
! 450: {
! 451: int size, unit = DISKUNIT(dev);
! 452: struct hp_softc *sc;
! 453:
! 454: if (unit >= hp_cd.cd_ndevs || hp_cd.cd_devs[unit] == 0)
! 455: return -1;
! 456:
! 457: sc = hp_cd.cd_devs[unit];
! 458: size = DL_GETPSIZE(&sc->sc_disk.dk_label->d_partitions[DISKPART(dev)]) *
! 459: (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE);
! 460:
! 461: return size;
! 462: }
! 463:
! 464: int
! 465: hpdump(dev, a1, a2, size)
! 466: dev_t dev;
! 467: daddr64_t a1;
! 468: caddr_t a2;
! 469: size_t size;
! 470: {
! 471: printf("hpdump: Not implemented yet.\n");
! 472: return 0;
! 473: }
! 474:
! 475: int
! 476: hpread(dev, uio)
! 477: dev_t dev;
! 478: struct uio *uio;
! 479: {
! 480: return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio));
! 481: }
! 482:
! 483: int
! 484: hpwrite(dev, uio)
! 485: dev_t dev;
! 486: struct uio *uio;
! 487: {
! 488: return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio));
! 489: }
CVSweb