md.c revision 51499
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/sys/dev/md/md.c 51499 1999-09-21 11:00:49Z phk $
10 *
11 */
12
13#include <sys/param.h>
14#include <sys/systm.h>
15#include <sys/sysctl.h>
16#include <sys/kernel.h>
17#include <sys/buf.h>
18#include <sys/malloc.h>
19#include <sys/conf.h>
20#include <sys/disk.h>
21#include <sys/devicestat.h>
22#include <sys/module.h>
23#include <machine/bus.h>
24#include <machine/clock.h>
25#include <machine/resource.h>
26
27#include <vm/vm.h>
28#include <vm/pmap.h>
29#include <vm/vm_param.h>
30
31#include <sys/bus.h>
32#include <isa/isareg.h>
33#include <isa/isavar.h>
34
35MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk");
36MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors");
37
38static int md_debug = 0;
39SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, "");
40
41#define CDEV_MAJOR	95
42#define BDEV_MAJOR	22
43
44static d_strategy_t mdstrategy;
45static d_open_t mdopen;
46static d_ioctl_t mdioctl;
47
48static struct cdevsw md_cdevsw = {
49        /* open */      mdopen,
50        /* close */     nullclose,
51        /* read */      physread,
52        /* write */     physwrite,
53        /* ioctl */     mdioctl,
54        /* stop */      nostop,
55        /* reset */     noreset,
56        /* devtotty */  nodevtotty,
57        /* poll */      nopoll,
58        /* mmap */      nommap,
59        /* strategy */  mdstrategy,
60        /* name */      "md",
61        /* parms */     noparms,
62        /* maj */       CDEV_MAJOR,
63        /* dump */      nodump,
64        /* psize */     nopsize,
65        /* flags */     D_DISK | D_CANFREE,
66        /* maxio */     0,
67        /* bmaj */      BDEV_MAJOR
68};
69static struct cdevsw mddisk_cdevsw;
70
71struct md_s {
72	int unit;
73	struct devstat stats;
74	struct buf_queue_head buf_queue;
75	struct disk disk;
76	dev_t dev;
77	unsigned nsect;
78	unsigned nsecp;
79	u_char **secp;
80
81	int busy;
82};
83
84static int mdunits;
85
86static int
87mdopen(dev_t dev, int flag, int fmt, struct proc *p)
88{
89	struct md_s *sc;
90	struct disklabel *dl;
91
92	if (md_debug)
93		printf("mdopen(%s %x %x %p)\n",
94			devtoname(dev), flag, fmt, p);
95
96	sc = dev->si_drv1;
97
98	dl = &sc->disk.d_label;
99	bzero(dl, sizeof(*dl));
100	dl->d_secsize = DEV_BSIZE;
101	dl->d_nsectors = 1024;
102	dl->d_ntracks = 1;
103	dl->d_secpercyl = dl->d_nsectors + dl->d_ntracks;
104	dl->d_secperunit = sc->nsect;
105	dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
106	return (0);
107}
108
109static int
110mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
111{
112
113	if (md_debug)
114		printf("mdioctl(%s %lx %p %x %p)\n",
115			devtoname(dev), cmd, addr, flags, p);
116
117	return (ENOIOCTL);
118}
119
120static void
121mdstrategy(struct buf *bp)
122{
123	int s, i;
124	struct md_s *sc;
125	devstat_trans_flags dop;
126	u_char *secp, **secpp, *dst;
127	unsigned secno, nsec, secval, uc;
128
129	if (md_debug > 1)
130		printf("mdstrategy(%p) %s %lx, %d, %ld, %p)\n",
131		    bp, devtoname(bp->b_dev), bp->b_flags, bp->b_blkno,
132		    bp->b_bcount / DEV_BSIZE, bp->b_data);
133
134	sc = bp->b_dev->si_drv1;
135
136	s = splbio();
137
138	bufqdisksort(&sc->buf_queue, bp);
139
140	if (sc->busy) {
141		splx(s);
142		return;
143	}
144
145	sc->busy++;
146
147	while (1) {
148		bp = bufq_first(&sc->buf_queue);
149		if (bp)
150			bufq_remove(&sc->buf_queue, bp);
151		splx(s);
152		if (!bp)
153			break;
154
155		devstat_start_transaction(&sc->stats);
156
157		if (bp->b_flags & B_FREEBUF)
158			dop = DEVSTAT_NO_DATA;
159		else if (bp->b_flags & B_READ)
160			dop = DEVSTAT_READ;
161		else
162			dop = DEVSTAT_WRITE;
163
164		nsec = bp->b_bcount / DEV_BSIZE;
165		secno = bp->b_pblkno;
166		dst = bp->b_data;
167		while (nsec--) {
168
169			if (secno < sc->nsecp) {
170				secpp = &sc->secp[secno];
171				if ((u_int)secpp > 255) {
172					secp = *secpp;
173					secval = 0;
174				} else {
175					secp = 0;
176					secval = (u_int) secpp;
177				}
178			} else {
179				secpp = 0;
180				secp = 0;
181				secval = 0;
182			}
183
184			if (bp->b_flags & B_FREEBUF) {
185				if (secpp) {
186					if (secp)
187						FREE(secp, M_MDSECT);
188					*secpp = 0;
189				}
190			} else if (bp->b_flags & B_READ) {
191				if (secp) {
192					bcopy(secp, dst, DEV_BSIZE);
193				} else if (secval) {
194					for (i = 0; i < DEV_BSIZE; i++)
195						dst[i] = secval;
196				} else {
197					bzero(dst, DEV_BSIZE);
198				}
199			} else {
200				uc = dst[0];
201				for (i = 1; i < DEV_BSIZE; i++)
202					if (dst[i] != uc)
203						break;
204				if (i == DEV_BSIZE && !uc) {
205					if (secp)
206						FREE(secp, M_MDSECT);
207					if (secpp)
208						*secpp = (u_char *)uc;
209				} else {
210					if (!secpp) {
211						MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
212						bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
213						bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
214						FREE(sc->secp, M_MD);
215						sc->secp = secpp;
216						sc->nsecp = secno + nsec + 1;
217						secpp = &sc->secp[secno];
218					}
219					if (i == DEV_BSIZE) {
220						if (secp)
221							FREE(secp, M_MDSECT);
222						*secpp = (u_char *)uc;
223					} else {
224						if (!secp)
225							MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
226						bcopy(dst, secp, DEV_BSIZE);
227
228						*secpp = secp;
229					}
230				}
231			}
232			secno++;
233			dst += DEV_BSIZE;
234		}
235
236		bp->b_resid = 0;
237		biodone(bp);
238		devstat_end_transaction(&sc->stats, bp->b_bcount,
239		    DEVSTAT_TAG_NONE, dop);
240
241		s = splbio();
242	}
243	sc->busy = 0;
244	return;
245}
246
247static dev_t
248mdcreate(void)
249{
250	struct md_s *sc;
251
252	MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
253	bzero(sc, sizeof(*sc));
254	sc->unit = mdunits++;
255
256	bufq_init(&sc->buf_queue);
257
258	devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
259		DEVSTAT_NO_ORDERED_TAGS,
260		DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 0x190);
261
262	sc->dev = disk_create(sc->unit, &sc->disk, 0,
263	    &md_cdevsw, &mddisk_cdevsw);
264
265	sc->dev->si_drv1 = sc;
266	sc->nsect = 10000 * 2;	/* for now */
267	MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
268	bzero(sc->secp, sizeof(u_char *));
269	sc->nsecp = 1;
270
271	return (0);
272}
273
274static void
275md_drvinit(void *unused)
276{
277
278	mdcreate();
279}
280
281SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
282
283