c77c9fb18b
Failing to probe is not an error, just a negative result.
726 lines
19 KiB
C
726 lines
19 KiB
C
/*-
|
|
* 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: mbr.c,v 1.8 1998/07/20 04:12:39 julian Exp $
|
|
*/
|
|
|
|
#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 buf *bp; */
|
|
u_int32_t table_offset;
|
|
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
|
|
|
|
#define DOSPTYP_ONTRACK 84
|
|
|
|
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 sl_h_dump_t mbr_dump; /* core dump req downward */
|
|
static sl_h_done_t mbr_done; /* callback after async request */
|
|
|
|
static struct slice_handler slicetype = {
|
|
"MBR",
|
|
0,
|
|
NULL,
|
|
0,
|
|
&mbr_done,
|
|
&mbr_IOreq,
|
|
&mbr_ioctl,
|
|
&mbr_open,
|
|
/*&mbr_close*/NULL,
|
|
&mbr_revoke, /* revoke */
|
|
&mbr_claim, /* claim */
|
|
&mbr_verify, /* verify */
|
|
&mbr_upconfig, /* config from below */
|
|
&mbr_dump
|
|
};
|
|
|
|
static void
|
|
sd_drvinit(void *unused)
|
|
{
|
|
sl_newtype(&slicetype);
|
|
}
|
|
|
|
SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL);
|
|
|
|
/*
|
|
* Allocate and the private data.
|
|
*/
|
|
static int
|
|
mbrallocprivate(sl_p slice)
|
|
{
|
|
register struct private_data *pd;
|
|
|
|
pd = malloc(sizeof(*pd), M_DEVBUF, M_NOWAIT);
|
|
if (pd == NULL) {
|
|
printf("mbr: failed malloc\n");
|
|
return (ENOMEM);
|
|
}
|
|
bzero(pd, sizeof(*pd));
|
|
pd->slice_down = slice;
|
|
slice->refs++;
|
|
slice->handler_up = &slicetype;
|
|
slice->private_up = pd;
|
|
slicetype.refs++;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
mbr_claim(sl_p slice)
|
|
{
|
|
int error = 0;
|
|
/*
|
|
* Don't even BOTHER if it's not 512 byte sectors
|
|
*/
|
|
if (slice->limits.blksize != 512)
|
|
return (EINVAL);
|
|
if (slice->private_up == NULL) {
|
|
if ((error = mbrallocprivate(slice))) {
|
|
return (error);
|
|
}
|
|
}
|
|
if ((error = slice_request_block(slice, 0))) {
|
|
mbr_revoke(slice->private_up);
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
mbr_verify(sl_p slice)
|
|
{
|
|
int error = 0;
|
|
/*
|
|
* Don't even BOTHER if it's not 512 byte sectors
|
|
*/
|
|
if (slice->limits.blksize != 512)
|
|
return (EINVAL);
|
|
if ((error = slice_request_block(slice, 0))) {
|
|
mbr_revoke(slice->private_up);
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* called with an argument of a bp when it is completed
|
|
*/
|
|
static int
|
|
mbr_done(sl_p slice, struct buf *bp)
|
|
{
|
|
struct private_data *pd;
|
|
struct dos_partition table[NDOSPART];
|
|
struct dos_partition *dp0, *dp, *dp2;
|
|
u_int8_t *cp;
|
|
int part;
|
|
int numactive = 0;
|
|
int i;
|
|
char name[64];
|
|
int error = 0;
|
|
|
|
RR;
|
|
/*
|
|
* Discover whether the IO was successful.
|
|
*/
|
|
pd = slice->private_up;
|
|
if ( bp->b_flags & B_ERROR ) {
|
|
error = bp->b_error;
|
|
bp->b_flags |= B_INVAL | B_AGE;
|
|
brelse(bp);
|
|
if (bootverbose)
|
|
printf ("failed.. IO error ");
|
|
goto nope;
|
|
}
|
|
cp = bp->b_data;
|
|
if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) {
|
|
bp->b_flags |= B_INVAL | B_AGE;
|
|
brelse(bp);
|
|
if (bootverbose)
|
|
printf ("rejected.. bad magic ");
|
|
goto nope;
|
|
}
|
|
dp0 = (struct dos_partition *) (cp + DOSPARTOFF);
|
|
|
|
/* copy the table out of the buf and release it. */
|
|
bcopy(dp0, table, sizeof(table));
|
|
bp->b_flags |= B_INVAL | B_AGE;
|
|
brelse(bp);
|
|
|
|
/*
|
|
* 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.
|
|
* XXX not true with interrupt driven probes.
|
|
*/
|
|
if (pd->table_offset == 0) {
|
|
for (part = 0, dp = table;
|
|
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.
|
|
*/
|
|
pd->table_offset = dp->dp_start;
|
|
#else
|
|
pd->table_offset = 63;
|
|
#endif
|
|
if (bootverbose)
|
|
printf("Found \"Ontrack Disk Manager\"\n");
|
|
slice_request_block(slice, pd->table_offset);
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The first block of the dos code is marked like a valid MBR.
|
|
* Try to distinguish this case by 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 = table; part < NDOSPART; part++, dp++) {
|
|
if (dp->dp_flag & 0x7f) {
|
|
if (bootverbose)
|
|
printf ("rejected.. bad flag ");
|
|
goto nope;
|
|
}
|
|
if ((dp->dp_typ) && (dp->dp_size) && (dp->dp_start == 0)) {
|
|
if (bootverbose)
|
|
printf("rejected.. Slice includes MBR ");
|
|
goto nope;
|
|
}
|
|
if (dp->dp_flag == 0x80)
|
|
numactive++;
|
|
}
|
|
if (numactive > 1) {
|
|
if (bootverbose)
|
|
printf ("rejected.. multiple active ");
|
|
goto nope;
|
|
}
|
|
/*-
|
|
* Handle the case when we are being asked to reevaluate
|
|
* an already loaded mbr table.
|
|
* We've already handled the case when it's completely vanished.
|
|
*
|
|
* Look at a slice that USED to be ours.
|
|
* Decide if any sub-slices need to be revoked.
|
|
* For each existing subslice, check that the basic size
|
|
* and position has not changed. Also check the TYPE.
|
|
* If not then at least ask them to verify themselves.
|
|
* It is possible we should allow a slice to grow.
|
|
*/
|
|
dp = pd->dos_table;
|
|
dp0 = pd->dos_table;
|
|
dp2 = table;
|
|
for (part = 0; part < NDOSPART; part++, dp++, dp2++) {
|
|
if (pd->subdevs[part].slice) {
|
|
if ((dp2->dp_start != dp->dp_start)
|
|
|| (dp2->dp_size != dp->dp_size)
|
|
|| (dp2->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.
|
|
*/
|
|
bcopy( table, pd->dos_table, sizeof(table));
|
|
|
|
/*
|
|
* Handle each of the partitions.
|
|
* We should check that each makes sense 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.
|
|
*
|
|
* Be aware that this may queue up one (or more) IO requests
|
|
* for each subslice created.
|
|
*/
|
|
if (bootverbose)
|
|
printf("yep \n");
|
|
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;
|
|
printf(" part %d, start=%d, size=%d\n", part + 1, dp->dp_start, dp->dp_size);
|
|
|
|
if ((dp->dp_start + dp->dp_size) >
|
|
(slice->limits.slicesize/slice->limits.blksize)) {
|
|
printf("mbr: slice %d too big ", part);
|
|
printf("(%x > %x:%x )\n",
|
|
(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,
|
|
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;
|
|
}
|
|
slice_start_probe(pd->subdevs[part].slice);
|
|
}
|
|
return (0);
|
|
nope:
|
|
printf("nope\n");
|
|
mbr_revoke(pd);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
* At the moment I don't know when it could be called from wd.c
|
|
* Possibly it might call the claim function itself so it may be called instead of
|
|
* the claim. It would have to inhibit the claim from calling the disklabel
|
|
* claim till after the correct values were assigned. possibbly this
|
|
* might be broken into two parts, the first of which hangs a struct off the
|
|
* private data, and the second of which fills it in after the mbr has been loaded.
|
|
*/
|
|
int
|
|
mbr_geom_hack(struct slice * slice, struct ide_geom *geom)
|
|
{
|
|
struct dos_partition table[NDOSPART];
|
|
struct dos_partition *dp, *dp0;
|
|
struct private_data *pd;
|
|
int part;
|
|
int error;
|
|
int max_ncyls;
|
|
int max_nsectors;
|
|
int max_ntracks;
|
|
u_int32_t secpercyl;
|
|
RR;
|
|
|
|
if (slice->handler_up != &slicetype)
|
|
return (ENXIO);
|
|
pd = slice->private_up; /* XXX */
|
|
if (pd == NULL)
|
|
return (ENXIO);
|
|
dp0 = pd->dos_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);
|
|
}
|
|
|
|
/*
|
|
* 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 int
|
|
mbr_ioctl(void *private, u_long 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)
|
|
{
|
|
int error;
|
|
|
|
RR;
|
|
switch (cmd) {
|
|
case SLCIOCRESET:
|
|
return (0);
|
|
|
|
case SLCIOCTRANSBAD:
|
|
{
|
|
struct private_data *pd;
|
|
struct subdev *sdp;
|
|
daddr_t blkno;
|
|
int part;
|
|
|
|
if (!slice->handler_up)
|
|
return (0);
|
|
blkno = *(daddr_t *)addr;
|
|
pd = slice->private_up;
|
|
sdp = pd->subdevs;
|
|
for (part = 0; part < NDOSPART; part++, sdp++) {
|
|
if (!sdp->slice)
|
|
continue;
|
|
if (blkno < sdp->offset)
|
|
continue;
|
|
if (blkno >= sdp->offset +
|
|
sdp->limit.slicesize / sdp->limit.blksize)
|
|
continue;
|
|
blkno -= sdp->offset;
|
|
slice = sdp->slice;
|
|
error = (*slice->handler_up->upconf)(slice, cmd,
|
|
(caddr_t)&blkno, flag, p);
|
|
if (!error)
|
|
*(daddr_t *)addr = blkno + sdp->offset;
|
|
return (error);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* These don't really make sense. keep the headers for a reminder */
|
|
default:
|
|
return (ENOIOCTL);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
mbr_dump(void *private, int32_t blkoff, int32_t blkcnt)
|
|
{
|
|
struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
|
|
RR;
|
|
sdp = private;
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
blkoff += sdp->offset;
|
|
if (slice->handler_down->dump) {
|
|
return (*slice->handler_down->dump)(slice->private_down,
|
|
blkoff, blkcnt);
|
|
}
|
|
return(ENXIO);
|
|
}
|