xref: /freebsd/sys/dev/md/md.c (revision f274479332fd8fe2f5aaf9ee55e388d6b1f46745)
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 
27f2744793SSheldon Hearn #ifndef MD_NSECT
28f2744793SSheldon Hearn #define MD_NSECT (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 
550cfaeeeeSPoul-Henning Kamp static void mdcreate_malloc(void);
560cfaeeeeSPoul-Henning Kamp 
5700a6a3c6SPoul-Henning Kamp #define CDEV_MAJOR	95
5800a6a3c6SPoul-Henning Kamp #define BDEV_MAJOR	22
5900a6a3c6SPoul-Henning Kamp 
6000a6a3c6SPoul-Henning Kamp static d_strategy_t mdstrategy;
6171e4fff8SPoul-Henning Kamp static d_strategy_t mdstrategy_preload;
6271e4fff8SPoul-Henning Kamp static d_strategy_t mdstrategy_malloc;
6300a6a3c6SPoul-Henning Kamp static d_open_t mdopen;
6400a6a3c6SPoul-Henning Kamp static d_ioctl_t mdioctl;
6500a6a3c6SPoul-Henning Kamp 
6600a6a3c6SPoul-Henning Kamp static struct cdevsw md_cdevsw = {
6700a6a3c6SPoul-Henning Kamp         /* open */      mdopen,
6800a6a3c6SPoul-Henning Kamp         /* close */     nullclose,
6900a6a3c6SPoul-Henning Kamp         /* read */      physread,
7000a6a3c6SPoul-Henning Kamp         /* write */     physwrite,
7100a6a3c6SPoul-Henning Kamp         /* ioctl */     mdioctl,
7200a6a3c6SPoul-Henning Kamp         /* poll */      nopoll,
7300a6a3c6SPoul-Henning Kamp         /* mmap */      nommap,
7400a6a3c6SPoul-Henning Kamp         /* strategy */  mdstrategy,
7500a6a3c6SPoul-Henning Kamp         /* name */      "md",
7600a6a3c6SPoul-Henning Kamp         /* maj */       CDEV_MAJOR,
7700a6a3c6SPoul-Henning Kamp         /* dump */      nodump,
7800a6a3c6SPoul-Henning Kamp         /* psize */     nopsize,
7971e4fff8SPoul-Henning Kamp         /* flags */     D_DISK | D_CANFREE | D_MEMDISK,
8000a6a3c6SPoul-Henning Kamp         /* bmaj */      BDEV_MAJOR
8100a6a3c6SPoul-Henning Kamp };
8200a6a3c6SPoul-Henning Kamp 
830cfaeeeeSPoul-Henning Kamp static struct cdevsw mddisk_cdevsw;
840cfaeeeeSPoul-Henning Kamp 
8500a6a3c6SPoul-Henning Kamp struct md_s {
8600a6a3c6SPoul-Henning Kamp 	int unit;
8700a6a3c6SPoul-Henning Kamp 	struct devstat stats;
888177437dSPoul-Henning Kamp 	struct bio_queue_head bio_queue;
8900a6a3c6SPoul-Henning Kamp 	struct disk disk;
9000a6a3c6SPoul-Henning Kamp 	dev_t dev;
9195f1a897SPoul-Henning Kamp 	int busy;
9295f1a897SPoul-Henning Kamp 	enum {MD_MALLOC, MD_PRELOAD} type;
9300a6a3c6SPoul-Henning Kamp 	unsigned nsect;
9495f1a897SPoul-Henning Kamp 
9595f1a897SPoul-Henning Kamp 	/* MD_MALLOC related fields */
9600a6a3c6SPoul-Henning Kamp 	unsigned nsecp;
9700a6a3c6SPoul-Henning Kamp 	u_char **secp;
9800a6a3c6SPoul-Henning Kamp 
9995f1a897SPoul-Henning Kamp 	/* MD_PRELOAD related fields */
10095f1a897SPoul-Henning Kamp 	u_char *pl_ptr;
10195f1a897SPoul-Henning Kamp 	unsigned pl_len;
10200a6a3c6SPoul-Henning Kamp };
10300a6a3c6SPoul-Henning Kamp 
10400a6a3c6SPoul-Henning Kamp static int mdunits;
10500a6a3c6SPoul-Henning Kamp 
10600a6a3c6SPoul-Henning Kamp static int
10700a6a3c6SPoul-Henning Kamp mdopen(dev_t dev, int flag, int fmt, struct proc *p)
10800a6a3c6SPoul-Henning Kamp {
10900a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
11000a6a3c6SPoul-Henning Kamp 	struct disklabel *dl;
11100a6a3c6SPoul-Henning Kamp 
11200a6a3c6SPoul-Henning Kamp 	if (md_debug)
11300a6a3c6SPoul-Henning Kamp 		printf("mdopen(%s %x %x %p)\n",
11400a6a3c6SPoul-Henning Kamp 			devtoname(dev), flag, fmt, p);
11500a6a3c6SPoul-Henning Kamp 
11600a6a3c6SPoul-Henning Kamp 	sc = dev->si_drv1;
1170cfaeeeeSPoul-Henning Kamp 	if (sc->unit + 1 == mdunits)
1180cfaeeeeSPoul-Henning Kamp 		mdcreate_malloc();
11900a6a3c6SPoul-Henning Kamp 
12000a6a3c6SPoul-Henning Kamp 	dl = &sc->disk.d_label;
12100a6a3c6SPoul-Henning Kamp 	bzero(dl, sizeof(*dl));
12200a6a3c6SPoul-Henning Kamp 	dl->d_secsize = DEV_BSIZE;
12300a6a3c6SPoul-Henning Kamp 	dl->d_nsectors = 1024;
12400a6a3c6SPoul-Henning Kamp 	dl->d_ntracks = 1;
12595f1a897SPoul-Henning Kamp 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
12600a6a3c6SPoul-Henning Kamp 	dl->d_secperunit = sc->nsect;
12700a6a3c6SPoul-Henning Kamp 	dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
12800a6a3c6SPoul-Henning Kamp 	return (0);
12900a6a3c6SPoul-Henning Kamp }
13000a6a3c6SPoul-Henning Kamp 
13100a6a3c6SPoul-Henning Kamp static int
13200a6a3c6SPoul-Henning Kamp mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
13300a6a3c6SPoul-Henning Kamp {
13400a6a3c6SPoul-Henning Kamp 
13500a6a3c6SPoul-Henning Kamp 	if (md_debug)
13600a6a3c6SPoul-Henning Kamp 		printf("mdioctl(%s %lx %p %x %p)\n",
13700a6a3c6SPoul-Henning Kamp 			devtoname(dev), cmd, addr, flags, p);
13800a6a3c6SPoul-Henning Kamp 
13900a6a3c6SPoul-Henning Kamp 	return (ENOIOCTL);
14000a6a3c6SPoul-Henning Kamp }
14100a6a3c6SPoul-Henning Kamp 
14200a6a3c6SPoul-Henning Kamp static void
1438177437dSPoul-Henning Kamp mdstrategy(struct bio *bp)
14400a6a3c6SPoul-Henning Kamp {
14571e4fff8SPoul-Henning Kamp 	struct md_s *sc;
14671e4fff8SPoul-Henning Kamp 
14771e4fff8SPoul-Henning Kamp 	if (md_debug > 1)
1488177437dSPoul-Henning Kamp 		printf("mdstrategy(%p) %s %x, %d, %ld, %p)\n",
1498177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
1508177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
15171e4fff8SPoul-Henning Kamp 
1528177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
15371e4fff8SPoul-Henning Kamp 	if (sc->type == MD_MALLOC) {
15471e4fff8SPoul-Henning Kamp 		mdstrategy_malloc(bp);
15571e4fff8SPoul-Henning Kamp 	} else {
15671e4fff8SPoul-Henning Kamp 		mdstrategy_preload(bp);
15771e4fff8SPoul-Henning Kamp 	}
15871e4fff8SPoul-Henning Kamp 	return;
15971e4fff8SPoul-Henning Kamp }
16071e4fff8SPoul-Henning Kamp 
16171e4fff8SPoul-Henning Kamp 
16271e4fff8SPoul-Henning Kamp static void
1638177437dSPoul-Henning Kamp mdstrategy_malloc(struct bio *bp)
16471e4fff8SPoul-Henning Kamp {
16500a6a3c6SPoul-Henning Kamp 	int s, i;
16600a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
16700a6a3c6SPoul-Henning Kamp 	devstat_trans_flags dop;
16800a6a3c6SPoul-Henning Kamp 	u_char *secp, **secpp, *dst;
16900a6a3c6SPoul-Henning Kamp 	unsigned secno, nsec, secval, uc;
17000a6a3c6SPoul-Henning Kamp 
17100a6a3c6SPoul-Henning Kamp 	if (md_debug > 1)
1728177437dSPoul-Henning Kamp 		printf("mdstrategy_malloc(%p) %s %x, %d, %ld, %p)\n",
1738177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
1748177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
17500a6a3c6SPoul-Henning Kamp 
1768177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
17700a6a3c6SPoul-Henning Kamp 
17800a6a3c6SPoul-Henning Kamp 	s = splbio();
17900a6a3c6SPoul-Henning Kamp 
1808177437dSPoul-Henning Kamp 	bioqdisksort(&sc->bio_queue, bp);
18100a6a3c6SPoul-Henning Kamp 
18200a6a3c6SPoul-Henning Kamp 	if (sc->busy) {
18300a6a3c6SPoul-Henning Kamp 		splx(s);
18400a6a3c6SPoul-Henning Kamp 		return;
18500a6a3c6SPoul-Henning Kamp 	}
18600a6a3c6SPoul-Henning Kamp 
18700a6a3c6SPoul-Henning Kamp 	sc->busy++;
18800a6a3c6SPoul-Henning Kamp 
18900a6a3c6SPoul-Henning Kamp 	while (1) {
1908177437dSPoul-Henning Kamp 		bp = bioq_first(&sc->bio_queue);
19100a6a3c6SPoul-Henning Kamp 		if (bp)
1928177437dSPoul-Henning Kamp 			bioq_remove(&sc->bio_queue, bp);
19300a6a3c6SPoul-Henning Kamp 		splx(s);
19400a6a3c6SPoul-Henning Kamp 		if (!bp)
19500a6a3c6SPoul-Henning Kamp 			break;
19600a6a3c6SPoul-Henning Kamp 
19700a6a3c6SPoul-Henning Kamp 		devstat_start_transaction(&sc->stats);
19800a6a3c6SPoul-Henning Kamp 
1998177437dSPoul-Henning Kamp 		if (bp->bio_cmd == BIO_DELETE)
20000a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_NO_DATA;
2018177437dSPoul-Henning Kamp 		else if (bp->bio_cmd == BIO_READ)
20200a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_READ;
20300a6a3c6SPoul-Henning Kamp 		else
20400a6a3c6SPoul-Henning Kamp 			dop = DEVSTAT_WRITE;
20500a6a3c6SPoul-Henning Kamp 
2068177437dSPoul-Henning Kamp 		nsec = bp->bio_bcount / DEV_BSIZE;
2078177437dSPoul-Henning Kamp 		secno = bp->bio_pblkno;
2088177437dSPoul-Henning Kamp 		dst = bp->bio_data;
20900a6a3c6SPoul-Henning Kamp 		while (nsec--) {
21000a6a3c6SPoul-Henning Kamp 
21100a6a3c6SPoul-Henning Kamp 			if (secno < sc->nsecp) {
21200a6a3c6SPoul-Henning Kamp 				secpp = &sc->secp[secno];
21333edfabeSPoul-Henning Kamp 				if ((u_int)*secpp > 255) {
21400a6a3c6SPoul-Henning Kamp 					secp = *secpp;
21500a6a3c6SPoul-Henning Kamp 					secval = 0;
21600a6a3c6SPoul-Henning Kamp 				} else {
21700a6a3c6SPoul-Henning Kamp 					secp = 0;
21833edfabeSPoul-Henning Kamp 					secval = (u_int) *secpp;
21900a6a3c6SPoul-Henning Kamp 				}
22000a6a3c6SPoul-Henning Kamp 			} else {
22100a6a3c6SPoul-Henning Kamp 				secpp = 0;
22200a6a3c6SPoul-Henning Kamp 				secp = 0;
22300a6a3c6SPoul-Henning Kamp 				secval = 0;
22400a6a3c6SPoul-Henning Kamp 			}
22533edfabeSPoul-Henning Kamp 			if (md_debug > 2)
2268177437dSPoul-Henning Kamp 				printf("%x %p %p %d\n",
2278177437dSPoul-Henning Kamp 				    bp->bio_flags, secpp, secp, secval);
22800a6a3c6SPoul-Henning Kamp 
2298177437dSPoul-Henning Kamp 			if (bp->bio_cmd == BIO_DELETE) {
23000a6a3c6SPoul-Henning Kamp 				if (secpp) {
23100a6a3c6SPoul-Henning Kamp 					if (secp)
23200a6a3c6SPoul-Henning Kamp 						FREE(secp, M_MDSECT);
23300a6a3c6SPoul-Henning Kamp 					*secpp = 0;
23400a6a3c6SPoul-Henning Kamp 				}
2358177437dSPoul-Henning Kamp 			} else if (bp->bio_cmd == BIO_READ) {
23600a6a3c6SPoul-Henning Kamp 				if (secp) {
23700a6a3c6SPoul-Henning Kamp 					bcopy(secp, dst, DEV_BSIZE);
23800a6a3c6SPoul-Henning Kamp 				} else if (secval) {
23900a6a3c6SPoul-Henning Kamp 					for (i = 0; i < DEV_BSIZE; i++)
24000a6a3c6SPoul-Henning Kamp 						dst[i] = secval;
24100a6a3c6SPoul-Henning Kamp 				} else {
24200a6a3c6SPoul-Henning Kamp 					bzero(dst, DEV_BSIZE);
24300a6a3c6SPoul-Henning Kamp 				}
24400a6a3c6SPoul-Henning Kamp 			} else {
24500a6a3c6SPoul-Henning Kamp 				uc = dst[0];
24600a6a3c6SPoul-Henning Kamp 				for (i = 1; i < DEV_BSIZE; i++)
24700a6a3c6SPoul-Henning Kamp 					if (dst[i] != uc)
24800a6a3c6SPoul-Henning Kamp 						break;
24900a6a3c6SPoul-Henning Kamp 				if (i == DEV_BSIZE && !uc) {
25000a6a3c6SPoul-Henning Kamp 					if (secp)
25100a6a3c6SPoul-Henning Kamp 						FREE(secp, M_MDSECT);
25200a6a3c6SPoul-Henning Kamp 					if (secpp)
25300a6a3c6SPoul-Henning Kamp 						*secpp = (u_char *)uc;
25400a6a3c6SPoul-Henning Kamp 				} else {
25500a6a3c6SPoul-Henning Kamp 					if (!secpp) {
25600a6a3c6SPoul-Henning Kamp 						MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
25700a6a3c6SPoul-Henning Kamp 						bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
25800a6a3c6SPoul-Henning Kamp 						bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
25900a6a3c6SPoul-Henning Kamp 						FREE(sc->secp, M_MD);
26000a6a3c6SPoul-Henning Kamp 						sc->secp = secpp;
26100a6a3c6SPoul-Henning Kamp 						sc->nsecp = secno + nsec + 1;
26200a6a3c6SPoul-Henning Kamp 						secpp = &sc->secp[secno];
26300a6a3c6SPoul-Henning Kamp 					}
26400a6a3c6SPoul-Henning Kamp 					if (i == DEV_BSIZE) {
26500a6a3c6SPoul-Henning Kamp 						if (secp)
26600a6a3c6SPoul-Henning Kamp 							FREE(secp, M_MDSECT);
26700a6a3c6SPoul-Henning Kamp 						*secpp = (u_char *)uc;
26800a6a3c6SPoul-Henning Kamp 					} else {
26900a6a3c6SPoul-Henning Kamp 						if (!secp)
27000a6a3c6SPoul-Henning Kamp 							MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
27100a6a3c6SPoul-Henning Kamp 						bcopy(dst, secp, DEV_BSIZE);
27200a6a3c6SPoul-Henning Kamp 
27300a6a3c6SPoul-Henning Kamp 						*secpp = secp;
27400a6a3c6SPoul-Henning Kamp 					}
27500a6a3c6SPoul-Henning Kamp 				}
27600a6a3c6SPoul-Henning Kamp 			}
27700a6a3c6SPoul-Henning Kamp 			secno++;
27800a6a3c6SPoul-Henning Kamp 			dst += DEV_BSIZE;
27900a6a3c6SPoul-Henning Kamp 		}
2808177437dSPoul-Henning Kamp 		bp->bio_resid = 0;
2818177437dSPoul-Henning Kamp 		devstat_end_transaction_bio(&sc->stats, bp);
28200a6a3c6SPoul-Henning Kamp 		biodone(bp);
28300a6a3c6SPoul-Henning Kamp 		s = splbio();
28400a6a3c6SPoul-Henning Kamp 	}
28500a6a3c6SPoul-Henning Kamp 	sc->busy = 0;
28600a6a3c6SPoul-Henning Kamp 	return;
28700a6a3c6SPoul-Henning Kamp }
28800a6a3c6SPoul-Henning Kamp 
28971e4fff8SPoul-Henning Kamp 
29095f1a897SPoul-Henning Kamp static void
2918177437dSPoul-Henning Kamp mdstrategy_preload(struct bio *bp)
29271e4fff8SPoul-Henning Kamp {
29371e4fff8SPoul-Henning Kamp 	int s;
29471e4fff8SPoul-Henning Kamp 	struct md_s *sc;
29571e4fff8SPoul-Henning Kamp 	devstat_trans_flags dop;
29671e4fff8SPoul-Henning Kamp 
29771e4fff8SPoul-Henning Kamp 	if (md_debug > 1)
2988177437dSPoul-Henning Kamp 		printf("mdstrategy_preload(%p) %s %x, %d, %ld, %p)\n",
2998177437dSPoul-Henning Kamp 		    bp, devtoname(bp->bio_dev), bp->bio_flags, bp->bio_blkno,
3008177437dSPoul-Henning Kamp 		    bp->bio_bcount / DEV_BSIZE, bp->bio_data);
30171e4fff8SPoul-Henning Kamp 
3028177437dSPoul-Henning Kamp 	sc = bp->bio_dev->si_drv1;
30371e4fff8SPoul-Henning Kamp 
30471e4fff8SPoul-Henning Kamp 	s = splbio();
30571e4fff8SPoul-Henning Kamp 
3068177437dSPoul-Henning Kamp 	bioqdisksort(&sc->bio_queue, bp);
30771e4fff8SPoul-Henning Kamp 
30871e4fff8SPoul-Henning Kamp 	if (sc->busy) {
30971e4fff8SPoul-Henning Kamp 		splx(s);
31071e4fff8SPoul-Henning Kamp 		return;
31171e4fff8SPoul-Henning Kamp 	}
31271e4fff8SPoul-Henning Kamp 
31371e4fff8SPoul-Henning Kamp 	sc->busy++;
31471e4fff8SPoul-Henning Kamp 
31571e4fff8SPoul-Henning Kamp 	while (1) {
3168177437dSPoul-Henning Kamp 		bp = bioq_first(&sc->bio_queue);
31771e4fff8SPoul-Henning Kamp 		if (bp)
3188177437dSPoul-Henning Kamp 			bioq_remove(&sc->bio_queue, bp);
31971e4fff8SPoul-Henning Kamp 		splx(s);
32071e4fff8SPoul-Henning Kamp 		if (!bp)
32171e4fff8SPoul-Henning Kamp 			break;
32271e4fff8SPoul-Henning Kamp 
32371e4fff8SPoul-Henning Kamp 		devstat_start_transaction(&sc->stats);
32471e4fff8SPoul-Henning Kamp 
3258177437dSPoul-Henning Kamp 		if (bp->bio_cmd == BIO_DELETE) {
32671e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_NO_DATA;
3278177437dSPoul-Henning Kamp 		} else if (bp->bio_cmd == BIO_READ) {
32871e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_READ;
3298177437dSPoul-Henning Kamp 			bcopy(sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_data, bp->bio_bcount);
33071e4fff8SPoul-Henning Kamp 		} else {
33171e4fff8SPoul-Henning Kamp 			dop = DEVSTAT_WRITE;
3328177437dSPoul-Henning Kamp 			bcopy(bp->bio_data, sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_bcount);
33371e4fff8SPoul-Henning Kamp 		}
3348177437dSPoul-Henning Kamp 		bp->bio_resid = 0;
3358177437dSPoul-Henning Kamp 		devstat_end_transaction_bio(&sc->stats, bp);
33671e4fff8SPoul-Henning Kamp 		biodone(bp);
33771e4fff8SPoul-Henning Kamp 		s = splbio();
33871e4fff8SPoul-Henning Kamp 	}
33971e4fff8SPoul-Henning Kamp 	sc->busy = 0;
34071e4fff8SPoul-Henning Kamp 	return;
34171e4fff8SPoul-Henning Kamp }
34271e4fff8SPoul-Henning Kamp 
34371e4fff8SPoul-Henning Kamp static struct md_s *
3440cfaeeeeSPoul-Henning Kamp mdcreate(void)
34500a6a3c6SPoul-Henning Kamp {
34600a6a3c6SPoul-Henning Kamp 	struct md_s *sc;
34700a6a3c6SPoul-Henning Kamp 
34800a6a3c6SPoul-Henning Kamp 	MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
34900a6a3c6SPoul-Henning Kamp 	bzero(sc, sizeof(*sc));
35000a6a3c6SPoul-Henning Kamp 	sc->unit = mdunits++;
3518177437dSPoul-Henning Kamp 	bioq_init(&sc->bio_queue);
35295f1a897SPoul-Henning Kamp 	devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
35395f1a897SPoul-Henning Kamp 		DEVSTAT_NO_ORDERED_TAGS,
35471e4fff8SPoul-Henning Kamp 		DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
35571e4fff8SPoul-Henning Kamp 		DEVSTAT_PRIORITY_OTHER);
3560cfaeeeeSPoul-Henning Kamp 	sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw);
35795f1a897SPoul-Henning Kamp 	sc->dev->si_drv1 = sc;
35871e4fff8SPoul-Henning Kamp 	return (sc);
35971e4fff8SPoul-Henning Kamp }
36071e4fff8SPoul-Henning Kamp 
36171e4fff8SPoul-Henning Kamp static void
36271e4fff8SPoul-Henning Kamp mdcreate_preload(u_char *image, unsigned length)
36371e4fff8SPoul-Henning Kamp {
36471e4fff8SPoul-Henning Kamp 	struct md_s *sc;
36571e4fff8SPoul-Henning Kamp 
3660cfaeeeeSPoul-Henning Kamp 	sc = mdcreate();
36766c16191SPoul-Henning Kamp 	sc->type = MD_PRELOAD;
36895f1a897SPoul-Henning Kamp 	sc->nsect = length / DEV_BSIZE;
36995f1a897SPoul-Henning Kamp 	sc->pl_ptr = image;
37095f1a897SPoul-Henning Kamp 	sc->pl_len = length;
37171e4fff8SPoul-Henning Kamp 
37271e4fff8SPoul-Henning Kamp 	if (sc->unit == 0)
37371e4fff8SPoul-Henning Kamp 		mdrootready = 1;
37495f1a897SPoul-Henning Kamp }
37595f1a897SPoul-Henning Kamp 
37695f1a897SPoul-Henning Kamp static void
37795f1a897SPoul-Henning Kamp mdcreate_malloc(void)
37895f1a897SPoul-Henning Kamp {
37995f1a897SPoul-Henning Kamp 	struct md_s *sc;
38095f1a897SPoul-Henning Kamp 
3810cfaeeeeSPoul-Henning Kamp 	sc = mdcreate();
38266c16191SPoul-Henning Kamp 	sc->type = MD_MALLOC;
38300a6a3c6SPoul-Henning Kamp 
384f2744793SSheldon Hearn 	sc->nsect = MD_NSECT;	/* for now */
38500a6a3c6SPoul-Henning Kamp 	MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
38600a6a3c6SPoul-Henning Kamp 	bzero(sc->secp, sizeof(u_char *));
38700a6a3c6SPoul-Henning Kamp 	sc->nsecp = 1;
3880cfaeeeeSPoul-Henning Kamp 	printf("md%d: Malloc disk\n", sc->unit);
38900a6a3c6SPoul-Henning Kamp }
39000a6a3c6SPoul-Henning Kamp 
39100a6a3c6SPoul-Henning Kamp static void
39200a6a3c6SPoul-Henning Kamp md_drvinit(void *unused)
39300a6a3c6SPoul-Henning Kamp {
39400a6a3c6SPoul-Henning Kamp 
39595f1a897SPoul-Henning Kamp 	caddr_t mod;
39695f1a897SPoul-Henning Kamp 	caddr_t c;
39795f1a897SPoul-Henning Kamp 	u_char *ptr, *name, *type;
39895f1a897SPoul-Henning Kamp 	unsigned len;
39995f1a897SPoul-Henning Kamp 
40071e4fff8SPoul-Henning Kamp #ifdef MD_ROOT_SIZE
40171e4fff8SPoul-Henning Kamp 	mdcreate_preload(mfs_root, MD_ROOT_SIZE*1024);
40271e4fff8SPoul-Henning Kamp #endif
40395f1a897SPoul-Henning Kamp 	mod = NULL;
40495f1a897SPoul-Henning Kamp 	while ((mod = preload_search_next_name(mod)) != NULL) {
40595f1a897SPoul-Henning Kamp 		name = (char *)preload_search_info(mod, MODINFO_NAME);
40695f1a897SPoul-Henning Kamp 		type = (char *)preload_search_info(mod, MODINFO_TYPE);
40795f1a897SPoul-Henning Kamp 		if (name == NULL)
40895f1a897SPoul-Henning Kamp 			continue;
40995f1a897SPoul-Henning Kamp 		if (type == NULL)
41095f1a897SPoul-Henning Kamp 			continue;
41171e4fff8SPoul-Henning Kamp 		if (strcmp(type, "md_image") && strcmp(type, "mfs_root"))
41295f1a897SPoul-Henning Kamp 			continue;
41395f1a897SPoul-Henning Kamp 		c = preload_search_info(mod, MODINFO_ADDR);
41495f1a897SPoul-Henning Kamp 		ptr = *(u_char **)c;
41595f1a897SPoul-Henning Kamp 		c = preload_search_info(mod, MODINFO_SIZE);
41695f1a897SPoul-Henning Kamp 		len = *(unsigned *)c;
41795f1a897SPoul-Henning Kamp 		printf("md%d: Preloaded image <%s> %d bytes at %p\n",
41895f1a897SPoul-Henning Kamp 		   mdunits, name, len, ptr);
41995f1a897SPoul-Henning Kamp 		mdcreate_preload(ptr, len);
42095f1a897SPoul-Henning Kamp 	}
42195f1a897SPoul-Henning Kamp 	mdcreate_malloc();
42200a6a3c6SPoul-Henning Kamp }
42300a6a3c6SPoul-Henning Kamp 
42471e4fff8SPoul-Henning Kamp SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
42500a6a3c6SPoul-Henning Kamp 
42671e4fff8SPoul-Henning Kamp #ifdef MD_ROOT
42771e4fff8SPoul-Henning Kamp static void
42871e4fff8SPoul-Henning Kamp md_takeroot(void *junk)
42971e4fff8SPoul-Henning Kamp {
43071e4fff8SPoul-Henning Kamp 	if (mdrootready)
43171e4fff8SPoul-Henning Kamp 		rootdevnames[0] = "ufs:/dev/md0c";
43271e4fff8SPoul-Henning Kamp }
43371e4fff8SPoul-Henning Kamp 
43471e4fff8SPoul-Henning Kamp SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
43571e4fff8SPoul-Henning Kamp #endif
436