diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2011-11-01 20:52:18 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2011-11-01 20:52:18 +0000 |
commit | cbcd523c77e444f13a61a014d0b16cea93096153 (patch) | |
tree | 9e6a10d9e8bbf8876cbec10430f94b438258cc01 /sys/arch | |
parent | b4db6257c8fbfc918e099d8b5fb64d3baab19f48 (diff) |
Rework disklabel handling to correctly support label spoofing, and thus
fix DIOCGPDINFO ioctl behaviour in the process.
Tested in SIMH only due to the lack of MSCP disks, RX02 floppies untested
but shouldn't be affected by this diff.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/vax/mscp/mscp_disk.c | 368 |
1 files changed, 149 insertions, 219 deletions
diff --git a/sys/arch/vax/mscp/mscp_disk.c b/sys/arch/vax/mscp/mscp_disk.c index c9bc08d52fa..e4143827fd6 100644 --- a/sys/arch/vax/mscp/mscp_disk.c +++ b/sys/arch/vax/mscp/mscp_disk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mscp_disk.c,v 1.37 2011/07/06 04:49:36 matthew Exp $ */ +/* $OpenBSD: mscp_disk.c,v 1.38 2011/11/01 20:52:17 miod Exp $ */ /* $NetBSD: mscp_disk.c,v 1.30 2001/11/13 07:38:28 lukem Exp $ */ /* * Copyright (c) 1996 Ludd, University of Lule}, Sweden. @@ -45,8 +45,6 @@ * write bad block forwarding code */ -#include <sys/cdefs.h> - #include <sys/param.h> #include <sys/buf.h> #include <sys/device.h> @@ -87,30 +85,29 @@ struct cfdriver rx_cd = { * Drive status, per drive */ struct ra_softc { - struct device ra_dev; /* Autoconf struct */ - struct disk ra_disk; - int ra_state; /* open/closed state */ - u_long ra_mediaid; /* media id */ - int ra_hwunit; /* Hardware unit number */ - int ra_havelabel; /* true if we have a label */ + struct device ra_dev; /* autoconf struct */ + struct disk ra_disk; + struct mscpv_guse ra_guse; /* status information */ + u_long ra_unitsize; /* unit size in sectors */ + int ra_state; /* open/closed state */ + int ra_hwunit; /* Hardware unit number */ }; #define rx_softc ra_softc void rxattach(struct device *, struct device *, void *); int rx_putonline(struct rx_softc *); -void rrmakelabel(struct disklabel *, long); #if NRA int ramatch(struct device *, struct cfdata *, void *); -void raattach(struct device *, struct device *, void *); int raread(dev_t, struct uio *); int rawrite(dev_t, struct uio *); int ra_putonline(struct ra_softc *); +int ragetdisklabel(dev_t, struct ra_softc *, struct disklabel *, int); bdev_decl(ra); -struct cfattach ra_ca = { +const struct cfattach ra_ca = { sizeof(struct ra_softc), (cfmatch_t)ramatch, rxattach }; @@ -119,13 +116,10 @@ struct cfattach ra_ca = { */ int -ramatch(parent, cf, aux) - struct device *parent; - struct cfdata *cf; - void *aux; +ramatch(struct device *parent, struct cfdata *cf, void *aux) { - struct drive_attach_args *da = aux; - struct mscp *mp = da->da_mp; + struct drive_attach_args *da = aux; + struct mscp *mp = da->da_mp; if ((da->da_typ & MSCPBUS_DISK) == 0) return 0; @@ -140,32 +134,81 @@ ramatch(parent, cf, aux) return 1; } -/* +/* + * Read the label from the drive. + */ +int +ragetdisklabel(dev_t dev, struct ra_softc *ra, struct disklabel *lp, + int spoofonly) +{ + int n, p = 0; + + bzero(lp, sizeof(struct disklabel)); + lp->d_secsize = DEV_BSIZE; + lp->d_nsectors = ra->ra_guse.guse_nspt; + lp->d_ntracks = ra->ra_guse.guse_ngpc * ra->ra_guse.guse_group; + lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; + DL_SETDSIZE(lp, ra->ra_unitsize); /* XXX might be zero */ + + if (lp->d_secpercyl) { + lp->d_ncylinders = ra->ra_unitsize / lp->d_secpercyl; + lp->d_type = DTYPE_MSCP; + } else { + lp->d_type = DTYPE_FLOPPY; + } + + lp->d_bbsize = BBSIZE; + lp->d_sbsize = SBSIZE; + + /* Create the disk name for disklabel. Phew... */ + lp->d_typename[p++] = MSCP_MID_CHAR(2, ra->ra_guse.guse_mediaid); + lp->d_typename[p++] = MSCP_MID_CHAR(1, ra->ra_guse.guse_mediaid); + if (MSCP_MID_ECH(0, ra->ra_guse.guse_mediaid)) + lp->d_typename[p++] = + MSCP_MID_CHAR(0, ra->ra_guse.guse_mediaid); + n = MSCP_MID_NUM(ra->ra_guse.guse_mediaid); + if (n > 99) { + lp->d_typename[p++] = '1'; + n -= 100; + } + if (n > 9) { + lp->d_typename[p++] = (n / 10) + '0'; + n %= 10; + } + lp->d_typename[p++] = n + '0'; + lp->d_typename[p] = 0; + + lp->d_version = 1; + lp->d_magic = lp->d_magic2 = DISKMAGIC; + lp->d_checksum = dkcksum(lp); + + return readdisklabel(DISKLABELDEV(dev), rastrategy, lp, spoofonly); +} + +/* * (Try to) put the drive online. This is done the first time the - * drive is opened, or if it har fallen offline. + * drive is opened, or if it has fallen offline. */ int -ra_putonline(ra) - struct ra_softc *ra; +ra_putonline(struct ra_softc *ra) { - struct disklabel *dl; + struct disklabel *dl; + int rc; + ra->ra_state = DK_RDLABEL; if (rx_putonline(ra) != MSCP_DONE) return MSCP_FAILED; dl = ra->ra_disk.dk_label; - - ra->ra_state = DK_RDLABEL; - printf("%s", ra->ra_dev.dv_xname); - if ((readdisklabel(MAKEDISKDEV(RAMAJOR, ra->ra_dev.dv_unit, - RAW_PART), rastrategy, dl, 0)) != 0) { - /* EIO and others */ - } else { - ra->ra_havelabel = 1; + rc = ragetdisklabel(MAKEDISKDEV(RAMAJOR, ra->ra_dev.dv_unit, RAW_PART), + ra, dl, 0); + if (rc != EIO) ra->ra_state = DK_OPEN; - } - printf(": size %lld sectors\n", DL_GETDSIZE(dl)); + printf("%s: %luMB, %lu bytes/sector, %lld sectors\n", + ra->ra_dev.dv_xname, + ra->ra_unitsize / (1048576 / dl->d_secsize), + dl->d_secsize, ra->ra_unitsize); return MSCP_DONE; } @@ -175,13 +218,11 @@ ra_putonline(ra) */ /*ARGSUSED*/ int -raopen(dev, flag, fmt, p) - dev_t dev; - int flag, fmt; - struct proc *p; +raopen(dev_t dev, int flag, int fmt, struct proc *p) { struct ra_softc *ra; int part, unit, mask; + /* * Make sure this is a reasonable open request. */ @@ -232,10 +273,7 @@ raopen(dev, flag, fmt, p) /* ARGSUSED */ int -raclose(dev, flags, fmt, p) - dev_t dev; - int flags, fmt; - struct proc *p; +raclose(dev_t dev, int flags, int fmt, struct proc *p) { int unit = DISKUNIT(dev); struct ra_softc *ra = ra_cd.cd_devs[unit]; @@ -263,7 +301,7 @@ raclose(dev, flags, fmt, p) (void) tsleep(&udautab[unit], PZERO - 1, "raclose", 0); splx(s); - ra->ra_state = CLOSED; + ra->ra_state = DK_CLOSED; } #endif return (0); @@ -273,8 +311,7 @@ raclose(dev, flags, fmt, p) * Queue a transfer request, and if possible, hand it to the controller. */ void -rastrategy(bp) - struct buf *bp; +rastrategy(struct buf *bp) { int unit; struct ra_softc *ra; @@ -327,18 +364,14 @@ rastrategy(bp) } int -raread(dev, uio) - dev_t dev; - struct uio *uio; +raread(dev_t dev, struct uio *uio) { return (physio(rastrategy, dev, B_READ, minphys, uio)); } int -rawrite(dev, uio) - dev_t dev; - struct uio *uio; +rawrite(dev_t dev, struct uio *uio) { return (physio(rastrategy, dev, B_WRITE, minphys, uio)); @@ -348,12 +381,7 @@ rawrite(dev, uio) * I/O controls. */ int -raioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; +raioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { int unit = DISKUNIT(dev); struct disklabel *lp, *tp; @@ -363,9 +391,11 @@ raioctl(dev, cmd, data, flag, p) lp = ra->ra_disk.dk_label; switch (cmd) { + case DIOCGPDINFO: + ragetdisklabel(dev, ra, (struct disklabel *)data, 1); + break; case DIOCGDINFO: - case DIOCGPDINFO: /* no separate 'physical' info available. */ bcopy(lp, data, sizeof (struct disklabel)); break; @@ -398,11 +428,7 @@ raioctl(dev, cmd, data, flag, p) int -radump(dev, blkno, va, size) - dev_t dev; - daddr64_t blkno; - caddr_t va; - size_t size; +radump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) { return ENXIO; } @@ -411,13 +437,13 @@ radump(dev, blkno, va, size) * Return the size of a partition, if known, or -1 if not. */ daddr64_t -rasize(dev) - dev_t dev; +rasize(dev_t dev) { - int unit = DISKUNIT(dev); + int unit = DISKUNIT(dev), part = DISKPART(dev); struct ra_softc *ra; + struct disklabel *lp; - if (unit >= ra_cd.cd_ndevs || ra_cd.cd_devs[unit] == 0) + if (unit >= ra_cd.cd_ndevs || ra_cd.cd_devs[unit] == NULL) return -1; ra = ra_cd.cd_devs[unit]; @@ -426,8 +452,13 @@ rasize(dev) if (ra_putonline(ra) == MSCP_FAILED) return -1; - return DL_GETPSIZE(&ra->ra_disk.dk_label->d_partitions[DISKPART(dev)]) * - (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE); + lp = ra->ra_disk.dk_label; + if (part >= lp->d_npartitions || + lp->d_partitions[part].p_fstype != FS_SWAP) + return -1; + else + return DL_GETPSIZE(&lp->d_partitions[part]) * + (lp->d_secsize / DEV_BSIZE); } #endif /* NRA */ @@ -444,7 +475,7 @@ int rxioctl(dev_t, int, caddr_t, int, struct proc *); int rxdump(dev_t, daddr64_t, caddr_t, size_t); daddr64_t rxsize(dev_t); -struct cfattach rx_ca = { +const struct cfattach rx_ca = { sizeof(struct rx_softc), (cfmatch_t)rxmatch, rxattach }; @@ -453,13 +484,10 @@ struct cfattach rx_ca = { */ int -rxmatch(parent, cf, aux) - struct device *parent; - struct cfdata *cf; - void *aux; +rxmatch(struct device *parent, struct cfdata *cf, void *aux) { - struct drive_attach_args *da = aux; - struct mscp *mp = da->da_mp; + struct drive_attach_args *da = aux; + struct mscp *mp = da->da_mp; if ((da->da_typ & MSCPBUS_DISK) == 0) return 0; @@ -479,20 +507,17 @@ rxmatch(parent, cf, aux) /* * The attach routine only checks and prints drive type. * Bringing the disk online is done when the disk is accessed - * the first time. + * the first time. */ void -rxattach(parent, self, aux) - struct device *parent, *self; - void *aux; +rxattach(struct device *parent, struct device *self, void *aux) { - struct rx_softc *rx = (void *)self; - struct drive_attach_args *da = aux; - struct mscp *mp = da->da_mp; - struct mscp_softc *mi = (void *)parent; - struct disklabel *dl; + struct rx_softc *rx = (void *)self; + struct drive_attach_args *da = aux; + struct mscp *mp = da->da_mp; + struct mscp_softc *mi = (void *)parent; - rx->ra_mediaid = mp->mscp_guse.guse_mediaid; + bcopy(&mp->mscp_guse, &rx->ra_guse, sizeof(struct mscpv_guse)); rx->ra_state = DK_CLOSED; rx->ra_hwunit = mp->mscp_unit; mi->mi_dp[mp->mscp_unit] = self; @@ -500,13 +525,6 @@ rxattach(parent, self, aux) rx->ra_disk.dk_name = rx->ra_dev.dv_xname; disk_attach(&rx->ra_dev, &rx->ra_disk); - /* Fill in what we know. The actual size is gotten later */ - dl = rx->ra_disk.dk_label; - - dl->d_secsize = DEV_BSIZE; - dl->d_nsectors = mp->mscp_guse.guse_nspt; - dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group; - dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid); #ifdef DEBUG printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n", @@ -516,19 +534,20 @@ rxattach(parent, self, aux) #endif } -/* +/* * (Try to) put the drive online. This is done the first time the - * drive is opened, or if it har fallen offline. + * drive is opened, or if it has fallen offline. */ int -rx_putonline(rx) - struct rx_softc *rx; +rx_putonline(struct rx_softc *rx) { - struct mscp *mp; - struct mscp_softc *mi = (struct mscp_softc *)rx->ra_dev.dv_parent; + struct mscp *mp; + struct mscp_softc *mi = (struct mscp_softc *)rx->ra_dev.dv_parent; volatile int i; - rx->ra_state = DK_CLOSED; + /* caller may be in DK_RDLABEL state */ + if (rx->ra_state == DK_OPEN) + rx->ra_state = DK_CLOSED; mp = mscp_getcp(mi, MSCP_WAIT); mp->mscp_opcode = M_OP_ONLINE; mp->mscp_unit = rx->ra_hwunit; @@ -538,11 +557,10 @@ rx_putonline(rx) /* Poll away */ i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0); - if (tsleep(&rx->ra_dev.dv_unit, PRIBIO, "rxonline", 100*100)) + if (tsleep(&rx->ra_dev.dv_unit, PRIBIO, "rxonline", 100*100) != 0) { rx->ra_state = DK_CLOSED; - - if (rx->ra_state == DK_CLOSED) return MSCP_FAILED; + } return MSCP_DONE; } @@ -554,10 +572,7 @@ rx_putonline(rx) */ /*ARGSUSED*/ int -rxopen(dev, flag, fmt, p) - dev_t dev; - int flag, fmt; - struct proc *p; +rxopen(dev_t dev, int flag, int fmt, struct proc *p) { struct rx_softc *rx; int unit; @@ -585,10 +600,7 @@ rxopen(dev, flag, fmt, p) /* ARGSUSED */ int -rxclose(dev, flags, fmt, p) - dev_t dev; - int flags, fmt; - struct proc *p; +rxclose(dev_t dev, int flags, int fmt, struct proc *p) { return (0); } @@ -601,8 +613,7 @@ rxclose(dev, flags, fmt, p) * revectoring routine. */ void -rxstrategy(bp) - struct buf *bp; +rxstrategy(struct buf *bp) { int unit; struct rx_softc *rx; @@ -649,18 +660,14 @@ done: } int -rxread(dev, uio) - dev_t dev; - struct uio *uio; +rxread(dev_t dev, struct uio *uio) { return (physio(rxstrategy, dev, B_READ, minphys, uio)); } int -rxwrite(dev, uio) - dev_t dev; - struct uio *uio; +rxwrite(dev_t dev, struct uio *uio) { return (physio(rxstrategy, dev, B_WRITE, minphys, uio)); @@ -670,12 +677,7 @@ rxwrite(dev, uio) * I/O controls. */ int -rxioctl(dev, cmd, data, flag, p) - dev_t dev; - int cmd; - caddr_t data; - int flag; - struct proc *p; +rxioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int unit = DISKUNIT(dev); struct disklabel *lp; @@ -710,11 +712,7 @@ rxioctl(dev, cmd, data, flag, p) } int -rxdump(dev, blkno, va, size) - dev_t dev; - daddr64_t blkno; - caddr_t va; - size_t size; +rxdump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) { /* Not likely. */ @@ -722,8 +720,7 @@ rxdump(dev, blkno, va, size) } daddr64_t -rxsize(dev) - dev_t dev; +rxsize(dev_t dev) { return -1; @@ -740,8 +737,7 @@ int rrioerror(struct device *, struct mscp *, struct buf *); void rrfillin(struct buf *, struct mscp *); void rrbb(struct device *, struct mscp *, struct buf *); - -struct mscp_device ra_device = { +struct mscp_device ra_device = { rrdgram, rriodone, rronline, @@ -755,30 +751,25 @@ struct mscp_device ra_device = { /* * Handle an error datagram. * This can come from an unconfigured drive as well. - */ -void -rrdgram(usc, mp, mi) - struct device *usc; - struct mscp *mp; - struct mscp_softc *mi; -{ + */ +void +rrdgram(struct device *usc, struct mscp *mp, struct mscp_softc *mi) +{ if (mscp_decodeerror(usc == NULL?"unconf disk" : usc->dv_xname, mp, mi)) - return; + return; /* * SDI status information bytes 10 and 11 are the microprocessor * error code and front panel code respectively. These vary per * drive type and are printed purely for field service information. */ - if (mp->mscp_format == M_FM_SDI) + if (mp->mscp_format == M_FM_SDI) printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n", mp->mscp_erd.erd_sdistat[10], mp->mscp_erd.erd_sdistat[11]); } -void -rriodone(usc, bp) - struct device *usc; - struct buf *bp; +void +rriodone(struct device *usc, struct buf *bp) { int s; struct rx_softc *rx = NULL; /* Wall */ @@ -806,12 +797,9 @@ rriodone(usc, bp) * sleeping on the drive on-line-ness. */ int -rronline(usc, mp) - struct device *usc; - struct mscp *mp; +rronline(struct device *usc, struct mscp *mp) { struct rx_softc *rx = (struct rx_softc *)usc; - struct disklabel *dl; wakeup((caddr_t)&usc->dv_unit); if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { @@ -821,65 +809,17 @@ rronline(usc, mp) } rx->ra_state = DK_OPEN; - - dl = rx->ra_disk.dk_label; - DL_SETDSIZE(dl, mp->mscp_onle.onle_unitsize); - - if (dl->d_secpercyl) { - dl->d_ncylinders = DL_GETDSIZE(dl) / dl->d_secpercyl; - dl->d_type = DTYPE_MSCP; - } else { - dl->d_type = DTYPE_FLOPPY; - } - rrmakelabel(dl, rx->ra_mediaid); + rx->ra_unitsize = mp->mscp_onle.onle_unitsize; return (MSCP_DONE); } -void -rrmakelabel(dl, type) - struct disklabel *dl; - long type; -{ - int n, p = 0; - - dl->d_bbsize = BBSIZE; - dl->d_sbsize = SBSIZE; - - /* Create the disk name for disklabel. Phew... */ - dl->d_typename[p++] = MSCP_MID_CHAR(2, type); - dl->d_typename[p++] = MSCP_MID_CHAR(1, type); - if (MSCP_MID_ECH(0, type)) - dl->d_typename[p++] = MSCP_MID_CHAR(0, type); - n = MSCP_MID_NUM(type); - if (n > 99) { - dl->d_typename[p++] = '1'; - n -= 100; - } - if (n > 9) { - dl->d_typename[p++] = (n / 10) + '0'; - n %= 10; - } - dl->d_typename[p++] = n + '0'; - dl->d_typename[p] = 0; - dl->d_npartitions = MAXPARTITIONS; - DL_SETPSIZE(&dl->d_partitions[0], DL_GETDSIZE(dl)); - DL_SETPSIZE(&dl->d_partitions[2], DL_GETDSIZE(dl)); - DL_SETPOFFSET(&dl->d_partitions[0], 0); - DL_SETPOFFSET(&dl->d_partitions[2], 0); - dl->d_version = 1; - dl->d_magic = dl->d_magic2 = DISKMAGIC; - dl->d_checksum = dkcksum(dl); -} - -/* +/* * We got some (configured) unit's status. Return DONE if it succeeded. */ int -rrgotstatus(usc, mp) - struct device *usc; - struct mscp *mp; -{ +rrgotstatus(struct device *usc, struct mscp *mp) +{ if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { printf("%s: attempt to get status failed: ", usc->dv_xname); mscp_printevent(mp); @@ -892,14 +832,12 @@ rrgotstatus(usc, mp) return (MSCP_DONE); } -/* +/* * A replace operation finished. */ /*ARGSUSED*/ -void -rrreplace(usc, mp) - struct device *usc; - struct mscp *mp; +void +rrreplace(struct device *usc, struct mscp *mp) { panic("udareplace"); @@ -910,11 +848,8 @@ rrreplace(usc, mp) * Need to write the bad block forwaring code first.... */ /*ARGSUSED*/ -int -rrioerror(usc, mp, bp) - struct device *usc; - struct mscp *mp; - struct buf *bp; +int +rrioerror(struct device *usc, struct mscp *mp, struct buf *bp) { struct ra_softc *ra = (void *)usc; int code = mp->mscp_event; @@ -946,9 +881,7 @@ rrioerror(usc, mp, bp) * Fill in disk addresses in a mscp packet waiting for transfer. */ void -rrfillin(bp, mp) - struct buf *bp; - struct mscp *mp; +rrfillin(struct buf *bp, struct mscp *mp) { struct rx_softc *rx = 0; /* Wall */ struct disklabel *lp; @@ -975,10 +908,7 @@ rrfillin(bp, mp) */ /*ARGSUSED*/ void -rrbb(usc, mp, bp) - struct device *usc; - struct mscp *mp; - struct buf *bp; +rrbb(struct device *usc, struct mscp *mp, struct buf *bp) { panic("udabb"); |