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 int 202 disk_dumpcheck(dev_t dev, u_int *count, u_int *blkno, u_int *secsize) 203 { 204 struct disk *dp; 205 struct disklabel *dl; 206 u_int boff; 207 208 dp = dev->si_disk; 209 if (!dp) 210 return (ENXIO); 211 if (!dp->d_slice) 212 return (ENXIO); 213 dl = dsgetlabel(dev, dp->d_slice); 214 if (!dl) 215 return (ENXIO); 216 *count = Maxmem * (PAGE_SIZE / dl->d_secsize); 217 if (dumplo <= LABELSECTOR || 218 (dumplo + *count > dl->d_partitions[dkpart(dev)].p_size)) 219 return (EINVAL); 220 boff = dl->d_partitions[dkpart(dev)].p_offset + 221 dp->d_slice->dss_slices[dkslice(dev)].ds_offset; 222 *blkno = boff + dumplo; 223 *secsize = dl->d_secsize; 224 return (0); 225 226 } 227 228 void 229 disk_invalidate (struct disk *disk) 230 { 231 if (disk->d_slice) 232 dsgone(&disk->d_slice); 233 } 234 235 void 236 disk_destroy(dev_t dev) 237 { 238 LIST_REMOVE(dev->si_disk, d_list); 239 bzero(dev->si_disk, sizeof(*dev->si_disk)); 240 dev->si_disk = NULL; 241 destroy_dev(dev); 242 return; 243 } 244 245 struct disk * 246 disk_enumerate(struct disk *disk) 247 { 248 if (!disk) 249 return (LIST_FIRST(&disklist)); 250 else 251 return (LIST_NEXT(disk, d_list)); 252 } 253 254 static int 255 sysctl_disks(SYSCTL_HANDLER_ARGS) 256 { 257 struct disk *disk; 258 int error, first; 259 260 disk = NULL; 261 first = 1; 262 263 while ((disk = disk_enumerate(disk))) { 264 if (!first) { 265 error = SYSCTL_OUT(req, " ", 1); 266 if (error) 267 return error; 268 } else { 269 first = 0; 270 } 271 error = SYSCTL_OUT(req, disk->d_dev->si_name, strlen(disk->d_dev->si_name)); 272 if (error) 273 return error; 274 } 275 error = SYSCTL_OUT(req, "", 1); 276 return error; 277 } 278 279 SYSCTL_PROC(_kern, OID_AUTO, disks, CTLTYPE_STRING | CTLFLAG_RD, 0, NULL, 280 sysctl_disks, "A", "names of available disks"); 281 282 /* 283 * The cdevsw functions 284 */ 285 286 static int 287 diskopen(dev_t dev, int oflags, int devtype, struct thread *td) 288 { 289 dev_t pdev; 290 struct disk *dp; 291 int error; 292 293 error = 0; 294 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 295 296 dp = pdev->si_disk; 297 if (!dp) 298 return (ENXIO); 299 300 while (dp->d_flags & DISKFLAG_LOCK) { 301 dp->d_flags |= DISKFLAG_WANTED; 302 error = tsleep(dp, PRIBIO | PCATCH, "diskopen", hz); 303 if (error) 304 return (error); 305 } 306 dp->d_flags |= DISKFLAG_LOCK; 307 308 if (!dsisopen(dp->d_slice)) { 309 if (!pdev->si_iosize_max) 310 pdev->si_iosize_max = dev->si_iosize_max; 311 error = dp->d_devsw->d_open(pdev, oflags, devtype, td); 312 } 313 314 /* Inherit properties from the whole/raw dev_t */ 315 inherit_raw(pdev, dev); 316 317 if (error) 318 goto out; 319 320 error = dsopen(dev, devtype, dp->d_dsflags, &dp->d_slice, &dp->d_label); 321 322 if (!dsisopen(dp->d_slice)) 323 dp->d_devsw->d_close(pdev, oflags, devtype, td); 324 out: 325 dp->d_flags &= ~DISKFLAG_LOCK; 326 if (dp->d_flags & DISKFLAG_WANTED) { 327 dp->d_flags &= ~DISKFLAG_WANTED; 328 wakeup(dp); 329 } 330 331 return(error); 332 } 333 334 static int 335 diskclose(dev_t dev, int fflag, int devtype, struct thread *td) 336 { 337 struct disk *dp; 338 int error; 339 dev_t pdev; 340 341 error = 0; 342 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 343 dp = pdev->si_disk; 344 if (!dp) 345 return (ENXIO); 346 dsclose(dev, devtype, dp->d_slice); 347 if (!dsisopen(dp->d_slice)) 348 error = dp->d_devsw->d_close(dp->d_dev, fflag, devtype, td); 349 return (error); 350 } 351 352 static void 353 diskstrategy(struct bio *bp) 354 { 355 dev_t pdev; 356 struct disk *dp; 357 358 pdev = dkmodpart(dkmodslice(bp->bio_dev, WHOLE_DISK_SLICE), RAW_PART); 359 dp = pdev->si_disk; 360 bp->bio_resid = bp->bio_bcount; 361 if (dp != bp->bio_dev->si_disk) 362 inherit_raw(pdev, bp->bio_dev); 363 364 if (!dp) { 365 biofinish(bp, NULL, ENXIO); 366 return; 367 } 368 369 if (dscheck(bp, dp->d_slice) <= 0) { 370 biodone(bp); 371 return; 372 } 373 374 if (bp->bio_bcount == 0) { 375 biodone(bp); 376 return; 377 } 378 379 KASSERT(dp->d_devsw != NULL, ("NULL devsw")); 380 KASSERT(dp->d_devsw->d_strategy != NULL, ("NULL d_strategy")); 381 dp->d_devsw->d_strategy(bp); 382 return; 383 384 } 385 386 static int 387 diskioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 388 { 389 struct disk *dp; 390 int error; 391 dev_t pdev; 392 393 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 394 dp = pdev->si_disk; 395 if (!dp) 396 return (ENXIO); 397 error = dsioctl(dev, cmd, data, fflag, &dp->d_slice); 398 if (error == ENOIOCTL) 399 error = dp->d_devsw->d_ioctl(dev, cmd, data, fflag, td); 400 return (error); 401 } 402 403 static int 404 diskpsize(dev_t dev) 405 { 406 struct disk *dp; 407 dev_t pdev; 408 409 pdev = dkmodpart(dkmodslice(dev, WHOLE_DISK_SLICE), RAW_PART); 410 dp = pdev->si_disk; 411 if (!dp) 412 return (-1); 413 if (dp != dev->si_disk) { 414 dev->si_drv1 = pdev->si_drv1; 415 dev->si_drv2 = pdev->si_drv2; 416 /* XXX: don't set bp->b_dev->si_disk (?) */ 417 } 418 return (dssize(dev, &dp->d_slice)); 419 } 420 421 SYSCTL_INT(_debug_sizeof, OID_AUTO, disklabel, CTLFLAG_RD, 422 0, sizeof(struct disklabel), "sizeof(struct disklabel)"); 423 424 SYSCTL_INT(_debug_sizeof, OID_AUTO, diskslices, CTLFLAG_RD, 425 0, sizeof(struct diskslices), "sizeof(struct diskslices)"); 426 427 SYSCTL_INT(_debug_sizeof, OID_AUTO, disk, CTLFLAG_RD, 428 0, sizeof(struct disk), "sizeof(struct disk)"); 429 430 #endif 431