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