diff options
Diffstat (limited to 'sys/dev/slice/mbr.c')
-rw-r--r-- | sys/dev/slice/mbr.c | 837 |
1 files changed, 837 insertions, 0 deletions
diff --git a/sys/dev/slice/mbr.c b/sys/dev/slice/mbr.c new file mode 100644 index 0000000..7babfc9 --- /dev/null +++ b/sys/dev/slice/mbr.c @@ -0,0 +1,837 @@ +/*- + * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. + * julian@freebsd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: $ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/fcntl.h> +#include <sys/disklabel.h> +#include <sys/dkstat.h> +#include <sys/malloc.h> +#include <sys/sliceio.h> +#include <dev/slice/slice.h> + + +struct private_data { + u_int32_t flags; + struct slice *slice_down; + int savedoflags; + struct dos_partition dos_table[NDOSPART]; + struct subdev { + int part; + struct slice *slice; + struct slicelimits limit; + struct private_data *pd; + u_int32_t offset; /* Fdisk only has 32 bits */ + } subdevs[NDOSPART]; +}; +/* + * Bits in the mbr private data flag word + */ +#define MBRF_OPEN_RBIT 0x01 +#define MBRF_S1_OPEN_RD 0x01 +#define MBRF_S2_OPEN_RD 0x02 +#define MBRF_S3_OPEN_RD 0x04 +#define MBRF_S4_OPEN_RD 0x08 +#define MBRF_MSK_RD 0x0F +#define MBRF_OPEN_WBIT 0x10 +#define MBRF_S1_OPEN_WR 0x10 +#define MBRF_S2_OPEN_WR 0x20 +#define MBRF_S3_OPEN_WR 0x40 +#define MBRF_S4_OPEN_WR 0x80 +#define MBRF_MSK_WR 0xF0 +#define MBRF_MSK_OPEN 0xFF + +static struct dos_partition historical_bogus_partition_table[NDOSPART] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000,}, +}; +#define DOSPTYP_ONTRACK 84 + +static sl_h_constructor_t mbr_constructor; /* constructor (from device) */ +static sl_h_IO_req_t mbr_IOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t mbr_ioctl; /* ioctl req downward (to device) */ +static sl_h_open_t mbr_open; /* downwards travelling open */ +static sl_h_close_t mbr_close; /* downwards travelling close */ +static sl_h_claim_t mbr_claim; /* upwards travelling claim */ +static sl_h_revoke_t mbr_revoke;/* upwards travelling revokation */ +static sl_h_verify_t mbr_verify;/* things changed, are we stil valid? */ +static sl_h_upconfig_t mbr_upconfig;/* config request from below */ + +static struct slice_handler slicetype = { + "MBR", + 0, + NULL, + 0, + &mbr_constructor, /* constructor */ + &mbr_IOreq, + &mbr_ioctl, + &mbr_open, + &mbr_close, + &mbr_revoke, /* revoke */ + &mbr_claim, /* claim */ + &mbr_verify, /* verify */ + &mbr_upconfig /* config from below */ +}; + +static void +sd_drvinit(void *unused) +{ + sl_newtype(&slicetype); +} + +SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL); + +/* + * Given a slice, extract out our table of information + */ +static int +mbr_find_table(sl_p slice, struct buf **bpp, int *blknum) +{ + int ontrack_offset = 0; + int error; + u_int8_t *cp; + struct dos_partition *dp0, *dp; + int part; + int redone = 0; + struct buf *bp; + +RR; + *bpp = NULL; +reread: + if (error = slice_readblock(slice, ontrack_offset, &bp)) + return (error); + cp = bp->b_data; + if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + error = EINVAL; + goto done; + } + dp0 = (struct dos_partition *) (cp + DOSPARTOFF); + + /* + * Check for "Ontrack Diskmanager". Note that if the geometry is + * still needed then we probably won't be able to read a DiskManager + * MBR because we will fail to read sector 63. The very act of + * finding a Disk Manager might however have given us the info we + * need if the disk manager set's its partition up correctly. + */ + if (!redone) { + for (part = 0, dp = dp0; + part < NDOSPART; part++, dp++) { + if (dp->dp_typ == DOSPTYP_ONTRACK) { +#ifdef MAYBE + /* + * It's not known if this should always 63 or + * if this is just the start of the 2nd + * track. + */ + ontrack_offset = dp->dp_start; +#else + ontrack_offset = 63; +#endif + if (bootverbose) + printf("Found \"Ontrack Disk Manager\"\n"); + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + redone++; + goto reread; + } + } + } +done: + if (blknum) + *blknum = ontrack_offset; + *bpp = bp; + return (error); +} + +/* + * Given a slice, extract out our table of information + */ +static int +mbr_extract_table(sl_p slice, struct dos_partition *table) +{ + int error; + struct buf *bp; + +RR; + /* start off with a known result */ + bzero(table, sizeof(*table) * NDOSPART); + error = mbr_find_table(slice, &bp, NULL); + if (!error) + bcopy((bp->b_data + DOSPARTOFF), table, + sizeof(*table) * NDOSPART); +done: + if (bp) { + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + } + return (error); +} + +/* + * read the block and replace the mbr table with that given. + * If there isn't one, clear the rest of the block. + */ +static int +mbr_insert_table(sl_p slice, struct dos_partition *table) +{ + int blknum = 0; + int error; + struct buf *bp; + +RR; + error = mbr_find_table(slice, &bp, &blknum); + if ( error == EINVAL) { + /* + * The block was read, but there was no table there. + * just clear out the cruft for now. + */ + bzero(bp->b_data, slice->limits.blksize); + } else if (error == 0) { + bcopy( table, (bp->b_data + DOSPARTOFF), + sizeof(*table) * NDOSPART); + bp->b_data[0x1FE] = 0x55; + bp->b_data[0x1FF] = 0xAA; + /* XXX Somehow we should get boot code in there too. */ + /* for now leave it to the tool */ + error = slice_writeblock(slice, blknum, bp); + } +done: + if (bp) { + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + } + return (error); +} + +/* + * look at a slice and figure out if we should be interested in it. (Is it + * ours?) + */ +static int +mbr_claim(struct slice * slice, struct slice * lower, void *ID) +{ + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + int max_ncyls; + int max_nsectors; + int max_ntracks; + u_int32_t secpercyl; + int numactive = 0; +RR; + + /* + * Don't even BOTHER if it's not 512 byte sectors + */ + if (slice->limits.blksize != 512) + return (EINVAL); + /* + * Try load a valid MBR table. This is 90% of what we need to check. + */ + if ((error = mbr_extract_table(slice, table)) != 0) { + return (error); + } + dp0 = table; + /* + * The first block of the dos code is marked like a valid MBR. + * Try to distinguish this case byt doing a sanity check on the table. + * Check: + * Flag byte can only be 0 or 0x80. + * At most one active partition. + * -Other tests to be added here- + */ + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + if (dp->dp_flag & 0x7f) { + printf ("rejected.. bad flag "); + return(EINVAL); /* must be either 0 or 0x80 */ + } + if ((dp->dp_typ) && (dp->dp_size) && (dp->dp_start == 0)) { + printf("rejected.. Slice includes MBR "); + return (EINVAL); + } + if (dp->dp_flag == 0x80) + numactive++; + } + if (numactive > 1) { + printf ("rejected.. multiple active "); + return (EINVAL); + } + /* + * If it's the MBR that comes with the disklabel then we should just + * give up and let the disklabel handler take control of this slice. + */ + if (bcmp(dp0, historical_bogus_partition_table, + sizeof historical_bogus_partition_table) == 0) { + printf("rejecting disklabel table "); + return (EINVAL); + } + /* + * well, it looks like one of ours. + */ + return (0); +} + +/* + * This routine tries to guess the geometry for + * old disk drivers that need the MBR code to set it. Bits taken from + * diskslice_machdep.c which itself evolved from earlier code. + * This is not part of the SLICE code per-se, but just a convenient place to + * put this HACK because everything is in scope. Only called by the IDE driver. + */ +int +mbr_geom_hack(struct slice * slice, struct ide_geom *geom) +{ + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + int max_ncyls; + int max_nsectors; + int max_ntracks; + u_int32_t secpercyl; +RR; + + /* + * Don't even BOTHER if it's not claimable by us. + */ + if ((error = mbr_claim(slice,NULL,0))) + return (error); + /* + * Load the mbr. + */ + if ((error = mbr_extract_table(slice, table)) != 0) { + return (error); + } + dp0 = table; + /* + * Guess the geometry. For some old drives (ESDI, st506) the + * driver below us may not yet know the geometry, but needs + * to before it can access blocks out of the first track. + * This hack is to use information in the MBR to "deduce" + * this information and pass it back. + */ + max_ncyls = 0; + max_nsectors = 0; + max_ntracks = 0; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + int ncyls; + int nsectors; + int ntracks; + + if (dp->dp_size == 0) + continue; + ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1; + if (max_ncyls < ncyls) + max_ncyls = ncyls; + nsectors = DPSECT(dp->dp_esect); + if (max_nsectors < nsectors) + max_nsectors = nsectors; + ntracks = dp->dp_ehd + 1; + if (max_ntracks < ntracks) + max_ntracks = ntracks; + } + if ((max_ncyls == 0) + && (max_nsectors == 0) + && (max_ntracks == 0)) { + /* we've gained nought, so just return */ + return (EINVAL); + } + secpercyl = (u_long) max_nsectors *max_ntracks; + printf("s=%d, h=%d, c=%d\n", max_nsectors, max_ntracks, max_ncyls); + /* + * Check that we have guessed the geometry right by checking + * the partition entries. + */ + error = 0; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + int cyl; + int sector; + int track; + int secpercyl; + + if (dp->dp_size == 0) + continue; + cyl = DPCYL(dp->dp_scyl, dp->dp_ssect); + track = dp->dp_shd; + sector = DPSECT(dp->dp_ssect) - 1; + secpercyl = max_nsectors * max_ntracks; + /* + * If the geometry doesn't work for any partition + * start then don't accept it. + */ + if (((((dp->dp_start / secpercyl) % 1024) != cyl) + && (cyl != 1023)) + || (((dp->dp_start % secpercyl) + / max_nsectors) != track) + || (((dp->dp_start % secpercyl) + % max_nsectors) != sector)) { + printf("Can't get disk geometry from MBR\n"); + return (EINVAL); + } + if ((dp->dp_start / secpercyl) > 1023) { + printf("part %d above BIOS reach\n", part); + } + } + + /* + * Set our newely hypothesised numbers into the geometry + * slots in the supplied SLICE. + */ + geom->secpertrack = max_nsectors; + geom->trackpercyl = max_ntracks; + geom->cyls = max_ncyls; + return (0); +} + +/* + * look at a slice we know to be ours and decide what the #$%^ to do with it. + * We presume the driver already did the geometry hack if needed. + */ +static int +mbr_constructor(sl_p slice) +{ + int i; + u_int64_t disksize = slice->limits.slicesize; + struct private_data *pd; + struct dos_partition *dp, *dp0; + int redone = 0; + int ontrack_offset = 0; + char name[64]; + sh_p tp; + + int part; + int error = 0; + +RR; + /* + * If we are being called to re-load a slice, + * then don't reallocate resources. + */ + if ( (pd = slice->private_up) == NULL) { + if (slice->name == NULL) { + printf("name is NULL\n"); + return (EINVAL); + } + if (strlen(slice->name) > 58) { + printf("slice: name %s too long\n", slice->name); + return (ENAMETOOLONG); + } + pd = malloc(sizeof(*pd), M_DEVBUF, M_NOWAIT); + if (pd == NULL) { + printf("fdisk: failed malloc\n"); + return (ENOMEM); + } + bzero(pd, sizeof(*pd)); + pd->slice_down = slice; + if ((error = mbr_extract_table(slice, pd->dos_table)) != 0) { + /* + * If it's just that there is no table there, + * Then we fake an empty one up and write it. if + * this were not ok, then we would have not been + * called. (as probe will have failed). If it's + * a physical error, then that's reason to fail. + */ + if (error != EINVAL) { + free(pd, M_DEVBUF); + return (error); + } + bzero(pd->dos_table, sizeof(pd->dos_table)); + if ((error = mbr_insert_table(slice, pd->dos_table))) { + free(pd, M_DEVBUF); + return (error); + } + + } + slice->refs++; + slice->handler_up = &slicetype; + slice->private_up = pd; + slicetype.refs++; + } + + dp0 = pd->dos_table; + + /* + * Handle each of the partitions. + * We should check that each makes sence and is legal. + * 1/ it should not already have a slice. + * 2/ should not be 0 length. + * 3/ should not go past end of our slice. + * 4/ should not include sector 0. + * 5/ should not overlap other slices. + */ + dp = dp0; + for (part = 0; part < NDOSPART; part++, dp++) { + int i; + if (pd->subdevs[part].slice != NULL) +breakout: continue; + if (dp->dp_size == 0) + continue; + if (dp->dp_start < 1) + continue; + if ((dp->dp_start + dp->dp_size) > + (slice->limits.slicesize/slice->limits.blksize)) + continue; + /* check for overlaps with existing slices */ + for (i = 0; i < NDOSPART; i++) { + /* skip empty slots (including this one) */ + if(pd->subdevs[i].slice == NULL ) + continue; + if ((dp0[i].dp_start < (dp->dp_start + dp->dp_size)) + && ((dp0[i].dp_start + dp0[i].dp_size) > dp->dp_start)) + { + printf("mbr: new slice %d overlaps slice %d\n", + part, i); + goto breakout; + } + } + /* + * the slice seems to make sense. Use it. + */ + pd->subdevs[part].part = part; + pd->subdevs[part].pd = pd; + pd->subdevs[part].offset = dp->dp_start; + pd->subdevs[part].limit.blksize + = slice->limits.blksize; + pd->subdevs[part].limit.slicesize + = (slice->limits.blksize * (u_int64_t)dp->dp_size); + + sprintf(name, "%ss%d", slice->name, part + 1); + sl_make_slice(&slicetype, + &pd->subdevs[part], + &pd->subdevs[part].limit, + &pd->subdevs[part].slice, + NULL, + name); + pd->subdevs[part].slice->probeinfo.typespecific = &dp->dp_typ; + switch (dp->dp_typ) { /* list stolen from fdisk */ + case 0x00: /* "unused" */ + case 0x01: /* "Primary DOS with 12 bit FAT" */ + case 0x02: /* "XENIX / filesystem" */ + case 0x03: /* "XENIX /usr filesystem" */ + case 0x04: /* "Primary DOS with 16 bit FAT" */ + case 0x05: /* "Extended DOS" */ + case 0x06: /* "Primary 'big' DOS (> 32MB)" */ + case 0x07: /* "OS/2 HPFS, QNX or Advanced UNIX" */ + case 0x08: /* "AIX filesystem" */ + case 0x09: /* "AIX boot partition or Coherent" */ + case 0x0A: /* "OS/2 Boot Manager or OPUS" */ + case 0x10: /* "OPUS" */ + case 0x40: /* "VENIX 286" */ + case 0x50: /* "DM" */ + case 0x51: /* "DM" */ + case 0x52: /* "CP/M or Microport SysV/AT" */ + case 0x56: /* "GB" */ + case 0x61: /* "Speed" */ + case 0x63: /* "ISC UNIX, System V/386, GNU HURD or Mach" */ + case 0x64: /* "Novell Netware 2.xx" */ + case 0x65: /* "Novell Netware 3.xx" */ + case 0x75: /* "PCIX" */ + case 0x80: /* "Minix 1.1 ... 1.4a" */ + case 0x81: /* "Minix 1.4b ... 1.5.10" */ + case 0x82: /* "Linux swap" */ + case 0x83: /* "Linux filesystem" */ + case 0x93: /* "Amoeba filesystem" */ + case 0x94: /* "Amoeba bad block table" */ + case 0xA6: /* "OpenBSD" */ + case 0xA7: /* "NEXTSTEP" */ + case 0xB7: /* "BSDI BSD/386 filesystem" */ + case 0xB8: /* "BSDI BSD/386 swap" */ + case 0xDB: /* "Concurrent CPM or C.DOS or CTOS" */ + case 0xE1: /* "Speed" */ + case 0xE3: /* "Speed" */ + case 0xE4: /* "Speed" */ + case 0xF1: /* "Speed" */ + case 0xF2: /* "DOS 3.3+ Secondary" */ + case 0xF4: /* "Speed" */ + case 0xFF: /* "BBT (Bad Blocks Table)" */ + printf("%s: type %d. Leaving\n", + pd->subdevs[part].slice->name, + (u_int)dp->dp_typ); + pd->subdevs[part].slice->probeinfo.type = NO_SUBPART; + break; + case DOSPTYP_386BSD: /* 0xA5 "FreeBSD/NetBSD/386BSD" */ + pd->subdevs[part].slice->probeinfo.type = "disklabel"; + break; + default: + pd->subdevs[part].slice->probeinfo.type = NULL; + } + if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) { + (*tp->constructor)(pd->subdevs[part].slice); + } + } + return (error); +} + +/* + * look at a slice that USED to be ours. + * decide if any sub-slices need to be revoked. + * If not then at least ask them to verify themselves. + * Note, arg 'slice' is not strictly needed + */ +static int +mbr_verify(sl_p slice) +{ + register struct private_data *pd; + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + /* register struct slice *slice; */ + +RR; + pd = slice->private_up; + /* slice = pd->slice_down; */ + bzero(table, sizeof(table)); + /* + * Try load a valid MBR table. This is 90% of what we need to check. + */ + if ((slice->limits.blksize != 512) + || ((error = mbr_extract_table(slice, table)) != 0)) { + /* + * Oh oh, we need to invalidate all the subslices. + * and relinquish this slice. + */ + return(mbr_revoke(pd)); + } + /* + * For each existing subslice, check that the basic size + * and position has not changed. Also check the TYPE. + * It is possible we should allow a slice to grow. + */ + dp = dp0 = pd->dos_table; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + if (pd->subdevs[part].slice) { + if ((table[part].dp_start != dp->dp_start) + || (table[part].dp_size != dp->dp_size) + || (table[part].dp_typ != dp->dp_typ) ) { + sl_rmslice(pd->subdevs[part].slice); + pd->subdevs[part].slice = NULL; + } else if ( pd->subdevs[part].slice->handler_up) { + (*pd->subdevs[part].slice->handler_up->verify) + (pd->subdevs[part].slice); + } + } + } + /* + * Having got rid of changing slices, replace + * the old table with the new one, and + * Handle any new slices by calling the constructor. + * This way, if we are in 'promiscuous' mode, + * (e.g. repartitionning a disk we are running on from + * Single user mode, the unchanged slices can remain open and active + * through the process. If you change an open slice, + * the vnodes will be changed to deadfs so a crash is probably + * nearby. XXX too late. It's written to disk.. (we COULD reverse it, + * but....) + */ + bcopy( table, dp0, sizeof(table)); + error = mbr_constructor(slice); + return (error); +} + +/* + * Invalidate all subslices, and free resources for this handler instance. + */ +static int +mbr_revoke(void *private) +{ + register struct private_data *pd; + register struct slice *slice; + int part; + +RR; + pd = private; + slice = pd->slice_down; + for (part = 0; part < NDOSPART; part++) { + if (pd->subdevs[part].slice) { + sl_rmslice(pd->subdevs[part].slice); + } + } + /* + * remove ourself as a handler + */ + slice->handler_up = NULL; + slice->private_up = NULL; + slicetype.refs--; + free(pd,M_DEVBUF); + sl_unref(slice); + return (0); +} + +/* + * shift the appropriate IO by the offset for that slice. + */ +static void +mbr_IOreq(void *private, struct buf * bp) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + +RR; + sdp = private; + pd = sdp->pd; + slice = pd->slice_down; + bp->b_pblkno += sdp->offset; /* add the offset for that slice */ + sliceio(slice, bp, SLW_ABOVE); +} + +static int +mbr_open(void *private, int flags, int mode, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int part; + int error; + int newflags = 0; + int oldoflags = 0; + int newoflags = 0; + +RR; + sdp = private; + part = sdp->part; + pd = sdp->pd; + slice = pd->slice_down; + + /* + * Calculate the change to to over-all picture here. + * Notice that this might result in LESS open bits + * if that was what was passed from above. + * (Prelude to 'mode-change' instead of open/close.) + */ + /* work out what our stored flags will be if this succeeds */ + newflags = pd->flags & ~((MBRF_OPEN_WBIT|MBRF_OPEN_RBIT) << part); + newflags |= (flags & FWRITE) ? (MBRF_OPEN_WBIT << part) : 0; + newflags |= (flags & FREAD) ? (MBRF_OPEN_RBIT << part) : 0; + + /* work out what we want to pass down this time */ + newoflags = (newflags & MBRF_MSK_WR) ? FWRITE : 0; + newoflags |= (newflags & MBRF_MSK_RD) ? FREAD : 0; + + /* + * If the agregate flags we used last time are the same as + * the agregate flags we would use this time, then don't + * bother re-doing the command. + */ + if (newoflags != pd->savedoflags) { + if (error = sliceopen(slice, newoflags, mode, p, SLW_ABOVE)) { + return (error); + } + } + + /* + * Now that we know it succeeded, commit, by replacing the old + * flags with the new ones. + */ + pd->flags &= ~MBRF_MSK_OPEN; + pd->flags |= newflags; + pd->savedoflags = newoflags; + return (0); +} + +static void +mbr_close(void *private, int flags, int mode, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int newflags; + int newoflags; + int part; + +RR; + sdp = private; + part = sdp->part; + pd = sdp->pd; + slice = pd->slice_down; + + if ((pd->flags & MBRF_MSK_OPEN) == 0) + return; + + /* work out what our stored flags will be if this succeeds */ + newflags = pd->flags & ~((MBRF_OPEN_WBIT|MBRF_OPEN_RBIT) << part); + newflags |= (flags & FWRITE) ? (MBRF_OPEN_WBIT << part) : 0; + newflags |= (flags & FREAD) ? (MBRF_OPEN_RBIT << part) : 0; + + /* work out what we want to pass down this time */ + newoflags = (newflags & MBRF_MSK_WR) ? FWRITE : 0; + newoflags |= (newflags & MBRF_MSK_RD) ? FREAD : 0; + + /* + * If this was the last open slice above, then release our own open + */ + pd->flags &= ~((MBRF_OPEN_RBIT|MBRF_OPEN_WBIT) << part); + if (pd->flags & MBRF_MSK_OPEN) { + sliceclose(slice, newoflags, mode, p, SLW_ABOVE); + } + pd->flags &= ~MBRF_MSK_OPEN; + pd->flags |= newflags; + pd->savedoflags = newoflags; + return ; +} + +static int +mbr_ioctl(void *private, int cmd, caddr_t addr, int flag, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int error; + +RR; + sdp = private; + pd = sdp->pd; + slice = pd->slice_down; + + return ((*slice->handler_down->ioctl) (slice->private_down, + cmd, addr, flag, p)); +} + +static int +mbr_upconfig(struct slice *slice, int cmd, caddr_t addr, + int flag, struct proc * p) +{ + RR; + switch (cmd) { + case SLCIOCRESET: + return (0); + +/* These don't really make sense. keep the headers for a reminder */ + default: + return (ENOIOCTL); + } + return (0); +} + |