Change the kernel dev_t, representing a pointer to a specinfo structure,
[dragonfly.git] / sys / dev / disk / md / md.c
CommitLineData
984263bc
MD
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: src/sys/dev/md/md.c,v 1.8.2.2 2002/08/19 17:43:34 jdp Exp $
b13267a5 10 * $DragonFly: src/sys/dev/disk/md/md.c,v 1.14 2006/09/10 01:26:34 dillon Exp $
984263bc
MD
11 *
12 */
13
984263bc
MD
14#include "opt_md.h" /* We have adopted some tasks from MFS */
15
16#include <sys/param.h>
17#include <sys/systm.h>
18#include <sys/buf.h>
19#include <sys/conf.h>
20#include <sys/devicestat.h>
21#include <sys/disk.h>
22#include <sys/kernel.h>
23#include <sys/malloc.h>
24#include <sys/sysctl.h>
25#include <sys/linker.h>
3020e3be
MD
26#include <sys/proc.h>
27#include <sys/buf2.h>
fbe276c7 28#include <sys/thread2.h>
984263bc
MD
29
30#ifndef MD_NSECT
31#define MD_NSECT (10000 * 2)
32#endif
33
34MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk");
35MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors");
36
37static int md_debug;
38SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, "");
39
984263bc
MD
40#if defined(MD_ROOT) && defined(MD_ROOT_SIZE)
41/* Image gets put here: */
42static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here";
43static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
44#endif
45
46static int mdrootready;
47
48static void mdcreate_malloc(void);
49
50#define CDEV_MAJOR 95
984263bc
MD
51
52static d_strategy_t mdstrategy;
53static d_strategy_t mdstrategy_preload;
54static d_strategy_t mdstrategy_malloc;
55static d_open_t mdopen;
56static d_ioctl_t mdioctl;
57
fef8985e
MD
58static struct dev_ops md_ops = {
59 { "md", CDEV_MAJOR, D_DISK | D_CANFREE | D_MEMDISK },
60 .d_open = mdopen,
61 .d_close = nullclose,
62 .d_read = physread,
63 .d_write = physwrite,
64 .d_ioctl = mdioctl,
65 .d_strategy = mdstrategy,
984263bc
MD
66};
67
984263bc
MD
68struct md_s {
69 int unit;
70 struct devstat stats;
81b5c339 71 struct bio_queue_head bio_queue;
984263bc 72 struct disk disk;
b13267a5 73 cdev_t dev;
984263bc
MD
74 int busy;
75 enum {MD_MALLOC, MD_PRELOAD} type;
76 unsigned nsect;
77
78 /* MD_MALLOC related fields */
79 unsigned nsecp;
80 u_char **secp;
81
82 /* MD_PRELOAD related fields */
83 u_char *pl_ptr;
84 unsigned pl_len;
85};
86
87static int mdunits;
88
89static int
fef8985e 90mdopen(struct dev_open_args *ap)
984263bc 91{
b13267a5 92 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
93 struct md_s *sc;
94 struct disklabel *dl;
95
96 if (md_debug)
fef8985e
MD
97 printf("mdopen(%s %x %x)\n",
98 devtoname(dev), ap->a_oflags, ap->a_devtype);
984263bc
MD
99
100 sc = dev->si_drv1;
101 if (sc->unit + 1 == mdunits)
102 mdcreate_malloc();
103
104 dl = &sc->disk.d_label;
105 bzero(dl, sizeof(*dl));
106 dl->d_secsize = DEV_BSIZE;
107 dl->d_nsectors = 1024;
108 dl->d_ntracks = 1;
109 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
110 dl->d_secperunit = sc->nsect;
111 dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl;
112 return (0);
113}
114
115static int
fef8985e 116mdioctl(struct dev_ioctl_args *ap)
984263bc 117{
b13267a5 118 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
119
120 if (md_debug)
fef8985e
MD
121 printf("mdioctl(%s %lx %p %x)\n",
122 devtoname(dev), ap->a_cmd, ap->a_data, ap->a_fflag);
984263bc
MD
123
124 return (ENOIOCTL);
125}
126
fef8985e
MD
127static int
128mdstrategy(struct dev_strategy_args *ap)
984263bc 129{
b13267a5 130 cdev_t dev = ap->a_head.a_dev;
fef8985e 131 struct bio *bio = ap->a_bio;
81b5c339 132 struct buf *bp = bio->bio_buf;
984263bc
MD
133 struct md_s *sc;
134
81b5c339 135 if (md_debug > 1) {
54078292
MD
136 printf("mdstrategy(%p) %s %08x, %lld, %d, %p)\n",
137 bp, devtoname(dev), bp->b_flags, bio->bio_offset,
138 bp->b_bcount, bp->b_data);
81b5c339
MD
139 }
140 bio->bio_driver_info = dev;
141 sc = dev->si_drv1;
984263bc 142 if (sc->type == MD_MALLOC) {
fef8985e 143 mdstrategy_malloc(ap);
984263bc 144 } else {
fef8985e 145 mdstrategy_preload(ap);
984263bc 146 }
fef8985e 147 return(0);
984263bc
MD
148}
149
150
fef8985e
MD
151static int
152mdstrategy_malloc(struct dev_strategy_args *ap)
984263bc 153{
b13267a5 154 cdev_t dev = ap->a_head.a_dev;
fef8985e 155 struct bio *bio = ap->a_bio;
81b5c339 156 struct buf *bp = bio->bio_buf;
984263bc 157 unsigned secno, nsec, secval, uc;
81b5c339
MD
158 u_char *secp, **secpp, *dst;
159 devstat_trans_flags dop;
160 struct md_s *sc;
161 int i;
984263bc
MD
162
163 if (md_debug > 1)
54078292
MD
164 printf("mdstrategy_malloc(%p) %s %08xx, %lld, %d, %p)\n",
165 bp, devtoname(dev), bp->b_flags, bio->bio_offset,
166 bp->b_bcount, bp->b_data);
984263bc 167
81b5c339 168 sc = dev->si_drv1;
984263bc 169
fbe276c7 170 crit_enter();
984263bc 171
81b5c339 172 bioqdisksort(&sc->bio_queue, bio);
984263bc
MD
173
174 if (sc->busy) {
fbe276c7 175 crit_exit();
fef8985e 176 return(0);
984263bc
MD
177 }
178
179 sc->busy++;
180
181 while (1) {
81b5c339 182 bio = bioq_first(&sc->bio_queue);
984263bc 183 if (bp)
81b5c339 184 bioq_remove(&sc->bio_queue, bio);
fbe276c7 185 crit_exit();
81b5c339 186 if (bio == NULL)
984263bc
MD
187 break;
188
189 devstat_start_transaction(&sc->stats);
190
10f3fee5
MD
191 switch(bp->b_cmd) {
192 case BUF_CMD_FREEBLKS:
984263bc 193 dop = DEVSTAT_NO_DATA;
10f3fee5
MD
194 break;
195 case BUF_CMD_READ:
984263bc 196 dop = DEVSTAT_READ;
10f3fee5
MD
197 break;
198 case BUF_CMD_WRITE:
984263bc 199 dop = DEVSTAT_WRITE;
10f3fee5
MD
200 break;
201 default:
202 panic("md: bad b_cmd %d", bp->b_cmd);
203 }
984263bc 204
54078292
MD
205 nsec = bp->b_bcount >> DEV_BSHIFT;
206 secno = (unsigned)(bio->bio_offset >> DEV_BSHIFT);
984263bc
MD
207 dst = bp->b_data;
208 while (nsec--) {
984263bc
MD
209 if (secno < sc->nsecp) {
210 secpp = &sc->secp[secno];
211 if ((u_int)*secpp > 255) {
212 secp = *secpp;
213 secval = 0;
214 } else {
215 secp = 0;
216 secval = (u_int) *secpp;
217 }
218 } else {
219 secpp = 0;
220 secp = 0;
221 secval = 0;
222 }
223 if (md_debug > 2)
54078292 224 printf("%08x %p %p %d\n", bp->b_flags, secpp, secp, secval);
984263bc 225
10f3fee5
MD
226 switch(bp->b_cmd) {
227 case BUF_CMD_FREEBLKS:
984263bc
MD
228 if (secpp) {
229 if (secp)
230 FREE(secp, M_MDSECT);
231 *secpp = 0;
232 }
10f3fee5
MD
233 break;
234 case BUF_CMD_READ:
984263bc
MD
235 if (secp) {
236 bcopy(secp, dst, DEV_BSIZE);
237 } else if (secval) {
238 for (i = 0; i < DEV_BSIZE; i++)
239 dst[i] = secval;
240 } else {
241 bzero(dst, DEV_BSIZE);
242 }
10f3fee5
MD
243 break;
244 case BUF_CMD_WRITE:
984263bc
MD
245 uc = dst[0];
246 for (i = 1; i < DEV_BSIZE; i++)
247 if (dst[i] != uc)
248 break;
249 if (i == DEV_BSIZE && !uc) {
250 if (secp)
251 FREE(secp, M_MDSECT);
252 if (secpp)
253 *secpp = (u_char *)uc;
254 } else {
255 if (!secpp) {
256 MALLOC(secpp, u_char **, (secno + nsec + 1) * sizeof(u_char *), M_MD, M_WAITOK);
257 bzero(secpp, (secno + nsec + 1) * sizeof(u_char *));
258 bcopy(sc->secp, secpp, sc->nsecp * sizeof(u_char *));
259 FREE(sc->secp, M_MD);
260 sc->secp = secpp;
261 sc->nsecp = secno + nsec + 1;
262 secpp = &sc->secp[secno];
263 }
264 if (i == DEV_BSIZE) {
265 if (secp)
266 FREE(secp, M_MDSECT);
267 *secpp = (u_char *)uc;
268 } else {
269 if (!secp)
270 MALLOC(secp, u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK);
271 bcopy(dst, secp, DEV_BSIZE);
272
273 *secpp = secp;
274 }
275 }
10f3fee5
MD
276 break;
277 default:
278 panic("md: bad b_cmd %d", bp->b_cmd);
279
984263bc
MD
280 }
281 secno++;
282 dst += DEV_BSIZE;
283 }
284 bp->b_resid = 0;
285 devstat_end_transaction_buf(&sc->stats, bp);
81b5c339 286 biodone(bio);
fbe276c7 287 crit_enter();
984263bc
MD
288 }
289 sc->busy = 0;
fef8985e 290 return(0);
984263bc
MD
291}
292
293
fef8985e
MD
294static int
295mdstrategy_preload(struct dev_strategy_args *ap)
984263bc 296{
b13267a5 297 cdev_t dev = ap->a_head.a_dev;
fef8985e 298 struct bio *bio = ap->a_bio;
81b5c339 299 struct buf *bp = bio->bio_buf;
984263bc 300 devstat_trans_flags dop;
81b5c339 301 struct md_s *sc;
984263bc
MD
302
303 if (md_debug > 1)
54078292
MD
304 printf("mdstrategy_preload(%p) %s %08x, %lld, %d, %p)\n",
305 bp, devtoname(dev), bp->b_flags, bio->bio_offset,
306 bp->b_bcount, bp->b_data);
984263bc 307
81b5c339 308 sc = dev->si_drv1;
984263bc 309
fbe276c7 310 crit_enter();
984263bc 311
81b5c339 312 bioqdisksort(&sc->bio_queue, bio);
984263bc
MD
313
314 if (sc->busy) {
fbe276c7 315 crit_exit();
fef8985e 316 return(0);
984263bc
MD
317 }
318
319 sc->busy++;
320
321 while (1) {
81b5c339
MD
322 bio = bioq_first(&sc->bio_queue);
323 if (bio)
324 bioq_remove(&sc->bio_queue, bio);
fbe276c7 325 crit_exit();
81b5c339 326 if (bio == NULL)
984263bc
MD
327 break;
328
329 devstat_start_transaction(&sc->stats);
330
10f3fee5
MD
331 switch(bp->b_cmd) {
332 case BUF_CMD_FREEBLKS:
984263bc 333 dop = DEVSTAT_NO_DATA;
10f3fee5
MD
334 break;
335 case BUF_CMD_READ:
984263bc 336 dop = DEVSTAT_READ;
54078292
MD
337 bcopy(sc->pl_ptr + bio->bio_offset,
338 bp->b_data, bp->b_bcount);
10f3fee5
MD
339 break;
340 case BUF_CMD_WRITE:
984263bc 341 dop = DEVSTAT_WRITE;
54078292
MD
342 bcopy(bp->b_data, sc->pl_ptr + bio->bio_offset,
343 bp->b_bcount);
10f3fee5
MD
344 break;
345 default:
346 panic("md: bad cmd %d\n", bp->b_cmd);
984263bc
MD
347 }
348 bp->b_resid = 0;
349 devstat_end_transaction_buf(&sc->stats, bp);
81b5c339 350 biodone(bio);
fbe276c7 351 crit_enter();
984263bc
MD
352 }
353 sc->busy = 0;
fef8985e 354 return(0);
984263bc
MD
355}
356
357static struct md_s *
358mdcreate(void)
359{
360 struct md_s *sc;
361
362 MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
363 bzero(sc, sizeof(*sc));
364 sc->unit = mdunits++;
81b5c339 365 bioq_init(&sc->bio_queue);
984263bc
MD
366 devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
367 DEVSTAT_NO_ORDERED_TAGS,
368 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
369 DEVSTAT_PRIORITY_OTHER);
fef8985e 370 sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_ops);
984263bc
MD
371 sc->dev->si_drv1 = sc;
372 return (sc);
373}
374
375static void
376mdcreate_preload(u_char *image, unsigned length)
377{
378 struct md_s *sc;
379
380 sc = mdcreate();
381 sc->type = MD_PRELOAD;
382 sc->nsect = length / DEV_BSIZE;
383 sc->pl_ptr = image;
384 sc->pl_len = length;
385
386 if (sc->unit == 0)
387 mdrootready = 1;
388}
389
390static void
391mdcreate_malloc(void)
392{
393 struct md_s *sc;
394
395 sc = mdcreate();
396 sc->type = MD_MALLOC;
397
398 sc->nsect = MD_NSECT; /* for now */
399 MALLOC(sc->secp, u_char **, sizeof(u_char *), M_MD, M_WAITOK);
400 bzero(sc->secp, sizeof(u_char *));
401 sc->nsecp = 1;
402 printf("md%d: Malloc disk\n", sc->unit);
403}
404
405static void
406md_drvinit(void *unused)
407{
408
409 caddr_t mod;
410 caddr_t c;
411 u_char *ptr, *name, *type;
412 unsigned len;
413
414#ifdef MD_ROOT_SIZE
415 mdcreate_preload(mfs_root, MD_ROOT_SIZE*1024);
416#endif
417 mod = NULL;
418 while ((mod = preload_search_next_name(mod)) != NULL) {
419 name = (char *)preload_search_info(mod, MODINFO_NAME);
420 type = (char *)preload_search_info(mod, MODINFO_TYPE);
421 if (name == NULL)
422 continue;
423 if (type == NULL)
424 continue;
425 if (strcmp(type, "md_image") && strcmp(type, "mfs_root"))
426 continue;
427 c = preload_search_info(mod, MODINFO_ADDR);
428 ptr = *(u_char **)c;
429 c = preload_search_info(mod, MODINFO_SIZE);
430 len = *(unsigned *)c;
431 printf("md%d: Preloaded image <%s> %d bytes at %p\n",
432 mdunits, name, len, ptr);
433 mdcreate_preload(ptr, len);
434 }
435 mdcreate_malloc();
436}
437
438SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
439
440#ifdef MD_ROOT
441static void
442md_takeroot(void *junk)
443{
444 if (mdrootready)
445 rootdevnames[0] = "ufs:/dev/md0c";
446}
447
448SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
449#endif