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 "opt_geom.h" 14 #ifndef GEOM 15 16 #include <sys/param.h> 17 #include <sys/systm.h> 18 #include <sys/kernel.h> 19 #include <sys/sysctl.h> 20 #include <sys/bio.h> 21 #include <sys/conf.h> 22 #include <sys/disk.h> 23 #include <sys/malloc.h> 24 #include <sys/sysctl.h> 25 #include <machine/md_var.h> 26 #include <sys/ctype.h> 27 28 static MALLOC_DEFINE(M_DISK, "disk", "disk data"); 29 30 static d_strategy_t diskstrategy; 31 static d_open_t diskopen; 32 static d_close_t diskclose; 33 static d_ioctl_t diskioctl; 34 static d_psize_t diskpsize; 35 36 static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist); 37 38 void disk_dev_synth(dev_t dev); 39 40 void 41 disk_dev_synth(dev_t dev) 42 { 43 struct disk *dp; 44 int u, s, p; 45 dev_t pdev; 46 47 if (dksparebits(dev)) 48 return; 49 LIST_FOREACH(dp, &disklist, d_list) { 50 if (major(dev) != dp->d_devsw->d_maj) 51 continue; 52 u = dkunit(dev); 53 p = RAW_PART; 54 s = WHOLE_DISK_SLICE; 55 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 56 if (pdev->si_devsw == NULL) 57 return; /* Probably a unit we don't have */ 58 s = dkslice(dev); 59 p = dkpart(dev); 60 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 61 /* XXX: actually should not happen */ 62 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 63 UID_ROOT, GID_OPERATOR, 0640, "%s%d", 64 dp->d_devsw->d_name, u); 65 dev_depends(pdev, dev); 66 return; 67 } 68 if (s == COMPATIBILITY_SLICE) { 69 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 70 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 71 dp->d_devsw->d_name, u, 'a' + p); 72 dev_depends(pdev, dev); 73 return; 74 } 75 if (p != RAW_PART) { 76 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 77 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 78 dp->d_devsw->d_name, u, s - BASE_SLICE + 1, 79 'a' + p); 80 } else { 81 dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 82 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 83 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 84 make_dev_alias(dev, "%s%ds%dc", 85 dp->d_devsw->d_name, u, s - BASE_SLICE + 1); 86 } 87 dev_depends(pdev, dev); 88 return; 89 } 90 } 91 92 static void 93 disk_clone(void *arg, char *name, int namelen, dev_t *dev) 94 { 95 struct disk *dp; 96 char const *d; 97 char *e; 98 int j, u, s, p; 99 dev_t pdev; 100 101 if (*dev != NODEV) 102 return; 103 104 LIST_FOREACH(dp, &disklist, d_list) { 105 d = dp->d_devsw->d_name; 106 j = dev_stdclone(name, &e, d, &u); 107 if (j == 0) 108 continue; 109 if (u > DKMAXUNIT) 110 continue; 111 p = RAW_PART; 112 s = WHOLE_DISK_SLICE; 113 pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p)); 114 if (pdev->si_disk == NULL) 115 continue; 116 if (*e != '\0') { 117 j = dev_stdclone(e, &e, "s", &s); 118 if (j == 0) 119 s = COMPATIBILITY_SLICE; 120 else if (j == 1 || j == 2) 121 s += BASE_SLICE - 1; 122 if (!*e) 123 ; /* ad0s1 case */ 124 else if (e[1] != '\0') 125 return; /* can never be a disk name */ 126 else if (*e < 'a' || *e > 'h') 127 return; /* can never be a disk name */ 128 else 129 p = *e - 'a'; 130 } 131 if (s == WHOLE_DISK_SLICE && p == RAW_PART) { 132 return; 133 } else if (s >= BASE_SLICE && p != RAW_PART) { 134 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 135 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d%c", 136 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1, 137 p + 'a'); 138 } else if (s >= BASE_SLICE) { 139 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 140 UID_ROOT, GID_OPERATOR, 0640, "%s%ds%d", 141 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 142 make_dev_alias(*dev, "%s%ds%dc", 143 pdev->si_devsw->d_name, u, s - BASE_SLICE + 1); 144 } else { 145 *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p), 146 UID_ROOT, GID_OPERATOR, 0640, "%s%d%c", 147 pdev->si_devsw->d_name, u, p + 'a'); 148 } 149 dev_depends(pdev, *dev); 150 return; 151 } 152 } 153 154 static void 155 inherit_raw(dev_t pdev, dev_t dev) 156 { 157 dev->si_disk = pdev->si_disk; 158 dev->si_drv1 = pdev->si_drv1; 159 dev->si_drv2 = pdev->si_drv2; 160 dev->si_iosize_max = pdev->si_iosize_max; 161 dev->si_bsize_phys = pdev->si_bsize_phys; 162 dev->si_bsize_best = pdev->si_bsize_best; 163 } 164 165 dev_t 166 disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto) 167 { 168 static int once; 169 dev_t dev; 170 171 if (!once) { 172 EVENTHANDLER_REGISTER(dev_clone, disk_clone, 0, 1000); 173 once++; 174 } 175 176 bzero(dp, sizeof(*dp)); 177 178 if (proto->d_open != diskopen) { 179 *proto = *cdevsw; 180 proto->d_open = diskopen; 181 proto->d_close = diskclose; 182 proto->d_ioctl = diskioctl; 183 proto->d_strategy = diskstrategy; 184 proto->d_psize = diskpsize; 185 } 186 187 if (bootverbose) 188 printf("Creating DISK %s%d\n", cdevsw->d_name, unit); 189 dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART), 190 UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit); 191 192 dev->si_disk = dp; 193 dp->d_dev = dev; 194 dp->d_dsflags = flags; 195 dp->d_devsw = cdevsw; 196 LIST_INSERT_HEAD(&disklist, dp, d_list); 197 198 return (dev); 199 } 200 201 static int 202 diskdumpconf(u_int onoff, dev_t dev, struct disk *dp) 203 { 204 struct dumperinfo di; 205 struct disklabel *dl; 206 207 if (!onoff) 208 return(set_dumper(NULL)); 209 dl = dsgetlabel(dev, dp->d_slice); 210 if (!dl) 211 return (ENXIO); 212 bzero(&di, sizeof di); 213 di.dumper = (dumper_t *)dp->d_devsw->d_dump; 214 di.priv = dp->d_dev; 215 di.blocksize = dl->d_secsize; 216 di.mediaoffset = (off_t)(dl->d_partitions[dkpart(dev)].p_offset + 217 dp->d_slice->dss_slices[dkslice(dev)].ds_offset) * DEV_BSIZE; 218 di.mediasize = 219 (off_t)(dl->d_partitions[dkpart(dev)].p_size) * DEV_BSIZE; 220 return(set_dumper(&di)); 221 } 222 223 void 224 disk_invalidate (struct disk *disk) 225 { 226 if (disk->d_slice) 227 dsgone(&disk->d_slice); 228 } 229 230 void 231 disk_destroy(dev_t dev) 232 { 233 LIST_REMOVE(dev->si_disk, d_list); 234 bzero(dev->si_disk, sizeof(*dev->si_disk)); 235 dev->si_disk = NULL; 236 destroy_dev(dev); 237 return; 238 } 239 240 struct disk * 241 disk_enumerate(struct disk *disk) 242 { 243 if (!disk) 244 return (LIST_FIRST(&disklist)); 245 else 246 return (LIST_NEXT(disk, d_list)); 247 } 248 249 static int 250 sysctl_disks(SYSCTL_HANDLER_ARGS) 251 { 252 struct disk *disk; 253 int error, first; 254 255 disk = NULL; 256 first = 1; 257 258 while ((disk = disk_enumerate(disk))) { 259 if (!first) { 260 error = SYSCTL_OUT(req, " ", 1); 261 if (error) 262 return error; 263 } else { 264 first = 0; 265 } 266 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 267 if (error) 268 return error; 269 } 270 error = SYSCTL_OUT(req, "", 1); 271 return error; 272 } 273 274 SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, 275 sysctl_disks, "A", "names of available disks"); 276 277 /* 278 * The cdevsw functions 279 */ 280 281 static int 282 diskopen(dev_t dev, int oflags, int devtype, struct thread *td) 283 { 284 dev_t pdev; 285 struct disk *dp; 286 int error; 287 288 error = 0; 289 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 290 291 dp = pdev->si_disk; 292 if (!dp) 293 return (ENXIO); 294 295 while (dp->d_flags & DISKFLAG_LOCK) { 296 dp->d_flags |= DISKFLAG_WANTED; 297 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 298 if (error) 299 return (error); 300 } 301 dp->d_flags |= DISKFLAG_LOCK; 302 303 if (!dsisopen(dp->d_slice)) { 304 if (!pdev->si_iosize_max) 305 pdev->si_iosize_max = dev->si_iosize_max; 306 error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 307 } 308 309 /* Inherit properties from the whole/raw dev_t */ 310 inherit_raw(pdev, dev); 311 312 if (error) 313 goto out; 314 315 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 316 317 if (!dsisopen(dp->d_slice)) 318 dp->d_devsw->d_close(pdev, oflags, devtype, td); 319 out: 320 dp->d_flags &= ~DISKFLAG_LOCK; 321 if (dp->d_flags & DISKFLAG_WANTED) { 322 dp->d_flags &= ~DISKFLAG_WANTED; 323 wakeup(dp); 324 } 325 326 return(error); 327 } 328 329 static int 330 diskclose(dev_t dev, int fflag, int devtype, struct thread *td) 331 { 332 struct disk *dp; 333 int error; 334 dev_t pdev; 335 336 error = 0; 337 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 338 dp = pdev->si_disk; 339 if (!dp) 340 return (ENXIO); 341 dsclose(dev, devtype, dp->d_slice); 342 if (!dsisopen(dp->d_slice)) 343 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 344 return (error); 345 } 346 347 static void 348 diskstrategy(struct bio *bp) 349 { 350 dev_t pdev; 351 struct disk *dp; 352 353 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 354 dp = pdev->si_disk; 355 bp->bio_resid = bp->bio_bcount; 356 if (dp != bp->bio_dev->si_disk) 357 inherit_raw(pdev, bp->bio_dev); 358 359 if (!dp) { 360 biofinish(bp, NULL, ENXIO); 361 return; 362 } 363 364 if (dscheck(bp, dp->d_slice) <= 0) { 365 biodone(bp); 366 return; 367 } 368 369 if (bp->bio_bcount == 0) { 370 biodone(bp); 371 return; 372 } 373 374 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 375 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 376 dp->d_devsw->d_strategy(bp); 377 return; 378 379 } 380 381 static int 382 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 383 { 384 struct disk *dp; 385 int error; 386 u_int u; 387 dev_t pdev; 388 389 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 390 dp = pdev->si_disk; 391 if (!dp) 392 return (ENXIO); 393 if (cmd == DIOCSKERNELDUMP) { 394 u = *(u_int *)data; 395 return (diskdumpconf(u, dev, dp)); 396 } 397 if (cmd == DIOCGFRONTSTUFF) { 398 *(off_t *)data = 8192; /* XXX: crude but enough) */ 399 return (0); 400 } 401 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 402 if (error == ENOIOCTL) 403 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 404 return (error); 405 } 406 407 static int 408 diskpsize(dev_t dev) 409 { 410 struct disk *dp; 411 dev_t pdev; 412 413 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 414 dp = pdev->si_disk; 415 if (!dp) 416 return (-1); 417 if (dp != dev->si_disk) { 418 dev->si_drv1 = pdev->si_drv1; 419 dev->si_drv2 = pdev->si_drv2; 420 /* XXX: don't set bp->b_dev->si_disk (?) */ 421 } 422 return (dssize(dev, &dp->d_slice)); 423 } 424 425 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 426 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 427 428 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 429 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 430 431 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 432 0, sizeof(struct disk), "sizeof(struct disk)"); 433 434 #endif 435