diff options
author | julian <julian@FreeBSD.org> | 1998-07-13 08:23:05 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1998-07-13 08:23:05 +0000 |
commit | 1dc298263b8472c42f06ae8d53d88b88d443c895 (patch) | |
tree | f7b039cefef35b7038646d2a611116206a1c3f50 /sys/dev/slice | |
parent | 1805fa7aa872b21ea42eaf5c8226a0739bc9f86f (diff) | |
download | FreeBSD-src-1dc298263b8472c42f06ae8d53d88b88d443c895.zip FreeBSD-src-1dc298263b8472c42f06ae8d53d88b88d443c895.tar.gz |
SLICE probing becomes asynchronous. It can now be triggered by
interupt level events. This needs a lot of cleanup, but has been working
here for a month or two.. originally needed for CAM integration
but that hasn't happenned yet. The probing state machines for each
handler should be replaced by a more generic state-service. It's
still quite messy in there..
Diffstat (limited to 'sys/dev/slice')
-rw-r--r-- | sys/dev/slice/disklabel.c | 676 | ||||
-rw-r--r-- | sys/dev/slice/mbr.c | 657 | ||||
-rw-r--r-- | sys/dev/slice/slice.h | 32 | ||||
-rw-r--r-- | sys/dev/slice/slice_base.c | 242 |
4 files changed, 696 insertions, 911 deletions
diff --git a/sys/dev/slice/disklabel.c b/sys/dev/slice/disklabel.c index 57d3c2a..197510d 100644 --- a/sys/dev/slice/disklabel.c +++ b/sys/dev/slice/disklabel.c @@ -23,9 +23,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: disklabel.c,v 1.5 1998/05/06 23:32:47 julian Exp $ + * $Id: disklabel.c,v 1.6 1998/06/07 19:40:31 dfr Exp $ */ #define BAD144 +#undef BAD144 #include <sys/param.h> #include <sys/kernel.h> @@ -65,7 +66,6 @@ struct private_data { #endif }; -static sl_h_constructor_t dkl_constructor; /* constructor (from device) */ static sl_h_IO_req_t dkl_IOreq; /* IO req downward (to device) */ static sl_h_ioctl_t dkl_ioctl; /* ioctl req downward (to device) */ static sl_h_open_t dkl_open; /* downwards travelling open */ @@ -75,13 +75,14 @@ static sl_h_revoke_t dkl_revoke;/* upwards travelling revokation */ static sl_h_verify_t dkl_verify;/* things changed, are we stil valid? */ static sl_h_upconfig_t dkl_upconfig;/* config requests from below */ static sl_h_dump_t dkl_dump; /* core dump req downward */ +static sl_h_done_t dkl_done; /* callback after async request */ static struct slice_handler slicetype = { "disklabel", 0, NULL, 0, - &dkl_constructor, /* constructor */ + &dkl_done, &dkl_IOreq, &dkl_ioctl, &dkl_open, @@ -101,342 +102,183 @@ sd_drvinit(void *unused) SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL); -/*- - * Given a slice, extract out our table of information - */ -/*- - * Attempt to read a disk label from a slice. - * The label must be partly set up before this: secpercyl, secsize - * and anything required in the strategy routine (e.g., dummy bounds for the - * partition containing the label) must be filled in before calling us. - * Returns NULL on success and an error string on failure. +/* + * Allocate and the private data. */ static int -dkl_extract_table(sl_p slice, struct disklabel * lp) +dklallocprivate(sl_p slice) { - int error = EINVAL; - struct buf *bp; - struct disklabel *dlp; - struct partition *dp; - int part; - int slice_offset; /* XXX */ + register struct private_data *pd; + + pd = malloc(sizeof(*pd), M_DEVBUF, M_NOWAIT); + if (pd == NULL) { + printf("dkl: 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); +} - RR; - /* start off with a known result */ - bzero(lp, sizeof(*lp)); - if (error = slice_readblock(slice, LABELSECTOR, &bp)) - return (error); +static int +dkl_claim(sl_p slice) +{ + int error = 0; /* - * Step through the block looking for the label. - * It may not be at the front (Though I have never seen this). - * When found, copy it to the destination supplied. + * Don't even BOTHER if it's not 512 byte sectors */ - error = EINVAL; - for (dlp = (struct disklabel *) bp->b_data; - dlp <= (struct disklabel *) ((char *) bp->b_data - + slice->limits.blksize - - sizeof(*dlp)); - dlp = (struct disklabel *) ((char *) dlp + sizeof(long))) { - if ((dlp->d_magic != DISKMAGIC) || - (dlp->d_magic2 != DISKMAGIC) || - (dlp->d_npartitions > MAXPARTITIONS) || - dkcksum(dlp)) - continue; - error = 0; - bcopy(dlp, lp, sizeof(*lp)); - /* - * disklabels are done relative to the base of the disk, - * rather than the local partition, (DUH!) - * so use partition 2 (c) to get the base, - * and subtract it from all non-0 offsets. - */ - dp = lp->d_partitions; - slice_offset = dp[2].p_offset; - for (part = 0; part < MAXPARTITIONS; part++, dp++) { - /* - * We could be reloading, in which case skip - * entries already set up. - */ - if (dp->p_size == 0) - continue; - if( dp->p_offset < slice_offset ) { - printf("slice before 'c'\n"); - dp->p_size = 0; - continue; - } - dp->p_offset -= slice_offset; + if (slice->limits.blksize != 512) + return (EINVAL); + if (slice->private_up == NULL) { + if ((error = dklallocprivate(slice))) { + return (error); } - break; } + slice->flags |= SLF_PROBING; + if ((error = slice_request_block(slice, LABELSECTOR))) { + slice->flags &= ~SLF_PROBING; + dkl_revoke(slice->private_up); + } + return (error); +} -done: - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); +static int +dkl_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, LABELSECTOR))) { + dkl_revoke(slice->private_up); + } return (error); } -/* - * given a table, write it to disk. + +/* + * called with an argument of a bp when it is completed */ static int -dkl_insert_table(sl_p slice, struct disklabel * lp) +dkl_done(sl_p slice, struct buf *bp) { - int error = EINVAL; - struct buf *bp; - struct disklabel *dlp; - struct partition *dp; + register struct private_data *pd; + struct disklabel label; + struct disklabel *lp, *dlp, *dl; + struct partition *dp0, *dp, *dp2; int part; - int slice_offset; /* XXX */ + int found = 0; + int i; + char name[64]; + int slice_offset; + int error = 0; + + +RR; + /* + * Discover whether the IO was successful. + */ + pd = slice->private_up; + if ( bp->b_flags & B_ERROR ) { + error = bp->b_error; + goto nope; + + } - RR; - /* start off with a known result */ - if (error = slice_readblock(slice, LABELSECTOR, &bp)) - return (error); /* * Step through the block looking for the label. * It may not be at the front (Though I have never seen this). - * When found, replace it witht he new one. + * When found, copy it to the destination supplied. */ - error = EINVAL; for (dlp = (struct disklabel *) bp->b_data; dlp <= (struct disklabel *) ((char *) bp->b_data + slice->limits.blksize - sizeof(*dlp)); - dlp = (struct disklabel *) ((char *) dlp + sizeof(long))) { - if ((dlp->d_magic != DISKMAGIC) || - (dlp->d_magic2 != DISKMAGIC) || - (dlp->d_npartitions > MAXPARTITIONS) || - dkcksum(dlp)) - continue; - error = 0; + dlp = (struct disklabel *) (((char *) dlp) + sizeof(long))) { + if ((dlp->d_magic == DISKMAGIC) && + (dlp->d_magic2 == DISKMAGIC) && + (dlp->d_npartitions <= MAXPARTITIONS) && + (dkcksum(dlp) == 0)) { + found = 1; + break; + } } - if (error) { - /* - * We didn't find one.. - * so clear the block and place the new disklabel - * at the start. - */ - bzero(bp->b_data, slice->limits.blksize); - dlp = (struct disklabel *) bp->b_data; + if (! found) { + goto nope; } + + /* copy the table out of the buf and release it. */ + bcopy(dlp, &label, sizeof(label)); + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + /* - * old disklabels are done relative to the base of the disk, + * Disklabels are done relative to the base of the disk, * rather than the local partition, (DUH!) * so use partition 2 (c) to get the base, * and subtract it from all non-0 offsets. */ - dp = dlp->d_partitions; + dp = label.d_partitions; slice_offset = dp[2].p_offset; - bcopy(lp, dlp, sizeof(*lp)); - slice_offset -= dp[2].p_offset; /* size we adjust by? */ for (part = 0; part < MAXPARTITIONS; part++, dp++) { + /* + * We could be reloading, in which case skip + * entries already set up. + */ if (dp->p_size == 0) continue; - dp->p_offset += slice_offset; - } - error = slice_writeblock(slice, LABELSECTOR, bp); -quit: - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); - return (error); -} - -#ifdef BAD144 -static int -dkl_internbad144(struct private_data *pd, struct dkbad *btp, int flag) -{ - struct disklabel *lp = &pd->disklabel; - struct dkbad_intern *bip = pd->bad; - int i; - - if (bip == NULL) { - bip = malloc(sizeof *bip, M_DEVBUF, flag); - if (bip == NULL) - return (ENOMEM); - pd->bad = bip; - } - /* - * Spare sectors are allocated beginning with the last sector of - * the second last track of the disk (the last track is used for - * the bad sector list). - */ - bip->bi_maxspare = lp->d_secperunit - lp->d_nsectors - 1; - bip->bi_nbad = DKBAD_MAXBAD; - for (i=0; i < DKBAD_MAXBAD && btp->bt_bad[i].bt_cyl != DKBAD_NOCYL; i++) - bip->bi_bad[i] = btp->bt_bad[i].bt_cyl * lp->d_secpercyl - + (btp->bt_bad[i].bt_trksec >> 8) - * lp->d_nsectors - + (btp->bt_bad[i].bt_trksec & 0x00ff); - bip->bi_bad[i] = -1; -#if 1 - for (i = 0; i < DKBAD_MAXBAD && bip->bi_bad[i] != -1; i++) - printf(" %8d => %8d\n", bip->bi_bad[i], - bip->bi_maxspare - i); -#endif - return (0); -} - -static int -dkl_readbad144(struct private_data *pd) -{ - sl_p slice = pd->slice_down; - struct disklabel *lp = &pd->disklabel; - struct dkbad *db; - struct buf *bp; - int blkno, i, error; - - for (i = 0; i < min(10, lp->d_nsectors); i += 2) { - blkno = lp->d_secperunit - lp->d_nsectors + i; - if (lp->d_secsize > slice->limits.blksize) - blkno *= lp->d_secsize / slice->limits.blksize; - else - blkno /= slice->limits.blksize / lp->d_secsize; - error = slice_readblock(slice, blkno, &bp); - if (error) - return (error); - bp->b_flags |= B_INVAL | B_AGE; - db = (struct dkbad *)bp->b_data; - if (db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC) { - printf(" bad144 table found at block %d\n", blkno); - error = dkl_internbad144(pd, db, M_NOWAIT); - brelse(bp); - return (error); + if ( dp->p_offset < slice_offset ) { + printf("slice before 'c'\n"); + dp->p_size = 0; + continue; } - brelse(bp); + dp->p_offset -= slice_offset; } - return (EINVAL); -} -static __inline daddr_t -dkl_transbad144(struct private_data *pd, daddr_t blkno) -{ - return transbad144(pd->bad, blkno); -} -#endif - -/*- - * look at a slice and figure out if we should be interested in it. (Is it - * ours?) - */ -static int -dkl_claim(struct slice * slice, struct slice * lower, void *ID) -{ - struct disklabel disklabel; - struct disklabel *dl, *dl0; - int error; - RR; /*- - * Try load a valid disklabel table. - * This is 90% of what we need to check. + * Handle the case when we are being asked to reevaluate + * an already loaded disklabel. + * 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. */ - if ((error = dkl_extract_table(slice, &disklabel)) != 0) { - return (error); + dl = &(pd->disklabel); + dp = dl->d_partitions; + dp2 = label.d_partitions; + for (part = 0; part < MAXPARTITIONS; part++, dp++, dp2++) { + if (pd->subdevs[part].slice) { + if ((dp2->p_offset != dp->p_offset) + || (dp2->p_size != dp->p_size)) { + 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); + } + } } - /*- - * If there is no geometry info, extract it from the label - * as some drivers need this. - */ - /* XXX */ - - /*- - * well, it looks like one of ours. - */ - return (0); -} - -/*- - * This is a special HACK function for the IDE driver. - * It is here because everything it need is in scope here, - * but it is not really part of the SLICE code. - * Because old ESDI drives could not tell their geometry, They need - * to get it from the MBR or the disklabel. This is the disklabel bit. - */ -int -dkl_geom_hack(struct slice * slice, struct ide_geom *geom) -{ - struct disklabel disklabel; - struct disklabel *dl, *dl0; - int error; - RR; - - /* first check it's a disklabel*/ - if ((error = dkl_claim (slice, NULL, 0))) - return (error); - /*- - * Try load a valid disklabel table. - * This is wasteful but never called on new (< 5 YO ) drives. + /*- having got rid of changing slices, replace + * the old table with the new one, and + * handle any new slices by calling the constructor. */ - if ((error = dkl_extract_table(slice, &disklabel)) != 0) { - return (error); - } - geom->secpertrack = disklabel. d_nsectors; - geom->trackpercyl = disklabel.d_ntracks; - geom->cyls = disklabel.d_ncylinders; - return (0); -} - -/*- - * look at a slice we know to be ours and decide what the #$%^ to do with it. - */ -static int -dkl_constructor(sl_p slice) -{ - int i; - u_int64_t disksize = slice->limits.slicesize; - struct private_data *pd; - struct partition *dp, *dp0; - struct disklabel *dl; - sh_p tp; - char name[64]; - - int part; - int error = 0; - u_long dkl_offset; + bcopy(&label, dl, sizeof(label)); - 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 = dkl_extract_table(slice, &pd->disklabel)) != 0) { - struct partinfo data; - /* - * If it's just that there is no disklabel there, - * Then we fake 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); - } - dkl_dummy_ioctl(slice, DIOCGPART, - (caddr_t) &data, 0, NULL); - bcopy(data.disklab, &pd->disklabel, - sizeof(pd->disklabel)); - if ((error = dkl_insert_table(slice, &pd->disklabel))) { - free(pd, M_DEVBUF); - return (error); - } - } #ifdef BAD144 +#if 0 + /* place holder: + remember to add some state machine to handle bad144 loading */ + if (pd->disklabel.d_flags & D_BADSECT) { if ((error = dkl_readbad144(pd))) { free(pd, M_DEVBUF); @@ -444,12 +286,7 @@ dkl_constructor(sl_p slice) } } #endif - slice->refs++; - slice->handler_up = &slicetype; - slice->private_up = pd; - slicetype.refs++; - } - dl = &pd->disklabel; +#endif dp0 = dl->d_partitions; /*- @@ -471,13 +308,13 @@ dkl_constructor(sl_p slice) * entries already set up. */ if (pd->subdevs[part].slice != NULL) - breakout: continue; +breakout: continue; /* * also skip partitions not present */ if (dp->p_size == 0) continue; -printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size); +printf(" part %c, start=%d, size=%d\n", part + 'a', dp->p_offset, dp->p_size); if ((dp->p_offset + dp->p_size) > (slice->limits.slicesize / slice->limits.blksize)) { @@ -489,14 +326,12 @@ printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size); } /* check for overlaps with existing slices */ for (i = 0; i < MAXPARTITIONS; i++) { - /* - * Don't bother if that slice was not made. - * This handles the (i == part) case. - */ + /* skip empty slots (including this one) */ if (pd->subdevs[i].slice == NULL) continue; if ((dp0[i].p_offset < (dp->p_offset + dp->p_size)) - && ((dp0[i].p_offset + dp0[i].p_size) > dp->p_offset)) { + && ((dp0[i].p_offset + dp0[i].p_size) > dp->p_offset)) + { printf("dkl: slice %d overlaps slice %d\n", part, i); goto breakout; @@ -518,7 +353,6 @@ printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size); &pd->subdevs[part], &pd->subdevs[part].limit, &pd->subdevs[part].slice, - NULL, name); pd->subdevs[part].slice->probeinfo.typespecific = &dp->p_fstype; switch (dp->p_fstype) { @@ -551,7 +385,7 @@ printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size); } /* * Dont allow further breakup of slices that - * cover our disklabel + * cover our disklabel (that would recurse forever) */ if (dp->p_offset < 16) { #if 0 @@ -560,68 +394,48 @@ printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size); #endif pd->subdevs[part].slice->probeinfo.type = NO_SUBPART; } - if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) { - (*tp->constructor)(pd->subdevs[part].slice); - } + slice_start_probe(pd->subdevs[part].slice); } + slice->flags &= ~SLF_PROBING; + return (0); +nope: +printf(" .. nope\n"); + dkl_revoke(pd); return (error); } +#if 0 /*- - * 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. + * This is a special HACK function for the IDE driver. + * It is here because everything it need is in scope here, + * but it is not really part of the SLICE code. + * Because old ESDI drives could not tell their geometry, They need + * to get it from the MBR or the disklabel. This is the disklabel bit. */ -static int -dkl_verify(sl_p slice) +int +dkl_geom_hack(struct slice * slice, struct ide_geom *geom) { - register struct private_data *pd; - struct disklabel label; - struct partition *dp, *dp2; - struct disklabel *dl; - int part; - int error; - /* register struct slice *slice; */ - + struct disklabel disklabel; + struct disklabel *dl, *dl0; + int error; RR; - pd = slice->private_up; - /* slice = pd->slice_down; */ - bzero(&label, sizeof(label)); - /* - * Try load a valid disklabel. This is 90% of what we need to check. + + /* first check it's a disklabel*/ + if ((error = dkl_claim (slice))) + return (error); + /*- + * Try load a valid disklabel table. + * This is wasteful but never called on new (< 5 YO ) drives. */ - if (((error = dkl_extract_table(slice, &label)) != 0) - || (slice->limits.blksize != 512)) { - /*- - * Oh oh, we need to invalidate all the subslices. - * and relinquish this slice. - */ - return (dkl_revoke(pd)); - } - dl = &(pd->disklabel); - dp = dl->d_partitions; - dp2 = label.d_partitions; - for (part = 0; part < MAXPARTITIONS; part++, dp++, dp2++) { - if (pd->subdevs[part].slice) { - if ((dp2->p_offset != dp->p_offset) - || (dp2->p_size != dp->p_size)) { - 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); - } - } + if ((error = dkl_extract_table(slice, &disklabel)) != 0) { + return (error); } - /*- having got rid of changing slices, replace - * the old table with the new one, and - * handle any new slices by calling the constructor. - */ - bcopy(&label, dl, sizeof(label)); - error = dkl_constructor(slice); -done: - return (error); + geom->secpertrack = disklabel. d_nsectors; + geom->trackpercyl = disklabel.d_ntracks; + geom->cyls = disklabel.d_ncylinders; + return (0); } +#endif /*- * Invalidate all subslices, and free resources for this handler instance. @@ -656,6 +470,96 @@ dkl_revoke(void *private) return (0); } +#ifdef BAD144 +#if 0 + bucket= blknum >> 4; /* set 16 blocks to the same bucket */ + bucket ^= (bucket>>16); /* combine bytes 1+3, 2+4 */ + bucket ^= (bucket>>8); /* combine bytes 1+3+2+4 */ + bucket &= 0x7F; /* AND 128 entries */ +#endif +/* + * Given a bad144 table, load the values into ram. + * eventually we should hash them so we can do forwards lookups. + * Probably should hash on (blknum >> 4) to minimise + * lookups for a clustered IO. (see above) + */ +static int +dkl_internbad144(struct private_data *pd, struct dkbad *btp, int flag) +{ + struct disklabel *lp = &pd->disklabel; + struct dkbad_intern *bip = pd->bad; + int i; + + if (bip == NULL) { + bip = malloc(sizeof *bip, M_DEVBUF, flag); + if (bip == NULL) + return (ENOMEM); + pd->bad = bip; + } + /* + * Spare sectors are allocated beginning with the last sector of + * the second last track of the disk (the last track is used for + * the bad sector list). + */ + bip->bi_maxspare = lp->d_secperunit - lp->d_nsectors - 1; + bip->bi_nbad = DKBAD_MAXBAD; + for (i=0; i < DKBAD_MAXBAD && btp->bt_bad[i].bt_cyl != DKBAD_NOCYL; i++) + bip->bi_bad[i] = btp->bt_bad[i].bt_cyl * lp->d_secpercyl + + (btp->bt_bad[i].bt_trksec >> 8) + * lp->d_nsectors + + (btp->bt_bad[i].bt_trksec & 0x00ff); + bip->bi_bad[i] = -1; +#if 1 + for (i = 0; i < DKBAD_MAXBAD && bip->bi_bad[i] != -1; i++) + printf(" %8d => %8d\n", bip->bi_bad[i], + bip->bi_maxspare - i); +#endif + return (0); +} + +/* + * Hunt in the last cylinder for the bad144 table + * this needs to be turned around to be made into a state operation + * driven by IO completion of the read. + */ +static int +dkl_readbad144(struct private_data *pd) +{ + sl_p slice = pd->slice_down; + struct disklabel *lp = &pd->disklabel; + struct dkbad *db; + struct buf *bp; + int blkno, i, error; + + for (i = 0; i < min(10, lp->d_nsectors); i += 2) { + blkno = lp->d_secperunit - lp->d_nsectors + i; + if (lp->d_secsize > slice->limits.blksize) + blkno *= lp->d_secsize / slice->limits.blksize; + else + blkno /= slice->limits.blksize / lp->d_secsize; + error = slice_readblock(slice, blkno, &bp); + if (error) + return (error); + bp->b_flags |= B_INVAL | B_AGE; + db = (struct dkbad *)bp->b_data; + if (db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC) { + printf(" bad144 table found at block %d\n", blkno); + error = dkl_internbad144(pd, db, M_NOWAIT); + brelse(bp); + return (error); + } + brelse(bp); + } + return (EINVAL); +} + +static __inline daddr_t +dkl_transbad144(struct private_data *pd, daddr_t blkno) +{ + return transbad144(pd->bad, blkno); +} +#endif + /*- * shift the appropriate IO by the offset for that slice. */ @@ -731,52 +635,6 @@ RR; return (0); } -#if 0 -static void -dkl_close(void *private, int flags, int mode, struct proc * p) -{ - register struct private_data *pd; - struct subdev *sdp; - register struct slice *slice; - u_int8_t newrflags = 0; - u_int8_t newwflags = 0; - int newoflags; - int part; - u_int8_t partbit; - -RR; - sdp = private; - part = sdp->part; - partbit = (1 << part); - pd = sdp->pd; - slice = pd->slice_down; - - if ((pd->rflags == 0) && (pd->wflags == 0)) - return; - - /* work out what our stored flags will be if this succeeds */ - newwflags &= ~ (partbit); - newrflags &= ~ (partbit); - newwflags |= (flags & FWRITE) ? (partbit) : 0; - newrflags |= (flags & FREAD) ? (partbit) : 0; - - /* work out what we want to pass down this time */ - newoflags = newwflags ? FWRITE : 0; - newoflags |= newrflags ? FREAD : 0; - - /* - * If this was the last open slice above, then release our own open - */ - if ((pd->rflags == 0) && (pd->wflags == 0)) { - sliceclose(slice, newoflags, mode, p, SLW_ABOVE); - } - pd->rflags = newrflags; - pd->wflags = newwflags; - pd->savedoflags = newoflags; - return ; -} -#endif /* 0 */ - static int dkl_ioctl(void *private, u_long cmd, caddr_t addr, int flag, struct proc * p) { @@ -920,6 +778,10 @@ dkcksum(lp) } #endif /* 0 */ +/* + * pass down a dump request. + * make sure it's offset by the right amount. + */ static int dkl_dump(void *private, int32_t blkoff, int32_t blkcnt) { @@ -932,7 +794,7 @@ RR; pd = sdp->pd; slice = pd->slice_down; blkoff += sdp->offset; - if(slice->handler_down->dump) { + if (slice->handler_down->dump) { return (*slice->handler_down->dump)(slice->private_down, blkoff, blkcnt); } diff --git a/sys/dev/slice/mbr.c b/sys/dev/slice/mbr.c index f462887..f3eff94 100644 --- a/sys/dev/slice/mbr.c +++ b/sys/dev/slice/mbr.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mbr.c,v 1.5 1998/05/06 23:32:48 julian Exp $ + * $Id: mbr.c,v 1.6 1998/06/07 19:40:31 dfr Exp $ */ #include <sys/param.h> @@ -42,6 +42,8 @@ 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; @@ -68,15 +70,8 @@ struct private_data { #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 */ @@ -86,13 +81,14 @@ 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_constructor, /* constructor */ + &mbr_done, &mbr_IOreq, &mbr_ioctl, &mbr_open, @@ -113,40 +109,115 @@ sd_drvinit(void *unused) SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL); /* - * Given a slice, extract out our table of information + * 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); + } + } + slice->flags |= SLF_PROBING; + if ((error = slice_request_block(slice, 0))) { + slice->flags &= ~SLF_PROBING; + 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_find_table(sl_p slice, struct buf **bpp, int *blknum) +mbr_done(sl_p slice, struct buf *bp) { - int ontrack_offset = 0; - int error; + struct private_data *pd; + struct dos_partition table[NDOSPART]; + struct dos_partition *dp0, *dp, *dp2; u_int8_t *cp; - struct dos_partition *dp0, *dp; int part; - int redone = 0; - struct buf *bp; + int numactive = 0; + int i; + char name[64]; + int error = 0; RR; - *bpp = NULL; -reread: - if (error = slice_readblock(slice, ontrack_offset, &bp)) - return (error); + /* + * 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); + goto nope; + } cp = bp->b_data; if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); error = EINVAL; - goto done; + 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 (!redone) { - for (part = 0, dp = dp0; + if (pd->table_offset == 0) { + for (part = 0, dp = table; part < NDOSPART; part++, dp++) { if (dp->dp_typ == DOSPTYP_ONTRACK) { #ifdef MAYBE @@ -155,342 +226,89 @@ reread: * if this is just the start of the 2nd * track. */ - ontrack_offset = dp->dp_start; + pd->table_offset = dp->dp_start; #else - ontrack_offset = 63; + pd->table_offset = 63; #endif if (bootverbose) printf("Found \"Ontrack Disk Manager\"\n"); - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); - redone++; - goto reread; + slice_request_block(slice, pd->table_offset); + return (0); } } } -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. + * 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 = dp0; part < NDOSPART; part++, dp++) { + for (part = 0, dp = table; part < NDOSPART; part++, dp++) { if (dp->dp_flag & 0x7f) { printf ("rejected.. bad flag "); - return(EINVAL); /* must be either 0 or 0x80 */ + goto nope; } if ((dp->dp_typ) && (dp->dp_size) && (dp->dp_start == 0)) { printf("rejected.. Slice includes MBR "); - return (EINVAL); + goto nope; } 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; + goto nope; } - 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. + /*- + * 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. */ - 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); + 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); + } } } - /* - * Set our newely hypothesised numbers into the geometry - * slots in the supplied SLICE. + * Having got rid of changing slices, replace + * the old table with the new one. */ - 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; + bcopy( table, pd->dos_table, sizeof(table)); /* * Handle each of the partitions. - * We should check that each makes sence and is legal. + * 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. */ dp = dp0; for (part = 0; part < NDOSPART; part++, dp++) { @@ -501,13 +319,20 @@ breakout: continue; 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)) + (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 ) + 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)) @@ -533,7 +358,6 @@ breakout: continue; &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 */ @@ -588,78 +412,126 @@ breakout: continue; default: pd->subdevs[part].slice->probeinfo.type = NULL; } - if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) { - (*tp->constructor)(pd->subdevs[part].slice); - } + slice_start_probe(pd->subdevs[part].slice); } + slice->flags &= ~SLF_PROBING; + return (0); +nope: + mbr_revoke(pd); 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 + * 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. */ -static int -mbr_verify(sl_p slice) +int +mbr_geom_hack(struct slice * slice, struct ide_geom *geom) { - register struct private_data *pd; struct dos_partition table[NDOSPART]; struct dos_partition *dp, *dp0; + struct private_data *pd; int part; int error; - /* register struct slice *slice; */ - + int max_ncyls; + int max_nsectors; + int max_ntracks; + u_int32_t secpercyl; RR; - pd = slice->private_up; - /* slice = pd->slice_down; */ - bzero(table, sizeof(table)); + + if (slice->handler_up != &slicetype) + return (ENXIO); + pd = slice->private_up; /* XXX */ + if (pd == NULL) + return (ENXIO); + dp0 = pd->dos_table; /* - * Try load a valid MBR table. This is 90% of what we need to check. + * 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. */ - 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)); + 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); /* - * 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. + * Check that we have guessed the geometry right by checking + * the partition entries. */ - dp = dp0 = pd->dos_table; + error = 0; 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); - } + 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); } } + /* - * 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....) + * Set our newely hypothesised numbers into the geometry + * slots in the supplied SLICE. */ - bcopy( table, dp0, sizeof(table)); - error = mbr_constructor(slice); - return (error); + geom->secpertrack = max_nsectors; + geom->trackpercyl = max_ntracks; + geom->cyls = max_ncyls; + return (0); } /* @@ -763,49 +635,6 @@ RR; return (0); } -#if 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 ; -} -#endif /* 0 */ - static int mbr_ioctl(void *private, u_long cmd, caddr_t addr, int flag, struct proc * p) { @@ -884,7 +713,7 @@ RR; pd = sdp->pd; slice = pd->slice_down; blkoff += sdp->offset; - if(slice->handler_down->dump) { + if (slice->handler_down->dump) { return (*slice->handler_down->dump)(slice->private_down, blkoff, blkcnt); } diff --git a/sys/dev/slice/slice.h b/sys/dev/slice/slice.h index 3d7eabd..ca6dfe0 100644 --- a/sys/dev/slice/slice.h +++ b/sys/dev/slice/slice.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: slice.h,v 1.2 1998/05/06 22:14:33 julian Exp $ + * $Id: slice.h,v 1.3 1998/06/07 19:40:32 dfr Exp $ */ typedef struct slice_handler *sh_p; @@ -62,6 +62,7 @@ struct ide_geom { * needed. */ struct probehints { + sh_p trial_handler; /* methods of handler being probed */ char *type; /* don't probe, just use this type */ void *typespecific; /* the lower layer specifies this */ }; @@ -109,6 +110,13 @@ struct slice { #define SLF_INVALID 0x00000100 /* Everything aborts */ #define SLF_LOCKED 0x00000200 /* Hold off, It's busy */ #define SLF_WANTED 0x00000400 /* I held off, wake me up */ +#define SLF_PROBING 0x00000800 /* Probe state machine active */ +#define SLF_PROBE_SEL 0x00001000 /* Probe selecting */ +#define SLF_DONT_ARGUE 0x00002000 /* an assign, not a probe */ + +#define SLF_WAIT_READ 0x00008000 /* waiting for a probe read */ +#define SLF_WAIT_WRITE 0x0000C000 /* waiting for a probe read */ +#define SLF_PROBE_STATE 0x0000C000 /* Present probe state */ /* * prototypes for slice methods @@ -116,12 +124,11 @@ struct slice { typedef void sl_h_IO_req_t(void *private, struct buf * buf); typedef int sl_h_ioctl_t(void *private, u_long cmd, caddr_t data, int fflag, struct proc * p); -typedef int sl_h_constructor_t(sl_p slice); +typedef int sl_h_done_t(sl_p slice, struct buf *bp); typedef int sl_h_open_t(void *private, int flags, int mode, struct proc * p); typedef void sl_h_close_t(void *private, int flags, int mode, struct proc * p); typedef int sl_h_revoke_t(void *private); -typedef int sl_h_claim_t(struct slice * slice, struct slice * lower, - void *ID); /* eg ID=165 for BSD */ +typedef int sl_h_claim_t(struct slice * slice); typedef int sl_h_verify_t(struct slice *slice); typedef int sl_h_upconfig_t(struct slice *slice, int cmd, caddr_t data, int fflag, struct proc *p); @@ -132,7 +139,7 @@ struct slice_handler { int version;/* the version of this handler */ struct slice_handler *next; /* next registered type */ int refs; /* references to this type */ - sl_h_constructor_t *constructor; /* make new instantiation */ + sl_h_done_t *done; /* return after async request */ sl_h_IO_req_t *IOreq; /* IO req downward (to device) */ sl_h_ioctl_t *ioctl; /* ioctl downward (to device) */ sl_h_open_t *open; /* downwards travelling open */ @@ -149,15 +156,18 @@ struct slice_handler { */ int sl_make_slice(sh_p handler_down, void *private_down, struct slicelimits *limits, - sl_p *slicepp, char *type, char *name); + sl_p *slicepp, char *name); void sl_rmslice(sl_p slice); int sl_newtype(sh_p tp); sh_p sl_findtype(char *type); -sh_p slice_probeall(sl_p slice); -int lockslice(sl_p slice); -int unlockslice(sl_p slice); -int slice_readblock(struct slice *slice, int blkno, struct buf **bpp); -int slice_writeblock(struct slice *slice, int blkno, struct buf *bp); +void slice_start_probe(sl_p slice); +int slice_lock(sl_p slice); +int slice_unlock(sl_p slice); +int slice_request_block(struct slice *slice, int blkno); +int slice_writeblock(struct slice * slice, int blkno, + void (*iodone )(struct buf *), + caddr_t data, int len); +void slice_probe_next(sl_p slice); /* * Definitions for "SLICE" utilities. (handler or device acting on a slice). diff --git a/sys/dev/slice/slice_base.c b/sys/dev/slice/slice_base.c index 60256ed..2752124 100644 --- a/sys/dev/slice/slice_base.c +++ b/sys/dev/slice/slice_base.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: slice_base.c,v 1.3 1998/04/22 10:25:10 julian Exp $ + * $Id: slice_base.c,v 1.4 1998/06/14 19:00:12 julian Exp $ */ #include <sys/param.h> @@ -41,6 +41,8 @@ #define SLICESPL() splbio() +static void sl_async_done(struct buf *bp); + static int slicexclusive = 0; /* default value == "foot shootable" */ @@ -83,47 +85,68 @@ sl_findtype(char *type) * Ask all known handler types if a given slice is handled by them. * If the slice specifies a type, then just find that. */ -sh_p -slice_probeall(sl_p slice) +void +slice_start_probe(sl_p slice) { sh_p tp = types; + if (slice->probeinfo.type == NULL) { - while (tp) { - printf("%s: probing for %s.. ",slice->name, tp->name); - if ((*tp->claim) (slice, NULL, NULL) == 0) { - printf("yep\n"); - return (tp); - } - printf("nope\n"); - tp = tp->next; + if(slice->handler_up == NULL) { + slice->probeinfo.trial_handler = tp; + printf("%s: probing for %s.. ",slice->name, tp->name); + (*tp->claim) (slice); } + return; + } + /* - * Null string ("") means "don't even try". Caller probably should - * pre-trap such cases but we'll check here too. + * Null string ("") means "don't even try". Caller probably + * should pre-trap such cases but we'll check here too. */ - } else if (slice->probeinfo.type[0]) { + if (slice->probeinfo.type[0]) { tp = sl_findtype(slice->probeinfo.type); - if ((tp) && ((*tp->claim) (slice, NULL, NULL) == 0)) { - printf("%s: attaching %s..\n",slice->name, tp->name); - return (tp); + if (tp) { + printf("%s: attaching %s..\n", slice->name, tp->name); + (*tp->claim) (slice); } } - /*printf("%s: Leaving as raw device\n", slice->name); */ - return (NULL); } +/* + * Move the slice probe type, on to the next type + * and call that. Called from failed probes. + */ +void +slice_probe_next(sl_p slice) +{ + sh_p tp = slice->probeinfo.trial_handler; + + if ((slice->flags & SLF_PROBING) == 0) + panic("slice_probe_next: bad call"); + if (tp != NULL) { + tp = tp->next; + slice->probeinfo.trial_handler = tp; + if (tp) { + printf("%s: probing for %s.. ",slice->name, tp->name); + (*tp->claim) (slice); + return; + } + } + slice->flags &= ~SLF_PROBING; +} /* * Make a handler instantiation of the requested type. + * don't take no for an answer. + * force it to mark it's new territory. + * Must be called from a with a user context. * */ static int -sl_make_handler(char *type, sl_p slice) +sl_make_handler(sl_p slice, char *type) { sh_p handler_up; - void *private_up; - int errval; /* * check that the type makes sense. @@ -135,17 +158,12 @@ sl_make_handler(char *type, sl_p slice) if (handler_up == NULL) { return (ENXIO); } + /* * and call the constructor */ - if (handler_up->constructor != NULL) { - errval = (*handler_up->constructor) (slice); - return (errval); - } else { - printf("slice handler %s has no constructor\n", - handler_up->name); - return (EINVAL); - } + slice->flags |= SLF_DONT_ARGUE; + return( (*handler_up->claim) (slice)); } /* @@ -154,7 +172,7 @@ sl_make_handler(char *type, sl_p slice) * XXX This doesn't work for SMP. */ int -lockslice(struct slice *slice) +slice_lock(struct slice *slice) { int s = SLICESPL(); slice->refs++; @@ -165,7 +183,7 @@ lockslice(struct slice *slice) return (ENXIO); } slice->flags |= SLF_WANTED; - tsleep(slice, PRIBIO, "lockslice", 0); + tsleep(slice, PRIBIO, "slice_lock", 0); } slice->flags |= SLF_LOCKED; splx(s); @@ -178,7 +196,7 @@ lockslice(struct slice *slice) * We can still hold a reference on it. */ int -unlockslice(struct slice *slice) +slice_unlock(struct slice *slice) { int s = SLICESPL(); slice->flags &= ~SLF_LOCKED; @@ -191,13 +209,13 @@ unlockslice(struct slice *slice) } /* - * create a new slice. Link it into the structures. don't yet find and call - * it's type handler. That's done later + * create a new slice. Link it into the structures. + * As of yet it has no upper handler. */ int sl_make_slice(sh_p handler_down, void *private_down, struct slicelimits * limits, - sl_p * slicepp, char *type, char *name) + sl_p * slicepp, char *name) { sl_p slice; @@ -226,11 +244,6 @@ sl_make_slice(sh_p handler_down, void *private_down, slice_add_device(slice); slice->refs = 1; /* one for our downward creator */ *slicepp = slice; - if (type) { - slice->refs++; /* don't go away *//* probably not needed */ - sl_make_handler(type, slice); - sl_unref(slice); - } return (0); } @@ -238,6 +251,7 @@ sl_make_slice(sh_p handler_down, void *private_down, * Forceably start a shutdown process on a slice. Either call it's shutdown * method, or do the default shutdown if there is no type-specific method. * XXX Really should say who called us. + * Should be called at SLICESPL (splbio) */ void sl_rmslice(sl_p slice) @@ -293,67 +307,139 @@ sl_unref(sl_p slice) } } + /* - * Read a block on behalf of a handler. + * Given a slice, launch an IOrequest for information * This is not a bulk IO routine but meant for probes etc. - * I think that perhaps it should attempt to do sliceopen() - * calls on the slice first. (XXX?) */ int -slice_readblock(struct slice * slice, int blkno, struct buf ** bpp) +slice_request_block(sl_p slice, int blknum) { struct buf *bp; - int error = 0; + int s; - /* - * posibly attempt to open device? - */ - /* --not yet-- */ - /* - * Now that it is open, get the buffer and set in the parameters. - */ +RR; + s = splbio(); +#ifdef PARANOID + if ( slice->private_up == NULL) { + panic("slice_request_block: no pd"); + } + if (slice->flags & SLF_PROBE_STATE) { + panic("slice_request_block: 2nd IO"); + } +#endif /* PARANOID */ bp = geteblk((int) slice->limits.blksize); if (bp == NULL) { return (ENOMEM); } - bp->b_pblkno = bp->b_blkno = blkno; + slice->flags |= SLF_WAIT_READ; + bp->b_iodone = &sl_async_done; + bp->b_flags |= B_CALL; + bp->b_dev = (dev_t)slice; /* XXX HACK ALERT! */ + bp->b_pblkno = bp->b_blkno = blknum; bp->b_bcount = slice->limits.blksize; bp->b_flags |= B_BUSY | B_READ; sliceio(slice, bp, SLW_ABOVE); - if (biowait(bp) != 0) { - printf("failure reading device block\n"); - error = EIO; - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); - bp = NULL; - } - *bpp = bp; - return (error); + splx(s); + return (0); } /* - * Read a block on behalf of a handler. + * Write a block on behalf of a handler. * This is not a bulk IO routine but meant for probes etc. * I think that perhaps it should attempt to do sliceopen() - * calls on the slice first. (XXX?) + * calls on the slice first. (XXX?) no, they may block? */ int -slice_writeblock(struct slice * slice, int blkno, struct buf * bp) +slice_writeblock(struct slice * slice, int blkno, + void (*iodone )(struct buf *), + caddr_t data, int len) { + struct buf *bp; int error = 0; +#ifdef PARANOID + if ( slice->handler_up == NULL) { + panic("slice_writeblock: no handler"); + } + if (slice->flags & SLF_PROBE_STATE) { + panic("slice_writeblock: 2nd IO"); + } +#endif /* PARANOID */ + if (len > slice->limits.blksize) + return (EINVAL); + bp = geteblk((int) slice->limits.blksize); if (bp == NULL) { return (ENOMEM); } + slice->flags |= SLF_WAIT_WRITE; + bcopy(data, bp->b_data, len); + bp->b_iodone = sl_async_done; + bp->b_flags |= B_CALL; + bp->b_dev = (dev_t)slice; /* XXX HACK ALERT! */ bp->b_pblkno = bp->b_blkno = blkno; bp->b_bcount = slice->limits.blksize; bp->b_flags |= B_BUSY | B_WRITE; sliceio(slice, bp, SLW_ABOVE); - if (biowait(bp) != 0) { - printf("failure reading device block\n"); - error = EIO; + return (0); +} + +/* + * called with an argument of a bp when it is completed + */ +static void +sl_async_done(struct buf *bp) +{ + sl_p slice; + int error; + +RR; + if (bp->b_dev < 0xf0000000) + panic ("b_dev used in SLICE code"); + slice = (struct slice *)bp->b_dev; /* XXX HACK! */ + +#ifdef PARANOID + if ( slice->handler_up == NULL) { + panic("sl_async_done: no pd"); } - return (error); + if (bp->b_flags & B_READ) { + if ((slice->flags & SLF_PROBE_STATE) != SLF_WAIT_READ) + panic("sl_async_done: unexpected read completion"); + } else { + if ((slice->flags & SLF_PROBE_STATE) != SLF_WAIT_WRITE) + panic("sl_async_done: unexpected write completion"); + } +#endif /* PARANOID */ + /* + * if the IO failed, then abandon the probes and + * return. Possibly ask the lower layer to try again later? + */ + if (bp->b_flags & B_ERROR) { + (* slice->handler_up->revoke)(slice->private_up); + + /* (* slice->handler_down->SOMETHING) (slice->private_down); */ + + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + return; + } + + error = (* slice->handler_up->done)(slice, bp); + /* + * If the handler has left itself there, or cleared + * the PROBING bit, then consider + * probing to have come to a close. So just return. + * an IO error would be a great hint to abandon probing as well. + * we could catch that on the way up but we might want to give + * the handler a chance to clean up state? + */ + if (slice->handler_up) + return; + if (error) { + slice->flags &= ~SLF_PROBING; + return; + } + slice_probe_next(slice); } /* @@ -500,7 +586,7 @@ sliceopen(struct slice *slice, int flags, int mode, /* * Firstly, don't allow re-opens of what is already open */ - if (error = lockslice(slice)) + if (error = slice_lock(slice)) return (error); error = EBUSY; /* default answer */ switch (who) { @@ -597,17 +683,15 @@ sliceopen(struct slice *slice, int flags, int mode, * Maybe we should ask the lower one to re-issue the request? */ if (slice->handler_up == NULL) { - if ((tp = slice_probeall(slice)) != NULL) { - (*tp->constructor)(slice); - } + slice_start_probe(slice); } } #endif reject: - unlockslice(slice); + slice_unlock(slice); if ((slice->flags & SLF_INVALID) == SLF_INVALID) error = ENODEV; /* we've been zapped while down there! */ - sl_unref(slice); /* lockslice gave us a ref.*/ + sl_unref(slice); /* slice_lock gave us a ref.*/ return (error); } @@ -620,7 +704,7 @@ sliceclose(struct slice *slice, int flags, int mode, if (slice->flags & SLF_INVALID) return ; - if (lockslice(slice)) + if (slice_lock(slice)) return ; switch (who) { case SLW_ABOVE: @@ -652,7 +736,7 @@ sliceclose(struct slice *slice, int flags, int mode, * Maybe we should ask the lower one to re-issue the request? */ if (slice->handler_up == NULL) { - if ((tp = slice_probeall(slice)) != NULL) { + if ((tp = slice_start_probe(slice)) != NULL) { (*tp->constructor)(slice); } } @@ -668,7 +752,7 @@ sliceclose(struct slice *slice, int flags, int mode, if ( (slice->flags & SLF_OPEN_STATE) == 0) (*slice->handler_down->close) (slice->private_down, flags, mode, p); - unlockslice(slice); + slice_unlock(slice); sl_unref(slice); return ; } |