aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/slice/mbr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/slice/mbr.c')
-rw-r--r--sys/dev/slice/mbr.c725
1 files changed, 0 insertions, 725 deletions
diff --git a/sys/dev/slice/mbr.c b/sys/dev/slice/mbr.c
deleted file mode 100644
index 212505da534d7..0000000000000
--- a/sys/dev/slice/mbr.c
+++ /dev/null
@@ -1,725 +0,0 @@
-/*-
- * 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);
-}