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