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