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