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 1300a6a3c6SPoul-Henning Kamp #include <sys/param.h> 1400a6a3c6SPoul-Henning Kamp #include <sys/systm.h> 1500a6a3c6SPoul-Henning Kamp #include <sys/sysctl.h> 1600a6a3c6SPoul-Henning Kamp #include <sys/kernel.h> 1700a6a3c6SPoul-Henning Kamp #include <sys/buf.h> 1800a6a3c6SPoul-Henning Kamp #include <sys/malloc.h> 1900a6a3c6SPoul-Henning Kamp #include <sys/conf.h> 2000a6a3c6SPoul-Henning Kamp #include <sys/disk.h> 2100a6a3c6SPoul-Henning Kamp #include <sys/devicestat.h> 2200a6a3c6SPoul-Henning Kamp #include <sys/module.h> 2300a6a3c6SPoul-Henning Kamp #include <machine/bus.h> 2400a6a3c6SPoul-Henning Kamp #include <machine/clock.h> 2500a6a3c6SPoul-Henning Kamp #include <machine/resource.h> 2600a6a3c6SPoul-Henning Kamp 2700a6a3c6SPoul-Henning Kamp #include <vm/vm.h> 2800a6a3c6SPoul-Henning Kamp #include <vm/pmap.h> 2900a6a3c6SPoul-Henning Kamp #include <vm/vm_param.h> 3000a6a3c6SPoul-Henning Kamp 3100a6a3c6SPoul-Henning Kamp #include <sys/bus.h> 3200a6a3c6SPoul-Henning Kamp #include <isa/isareg.h> 3300a6a3c6SPoul-Henning Kamp #include <isa/isavar.h> 3400a6a3c6SPoul-Henning Kamp 3500a6a3c6SPoul-Henning Kamp MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk"); 3600a6a3c6SPoul-Henning Kamp MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors"); 3700a6a3c6SPoul-Henning Kamp 3800a6a3c6SPoul-Henning Kamp static int md_debug = 0; 3900a6a3c6SPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, ""); 4000a6a3c6SPoul-Henning Kamp 4100a6a3c6SPoul-Henning Kamp #define CDEV_MAJOR 95 4200a6a3c6SPoul-Henning Kamp #define BDEV_MAJOR 22 4300a6a3c6SPoul-Henning Kamp 4400a6a3c6SPoul-Henning Kamp static d_strategy_t mdstrategy; 4500a6a3c6SPoul-Henning Kamp static d_open_t mdopen; 4600a6a3c6SPoul-Henning Kamp static d_ioctl_t mdioctl; 4700a6a3c6SPoul-Henning Kamp 4800a6a3c6SPoul-Henning Kamp static struct cdevsw md_cdevsw = { 4900a6a3c6SPoul-Henning Kamp /* open */ mdopen, 5000a6a3c6SPoul-Henning Kamp /* close */ nullclose, 5100a6a3c6SPoul-Henning Kamp /* read */ physread, 5200a6a3c6SPoul-Henning Kamp /* write */ physwrite, 5300a6a3c6SPoul-Henning Kamp /* ioctl */ mdioctl, 5400a6a3c6SPoul-Henning Kamp /* stop */ nostop, 5500a6a3c6SPoul-Henning Kamp /* reset */ noreset, 5600a6a3c6SPoul-Henning Kamp /* devtotty */ nodevtotty, 5700a6a3c6SPoul-Henning Kamp /* poll */ nopoll, 5800a6a3c6SPoul-Henning Kamp /* mmap */ nommap, 5900a6a3c6SPoul-Henning Kamp /* strategy */ mdstrategy, 6000a6a3c6SPoul-Henning Kamp /* name */ "md", 6100a6a3c6SPoul-Henning Kamp /* parms */ noparms, 6200a6a3c6SPoul-Henning Kamp /* maj */ CDEV_MAJOR, 6300a6a3c6SPoul-Henning Kamp /* dump */ nodump, 6400a6a3c6SPoul-Henning Kamp /* psize */ nopsize, 6500a6a3c6SPoul-Henning Kamp /* flags */ D_DISK | D_CANFREE, 6600a6a3c6SPoul-Henning Kamp /* maxio */ 0, 6700a6a3c6SPoul-Henning Kamp /* bmaj */ BDEV_MAJOR 6800a6a3c6SPoul-Henning Kamp }; 6900a6a3c6SPoul-Henning Kamp static struct cdevsw mddisk_cdevsw; 7000a6a3c6SPoul-Henning Kamp 7100a6a3c6SPoul-Henning Kamp struct md_s { 7200a6a3c6SPoul-Henning Kamp int unit; 7300a6a3c6SPoul-Henning Kamp struct devstat stats; 7400a6a3c6SPoul-Henning Kamp struct buf_queue_head buf_queue; 7500a6a3c6SPoul-Henning Kamp struct disk disk; 7600a6a3c6SPoul-Henning Kamp dev_t dev; 7700a6a3c6SPoul-Henning Kamp unsigned nsect; 7800a6a3c6SPoul-Henning Kamp unsigned nsecp; 7900a6a3c6SPoul-Henning Kamp u_char **secp; 8000a6a3c6SPoul-Henning Kamp 8100a6a3c6SPoul-Henning Kamp int busy; 8200a6a3c6SPoul-Henning Kamp }; 8300a6a3c6SPoul-Henning Kamp 8400a6a3c6SPoul-Henning Kamp static int mdunits; 8500a6a3c6SPoul-Henning Kamp 8600a6a3c6SPoul-Henning Kamp static int 8700a6a3c6SPoul-Henning Kamp mdopen(dev_t dev, int flag, int fmt, struct proc *p) 8800a6a3c6SPoul-Henning Kamp { 8900a6a3c6SPoul-Henning Kamp struct md_s *sc; 9000a6a3c6SPoul-Henning Kamp struct disklabel *dl; 9100a6a3c6SPoul-Henning Kamp 9200a6a3c6SPoul-Henning Kamp if (md_debug) 9300a6a3c6SPoul-Henning Kamp printf("mdopen(%s %x %x %p)\n", 9400a6a3c6SPoul-Henning Kamp devtoname(dev), flag, fmt, p); 9500a6a3c6SPoul-Henning Kamp 9600a6a3c6SPoul-Henning Kamp sc = dev->si_drv1; 9700a6a3c6SPoul-Henning Kamp 9800a6a3c6SPoul-Henning Kamp dl = &sc->disk.d_label; 9900a6a3c6SPoul-Henning Kamp bzero(dl, sizeof(*dl)); 10000a6a3c6SPoul-Henning Kamp dl->d_secsize = DEV_BSIZE; 10100a6a3c6SPoul-Henning Kamp dl->d_nsectors = 1024; 10200a6a3c6SPoul-Henning Kamp dl->d_ntracks = 1; 10300a6a3c6SPoul-Henning Kamp dl->d_secpercyl = dl->d_nsectors + dl->d_ntracks; 10400a6a3c6SPoul-Henning Kamp dl->d_secperunit = sc->nsect; 10500a6a3c6SPoul-Henning Kamp dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl; 10600a6a3c6SPoul-Henning Kamp return (0); 10700a6a3c6SPoul-Henning Kamp } 10800a6a3c6SPoul-Henning Kamp 10900a6a3c6SPoul-Henning Kamp static int 11000a6a3c6SPoul-Henning Kamp mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 11100a6a3c6SPoul-Henning Kamp { 11200a6a3c6SPoul-Henning Kamp 11300a6a3c6SPoul-Henning Kamp if (md_debug) 11400a6a3c6SPoul-Henning Kamp printf("mdioctl(%s %lx %p %x %p)\n", 11500a6a3c6SPoul-Henning Kamp devtoname(dev), cmd, addr, flags, p); 11600a6a3c6SPoul-Henning Kamp 11700a6a3c6SPoul-Henning Kamp return (ENOIOCTL); 11800a6a3c6SPoul-Henning Kamp } 11900a6a3c6SPoul-Henning Kamp 12000a6a3c6SPoul-Henning Kamp static void 12100a6a3c6SPoul-Henning Kamp mdstrategy(struct buf *bp) 12200a6a3c6SPoul-Henning Kamp { 12300a6a3c6SPoul-Henning Kamp int s, i; 12400a6a3c6SPoul-Henning Kamp struct md_s *sc; 12500a6a3c6SPoul-Henning Kamp devstat_trans_flags dop; 12600a6a3c6SPoul-Henning Kamp u_char *secp, **secpp, *dst; 12700a6a3c6SPoul-Henning Kamp unsigned secno, nsec, secval, uc; 12800a6a3c6SPoul-Henning Kamp 12900a6a3c6SPoul-Henning Kamp if (md_debug > 1) 13000a6a3c6SPoul-Henning Kamp printf("mdstrategy(%p) %s %lx, %d, %ld, %p)\n", 13100a6a3c6SPoul-Henning Kamp bp, devtoname(bp->b_dev), bp->b_flags, bp->b_blkno, 13200a6a3c6SPoul-Henning Kamp bp->b_bcount / DEV_BSIZE, bp->b_data); 13300a6a3c6SPoul-Henning Kamp 13400a6a3c6SPoul-Henning Kamp sc = bp->b_dev->si_drv1; 13500a6a3c6SPoul-Henning Kamp 13600a6a3c6SPoul-Henning Kamp s = splbio(); 13700a6a3c6SPoul-Henning Kamp 13800a6a3c6SPoul-Henning Kamp bufqdisksort(&sc->buf_queue, bp); 13900a6a3c6SPoul-Henning Kamp 14000a6a3c6SPoul-Henning Kamp if (sc->busy) { 14100a6a3c6SPoul-Henning Kamp splx(s); 14200a6a3c6SPoul-Henning Kamp return; 14300a6a3c6SPoul-Henning Kamp } 14400a6a3c6SPoul-Henning Kamp 14500a6a3c6SPoul-Henning Kamp sc->busy++; 14600a6a3c6SPoul-Henning Kamp 14700a6a3c6SPoul-Henning Kamp while (1) { 14800a6a3c6SPoul-Henning Kamp bp = bufq_first(&sc->buf_queue); 14900a6a3c6SPoul-Henning Kamp if (bp) 15000a6a3c6SPoul-Henning Kamp bufq_remove(&sc->buf_queue, bp); 15100a6a3c6SPoul-Henning Kamp splx(s); 15200a6a3c6SPoul-Henning Kamp if (!bp) 15300a6a3c6SPoul-Henning Kamp break; 15400a6a3c6SPoul-Henning Kamp 15500a6a3c6SPoul-Henning Kamp devstat_start_transaction(&sc->stats); 15600a6a3c6SPoul-Henning Kamp 15700a6a3c6SPoul-Henning Kamp if (bp->b_flags & B_FREEBUF) 15800a6a3c6SPoul-Henning Kamp dop = DEVSTAT_NO_DATA; 15900a6a3c6SPoul-Henning Kamp else if (bp->b_flags & B_READ) 16000a6a3c6SPoul-Henning Kamp dop = DEVSTAT_READ; 16100a6a3c6SPoul-Henning Kamp else 16200a6a3c6SPoul-Henning Kamp dop = DEVSTAT_WRITE; 16300a6a3c6SPoul-Henning Kamp 16400a6a3c6SPoul-Henning Kamp nsec = bp->b_bcount / DEV_BSIZE; 16500a6a3c6SPoul-Henning Kamp secno = bp->b_pblkno; 16600a6a3c6SPoul-Henning Kamp dst = bp->b_data; 16700a6a3c6SPoul-Henning Kamp while (nsec--) { 16800a6a3c6SPoul-Henning Kamp 16900a6a3c6SPoul-Henning Kamp if (secno < sc->nsecp) { 17000a6a3c6SPoul-Henning Kamp secpp = &sc->secp[secno]; 17100a6a3c6SPoul-Henning Kamp if ((u_int)secpp > 255) { 17200a6a3c6SPoul-Henning Kamp secp = *secpp; 17300a6a3c6SPoul-Henning Kamp secval = 0; 17400a6a3c6SPoul-Henning Kamp } else { 17500a6a3c6SPoul-Henning Kamp secp = 0; 17600a6a3c6SPoul-Henning Kamp secval = (u_int) secpp; 17700a6a3c6SPoul-Henning Kamp } 17800a6a3c6SPoul-Henning Kamp } else { 17900a6a3c6SPoul-Henning Kamp secpp = 0; 18000a6a3c6SPoul-Henning Kamp secp = 0; 18100a6a3c6SPoul-Henning Kamp secval = 0; 18200a6a3c6SPoul-Henning Kamp } 18300a6a3c6SPoul-Henning Kamp 18400a6a3c6SPoul-Henning Kamp if (bp->b_flags & B_FREEBUF) { 18500a6a3c6SPoul-Henning Kamp if (secpp) { 18600a6a3c6SPoul-Henning Kamp if (secp) 18700a6a3c6SPoul-Henning Kamp FREE(secp, M_MDSECT); 18800a6a3c6SPoul-Henning Kamp *secpp = 0; 18900a6a3c6SPoul-Henning Kamp } 19000a6a3c6SPoul-Henning Kamp } else if (bp->b_flags & B_READ) { 19100a6a3c6SPoul-Henning Kamp if (secp) { 19200a6a3c6SPoul-Henning Kamp bcopy(secp, dst, DEV_BSIZE); 19300a6a3c6SPoul-Henning Kamp } else if (secval) { 19400a6a3c6SPoul-Henning Kamp for (i = 0; i < DEV_BSIZE; i++) 19500a6a3c6SPoul-Henning Kamp dst[i] = secval; 19600a6a3c6SPoul-Henning Kamp } else { 19700a6a3c6SPoul-Henning Kamp bzero(dst, DEV_BSIZE); 19800a6a3c6SPoul-Henning Kamp } 19900a6a3c6SPoul-Henning Kamp } else { 20000a6a3c6SPoul-Henning Kamp uc = dst[0]; 20100a6a3c6SPoul-Henning Kamp for (i = 1; i < DEV_BSIZE; i++) 20200a6a3c6SPoul-Henning Kamp if (dst[i] != uc) 20300a6a3c6SPoul-Henning Kamp break; 20400a6a3c6SPoul-Henning Kamp if (i == DEV_BSIZE && !uc) { 20500a6a3c6SPoul-Henning Kamp if (secp) 20600a6a3c6SPoul-Henning Kamp FREE(secp, M_MDSECT); 20700a6a3c6SPoul-Henning Kamp if (secpp) 20800a6a3c6SPoul-Henning Kamp *secpp = (u_char *)uc; 20900a6a3c6SPoul-Henning Kamp } else { 21000a6a3c6SPoul-Henning Kamp if (!secpp) { 21100a6a3c6SPoul-Henning Kamp MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK); 21200a6a3c6SPoul-Henning Kamp bzero(secpp, (secno + nsec + 1) * sizeof(u_char *)); 21300a6a3c6SPoul-Henning Kamp bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *)); 21400a6a3c6SPoul-Henning Kamp FREE(sc->secp, M_MD); 21500a6a3c6SPoul-Henning Kamp sc->secp = secpp; 21600a6a3c6SPoul-Henning Kamp sc->nsecp = secno + nsec + 1; 21700a6a3c6SPoul-Henning Kamp secpp = &sc->secp[secno]; 21800a6a3c6SPoul-Henning Kamp } 21900a6a3c6SPoul-Henning Kamp if (i == DEV_BSIZE) { 22000a6a3c6SPoul-Henning Kamp if (secp) 22100a6a3c6SPoul-Henning Kamp FREE(secp, M_MDSECT); 22200a6a3c6SPoul-Henning Kamp *secpp = (u_char *)uc; 22300a6a3c6SPoul-Henning Kamp } else { 22400a6a3c6SPoul-Henning Kamp if (!secp) 22500a6a3c6SPoul-Henning Kamp MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK); 22600a6a3c6SPoul-Henning Kamp bcopy(dst, secp, DEV_BSIZE); 22700a6a3c6SPoul-Henning Kamp 22800a6a3c6SPoul-Henning Kamp *secpp = secp; 22900a6a3c6SPoul-Henning Kamp } 23000a6a3c6SPoul-Henning Kamp } 23100a6a3c6SPoul-Henning Kamp } 23200a6a3c6SPoul-Henning Kamp secno++; 23300a6a3c6SPoul-Henning Kamp dst += DEV_BSIZE; 23400a6a3c6SPoul-Henning Kamp } 23500a6a3c6SPoul-Henning Kamp 23600a6a3c6SPoul-Henning Kamp bp->b_resid = 0; 23700a6a3c6SPoul-Henning Kamp biodone(bp); 23800a6a3c6SPoul-Henning Kamp devstat_end_transaction(&sc->stats, bp->b_bcount, 23900a6a3c6SPoul-Henning Kamp DEVSTAT_TAG_NONE, dop); 24000a6a3c6SPoul-Henning Kamp 24100a6a3c6SPoul-Henning Kamp s = splbio(); 24200a6a3c6SPoul-Henning Kamp } 24300a6a3c6SPoul-Henning Kamp sc->busy = 0; 24400a6a3c6SPoul-Henning Kamp return; 24500a6a3c6SPoul-Henning Kamp } 24600a6a3c6SPoul-Henning Kamp 24700a6a3c6SPoul-Henning Kamp static dev_t 24800a6a3c6SPoul-Henning Kamp mdcreate(void) 24900a6a3c6SPoul-Henning Kamp { 25000a6a3c6SPoul-Henning Kamp struct md_s *sc; 25100a6a3c6SPoul-Henning Kamp 25200a6a3c6SPoul-Henning Kamp MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK); 25300a6a3c6SPoul-Henning Kamp bzero(sc, sizeof(*sc)); 25400a6a3c6SPoul-Henning Kamp sc->unit = mdunits++; 25500a6a3c6SPoul-Henning Kamp 25600a6a3c6SPoul-Henning Kamp bufq_init(&sc->buf_queue); 25700a6a3c6SPoul-Henning Kamp 25800a6a3c6SPoul-Henning Kamp devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE, 25900a6a3c6SPoul-Henning Kamp DEVSTAT_NO_ORDERED_TAGS, 26000a6a3c6SPoul-Henning Kamp DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 0x190); 26100a6a3c6SPoul-Henning Kamp 26200a6a3c6SPoul-Henning Kamp sc->dev = disk_create(sc->unit, &sc->disk, 0, 26300a6a3c6SPoul-Henning Kamp &md_cdevsw, &mddisk_cdevsw); 26400a6a3c6SPoul-Henning Kamp 26500a6a3c6SPoul-Henning Kamp sc->dev->si_drv1 = sc; 26600a6a3c6SPoul-Henning Kamp sc->nsect = 10000 * 2; /* for now */ 26700a6a3c6SPoul-Henning Kamp MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK); 26800a6a3c6SPoul-Henning Kamp bzero(sc->secp, sizeof(u_char *)); 26900a6a3c6SPoul-Henning Kamp sc->nsecp = 1; 27000a6a3c6SPoul-Henning Kamp 27100a6a3c6SPoul-Henning Kamp return (0); 27200a6a3c6SPoul-Henning Kamp } 27300a6a3c6SPoul-Henning Kamp 27400a6a3c6SPoul-Henning Kamp static void 27500a6a3c6SPoul-Henning Kamp md_drvinit(void *unused) 27600a6a3c6SPoul-Henning Kamp { 27700a6a3c6SPoul-Henning Kamp 27800a6a3c6SPoul-Henning Kamp mdcreate(); 27900a6a3c6SPoul-Henning Kamp } 28000a6a3c6SPoul-Henning Kamp 28100a6a3c6SPoul-Henning Kamp SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL) 28200a6a3c6SPoul-Henning Kamp 283