xref: /freebsd/sys/dev/md/md.c (revision 9626b608de4a43ec9984c3ee95b2ce624b3c0924)
100a6a3c6SPoul-Henning Kamp /*
200a6a3c6SPoul-Henning Kamp  * ----------------------------------------------------------------------------
300a6a3c6SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
400a6a3c6SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
500a6a3c6SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
600a6a3c6SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
700a6a3c6SPoul-Henning Kamp  * ----------------------------------------------------------------------------
800a6a3c6SPoul-Henning Kamp  *
900a6a3c6SPoul-Henning Kamp  * $FreeBSD$
1000a6a3c6SPoul-Henning Kamp  *
1100a6a3c6SPoul-Henning Kamp  */
1200a6a3c6SPoul-Henning Kamp 
1371e4fff8SPoul-Henning Kamp #include "opt_mfs.h"		/* We have adopted some tasks from MFS */
1471e4fff8SPoul-Henning Kamp #include "opt_md.h"		/* We have adopted some tasks from MFS */
1571e4fff8SPoul-Henning Kamp 
1600a6a3c6SPoul-Henning Kamp #include <sys/param.h>
1700a6a3c6SPoul-Henning Kamp #include <sys/systm.h>
189626b608SPoul-Henning Kamp #include <sys/bio.h>
1900a6a3c6SPoul-Henning Kamp #include <sys/conf.h>
2000a6a3c6SPoul-Henning Kamp #include <sys/devicestat.h>
2127068b01SBrian Feldman #include <sys/disk.h>
2227068b01SBrian Feldman #include <sys/kernel.h>
2327068b01SBrian Feldman #include <sys/malloc.h>
2427068b01SBrian Feldman #include <sys/sysctl.h>
2595f1a897SPoul-Henning Kamp #include <sys/linker.h>
2600a6a3c6SPoul-Henning Kamp 
2733edfabeSPoul-Henning Kamp #ifndef MDNSECT
2833edfabeSPoul-Henning Kamp #define MDNSECT (10000 * 2)
2933edfabeSPoul-Henning Kamp #endif
3033edfabeSPoul-Henning Kamp 
3100a6a3c6SPoul-Henning Kamp MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk");
3200a6a3c6SPoul-Henning Kamp MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors");
3300a6a3c6SPoul-Henning Kamp 
3471e4fff8SPoul-Henning Kamp static int md_debug;
3500a6a3c6SPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, "");
3600a6a3c6SPoul-Henning Kamp 
3771e4fff8SPoul-Henning Kamp #if defined(MFS_ROOT) && !defined(MD_ROOT)
3871e4fff8SPoul-Henning Kamp #define MD_ROOT MFS_ROOT
3971e4fff8SPoul-Henning Kamp #warning "option MFS_ROOT has been superceeded by MD_ROOT"
4071e4fff8SPoul-Henning Kamp #endif
4171e4fff8SPoul-Henning Kamp 
4271e4fff8SPoul-Henning Kamp #if defined(MFS_ROOT_SIZE) && !defined(MD_ROOT_SIZE)
4371e4fff8SPoul-Henning Kamp #define MD_ROOT_SIZE MFS_ROOT_SIZE
4471e4fff8SPoul-Henning Kamp #warning "option MFS_ROOT_SIZE has been superceeded by MD_ROOT_SIZE"
4571e4fff8SPoul-Henning Kamp #endif
4671e4fff8SPoul-Henning Kamp 
4771e4fff8SPoul-Henning Kamp #if defined(MD_ROOT) && defined(MD_ROOT_SIZE)
4871e4fff8SPoul-Henning Kamp /* Image gets put here: */
4971e4fff8SPoul-Henning Kamp static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here";
5071e4fff8SPoul-Henning Kamp static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
5171e4fff8SPoul-Henning Kamp #endif
5271e4fff8SPoul-Henning Kamp 
5371e4fff8SPoul-Henning Kamp static int mdrootready;
5471e4fff8SPoul-Henning Kamp 
5500a6a3c6SPoul-Henning Kamp #define CDEV_MAJOR	95
5600a6a3c6SPoul-Henning Kamp #define BDEV_MAJOR	22
5700a6a3c6SPoul-Henning Kamp 
5800a6a3c6SPoul-Henning Kamp static d_strategy_t mdstrategy;
5971e4fff8SPoul-Henning Kamp static d_strategy_t mdstrategy_preload;
6071e4fff8SPoul-Henning Kamp static d_strategy_t mdstrategy_malloc;
6100a6a3c6SPoul-Henning Kamp static d_open_t mdopen;
6200a6a3c6SPoul-Henning Kamp static d_ioctl_t mdioctl;
6300a6a3c6SPoul-Henning Kamp 
6400a6a3c6SPoul-Henning Kamp static struct cdevsw md_cdevsw = {
6500a6a3c6SPoul-Henning Kamp         /* open */      mdopen,
6600a6a3c6SPoul-Henning Kamp         /* close */     nullclose,
6700a6a3c6SPoul-Henning Kamp         /* read */      physread,
6800a6a3c6SPoul-Henning Kamp         /* write */     physwrite,
6900a6a3c6SPoul-Henning Kamp         /* ioctl */     mdioctl,
7000a6a3c6SPoul-Henning Kamp         /* poll */      nopoll,
7100a6a3c6SPoul-Henning Kamp         /* mmap */      nommap,
7200a6a3c6SPoul-Henning Kamp         /* strategy */  mdstrategy,
7300a6a3c6SPoul-Henning Kamp         /* name */      "md",
7400a6a3c6SPoul-Henning Kamp         /* maj */       CDEV_MAJOR,
7500a6a3c6SPoul-Henning Kamp         /* dump */      nodump,
7600a6a3c6SPoul-Henning Kamp         /* psize */     nopsize,
7771e4fff8SPoul-Henning Kamp         /* flags */     D_DISK | D_CANFREE | D_MEMDISK,
7800a6a3c6SPoul-Henning Kamp         /* bmaj */      BDEV_MAJOR
7900a6a3c6SPoul-Henning Kamp };
8000a6a3c6SPoul-Henning Kamp 
8100a6a3c6SPoul-Henning Kamp struct md_s {
8200a6a3c6SPoul-Henning Kamp 	int unit;
8300a6a3c6SPoul-Henning Kamp 	struct devstat stats;
848177437dSPoul-Henning Kamp 	struct bio_queue_head bio_queue;
8500a6a3c6SPoul-Henning Kamp 	struct disk disk;
8600a6a3c6SPoul-Henning Kamp 	dev_t dev;
8795f1a897SPoul-Henning Kamp 	int busy;
8895f1a897SPoul-Henning Kamp 	enum {MD_MALLOC, MD_PRELOAD} type;
8900a6a3c6SPoul-Henning Kamp 	unsigned nsect;
9071e4fff8SPoul-Henning Kamp 	struct cdevsw devsw;
9195f1a897SPoul-Henning Kamp 
9295f1a897SPoul-Henning Kamp 	/* MD_MALLOC related fields */
9300a6a3c6SPoul-Henning Kamp 	unsigned nsecp;
9400a6a3c6SPoul-Henning Kamp 	u_char **secp;
9500a6a3c6SPoul-Henning Kamp 
9695f1a897SPoul-Henning Kamp 	/* MD_PRELOAD related fields */
9795f1a897SPoul-Henning Kamp 	u_char *pl_ptr;
9895f1a897SPoul-Henning Kamp 	unsigned pl_len;
9900a6a3c6SPoul-Henning Kamp };
10000a6a3c6SPoul-Henning Kamp 
10100a6a3c6SPoul-Henning Kamp static int mdunits;
10200a6a3c6SPoul-Henning Kamp 
10300a6a3c6SPoul-Henning Kamp static int
10400a6a3c6SPoul-Henning Kamp mdopen(dev_t dev, int flag, int fmt, struct proc *p)
10500a6a3c6SPoul-Henning Kamp {
10600a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
10700a6a3c6SPoul-Henning Kamp 	struct disklabel *dl;
10800a6a3c6SPoul-Henning Kamp 
10900a6a3c6SPoul-Henning Kamp 	if (md_debug)
11000a6a3c6SPoul-Henning Kamp 		printf("mdopen(%s %x %x %p)\n",
11100a6a3c6SPoul-Henning Kamp 			devtoname(dev), flag, fmt, p);
11200a6a3c6SPoul-Henning Kamp 
11300a6a3c6SPoul-Henning Kamp 	sc = dev->si_drv1;
11400a6a3c6SPoul-Henning Kamp 
11500a6a3c6SPoul-Henning Kamp 	dl = &sc->disk.d_label;
11600a6a3c6SPoul-Henning Kamp 	bzero(dl, sizeof(*dl));
11700a6a3c6SPoul-Henning Kamp 	dl->d_secsize = DEV_BSIZE;
11800a6a3c6SPoul-Henning Kamp 	dl->d_nsectors = 1024;
11900a6a3c6SPoul-Henning Kamp 	dl->d_ntracks = 1;
12095f1a897SPoul-Henning Kamp 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
12100a6a3c6SPoul-Henning Kamp 	dl->d_secperunit = sc->nsect;
12200a6a3c6SPoul-Henning Kamp 	dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
12300a6a3c6SPoul-Henning Kamp 	return (0);
12400a6a3c6SPoul-Henning Kamp }
12500a6a3c6SPoul-Henning Kamp 
12600a6a3c6SPoul-Henning Kamp static int
12700a6a3c6SPoul-Henning Kamp mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
12800a6a3c6SPoul-Henning Kamp {
12900a6a3c6SPoul-Henning Kamp 
13000a6a3c6SPoul-Henning Kamp 	if (md_debug)
13100a6a3c6SPoul-Henning Kamp 		printf("mdioctl(%s %lx %p %x %p)\n",
13200a6a3c6SPoul-Henning Kamp 			devtoname(dev), cmd, addr, flags, p);
13300a6a3c6SPoul-Henning Kamp 
13400a6a3c6SPoul-Henning Kamp 	return (ENOIOCTL);
13500a6a3c6SPoul-Henning Kamp }
13600a6a3c6SPoul-Henning Kamp 
13700a6a3c6SPoul-Henning Kamp static void
1388177437dSPoul-Henning Kamp mdstrategy(struct bio *bp)
13900a6a3c6SPoul-Henning Kamp {
14071e4fff8SPoul-Henning Kamp 	struct md_s *sc;
14171e4fff8SPoul-Henning Kamp 
14271e4fff8SPoul-Henning Kamp 	if (md_debug > 1)
1438177437dSPoul-Henning Kamp 		printf("mdstrategy(%p) %s %x, %d, %ld, %p)\n",
1448177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
1458177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
14671e4fff8SPoul-Henning Kamp 
1478177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
14871e4fff8SPoul-Henning Kamp 	if (sc->type == MD_MALLOC) {
14971e4fff8SPoul-Henning Kamp 		mdstrategy_malloc(bp);
15071e4fff8SPoul-Henning Kamp 	} else {
15171e4fff8SPoul-Henning Kamp 		mdstrategy_preload(bp);
15271e4fff8SPoul-Henning Kamp 	}
15371e4fff8SPoul-Henning Kamp 	return;
15471e4fff8SPoul-Henning Kamp }
15571e4fff8SPoul-Henning Kamp 
15671e4fff8SPoul-Henning Kamp 
15771e4fff8SPoul-Henning Kamp static void
1588177437dSPoul-Henning Kamp mdstrategy_malloc(struct bio *bp)
15971e4fff8SPoul-Henning Kamp {
16000a6a3c6SPoul-Henning Kamp 	int s, i;
16100a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
16200a6a3c6SPoul-Henning Kamp 	devstat_trans_flags dop;
16300a6a3c6SPoul-Henning Kamp 	u_char *secp, **secpp, *dst;
16400a6a3c6SPoul-Henning Kamp 	unsigned secno, nsec, secval, uc;
16500a6a3c6SPoul-Henning Kamp 
16600a6a3c6SPoul-Henning Kamp 	if (md_debug > 1)
1678177437dSPoul-Henning Kamp 		printf("mdstrategy_malloc(%p) %s %x, %d, %ld, %p)\n",
1688177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
1698177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
17000a6a3c6SPoul-Henning Kamp 
1718177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
17200a6a3c6SPoul-Henning Kamp 
17300a6a3c6SPoul-Henning Kamp 	s = splbio();
17400a6a3c6SPoul-Henning Kamp 
1758177437dSPoul-Henning Kamp 	bioqdisksort(&sc->bio_queue, bp);
17600a6a3c6SPoul-Henning Kamp 
17700a6a3c6SPoul-Henning Kamp 	if (sc->busy) {
17800a6a3c6SPoul-Henning Kamp 		splx(s);
17900a6a3c6SPoul-Henning Kamp 		return;
18000a6a3c6SPoul-Henning Kamp 	}
18100a6a3c6SPoul-Henning Kamp 
18200a6a3c6SPoul-Henning Kamp 	sc->busy++;
18300a6a3c6SPoul-Henning Kamp 
18400a6a3c6SPoul-Henning Kamp 	while (1) {
1858177437dSPoul-Henning Kamp 		bp = bioq_first(&sc->bio_queue);
18600a6a3c6SPoul-Henning Kamp 		if (bp)
1878177437dSPoul-Henning Kamp 			bioq_remove(&sc->bio_queue, bp);
18800a6a3c6SPoul-Henning Kamp 		splx(s);
18900a6a3c6SPoul-Henning Kamp 		if (!bp)
19000a6a3c6SPoul-Henning Kamp 			break;
19100a6a3c6SPoul-Henning Kamp 
19200a6a3c6SPoul-Henning Kamp 		devstat_start_transaction(&sc->stats);
19300a6a3c6SPoul-Henning Kamp 
1948177437dSPoul-Henning Kamp 		if (bp->bio_cmd == BIO_DELETE)
19500a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_NO_DATA;
1968177437dSPoul-Henning Kamp 		else if (bp->bio_cmd == BIO_READ)
19700a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_READ;
19800a6a3c6SPoul-Henning Kamp 		else
19900a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_WRITE;
20000a6a3c6SPoul-Henning Kamp 
2018177437dSPoul-Henning Kamp 		nsec = bp->bio_bcount / DEV_BSIZE;
2028177437dSPoul-Henning Kamp 		secno = bp->bio_pblkno;
2038177437dSPoul-Henning Kamp 		dst = bp->bio_data;
20400a6a3c6SPoul-Henning Kamp 		while (nsec--) {
20500a6a3c6SPoul-Henning Kamp 
20600a6a3c6SPoul-Henning Kamp 			if (secno < sc->nsecp) {
20700a6a3c6SPoul-Henning Kamp 				secpp = &sc->secp[secno];
20833edfabeSPoul-Henning Kamp 				if ((u_int)*secpp > 255) {
20900a6a3c6SPoul-Henning Kamp 					secp = *secpp;
21000a6a3c6SPoul-Henning Kamp 					secval = 0;
21100a6a3c6SPoul-Henning Kamp 				} else {
21200a6a3c6SPoul-Henning Kamp 					secp = 0;
21333edfabeSPoul-Henning Kamp 					secval = (u_int) *secpp;
21400a6a3c6SPoul-Henning Kamp 				}
21500a6a3c6SPoul-Henning Kamp 			} else {
21600a6a3c6SPoul-Henning Kamp 				secpp = 0;
21700a6a3c6SPoul-Henning Kamp 				secp = 0;
21800a6a3c6SPoul-Henning Kamp 				secval = 0;
21900a6a3c6SPoul-Henning Kamp 			}
22033edfabeSPoul-Henning Kamp 			if (md_debug > 2)
2218177437dSPoul-Henning Kamp 				printf("%x %p %p %d\n",
2228177437dSPoul-Henning Kamp 				    bp->bio_flags, secpp, secp, secval);
22300a6a3c6SPoul-Henning Kamp 
2248177437dSPoul-Henning Kamp 			if (bp->bio_cmd == BIO_DELETE) {
22500a6a3c6SPoul-Henning Kamp 				if (secpp) {
22600a6a3c6SPoul-Henning Kamp 					if (secp)
22700a6a3c6SPoul-Henning Kamp 						FREE(secp, M_MDSECT);
22800a6a3c6SPoul-Henning Kamp 					*secpp = 0;
22900a6a3c6SPoul-Henning Kamp 				}
2308177437dSPoul-Henning Kamp 			} else if (bp->bio_cmd == BIO_READ) {
23100a6a3c6SPoul-Henning Kamp 				if (secp) {
23200a6a3c6SPoul-Henning Kamp 					bcopy(secp, dst, DEV_BSIZE);
23300a6a3c6SPoul-Henning Kamp 				} else if (secval) {
23400a6a3c6SPoul-Henning Kamp 					for (i = 0; i < DEV_BSIZE; i++)
23500a6a3c6SPoul-Henning Kamp 						dst[i] = secval;
23600a6a3c6SPoul-Henning Kamp 				} else {
23700a6a3c6SPoul-Henning Kamp 					bzero(dst, DEV_BSIZE);
23800a6a3c6SPoul-Henning Kamp 				}
23900a6a3c6SPoul-Henning Kamp 			} else {
24000a6a3c6SPoul-Henning Kamp 				uc = dst[0];
24100a6a3c6SPoul-Henning Kamp 				for (i = 1; i < DEV_BSIZE; i++)
24200a6a3c6SPoul-Henning Kamp 					if (dst[i] != uc)
24300a6a3c6SPoul-Henning Kamp 						break;
24400a6a3c6SPoul-Henning Kamp 				if (i == DEV_BSIZE && !uc) {
24500a6a3c6SPoul-Henning Kamp 					if (secp)
24600a6a3c6SPoul-Henning Kamp 						FREE(secp, M_MDSECT);
24700a6a3c6SPoul-Henning Kamp 					if (secpp)
24800a6a3c6SPoul-Henning Kamp 						*secpp = (u_char *)uc;
24900a6a3c6SPoul-Henning Kamp 				} else {
25000a6a3c6SPoul-Henning Kamp 					if (!secpp) {
25100a6a3c6SPoul-Henning Kamp 						MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
25200a6a3c6SPoul-Henning Kamp 						bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
25300a6a3c6SPoul-Henning Kamp 						bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
25400a6a3c6SPoul-Henning Kamp 						FREE(sc->secp, M_MD);
25500a6a3c6SPoul-Henning Kamp 						sc->secp = secpp;
25600a6a3c6SPoul-Henning Kamp 						sc->nsecp = secno + nsec + 1;
25700a6a3c6SPoul-Henning Kamp 						secpp = &sc->secp[secno];
25800a6a3c6SPoul-Henning Kamp 					}
25900a6a3c6SPoul-Henning Kamp 					if (i == DEV_BSIZE) {
26000a6a3c6SPoul-Henning Kamp 						if (secp)
26100a6a3c6SPoul-Henning Kamp 							FREE(secp, M_MDSECT);
26200a6a3c6SPoul-Henning Kamp 						*secpp = (u_char *)uc;
26300a6a3c6SPoul-Henning Kamp 					} else {
26400a6a3c6SPoul-Henning Kamp 						if (!secp)
26500a6a3c6SPoul-Henning Kamp 							MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
26600a6a3c6SPoul-Henning Kamp 						bcopy(dst, secp, DEV_BSIZE);
26700a6a3c6SPoul-Henning Kamp 
26800a6a3c6SPoul-Henning Kamp 						*secpp = secp;
26900a6a3c6SPoul-Henning Kamp 					}
27000a6a3c6SPoul-Henning Kamp 				}
27100a6a3c6SPoul-Henning Kamp 			}
27200a6a3c6SPoul-Henning Kamp 			secno++;
27300a6a3c6SPoul-Henning Kamp 			dst += DEV_BSIZE;
27400a6a3c6SPoul-Henning Kamp 		}
2758177437dSPoul-Henning Kamp 		bp->bio_resid = 0;
2768177437dSPoul-Henning Kamp 		devstat_end_transaction_bio(&sc->stats, bp);
27700a6a3c6SPoul-Henning Kamp 		biodone(bp);
27800a6a3c6SPoul-Henning Kamp 		s = splbio();
27900a6a3c6SPoul-Henning Kamp 	}
28000a6a3c6SPoul-Henning Kamp 	sc->busy = 0;
28100a6a3c6SPoul-Henning Kamp 	return;
28200a6a3c6SPoul-Henning Kamp }
28300a6a3c6SPoul-Henning Kamp 
28471e4fff8SPoul-Henning Kamp 
28595f1a897SPoul-Henning Kamp static void
2868177437dSPoul-Henning Kamp mdstrategy_preload(struct bio *bp)
28771e4fff8SPoul-Henning Kamp {
28871e4fff8SPoul-Henning Kamp 	int s;
28971e4fff8SPoul-Henning Kamp 	struct md_s *sc;
29071e4fff8SPoul-Henning Kamp 	devstat_trans_flags dop;
29171e4fff8SPoul-Henning Kamp 
29271e4fff8SPoul-Henning Kamp 	if (md_debug > 1)
2938177437dSPoul-Henning Kamp 		printf("mdstrategy_preload(%p) %s %x, %d, %ld, %p)\n",
2948177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
2958177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
29671e4fff8SPoul-Henning Kamp 
2978177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
29871e4fff8SPoul-Henning Kamp 
29971e4fff8SPoul-Henning Kamp 	s = splbio();
30071e4fff8SPoul-Henning Kamp 
3018177437dSPoul-Henning Kamp 	bioqdisksort(&sc->bio_queue, bp);
30271e4fff8SPoul-Henning Kamp 
30371e4fff8SPoul-Henning Kamp 	if (sc->busy) {
30471e4fff8SPoul-Henning Kamp 		splx(s);
30571e4fff8SPoul-Henning Kamp 		return;
30671e4fff8SPoul-Henning Kamp 	}
30771e4fff8SPoul-Henning Kamp 
30871e4fff8SPoul-Henning Kamp 	sc->busy++;
30971e4fff8SPoul-Henning Kamp 
31071e4fff8SPoul-Henning Kamp 	while (1) {
3118177437dSPoul-Henning Kamp 		bp = bioq_first(&sc->bio_queue);
31271e4fff8SPoul-Henning Kamp 		if (bp)
3138177437dSPoul-Henning Kamp 			bioq_remove(&sc->bio_queue, bp);
31471e4fff8SPoul-Henning Kamp 		splx(s);
31571e4fff8SPoul-Henning Kamp 		if (!bp)
31671e4fff8SPoul-Henning Kamp 			break;
31771e4fff8SPoul-Henning Kamp 
31871e4fff8SPoul-Henning Kamp 		devstat_start_transaction(&sc->stats);
31971e4fff8SPoul-Henning Kamp 
3208177437dSPoul-Henning Kamp 		if (bp->bio_cmd == BIO_DELETE) {
32171e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_NO_DATA;
3228177437dSPoul-Henning Kamp 		} else if (bp->bio_cmd == BIO_READ) {
32371e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_READ;
3248177437dSPoul-Henning Kamp 			bcopy(sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_data, bp->bio_bcount);
32571e4fff8SPoul-Henning Kamp 		} else {
32671e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_WRITE;
3278177437dSPoul-Henning Kamp 			bcopy(bp->bio_data, sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_bcount);
32871e4fff8SPoul-Henning Kamp 		}
3298177437dSPoul-Henning Kamp 		bp->bio_resid = 0;
3308177437dSPoul-Henning Kamp 		devstat_end_transaction_bio(&sc->stats, bp);
33171e4fff8SPoul-Henning Kamp 		biodone(bp);
33271e4fff8SPoul-Henning Kamp 		s = splbio();
33371e4fff8SPoul-Henning Kamp 	}
33471e4fff8SPoul-Henning Kamp 	sc->busy = 0;
33571e4fff8SPoul-Henning Kamp 	return;
33671e4fff8SPoul-Henning Kamp }
33771e4fff8SPoul-Henning Kamp 
33871e4fff8SPoul-Henning Kamp static struct md_s *
33971e4fff8SPoul-Henning Kamp mdcreate(struct cdevsw *devsw)
34000a6a3c6SPoul-Henning Kamp {
34100a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
34200a6a3c6SPoul-Henning Kamp 
34300a6a3c6SPoul-Henning Kamp 	MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
34400a6a3c6SPoul-Henning Kamp 	bzero(sc, sizeof(*sc));
34500a6a3c6SPoul-Henning Kamp 	sc->unit = mdunits++;
3468177437dSPoul-Henning Kamp 	bioq_init(&sc->bio_queue);
34795f1a897SPoul-Henning Kamp 	devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
34895f1a897SPoul-Henning Kamp 		DEVSTAT_NO_ORDERED_TAGS,
34971e4fff8SPoul-Henning Kamp 		DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
35071e4fff8SPoul-Henning Kamp 		DEVSTAT_PRIORITY_OTHER);
35171e4fff8SPoul-Henning Kamp 	sc->dev = disk_create(sc->unit, &sc->disk, 0, devsw, &sc->devsw);
35295f1a897SPoul-Henning Kamp 	sc->dev->si_drv1 = sc;
35371e4fff8SPoul-Henning Kamp 	return (sc);
35471e4fff8SPoul-Henning Kamp }
35571e4fff8SPoul-Henning Kamp 
35671e4fff8SPoul-Henning Kamp static void
35771e4fff8SPoul-Henning Kamp mdcreate_preload(u_char *image, unsigned length)
35871e4fff8SPoul-Henning Kamp {
35971e4fff8SPoul-Henning Kamp 	struct md_s *sc;
36071e4fff8SPoul-Henning Kamp 
36171e4fff8SPoul-Henning Kamp 	sc = mdcreate(&md_cdevsw);
36266c16191SPoul-Henning Kamp 	sc->type = MD_PRELOAD;
36395f1a897SPoul-Henning Kamp 	sc->nsect = length / DEV_BSIZE;
36495f1a897SPoul-Henning Kamp 	sc->pl_ptr = image;
36595f1a897SPoul-Henning Kamp 	sc->pl_len = length;
36671e4fff8SPoul-Henning Kamp 
36771e4fff8SPoul-Henning Kamp 	if (sc->unit == 0)
36871e4fff8SPoul-Henning Kamp 		mdrootready = 1;
36995f1a897SPoul-Henning Kamp }
37095f1a897SPoul-Henning Kamp 
37195f1a897SPoul-Henning Kamp static void
37295f1a897SPoul-Henning Kamp mdcreate_malloc(void)
37395f1a897SPoul-Henning Kamp {
37495f1a897SPoul-Henning Kamp 	struct md_s *sc;
37595f1a897SPoul-Henning Kamp 
37671e4fff8SPoul-Henning Kamp 	sc = mdcreate(&md_cdevsw);
37766c16191SPoul-Henning Kamp 	sc->type = MD_MALLOC;
37800a6a3c6SPoul-Henning Kamp 
37933edfabeSPoul-Henning Kamp 	sc->nsect = MDNSECT;	/* for now */
38000a6a3c6SPoul-Henning Kamp 	MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
38100a6a3c6SPoul-Henning Kamp 	bzero(sc->secp, sizeof(u_char *));
38200a6a3c6SPoul-Henning Kamp 	sc->nsecp = 1;
38300a6a3c6SPoul-Henning Kamp }
38400a6a3c6SPoul-Henning Kamp 
38500a6a3c6SPoul-Henning Kamp static void
38600a6a3c6SPoul-Henning Kamp md_drvinit(void *unused)
38700a6a3c6SPoul-Henning Kamp {
38800a6a3c6SPoul-Henning Kamp 
38995f1a897SPoul-Henning Kamp 	caddr_t mod;
39095f1a897SPoul-Henning Kamp 	caddr_t c;
39195f1a897SPoul-Henning Kamp 	u_char *ptr, *name, *type;
39295f1a897SPoul-Henning Kamp 	unsigned len;
39395f1a897SPoul-Henning Kamp 
39471e4fff8SPoul-Henning Kamp #ifdef MD_ROOT_SIZE
39571e4fff8SPoul-Henning Kamp 	mdcreate_preload(mfs_root, MD_ROOT_SIZE*1024);
39671e4fff8SPoul-Henning Kamp #endif
39795f1a897SPoul-Henning Kamp 	mod = NULL;
39895f1a897SPoul-Henning Kamp 	while ((mod = preload_search_next_name(mod)) != NULL) {
39995f1a897SPoul-Henning Kamp 		name = (char *)preload_search_info(mod, MODINFO_NAME);
40095f1a897SPoul-Henning Kamp 		type = (char *)preload_search_info(mod, MODINFO_TYPE);
40195f1a897SPoul-Henning Kamp 		if (name == NULL)
40295f1a897SPoul-Henning Kamp 			continue;
40395f1a897SPoul-Henning Kamp 		if (type == NULL)
40495f1a897SPoul-Henning Kamp 			continue;
40571e4fff8SPoul-Henning Kamp 		if (strcmp(type, "md_image") && strcmp(type, "mfs_root"))
40695f1a897SPoul-Henning Kamp 			continue;
40795f1a897SPoul-Henning Kamp 		c = preload_search_info(mod, MODINFO_ADDR);
40895f1a897SPoul-Henning Kamp 		ptr = *(u_char **)c;
40995f1a897SPoul-Henning Kamp 		c = preload_search_info(mod, MODINFO_SIZE);
41095f1a897SPoul-Henning Kamp 		len = *(unsigned *)c;
41195f1a897SPoul-Henning Kamp 		printf("md%d: Preloaded image <%s> %d bytes at %p\n",
41295f1a897SPoul-Henning Kamp 		   mdunits, name, len, ptr);
41395f1a897SPoul-Henning Kamp 		mdcreate_preload(ptr, len);
41495f1a897SPoul-Henning Kamp 	}
41566c16191SPoul-Henning Kamp 	printf("md%d: Malloc disk\n", mdunits);
41695f1a897SPoul-Henning Kamp 	mdcreate_malloc();
41700a6a3c6SPoul-Henning Kamp }
41800a6a3c6SPoul-Henning Kamp 
41971e4fff8SPoul-Henning Kamp SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
42000a6a3c6SPoul-Henning Kamp 
42171e4fff8SPoul-Henning Kamp #ifdef MD_ROOT
42271e4fff8SPoul-Henning Kamp static void
42371e4fff8SPoul-Henning Kamp md_takeroot(void *junk)
42471e4fff8SPoul-Henning Kamp {
42571e4fff8SPoul-Henning Kamp 	if (mdrootready)
42671e4fff8SPoul-Henning Kamp 		rootdevnames[0] = "ufs:/dev/md0c";
42771e4fff8SPoul-Henning Kamp }
42871e4fff8SPoul-Henning Kamp 
42971e4fff8SPoul-Henning Kamp SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
43071e4fff8SPoul-Henning Kamp #endif
431