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