diff options
40 files changed, 5588 insertions, 203 deletions
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c index 6d96c0c..1aeef1c 100644 --- a/sys/amd64/amd64/autoconf.c +++ b/sys/amd64/amd64/autoconf.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 - * $Id: autoconf.c,v 1.91 1998/03/16 12:07:54 msmith Exp $ + * $Id: autoconf.c,v 1.92 1998/03/17 00:28:02 msmith Exp $ */ /* @@ -107,6 +107,7 @@ SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL) static void configure_finish __P((void)); static void configure_start __P((void)); static int setdumpdev __P((dev_t dev)); +#ifndef SLICE static void setroot __P((void)); #ifdef CD9660 @@ -135,6 +136,7 @@ static struct { static int find_cdrom_root __P((void)); + static int find_cdrom_root() { @@ -170,6 +172,7 @@ find_cdrom_root() return EINVAL; } #endif /* CD9660 */ +#endif /* !SLICE */ static void configure_start() @@ -300,6 +303,8 @@ configure(dummy) cold = 0; } +#ifndef SLICE + void cpu_rootconf() { @@ -370,6 +375,24 @@ cpu_rootconf() } #endif +#if defined(LFS) || defined(LFS_ROOT) + if (!mountrootfsname) { + if (bootverbose) + printf("Considering LFS root f/s.\n"); + mountrootfsname = "lfs"; + /* + * Ignore the -a flag if this kernel isn't compiled + * with a generic root/swap configuration: if we skip + * setroot() and we aren't a generic kernel, chaos + * will ensue because setconf() will be a no-op. + * (rootdev is always initialized to NODEV in a + * generic configuration, so we test for that.) + */ + if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) + setroot(); + } +#endif + if (!mountrootfsname) { panic("Nobody wants to mount my root for me"); } @@ -377,6 +400,8 @@ cpu_rootconf() setconf(); } +#endif + void cpu_dumpconf() { @@ -420,6 +445,8 @@ setdumpdev(dev) return (0); } +#ifndef SLICE + u_long bootdev = 0; /* not a dev_t - encoding is different */ /* Name lookup for bootable majors XXX extend me */ @@ -484,6 +511,8 @@ setroot() printf("changing root device to %s%s\n", sname, partname); } +#endif + static int sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS { diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 21bf3c4..b41d6ac 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.424 1998/04/09 22:28:57 sos Exp $ +# $Id: LINT,v 1.425 1998/04/18 04:58:00 ahasty Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -470,8 +470,10 @@ options UNION #Union filesystem options "CD9660_ROOT" #CD-ROM usable as root device options FFS_ROOT #FFS usable as root device options NFS_ROOT #NFS usable as root device -# This DEVFS is experimental but seems to work +# DEVFS and SLICE are experimental but seems to work. +# SLICE disables too much old code so enabling it in LINT would be bad options DEVFS #devices filesystem +#options SLICE #devfs based disk handling # Allow the FFS to use Softupdates technology. # To do this you need to fetch the two files diff --git a/sys/conf/files b/sys/conf/files index 6f77e75..19dd181 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -53,6 +53,10 @@ dev/ppbus/ppbconf.c optional ppbus dev/ppbus/ppi.c optional ppi dev/ppbus/pps.c optional pps dev/ppbus/vpo.c optional vpo +dev/slice/slice_base.c optional slice +dev/slice/slice_device.c optional slice +dev/slice/mbr.c optional slice +dev/slice/disklabel.c optional slice dev/vn/vn.c optional vn dev/vx/if_vx.c optional vx device-driver gnu/ext2fs/ext2_alloc.c optional ext2fs diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index a08df9d..f0a9e71 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.195 1998/03/23 16:44:22 peter Exp $ +# $Id: files.i386,v 1.196 1998/04/06 15:49:35 peter Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -36,6 +36,7 @@ i386/eisa/eisaconf.c optional eisa i386/eisa/if_vx_eisa.c optional vx device-driver i386/eisa/if_fea.c optional fea device-driver i386/i386/autoconf.c standard device-driver +i386/i386/mountroot.c optional slice i386/i386/bios.c standard i386/i386/bioscall.s standard i386/i386/busdma_machdep.c standard diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index d09b927..abc2634 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -43,7 +43,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.107 1998/01/24 02:54:18 eivind Exp $ + * $Id: fd.c,v 1.108 1998/04/17 22:36:31 des Exp $ * */ @@ -82,9 +82,13 @@ #include <sys/ftape.h> #include <i386/isa/ftreg.h> #endif -#ifdef DEVFS +#ifdef DEVFS #include <sys/devfsext.h> -#endif +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#endif /* SLICE */ +#endif /* DEVFS */ /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX @@ -180,8 +184,21 @@ static struct fd_data { struct callout_handle toffhandle; struct callout_handle tohandle; #ifdef DEVFS +#ifdef SLICE + int unit; /* as in fd0 */ + void *bdevs[MAXPARTITIONS]; + void *cdevs[MAXPARTITIONS]; + struct subdev{ + struct slice *slice; + int minor; + struct fd_data *drive; + struct slicelimits limit; + }subdevs[16]; + struct intr_config_hook ich; +#else /* SLICE */ void *bdevs[1 + NUMDENS + MAXPARTITIONS]; void *cdevs[1 + NUMDENS + MAXPARTITIONS]; +#endif /* SLICE */ #endif } fd_data[NFD]; @@ -227,7 +244,9 @@ static timeout_t fd_timeout; static timeout_t fd_pseudointr; static int fdstate(fdcu_t, fdc_p); static int retrier(fdcu_t); +#ifndef SLICE static int fdformat(dev_t, struct fd_formb *, struct proc *); +#endif static int enable_fifo(fdc_p fdc); @@ -284,6 +303,7 @@ static d_close_t fdclose; static d_ioctl_t fdioctl; static d_strategy_t fdstrategy; +/* even if SLICE defined, these are needed for the ft support. */ #define CDEV_MAJOR 9 #define BDEV_MAJOR 2 static struct cdevsw fd_cdevsw; @@ -294,6 +314,30 @@ static struct bdevsw fd_bdevsw = static struct isa_device *fdcdevs[NFDC]; +#ifdef SLICE +static sl_h_IO_req_t fdsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t fdsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t fdsopen; /* downwards travelling open */ +static sl_h_close_t fdsclose; /* downwards travelling close */ +static void fdsinit(void *); + +static struct slice_handler slicetype = { + "floppy", + 0, + NULL, + 0, + NULL, /* constructor */ + &fdsIOreq, + &fdsioctl, + &fdsopen, + &fdsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif /* SLICE */ + static int fdc_err(fdcu_t fdcu, const char *s) { @@ -529,8 +573,12 @@ fdattach(struct isa_device *dev) struct isa_device *fdup; int ic_type = 0; #ifdef DEVFS +#ifdef SLICE + char namebuf[64]; +#else int mynor; int typemynor; +#endif /* SLICE */ int typesize; #endif @@ -682,6 +730,9 @@ fdattach(struct isa_device *dev) continue; fd->track = FD_NO_TRACK; +#ifdef SLICE + fd->unit = fdu; +#endif fd->fdc = fdc; fd->fdsu = fdsu; fd->options = 0; @@ -721,6 +772,30 @@ fdattach(struct isa_device *dev) continue; } #ifdef DEVFS +#ifdef SLICE + sprintf(namebuf,"fd%d",fdu); + fd->subdevs[0].minor = 0; + fd->subdevs[0].drive = fd; + fd->subdevs[0].limit.blksize = + 128 << (fd_types[fd->type - 1].secsize); + fd->subdevs[0].limit.slicesize = + fd_types[fd->type - 1].size + * fd->subdevs[0].limit.blksize; + fd->ft = fd_types + (fd->type - 1); /* default value */ + sl_make_slice(&slicetype, + &fd->subdevs[0], + &fd->subdevs[0].limit, + &fd->subdevs[0].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[0].slice->probeinfo.typespecific = NULL; + fd->subdevs[0].slice->probeinfo.type = NULL; + + fd->ich.ich_func = fdsinit; + fd->ich.ich_arg = &fd->subdevs[0]; + config_intrhook_establish(&fd->ich); +#else /* SLICE */ mynor = fdu << 6; fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -728,6 +803,7 @@ fdattach(struct isa_device *dev) fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fdu); +#endif /* SLICE */ for (i = 1; i < 1 + NUMDENS; i++) { /* * XXX this and the lookup in Fdopen() should be @@ -755,7 +831,6 @@ fdattach(struct isa_device *dev) continue; break; } - typemynor = mynor | i; typesize = fd_types[i - 1].size / 2; /* * XXX all these conversions give bloated code and @@ -765,6 +840,27 @@ fdattach(struct isa_device *dev) typesize = 1480; if (typesize == 1722) typesize = 1720; +#ifdef SLICE + sprintf(namebuf,"fd%d.%d",fdu,typesize); + fd->subdevs[i].minor = i; + fd->subdevs[i].drive = fd; + fd->subdevs[i].limit.blksize = + 128 << (fd_types[i - 1].secsize); + fd->subdevs[i].limit.slicesize = + fd_types[i - 1].size + * fd->subdevs[i].limit.blksize; + sl_make_slice(&slicetype, + &fd->subdevs[i], + &fd->subdevs[i].limit, + &fd->subdevs[i].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[i].slice->probeinfo.typespecific = NULL; + fd->subdevs[i].slice->probeinfo.type = NO_SUBPART; + } +#else /* SLICE */ + typemynor = mynor | i; fd->bdevs[i] = devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -774,14 +870,15 @@ fdattach(struct isa_device *dev) UID_ROOT, GID_OPERATOR, 0640, "rfd%d.%d", fdu, typesize); } + for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = - devfs_link(fd->bdevs[0], + fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0], "fd%d%c", fdu, 'a' + i); fd->cdevs[1 + NUMDENS + i] = devfs_link(fd->cdevs[0], "rfd%d%c", fdu, 'a' + i); } +#endif /* SLICE */ #endif /* DEVFS */ #ifdef notyet if (dk_ndrive < DK_NDRIVE) { @@ -800,6 +897,22 @@ fdattach(struct isa_device *dev) return (1); } + +#ifdef SLICE + +static void +fdsinit(void *arg) +{ + struct subdev *sd = arg; + sh_p tp; + + if ((tp = slice_probeall(sd->slice)) != NULL) { + (*tp->constructor)(sd->slice); + } + config_intrhook_disestablish(&sd->drive->ich); +} +#endif /* SLICE */ + /****************************************************************************/ /* motor control stuff */ /* remember to not deselect the drive we're working on */ @@ -1022,6 +1135,10 @@ Fdopen(dev_t dev, int flags, int mode, struct proc *p) if (type == 0) type = fd_data[fdu].type; else { + /* + * For each type of basic drive, make sure we are trying + * to open a type it can do, + */ if (type != fd_data[fdu].type) { switch (fd_data[fdu].type) { case FD_360: @@ -1182,6 +1299,49 @@ bad: biodone(bp); } +#ifdef SLICE +/****************************************************************************/ +/* fdsIOreq */ +/****************************************************************************/ +static void +fdsIOreq(void *private ,struct buf *bp) +{ + unsigned nblocks, blknum, cando; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + size_t fdblk; + struct subdev *sd; + + sd = private; + fd = sd->drive; + fdu = fd->unit; + fdc = fd->fdc; + fdcu = fdc->fdcu; + + /* check for controller already busy with tape */ + if (fdc->flags & FDC_TAPE_BUSY) { + bp->b_error = EBUSY; + bp->b_flags |= B_ERROR; + goto bad; + } + bp->b_driver1 = sd; /* squirrel away which device.. */ + bp->b_resid = 0; + s = splbio(); + bufqdisksort(&fdc->head, bp); + untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); + return; +} +#endif /* SLICE */ + /***************************************************************\ * fdstart * * We have just queued something.. if the controller is not busy * @@ -1292,6 +1452,7 @@ fdintr(fdcu_t fdcu) static int fdstate(fdcu_t fdcu, fdc_p fdc) { + struct subdev *sd; int read, format, head, sec = 0, sectrac, st0, cyl, st3; unsigned blknum = 0, b_cylinder = 0; fdu_t fdu = fdc->fdu; @@ -1317,8 +1478,14 @@ fdstate(fdcu_t fdcu, fdc_p fdc) TRACE1("[fdc%d IDLE]", fdcu); return(0); } +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; +#else fdu = FDUNIT(minor(bp->b_dev)); fd = fd_data + fdu; +#endif fdblk = 128 << fd->ft->secsize; if (fdc->fd && (fd != fdc->fd)) { @@ -1332,7 +1499,7 @@ fdstate(fdcu_t fdcu, fdc_p fdc) - (char *)finfo; } if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { - blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk + + blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + fd->skip/fdblk; b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); } @@ -1704,13 +1871,26 @@ static int retrier(fdcu) fdcu_t fdcu; { + struct subdev *sd; fdc_p fdc = fdc_data + fdcu; register struct buf *bp; +#ifdef SLICE + struct fd_data *fd; + int fdu; +#endif bp = bufq_first(&fdc->head); +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; + if(fd->options & FDOPT_NORETRY) + goto fail; +#else if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) goto fail; +#endif switch(fdc->retry) { case 0: case 1: case 2: @@ -1727,14 +1907,19 @@ retrier(fdcu) default: fail: { +#ifdef SLICE + printf("fd%d: hard error, block %d ", fdu, + fd->skip / DEV_BSIZE); +#else dev_t sav_b_dev = bp->b_dev; /* Trick diskerr */ bp->b_dev = makedev(major(bp->b_dev), - (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); + (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); diskerr(bp, "fd", "hard error", LOG_PRINTF, fdc->fd->skip / DEV_BSIZE, (struct disklabel *)NULL); bp->b_dev = sav_b_dev; +#endif /* !SLICE */ if (fdc->flags & FDC_STAT_VALID) { printf( @@ -1764,11 +1949,16 @@ retrier(fdcu) return(1); } +#ifdef SLICE +static int +fdformat( struct subdev *sd, struct fd_formb *finfo, struct proc *p) +#else /* !SLICE */ static int fdformat(dev, finfo, p) dev_t dev; struct fd_formb *finfo; struct proc *p; +#endif /* !SLICE */ { fdu_t fdu; fd_p fd; @@ -1777,8 +1967,13 @@ fdformat(dev, finfo, p) int rv = 0, s; size_t fdblk; - fdu = FDUNIT(minor(dev)); - fd = &fd_data[fdu]; +#ifdef SLICE + fd = sd->drive; + fdu = fd->unit; +#else + fdu = FDUNIT(minor(dev)); + fd = &fd_data[fdu]; +#endif fdblk = 128 << fd->ft->secsize; /* set up a buffer header for fdstrategy() */ @@ -1792,7 +1987,6 @@ fdformat(dev, finfo, p) bzero((void *)bp, sizeof(struct buf)); bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; bp->b_proc = p; - bp->b_dev = dev; /* * calculate a fake blkno, so fdstrategy() would initiate a @@ -1805,7 +1999,13 @@ fdformat(dev, finfo, p) bp->b_data = (caddr_t)finfo; /* now do the format */ +#ifdef SLICE + bp->b_driver1 = sd; + fdsIOreq(sd, bp); +#else /* !SLICE */ + bp->b_dev = dev; fdstrategy(bp); +#endif /* !SLICE */ /* ...and wait for it to complete */ s = splbio(); @@ -1836,7 +2036,7 @@ fdformat(dev, finfo, p) * TODO: don't allocate buffer on stack. */ -int +static int fdioctl(dev, cmd, addr, flag, p) dev_t dev; int cmd; @@ -1861,10 +2061,33 @@ fdioctl(dev, cmd, addr, flag, p) return ftioctl(dev, cmd, addr, flag, p); #endif +#ifdef SLICE + /* + * if SLICE is defined then only ft accesses come here + * so break the rest off to another function for SLICE access. + */ + return (ENOTTY); +} + +/* + * Slice ioctls come here + */ +static int +fdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + struct subdev *sd = private; + fd_p fd = sd->drive; + fdu_t fdu = fd->unit; + fdc_p fdc = fd->fdc; + fdcu_t fdcu = fdc->fdcu; + size_t fdblk; + int error = 0; +#endif /* SLICE */ fdblk = 128 << fd->ft->secsize; switch (cmd) { +#ifndef SLICE case DIOCGDINFO: bzero(buffer, sizeof (buffer)); dl = (struct disklabel *)buffer; @@ -1908,7 +2131,7 @@ fdioctl(dev, cmd, addr, flag, p) error = writedisklabel(dev, fdstrategy, (struct disklabel *)buffer); break; - +#endif /* !SLICE */ case FD_FORM: if((flag & FWRITE) == 0) error = EBADF; /* must be opened for writing */ @@ -1916,26 +2139,30 @@ fdioctl(dev, cmd, addr, flag, p) FD_FORMAT_VERSION) error = EINVAL; /* wrong version of formatting prog */ else +#ifdef SLICE + error = fdformat(sd, (struct fd_formb *)addr, p); +#else error = fdformat(dev, (struct fd_formb *)addr, p); +#endif break; case FD_GTYPE: /* get drive type */ - *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; + *(struct fd_type *)addr = *fd->ft; break; case FD_STYPE: /* set drive type */ /* this is considered harmful; only allow for superuser */ if(suser(p->p_ucred, &p->p_acflag) != 0) return EPERM; - *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; + *fd->ft = *(struct fd_type *)addr; break; case FD_GOPTS: /* get drive options */ - *(int *)addr = fd_data[FDUNIT(minor(dev))].options; + *(int *)addr = fd->options; break; case FD_SOPTS: /* set drive options */ - fd_data[FDUNIT(minor(dev))].options = *(int *)addr; + fd->options = *(int *)addr; break; default: @@ -1959,7 +2186,32 @@ static void fd_drvinit(void *notused ) SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) + +#ifdef SLICE +static int +fdsopen(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + return(Fdopen(makedev(0,sd->minor), 0 , 0, p)); +} + +static void +fdsclose(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + fdclose(makedev(0,sd->minor), 0 , 0, p); + return ; +} + +#endif /* SLICE */ #endif + /* * Hello emacs, these are the * Local Variables: diff --git a/sys/dev/slice/disklabel.c b/sys/dev/slice/disklabel.c new file mode 100644 index 0000000..cb2119b --- /dev/null +++ b/sys/dev/slice/disklabel.c @@ -0,0 +1,827 @@ +/*- + * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. + * julian@freebsd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: $ + */ + + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/fcntl.h> +#include <sys/disklabel.h> +#include <sys/diskslice.h> +#include <sys/dkstat.h> +#include <sys/malloc.h> +#include <dev/slice/slice.h> + +#include <sys/conf.h> +#include <sys/sliceio.h> +#include <sys/syslog.h> + + +struct private_data { + u_int32_t flags; + u_int8_t rflags; + u_int8_t wflags; + int savedoflags; + struct slice *slice_down; + struct disklabel disklabel; + struct subdev { + int part; + struct slice *slice; + struct slicelimits limit; + struct private_data *pd; + u_int32_t offset; /* all disklabel supports */ + } subdevs[MAXPARTITIONS]; +}; + +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 */ +static sl_h_close_t dkl_close; /* downwards travelling close */ +static sl_h_claim_t dkl_claim; /* upwards travelling claim */ +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 struct slice_handler slicetype = { + "disklabel", + 0, + NULL, + 0, + &dkl_constructor, /* constructor */ + &dkl_IOreq, + &dkl_ioctl, + &dkl_open, + &dkl_close, + &dkl_revoke, /* revoke */ + &dkl_claim, /* claim */ + &dkl_verify, /* verify */ + &dkl_upconfig /* subslice manipulation */ +}; + +static void +sd_drvinit(void *unused) +{ + sl_newtype(&slicetype); +} + +SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL); + +/*- + * Given a slice, extract out our table of information + */ +/*- + * 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. + */ +static int +dkl_extract_table(sl_p slice, struct disklabel * lp) +{ + int error = EINVAL; + struct buf *bp; + struct disklabel *dlp; + struct partition *dp; + int part; + int slice_offset; /* XXX */ + + RR; + /* start off with a known result */ + bzero(lp, sizeof(*lp)); + 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, 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; + 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; + } + break; + } + +done: + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + return (error); +} +/* + * given a table, write it to disk. + */ +static int +dkl_insert_table(sl_p slice, struct disklabel * lp) +{ + int error = EINVAL; + struct buf *bp; + struct disklabel *dlp; + struct partition *dp; + int part; + int slice_offset; /* XXX */ + + 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. + */ + 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; + } + 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; + } + /* + * old 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; + 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++) { + 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); +} + + + +/*- + * 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. + */ + if ((error = dkl_extract_table(slice, &disklabel)) != 0) { + return (error); + } + /*- + * 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. + */ + 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; + + 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); + } + } + slice->refs++; + slice->handler_up = &slicetype; + slice->private_up = pd; + slicetype.refs++; + } + dl = &pd->disklabel; + dp0 = dl->d_partitions; + + /*- + * Handle each of the partitions. + * We should check that each makes sence and is legal. + * 1/ it should not already have a slice. + * 2/ should not be 0 length. + * 3/ should not go past end of our slice. + * 4/ should not overlap other slices. + * It can include sector 0 (unfortunatly) + */ + dp = dp0; + for (part = 0; part < MAXPARTITIONS; part++, dp++) { + int i; + if ( part == 2 ) + continue; /* XXX skip the 'c' partition */ + /* + * We could be reloading, in which case skip + * entries already set up. + */ + if (pd->subdevs[part].slice != NULL) + 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); + + if ((dp->p_offset + dp->p_size) > + (slice->limits.slicesize / slice->limits.blksize)) { + printf("dkl: slice %d too big ", part); + printf("(%x > %x:%x )\n", + (dp->p_offset + dp->p_size), + (slice->limits.slicesize / slice->limits.blksize) ); + continue; + } + /* 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. + */ + 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)) { + printf("dkl: 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->p_offset; + pd->subdevs[part].limit.blksize + = slice->limits.blksize; + pd->subdevs[part].limit.slicesize + = (slice->limits.blksize * (u_int64_t)dp->p_size); + + sprintf(name, "%s%c", slice->name, (char )('a' + part)); + sl_make_slice(&slicetype, + &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) { + case FS_UNUSED: + /* allow unuseed to be further split */ + pd->subdevs[part].slice->probeinfo.type = NULL; + break; + case FS_V6: + case FS_V7: + case FS_SYSV: + case FS_V71K: + case FS_V8: + case FS_MSDOS: + case FS_BSDLFS: + case FS_OTHER: + case FS_HPFS: + case FS_ISO9660: + case FS_BOOT : +#if 0 + printf("%s: type %d. Leaving\n", + pd->subdevs[part].slice->name, + (u_int)dp->p_fstype); +#endif + case FS_SWAP: + case FS_BSDFFS: + pd->subdevs[part].slice->probeinfo.type = NO_SUBPART; + break; + default: + pd->subdevs[part].slice->probeinfo.type = NULL; + } + /* + * Dont allow further breakup of slices that + * cover our disklabel + */ + if (dp->p_offset < 16) { +#if 0 + printf("%s: covers disklabel. Leaving\n", + pd->subdevs[part].slice->name); +#endif + pd->subdevs[part].slice->probeinfo.type = NO_SUBPART; + } + if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) { + (*tp->constructor)(pd->subdevs[part].slice); + } + } + return (error); +} + +/*- + * look at a slice that USED to be ours. + * decide if any sub-slices need to be revoked. + * If not then at least ask them to verify themselves. + */ +static int +dkl_verify(sl_p slice) +{ + register struct private_data *pd; + struct disklabel label; + struct partition *dp, *dp2; + struct disklabel *dl; + int part; + int error; + /* register struct slice *slice; */ + + 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. + */ + 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); + } + } + } + /*- 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); +} + +/*- + * Invalidate all subslices, and free resources for this handler instance. + */ +static int +dkl_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 < MAXPARTITIONS; 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 +dkl_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); +} + +/* + * 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 +dkl_open(void *private, int flags, int mode, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int error; + 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; + + /* + * 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 */ + 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 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->rflags = newrflags; + pd->wflags = newwflags; + pd->savedoflags = newoflags; + return (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 ; +} + +static int +dkl_ioctl(void *private, int cmd, caddr_t addr, int flag, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + struct disklabel *lp; + int error; + + RR; + sdp = private; + pd = sdp->pd; + slice = pd->slice_down; + lp = &pd->disklabel; + switch (cmd) { + case DIOCGDINFO: + *(struct disklabel *)addr = *lp; + return (0); + + case DIOCGPART: + if (lp == NULL) + return (EINVAL); + ((struct partinfo *)addr)->disklab = lp; + ((struct partinfo *)addr)->part = lp->d_partitions + sdp->part; + return (0); + +/* These don't really make sense. keep the headers for a reminder */ + case DIOCSDINFO: + case DIOCSYNCSLICEINFO: + case DIOCWDINFO: + case DIOCWLABEL: + return (ENOIOCTL); + } + + return ((*slice->handler_down->ioctl) (slice->private_down, + cmd, addr, flag, p)); +} + +static int +dkl_upconfig(struct slice *slice, int cmd, caddr_t addr, int flag, struct proc * p) +{ + RR; + switch (cmd) { + case SLCIOCRESET: + return (0); + +/* These don't really make sense. keep the headers for a reminder */ + default: + return (ENOIOCTL); + } + return (0); +} + +static struct disklabel static_label; +/* + * This is a hack routine called from the slice generic code to produce a dummy + * disklabel when given a slice descriptor. It's in here because this code + * knows about disklabels. + */ +int +dkl_dummy_ioctl(struct slice *slice, int cmd, caddr_t addr, + int flag, struct proc * p) +{ + struct disklabel *lp = &static_label; + + switch (cmd) { + case DIOCGDINFO: + case DIOCGPART: + bzero(lp, sizeof(static_label)); + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_secsize = slice->limits.blksize; + lp->d_nsectors = 1; + lp->d_ntracks = 1; + lp->d_secpercyl = 1; + lp->d_ncylinders = + lp->d_secperunit = slice->limits.slicesize + / slice->limits.blksize; + lp->d_npartitions = RAW_PART + 1; + lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; + lp->d_partitions[RAW_PART].p_offset = 0; + break; + default: + return (ENOIOCTL); + } + lp->d_checksum = dkcksum(lp); + + switch (cmd) { + case DIOCGDINFO: + *(struct disklabel *)addr = *lp; + break; + case DIOCGPART: + /* XXX hack alert. + * This is a hack as this information is consumed immediatly + * otherwise the use of a static buffer would be dangerous. + */ + ((struct partinfo *)addr)->disklab = lp; + ((struct partinfo *)addr)->part = lp->d_partitions + RAW_PART; + } + + return (0); + +} + +#if 0 /* use the existing one for now */ +/*- + * Compute checksum for disk label. + */ +u_int +dkcksum(lp) + register struct disklabel *lp; +{ + register u_short *start, *end; + register u_short sum = 0; + + start = (u_short *) lp; + end = (u_short *) & lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return (sum); +} +#endif /* 0 */ + diff --git a/sys/dev/slice/mbr.c b/sys/dev/slice/mbr.c new file mode 100644 index 0000000..7babfc9 --- /dev/null +++ b/sys/dev/slice/mbr.c @@ -0,0 +1,837 @@ +/*- + * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. + * julian@freebsd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: $ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/fcntl.h> +#include <sys/disklabel.h> +#include <sys/dkstat.h> +#include <sys/malloc.h> +#include <sys/sliceio.h> +#include <dev/slice/slice.h> + + +struct private_data { + u_int32_t flags; + struct slice *slice_down; + int savedoflags; + struct dos_partition dos_table[NDOSPART]; + struct subdev { + int part; + struct slice *slice; + struct slicelimits limit; + struct private_data *pd; + u_int32_t offset; /* Fdisk only has 32 bits */ + } subdevs[NDOSPART]; +}; +/* + * Bits in the mbr private data flag word + */ +#define MBRF_OPEN_RBIT 0x01 +#define MBRF_S1_OPEN_RD 0x01 +#define MBRF_S2_OPEN_RD 0x02 +#define MBRF_S3_OPEN_RD 0x04 +#define MBRF_S4_OPEN_RD 0x08 +#define MBRF_MSK_RD 0x0F +#define MBRF_OPEN_WBIT 0x10 +#define MBRF_S1_OPEN_WR 0x10 +#define MBRF_S2_OPEN_WR 0x20 +#define MBRF_S3_OPEN_WR 0x40 +#define MBRF_S4_OPEN_WR 0x80 +#define MBRF_MSK_WR 0xF0 +#define MBRF_MSK_OPEN 0xFF + +static struct dos_partition historical_bogus_partition_table[NDOSPART] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + {0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000,}, +}; +#define DOSPTYP_ONTRACK 84 + +static sl_h_constructor_t mbr_constructor; /* constructor (from device) */ +static sl_h_IO_req_t mbr_IOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t mbr_ioctl; /* ioctl req downward (to device) */ +static sl_h_open_t mbr_open; /* downwards travelling open */ +static sl_h_close_t mbr_close; /* downwards travelling close */ +static sl_h_claim_t mbr_claim; /* upwards travelling claim */ +static sl_h_revoke_t mbr_revoke;/* upwards travelling revokation */ +static sl_h_verify_t mbr_verify;/* things changed, are we stil valid? */ +static sl_h_upconfig_t mbr_upconfig;/* config request from below */ + +static struct slice_handler slicetype = { + "MBR", + 0, + NULL, + 0, + &mbr_constructor, /* constructor */ + &mbr_IOreq, + &mbr_ioctl, + &mbr_open, + &mbr_close, + &mbr_revoke, /* revoke */ + &mbr_claim, /* claim */ + &mbr_verify, /* verify */ + &mbr_upconfig /* config from below */ +}; + +static void +sd_drvinit(void *unused) +{ + sl_newtype(&slicetype); +} + +SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL); + +/* + * Given a slice, extract out our table of information + */ +static int +mbr_find_table(sl_p slice, struct buf **bpp, int *blknum) +{ + int ontrack_offset = 0; + int error; + u_int8_t *cp; + struct dos_partition *dp0, *dp; + int part; + int redone = 0; + struct buf *bp; + +RR; + *bpp = NULL; +reread: + if (error = slice_readblock(slice, ontrack_offset, &bp)) + return (error); + cp = bp->b_data; + if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + error = EINVAL; + goto done; + } + dp0 = (struct dos_partition *) (cp + DOSPARTOFF); + + /* + * Check for "Ontrack Diskmanager". Note that if the geometry is + * still needed then we probably won't be able to read a DiskManager + * MBR because we will fail to read sector 63. The very act of + * finding a Disk Manager might however have given us the info we + * need if the disk manager set's its partition up correctly. + */ + if (!redone) { + for (part = 0, dp = dp0; + part < NDOSPART; part++, dp++) { + if (dp->dp_typ == DOSPTYP_ONTRACK) { +#ifdef MAYBE + /* + * It's not known if this should always 63 or + * if this is just the start of the 2nd + * track. + */ + ontrack_offset = dp->dp_start; +#else + ontrack_offset = 63; +#endif + if (bootverbose) + printf("Found \"Ontrack Disk Manager\"\n"); + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + redone++; + goto reread; + } + } + } +done: + if (blknum) + *blknum = ontrack_offset; + *bpp = bp; + return (error); +} + +/* + * Given a slice, extract out our table of information + */ +static int +mbr_extract_table(sl_p slice, struct dos_partition *table) +{ + int error; + struct buf *bp; + +RR; + /* start off with a known result */ + bzero(table, sizeof(*table) * NDOSPART); + error = mbr_find_table(slice, &bp, NULL); + if (!error) + bcopy((bp->b_data + DOSPARTOFF), table, + sizeof(*table) * NDOSPART); +done: + if (bp) { + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + } + return (error); +} + +/* + * read the block and replace the mbr table with that given. + * If there isn't one, clear the rest of the block. + */ +static int +mbr_insert_table(sl_p slice, struct dos_partition *table) +{ + int blknum = 0; + int error; + struct buf *bp; + +RR; + error = mbr_find_table(slice, &bp, &blknum); + if ( error == EINVAL) { + /* + * The block was read, but there was no table there. + * just clear out the cruft for now. + */ + bzero(bp->b_data, slice->limits.blksize); + } else if (error == 0) { + bcopy( table, (bp->b_data + DOSPARTOFF), + sizeof(*table) * NDOSPART); + bp->b_data[0x1FE] = 0x55; + bp->b_data[0x1FF] = 0xAA; + /* XXX Somehow we should get boot code in there too. */ + /* for now leave it to the tool */ + error = slice_writeblock(slice, blknum, bp); + } +done: + if (bp) { + bp->b_flags |= B_INVAL | B_AGE; + brelse(bp); + } + return (error); +} + +/* + * look at a slice and figure out if we should be interested in it. (Is it + * ours?) + */ +static int +mbr_claim(struct slice * slice, struct slice * lower, void *ID) +{ + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + int max_ncyls; + int max_nsectors; + int max_ntracks; + u_int32_t secpercyl; + int numactive = 0; +RR; + + /* + * Don't even BOTHER if it's not 512 byte sectors + */ + if (slice->limits.blksize != 512) + return (EINVAL); + /* + * Try load a valid MBR table. This is 90% of what we need to check. + */ + if ((error = mbr_extract_table(slice, table)) != 0) { + return (error); + } + dp0 = table; + /* + * The first block of the dos code is marked like a valid MBR. + * Try to distinguish this case byt doing a sanity check on the table. + * Check: + * Flag byte can only be 0 or 0x80. + * At most one active partition. + * -Other tests to be added here- + */ + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + if (dp->dp_flag & 0x7f) { + printf ("rejected.. bad flag "); + return(EINVAL); /* must be either 0 or 0x80 */ + } + if ((dp->dp_typ) && (dp->dp_size) && (dp->dp_start == 0)) { + printf("rejected.. Slice includes MBR "); + return (EINVAL); + } + if (dp->dp_flag == 0x80) + numactive++; + } + if (numactive > 1) { + printf ("rejected.. multiple active "); + return (EINVAL); + } + /* + * If it's the MBR that comes with the disklabel then we should just + * give up and let the disklabel handler take control of this slice. + */ + if (bcmp(dp0, historical_bogus_partition_table, + sizeof historical_bogus_partition_table) == 0) { + printf("rejecting disklabel table "); + return (EINVAL); + } + /* + * well, it looks like one of ours. + */ + return (0); +} + +/* + * This routine tries to guess the geometry for + * old disk drivers that need the MBR code to set it. Bits taken from + * diskslice_machdep.c which itself evolved from earlier code. + * This is not part of the SLICE code per-se, but just a convenient place to + * put this HACK because everything is in scope. Only called by the IDE driver. + */ +int +mbr_geom_hack(struct slice * slice, struct ide_geom *geom) +{ + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + int max_ncyls; + int max_nsectors; + int max_ntracks; + u_int32_t secpercyl; +RR; + + /* + * Don't even BOTHER if it's not claimable by us. + */ + if ((error = mbr_claim(slice,NULL,0))) + return (error); + /* + * Load the mbr. + */ + if ((error = mbr_extract_table(slice, table)) != 0) { + return (error); + } + dp0 = table; + /* + * Guess the geometry. For some old drives (ESDI, st506) the + * driver below us may not yet know the geometry, but needs + * to before it can access blocks out of the first track. + * This hack is to use information in the MBR to "deduce" + * this information and pass it back. + */ + max_ncyls = 0; + max_nsectors = 0; + max_ntracks = 0; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + int ncyls; + int nsectors; + int ntracks; + + if (dp->dp_size == 0) + continue; + ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1; + if (max_ncyls < ncyls) + max_ncyls = ncyls; + nsectors = DPSECT(dp->dp_esect); + if (max_nsectors < nsectors) + max_nsectors = nsectors; + ntracks = dp->dp_ehd + 1; + if (max_ntracks < ntracks) + max_ntracks = ntracks; + } + if ((max_ncyls == 0) + && (max_nsectors == 0) + && (max_ntracks == 0)) { + /* we've gained nought, so just return */ + return (EINVAL); + } + secpercyl = (u_long) max_nsectors *max_ntracks; + printf("s=%d, h=%d, c=%d\n", max_nsectors, max_ntracks, max_ncyls); + /* + * Check that we have guessed the geometry right by checking + * the partition entries. + */ + error = 0; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + int cyl; + int sector; + int track; + int secpercyl; + + if (dp->dp_size == 0) + continue; + cyl = DPCYL(dp->dp_scyl, dp->dp_ssect); + track = dp->dp_shd; + sector = DPSECT(dp->dp_ssect) - 1; + secpercyl = max_nsectors * max_ntracks; + /* + * If the geometry doesn't work for any partition + * start then don't accept it. + */ + if (((((dp->dp_start / secpercyl) % 1024) != cyl) + && (cyl != 1023)) + || (((dp->dp_start % secpercyl) + / max_nsectors) != track) + || (((dp->dp_start % secpercyl) + % max_nsectors) != sector)) { + printf("Can't get disk geometry from MBR\n"); + return (EINVAL); + } + if ((dp->dp_start / secpercyl) > 1023) { + printf("part %d above BIOS reach\n", part); + } + } + + /* + * Set our newely hypothesised numbers into the geometry + * slots in the supplied SLICE. + */ + geom->secpertrack = max_nsectors; + geom->trackpercyl = max_ntracks; + geom->cyls = max_ncyls; + return (0); +} + +/* + * look at a slice we know to be ours and decide what the #$%^ to do with it. + * We presume the driver already did the geometry hack if needed. + */ +static int +mbr_constructor(sl_p slice) +{ + int i; + u_int64_t disksize = slice->limits.slicesize; + struct private_data *pd; + struct dos_partition *dp, *dp0; + int redone = 0; + int ontrack_offset = 0; + char name[64]; + sh_p tp; + + int part; + int error = 0; + +RR; + /* + * If we are being called to re-load a slice, + * then don't reallocate resources. + */ + if ( (pd = slice->private_up) == NULL) { + if (slice->name == NULL) { + printf("name is NULL\n"); + return (EINVAL); + } + if (strlen(slice->name) > 58) { + printf("slice: name %s too long\n", slice->name); + return (ENAMETOOLONG); + } + pd = malloc(sizeof(*pd), M_DEVBUF, M_NOWAIT); + if (pd == NULL) { + printf("fdisk: failed malloc\n"); + return (ENOMEM); + } + bzero(pd, sizeof(*pd)); + pd->slice_down = slice; + if ((error = mbr_extract_table(slice, pd->dos_table)) != 0) { + /* + * If it's just that there is no table there, + * Then we fake an empty one up and write it. if + * this were not ok, then we would have not been + * called. (as probe will have failed). If it's + * a physical error, then that's reason to fail. + */ + if (error != EINVAL) { + free(pd, M_DEVBUF); + return (error); + } + bzero(pd->dos_table, sizeof(pd->dos_table)); + if ((error = mbr_insert_table(slice, pd->dos_table))) { + free(pd, M_DEVBUF); + return (error); + } + + } + slice->refs++; + slice->handler_up = &slicetype; + slice->private_up = pd; + slicetype.refs++; + } + + dp0 = pd->dos_table; + + /* + * Handle each of the partitions. + * We should check that each makes sence and is legal. + * 1/ it should not already have a slice. + * 2/ should not be 0 length. + * 3/ should not go past end of our slice. + * 4/ should not include sector 0. + * 5/ should not overlap other slices. + */ + dp = dp0; + for (part = 0; part < NDOSPART; part++, dp++) { + int i; + if (pd->subdevs[part].slice != NULL) +breakout: continue; + if (dp->dp_size == 0) + continue; + if (dp->dp_start < 1) + continue; + if ((dp->dp_start + dp->dp_size) > + (slice->limits.slicesize/slice->limits.blksize)) + continue; + /* check for overlaps with existing slices */ + for (i = 0; i < NDOSPART; i++) { + /* skip empty slots (including this one) */ + if(pd->subdevs[i].slice == NULL ) + continue; + if ((dp0[i].dp_start < (dp->dp_start + dp->dp_size)) + && ((dp0[i].dp_start + dp0[i].dp_size) > dp->dp_start)) + { + printf("mbr: new slice %d overlaps slice %d\n", + part, i); + goto breakout; + } + } + /* + * the slice seems to make sense. Use it. + */ + pd->subdevs[part].part = part; + pd->subdevs[part].pd = pd; + pd->subdevs[part].offset = dp->dp_start; + pd->subdevs[part].limit.blksize + = slice->limits.blksize; + pd->subdevs[part].limit.slicesize + = (slice->limits.blksize * (u_int64_t)dp->dp_size); + + sprintf(name, "%ss%d", slice->name, part + 1); + sl_make_slice(&slicetype, + &pd->subdevs[part], + &pd->subdevs[part].limit, + &pd->subdevs[part].slice, + NULL, + name); + pd->subdevs[part].slice->probeinfo.typespecific = &dp->dp_typ; + switch (dp->dp_typ) { /* list stolen from fdisk */ + case 0x00: /* "unused" */ + case 0x01: /* "Primary DOS with 12 bit FAT" */ + case 0x02: /* "XENIX / filesystem" */ + case 0x03: /* "XENIX /usr filesystem" */ + case 0x04: /* "Primary DOS with 16 bit FAT" */ + case 0x05: /* "Extended DOS" */ + case 0x06: /* "Primary 'big' DOS (> 32MB)" */ + case 0x07: /* "OS/2 HPFS, QNX or Advanced UNIX" */ + case 0x08: /* "AIX filesystem" */ + case 0x09: /* "AIX boot partition or Coherent" */ + case 0x0A: /* "OS/2 Boot Manager or OPUS" */ + case 0x10: /* "OPUS" */ + case 0x40: /* "VENIX 286" */ + case 0x50: /* "DM" */ + case 0x51: /* "DM" */ + case 0x52: /* "CP/M or Microport SysV/AT" */ + case 0x56: /* "GB" */ + case 0x61: /* "Speed" */ + case 0x63: /* "ISC UNIX, System V/386, GNU HURD or Mach" */ + case 0x64: /* "Novell Netware 2.xx" */ + case 0x65: /* "Novell Netware 3.xx" */ + case 0x75: /* "PCIX" */ + case 0x80: /* "Minix 1.1 ... 1.4a" */ + case 0x81: /* "Minix 1.4b ... 1.5.10" */ + case 0x82: /* "Linux swap" */ + case 0x83: /* "Linux filesystem" */ + case 0x93: /* "Amoeba filesystem" */ + case 0x94: /* "Amoeba bad block table" */ + case 0xA6: /* "OpenBSD" */ + case 0xA7: /* "NEXTSTEP" */ + case 0xB7: /* "BSDI BSD/386 filesystem" */ + case 0xB8: /* "BSDI BSD/386 swap" */ + case 0xDB: /* "Concurrent CPM or C.DOS or CTOS" */ + case 0xE1: /* "Speed" */ + case 0xE3: /* "Speed" */ + case 0xE4: /* "Speed" */ + case 0xF1: /* "Speed" */ + case 0xF2: /* "DOS 3.3+ Secondary" */ + case 0xF4: /* "Speed" */ + case 0xFF: /* "BBT (Bad Blocks Table)" */ + printf("%s: type %d. Leaving\n", + pd->subdevs[part].slice->name, + (u_int)dp->dp_typ); + pd->subdevs[part].slice->probeinfo.type = NO_SUBPART; + break; + case DOSPTYP_386BSD: /* 0xA5 "FreeBSD/NetBSD/386BSD" */ + pd->subdevs[part].slice->probeinfo.type = "disklabel"; + break; + default: + pd->subdevs[part].slice->probeinfo.type = NULL; + } + if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) { + (*tp->constructor)(pd->subdevs[part].slice); + } + } + return (error); +} + +/* + * look at a slice that USED to be ours. + * decide if any sub-slices need to be revoked. + * If not then at least ask them to verify themselves. + * Note, arg 'slice' is not strictly needed + */ +static int +mbr_verify(sl_p slice) +{ + register struct private_data *pd; + struct dos_partition table[NDOSPART]; + struct dos_partition *dp, *dp0; + int part; + int error; + /* register struct slice *slice; */ + +RR; + pd = slice->private_up; + /* slice = pd->slice_down; */ + bzero(table, sizeof(table)); + /* + * Try load a valid MBR table. This is 90% of what we need to check. + */ + if ((slice->limits.blksize != 512) + || ((error = mbr_extract_table(slice, table)) != 0)) { + /* + * Oh oh, we need to invalidate all the subslices. + * and relinquish this slice. + */ + return(mbr_revoke(pd)); + } + /* + * For each existing subslice, check that the basic size + * and position has not changed. Also check the TYPE. + * It is possible we should allow a slice to grow. + */ + dp = dp0 = pd->dos_table; + for (part = 0, dp = dp0; part < NDOSPART; part++, dp++) { + if (pd->subdevs[part].slice) { + if ((table[part].dp_start != dp->dp_start) + || (table[part].dp_size != dp->dp_size) + || (table[part].dp_typ != dp->dp_typ) ) { + sl_rmslice(pd->subdevs[part].slice); + pd->subdevs[part].slice = NULL; + } else if ( pd->subdevs[part].slice->handler_up) { + (*pd->subdevs[part].slice->handler_up->verify) + (pd->subdevs[part].slice); + } + } + } + /* + * Having got rid of changing slices, replace + * the old table with the new one, and + * Handle any new slices by calling the constructor. + * This way, if we are in 'promiscuous' mode, + * (e.g. repartitionning a disk we are running on from + * Single user mode, the unchanged slices can remain open and active + * through the process. If you change an open slice, + * the vnodes will be changed to deadfs so a crash is probably + * nearby. XXX too late. It's written to disk.. (we COULD reverse it, + * but....) + */ + bcopy( table, dp0, sizeof(table)); + error = mbr_constructor(slice); + return (error); +} + +/* + * Invalidate all subslices, and free resources for this handler instance. + */ +static int +mbr_revoke(void *private) +{ + register struct private_data *pd; + register struct slice *slice; + int part; + +RR; + pd = private; + slice = pd->slice_down; + for (part = 0; part < NDOSPART; part++) { + if (pd->subdevs[part].slice) { + sl_rmslice(pd->subdevs[part].slice); + } + } + /* + * remove ourself as a handler + */ + slice->handler_up = NULL; + slice->private_up = NULL; + slicetype.refs--; + free(pd,M_DEVBUF); + sl_unref(slice); + return (0); +} + +/* + * shift the appropriate IO by the offset for that slice. + */ +static void +mbr_IOreq(void *private, struct buf * bp) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + +RR; + sdp = private; + pd = sdp->pd; + slice = pd->slice_down; + bp->b_pblkno += sdp->offset; /* add the offset for that slice */ + sliceio(slice, bp, SLW_ABOVE); +} + +static int +mbr_open(void *private, int flags, int mode, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int part; + int error; + int newflags = 0; + int oldoflags = 0; + int newoflags = 0; + +RR; + sdp = private; + part = sdp->part; + pd = sdp->pd; + slice = pd->slice_down; + + /* + * Calculate the change to to over-all picture here. + * Notice that this might result in LESS open bits + * if that was what was passed from above. + * (Prelude to 'mode-change' instead of open/close.) + */ + /* work out what our stored flags will be if this succeeds */ + newflags = pd->flags & ~((MBRF_OPEN_WBIT|MBRF_OPEN_RBIT) << part); + newflags |= (flags & FWRITE) ? (MBRF_OPEN_WBIT << part) : 0; + newflags |= (flags & FREAD) ? (MBRF_OPEN_RBIT << part) : 0; + + /* work out what we want to pass down this time */ + newoflags = (newflags & MBRF_MSK_WR) ? FWRITE : 0; + newoflags |= (newflags & MBRF_MSK_RD) ? FREAD : 0; + + /* + * If the agregate flags we used last time are the same as + * the agregate flags we would use this time, then don't + * bother re-doing the command. + */ + if (newoflags != pd->savedoflags) { + if (error = sliceopen(slice, newoflags, mode, p, SLW_ABOVE)) { + return (error); + } + } + + /* + * Now that we know it succeeded, commit, by replacing the old + * flags with the new ones. + */ + pd->flags &= ~MBRF_MSK_OPEN; + pd->flags |= newflags; + pd->savedoflags = newoflags; + return (0); +} + +static void +mbr_close(void *private, int flags, int mode, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int newflags; + int newoflags; + int part; + +RR; + sdp = private; + part = sdp->part; + pd = sdp->pd; + slice = pd->slice_down; + + if ((pd->flags & MBRF_MSK_OPEN) == 0) + return; + + /* work out what our stored flags will be if this succeeds */ + newflags = pd->flags & ~((MBRF_OPEN_WBIT|MBRF_OPEN_RBIT) << part); + newflags |= (flags & FWRITE) ? (MBRF_OPEN_WBIT << part) : 0; + newflags |= (flags & FREAD) ? (MBRF_OPEN_RBIT << part) : 0; + + /* work out what we want to pass down this time */ + newoflags = (newflags & MBRF_MSK_WR) ? FWRITE : 0; + newoflags |= (newflags & MBRF_MSK_RD) ? FREAD : 0; + + /* + * If this was the last open slice above, then release our own open + */ + pd->flags &= ~((MBRF_OPEN_RBIT|MBRF_OPEN_WBIT) << part); + if (pd->flags & MBRF_MSK_OPEN) { + sliceclose(slice, newoflags, mode, p, SLW_ABOVE); + } + pd->flags &= ~MBRF_MSK_OPEN; + pd->flags |= newflags; + pd->savedoflags = newoflags; + return ; +} + +static int +mbr_ioctl(void *private, int cmd, caddr_t addr, int flag, struct proc * p) +{ + register struct private_data *pd; + struct subdev *sdp; + register struct slice *slice; + int error; + +RR; + sdp = private; + pd = sdp->pd; + slice = pd->slice_down; + + return ((*slice->handler_down->ioctl) (slice->private_down, + cmd, addr, flag, p)); +} + +static int +mbr_upconfig(struct slice *slice, int cmd, caddr_t addr, + int flag, struct proc * p) +{ + RR; + switch (cmd) { + case SLCIOCRESET: + return (0); + +/* These don't really make sense. keep the headers for a reminder */ + default: + return (ENOIOCTL); + } + return (0); +} + diff --git a/sys/dev/slice/slice.4 b/sys/dev/slice/slice.4 new file mode 100644 index 0000000..2fffdb3 --- /dev/null +++ b/sys/dev/slice/slice.4 @@ -0,0 +1,152 @@ +yes I know this is not in mandoc format.. + +The slices are stackable.. +With alternating layers of handler(driver)/slice/handler/slice/handler/slice +The "Slice" is implemented as a common structure shared between three +pieces of code. Each slice in the stack can be thought of in OO terms as +an instance of the 'slice' object. Methods include all the 'device' node +methods exported via the cdevsw[], bdevsw[] and devfs interfaces. Thus +whenever a handler exports a slice object, a unique node is made available +to the users via the device system, to access that slice, as if it were a +disk in it's own right. Since the interface is implemented by the same +code no matter where in the stack it occurs, all partitions and devices +which are exported by the slice code, exhibit almost identical behavior. +Theoretically, it should be possible to treat a partition of a device, as +if it were a separate device, as it should exhibit the same behavior as +the device itself (except for size). + +The diagram below exhibits the form of one layer of the stack. Each handler +can decide how many slices to export on the upper side, and +how many slices to connect to on the lower side. If A slice can not be +further subdivided, there may not be an upper handler. + + [upper handler] (optional) + ^ + | + | + v |------ raw (char) device +[common slice information]<---------->[slice device] + ^ |------ block device + | + | + v + [lower handler] (may be a device driver) + +Each of these 3 items share some knowledge of the internal structure and +contents of the slice structure. They also know each other's published +interfaces. This may change as the design settles down and it becomes more +obvious which parts can be hidden. + +The slices are created bottom up. +When the driver decides that there is media that should be made available, +it creates a 'slice' object to represent it. This slice object comes with a +set of methods for exporting and implementing a device. The action of creating +a slice therefor creates the interface through which a user can access that +device. A driver might even export such slice before the media is present, +in order to make a device node available to the user. (e.g. the floppy +driver would make /dev/rfd0 available even if there was no media present, +simply because it has no way of detecting that the media has been added. +Attempts to open or access that node would result in the usual EIO +errors. + +i.e. the device probes, and creates a static 'slice' that is associated with +the device.. The static slice can't be removed unless the driver does so, +thought if the media is changed the size of the slice may change. + + +Some time after the media has been detected, or deduced to be present, +the driver would ask the system to try interpret the contents of the +media. It does this by passing the slice to the generic code. The generic +code will ask all the possible handlers to see if that slice (or virtual +disk) has the structure it requires. Sometimes the driver (or lower handler, +for that is what the driver is from the point of view of the slice) Will 'seed' +the slice with a 'hint' which will make the generic code narrow it's requests +to a particular handler, or group of handlers. + +When a slice object attaches an handler to one of it's slices, that handler +might elect to further export more slices, each representing some different +view of the slice. This could result on a multi layer stack of slices and +handlers, depending on the contents of the device. Whether a handler will +elect to further divide a slice given to it is solely up to that handler. No +other code has jurisdiction over that decision. + +Because a device may need to know that it is being used, it is important +that open() events be cascaded down towards the device. Handlers that +export multiple slices upwards must pass down the union of all the open +states of those slices. + +A lower level handler can decide that the slices it has exported are no +longer valid. This can occur for several reasons. For example a write to a +low level slice might change the structures defining a higher level slice, +or a driver (the lowest level handler) might notice that the media on which +a slice is based, has been removed, or in some other way become +unavailable. The handler must be able to invalidate the slice(es) affected, +and know that the system will cascade that invalidation upwards as needed. +A higher handler may decide to no pass on the invalidation if it calculates +that higher level services can still be provided without the particular +lower slice being present, (e.g. a RAID handler). + +Access to various layers is controlled by a strict protocol to avoid +accidental system damage. There is a single sysctl variable that can +disable the enforcement of this protocol, however it should ony be used +in special (e.g. system instalation) circumstances. The basic protocol +is that a higher level device cannot be opened while one of it's lower +layers is open for writing. Similarly, a lower layer cannot be openned for +writing while an upper layer is open at all. Two devices at different +layers can be openned at the same time if there is no direct +decendancy between the two. In an analogue, we might say that 'cousins' +can be openned independantly, but anscestors and descendents cannot. +The sysctl variable kern.slicexclusive has 3 values. +0 disables the checks metioned above. 1 enables them, and 2 +enables eve more draconian rules in which even READ opens are disabled. + +Further rules govern the interaction of the block and raw versions of a +slice. For example, if a block device is open for read/write, it's raw +device can not be written to (in mode 1) + +[think about upwards permission inherritance for subslices] + + +[setting up new configurations] +A disk exports simply a raw slice. It has no preference as to what goes on it.. +(preferences are stored in the slice's probehints structure.) +To slice it into fdisk type: +1/ set the hints to "mbr", through an ioctl on that device. (e.g. rsd0) +2/ Run the "mbr" code's constructor. this will initialise the slice. + The "mbr" code will actually write an mbr to the slice, + with default values. (so it will recognise it in the future). + (this is why the claim is separate from the constructor). The claim() + is nondestructive. The constructor KNOWS it owns the slice. +3/ Send ioctls to the device that are redirected UP to the new handler. + These ioctls allow "type specific templates" and manipulation + of slice tables. Each hander interprets these to suit it's own table + format. This uses the sl_h_upconfig() method, which is basically an + ioctl entrypoint, but which is not automatically cascaded up. + + +rc should have the following added to it to make the system 'safe' +when multi-user mode is entered. + +*** /etc/rc.orig Sat Apr 18 14:34:48 1998 +--- /etc/rc Sat Apr 18 14:38:32 1998 +*************** +*** 82,87 **** +--- 82,96 ---- + exit 1 + fi + ++ ###DEVFS ++ # put the storage slices into safe mode. ++ # 0 == unsafe. One char, one blk and one subslice can all be openned R/W. ++ # 1 = readonly. If a subslice is open, a blk and chr can be openned R/O. ++ # If a slice is open R/W, subslices cannot be openned. ++ # 2 = exclusive. If a subslice is open, a blk or chr cannot be openned. ++ # and visa versa. ++ sysctl -w kern.slicexclusive=1 ++ + # If there is a global system configuration file, suck it in. + if [ -f /etc/rc.conf ]; then + . /etc/rc.conf + + + diff --git a/sys/dev/slice/slice.h b/sys/dev/slice/slice.h new file mode 100644 index 0000000..553bdb5 --- /dev/null +++ b/sys/dev/slice/slice.h @@ -0,0 +1,195 @@ +/*- + * 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: $ + */ + +typedef struct slice_handler *sh_p; +typedef struct slice *sl_p; + +struct slicelimits { + u_int32_t blksize; /* IN BYTES */ + u_int64_t slicesize; /* IN BYTES */ +}; +typedef struct slicelimits *slmt_p; + +/* + * This struct is only used by the IDE geometry guessing hack in + * the MBR and disklabel code, when talked to by the IDE driver with a VERY + * OLD DISK + */ +struct ide_geom { + u_int32_t secpertrack; /* set to 0 if geom not known */ + u_int16_t trackpercyl; + u_int32_t cyls; +}; + +/* + * The probehints are set by the lower handler, to give direction as to + * what handler is probably required above. If a slice is repartitioned, + * these may change e.g. mbr may set 165 meaning "FreeBSD slice" or 4 "DOS". + * -type: a string for the type that should be used. + * if it's a null string ("") then don't even try find a sub handler. + * defined as NO_SUBPART + * if it's a NULL pointer (NULL) then probe all known types. + * -typespecific: A pointer to SOMETHING that teh lower handler thinks + * may be of interest to the higher hamdlers. The "something" is dependent + * on the type of the lower handler so the upper handler must know of + * this in advance. The type of this should be specified in an + * include file associated with the lower type. This is probably rarely + * needed. + */ +struct probehints { + char *type; /* don't probe, just use this type */ + void *typespecific; /* the lower layer specifies this */ +}; +#define NO_SUBPART "" +/* + * The common slice structure with data, methods and linkages. + */ +struct slice { + /* Per slice data */ + char *name; /* e.g. sd0 wd0s1, wd0s1a ?? */ + struct probehints probeinfo; /* how we should probe this */ + u_int32_t flags; /* this device open, etc. */ + u_int16_t refs; /* active references, free if 1->0 */ + u_int16_t opencount; /* actual count of opens if allowed */ + struct slicelimits limits; /* limits on this slice */ + sh_p handler_up; /* type methods etc. */ + void *private_up; /* data for the slice type */ + sh_p handler_down; /* type methods etc. */ + void *private_down; /* data for the slice type */ + /*------- fields for the slice device driver -------*/ + LIST_ENTRY(slice) hash_list; /* next slice in this bucket */ + u_int32_t minor; /* the key for finding us */ + void *devfs_btoken; + void *devfs_ctoken; +}; + +/* bit definitions for the slice flags */ +#define SLF_CLOSED 0x00000000 /* slice not open */ +#define SLF_OPEN_BLK_RD 0x00000001 /* blk slice readable */ +#define SLF_OPEN_BLK_WR 0x00000002 /* blk slice writeable */ +#define SLF_OPEN_BLK (SLF_OPEN_BLK_RD|SLF_OPEN_BLK_WR) +#define SLF_OPEN_CHR_RD 0x00000004 /* raw slice readable */ +#define SLF_OPEN_CHR_WR 0x00000008 /* raw slice writeable */ +#define SLF_OPEN_CHR (SLF_OPEN_CHR_RD|SLF_OPEN_CHR_WR) +#define SLF_OPEN_DEV_RD (SLF_OPEN_CHR_RD|SLF_OPEN_BLK_RD) +#define SLF_OPEN_DEV_WR (SLF_OPEN_CHR_WR|SLF_OPEN_BLK_WR) +#define SLF_OPEN_DEV (SLF_OPEN_DEV_RD|SLF_OPEN_DEV_WR) +#define SLF_OPEN_UP_RD 0x00000010 /* upper layer is readable */ +#define SLF_OPEN_UP_WR 0x00000020 /* upper layer is writable */ +#define SLF_OPEN_UP 0x00000030 /* upper layer is open */ +#define SLF_OPEN_WR (SLF_OPEN_UP_WR|SLF_OPEN_DEV_WR) +#define SLF_OPEN_RD (SLF_OPEN_UP_RD|SLF_OPEN_DEV_RD) +#define SLF_OPEN_STATE (SLF_OPEN_WR|SLF_OPEN_RD) /* Mask open state */ + +#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 */ + +/* + * prototypes for slice methods + */ +typedef void sl_h_IO_req_t(void *private, struct buf * buf); +typedef int sl_h_ioctl_t(void *private, int cmd, caddr_t data, + int fflag, struct proc * p); +typedef int sl_h_constructor_t(sl_p slice); +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_verify_t(struct slice *slice); +typedef int sl_h_upconfig_t(struct slice *slice, int cmd, caddr_t data, + int fflag, struct proc *p); + +struct slice_handler { + char *name; + 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_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 */ + sl_h_close_t *close; /* downwards travelling close */ + sl_h_revoke_t *revoke; /* revoke upwards (towards user ) */ + sl_h_claim_t *claim; /* claim a new slice */ + sl_h_verify_t *verify; /* verify that a slice as it was before */ + sl_h_upconfig_t *upconf; /* config requests from slice below */ +}; + +/* + * general routines that handlers need. + */ +int sl_make_slice(sh_p handler_down, void *private_down, + struct slicelimits *limits, + sl_p *slicepp, char *type, 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); + +/* + * Definitions for "SLICE" utilities. (handler or device acting on a slice). + */ +enum slc_who { SLW_ABOVE, SLW_DEVICE }; /* helps to know who's calling */ + +void sliceio(sl_p slice, struct buf * bp, enum slc_who who); +int sliceopen(sl_p slice, int flags, int mode, + struct proc * p, enum slc_who who); +void sliceclose(sl_p slice, int flags, int mode, + struct proc * p, enum slc_who who); + +void sl_unref(sl_p slice); +void slice_add_device(sl_p slice); +void slice_remove_device(sl_p slice); + +/* + * The geometry guessing HACK functions + */ +int mbr_geom_hack(struct slice * slice, struct ide_geom *geom); +int dkl_geom_hack(struct slice * slice, struct ide_geom *geom); +/* + * The routine to produce a dummy disklabel from a slice. + * Lives in disklabel.c because that's where everyhting is in scope, + * but is used in slice_device.c. XXX hack. + */ +int dkl_dummy_ioctl(struct slice *slice, int cmd, caddr_t addr, + int flag, struct proc * p); + +/* + * debugging + */ +#if 0 +#define RR printf(__FUNCTION__ " called\n") +#else +#define RR /* nothing */ +#endif diff --git a/sys/dev/slice/slice_base.c b/sys/dev/slice/slice_base.c new file mode 100644 index 0000000..558720b --- /dev/null +++ b/sys/dev/slice/slice_base.c @@ -0,0 +1,671 @@ +/*- + * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. + * julian@freebsd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> /* SYSINIT stuff */ +#include <sys/fcntl.h> /* FREAD/FWRITE */ +#include <sys/conf.h> /* cdevsw stuff */ +#include <sys/malloc.h> /* malloc region definitions */ +#include <sys/buf.h> /* buffers for IO */ +#include <sys/queue.h> /* linked lists etc. */ +#include <sys/stat.h> /* S_IFCHR, S_IFBLK */ +#include <sys/sysctl.h> /* the sysctl for shooting self in foot */ +/*#include <sys/devfsext.h> */ /* DEVFS defintitions */ +#include <dev/slice/slice.h> /* temporary location */ + +#define SLICESPL() splbio() + + +static int slicexclusive = 0; /* default value == "foot shootable" */ + +/* + * Make a new type available. Just link it in, but first make sure there is + * no name collision. + */ + +static sh_p types; + +int +sl_newtype(sh_p tp) +{ + if (sl_findtype(tp->name)) { + return (EEXIST); + } + tp->next = types; + types = tp; + return (0); +} + +/* + * Look for a type of the name given. + */ +sh_p +sl_findtype(char *type) +{ + sh_p tp; + + tp = types; + while (tp) { + if (strcmp(tp->name, type) == 0) + return (tp); + tp = tp->next; + } + return (NULL); +} + +/* + * 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) +{ + 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; + } + /* + * 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]) { + 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); + } + } + /*printf("%s: Leaving as raw device\n", slice->name); */ + return (NULL); +} + + + +/* + * Make a handler instantiation of the requested type. + * + */ +static int +sl_make_handler(char *type, sl_p slice) +{ + sh_p handler_up; + void *private_up; + int errval; + + /* + * check that the type makes sense. + */ + if (type == NULL) { + return (EINVAL); + } + handler_up = sl_findtype(type); + 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); + } +} + +/* + * lock and unlock Slices while doing operations such as open(). + * gets a reference on the slice.. + * XXX This doesn't work for SMP. + */ +int +lockslice(struct slice *slice) +{ + int s = SLICESPL(); + slice->refs++; + while ( slice->flags & (SLF_LOCKED | SLF_INVALID)) { + if (slice->flags & SLF_INVALID) { + sl_unref(slice); + splx(s); + return (ENXIO); + } + slice->flags |= SLF_WANTED; + tsleep(slice, PRIBIO, "lockslice", 0); + } + slice->flags |= SLF_LOCKED; + splx(s); + return (0); +} + +/* + * Releases a slice + * Assumes that if we had it locked, no-one else could invalidate it. + * We can still hold a reference on it. + */ +int +unlockslice(struct slice *slice) +{ + int s = SLICESPL(); + slice->flags &= ~SLF_LOCKED; + if ( slice->flags & SLF_WANTED) { + slice->flags &= ~SLF_WANTED; + wakeup(slice); + } + splx(s); + return (0); +} + +/* + * create a new slice. Link it into the structures. don't yet find and call + * it's type handler. That's done later + */ +int +sl_make_slice(sh_p handler_down, void *private_down, + struct slicelimits * limits, + sl_p * slicepp, char *type, char *name) +{ + sl_p slice; + + /* + * Allocate storage for this instance . + */ + slice = malloc(sizeof(*slice), M_DEVBUF, M_NOWAIT); + if (slice == NULL) { + printf("slice failed to allocate driver storage\n"); + return (ENOMEM); + } + bzero(slice, sizeof(*slice)); + if (name) { + slice->name = malloc(strlen(name) + 1, M_DEVBUF, M_NOWAIT); + if (slice->name == NULL) { + printf("slice failed name storage\n"); + free(slice, M_DEVBUF); + return (ENOMEM); + } + strcpy(slice->name, name); + } + slice->handler_down = handler_down; + slice->private_down = private_down; + handler_down->refs++; + slice->limits = *limits; + 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); +} + +/* + * 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. + */ +void +sl_rmslice(sl_p slice) +{ +RR; + /* + * An extra reference so it doesn't go away while we are not looking. + */ + slice->refs++; + + if (slice->flags & SLF_INVALID) { + /* + * If it's already shutting down, let it die without further + * taunting. "go away or I'll taunt you a second time, you + * silly eenglish pig-dog" + */ + sl_unref(slice);/* possibly the last reference */ + return; + } + + /* + * Mark it as invalid so any newcomers know not to try use it. + * No real need to LOCK it. + */ + slice->flags &= ~SLF_OPEN_STATE; + slice->flags |= SLF_INVALID; + + /* + * remove the device appendages. + * Any open vnodes SHOULD go to deadfs. + */ + slice_remove_device(slice); + + /* + * Propogate the damage upwards. + * Note that the revoke method is not optional. + * The upper handler releases it's reference so refs--. + */ + if (slice->handler_up) { + (*slice->handler_up->revoke) (slice->private_up); + } + sl_unref(slice); /* One for the lower handler that called us */ + sl_unref(slice); /* possibly the last reference */ +} + + + +void +sl_unref(sl_p slice) +{ + if ((--(slice->refs)) == 0) { + FREE(slice, M_DEVBUF); + } +} + +/* + * Read 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?) + */ +int +slice_readblock(struct slice * slice, int blkno, struct buf ** bpp) +{ + struct buf *bp; + int error = 0; + + /* + * posibly attempt to open device? + */ + /* --not yet-- */ + /* + * Now that it is open, get the buffer and set in the parameters. + */ + bp = geteblk((int) slice->limits.blksize); + if (bp == NULL) { + return (ENOMEM); + } + bp->b_pblkno = bp->b_blkno = blkno; + 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); +} + +/* + * Read 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?) + */ +int +slice_writeblock(struct slice * slice, int blkno, struct buf * bp) +{ + int error = 0; + + if (bp == NULL) { + return (ENOMEM); + } + 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 (error); +} + +/* + * functions that are used to call the next level down. + */ +void +sliceio(sl_p slice, struct buf * bp, enum slc_who who) +{ + /* XXX do shortcuts here */ + + if (slice->flags & SLF_INVALID) { + bp->b_error = ENXIO; + goto bad; + } + /* + * if it's from above, assume it hasn't + * broken it's agreement about read/write. + * A higher level slice would have caught it. + * Make no such assumption if it's this device. + */ + if (who == SLW_DEVICE) { + if (((slice->flags & SLF_OPEN_DEV_WR) == 0) && + ( (bp->b_flags & B_READ) == B_WRITE )) { + bp->b_error = EROFS; + goto bad; + } + } + (*slice->handler_down->IOreq) (slice->private_down, bp); + return; +bad: + bp->b_flags |= B_ERROR; + /* toss transfer, we're done early */ + biodone(bp); + return; +} + +/* + * Try open a slice. + * don't forget to say if we are above (1) or the dev (0). + * + * We really need to add a lot of support for CHANGING + * what we have openned.. i.e if we have ABOVE open R/W + * and DEVICE open R/O, then closing the device + * should downgrade our open to those items below us to R/O. + * This would need support in both open and close routines in both + * slice and handler code. + * + * ((*) == Illegal state.. (how did we get here?)) + * (must have been in "shoot foot mode"). + * A bit already set can be set again. (may represent part of an upgrade) + * This may not hold true if we are in an 'illegal state'. + * Some such opens will fail in an attempt to revert to a legal state. + * success = ((request & allowed[state]) == request) + */ +#define UP_RDWR SLF_OPEN_UP +#define CHR_RDWR SLF_OPEN_CHR +#define CHR_RD SLF_OPEN_CHR_RD +#define BLK_RDWR SLF_OPEN_BLK +#define BLK_RD SLF_OPEN_BLK_RD +static u_char allowed[64] = { +/* Present state | requested states allowed */ +/* UP CHR BLK | UP CHR BLK */ +/* R W R W R W | R W R W R W */ +/* 0 0 0 0 0 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ), +/* 0 0 0 0 0 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ), +/* 0 0 0 0 1 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ), +/* 0 0 0 0 1 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ), +/* 0 0 0 1 0 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ), +/* 0 0 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 0 0 1 1 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ), +/* 0 0 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 0 1 0 0 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ), +/* 0 0 1 0 0 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ), +/* 0 0 1 0 1 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ), +/* 0 0 1 0 1 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ), +/* 0 0 1 1 0 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ), +/* 0 0 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 0 1 1 1 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ), +/* 0 0 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 0 1 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 0 1 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 0 1 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 0 1 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 0 1 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 0 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 0 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 0 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 0 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 0 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 1 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 1 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 1 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ), +/* 1 1 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ), +/* 1 1 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ) }; + +int +sliceopen(struct slice *slice, int flags, int mode, + struct proc * p, enum slc_who who) +{ + int s; + int error; + int sl_flags = slice->flags & SLF_OPEN_STATE; + int or_flags; + int and_flags; + int dn_flags; + int odn_flags; + + + if (slice->flags & SLF_INVALID) + return (ENXIO); + /* + * Firstly, don't allow re-opens of what is already open + */ + if (error = lockslice(slice)) + return (error); + error = EBUSY; /* default answer */ + switch (who) { + case SLW_ABOVE: + or_flags = ((flags & FREAD) ? SLF_OPEN_UP_RD : 0); + or_flags |= ((flags & FWRITE) ? SLF_OPEN_UP_WR : 0); + and_flags = ~SLF_OPEN_UP; + break; + case SLW_DEVICE: + switch (mode & S_IFMT) { + case S_IFCHR: + or_flags = ((flags & FREAD) ? SLF_OPEN_CHR_RD : 0); + or_flags |= ((flags & FWRITE) ? SLF_OPEN_CHR_WR : 0); + and_flags = ~SLF_OPEN_CHR; + break; + case S_IFBLK: + or_flags = ((flags & FREAD) ? SLF_OPEN_BLK_RD : 0); + or_flags |= ((flags & FWRITE) ? SLF_OPEN_BLK_WR : 0); + and_flags = ~SLF_OPEN_BLK; + break; + default: + panic("slice: bad open type"); + } + break; + default: + panic("slice: bad request source"); + } + /* + * Be appropriatly paranoid depending on the system mode. + * This is also probably wrong XXX + */ + switch(slicexclusive) { + case 2: + /* + * if any one path has it open, we forbid any other + * paths. Only allow an upgrade/downgrade from + * the same source as the present openner. + */ + if ( sl_flags & and_flags) + goto reject; + case 1: /* + * The behaviour is encoded into the state array given above. + */ + if ((or_flags & allowed[sl_flags]) != or_flags) + goto reject; + break; + case 0: /* + * Permission is granted to shoot self in foot. + * All three of UPPER, CHAR and BLK can be open at once. + */ + break; + } + /* + * Get the old open mode and the new open mode. + * If we already have it open in this way, don't do it again. + * + * XXX More thought needed for the locking and open-flags. + * For now ignore the existance of flags other than FWRITE & FREAD. + */ + odn_flags = (sl_flags & SLF_OPEN_WR) ? FWRITE : 0; + odn_flags |= (sl_flags & SLF_OPEN_RD) ? FREAD : 0; + sl_flags &= and_flags; + sl_flags |= or_flags; + dn_flags = (sl_flags & SLF_OPEN_WR) ? FWRITE : 0; + dn_flags |= (sl_flags & SLF_OPEN_RD) ? FREAD : 0; + error = 0; + if (dn_flags != odn_flags) { + if ((error = (*slice->handler_down->open) (slice->private_down, + dn_flags, mode, p)) != 0) { + goto reject; + } + } + slice->flags &= ~SLF_OPEN_STATE; + slice->flags |= sl_flags; +reject: + unlockslice(slice); + sl_unref(slice); /* lockslice gave us a ref.*/ + return (error); +} + +void +sliceclose(struct slice *slice, int flags, int mode, + struct proc * p, enum slc_who who) +{ + sh_p tp; + + if (slice->flags & SLF_INVALID) + return ; + if (lockslice(slice)) + return ; + switch (who) { + case SLW_ABOVE: + slice->flags &= ~SLF_OPEN_UP; + break; + case SLW_DEVICE: + switch (mode & S_IFMT) { + case S_IFCHR: + slice->flags &= ~SLF_OPEN_CHR; + break; + case S_IFBLK: + slice->flags &= ~SLF_OPEN_BLK; + break; + default: + panic("slice: bad open type"); + } + /* + * If we had an upper handler, ask it to check if it's still + * valid. it may decide to self destruct. + */ + if (slice->handler_up) { + (*slice->handler_up->verify)(slice); + } + /* + * If we don't have an upper handler, check if + * maybe there is now a suitable environment for one. + * We may end up with a different handler + * from what we had above. Maybe we should clear the hint? + * 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); + } + } + break; + } + /* + * Last-close semantics strike again + * This may refine to a downgrade if we closed (say) the last writer + * but there are still readers. + * probably open/close should merge to one 'mode-change' function. + * (except for a vnode reference with no mode) + */ + if ( (slice->flags & SLF_OPEN_STATE) == 0) + (*slice->handler_down->close) (slice->private_down, + flags, mode, p); + unlockslice(slice); + sl_unref(slice); + return ; +} + + +/* + * control behaviour of slices WRT sharing: + * 2 = no sharing + * 1 = read on a device already mounted (or parent of) is ok. No writes. + * 0 = go ahead.. shoot yourself in the foot. + */ +static int +sysctl_kern_slicexclusive SYSCTL_HANDLER_ARGS +{ + int error; + int new_val = slicexclusive; + + error = sysctl_handle_int(oidp, &new_val, 0, req); + if (error == 0) { + if ((new_val >= 0) && (new_val < 3)) { + slicexclusive = new_val; + } else { + error = EINVAL; + } + } + return (error); +} + +SYSCTL_PROC(_kern, OID_AUTO, slicexclusive, CTLTYPE_INT|CTLFLAG_RW, + 0, sizeof slicexclusive, sysctl_kern_slicexclusive, "I", ""); + diff --git a/sys/dev/slice/slice_device.c b/sys/dev/slice/slice_device.c new file mode 100644 index 0000000..4b7f86b --- /dev/null +++ b/sys/dev/slice/slice_device.c @@ -0,0 +1,388 @@ +/*- + * Copyright (C) 1997,1998 Julian Elischer. All rights reserved. + * julian@freebsd.org + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> /* SYSINIT stuff */ +#include <sys/conf.h> /* cdevsw stuff */ +#include <sys/malloc.h> /* malloc region definitions */ +#include <sys/buf.h> /* bufs for describing IO */ +#include <sys/fcntl.h> /* file open modes etc. */ +#include <sys/queue.h> /* standard queue macros */ +#include <sys/stat.h> /* S_IFBLK, S_IFMT etc. */ +#include <sys/devfsext.h> /* DEVFS defintitions */ +#include <dev/slice/slice.h> /* temporary location */ + + + +/* Function prototypes (these should all be static except for slicenew()) */ +static d_open_t slcdevopen; +static d_close_t slcdevclose; +static d_ioctl_t slcdevioctl; +static d_dump_t slcdevdump; +static d_psize_t slcdevsize; +static d_strategy_t slcdevstrategy; + +#define BDEV_MAJOR 14 +#define CDEV_MAJOR 20 + +static struct cdevsw slice_cdevsw; +static struct bdevsw slice_bdevsw = { + slcdevopen, + slcdevclose, + slcdevstrategy, + slcdevioctl, + slcdevdump, + slcdevsize, + D_DISK, + "slice", + &slice_cdevsw, + -1 +}; + +static dev_t cdevnum, bdevnum; + +#define UNIT_HASH_SIZE 64 +LIST_HEAD(slice_bucket, slice) hash_table[UNIT_HASH_SIZE - 1]; + +/* + * Now for some driver initialisation. Occurs ONCE during boot (very early). + */ +static void +slice_drvinit(void *unused) +{ + int i; + + /* + * add bdevsw and cdevsw entries + */ + bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &slice_bdevsw); + + /* + * clear out the hash table + */ + for (i = 0; i < UNIT_HASH_SIZE; i++) { + LIST_INIT(hash_table + i); + } +} + +SYSINIT(slicedev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, + slice_drvinit, NULL); + +static int nextunit = 0; + +void +slice_add_device(sl_p slice) +{ + int unit = nextunit++; + char *name = slice->name; +RR; + slice->minor = makedev(0, + (((unit << 8) & 0xffff0000) | (unit & 0x000000ff))); + /* + * put it on the hash chain for it's bucket so we can find it again + * later. + */ + LIST_INSERT_HEAD(hash_table + (slice->minor % UNIT_HASH_SIZE), + slice, hash_list); + /* + * Add an entry in the devfs for it. Possibly should happen later. + */ + slice->devfs_ctoken = devfs_add_devswf(&slice_cdevsw, unit, DV_CHR, + UID_ROOT, GID_KMEM, 0600, "r%s", name ? name : "-"); + slice->devfs_btoken = devfs_add_devswf(&slice_bdevsw, unit, DV_BLK, + UID_ROOT, GID_KMEM, 0600, "%s", name ? name : "-"); + /* XXX link this node into upper list of caller */ +} + +/* + * Given a minor number, find the slice which the operations are destined. + * When DEVFS DDEV devices are enabled this is bypassed entirely. + */ +static struct slice * +minor_to_slice(unsigned int minor) +{ + int hash = minor % UNIT_HASH_SIZE; + struct slice *slice; + + slice = (hash_table + hash)->lh_first; + while (slice) { + if (slice->minor == minor) { + return (slice); + } + slice = slice->hash_list.le_next; + } + return (NULL); +} + +/* + * Macro to check that the unit number is valid Often this isn't needed as + * once the open() is performed, the unit number is pretty much safe.. The + * exception would be if we implemented devices that could "go away". in + * which case all these routines would be wise to check the number, + * DIAGNOSTIC or not. + */ +#define CHECKUNIT() \ +do { /* the do-while is a safe way to do this grouping */ \ + if (slice == NULL) { \ + printf( __FUNCTION__ ": unit not attached\n", unit); \ + panic ("slice"); \ + } \ +} while (0) + +#ifdef DIAGNOSTIC +#define CHECKUNIT_DIAG() CHECKUNIT() +#else /* DIAGNOSTIC */ +#define CHECKUNIT_DIAG() +#endif /* DIAGNOSTIC */ + +int +slcdevioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc * p) +{ + sl_p slice = minor_to_slice(minor(dev)); + int error = 0; + + CHECKUNIT_DIAG(); +RR; + + /* + * Look for only some generic "inherrited" ioctls that apply to all + * disk-like devices otherwise pass it down to the previous handler + */ + + switch (cmd) { + /* + * At present there are none, but eventually there would be + * something that returns the basic partition parameters. + * Whether this would be in the form of a disklabel or + * similar I have not yet decided. + */ + default: + if (slice->handler_down->ioctl) { + error = (*slice->handler_down->ioctl) + (slice->private_down, cmd, data, flag, p); + } else { + error = ENOTTY; + } + if (error) { + /* + * If no disklabel was returned, let's make + * up something that will satisfy the system's + * need for a disklabel to mount an ffs on. + * Don't overwrite error unless we get a dummy. + * let the called routine decide + * if it can handle any ioctl. + */ + if (dkl_dummy_ioctl(slice, cmd, data, flag, p) == 0) { + error = 0; + } + } + break; + } + return (error); +} + +/* + * You also need read, write, open, close routines. This should get you + * started. + * The open MIGHT allow the caller to proceed if it is a READ + * mode, and it is open at a higher layer. + * All Accesses would have to be checked for READ + * as the system doesn't enforce this at this time. + */ +static int +slcdevopen(dev_t dev, int flags, int mode, struct proc * p) +{ + sl_p slice = minor_to_slice(minor(dev)); + int error; + +RR; + if (slice == NULL) + return (ENXIO); +#if 1 /* the hack */ + if ((mode & S_IFMT) == S_IFBLK) { + /* + * XXX Because a mount -u does not re-open the device + * The hack here, is to always open block devices + * in full read/write mode. Eventually, if DEVFS + * becomes ubiquitous, VOP to do a file upgrade + * might be implemented. Other Filesystems need + * not implement it.. + * THIS SHOULD BE DONE IN slice_device.c + */ + flags |= FWRITE; + } +#endif /* the hack */ + return (sliceopen(slice, flags, mode, p, SLW_DEVICE)); +} + +static int +slcdevclose(dev_t dev, int flags, int mode, struct proc * p) +{ + sl_p slice = minor_to_slice(minor(dev)); +RR; + CHECKUNIT_DIAG(); + sliceclose(slice, flags, mode, p, SLW_DEVICE); + return(0); +} + +static int +slcdevsize(dev_t dev) +{ + sl_p slice = minor_to_slice(minor(dev)); + +RR; + if (slice == NULL) + return (-1); + +#if 0 + return (slice->limits.slicesize / slice->limits.blksize); +#else + return (slice->limits.slicesize / 512); +#endif +} + + +/* + * Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer to + * complete. Multi-page transfers are supported. All I/O requests must be a + * multiple of a sector in length. + */ +void +slcdevstrategy(struct buf * bp) +{ + sl_p slice = minor_to_slice(minor(bp->b_dev)); + u_int64_t start, end; + u_int32_t blksize; + daddr_t blkno; + int s; + +RR; + if (slice == NULL) { + bp->b_error = ENXIO; + goto bad; + } + blksize = slice->limits.blksize; + /* Check we are going to be able to do this kind of transfer */ + /* Check the start point too if DEV_BSIZE != reallity */ + if (bp->b_blkno < 0) { + Debugger("Slice code got negative blocknumber"); + bp->b_error = EINVAL; + goto bad; + } + start = (u_int64_t)bp->b_blkno * DEV_BSIZE; + if (blksize != DEV_BSIZE) { + if ((start % blksize) != 0) { + Debugger("slice: request not on block boundary."); + bp->b_error = EINVAL; + goto bad; + } + blkno = start / blksize; + } else { + blkno = bp->b_blkno; + } + + if ((bp->b_bcount % blksize) != 0) { + printf("bcount = %d, blksize= %d(%d)\n", + bp->b_bcount, blksize, + slice->limits.blksize); + Debugger("slice: request not multile of blocksize."); + bp->b_error = EINVAL; + goto bad; + } + /* + * Do bounds checking, adjust transfer, and set b_pblkno. + */ + bp->b_pblkno = blkno; + end = start + (u_int64_t)bp->b_bcount; /* first byte BEYOND the IO */ + + /* + * Handle the cases near or beyond the end of the slice. Assumes IO + * is < 2^63 bytes long. (pretty safe) + */ + if (end > slice->limits.slicesize) { + int64_t size; + size = slice->limits.slicesize - start; + /* + * if exactly on end of slice, return EOF + */ + if ((size == 0) && (bp->b_flags & B_READ)) { + printf("slice: at end of slice."); + bp->b_resid = bp->b_bcount; + goto done; + } + if (size <= 0) { + printf("slice: beyond end of slice."); + bp->b_error = EINVAL; + goto bad; + } + bp->b_bcount = size; + } + sliceio(slice, bp, SLW_DEVICE); + return; + +done: + s = splbio(); + /* toss transfer, we're done early */ + biodone(bp); + splx(s); + return; +bad: + bp->b_flags |= B_ERROR; + goto done; + +} + +void +slice_remove_device(sl_p slice) +{ + /* + * Remove the devfs entry, which revokes the vnode etc. XXX if + * handler has madde more, we should tell it too. e.g. floppy driver + * does this. + */ +RR; + devfs_remove_dev(slice->devfs_btoken); + devfs_remove_dev(slice->devfs_ctoken); + + /* + * Remove it from the hashtable. + */ + LIST_REMOVE(slice, hash_list); +} + +static int +slcdevdump(dev_t dev) +{ + sl_p slice = minor_to_slice(minor(dev)); +RR; + if (slice == NULL) + return (ENXIO); + return (0); +} diff --git a/sys/dev/slice/slices.thought b/sys/dev/slice/slices.thought new file mode 100644 index 0000000..654f250 --- /dev/null +++ b/sys/dev/slice/slices.thought @@ -0,0 +1,124 @@ +Original notes on how this might be implememented.. may not reflect +the final code very much. +======================================================[JRE] + +the slices are 'kinda' stackable.. +With alternating layers of handler(driver)/slice/handler/slice/handler/slice +The "Slice" is a common structure shared between three pieces of code. +1/ the lower handler +2/ the upper handler +3/ the generic slice code, which implements the device nodes etc. +Each of these 3 items share a knowledge of the internal struture and +contents of the slice structure. they also know each other's published +interfaces. + +Each layer is much like the previous.. +Each layer has similar characteristics.. +The slices are created bottom up.. +i.e. the device probes, and creates a static 'slice' that is +assiciated with the device.. The static slice +can't be altered, unless the media is changed.. + +A translation method, which might be NULL, in which case +it is a simple case of offset addition. +Possibly the offset might be already added.. +possibly this might be achieved by specifying a default method set. + +Each disk slice has a structure associated with it.. +When a slice is 'loaded' there must be some way of deciding if it has +a subslice structure. if it does, then that structure must +be loaded to create mode slices.. +this is recursive. + +The structuring must be such that it can recognise an attempt to change +higer level structuring.. +This suggests a recursive 'open' count.. for open subslices. + +The idea would be to pass the following operations through methods. + + translation to (possibly more than one) io operation + open count passing.. + interpretation of subslicing and other slicing operations. + possibly there might be permissions inherritance. + open a slice... + create a slice.. methods are supplied by the disk driver.. + + upward methods: + force close + + identify slice type.. slice type modules each asked + to identify.. + +to do IO + +1/ find apropriate slice (hash) +LIST_HEAD(slice_bucket, slice) hash_table[UNIT_HASH_SIZE - 1]; + +in the init, +for ( i = 0; i < UNIT_HASH_SIZE; i++) { + LIST_INIT(hash_table + i) +} + +struct slice *minor_to_slice(unsigned int minor) +{ + int hash = minor % UNIT_HASH_SIZE; + struct slice *slice; + + slice = (hash_table + hash)->lh_first; + while (slice) { + if (slice->minor == minor) { + return (slice); + } + slice = slice->hashlist.le_next + } + return (NULL); +} +2/ + if IO method, + do IO method.. + return + check bounds + adjust offset + follow slice-parent link and loop to top +IO methods are supplied by drivers +drivers including concatination drivers etc. + +concatination must be seen as a slice type + +once all parts of a concatinated slice are created, then +the new 'concatinated slice' appears in the devfs. +a concatinated slice has a 'label' that identifies it's volume +and it's part (e.g. part 3 out of 5) +'slice's in ram are either Primary or slave slices in a concatinated slice.. + + +to set up a slice call slice_add() which: +1/ If (slice type not known) + Identify the type (call all type probe routines in turn) +2/ call the succeeding type attach routine +3/ the attach routine calls slice_add() for each sub slice +The probe and attach may merge. + + +the type of a slice must be detirmined taking into account the type of the +parent slice.. It is conceivable that the parent slice +might TELL the slice_add() routine what to make the slice.. +Possibly the parent set's a CONTEXT which might be helpful +in identifying a slice + + +disk: +set up Method struct: +IO points to disk strategy +set size to whole disk +set offset to 0 +set context to RAW +call slice_add + + +slice_add() +called when we know about a slice..possibly we should fill out a slice +struct before calling it. +The slice struct is all that is needed to be able to do IO +to the slice. slice_add, will then link the slice into +the system as needed. diff --git a/sys/dev/vn/vn.c b/sys/dev/vn/vn.c index 8439c52..664014a 100644 --- a/sys/dev/vn/vn.c +++ b/sys/dev/vn/vn.c @@ -38,7 +38,7 @@ * from: Utah Hdr: vn.c 1.13 94/04/02 * * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 - * $Id: vn.c,v 1.54 1998/02/09 06:07:59 eivind Exp $ + * $Id: vn.c,v 1.55 1998/02/20 13:27:36 bde Exp $ */ /* @@ -84,17 +84,19 @@ #include <sys/diskslice.h> #include <sys/stat.h> #include <sys/conf.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#endif /* SLICE */ #include <miscfs/specfs/specdev.h> #include <sys/vnioctl.h> +static d_ioctl_t vnioctl; +#ifndef SLICE static d_open_t vnopen; static d_close_t vnclose; -static d_ioctl_t vnioctl; static d_dump_t vndump; static d_psize_t vnsize; static d_strategy_t vnstrategy; @@ -106,6 +108,30 @@ static struct bdevsw vn_bdevsw = { vnopen, vnclose, vnstrategy, vnioctl, /*15*/ vndump, vnsize, D_DISK | D_NOCLUSTERRW, "vn", &vn_cdevsw, -1 }; +#else /* SLICE */ + +static sl_h_IO_req_t nvsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t nvsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t nvsopen; /* downwards travelling open */ +static sl_h_close_t nvsclose; /* downwards travelling close */ + +static struct slice_handler slicetype = { + "vn", + 0, + NULL, + 0, + NULL, /* constructor */ + &nvsIOreq, + &nvsioctl, + &nvsopen, + &nvsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif + #define vnunit(dev) dkunit(dev) #define getvnbuf() \ @@ -117,16 +143,19 @@ static struct bdevsw vn_bdevsw = struct vn_softc { int sc_flags; /* flags */ size_t sc_size; /* size of vn */ -#if defined(DEVFS) && defined(notyet) - void *sc_bdev; /* devfs token for whole disk */ - void *sc_cdev; /* devfs token for raw whole disk */ -#endif +#ifdef SLICE + struct slice *slice; + struct slicelimits limit; + int mynor; + int unit; +#else + struct diskslices *sc_slices; +#endif /* SLICE */ struct vnode *sc_vp; /* vnode */ struct ucred *sc_cred; /* credentials */ int sc_maxactive; /* max # of active requests */ struct buf sc_tab; /* transfer queue */ u_long sc_options; /* options */ - struct diskslices *sc_slices; }; /* sc_flags */ @@ -142,6 +171,7 @@ static int vnsetcred (struct vn_softc *vn, struct ucred *cred); static void vnshutdown (int, void *); static void vnclear (struct vn_softc *vn); +#ifndef SLICE static int vnclose(dev_t dev, int flags, int mode, struct proc *p) { @@ -393,6 +423,170 @@ vnstrategy(struct buf *bp) } } +#else /* SLICE */ +static void +nvsIOreq(void *private ,struct buf *bp) +{ + struct vn_softc *vn = private; + u_int32_t unit = vn->unit; + register daddr_t bn; + int error; + int isvplocked = 0; + long sz; + struct uio auio; + struct iovec aiov; + + IFOPT(vn, VN_DEBUG) + printf("vnstrategy(%p): unit %d\n", bp, unit); + + if ((vn->sc_flags & VNF_INITED) == 0) { + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return; + } + bn = bp->b_pblkno; + bp->b_resid = bp->b_bcount;/* XXX best place to set this? */ + sz = howmany(bp->b_bcount, DEV_BSIZE); + + if( (bp->b_flags & B_PAGING) == 0) { + aiov.iov_base = bp->b_data; + aiov.iov_len = bp->b_bcount; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = dbtob(bn); + auio.uio_segflg = UIO_SYSSPACE; + if( bp->b_flags & B_READ) + auio.uio_rw = UIO_READ; + else + auio.uio_rw = UIO_WRITE; + auio.uio_resid = bp->b_bcount; + auio.uio_procp = curproc; + if (!VOP_ISLOCKED(vn->sc_vp)) { + isvplocked = 1; + vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc); + } + if( bp->b_flags & B_READ) + error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred); + else + error = VOP_WRITE(vn->sc_vp, &auio, 0, vn->sc_cred); + if (isvplocked) { + VOP_UNLOCK(vn->sc_vp, 0, curproc); + isvplocked = 0; + } + bp->b_resid = auio.uio_resid; + + if( error ) + bp->b_flags |= B_ERROR; + biodone(bp); + } else { + long bsize, resid; + off_t byten; + int flags; + caddr_t addr; + struct buf *nbp; + + nbp = getvnbuf(); + byten = dbtob(bn); + /* This is probably the only time this is RIGHT */ + bsize = vn->sc_vp->v_mount->mnt_stat.f_iosize; + addr = bp->b_data; + flags = bp->b_flags | B_CALL; + for (resid = bp->b_resid; resid; ) { + struct vnode *vp; + daddr_t nbn; + int off, s, nra; + + nra = 0; + if (!VOP_ISLOCKED(vn->sc_vp)) { + isvplocked = 1; + vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc); + } + error = VOP_BMAP(vn->sc_vp, (daddr_t)(byten / bsize), + &vp, &nbn, &nra, NULL); + if (isvplocked) { + VOP_UNLOCK(vn->sc_vp, 0, curproc); + isvplocked = 0; + } + if (error == 0 && nbn == -1) + error = EIO; + + IFOPT(vn, VN_DONTCLUSTER) + nra = 0; + + off = byten % bsize; + if (off) + sz = bsize - off; + else + sz = (1 + nra) * bsize; + if (resid < sz) + sz = resid; + + if (error) { + bp->b_resid -= (resid - sz); + bp->b_flags |= B_ERROR; + biodone(bp); + putvnbuf(nbp); + return; + } + + IFOPT(vn,VN_IO) + printf( + /* XXX no %qx in kernel. Synthesize it. */ + "vnstrategy: vp %p/%p bn 0x%lx%08lx/0x%lx sz 0x%x\n", + vn->sc_vp, vp, (long)(byten >> 32), + (u_long)byten, nbn, sz); + + nbp->b_flags = flags; + nbp->b_bcount = sz; + nbp->b_bufsize = sz; + nbp->b_error = 0; + if (vp->v_type == VBLK || vp->v_type == VCHR) + nbp->b_dev = vp->v_rdev; + else + nbp->b_dev = NODEV; + nbp->b_data = addr; + nbp->b_blkno = nbn + btodb(off); + nbp->b_proc = bp->b_proc; + nbp->b_iodone = vniodone; + nbp->b_vp = vp; + nbp->b_rcred = vn->sc_cred; /* XXX crdup? */ + nbp->b_wcred = vn->sc_cred; /* XXX crdup? */ + nbp->b_dirtyoff = bp->b_dirtyoff; + nbp->b_dirtyend = bp->b_dirtyend; + nbp->b_validoff = bp->b_validoff; + nbp->b_validend = bp->b_validend; + + if ((nbp->b_flags & B_READ) == 0) + nbp->b_vp->v_numoutput++; + + VOP_STRATEGY(nbp); + + s = splbio(); + while ((nbp->b_flags & B_DONE) == 0) { + nbp->b_flags |= B_WANTED; + tsleep(nbp, PRIBIO, "vnwait", 0); + } + splx(s); + + if( nbp->b_flags & B_ERROR) { + bp->b_flags |= B_ERROR; + bp->b_resid -= (resid - sz); + biodone(bp); + putvnbuf(nbp); + return; + } + + byten += sz; + addr += sz; + resid -= sz; + } + biodone(bp); + putvnbuf(nbp); + } +} +#endif /* SLICE */ + void vniodone( struct buf *bp) { bp->b_flags |= B_DONE; @@ -409,6 +603,9 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) struct nameidata nd; int error; u_long *f; +#ifdef SLICE + sh_p tp; +#endif IFOPT(vn,VN_FOLLOW) @@ -424,6 +621,7 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case VNIOCUCLEAR: goto vn_specific; } +#ifndef SLICE IFOPT(vn,VN_LABELS) { if (vn->sc_slices != NULL) { @@ -438,6 +636,7 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) return (ENOTTY); } +#endif vn_specific: error = suser(p->p_ucred, &p->p_acflag); @@ -477,6 +676,28 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) } vio->vn_size = dbtob(vn->sc_size); vn->sc_flags |= VNF_INITED; +#ifdef SLICE +/* + * XXX The filesystem blocksize will say 1024 + * for a 8K filesystem. don't know yet how to deal with this, + * so lie for now.. say 512. + */ +#if 0 + vn->limit.blksize = vn->sc_vp->v_mount->mnt_stat.f_bsize; +#else + vn->limit.blksize = DEV_BSIZE; +#endif + vn->slice->limits.blksize = vn->limit.blksize; + vn->limit.slicesize = vattr.va_size; + vn->slice->limits.slicesize = vattr.va_size; + /* + * We have a media to read/write. + * Try identify it. + */ + if ((tp = slice_probeall(vn->slice)) != NULL) { + (*tp->constructor)(vn->slice); + } +#else IFOPT(vn, VN_LABELS) { /* * Reopen so that `ds' knows which devices are open. @@ -489,6 +710,7 @@ vnioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) if (error) vnclear(vn); } +#endif IFOPT(vn, VN_FOLLOW) printf("vnioctl: SET vp %p size %x\n", vn->sc_vp, vn->sc_size); @@ -588,6 +810,14 @@ vnclear(struct vn_softc *vn) IFOPT(vn, VN_FOLLOW) printf("vnclear(%p): vp=%p\n", vn, vp); +#ifdef SLICE + if (vn->slice->handler_up) { + (*(vn->slice->handler_up->revoke)) (vn->slice->private_up); + } +#else /* SLICE */ + if (vn->sc_slices != NULL) + dsgone(&vn->sc_slices); +#endif vn->sc_flags &= ~VNF_INITED; if (vp == (struct vnode *)0) panic("vnclear: null vp"); @@ -596,10 +826,9 @@ vnclear(struct vn_softc *vn) vn->sc_vp = (struct vnode *)0; vn->sc_cred = (struct ucred *)0; vn->sc_size = 0; - if (vn->sc_slices != NULL) - dsgone(&vn->sc_slices); } +#ifndef SLICE static int vnsize(dev_t dev) { @@ -617,44 +846,94 @@ vndump(dev_t dev) return (ENODEV); } -static int vn_devsw_installed; +static vn_devsw_installed = 0; +#endif /* !SLICE */ static void vn_drvinit(void *unused) { -#ifdef DEVFS - int mynor; - int unit; - struct vn_softc *vn; -#endif - +#ifndef SLICE if( ! vn_devsw_installed ) { if (at_shutdown(&vnshutdown, NULL, SHUTDOWN_POST_SYNC)) { printf("vn: could not install shutdown hook\n"); return; } bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &vn_bdevsw); -#ifdef DEVFS - for (unit = 0; unit < NVN; unit++) { - vn = vn_softc[unit]; - mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); - /* - * XXX not saving tokens yet. The vn devices don't - * exist until after they have been opened :-). - */ - devfs_add_devswf(&vn_bdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "vn%d", unit); - devfs_add_devswf(&vn_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rvn%d", unit); - } -#endif vn_devsw_installed = 1; } +#else /* SLICE */ + int mynor; + int unit; + struct vn_softc *vn; + char namebuf[64]; + if (at_shutdown(&vnshutdown, NULL, SHUTDOWN_POST_SYNC)) { + printf("vn: could not install shutdown hook\n"); + return; + } + for (unit = 0; unit < NVN; unit++) { + vn = malloc(sizeof *vn, M_DEVBUF, M_NOWAIT); + if (!vn) + return; + bzero(vn, sizeof *vn); + vn_softc[unit] = vn; + vn->unit = unit; + sprintf(namebuf,"vn%d",vn->unit); + vn->mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, + RAW_PART); + vn->limit.blksize = DEV_BSIZE; + vn->limit.slicesize = ((u_int64_t)vn->sc_size * DEV_BSIZE); + sl_make_slice(&slicetype, + vn, + &vn->limit, + &vn->slice, + NULL, + namebuf); + /* Allow full probing */ + vn->slice->probeinfo.typespecific = NULL; + vn->slice->probeinfo.type = NULL; + } +#define CDEV_MAJOR 20 /* not really needed */ +#endif /* SLICE */ } SYSINIT(vndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,vn_drvinit,NULL) +#ifdef SLICE + +static int +nvsopen(void *private, int flags, int mode, struct proc *p) +{ + struct vn_softc *vn; + + vn = private; + + IFOPT(vn, VN_FOLLOW) + printf("vnopen(0x%lx, 0x%x, 0x%x, %p)\n", + makedev(0,vn->mynor) , flags, mode, p); + return (0); +} +static void +nvsclose(void *private, int flags, int mode, struct proc *p) +{ + struct vn_softc *vn; + + vn = private; + IFOPT(vn, VN_FOLLOW) + printf("vnclose(0x%lx, 0x%x, 0x%x, %p)\n", + makedev(0,vn->mynor) , flags, mode, p); + return; +} + +static int +nvsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + struct vn_softc *vn; + + vn = private; + + return(vnioctl(makedev(0,vn->mynor), cmd, addr, flag, p)); +} + +#endif #endif diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index 1431b19..c4a4a57 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 - * $Id: cd9660_vfsops.c,v 1.34 1998/03/01 22:46:00 msmith Exp $ + * $Id: cd9660_vfsops.c,v 1.35 1998/03/08 09:56:41 julian Exp $ */ #include <sys/param.h> @@ -143,6 +143,9 @@ iso_get_ssector(dev, p) return ntohl(t.entry.addr.lba); } +#ifdef SLICE +extern struct vnode *root_device_vnode; +#endif static int iso_mountroot(mp, p) @@ -152,10 +155,18 @@ iso_mountroot(mp, p) struct iso_args args; int error; +#ifdef SLICE + rootvp = root_device_vnode; + if (rootvp == NULL) { + printf("cd9660_mountroot: rootvp not set"); + return (EINVAL); + } +#else if ((error = bdevvp(rootdev, &rootvp))) { printf("iso_mountroot: can't find rootvp"); return (error); } +#endif args.flags = ISOFSMNT_ROOT; args.ssector = iso_get_ssector(rootdev, p); if (bootverbose) diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 666322f..82f001d 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.59 1998/03/08 08:46:18 dyson Exp $ + * $Id: spec_vnops.c,v 1.60 1998/03/08 09:57:36 julian Exp $ */ #include <sys/param.h> @@ -761,8 +761,15 @@ spec_getpages(ap) * Round up physical size for real devices, use the * fundamental blocksize of the fs if possible. */ - if (vp && vp->v_mount) + if (vp && vp->v_mount) { + if (vp->v_type != VBLK) { + vprint("Non VBLK", vp); + } blksiz = vp->v_mount->mnt_stat.f_bsize; + if (blksiz < DEV_BSIZE) { + blksiz = DEV_BSIZE; + } + } else blksiz = DEV_BSIZE; size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 21bf3c4..b41d6ac 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.424 1998/04/09 22:28:57 sos Exp $ +# $Id: LINT,v 1.425 1998/04/18 04:58:00 ahasty Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -470,8 +470,10 @@ options UNION #Union filesystem options "CD9660_ROOT" #CD-ROM usable as root device options FFS_ROOT #FFS usable as root device options NFS_ROOT #NFS usable as root device -# This DEVFS is experimental but seems to work +# DEVFS and SLICE are experimental but seems to work. +# SLICE disables too much old code so enabling it in LINT would be bad options DEVFS #devices filesystem +#options SLICE #devfs based disk handling # Allow the FFS to use Softupdates technology. # To do this you need to fetch the two files diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 21bf3c4..b41d6ac 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.424 1998/04/09 22:28:57 sos Exp $ +# $Id: LINT,v 1.425 1998/04/18 04:58:00 ahasty Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -470,8 +470,10 @@ options UNION #Union filesystem options "CD9660_ROOT" #CD-ROM usable as root device options FFS_ROOT #FFS usable as root device options NFS_ROOT #NFS usable as root device -# This DEVFS is experimental but seems to work +# DEVFS and SLICE are experimental but seems to work. +# SLICE disables too much old code so enabling it in LINT would be bad options DEVFS #devices filesystem +#options SLICE #devfs based disk handling # Allow the FFS to use Softupdates technology. # To do this you need to fetch the two files diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index a08df9d..f0a9e71 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.195 1998/03/23 16:44:22 peter Exp $ +# $Id: files.i386,v 1.196 1998/04/06 15:49:35 peter Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -36,6 +36,7 @@ i386/eisa/eisaconf.c optional eisa i386/eisa/if_vx_eisa.c optional vx device-driver i386/eisa/if_fea.c optional fea device-driver i386/i386/autoconf.c standard device-driver +i386/i386/mountroot.c optional slice i386/i386/bios.c standard i386/i386/bioscall.s standard i386/i386/busdma_machdep.c standard diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c index 6d96c0c..1aeef1c 100644 --- a/sys/i386/i386/autoconf.c +++ b/sys/i386/i386/autoconf.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 - * $Id: autoconf.c,v 1.91 1998/03/16 12:07:54 msmith Exp $ + * $Id: autoconf.c,v 1.92 1998/03/17 00:28:02 msmith Exp $ */ /* @@ -107,6 +107,7 @@ SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL) static void configure_finish __P((void)); static void configure_start __P((void)); static int setdumpdev __P((dev_t dev)); +#ifndef SLICE static void setroot __P((void)); #ifdef CD9660 @@ -135,6 +136,7 @@ static struct { static int find_cdrom_root __P((void)); + static int find_cdrom_root() { @@ -170,6 +172,7 @@ find_cdrom_root() return EINVAL; } #endif /* CD9660 */ +#endif /* !SLICE */ static void configure_start() @@ -300,6 +303,8 @@ configure(dummy) cold = 0; } +#ifndef SLICE + void cpu_rootconf() { @@ -370,6 +375,24 @@ cpu_rootconf() } #endif +#if defined(LFS) || defined(LFS_ROOT) + if (!mountrootfsname) { + if (bootverbose) + printf("Considering LFS root f/s.\n"); + mountrootfsname = "lfs"; + /* + * Ignore the -a flag if this kernel isn't compiled + * with a generic root/swap configuration: if we skip + * setroot() and we aren't a generic kernel, chaos + * will ensue because setconf() will be a no-op. + * (rootdev is always initialized to NODEV in a + * generic configuration, so we test for that.) + */ + if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) + setroot(); + } +#endif + if (!mountrootfsname) { panic("Nobody wants to mount my root for me"); } @@ -377,6 +400,8 @@ cpu_rootconf() setconf(); } +#endif + void cpu_dumpconf() { @@ -420,6 +445,8 @@ setdumpdev(dev) return (0); } +#ifndef SLICE + u_long bootdev = 0; /* not a dev_t - encoding is different */ /* Name lookup for bootable majors XXX extend me */ @@ -484,6 +511,8 @@ setroot() printf("changing root device to %s%s\n", sname, partname); } +#endif + static int sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS { diff --git a/sys/i386/i386/mountroot.c b/sys/i386/i386/mountroot.c new file mode 100644 index 0000000..4dfbb83 --- /dev/null +++ b/sys/i386/i386/mountroot.c @@ -0,0 +1,359 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + * $Id: autoconf.c,v 1.82 1997/11/21 18:27:08 bde Exp $ + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ +#include "opt_cd9660.h" +#include "opt_ffs.h" +#include "opt_nfs.h" +#include "opt_mfs.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/devfsext.h> +#include <sys/disklabel.h> +#include <sys/reboot.h> +#include <sys/kernel.h> +#include <sys/mount.h> +#include <sys/sysctl.h> +#include <machine/bootinfo.h> +#include <machine/md_var.h> + +u_long bootdev = 0; /* from bootblocks: not dev_t - encoding is different */ +struct vnode *root_device_vnode = NULL; +char root_device_name[64]; + + +/*#include <sys/fcntl.h> +#include <sys/proc.h> +#include <sys/stat.h> +#include <machine/clock.h> */ + +struct major_hack { + int major; + char *name; +} hack_major[] = { +{0, "wd"}, /* ST506 disk controller (with IDE extensions) */ +{2, "fd"}, /* floppy disk */ +{3, "wt"}, /* QIC-02/36 tape */ +{4, "sd"}, /* SCSI "disk" type */ +{5, "st"}, /* SCSI "tape" type */ +{6, "cd"}, /* SCSI "cdrom" type */ +{7, "mcd"}, /* Mitsumi CDROM interface */ +{15, "vn"}, /* vnode disk device */ +{16, "scd"}, /* Sony CDROM interface */ +{17, "matcd"}, /* Matsushita/Panasonic/Creative(SB) CDROM interface */ +{18, "ata"}, /* "device independent" ATA/IDE driver */ +{19, "wcdb"}, /* ATAPI CDROM client of "ata" */ +{20, "od"}, /* SCSI "magneto-optical" disk */ +{21, "ccd"}, /* concatenated disk */ +{22, "gd"}, /* Geometry disk. */ +{23, "worm"}, /* SCSI "worm type" */ +{0, NULL} +}; + +static struct { + char *name; + int major; +} try_cdrom[] = { + { "cd", 6 }, + { "mcd", 7 }, + { "scd", 16 }, + { "matcd", 17 }, + { "wcd", 19 }, + { 0, 0} +}; + +#ifdef CD9660 +/* + * XXX All this CD-ROM root stuff is fairly messy. Ick. + * We need to look for a cdrom that we can open. + * Of course we don't KNOW which, so just try them all in + * an arbitrary order. + * If we find one, we open it and put it's vnode into the right place. + * (and the name) + */ +static int +find_cdrom_root(void) +{ + int i, j, error; + struct bdevsw *bd; + char buf[32]; + struct vnode *vn; + +#if CD9660_ROOTDELAY > 0 + DELAY(CD9660_ROOTDELAY * 1000000); +#endif + for (i = 0 ; i < 2; i++) { + for (j = 0 ; try_cdrom[j].name ; j++) { + if (try_cdrom[j].major >= nblkdev) + continue; + /*if (bootverbose)*/ + printf("trying %s%d as rootdev\n", + try_cdrom[j].name, i); + sprintf(buf, "\%s%d", try_cdrom[j].name, i); + vn = devfs_open_device(buf, DV_BLK); + if (vn) { + root_device_vnode = vn; + strcpy(root_device_name, buf); + rootdev = makedev(try_cdrom[j].major, i * 8); + return 0; + } + } + } + return EINVAL; +} +#endif /* CD9660 */ + + +/* + * Open a standard 386BSD compatible disk, according to the + * old rules (sd0a is the a part of the first BSD slice on sd0.) + */ +static int +open_root_by_major(dev_t dev) +{ + /* + * given a dev_t (from god-only knows where) + * turn it into a sane device name. + */ + int maj = major(dev); + int min = minor(dev); + int unit = (min >> 3) & 0x0f; + int part = (min & 0x07); + int i = 0; + struct major_hack *mp; + struct vnode *vn; + char buf[32]; + + mp = hack_major; + while (mp->name) { + if ( mp->major == maj) + break; + mp++; + } + if (mp->name == NULL) { + return (EINVAL); + } + + /* try see if we have old style partitions */ + sprintf(buf,"/%s%d%c", mp->name, unit, 'a'+ part); + printf ("WOULD SELECT %s ", buf); + if ((vn = devfs_open_device(buf, DV_BLK))) { + printf("And it exists\n"); + } else { + printf("but it doesn't exist\n"); + for ( i = 1; i < 5; i++ ) { + sprintf(buf,"/%s%ds%d%c", mp->name, unit, i, 'a'+ part); + if ((vn = devfs_open_device(buf, DV_BLK))) { + printf("%s exists, I'll use that\n", buf); + break; + } else { + printf ("%s didn't work\n", buf); + } + } + if (i == 5) { + return (EINVAL); + } + } + if (vn) { + root_device_vnode = vn; + strcpy(root_device_name, buf); + rootdev = devfs_vntodev(vn); + return (0); + } + return (EINVAL); +} + +/* + * Attempt to find the device from which we were booted. + * If we can do so, and not instructed not to do so, + * change rootdev to correspond to the load device. + */ +static void +setroot(void) +{ + int majdev, mindev, unit, part, adaptor; + dev_t newrootdev; + struct vnode *vn; + char buf[32]; + +/*printf("howto %x bootdev %x ", boothowto, bootdev);*/ + /* + * If bootdev is screwy, just open the default device + * that was compiled in. + */ + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) { + open_root_by_major(rootdev); + return; + } + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + + /* + * We have two choices.. do it by hand + * or use the major/minor we were given + */ + switch (majdev) { + case 2: /*fd*/ + sprintf(buf,"/fd%d", unit); + if ((vn = devfs_open_device(buf, DV_BLK))) { + root_device_vnode = vn; + strcpy(root_device_name, buf); + rootdev = devfs_vntodev(vn); + } + break; + case 0: /*wd*/ + case 4: /*sd*/ + newrootdev = makedev(majdev,(unit * 8)+part); + open_root_by_major(newrootdev); + break; + default: /* try something different.. you never know.. */ + open_root_by_major(rootdev); + return; + } + if ( root_device_vnode == NULL) { + panic("can't mount root"); + } +} + +void +cpu_rootconf() +{ + /* + * XXX NetBSD has a much cleaner approach to finding root. + * XXX We should adopt their code. + */ +#ifdef CD9660 + if ((boothowto & RB_CDROM)) { + if (bootverbose) + printf("Considering CD-ROM root f/s.\n"); + /* NB: find_cdrom_root() sets rootdev if successful. */ + if (find_cdrom_root() == 0) + mountrootfsname = "cd9660"; + else if (bootverbose) + printf("No CD-ROM available as root f/s.\n"); + } +#endif /* CD9660 */ + +#ifdef MFS_ROOT + if (!mountrootfsname) { + if (bootverbose) + printf("Considering MFS root f/s.\n"); + mountrootfsname = "mfs"; + /* + * Ignore the -a flag if this kernel isn't compiled + * with a generic root/swap configuration: if we skip + * setroot() and we aren't a generic kernel, chaos + * will ensue because setconf() will be a no-op. + * (rootdev is always initialized to NODEV in a + * generic configuration, so we test for that.) + */ + if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) + setroot(); + } +#endif + +#ifdef BOOTP_NFSROOT + if (!mountrootfsname && !nfs_diskless_valid) { + if (bootverbose) + printf("Considering BOOTP NFS root f/s.\n"); + mountrootfsname = "nfs"; + } +#endif /* BOOTP_NFSROOT */ +#ifdef NFS + if (!mountrootfsname && nfs_diskless_valid) { + if (bootverbose) + printf("Considering NFS root f/s.\n"); + mountrootfsname = "nfs"; + } +#endif /* NFS */ + +#ifdef FFS + if (!mountrootfsname) { + mountrootfsname = "ufs"; + if (bootverbose) + printf("Considering FFS root f/s.\n"); + /* + * Ignore the -a flag if this kernel isn't compiled + * with a generic root/swap configuration: if we skip + * setroot() and we aren't a generic kernel, chaos + * will ensue because setconf() will be a no-op. + * (rootdev is always initialized to NODEV in a + * generic configuration, so we test for that.) + */ + if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) + setroot(); + } +#endif + +#ifdef LFS + if (!mountrootfsname) { + if (bootverbose) + printf("Considering LFS root f/s.\n"); + mountrootfsname = "lfs"; + /* + * Ignore the -a flag if this kernel isn't compiled + * with a generic root/swap configuration: if we skip + * setroot() and we aren't a generic kernel, chaos + * will ensue because setconf() will be a no-op. + * (rootdev is always initialized to NODEV in a + * generic configuration, so we test for that.) + */ + if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) + setroot(); + } +#endif + + if (!mountrootfsname) { + panic("Nobody wants to mount my root for me"); + } + + setconf(); +} + diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c index d09b927..abc2634 100644 --- a/sys/i386/isa/fd.c +++ b/sys/i386/isa/fd.c @@ -43,7 +43,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.107 1998/01/24 02:54:18 eivind Exp $ + * $Id: fd.c,v 1.108 1998/04/17 22:36:31 des Exp $ * */ @@ -82,9 +82,13 @@ #include <sys/ftape.h> #include <i386/isa/ftreg.h> #endif -#ifdef DEVFS +#ifdef DEVFS #include <sys/devfsext.h> -#endif +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#endif /* SLICE */ +#endif /* DEVFS */ /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX @@ -180,8 +184,21 @@ static struct fd_data { struct callout_handle toffhandle; struct callout_handle tohandle; #ifdef DEVFS +#ifdef SLICE + int unit; /* as in fd0 */ + void *bdevs[MAXPARTITIONS]; + void *cdevs[MAXPARTITIONS]; + struct subdev{ + struct slice *slice; + int minor; + struct fd_data *drive; + struct slicelimits limit; + }subdevs[16]; + struct intr_config_hook ich; +#else /* SLICE */ void *bdevs[1 + NUMDENS + MAXPARTITIONS]; void *cdevs[1 + NUMDENS + MAXPARTITIONS]; +#endif /* SLICE */ #endif } fd_data[NFD]; @@ -227,7 +244,9 @@ static timeout_t fd_timeout; static timeout_t fd_pseudointr; static int fdstate(fdcu_t, fdc_p); static int retrier(fdcu_t); +#ifndef SLICE static int fdformat(dev_t, struct fd_formb *, struct proc *); +#endif static int enable_fifo(fdc_p fdc); @@ -284,6 +303,7 @@ static d_close_t fdclose; static d_ioctl_t fdioctl; static d_strategy_t fdstrategy; +/* even if SLICE defined, these are needed for the ft support. */ #define CDEV_MAJOR 9 #define BDEV_MAJOR 2 static struct cdevsw fd_cdevsw; @@ -294,6 +314,30 @@ static struct bdevsw fd_bdevsw = static struct isa_device *fdcdevs[NFDC]; +#ifdef SLICE +static sl_h_IO_req_t fdsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t fdsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t fdsopen; /* downwards travelling open */ +static sl_h_close_t fdsclose; /* downwards travelling close */ +static void fdsinit(void *); + +static struct slice_handler slicetype = { + "floppy", + 0, + NULL, + 0, + NULL, /* constructor */ + &fdsIOreq, + &fdsioctl, + &fdsopen, + &fdsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif /* SLICE */ + static int fdc_err(fdcu_t fdcu, const char *s) { @@ -529,8 +573,12 @@ fdattach(struct isa_device *dev) struct isa_device *fdup; int ic_type = 0; #ifdef DEVFS +#ifdef SLICE + char namebuf[64]; +#else int mynor; int typemynor; +#endif /* SLICE */ int typesize; #endif @@ -682,6 +730,9 @@ fdattach(struct isa_device *dev) continue; fd->track = FD_NO_TRACK; +#ifdef SLICE + fd->unit = fdu; +#endif fd->fdc = fdc; fd->fdsu = fdsu; fd->options = 0; @@ -721,6 +772,30 @@ fdattach(struct isa_device *dev) continue; } #ifdef DEVFS +#ifdef SLICE + sprintf(namebuf,"fd%d",fdu); + fd->subdevs[0].minor = 0; + fd->subdevs[0].drive = fd; + fd->subdevs[0].limit.blksize = + 128 << (fd_types[fd->type - 1].secsize); + fd->subdevs[0].limit.slicesize = + fd_types[fd->type - 1].size + * fd->subdevs[0].limit.blksize; + fd->ft = fd_types + (fd->type - 1); /* default value */ + sl_make_slice(&slicetype, + &fd->subdevs[0], + &fd->subdevs[0].limit, + &fd->subdevs[0].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[0].slice->probeinfo.typespecific = NULL; + fd->subdevs[0].slice->probeinfo.type = NULL; + + fd->ich.ich_func = fdsinit; + fd->ich.ich_arg = &fd->subdevs[0]; + config_intrhook_establish(&fd->ich); +#else /* SLICE */ mynor = fdu << 6; fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -728,6 +803,7 @@ fdattach(struct isa_device *dev) fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fdu); +#endif /* SLICE */ for (i = 1; i < 1 + NUMDENS; i++) { /* * XXX this and the lookup in Fdopen() should be @@ -755,7 +831,6 @@ fdattach(struct isa_device *dev) continue; break; } - typemynor = mynor | i; typesize = fd_types[i - 1].size / 2; /* * XXX all these conversions give bloated code and @@ -765,6 +840,27 @@ fdattach(struct isa_device *dev) typesize = 1480; if (typesize == 1722) typesize = 1720; +#ifdef SLICE + sprintf(namebuf,"fd%d.%d",fdu,typesize); + fd->subdevs[i].minor = i; + fd->subdevs[i].drive = fd; + fd->subdevs[i].limit.blksize = + 128 << (fd_types[i - 1].secsize); + fd->subdevs[i].limit.slicesize = + fd_types[i - 1].size + * fd->subdevs[i].limit.blksize; + sl_make_slice(&slicetype, + &fd->subdevs[i], + &fd->subdevs[i].limit, + &fd->subdevs[i].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[i].slice->probeinfo.typespecific = NULL; + fd->subdevs[i].slice->probeinfo.type = NO_SUBPART; + } +#else /* SLICE */ + typemynor = mynor | i; fd->bdevs[i] = devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -774,14 +870,15 @@ fdattach(struct isa_device *dev) UID_ROOT, GID_OPERATOR, 0640, "rfd%d.%d", fdu, typesize); } + for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = - devfs_link(fd->bdevs[0], + fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0], "fd%d%c", fdu, 'a' + i); fd->cdevs[1 + NUMDENS + i] = devfs_link(fd->cdevs[0], "rfd%d%c", fdu, 'a' + i); } +#endif /* SLICE */ #endif /* DEVFS */ #ifdef notyet if (dk_ndrive < DK_NDRIVE) { @@ -800,6 +897,22 @@ fdattach(struct isa_device *dev) return (1); } + +#ifdef SLICE + +static void +fdsinit(void *arg) +{ + struct subdev *sd = arg; + sh_p tp; + + if ((tp = slice_probeall(sd->slice)) != NULL) { + (*tp->constructor)(sd->slice); + } + config_intrhook_disestablish(&sd->drive->ich); +} +#endif /* SLICE */ + /****************************************************************************/ /* motor control stuff */ /* remember to not deselect the drive we're working on */ @@ -1022,6 +1135,10 @@ Fdopen(dev_t dev, int flags, int mode, struct proc *p) if (type == 0) type = fd_data[fdu].type; else { + /* + * For each type of basic drive, make sure we are trying + * to open a type it can do, + */ if (type != fd_data[fdu].type) { switch (fd_data[fdu].type) { case FD_360: @@ -1182,6 +1299,49 @@ bad: biodone(bp); } +#ifdef SLICE +/****************************************************************************/ +/* fdsIOreq */ +/****************************************************************************/ +static void +fdsIOreq(void *private ,struct buf *bp) +{ + unsigned nblocks, blknum, cando; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + size_t fdblk; + struct subdev *sd; + + sd = private; + fd = sd->drive; + fdu = fd->unit; + fdc = fd->fdc; + fdcu = fdc->fdcu; + + /* check for controller already busy with tape */ + if (fdc->flags & FDC_TAPE_BUSY) { + bp->b_error = EBUSY; + bp->b_flags |= B_ERROR; + goto bad; + } + bp->b_driver1 = sd; /* squirrel away which device.. */ + bp->b_resid = 0; + s = splbio(); + bufqdisksort(&fdc->head, bp); + untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); + return; +} +#endif /* SLICE */ + /***************************************************************\ * fdstart * * We have just queued something.. if the controller is not busy * @@ -1292,6 +1452,7 @@ fdintr(fdcu_t fdcu) static int fdstate(fdcu_t fdcu, fdc_p fdc) { + struct subdev *sd; int read, format, head, sec = 0, sectrac, st0, cyl, st3; unsigned blknum = 0, b_cylinder = 0; fdu_t fdu = fdc->fdu; @@ -1317,8 +1478,14 @@ fdstate(fdcu_t fdcu, fdc_p fdc) TRACE1("[fdc%d IDLE]", fdcu); return(0); } +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; +#else fdu = FDUNIT(minor(bp->b_dev)); fd = fd_data + fdu; +#endif fdblk = 128 << fd->ft->secsize; if (fdc->fd && (fd != fdc->fd)) { @@ -1332,7 +1499,7 @@ fdstate(fdcu_t fdcu, fdc_p fdc) - (char *)finfo; } if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { - blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk + + blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + fd->skip/fdblk; b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); } @@ -1704,13 +1871,26 @@ static int retrier(fdcu) fdcu_t fdcu; { + struct subdev *sd; fdc_p fdc = fdc_data + fdcu; register struct buf *bp; +#ifdef SLICE + struct fd_data *fd; + int fdu; +#endif bp = bufq_first(&fdc->head); +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; + if(fd->options & FDOPT_NORETRY) + goto fail; +#else if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) goto fail; +#endif switch(fdc->retry) { case 0: case 1: case 2: @@ -1727,14 +1907,19 @@ retrier(fdcu) default: fail: { +#ifdef SLICE + printf("fd%d: hard error, block %d ", fdu, + fd->skip / DEV_BSIZE); +#else dev_t sav_b_dev = bp->b_dev; /* Trick diskerr */ bp->b_dev = makedev(major(bp->b_dev), - (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); + (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); diskerr(bp, "fd", "hard error", LOG_PRINTF, fdc->fd->skip / DEV_BSIZE, (struct disklabel *)NULL); bp->b_dev = sav_b_dev; +#endif /* !SLICE */ if (fdc->flags & FDC_STAT_VALID) { printf( @@ -1764,11 +1949,16 @@ retrier(fdcu) return(1); } +#ifdef SLICE +static int +fdformat( struct subdev *sd, struct fd_formb *finfo, struct proc *p) +#else /* !SLICE */ static int fdformat(dev, finfo, p) dev_t dev; struct fd_formb *finfo; struct proc *p; +#endif /* !SLICE */ { fdu_t fdu; fd_p fd; @@ -1777,8 +1967,13 @@ fdformat(dev, finfo, p) int rv = 0, s; size_t fdblk; - fdu = FDUNIT(minor(dev)); - fd = &fd_data[fdu]; +#ifdef SLICE + fd = sd->drive; + fdu = fd->unit; +#else + fdu = FDUNIT(minor(dev)); + fd = &fd_data[fdu]; +#endif fdblk = 128 << fd->ft->secsize; /* set up a buffer header for fdstrategy() */ @@ -1792,7 +1987,6 @@ fdformat(dev, finfo, p) bzero((void *)bp, sizeof(struct buf)); bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; bp->b_proc = p; - bp->b_dev = dev; /* * calculate a fake blkno, so fdstrategy() would initiate a @@ -1805,7 +1999,13 @@ fdformat(dev, finfo, p) bp->b_data = (caddr_t)finfo; /* now do the format */ +#ifdef SLICE + bp->b_driver1 = sd; + fdsIOreq(sd, bp); +#else /* !SLICE */ + bp->b_dev = dev; fdstrategy(bp); +#endif /* !SLICE */ /* ...and wait for it to complete */ s = splbio(); @@ -1836,7 +2036,7 @@ fdformat(dev, finfo, p) * TODO: don't allocate buffer on stack. */ -int +static int fdioctl(dev, cmd, addr, flag, p) dev_t dev; int cmd; @@ -1861,10 +2061,33 @@ fdioctl(dev, cmd, addr, flag, p) return ftioctl(dev, cmd, addr, flag, p); #endif +#ifdef SLICE + /* + * if SLICE is defined then only ft accesses come here + * so break the rest off to another function for SLICE access. + */ + return (ENOTTY); +} + +/* + * Slice ioctls come here + */ +static int +fdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + struct subdev *sd = private; + fd_p fd = sd->drive; + fdu_t fdu = fd->unit; + fdc_p fdc = fd->fdc; + fdcu_t fdcu = fdc->fdcu; + size_t fdblk; + int error = 0; +#endif /* SLICE */ fdblk = 128 << fd->ft->secsize; switch (cmd) { +#ifndef SLICE case DIOCGDINFO: bzero(buffer, sizeof (buffer)); dl = (struct disklabel *)buffer; @@ -1908,7 +2131,7 @@ fdioctl(dev, cmd, addr, flag, p) error = writedisklabel(dev, fdstrategy, (struct disklabel *)buffer); break; - +#endif /* !SLICE */ case FD_FORM: if((flag & FWRITE) == 0) error = EBADF; /* must be opened for writing */ @@ -1916,26 +2139,30 @@ fdioctl(dev, cmd, addr, flag, p) FD_FORMAT_VERSION) error = EINVAL; /* wrong version of formatting prog */ else +#ifdef SLICE + error = fdformat(sd, (struct fd_formb *)addr, p); +#else error = fdformat(dev, (struct fd_formb *)addr, p); +#endif break; case FD_GTYPE: /* get drive type */ - *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; + *(struct fd_type *)addr = *fd->ft; break; case FD_STYPE: /* set drive type */ /* this is considered harmful; only allow for superuser */ if(suser(p->p_ucred, &p->p_acflag) != 0) return EPERM; - *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; + *fd->ft = *(struct fd_type *)addr; break; case FD_GOPTS: /* get drive options */ - *(int *)addr = fd_data[FDUNIT(minor(dev))].options; + *(int *)addr = fd->options; break; case FD_SOPTS: /* set drive options */ - fd_data[FDUNIT(minor(dev))].options = *(int *)addr; + fd->options = *(int *)addr; break; default: @@ -1959,7 +2186,32 @@ static void fd_drvinit(void *notused ) SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) + +#ifdef SLICE +static int +fdsopen(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + return(Fdopen(makedev(0,sd->minor), 0 , 0, p)); +} + +static void +fdsclose(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + fdclose(makedev(0,sd->minor), 0 , 0, p); + return ; +} + +#endif /* SLICE */ #endif + /* * Hello emacs, these are the * Local Variables: diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 26b3832..92a6a08 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.157 1998/04/18 13:25:49 obrien Exp $ + * $Id: wd.c,v 1.158 1998/04/19 03:26:05 peter Exp $ */ /* TODO: @@ -80,7 +80,12 @@ #include <sys/buf.h> #include <sys/malloc.h> #ifdef DEVFS +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#else #include <sys/devfsext.h> +#endif /*SLICE*/ #endif /*DEVFS*/ #include <machine/bootinfo.h> #include <machine/clock.h> @@ -170,9 +175,16 @@ struct disk { int dk_port; /* i/o port base */ int dk_altport; /* altstatus port base */ #ifdef DEVFS +#ifdef SLICE + struct slice *slice; + int minor; + struct slicelimits limit; + struct intr_config_hook ich; +#else void *dk_bdev; /* devfs token for whole disk */ void *dk_cdev; /* devfs token for raw whole disk */ -#endif +#endif /* SLICE */ +#endif /* DEVFS */ u_long cfg_flags; /* configured characteristics */ short dk_flags; /* drive characteristics found */ #define DKFL_SINGLE 0x00004 /* sector at a time mode */ @@ -243,6 +255,33 @@ struct isa_driver wdcdriver = { wdprobe, wdattach, "wdc", }; +#ifdef SLICE + +static sl_h_IO_req_t wdsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t wdsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t wdsopen; /* downwards travelling open */ +static sl_h_close_t wdsclose; /* downwards travelling close */ +static void wds_init(void*); + +static struct slice_handler slicetype = { + "IDE", + 0, + NULL, + 0, + NULL, /* constructor */ + &wdsIOreq, + &wdsioctl, + &wdsopen, + &wdsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif + +#ifndef SLICE + static d_open_t wdopen; static d_close_t wdclose; static d_strategy_t wdstrategy; @@ -256,6 +295,7 @@ static struct cdevsw wd_cdevsw; static struct bdevsw wd_bdevsw = { wdopen, wdclose, wdstrategy, wdioctl, /*0*/ wddump, wdsize, D_DISK, "wd", &wd_cdevsw, -1 }; +#endif /* !SLICE */ #ifdef CMD640 static int atapictrlr; @@ -404,7 +444,7 @@ nodevice: static int wdattach(struct isa_device *dvp) { -#ifdef DEVFS +#if defined(DEVFS) && ! defined(SLICE) int mynor; #endif int unit, lunit; @@ -485,12 +525,18 @@ wdattach(struct isa_device *dvp) if (du->cfg_flags & WDOPT_SLEEPHACK) printf(", sleep-hack"); printf("\n"); +#ifdef SLICE +/* + * Here we somehow schedule the geometry HACK fro later and print + * something meaningful. + */ +#endif if (du->dk_params.wdp_heads == 0) printf("wd%d: size unknown, using %s values\n", lunit, du->dk_dd.d_secperunit > 17 ? "BIOS" : "fake"); - printf( -"wd%d: %luMB (%lu sectors), %lu cyls, %lu heads, %lu S/T, %lu B/S\n", + printf( "wd%d: %luMB (%lu sectors), " + "%lu cyls, %lu heads, %lu S/T, %lu B/S\n", lunit, du->dk_dd.d_secperunit / ((1024L * 1024L) / du->dk_dd.d_secsize), @@ -502,8 +548,9 @@ wdattach(struct isa_device *dvp) if (bootverbose) { wp = &du->dk_params; - printf( -"wd%d: ATA INQUIRE valid = %04x, dmamword = %04x, apio = %04x, udma = %04x\n", + printf( "wd%d: ATA INQUIRE valid = %04x, " + "dmamword = %04x, apio = %04x, " + "udma = %04x\n", du->dk_lunit, wp->wdp_atavalid, wp->wdp_dmamword, @@ -518,6 +565,36 @@ wdattach(struct isa_device *dvp) wdtimeout(du); #ifdef DEVFS +#ifdef SLICE + { + char namebuf[64]; + sprintf(namebuf,"wd%d",lunit); + du->minor = dkmakeminor(lunit, + WHOLE_DISK_SLICE, RAW_PART); + du->limit.blksize = du->dk_dd.d_secsize; + du->limit.slicesize = + (u_int64_t)du->dk_dd.d_secsize * + du->dk_dd.d_secperunit; + /* + * Fill in the 3 geometry entries + * to tell the mbr code + * we already know it, so that it + * doesn't try deduce it. + */ + sl_make_slice(&slicetype, + du, + &du->limit, + &du->slice, + NULL, + namebuf); + /* Allow full probing */ + du->slice->probeinfo.typespecific = NULL; + du->slice->probeinfo.type = NULL; + } + du->ich.ich_func = wds_init; + du->ich.ich_arg = du; + config_intrhook_establish(&du->ich); +#else mynor = dkmakeminor(lunit, WHOLE_DISK_SLICE, RAW_PART); du->dk_bdev = devfs_add_devswf(&wd_bdevsw, mynor, DV_BLK, UID_ROOT, @@ -528,6 +605,7 @@ wdattach(struct isa_device *dvp) GID_OPERATOR, 0640, "rwd%d", lunit); #endif +#endif if (dk_ndrive < DK_NDRIVE) { sprintf(dk_names[dk_ndrive], "wd%d", lunit); @@ -583,6 +661,47 @@ next: ; return (1); } +#ifdef SLICE +extern struct proc *curproc; +static void +wds_init(void *arg) +{ + struct disk *du = arg; + sh_p tp; + int err = 0; + struct ide_geom geom; + + if ((err = wdsopen(du, 0, 0, curproc))) { + printf("wd open failed with %d", err); + return; + } + /* + * If we still don't have geometry, + * Then call the IDE geometry HACK functions. + */ +#if 0 + if ( ?? ) { /* how do we know? */ + bzero (&geom, sizeof(geom)); + if (mbr_geom_hack(du->slice)) && (dkl_geom_hack(du->slice)) { + printf("We really have no geometry\n"); + } else { + du->dk_dd.d_secperunit = (geom.cyls * + geom.trackpercyl * geom.secpertrack); + du->dk_dd.d_ncylinders = geom.cyls; + du->dk_dd.d_ntracks = geom.trackpercyl; + du->dk_dd.d_nsectors = geom.secpertrack; + } + } +#endif + if ((tp = slice_probeall(du->slice)) != NULL) { + (*tp->constructor)(du->slice); + } + config_intrhook_disestablish(&du->ich); + wdsclose(du, 0, 0, curproc); +} +#endif + +#ifndef SLICE /* Read/write routine for a buffer. Finds the proper unit, range checks * arguments, and schedules the transfer. Does not wait for the transfer * to complete. Multi-page transfers are supported. All I/O requests must @@ -695,6 +814,7 @@ wdstrategy1(struct buf *bp) */ wdstrategy(bp); } +#endif /* !SLICE */ /* * Routine to queue a command to the controller. The unit's @@ -720,6 +840,11 @@ wdustart(register struct disk *du) if (bp == NULL) { /* yes, an assign */ return; } + /* + * store away which device we came from. + */ + bp->b_driver1 = du; + bufq_remove(&drive_queue[du->dk_lunit], bp); /* link onto controller queue */ @@ -727,6 +852,7 @@ wdustart(register struct disk *du) /* mark the drive unit as busy */ wdutab[du->dk_lunit].b_active = 1; + } /* @@ -781,8 +907,13 @@ wdstart(int ctrlr) } /* obtain controller and drive information */ +#ifdef SLICE + du = bp->b_driver1; + lunit = du->dk_lunit; +#else /* !SLICE */ lunit = dkunit(bp->b_dev); du = wddrives[lunit]; +#endif /* !SLICE */ /* if not really a transfer, do control operations specially */ if (du->dk_state < OPEN) { @@ -822,6 +953,7 @@ wdstart(int ctrlr) du->dk_flags |= DKFL_SINGLE; } +#ifndef SLICE if (du->dk_flags & DKFL_SINGLE && dsgetbad(bp->b_dev, du->dk_slices) != NULL) { /* XXX */ @@ -831,6 +963,7 @@ wdstart(int ctrlr) blknum = transbad144(dsgetbad(bp->b_dev, du->dk_slices), blknum - ds_offset) + ds_offset; } +#endif wdtab[ctrlr].b_active = 1; /* mark controller active */ @@ -1077,7 +1210,11 @@ wdintr(int unit) } #endif bp = bufq_first(&wdtab[unit].controller_queue); +#ifdef SLICE + du = bp->b_driver1; +#else /* !SLICE */ du = wddrives[dkunit(bp->b_dev)]; +#endif /* !SLICE */ /* finish off DMA */ if (du->dk_flags & (DKFL_DMA|DKFL_USEDMA)) { @@ -1284,6 +1421,7 @@ done: ; wdstart(unit); } +#ifndef SLICE /* * Initialize a drive. */ @@ -1460,6 +1598,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p) return (0); #endif } +#endif /* !SLICE */ /* * Implement operations other than read/write. @@ -1473,7 +1612,11 @@ wdcontrol(register struct buf *bp) register struct disk *du; int ctrlr; +#ifdef SLICE + du = bp->b_driver1; +#else /* !SLICE */ du = wddrives[dkunit(bp->b_dev)]; +#endif /* !SLICE */ #ifdef CMD640 ctrlr = du->dk_ctrlr_cmd640; #else @@ -1953,6 +2096,7 @@ failed: return (0); } +#ifndef SLICE int wdclose(dev_t dev, int flags, int fmt, struct proc *p) { @@ -1974,11 +2118,12 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p) du = wddrives[lunit]; wdsleep(du->dk_ctrlr, "wdioct"); +#ifndef SLICE error = dsioctl("wd", dev, cmd, addr, flags, &du->dk_slices, wdstrategy1, (ds_setgeom_t *)NULL); if (error != ENOIOCTL) return (error); - +#endif /* SLICE */ switch (cmd) { case DIOCSBADSCAN: if (*(int *)addr) @@ -2240,15 +2385,20 @@ out: } return (0); } +#endif /* !SLICE */ static void wderror(struct buf *bp, struct disk *du, char *mesg) { +#ifndef SLICE + printf("wd%d: %s:\n", du->dk_lunit, mesg); +#else /* !SLICE */ if (bp == NULL) printf("wd%d: %s:\n", du->dk_lunit, mesg); else diskerr(bp, "wd", mesg, LOG_PRINTF, du->dk_skip, dsgetlabel(bp->b_dev, du->dk_slices)); +#endif /* !SLICE */ printf("wd%d: status %b error %b\n", du->dk_lunit, du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS); } @@ -2471,6 +2621,7 @@ wdwait(struct disk *du, u_char bits_wanted, int timeout) return (-1); } +#ifndef SLICE static wd_devsw_installed = 0; static void wd_drvinit(void *unused) @@ -2485,6 +2636,128 @@ static void wd_drvinit(void *unused) } SYSINIT(wddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wd_drvinit,NULL) +#endif /* !SLICE */ + + + +#ifdef SLICE +/* + * Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer + * to complete. Multi-page transfers are supported. All I/O requests must + * be a multiple of a sector in length. + */ +static void +wdsIOreq(void *private ,struct buf *bp) +{ + struct disk *du = private; + int s; + int lunit = du->dk_lunit; + + /* queue transfer on drive, activate drive and controller if idle */ + s = splbio(); + + bufqdisksort(&drive_queue[lunit], bp); + + /* + * Move the head of the drive queue to the controller queue. + */ + if (wdutab[lunit].b_active == 0) + wdustart(du); + + /* + * Kick off the controller if there is anything for IT to do. + */ +#ifdef CMD640 + if (wdtab[du->dk_ctrlr_cmd640].b_active == 0) +#else + if (wdtab[du->dk_ctrlr].b_active == 0) +#endif + wdstart(du->dk_ctrlr); /* start controller */ + + splx(s); + return; + +} + +/* + * Initialize a drive. + */ +static int +wdsopen(void *private, int flags, int mode, struct proc *p) +{ + register struct disk *du; + register unsigned int lunit; + int error = 0; + + du = private; + + /* Finish flushing IRQs left over from wdattach(). */ +#ifdef CMD640 + if (wdtab[du->dk_ctrlr_cmd640].b_active == 2) + wdtab[du->dk_ctrlr_cmd640].b_active = 0; +#else + if (wdtab[du->dk_ctrlr].b_active == 2) + wdtab[du->dk_ctrlr].b_active = 0; +#endif + + du->dk_state = OPEN; + du->dk_flags &= ~DKFL_BADSCAN; + + return (error); +} + +static void +wdsclose(void *private, int flags, int mode, struct proc *p) +{ + register struct disk *du; + + du = private; + du->dk_state = CLOSED; + return; +} + +static int +wdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + register struct disk *du; + int error; + du = private; + wdsleep(du->dk_ctrlr, "wdioct"); + switch (cmd) { + case DIOCSBADSCAN: + if (*(int *)addr) + du->dk_flags |= DKFL_BADSCAN; + else + du->dk_flags &= ~DKFL_BADSCAN; + return (0); +#ifdef notyet + case DIOCWFORMAT: + if (!(flag & FWRITE)) + return (EBADF); + fop = (struct format_op *)addr; + aiov.iov_base = fop->df_buf; + aiov.iov_len = fop->df_count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = fop->df_count; + auio.uio_segflg = 0; + auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize; +#error /* XXX the 386BSD interface is different */ + error = physio(wdformat, &rwdbuf[lunit], 0, dev, B_WRITE, + minphys, &auio); + fop->df_count -= auio.uio_resid; + fop->df_reg[0] = du->dk_status; + fop->df_reg[1] = du->dk_error; + return (error); +#endif + + default: + return (ENOTTY); + } +} + +#endif /* NWDC > 0 */ #endif /* NWDC > 0 */ diff --git a/sys/isa/fd.c b/sys/isa/fd.c index d09b927..abc2634 100644 --- a/sys/isa/fd.c +++ b/sys/isa/fd.c @@ -43,7 +43,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.107 1998/01/24 02:54:18 eivind Exp $ + * $Id: fd.c,v 1.108 1998/04/17 22:36:31 des Exp $ * */ @@ -82,9 +82,13 @@ #include <sys/ftape.h> #include <i386/isa/ftreg.h> #endif -#ifdef DEVFS +#ifdef DEVFS #include <sys/devfsext.h> -#endif +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#endif /* SLICE */ +#endif /* DEVFS */ /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX @@ -180,8 +184,21 @@ static struct fd_data { struct callout_handle toffhandle; struct callout_handle tohandle; #ifdef DEVFS +#ifdef SLICE + int unit; /* as in fd0 */ + void *bdevs[MAXPARTITIONS]; + void *cdevs[MAXPARTITIONS]; + struct subdev{ + struct slice *slice; + int minor; + struct fd_data *drive; + struct slicelimits limit; + }subdevs[16]; + struct intr_config_hook ich; +#else /* SLICE */ void *bdevs[1 + NUMDENS + MAXPARTITIONS]; void *cdevs[1 + NUMDENS + MAXPARTITIONS]; +#endif /* SLICE */ #endif } fd_data[NFD]; @@ -227,7 +244,9 @@ static timeout_t fd_timeout; static timeout_t fd_pseudointr; static int fdstate(fdcu_t, fdc_p); static int retrier(fdcu_t); +#ifndef SLICE static int fdformat(dev_t, struct fd_formb *, struct proc *); +#endif static int enable_fifo(fdc_p fdc); @@ -284,6 +303,7 @@ static d_close_t fdclose; static d_ioctl_t fdioctl; static d_strategy_t fdstrategy; +/* even if SLICE defined, these are needed for the ft support. */ #define CDEV_MAJOR 9 #define BDEV_MAJOR 2 static struct cdevsw fd_cdevsw; @@ -294,6 +314,30 @@ static struct bdevsw fd_bdevsw = static struct isa_device *fdcdevs[NFDC]; +#ifdef SLICE +static sl_h_IO_req_t fdsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t fdsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t fdsopen; /* downwards travelling open */ +static sl_h_close_t fdsclose; /* downwards travelling close */ +static void fdsinit(void *); + +static struct slice_handler slicetype = { + "floppy", + 0, + NULL, + 0, + NULL, /* constructor */ + &fdsIOreq, + &fdsioctl, + &fdsopen, + &fdsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif /* SLICE */ + static int fdc_err(fdcu_t fdcu, const char *s) { @@ -529,8 +573,12 @@ fdattach(struct isa_device *dev) struct isa_device *fdup; int ic_type = 0; #ifdef DEVFS +#ifdef SLICE + char namebuf[64]; +#else int mynor; int typemynor; +#endif /* SLICE */ int typesize; #endif @@ -682,6 +730,9 @@ fdattach(struct isa_device *dev) continue; fd->track = FD_NO_TRACK; +#ifdef SLICE + fd->unit = fdu; +#endif fd->fdc = fdc; fd->fdsu = fdsu; fd->options = 0; @@ -721,6 +772,30 @@ fdattach(struct isa_device *dev) continue; } #ifdef DEVFS +#ifdef SLICE + sprintf(namebuf,"fd%d",fdu); + fd->subdevs[0].minor = 0; + fd->subdevs[0].drive = fd; + fd->subdevs[0].limit.blksize = + 128 << (fd_types[fd->type - 1].secsize); + fd->subdevs[0].limit.slicesize = + fd_types[fd->type - 1].size + * fd->subdevs[0].limit.blksize; + fd->ft = fd_types + (fd->type - 1); /* default value */ + sl_make_slice(&slicetype, + &fd->subdevs[0], + &fd->subdevs[0].limit, + &fd->subdevs[0].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[0].slice->probeinfo.typespecific = NULL; + fd->subdevs[0].slice->probeinfo.type = NULL; + + fd->ich.ich_func = fdsinit; + fd->ich.ich_arg = &fd->subdevs[0]; + config_intrhook_establish(&fd->ich); +#else /* SLICE */ mynor = fdu << 6; fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -728,6 +803,7 @@ fdattach(struct isa_device *dev) fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fdu); +#endif /* SLICE */ for (i = 1; i < 1 + NUMDENS; i++) { /* * XXX this and the lookup in Fdopen() should be @@ -755,7 +831,6 @@ fdattach(struct isa_device *dev) continue; break; } - typemynor = mynor | i; typesize = fd_types[i - 1].size / 2; /* * XXX all these conversions give bloated code and @@ -765,6 +840,27 @@ fdattach(struct isa_device *dev) typesize = 1480; if (typesize == 1722) typesize = 1720; +#ifdef SLICE + sprintf(namebuf,"fd%d.%d",fdu,typesize); + fd->subdevs[i].minor = i; + fd->subdevs[i].drive = fd; + fd->subdevs[i].limit.blksize = + 128 << (fd_types[i - 1].secsize); + fd->subdevs[i].limit.slicesize = + fd_types[i - 1].size + * fd->subdevs[i].limit.blksize; + sl_make_slice(&slicetype, + &fd->subdevs[i], + &fd->subdevs[i].limit, + &fd->subdevs[i].slice, + NULL, + namebuf); + /* Allow full probing */ + fd->subdevs[i].slice->probeinfo.typespecific = NULL; + fd->subdevs[i].slice->probeinfo.type = NO_SUBPART; + } +#else /* SLICE */ + typemynor = mynor | i; fd->bdevs[i] = devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -774,14 +870,15 @@ fdattach(struct isa_device *dev) UID_ROOT, GID_OPERATOR, 0640, "rfd%d.%d", fdu, typesize); } + for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = - devfs_link(fd->bdevs[0], + fd->bdevs[1 + NUMDENS + i] = devfs_link(fd->bdevs[0], "fd%d%c", fdu, 'a' + i); fd->cdevs[1 + NUMDENS + i] = devfs_link(fd->cdevs[0], "rfd%d%c", fdu, 'a' + i); } +#endif /* SLICE */ #endif /* DEVFS */ #ifdef notyet if (dk_ndrive < DK_NDRIVE) { @@ -800,6 +897,22 @@ fdattach(struct isa_device *dev) return (1); } + +#ifdef SLICE + +static void +fdsinit(void *arg) +{ + struct subdev *sd = arg; + sh_p tp; + + if ((tp = slice_probeall(sd->slice)) != NULL) { + (*tp->constructor)(sd->slice); + } + config_intrhook_disestablish(&sd->drive->ich); +} +#endif /* SLICE */ + /****************************************************************************/ /* motor control stuff */ /* remember to not deselect the drive we're working on */ @@ -1022,6 +1135,10 @@ Fdopen(dev_t dev, int flags, int mode, struct proc *p) if (type == 0) type = fd_data[fdu].type; else { + /* + * For each type of basic drive, make sure we are trying + * to open a type it can do, + */ if (type != fd_data[fdu].type) { switch (fd_data[fdu].type) { case FD_360: @@ -1182,6 +1299,49 @@ bad: biodone(bp); } +#ifdef SLICE +/****************************************************************************/ +/* fdsIOreq */ +/****************************************************************************/ +static void +fdsIOreq(void *private ,struct buf *bp) +{ + unsigned nblocks, blknum, cando; + int s; + fdcu_t fdcu; + fdu_t fdu; + fdc_p fdc; + fd_p fd; + size_t fdblk; + struct subdev *sd; + + sd = private; + fd = sd->drive; + fdu = fd->unit; + fdc = fd->fdc; + fdcu = fdc->fdcu; + + /* check for controller already busy with tape */ + if (fdc->flags & FDC_TAPE_BUSY) { + bp->b_error = EBUSY; + bp->b_flags |= B_ERROR; + goto bad; + } + bp->b_driver1 = sd; /* squirrel away which device.. */ + bp->b_resid = 0; + s = splbio(); + bufqdisksort(&fdc->head, bp); + untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ + fdstart(fdcu); + splx(s); + return; + +bad: + biodone(bp); + return; +} +#endif /* SLICE */ + /***************************************************************\ * fdstart * * We have just queued something.. if the controller is not busy * @@ -1292,6 +1452,7 @@ fdintr(fdcu_t fdcu) static int fdstate(fdcu_t fdcu, fdc_p fdc) { + struct subdev *sd; int read, format, head, sec = 0, sectrac, st0, cyl, st3; unsigned blknum = 0, b_cylinder = 0; fdu_t fdu = fdc->fdu; @@ -1317,8 +1478,14 @@ fdstate(fdcu_t fdcu, fdc_p fdc) TRACE1("[fdc%d IDLE]", fdcu); return(0); } +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; +#else fdu = FDUNIT(minor(bp->b_dev)); fd = fd_data + fdu; +#endif fdblk = 128 << fd->ft->secsize; if (fdc->fd && (fd != fdc->fd)) { @@ -1332,7 +1499,7 @@ fdstate(fdcu_t fdcu, fdc_p fdc) - (char *)finfo; } if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { - blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk + + blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + fd->skip/fdblk; b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); } @@ -1704,13 +1871,26 @@ static int retrier(fdcu) fdcu_t fdcu; { + struct subdev *sd; fdc_p fdc = fdc_data + fdcu; register struct buf *bp; +#ifdef SLICE + struct fd_data *fd; + int fdu; +#endif bp = bufq_first(&fdc->head); +#ifdef SLICE + sd = bp->b_driver1; + fd = sd->drive; + fdu = fd->unit; + if(fd->options & FDOPT_NORETRY) + goto fail; +#else if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) goto fail; +#endif switch(fdc->retry) { case 0: case 1: case 2: @@ -1727,14 +1907,19 @@ retrier(fdcu) default: fail: { +#ifdef SLICE + printf("fd%d: hard error, block %d ", fdu, + fd->skip / DEV_BSIZE); +#else dev_t sav_b_dev = bp->b_dev; /* Trick diskerr */ bp->b_dev = makedev(major(bp->b_dev), - (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); + (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); diskerr(bp, "fd", "hard error", LOG_PRINTF, fdc->fd->skip / DEV_BSIZE, (struct disklabel *)NULL); bp->b_dev = sav_b_dev; +#endif /* !SLICE */ if (fdc->flags & FDC_STAT_VALID) { printf( @@ -1764,11 +1949,16 @@ retrier(fdcu) return(1); } +#ifdef SLICE +static int +fdformat( struct subdev *sd, struct fd_formb *finfo, struct proc *p) +#else /* !SLICE */ static int fdformat(dev, finfo, p) dev_t dev; struct fd_formb *finfo; struct proc *p; +#endif /* !SLICE */ { fdu_t fdu; fd_p fd; @@ -1777,8 +1967,13 @@ fdformat(dev, finfo, p) int rv = 0, s; size_t fdblk; - fdu = FDUNIT(minor(dev)); - fd = &fd_data[fdu]; +#ifdef SLICE + fd = sd->drive; + fdu = fd->unit; +#else + fdu = FDUNIT(minor(dev)); + fd = &fd_data[fdu]; +#endif fdblk = 128 << fd->ft->secsize; /* set up a buffer header for fdstrategy() */ @@ -1792,7 +1987,6 @@ fdformat(dev, finfo, p) bzero((void *)bp, sizeof(struct buf)); bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; bp->b_proc = p; - bp->b_dev = dev; /* * calculate a fake blkno, so fdstrategy() would initiate a @@ -1805,7 +1999,13 @@ fdformat(dev, finfo, p) bp->b_data = (caddr_t)finfo; /* now do the format */ +#ifdef SLICE + bp->b_driver1 = sd; + fdsIOreq(sd, bp); +#else /* !SLICE */ + bp->b_dev = dev; fdstrategy(bp); +#endif /* !SLICE */ /* ...and wait for it to complete */ s = splbio(); @@ -1836,7 +2036,7 @@ fdformat(dev, finfo, p) * TODO: don't allocate buffer on stack. */ -int +static int fdioctl(dev, cmd, addr, flag, p) dev_t dev; int cmd; @@ -1861,10 +2061,33 @@ fdioctl(dev, cmd, addr, flag, p) return ftioctl(dev, cmd, addr, flag, p); #endif +#ifdef SLICE + /* + * if SLICE is defined then only ft accesses come here + * so break the rest off to another function for SLICE access. + */ + return (ENOTTY); +} + +/* + * Slice ioctls come here + */ +static int +fdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + struct subdev *sd = private; + fd_p fd = sd->drive; + fdu_t fdu = fd->unit; + fdc_p fdc = fd->fdc; + fdcu_t fdcu = fdc->fdcu; + size_t fdblk; + int error = 0; +#endif /* SLICE */ fdblk = 128 << fd->ft->secsize; switch (cmd) { +#ifndef SLICE case DIOCGDINFO: bzero(buffer, sizeof (buffer)); dl = (struct disklabel *)buffer; @@ -1908,7 +2131,7 @@ fdioctl(dev, cmd, addr, flag, p) error = writedisklabel(dev, fdstrategy, (struct disklabel *)buffer); break; - +#endif /* !SLICE */ case FD_FORM: if((flag & FWRITE) == 0) error = EBADF; /* must be opened for writing */ @@ -1916,26 +2139,30 @@ fdioctl(dev, cmd, addr, flag, p) FD_FORMAT_VERSION) error = EINVAL; /* wrong version of formatting prog */ else +#ifdef SLICE + error = fdformat(sd, (struct fd_formb *)addr, p); +#else error = fdformat(dev, (struct fd_formb *)addr, p); +#endif break; case FD_GTYPE: /* get drive type */ - *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft; + *(struct fd_type *)addr = *fd->ft; break; case FD_STYPE: /* set drive type */ /* this is considered harmful; only allow for superuser */ if(suser(p->p_ucred, &p->p_acflag) != 0) return EPERM; - *fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr; + *fd->ft = *(struct fd_type *)addr; break; case FD_GOPTS: /* get drive options */ - *(int *)addr = fd_data[FDUNIT(minor(dev))].options; + *(int *)addr = fd->options; break; case FD_SOPTS: /* set drive options */ - fd_data[FDUNIT(minor(dev))].options = *(int *)addr; + fd->options = *(int *)addr; break; default: @@ -1959,7 +2186,32 @@ static void fd_drvinit(void *notused ) SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) + +#ifdef SLICE +static int +fdsopen(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + return(Fdopen(makedev(0,sd->minor), 0 , 0, p)); +} + +static void +fdsclose(void *private, int flags, int mode, struct proc *p) +{ + struct subdev *sd; + + sd = private; + + fdclose(makedev(0,sd->minor), 0 , 0, p); + return ; +} + +#endif /* SLICE */ #endif + /* * Hello emacs, these are the * Local Variables: diff --git a/sys/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c index 1431b19..c4a4a57 100644 --- a/sys/isofs/cd9660/cd9660_vfsops.c +++ b/sys/isofs/cd9660/cd9660_vfsops.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 - * $Id: cd9660_vfsops.c,v 1.34 1998/03/01 22:46:00 msmith Exp $ + * $Id: cd9660_vfsops.c,v 1.35 1998/03/08 09:56:41 julian Exp $ */ #include <sys/param.h> @@ -143,6 +143,9 @@ iso_get_ssector(dev, p) return ntohl(t.entry.addr.lba); } +#ifdef SLICE +extern struct vnode *root_device_vnode; +#endif static int iso_mountroot(mp, p) @@ -152,10 +155,18 @@ iso_mountroot(mp, p) struct iso_args args; int error; +#ifdef SLICE + rootvp = root_device_vnode; + if (rootvp == NULL) { + printf("cd9660_mountroot: rootvp not set"); + return (EINVAL); + } +#else if ((error = bdevvp(rootdev, &rootvp))) { printf("iso_mountroot: can't find rootvp"); return (error); } +#endif args.flags = ISOFSMNT_ROOT; args.ssector = iso_get_ssector(rootdev, p); if (bootverbose) diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 3de881d..c6659bf 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -39,7 +39,7 @@ * SUCH DAMAGE. * * @(#)init_main.c 8.9 (Berkeley) 1/21/94 - * $Id: init_main.c,v 1.89 1998/04/11 17:24:06 phk Exp $ + * $Id: init_main.c,v 1.90 1998/04/17 22:36:49 des Exp $ */ #include "opt_devfs.h" @@ -582,7 +582,7 @@ start_init(p) options = 1; #endif -#if defined(DEVFS) && defined(DEVFS_ROOT) +#if defined(DEVFS) && defined(SLICE) (void)subyte(--ucp, 'd'); options = 1; #endif diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c index 5ffb5db..4b11dc6 100644 --- a/sys/kern/subr_diskslice.c +++ b/sys/kern/subr_diskslice.c @@ -1,3 +1,6 @@ +#ifdef SLICE +#undef DEVFS +#endif /*- * Copyright (c) 1994 Bruce D. Evans. * All rights reserved. @@ -43,7 +46,7 @@ * from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $ * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $ - * $Id: subr_diskslice.c,v 1.41 1998/01/24 02:54:34 eivind Exp $ + * $Id: subr_diskslice.c,v 1.42 1998/02/15 05:41:31 bde Exp $ */ #include "opt_devfs.h" diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index a42a89a..ffe86ce 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * @(#)vfs_conf.c 8.8 (Berkeley) 3/31/94 - * $Id: vfs_conf.c,v 1.21 1998/02/09 06:09:32 eivind Exp $ + * $Id: vfs_conf.c,v 1.22 1998/03/11 00:10:31 msmith Exp $ */ /* @@ -73,9 +73,12 @@ MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); static struct mount *rootfs; struct vnode *rootvnode; char *mountrootfsname; +#ifdef SLICE +char rootdevice[32]; +#endif /* SLICE */ #ifdef BOOTP extern void bootpc_init __P((void)); -#endif +#endif /* BOOTP */ /* * vfs_init() will set maxvfsconf diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 8e6c9dc..5e6386e 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 - * $Id: vfs_subr.c,v 1.150 1998/04/16 03:31:26 peter Exp $ + * $Id: vfs_subr.c,v 1.151 1998/04/18 06:26:16 peter Exp $ */ /* @@ -71,6 +71,9 @@ #include <vm/vm_zone.h> #include <sys/sysctl.h> +#if defined(DEVFS) +#include <sys/devfsext.h> +#endif /* DEVFS */ #include <miscfs/specfs/specdev.h> static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure"); @@ -1090,7 +1093,7 @@ reassignbuf(bp, newvp) splx(s); } -#ifndef DEVFS_ROOT +#ifndef SLICE /* * Create a vnode for a block device. * Used for mounting the root file system. @@ -1120,7 +1123,7 @@ bdevvp(dev, vpp) *vpp = vp; return (0); } -#endif /* !DEVFS_ROOT */ +#endif /* !SLICE */ /* * Check to see if the new vnode represents a special device @@ -1151,6 +1154,8 @@ loop: continue; /* * Alias, but not in use, so flush it out. + * Only alias active device nodes. + * Not sure why we don't re-use this like we do below. */ simple_lock(&vp->v_interlock); if (vp->v_usecount == 0) { @@ -1159,12 +1164,26 @@ loop: goto loop; } if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { + /* + * It dissappeared, and we may have slept. + * Restart from the beginning + */ simple_unlock(&spechash_slock); goto loop; } break; } + /* + * It would be a lot clearer what is going on here if + * this had been expressed as: + * if ( vp && (vp->v_tag == VT_NULL)) + * and the clauses had been swapped. + */ if (vp == NULL || vp->v_tag != VT_NON) { + /* + * Put the new vnode into the hash chain. + * and if there was an alias, connect them. + */ MALLOC(nvp->v_specinfo, struct specinfo *, sizeof(struct specinfo), M_VNODE, M_WAITOK); nvp->v_rdev = nvp_rdev; @@ -1180,6 +1199,12 @@ loop: } return (NULLVP); } + /* + * if ( vp && (vp->v_tag == VT_NULL)) + * We have a vnode alias, but it is a trashed. + * Make it look like it's newley allocated. (by getnewvnode()) + * The caller should use this instead. + */ simple_unlock(&spechash_slock); VOP_UNLOCK(vp, 0, p); simple_lock(&vp->v_interlock); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index a42a89a..ffe86ce 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * @(#)vfs_conf.c 8.8 (Berkeley) 3/31/94 - * $Id: vfs_conf.c,v 1.21 1998/02/09 06:09:32 eivind Exp $ + * $Id: vfs_conf.c,v 1.22 1998/03/11 00:10:31 msmith Exp $ */ /* @@ -73,9 +73,12 @@ MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); static struct mount *rootfs; struct vnode *rootvnode; char *mountrootfsname; +#ifdef SLICE +char rootdevice[32]; +#endif /* SLICE */ #ifdef BOOTP extern void bootpc_init __P((void)); -#endif +#endif /* BOOTP */ /* * vfs_init() will set maxvfsconf diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 8e6c9dc..5e6386e 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 - * $Id: vfs_subr.c,v 1.150 1998/04/16 03:31:26 peter Exp $ + * $Id: vfs_subr.c,v 1.151 1998/04/18 06:26:16 peter Exp $ */ /* @@ -71,6 +71,9 @@ #include <vm/vm_zone.h> #include <sys/sysctl.h> +#if defined(DEVFS) +#include <sys/devfsext.h> +#endif /* DEVFS */ #include <miscfs/specfs/specdev.h> static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure"); @@ -1090,7 +1093,7 @@ reassignbuf(bp, newvp) splx(s); } -#ifndef DEVFS_ROOT +#ifndef SLICE /* * Create a vnode for a block device. * Used for mounting the root file system. @@ -1120,7 +1123,7 @@ bdevvp(dev, vpp) *vpp = vp; return (0); } -#endif /* !DEVFS_ROOT */ +#endif /* !SLICE */ /* * Check to see if the new vnode represents a special device @@ -1151,6 +1154,8 @@ loop: continue; /* * Alias, but not in use, so flush it out. + * Only alias active device nodes. + * Not sure why we don't re-use this like we do below. */ simple_lock(&vp->v_interlock); if (vp->v_usecount == 0) { @@ -1159,12 +1164,26 @@ loop: goto loop; } if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { + /* + * It dissappeared, and we may have slept. + * Restart from the beginning + */ simple_unlock(&spechash_slock); goto loop; } break; } + /* + * It would be a lot clearer what is going on here if + * this had been expressed as: + * if ( vp && (vp->v_tag == VT_NULL)) + * and the clauses had been swapped. + */ if (vp == NULL || vp->v_tag != VT_NON) { + /* + * Put the new vnode into the hash chain. + * and if there was an alias, connect them. + */ MALLOC(nvp->v_specinfo, struct specinfo *, sizeof(struct specinfo), M_VNODE, M_WAITOK); nvp->v_rdev = nvp_rdev; @@ -1180,6 +1199,12 @@ loop: } return (NULLVP); } + /* + * if ( vp && (vp->v_tag == VT_NULL)) + * We have a vnode alias, but it is a trashed. + * Make it look like it's newley allocated. (by getnewvnode()) + * The caller should use this instead. + */ simple_unlock(&spechash_slock); VOP_UNLOCK(vp, 0, p); simple_lock(&vp->v_interlock); diff --git a/sys/miscfs/devfs/devfs_tree.c b/sys/miscfs/devfs/devfs_tree.c index c7c561e..6d03fa6 100644 --- a/sys/miscfs/devfs/devfs_tree.c +++ b/sys/miscfs/devfs/devfs_tree.c @@ -1,4 +1,4 @@ -/*#define SPLIT_DEVS 1*/ + /* * Copyright 1997,1998 Julian Elischer. All rights reserved. * julian@freebsd.org @@ -24,15 +24,20 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: devfs_tree.c,v 1.50 1998/03/26 20:52:05 phk Exp $ + * $Id: devfs_tree.c,v 1.51 1998/04/17 22:36:53 des Exp $ */ + +#define SPLIT_DEVS 1 +/*#define SPLIT_DEVS 1*/ + #include "opt_devfs.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/malloc.h> #include <sys/mount.h> #include <sys/proc.h> @@ -894,44 +899,6 @@ DBPRINT((" vntodn ")); return(0); } -#ifdef DEVFS_ROOT -static dn_p -findbdev(dev_t dev, dn_p dir) -{ - devnm_p newfp; - dn_p dnp; - - for(newfp = dir->by.Dir.dirlist;newfp;newfp=newfp->next) { - dnp = newfp->dnp; - if (dnp->type == DEV_BDEV && dnp->by.Bdev.dev == dev) { - return (dnp); - } - if (dnp->type == DEV_DIR) { - if (dnp = findbdev(dev, dnp)) - return dnp; - } - } - return (0); -} - -/* - * Create a vnode for a block device. - * Used for mounting the root file system. - */ -int -bdevvp(dev_t dev, struct vnode **vpp) -{ - dn_p dnp = 0; - - if (dev == NODEV) - return(0); - dnp= findbdev(dev, dev_root->dnp); - if (!dnp) - return (ENOENT); - return (devfs_dntovn(dnp, vpp)); -} -#endif /* DEVFS_ROOT */ - /***************************************************************\ * given a dev_node, find the appropriate vnode if one is already* * associated, or get a new one an associate it with the dev_node* @@ -1207,3 +1174,116 @@ devfs_link(void *original, char *fmt, ...) return new_dev; } +/* + * internal kernel call to open a device. Return either 0 or an open vnode. + */ +struct vnode * +devfs_open_device(char *path, int type) +{ + register char *lastslash; + char *nextpart; + devnm_p nm_p; + dn_p dirnode; + struct vnode *vn; + + /* + * If the caller didn't supply a full path, ignore and be + * noisy about it. + */ + if (*path != '/') { + printf (__FUNCTION__ ": caller supplied bad path\n"); + return (NULL); + } + + /* + * find the last '/'. Unfortunatly rindex() while being in + * libkern source, is not being compiled.. do it by hand. + * lastslash = strrchr(path,(int)'c'); + * There will be at LEAST one '/'. + */ + { + register char *p = path; /* don't destroy path */ + + for (lastslash = NULL;*p; ++p) { + if (*p == '/') + lastslash = p; + } + } + dirnode = dev_root->dnp; + if(lastslash != path) { + /* find the directory we need */ + *lastslash = '\0'; + if (dev_finddir(path, dirnode, NULL, &dirnode) != 0) { + *lastslash = '/'; + return (NULL); + } + /* ok we found the directory, put the slash back */ + *lastslash = '/'; + } + nextpart = ++lastslash; + if (*nextpart == '\0') + return (NULL); + /* + * Now only return true if it exists and is the right type. + */ + if ((nm_p = dev_findname(dirnode, nextpart)) == NULL) { + return (NULL); + } + switch(type) { + case DV_BLK: + if( nm_p->dnp->type != DEV_BDEV) + return (NULL); + break; + case DV_CHR: + if( nm_p->dnp->type != DEV_CDEV) + return (NULL); + break; + } + + if ( devfs_dntovn(nm_p->dnp, &vn)) + return (NULL); + +#if 0 + if ( VOP_OPEN(vn, FREAD, proc0.p_cred->pc_ucred, &proc0)) { + vput(vn); + return (NULL); + } +#endif + return (vn); +} + +/* + * internal kernel call to close a devfs device. + * It should have been openned by th ecall above. + * try not mix it with user-openned vnodes. + * Frees the vnode. + */ +void +devfs_close_device(struct vnode *vn) +{ +#if 0 + VOP_CLOSE(vn, 0, proc0.p_cred->pc_ucred, &proc0) ; +#endif + vput(vn); +} + +/* + * Little utility routine for compatibilty. + * Returns the dev_t that a devfs vnode represents. + * should go away after dev_t go away :). + */ +dev_t +devfs_vntodev(struct vnode *vn) +{ + register dn_p dnp; + dnp = (dn_p)vn->v_data; + switch (dnp->type) { + case DEV_BDEV: + return (dnp->by.Bdev.dev); + break; + case DEV_CDEV: + return (dnp->by.Cdev.dev); + break; + } + panic ("bad devfs DEVICE vnode"); +} diff --git a/sys/miscfs/devfs/devfs_vfsops.c b/sys/miscfs/devfs/devfs_vfsops.c index 442dc1b..c87ec56 100644 --- a/sys/miscfs/devfs/devfs_vfsops.c +++ b/sys/miscfs/devfs/devfs_vfsops.c @@ -23,10 +23,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: devfs_vfsops.c,v 1.27 1998/03/01 22:46:08 msmith Exp $ + * $Id: devfs_vfsops.c,v 1.28 1998/04/17 22:36:53 des Exp $ * */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> diff --git a/sys/miscfs/devfs/devfs_vnops.c b/sys/miscfs/devfs/devfs_vnops.c index 773d903..6c9bae7 100644 --- a/sys/miscfs/devfs/devfs_vnops.c +++ b/sys/miscfs/devfs/devfs_vnops.c @@ -1,3 +1,4 @@ + /* * Copyright 1997,1998 Julian Elischer. All rights reserved. * julian@freebsd.org @@ -23,9 +24,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: devfs_vnops.c,v 1.52 1998/03/10 09:12:19 julian Exp $ + * $Id: devfs_vnops.c,v 1.53 1998/03/26 20:52:12 phk Exp $ */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/namei.h> @@ -482,33 +484,23 @@ DBPRINT(("getattr\n")); vap->va_fileid = (long)file_node; vap->va_size = file_node->len; /* now a u_quad_t */ vap->va_blocksize = 512; - if(file_node->ctime.tv_sec) - { - vap->va_ctime = file_node->ctime; - } - else - { - TIMEVAL_TO_TIMESPEC(&boottime,&(vap->va_ctime)); - } - if(file_node->mtime.tv_sec) - { - vap->va_mtime = file_node->mtime; - } - else - { - TIMEVAL_TO_TIMESPEC(&boottime,&(vap->va_mtime)); - } - if(file_node->atime.tv_sec) - { - vap->va_atime = file_node->atime; - } - else + /* + * XXX If the node times are in Jan 1, 1970, then + * update them to the boot time. + * When we made the node, the date/time was not yet known. + */ + if(file_node->ctime.tv_sec < (24 * 3600)) { - TIMEVAL_TO_TIMESPEC(&boottime,&(vap->va_atime)); + TIMEVAL_TO_TIMESPEC(&boottime,&(file_node->ctime)); + TIMEVAL_TO_TIMESPEC(&boottime,&(file_node->mtime)); + TIMEVAL_TO_TIMESPEC(&boottime,&(file_node->atime)); } + vap->va_ctime = file_node->ctime; + vap->va_mtime = file_node->mtime; + vap->va_atime = file_node->atime; vap->va_gen = 0; vap->va_flags = 0; - vap->va_bytes = file_node->len; /* u_quad_t */ + vap->va_bytes = file_node->len; /* u_quad_t */ vap->va_filerev = 0; /* XXX */ /* u_quad_t */ vap->va_vaflags = 0; /* XXX */ return 0; diff --git a/sys/miscfs/devfs/devfsdefs.h b/sys/miscfs/devfs/devfsdefs.h index b475e22..ef31dd9 100644 --- a/sys/miscfs/devfs/devfsdefs.h +++ b/sys/miscfs/devfs/devfsdefs.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: devfsdefs.h,v 1.12 1997/10/11 18:31:29 phk Exp $ + * $Id: devfsdefs.h,v 1.13 1998/01/02 07:31:07 julian Exp $ */ #ifdef DEVFS_DEBUG #define DBPRINT(A) printf(A) @@ -31,7 +31,6 @@ #define DBPRINT(A) #endif - /* first a couple of defines for compatibility with inodes */ #define ISUID 04000 /* set user identifier when exec'ing */ diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 666322f..82f001d 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.59 1998/03/08 08:46:18 dyson Exp $ + * $Id: spec_vnops.c,v 1.60 1998/03/08 09:57:36 julian Exp $ */ #include <sys/param.h> @@ -761,8 +761,15 @@ spec_getpages(ap) * Round up physical size for real devices, use the * fundamental blocksize of the fs if possible. */ - if (vp && vp->v_mount) + if (vp && vp->v_mount) { + if (vp->v_type != VBLK) { + vprint("Non VBLK", vp); + } blksiz = vp->v_mount->mnt_stat.f_bsize; + if (blksiz < DEV_BSIZE) { + blksiz = DEV_BSIZE; + } + } else blksiz = DEV_BSIZE; size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h index b4c6f77..9c225a3 100644 --- a/sys/miscfs/specfs/specdev.h +++ b/sys/miscfs/specfs/specdev.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)specdev.h 8.6 (Berkeley) 5/21/95 - * $Id: specdev.h,v 1.13 1997/10/15 13:23:21 phk Exp $ + * $Id: specdev.h,v 1.14 1998/03/08 09:57:40 julian Exp $ */ /* @@ -43,7 +43,8 @@ struct specinfo { struct vnode **si_hashchain; struct vnode *si_specnext; struct mount *si_mountpoint; - dev_t si_rdev; + dev_t si_rdev; + unsigned long si_blksize; /* smallest IO unit */ }; /* * Exported shorthand @@ -52,6 +53,7 @@ struct specinfo { #define v_hashchain v_specinfo->si_hashchain #define v_specnext v_specinfo->si_specnext #define v_specmountpoint v_specinfo->si_mountpoint +#define v_blksize v_specinfo->si_blksize /* * Special device management diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index bbc83ae..a5d6236 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,3 @@ - /* * Written by Julian Elischer (julian@dialix.oz.au) * for TRW Financial Systems for use under the MACH(2.5) operating system. @@ -15,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id: sd.c,v 1.122 1998/04/15 17:47:21 bde Exp $ + * $Id: sd.c,v 1.123 1998/04/17 22:37:10 des Exp $ */ #include "opt_bounce.h" @@ -35,7 +34,11 @@ #include <sys/conf.h> #ifdef DEVFS #include <sys/devfsext.h> -#endif /*DEVFS*/ +#ifdef SLICE +#include <sys/device.h> +#include <dev/slice/slice.h> +#endif /* SLICE */ +#endif /* DEVFS */ #include <scsi/scsi_disk.h> #include <scsi/scsiconf.h> @@ -93,8 +96,17 @@ struct scsi_data { struct buf_queue_head buf_queue; int dkunit; /* disk stats unit number */ #ifdef DEVFS +#ifdef SLICE + struct slice *slice; + int mynor; + struct slicelimits limit; + struct scsi_link *sc_link; + int unit; + struct intr_config_hook ich; +#else /* SLICE */ void *b_devfs_token; void *c_devfs_token; +#endif /* SLICE */ void *ctl_devfs_token; #endif }; @@ -119,10 +131,35 @@ static d_strategy_t sdstrategy; #define CDEV_MAJOR 13 #define BDEV_MAJOR 4 +#ifndef SLICE static struct cdevsw sd_cdevsw; static struct bdevsw sd_bdevsw = { sdopen, sdclose, sdstrategy, sdioctl, /*4*/ sddump, sdsize, D_DISK, "sd", &sd_cdevsw, -1 }; +#else /* ! SLICE */ + +static sl_h_IO_req_t sdsIOreq; /* IO req downward (to device) */ +static sl_h_ioctl_t sdsioctl; /* ioctl req downward (to device) */ +static sl_h_open_t sdsopen; /* downwards travelling open */ +static sl_h_close_t sdsclose; /* downwards travelling close */ +static void sds_init (void *arg); + +static struct slice_handler slicetype = { + "scsidisk", + 0, + NULL, + 0, + NULL, /* constructor */ + &sdsIOreq, + &sdsioctl, + &sdsopen, + &sdsclose, + NULL, /* revoke */ + NULL, /* claim */ + NULL, /* verify */ + NULL /* upconfig */ +}; +#endif @@ -148,7 +185,11 @@ static struct scsi_device sd_switch = sd_open, sd_ioctl, sd_close, +#ifndef SLICE sd_strategy, +#else + NULL, +#endif }; static struct scsi_xfer sx; @@ -227,6 +268,31 @@ sdattach(struct scsi_link *sc_link) sd_registerdev(unit); #ifdef DEVFS +#ifdef SLICE + { + char namebuf[64]; + sd->unit = unit; + sd->sc_link = sc_link; + sprintf(namebuf,"sd%d",sd->unit); + sd->mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); + sd->limit.blksize = sd->params.secsiz; + /* need to cast to avoid overflow! */ + sd->limit.slicesize = + (u_int64_t)sd->params.secsiz * sd->params.disksize; + sl_make_slice(&slicetype, + sd, + &sd->limit, + &sd->slice, + NULL, + namebuf); + /* Allow full probing */ + sd->slice->probeinfo.typespecific = NULL; + sd->slice->probeinfo.type = NULL; + } + sd->ich.ich_func = sds_init; + sd->ich.ich_arg = sd; + config_intrhook_establish(&sd->ich); +#else /* SLICE */ mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART); sd->b_devfs_token = devfs_add_devswf(&sd_bdevsw, mynor, DV_BLK, UID_ROOT, GID_OPERATOR, 0640, @@ -240,11 +306,26 @@ sdattach(struct scsi_link *sc_link) DV_CHR, UID_ROOT, GID_WHEEL, 0600, "rsd%d.ctl", unit); +#endif /* SLICE */ #endif - return 0; } +#ifdef SLICE +/* run a LOT later */ +static void +sds_init(void *arg) +{ + struct scsi_data *sd = arg; + sh_p tp; + + if ((tp = slice_probeall(sd->slice)) != NULL) { + (*tp->constructor)(sd->slice); + } + config_intrhook_disestablish(&sd->ich); +} +#endif /* SLICE */ + /* * open the device. Make sure the partition info is a up-to-date as can be. */ @@ -295,6 +376,7 @@ sd_open(dev, mode, fmt, p, sc_link) */ sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ if (!(sc_link->flags & SDEV_MEDIA_LOADED) && sd->dk_slices != NULL) { +#ifndef SLICE /* * If somebody still has it open, then forbid re-entry. */ @@ -304,6 +386,7 @@ sd_open(dev, mode, fmt, p, sc_link) } dsgone(&sd->dk_slices); +#endif /* !SLICE */ } /* @@ -339,11 +422,13 @@ sd_open(dev, mode, fmt, p, sc_link) /* XXX as long as it's not 0 - readdisklabel divides by it (?) */ label.d_secperunit = sd->params.disksize; +#ifndef SLICE /* Initialize slice tables. */ errcode = dsopen("sd", dev, fmt, &sd->dk_slices, &label, sdstrategy1, (ds_setgeom_t *)NULL, &sd_bdevsw, &sd_cdevsw); if (errcode != 0) goto bad; +#endif /* !SLICE */ SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized ")); SC_DEBUG(sc_link, SDEV_DB3, ("open %ld %ld\n", sdstrats, sdqueues)); @@ -379,15 +464,18 @@ sd_close(dev, fflag, fmt, p, sc_link) errcode = scsi_device_lock(sc_link); if (errcode) return errcode; +#ifndef SLICE dsclose(dev, fmt, sd->dk_slices); if (!dsisopen(sd->dk_slices)) { scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); sc_link->flags &= ~SDEV_OPEN; } +#endif /* ! SLICE */ scsi_device_unlock(sc_link); return (0); } +#ifndef SLICE /* * Actually translate the requested transfer into one the physical driver * can understand. The transfer is described by a buf and will include @@ -518,6 +606,7 @@ sdstrategy1(struct buf *bp) sdstrategy(bp); } +#endif /* ! SLICE */ /* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, @@ -650,7 +739,7 @@ sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p, #if 0 /* Wait until we have exclusive access to the device. */ /* XXX this is how wd does it. How did we work without this? */ - wdsleep(du->dk_ctrlr, "wdioct"); + sdsleep(du->dk_ctrlr, "wdioct"); #endif /* @@ -662,10 +751,10 @@ sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p, if (cmd == DIOCSBAD) return (EINVAL); /* XXX */ +#ifndef SLICE error = scsi_device_lock(sc_link); if (error) return error; - error = dsioctl("sd", dev, cmd, addr, flag, &sd->dk_slices, sdstrategy1, (ds_setgeom_t *)NULL); scsi_device_unlock(sc_link); @@ -673,6 +762,7 @@ sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p, return (error); if (PARTITION(dev) != RAW_PART) return (ENOTTY); +#endif /* ! SLICE */ /* really only take this from the ctl device XXX */ return (scsi_do_ioctl(dev, cmd, addr, flag, p, sc_link)); } @@ -888,6 +978,7 @@ sd_get_parms(int unit, int flags) return (error); } +#ifndef SLICE static int sdsize(dev_t dev) { @@ -899,6 +990,7 @@ sdsize(dev_t dev) return (dssize(dev, &sd->dk_slices, sdopen, sdclose)); } +#endif /* ! SLICE */ /* * sense handler: Called to determine what to do when the * device returns a CHECK CONDITION. @@ -952,6 +1044,7 @@ sd_sense_handler(struct scsi_xfer *xs) return SCSIRET_DO_RETRY; } +#ifndef SLICE /* * dump all of physical memory into the partition specified, starting * at offset 'dumplo' into the partition. @@ -1092,7 +1185,9 @@ sddump(dev_t dev) } return (0); } +#endif /* !SLICE */ +#ifndef SLICE static sd_devsw_installed = 0; static void sd_drvinit(void *unused) @@ -1106,3 +1201,109 @@ static void sd_drvinit(void *unused) SYSINIT(sddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,sd_drvinit,NULL) +#endif /* !SLICE */ +#ifdef SLICE + +/* + * Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer + * to complete. Multi-page transfers are supported. All I/O requests must + * be a multiple of a sector in length. +scsi_strategy(bp, &sd_switch); + */ +static void +sdsIOreq(void *private ,struct buf *bp) +{ + struct scsi_data *sd = private; + u_int32_t opri; + u_int32_t unit = sd->unit; + struct scsi_link *sc_link = sd->sc_link; + + SC_DEBUG(sc_link, SDEV_DB2, ("sdIOreq\n")); + SC_DEBUG(sc_link, SDEV_DB1, ("%ld bytes @ blk%ld\n", + bp->b_bcount, bp->b_pblkno)); + + bp->b_resid = 0; + bp->b_error = 0; + + (*sc_link->adapter->scsi_minphys)(bp); + + sdstrats++; + /* + * If the device has been made invalid, error out + */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + bp->b_error = EIO; + goto bad; + } + + /* + * check it's not too big a transfer for our adapter + */ + /*scsi_minphys(bp,&sd_switch);*/ + + opri = SPLSD(); + /* + * Use a bounce buffer if necessary + */ +#ifdef BOUNCE_BUFFERS + if (sc_link->flags & SDEV_BOUNCE) + vm_bounce_alloc(bp); +#endif + + /* + * Place it in the queue of disk activities for this disk + */ +#ifdef SDDISKSORT + bufq_disksort(&sd->buf_queue, bp); +#else + bufq_insert_tail(&sd->buf_queue, bp); +#endif + + /* + * Tell the device to get going on the transfer if it's + * not doing anything, otherwise just wait for completion + */ + sdstart(unit, 0); + + splx(opri); + return; +bad: + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + biodone(bp); + return; +} + + +static int +sdsopen(void *private, int flags, int mode, struct proc *p) +{ + struct scsi_data *sd; + + sd = private; + + return(sdopen(makedev(0,sd->mynor), 0 , 0, p)); +} + +static void +sdsclose(void *private, int flags, int mode, struct proc *p) +{ + struct scsi_data *sd; + + sd = private; + + sdclose(makedev(0,sd->mynor), 0 , 0, p); + return; +} +static int +sdsioctl( void *private, int cmd, caddr_t addr, int flag, struct proc *p) +{ + struct scsi_data *sd; + + sd = private; + + return(sdioctl(makedev(0,sd->mynor), cmd, addr, flag, p)); +} + +#endif diff --git a/sys/sys/devfsext.h b/sys/sys/devfsext.h index 1cbf003..47842e0 100644 --- a/sys/sys/devfsext.h +++ b/sys/sys/devfsext.h @@ -1,17 +1,47 @@ /* usual BSD style copyright here */ /* Written by Julian Elischer (julian@dialix.oz.au)*/ /* - * $Id: devfsext.h,v 1.15 1997/02/22 09:44:59 peter Exp $ + * $Id: devfsext.h,v 1.16 1997/09/16 14:23:35 bde Exp $ */ #ifndef _SYS_DEVFSECT_H_ #define _SYS_DEVFSECT_H_ +/* + * Make a device at a path, and get a cookie for it in return. + * Specify the type, the minor number and the devsw entry to use, + * and the initial default perms/ownerships. + */ void *devfs_add_devswf __P((void *devsw, int minor, int chrblk, uid_t uid, gid_t gid, int perms, char *fmt, ...)); +/* + * Make a link to a device you already made, and have the cookie for + * We get another cookie, but for now, it can be discarded, as + * at the moment there is nothing you can do with it that you couldn't do + * with the original cookie. ( XXX this might be something I should change ) + */ void *devfs_link __P((void *original, char *fmt, ...)); + +/* + * Remove all instances of a device you have made. INCLUDING LINKS. + * I.e. either the cookie from the original device or the cookie + * from a link will have the effect of removing both entries. + * Removing with BOTH an original cookie and one from a link is + * likely to cause a panic. + */ void devfs_remove_dev __P((void *devnmp)); +/* + * Check if a device exists and is the type you need. Returns NULL or a + * cookie that can be used to try 'open' the device. XXX This is a bit + * of a duplication of devfs_lookup(). I might one day try merge them a bit. + * Used for mountroot under DEVFS. Path is relative to the base of the devfs. + */ +struct vnode *devfs_open_device __P((char *path, int devtype)); +void devfs_close_device __P((struct vnode *vn)); + +dev_t devfs_vntodev __P((struct vnode *vn)); /* extract dev_t from devfs vn */ + #define DV_CHR 0 #define DV_BLK 1 #define DV_DEV 2 diff --git a/sys/sys/sliceio.h b/sys/sys/sliceio.h new file mode 100644 index 0000000..a5d3cae --- /dev/null +++ b/sys/sys/sliceio.h @@ -0,0 +1,37 @@ +/* + * $Id: mtio.h,v 1.10 1997/02/22 09:45:37 peter Exp $ + */ + +#ifndef _SYS_SLICEIO_H_ +#define _SYS_SLICEIO_H_ + +#ifndef KERNEL +#include <sys/types.h> +#endif +#include <sys/ioccom.h> +#define SLCTYPE_SIZE 16 +#define SLCNAME_SIZE 32 + +struct sliceinfo { + u_int64_t size; + u_int32_t blocksize; + char type[SLCTYPE_SIZE]; /* e.g. sd or raw*/ + char hint[SLCTYPE_SIZE]; /* e.g. mbr or ""*/ + char handler[SLCTYPE_SIZE]; /* e.g. mbr or "" */ + char devicename[SLCNAME_SIZE]; /* e.g. sd0s1a */ +}; + +struct subsliceinfo { + struct sliceinfo wholesliceinfo; /* size of the whole slice */ + int slicenumber; /* which subslice we are on */ + u_int64_t offset; /* where that subslice starts */ + struct sliceinfo subsliceinfo; /* info about that subslice */ +}; + +#define SLCIOCRESET _IO('S', 0) /* reset and reprobe. */ +#define SLCIOCINQ _IOR('S', 2, struct sliceinfo) /* info on container */ +#define SLCIOCMOD _IOW('S', 3, struct sliceinfo) /* force container */ +#define SLCIOCGETSUB _IOWR('S', 4, struct subsliceinfo) /* get sub info */ +#define SLCIOCSETSUB _IOWR('S', 5, struct subsliceinfo) /* set sub info */ + +#endif /* !_SYS_SLICEIO_H_ */ diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 9b4753c..c07d845 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 - * $Id: ffs_vfsops.c,v 1.77 1998/03/27 14:20:57 peter Exp $ + * $Id: ffs_vfsops.c,v 1.78 1998/03/30 09:56:00 phk Exp $ */ #include "opt_quota.h" @@ -128,6 +128,9 @@ VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0); * system call will fail with EFAULT in copyinstr in * namei() if it is a genuine NULL from the user. */ +#ifdef SLICE +extern struct vnode *root_device_vnode; +#endif static int ffs_mount( mp, path, data, ndp, p) struct mount *mp; /* mount struct pointer*/ @@ -156,6 +159,13 @@ ffs_mount( mp, path, data, ndp, p) *** */ +#ifdef SLICE + rootvp = root_device_vnode; + if (rootvp == NULL) { + printf("ffs_mountroot: rootvp not set"); + return (EINVAL); + } +#else /* !SLICE */ if ((err = bdevvp(rootdev, &rootvp))) { printf("ffs_mountroot: can't find rootvp"); return (err); @@ -165,6 +175,7 @@ ffs_mount( mp, path, data, ndp, p) mp->mnt_flag |= MNT_NOCLUSTERR; if (bdevsw[major(rootdev)]->d_flags & D_NOCLUSTERW) mp->mnt_flag |= MNT_NOCLUSTERW; +#endif /* !SLICE */ if( ( err = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; @@ -307,12 +318,18 @@ ffs_mount( mp, path, data, ndp, p) /* ******************** * UPDATE + * If it's not the same vnode, or at least the same device + * then it's not correct. ******************** */ - if (devvp != ump->um_devvp) - err = EINVAL; /* needs translation */ - else + if (devvp != ump->um_devvp) { + if ( devvp->v_rdev == ump->um_devvp->v_rdev) { + vrele(devvp); + } else { + err = EINVAL; /* needs translation */ + } + } else vrele(devvp); /* * Update device name only on success |