1 /* $NetBSD: dk.c,v 1.103 2021/05/22 13:43:50 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.103 2021/05/22 13:43:50 mlelstv Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_dkwedge.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/proc.h> 42 #include <sys/errno.h> 43 #include <sys/pool.h> 44 #include <sys/ioctl.h> 45 #include <sys/disklabel.h> 46 #include <sys/disk.h> 47 #include <sys/fcntl.h> 48 #include <sys/buf.h> 49 #include <sys/bufq.h> 50 #include <sys/vnode.h> 51 #include <sys/stat.h> 52 #include <sys/conf.h> 53 #include <sys/callout.h> 54 #include <sys/kernel.h> 55 #include <sys/malloc.h> 56 #include <sys/device.h> 57 #include <sys/kauth.h> 58 59 #include <miscfs/specfs/specdev.h> 60 61 MALLOC_DEFINE(M_DKWEDGE, "dkwedge", "Disk wedge structures"); 62 63 typedef enum { 64 DKW_STATE_LARVAL = 0, 65 DKW_STATE_RUNNING = 1, 66 DKW_STATE_DYING = 2, 67 DKW_STATE_DEAD = 666 68 } dkwedge_state_t; 69 70 struct dkwedge_softc { 71 device_t sc_dev; /* pointer to our pseudo-device */ 72 struct cfdata sc_cfdata; /* our cfdata structure */ 73 uint8_t sc_wname[128]; /* wedge name (Unicode, UTF-8) */ 74 75 dkwedge_state_t sc_state; /* state this wedge is in */ 76 77 struct disk *sc_parent; /* parent disk */ 78 daddr_t sc_offset; /* LBA offset of wedge in parent */ 79 uint64_t sc_size; /* size of wedge in blocks */ 80 char sc_ptype[32]; /* partition type */ 81 dev_t sc_pdev; /* cached parent's dev_t */ 82 /* link on parent's wedge list */ 83 LIST_ENTRY(dkwedge_softc) sc_plink; 84 85 struct disk sc_dk; /* our own disk structure */ 86 struct bufq_state *sc_bufq; /* buffer queue */ 87 struct callout sc_restart_ch; /* callout to restart I/O */ 88 89 kmutex_t sc_iolock; 90 kcondvar_t sc_dkdrn; 91 u_int sc_iopend; /* I/Os pending */ 92 int sc_flags; /* flags (sc_iolock) */ 93 int sc_mode; /* parent open mode */ 94 }; 95 96 #define DK_F_WAIT_DRAIN 0x0001 /* waiting for I/O to drain */ 97 98 static void dkstart(struct dkwedge_softc *); 99 static void dkiodone(struct buf *); 100 static void dkrestart(void *); 101 static void dkminphys(struct buf *); 102 103 static int dklastclose(struct dkwedge_softc *); 104 static int dkwedge_cleanup_parent(struct dkwedge_softc *, int); 105 static int dkwedge_detach(device_t, int); 106 static void dkwedge_delall1(struct disk *, bool); 107 static int dkwedge_del1(struct dkwedge_info *, int); 108 static int dk_open_parent(dev_t, int, struct vnode **); 109 static int dk_close_parent(struct vnode *, int); 110 111 static dev_type_open(dkopen); 112 static dev_type_close(dkclose); 113 static dev_type_read(dkread); 114 static dev_type_write(dkwrite); 115 static dev_type_ioctl(dkioctl); 116 static dev_type_strategy(dkstrategy); 117 static dev_type_dump(dkdump); 118 static dev_type_size(dksize); 119 static dev_type_discard(dkdiscard); 120 121 const struct bdevsw dk_bdevsw = { 122 .d_open = dkopen, 123 .d_close = dkclose, 124 .d_strategy = dkstrategy, 125 .d_ioctl = dkioctl, 126 .d_dump = dkdump, 127 .d_psize = dksize, 128 .d_discard = dkdiscard, 129 .d_flag = D_DISK | D_MPSAFE 130 }; 131 132 const struct cdevsw dk_cdevsw = { 133 .d_open = dkopen, 134 .d_close = dkclose, 135 .d_read = dkread, 136 .d_write = dkwrite, 137 .d_ioctl = dkioctl, 138 .d_stop = nostop, 139 .d_tty = notty, 140 .d_poll = nopoll, 141 .d_mmap = nommap, 142 .d_kqfilter = nokqfilter, 143 .d_discard = dkdiscard, 144 .d_flag = D_DISK | D_MPSAFE 145 }; 146 147 static struct dkwedge_softc **dkwedges; 148 static u_int ndkwedges; 149 static krwlock_t dkwedges_lock; 150 151 static LIST_HEAD(, dkwedge_discovery_method) dkwedge_discovery_methods; 152 static krwlock_t dkwedge_discovery_methods_lock; 153 154 /* 155 * dkwedge_match: 156 * 157 * Autoconfiguration match function for pseudo-device glue. 158 */ 159 static int 160 dkwedge_match(device_t parent, cfdata_t match, 161 void *aux) 162 { 163 164 /* Pseudo-device; always present. */ 165 return (1); 166 } 167 168 /* 169 * dkwedge_attach: 170 * 171 * Autoconfiguration attach function for pseudo-device glue. 172 */ 173 static void 174 dkwedge_attach(device_t parent, device_t self, 175 void *aux) 176 { 177 178 if (!pmf_device_register(self, NULL, NULL)) 179 aprint_error_dev(self, "couldn't establish power handler\n"); 180 } 181 182 CFDRIVER_DECL(dk, DV_DISK, NULL); 183 CFATTACH_DECL3_NEW(dk, 0, 184 dkwedge_match, dkwedge_attach, dkwedge_detach, NULL, NULL, NULL, 185 DVF_DETACH_SHUTDOWN); 186 187 /* 188 * dkwedge_wait_drain: 189 * 190 * Wait for I/O on the wedge to drain. 191 */ 192 static void 193 dkwedge_wait_drain(struct dkwedge_softc *sc) 194 { 195 196 mutex_enter(&sc->sc_iolock); 197 while (sc->sc_iopend != 0) { 198 sc->sc_flags |= DK_F_WAIT_DRAIN; 199 cv_wait(&sc->sc_dkdrn, &sc->sc_iolock); 200 } 201 mutex_exit(&sc->sc_iolock); 202 } 203 204 /* 205 * dkwedge_compute_pdev: 206 * 207 * Compute the parent disk's dev_t. 208 */ 209 static int 210 dkwedge_compute_pdev(const char *pname, dev_t *pdevp, enum vtype type) 211 { 212 const char *name, *cp; 213 devmajor_t pmaj; 214 int punit; 215 char devname[16]; 216 217 name = pname; 218 switch (type) { 219 case VBLK: 220 pmaj = devsw_name2blk(name, devname, sizeof(devname)); 221 break; 222 case VCHR: 223 pmaj = devsw_name2chr(name, devname, sizeof(devname)); 224 break; 225 default: 226 pmaj = NODEVMAJOR; 227 break; 228 } 229 if (pmaj == NODEVMAJOR) 230 return (ENODEV); 231 232 name += strlen(devname); 233 for (cp = name, punit = 0; *cp >= '0' && *cp <= '9'; cp++) 234 punit = (punit * 10) + (*cp - '0'); 235 if (cp == name) { 236 /* Invalid parent disk name. */ 237 return (ENODEV); 238 } 239 240 *pdevp = MAKEDISKDEV(pmaj, punit, RAW_PART); 241 242 return (0); 243 } 244 245 /* 246 * dkwedge_array_expand: 247 * 248 * Expand the dkwedges array. 249 */ 250 static void 251 dkwedge_array_expand(void) 252 { 253 int newcnt = ndkwedges + 16; 254 struct dkwedge_softc **newarray, **oldarray; 255 256 newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE, 257 M_WAITOK|M_ZERO); 258 if ((oldarray = dkwedges) != NULL) 259 memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray)); 260 dkwedges = newarray; 261 ndkwedges = newcnt; 262 if (oldarray != NULL) 263 free(oldarray, M_DKWEDGE); 264 } 265 266 static void 267 dk_set_geometry(struct dkwedge_softc *sc, struct disk *pdk) 268 { 269 struct disk *dk = &sc->sc_dk; 270 struct disk_geom *dg = &dk->dk_geom; 271 272 memset(dg, 0, sizeof(*dg)); 273 274 dg->dg_secperunit = sc->sc_size; 275 dg->dg_secsize = DEV_BSIZE << pdk->dk_blkshift; 276 277 /* fake numbers, 1 cylinder is 1 MB with default sector size */ 278 dg->dg_nsectors = 32; 279 dg->dg_ntracks = 64; 280 dg->dg_ncylinders = dg->dg_secperunit / (dg->dg_nsectors * dg->dg_ntracks); 281 282 disk_set_info(sc->sc_dev, dk, NULL); 283 } 284 285 /* 286 * dkwedge_add: [exported function] 287 * 288 * Add a disk wedge based on the provided information. 289 * 290 * The incoming dkw_devname[] is ignored, instead being 291 * filled in and returned to the caller. 292 */ 293 int 294 dkwedge_add(struct dkwedge_info *dkw) 295 { 296 struct dkwedge_softc *sc, *lsc; 297 struct disk *pdk; 298 u_int unit; 299 int error; 300 dev_t pdev; 301 302 dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0'; 303 pdk = disk_find(dkw->dkw_parent); 304 if (pdk == NULL) 305 return (ENODEV); 306 307 error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VBLK); 308 if (error) 309 return (error); 310 311 if (dkw->dkw_offset < 0) 312 return (EINVAL); 313 314 /* 315 * Check for an existing wedge at the same disk offset. Allow 316 * updating a wedge if the only change is the size, and the new 317 * size is larger than the old. 318 */ 319 sc = NULL; 320 mutex_enter(&pdk->dk_openlock); 321 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 322 if (lsc->sc_offset != dkw->dkw_offset) 323 continue; 324 if (strcmp(lsc->sc_wname, dkw->dkw_wname) != 0) 325 break; 326 if (strcmp(lsc->sc_ptype, dkw->dkw_ptype) != 0) 327 break; 328 if (lsc->sc_size > dkw->dkw_size) 329 break; 330 331 sc = lsc; 332 sc->sc_size = dkw->dkw_size; 333 dk_set_geometry(sc, pdk); 334 335 break; 336 } 337 mutex_exit(&pdk->dk_openlock); 338 339 if (sc != NULL) 340 goto announce; 341 342 sc = malloc(sizeof(*sc), M_DKWEDGE, M_WAITOK|M_ZERO); 343 sc->sc_state = DKW_STATE_LARVAL; 344 sc->sc_parent = pdk; 345 sc->sc_pdev = pdev; 346 sc->sc_offset = dkw->dkw_offset; 347 sc->sc_size = dkw->dkw_size; 348 349 memcpy(sc->sc_wname, dkw->dkw_wname, sizeof(sc->sc_wname)); 350 sc->sc_wname[sizeof(sc->sc_wname) - 1] = '\0'; 351 352 memcpy(sc->sc_ptype, dkw->dkw_ptype, sizeof(sc->sc_ptype)); 353 sc->sc_ptype[sizeof(sc->sc_ptype) - 1] = '\0'; 354 355 bufq_alloc(&sc->sc_bufq, "fcfs", 0); 356 357 callout_init(&sc->sc_restart_ch, 0); 358 callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); 359 360 mutex_init(&sc->sc_iolock, MUTEX_DEFAULT, IPL_BIO); 361 cv_init(&sc->sc_dkdrn, "dkdrn"); 362 363 /* 364 * Wedge will be added; increment the wedge count for the parent. 365 * Only allow this to happend if RAW_PART is the only thing open. 366 */ 367 mutex_enter(&pdk->dk_openlock); 368 if (pdk->dk_openmask & ~(1 << RAW_PART)) 369 error = EBUSY; 370 else { 371 /* Check for wedge overlap. */ 372 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 373 daddr_t lastblk = sc->sc_offset + sc->sc_size - 1; 374 daddr_t llastblk = lsc->sc_offset + lsc->sc_size - 1; 375 376 if (sc->sc_offset >= lsc->sc_offset && 377 sc->sc_offset <= llastblk) { 378 /* Overlaps the tail of the existing wedge. */ 379 break; 380 } 381 if (lastblk >= lsc->sc_offset && 382 lastblk <= llastblk) { 383 /* Overlaps the head of the existing wedge. */ 384 break; 385 } 386 } 387 if (lsc != NULL) { 388 if (sc->sc_offset == lsc->sc_offset && 389 sc->sc_size == lsc->sc_size && 390 strcmp(sc->sc_wname, lsc->sc_wname) == 0) 391 error = EEXIST; 392 else 393 error = EINVAL; 394 } else { 395 pdk->dk_nwedges++; 396 LIST_INSERT_HEAD(&pdk->dk_wedges, sc, sc_plink); 397 } 398 } 399 mutex_exit(&pdk->dk_openlock); 400 if (error) { 401 cv_destroy(&sc->sc_dkdrn); 402 mutex_destroy(&sc->sc_iolock); 403 bufq_free(sc->sc_bufq); 404 free(sc, M_DKWEDGE); 405 return (error); 406 } 407 408 /* Fill in our cfdata for the pseudo-device glue. */ 409 sc->sc_cfdata.cf_name = dk_cd.cd_name; 410 sc->sc_cfdata.cf_atname = dk_ca.ca_name; 411 /* sc->sc_cfdata.cf_unit set below */ 412 sc->sc_cfdata.cf_fstate = FSTATE_STAR; 413 414 /* Insert the larval wedge into the array. */ 415 rw_enter(&dkwedges_lock, RW_WRITER); 416 for (error = 0;;) { 417 struct dkwedge_softc **scpp; 418 419 /* 420 * Check for a duplicate wname while searching for 421 * a slot. 422 */ 423 for (scpp = NULL, unit = 0; unit < ndkwedges; unit++) { 424 if (dkwedges[unit] == NULL) { 425 if (scpp == NULL) { 426 scpp = &dkwedges[unit]; 427 sc->sc_cfdata.cf_unit = unit; 428 } 429 } else { 430 /* XXX Unicode. */ 431 if (strcmp(dkwedges[unit]->sc_wname, 432 sc->sc_wname) == 0) { 433 error = EEXIST; 434 break; 435 } 436 } 437 } 438 if (error) 439 break; 440 KASSERT(unit == ndkwedges); 441 if (scpp == NULL) 442 dkwedge_array_expand(); 443 else { 444 KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]); 445 *scpp = sc; 446 break; 447 } 448 } 449 rw_exit(&dkwedges_lock); 450 if (error) { 451 mutex_enter(&pdk->dk_openlock); 452 pdk->dk_nwedges--; 453 LIST_REMOVE(sc, sc_plink); 454 mutex_exit(&pdk->dk_openlock); 455 456 cv_destroy(&sc->sc_dkdrn); 457 mutex_destroy(&sc->sc_iolock); 458 bufq_free(sc->sc_bufq); 459 free(sc, M_DKWEDGE); 460 return (error); 461 } 462 463 /* 464 * Now that we know the unit #, attach a pseudo-device for 465 * this wedge instance. This will provide us with the 466 * device_t necessary for glue to other parts of the system. 467 * 468 * This should never fail, unless we're almost totally out of 469 * memory. 470 */ 471 if ((sc->sc_dev = config_attach_pseudo(&sc->sc_cfdata)) == NULL) { 472 aprint_error("%s%u: unable to attach pseudo-device\n", 473 sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit); 474 475 rw_enter(&dkwedges_lock, RW_WRITER); 476 dkwedges[sc->sc_cfdata.cf_unit] = NULL; 477 rw_exit(&dkwedges_lock); 478 479 mutex_enter(&pdk->dk_openlock); 480 pdk->dk_nwedges--; 481 LIST_REMOVE(sc, sc_plink); 482 mutex_exit(&pdk->dk_openlock); 483 484 cv_destroy(&sc->sc_dkdrn); 485 mutex_destroy(&sc->sc_iolock); 486 bufq_free(sc->sc_bufq); 487 free(sc, M_DKWEDGE); 488 return (ENOMEM); 489 } 490 491 /* Return the devname to the caller. */ 492 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 493 sizeof(dkw->dkw_devname)); 494 495 /* 496 * XXX Really ought to make the disk_attach() and the changing 497 * of state to RUNNING atomic. 498 */ 499 500 disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL); 501 dk_set_geometry(sc, pdk); 502 disk_attach(&sc->sc_dk); 503 504 /* Disk wedge is ready for use! */ 505 sc->sc_state = DKW_STATE_RUNNING; 506 507 announce: 508 /* Announce our arrival. */ 509 aprint_normal( 510 "%s at %s: \"%s\", %"PRIu64" blocks at %"PRId64", type: %s\n", 511 device_xname(sc->sc_dev), pdk->dk_name, 512 sc->sc_wname, /* XXX Unicode */ 513 sc->sc_size, sc->sc_offset, 514 sc->sc_ptype[0] == '\0' ? "<unknown>" : sc->sc_ptype); 515 516 return (0); 517 } 518 519 /* 520 * dkwedge_find: 521 * 522 * Lookup a disk wedge based on the provided information. 523 * NOTE: We look up the wedge based on the wedge devname, 524 * not wname. 525 * 526 * Return NULL if the wedge is not found, otherwise return 527 * the wedge's softc. Assign the wedge's unit number to unitp 528 * if unitp is not NULL. 529 */ 530 static struct dkwedge_softc * 531 dkwedge_find(struct dkwedge_info *dkw, u_int *unitp) 532 { 533 struct dkwedge_softc *sc = NULL; 534 u_int unit; 535 536 /* Find our softc. */ 537 dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0'; 538 rw_enter(&dkwedges_lock, RW_READER); 539 for (unit = 0; unit < ndkwedges; unit++) { 540 if ((sc = dkwedges[unit]) != NULL && 541 strcmp(device_xname(sc->sc_dev), dkw->dkw_devname) == 0 && 542 strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) { 543 break; 544 } 545 } 546 rw_exit(&dkwedges_lock); 547 if (unit == ndkwedges) 548 return NULL; 549 550 if (unitp != NULL) 551 *unitp = unit; 552 553 return sc; 554 } 555 556 /* 557 * dkwedge_del: [exported function] 558 * 559 * Delete a disk wedge based on the provided information. 560 * NOTE: We look up the wedge based on the wedge devname, 561 * not wname. 562 */ 563 int 564 dkwedge_del(struct dkwedge_info *dkw) 565 { 566 return dkwedge_del1(dkw, 0); 567 } 568 569 int 570 dkwedge_del1(struct dkwedge_info *dkw, int flags) 571 { 572 struct dkwedge_softc *sc = NULL; 573 574 /* Find our softc. */ 575 if ((sc = dkwedge_find(dkw, NULL)) == NULL) 576 return (ESRCH); 577 578 return config_detach(sc->sc_dev, flags); 579 } 580 581 static int 582 dkwedge_cleanup_parent(struct dkwedge_softc *sc, int flags) 583 { 584 struct disk *dk = &sc->sc_dk; 585 int rc; 586 587 rc = 0; 588 mutex_enter(&dk->dk_openlock); 589 if (dk->dk_openmask == 0) 590 /* nothing to do */ 591 mutex_exit(&dk->dk_openlock); 592 else if ((flags & DETACH_FORCE) == 0) { 593 rc = EBUSY; 594 mutex_exit(&dk->dk_openlock); 595 } else { 596 mutex_enter(&sc->sc_parent->dk_rawlock); 597 rc = dklastclose(sc); /* releases locks */ 598 } 599 600 return rc; 601 } 602 603 /* 604 * dkwedge_detach: 605 * 606 * Autoconfiguration detach function for pseudo-device glue. 607 */ 608 static int 609 dkwedge_detach(device_t self, int flags) 610 { 611 struct dkwedge_softc *sc = NULL; 612 u_int unit; 613 int bmaj, cmaj, rc; 614 615 rw_enter(&dkwedges_lock, RW_WRITER); 616 for (unit = 0; unit < ndkwedges; unit++) { 617 if ((sc = dkwedges[unit]) != NULL && sc->sc_dev == self) 618 break; 619 } 620 if (unit == ndkwedges) 621 rc = ENXIO; 622 else if ((rc = dkwedge_cleanup_parent(sc, flags)) == 0) { 623 /* Mark the wedge as dying. */ 624 sc->sc_state = DKW_STATE_DYING; 625 } 626 rw_exit(&dkwedges_lock); 627 628 if (rc != 0) 629 return rc; 630 631 pmf_device_deregister(self); 632 633 /* Locate the wedge major numbers. */ 634 bmaj = bdevsw_lookup_major(&dk_bdevsw); 635 cmaj = cdevsw_lookup_major(&dk_cdevsw); 636 637 /* Kill any pending restart. */ 638 callout_stop(&sc->sc_restart_ch); 639 640 /* 641 * dkstart() will kill any queued buffers now that the 642 * state of the wedge is not RUNNING. Once we've done 643 * that, wait for any other pending I/O to complete. 644 */ 645 dkstart(sc); 646 dkwedge_wait_drain(sc); 647 648 /* Nuke the vnodes for any open instances. */ 649 vdevgone(bmaj, unit, unit, VBLK); 650 vdevgone(cmaj, unit, unit, VCHR); 651 652 /* Clean up the parent. */ 653 dkwedge_cleanup_parent(sc, flags | DETACH_FORCE); 654 655 /* Announce our departure. */ 656 aprint_normal("%s at %s (%s) deleted\n", device_xname(sc->sc_dev), 657 sc->sc_parent->dk_name, 658 sc->sc_wname); /* XXX Unicode */ 659 660 mutex_enter(&sc->sc_parent->dk_openlock); 661 sc->sc_parent->dk_nwedges--; 662 LIST_REMOVE(sc, sc_plink); 663 mutex_exit(&sc->sc_parent->dk_openlock); 664 665 /* Delete our buffer queue. */ 666 bufq_free(sc->sc_bufq); 667 668 /* Detach from the disk list. */ 669 disk_detach(&sc->sc_dk); 670 disk_destroy(&sc->sc_dk); 671 672 /* Poof. */ 673 rw_enter(&dkwedges_lock, RW_WRITER); 674 dkwedges[unit] = NULL; 675 sc->sc_state = DKW_STATE_DEAD; 676 rw_exit(&dkwedges_lock); 677 678 mutex_destroy(&sc->sc_iolock); 679 cv_destroy(&sc->sc_dkdrn); 680 681 free(sc, M_DKWEDGE); 682 683 return 0; 684 } 685 686 /* 687 * dkwedge_delall: [exported function] 688 * 689 * Delete all of the wedges on the specified disk. Used when 690 * a disk is being detached. 691 */ 692 void 693 dkwedge_delall(struct disk *pdk) 694 { 695 dkwedge_delall1(pdk, false); 696 } 697 698 static void 699 dkwedge_delall1(struct disk *pdk, bool idleonly) 700 { 701 struct dkwedge_info dkw; 702 struct dkwedge_softc *sc; 703 int flags; 704 705 flags = DETACH_QUIET; 706 if (!idleonly) flags |= DETACH_FORCE; 707 708 for (;;) { 709 mutex_enter(&pdk->dk_openlock); 710 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 711 if (!idleonly || sc->sc_dk.dk_openmask == 0) 712 break; 713 } 714 if (sc == NULL) { 715 KASSERT(idleonly || pdk->dk_nwedges == 0); 716 mutex_exit(&pdk->dk_openlock); 717 return; 718 } 719 strlcpy(dkw.dkw_parent, pdk->dk_name, sizeof(dkw.dkw_parent)); 720 strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev), 721 sizeof(dkw.dkw_devname)); 722 mutex_exit(&pdk->dk_openlock); 723 (void) dkwedge_del1(&dkw, flags); 724 } 725 } 726 727 /* 728 * dkwedge_list: [exported function] 729 * 730 * List all of the wedges on a particular disk. 731 */ 732 int 733 dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l) 734 { 735 struct uio uio; 736 struct iovec iov; 737 struct dkwedge_softc *sc; 738 struct dkwedge_info dkw; 739 int error = 0; 740 741 iov.iov_base = dkwl->dkwl_buf; 742 iov.iov_len = dkwl->dkwl_bufsize; 743 744 uio.uio_iov = &iov; 745 uio.uio_iovcnt = 1; 746 uio.uio_offset = 0; 747 uio.uio_resid = dkwl->dkwl_bufsize; 748 uio.uio_rw = UIO_READ; 749 KASSERT(l == curlwp); 750 uio.uio_vmspace = l->l_proc->p_vmspace; 751 752 dkwl->dkwl_ncopied = 0; 753 754 mutex_enter(&pdk->dk_openlock); 755 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 756 if (uio.uio_resid < sizeof(dkw)) 757 break; 758 759 if (sc->sc_state != DKW_STATE_RUNNING) 760 continue; 761 762 strlcpy(dkw.dkw_devname, device_xname(sc->sc_dev), 763 sizeof(dkw.dkw_devname)); 764 memcpy(dkw.dkw_wname, sc->sc_wname, sizeof(dkw.dkw_wname)); 765 dkw.dkw_wname[sizeof(dkw.dkw_wname) - 1] = '\0'; 766 strlcpy(dkw.dkw_parent, sc->sc_parent->dk_name, 767 sizeof(dkw.dkw_parent)); 768 dkw.dkw_offset = sc->sc_offset; 769 dkw.dkw_size = sc->sc_size; 770 strlcpy(dkw.dkw_ptype, sc->sc_ptype, sizeof(dkw.dkw_ptype)); 771 772 error = uiomove(&dkw, sizeof(dkw), &uio); 773 if (error) 774 break; 775 dkwl->dkwl_ncopied++; 776 } 777 dkwl->dkwl_nwedges = pdk->dk_nwedges; 778 mutex_exit(&pdk->dk_openlock); 779 780 return (error); 781 } 782 783 device_t 784 dkwedge_find_by_wname(const char *wname) 785 { 786 device_t dv = NULL; 787 struct dkwedge_softc *sc; 788 int i; 789 790 rw_enter(&dkwedges_lock, RW_WRITER); 791 for (i = 0; i < ndkwedges; i++) { 792 if ((sc = dkwedges[i]) == NULL) 793 continue; 794 if (strcmp(sc->sc_wname, wname) == 0) { 795 if (dv != NULL) { 796 printf( 797 "WARNING: double match for wedge name %s " 798 "(%s, %s)\n", wname, device_xname(dv), 799 device_xname(sc->sc_dev)); 800 continue; 801 } 802 dv = sc->sc_dev; 803 } 804 } 805 rw_exit(&dkwedges_lock); 806 return dv; 807 } 808 809 device_t 810 dkwedge_find_by_parent(const char *name, size_t *i) 811 { 812 rw_enter(&dkwedges_lock, RW_WRITER); 813 for (; *i < (size_t)ndkwedges; (*i)++) { 814 struct dkwedge_softc *sc; 815 if ((sc = dkwedges[*i]) == NULL) 816 continue; 817 if (strcmp(sc->sc_parent->dk_name, name) != 0) 818 continue; 819 rw_exit(&dkwedges_lock); 820 return sc->sc_dev; 821 } 822 rw_exit(&dkwedges_lock); 823 return NULL; 824 } 825 826 void 827 dkwedge_print_wnames(void) 828 { 829 struct dkwedge_softc *sc; 830 int i; 831 832 rw_enter(&dkwedges_lock, RW_WRITER); 833 for (i = 0; i < ndkwedges; i++) { 834 if ((sc = dkwedges[i]) == NULL) 835 continue; 836 printf(" wedge:%s", sc->sc_wname); 837 } 838 rw_exit(&dkwedges_lock); 839 } 840 841 /* 842 * We need a dummy object to stuff into the dkwedge discovery method link 843 * set to ensure that there is always at least one object in the set. 844 */ 845 static struct dkwedge_discovery_method dummy_discovery_method; 846 __link_set_add_bss(dkwedge_methods, dummy_discovery_method); 847 848 /* 849 * dkwedge_init: 850 * 851 * Initialize the disk wedge subsystem. 852 */ 853 void 854 dkwedge_init(void) 855 { 856 __link_set_decl(dkwedge_methods, struct dkwedge_discovery_method); 857 struct dkwedge_discovery_method * const *ddmp; 858 struct dkwedge_discovery_method *lddm, *ddm; 859 860 rw_init(&dkwedges_lock); 861 rw_init(&dkwedge_discovery_methods_lock); 862 863 if (config_cfdriver_attach(&dk_cd) != 0) 864 panic("dkwedge: unable to attach cfdriver"); 865 if (config_cfattach_attach(dk_cd.cd_name, &dk_ca) != 0) 866 panic("dkwedge: unable to attach cfattach"); 867 868 rw_enter(&dkwedge_discovery_methods_lock, RW_WRITER); 869 870 LIST_INIT(&dkwedge_discovery_methods); 871 872 __link_set_foreach(ddmp, dkwedge_methods) { 873 ddm = *ddmp; 874 if (ddm == &dummy_discovery_method) 875 continue; 876 if (LIST_EMPTY(&dkwedge_discovery_methods)) { 877 LIST_INSERT_HEAD(&dkwedge_discovery_methods, 878 ddm, ddm_list); 879 continue; 880 } 881 LIST_FOREACH(lddm, &dkwedge_discovery_methods, ddm_list) { 882 if (ddm->ddm_priority == lddm->ddm_priority) { 883 aprint_error("dk-method-%s: method \"%s\" " 884 "already exists at priority %d\n", 885 ddm->ddm_name, lddm->ddm_name, 886 lddm->ddm_priority); 887 /* Not inserted. */ 888 break; 889 } 890 if (ddm->ddm_priority < lddm->ddm_priority) { 891 /* Higher priority; insert before. */ 892 LIST_INSERT_BEFORE(lddm, ddm, ddm_list); 893 break; 894 } 895 if (LIST_NEXT(lddm, ddm_list) == NULL) { 896 /* Last one; insert after. */ 897 KASSERT(lddm->ddm_priority < ddm->ddm_priority); 898 LIST_INSERT_AFTER(lddm, ddm, ddm_list); 899 break; 900 } 901 } 902 } 903 904 rw_exit(&dkwedge_discovery_methods_lock); 905 } 906 907 #ifdef DKWEDGE_AUTODISCOVER 908 int dkwedge_autodiscover = 1; 909 #else 910 int dkwedge_autodiscover = 0; 911 #endif 912 913 /* 914 * dkwedge_discover: [exported function] 915 * 916 * Discover the wedges on a newly attached disk. 917 * Remove all unused wedges on the disk first. 918 */ 919 void 920 dkwedge_discover(struct disk *pdk) 921 { 922 struct dkwedge_discovery_method *ddm; 923 struct vnode *vp; 924 int error; 925 dev_t pdev; 926 927 /* 928 * Require people playing with wedges to enable this explicitly. 929 */ 930 if (dkwedge_autodiscover == 0) 931 return; 932 933 rw_enter(&dkwedge_discovery_methods_lock, RW_READER); 934 935 /* 936 * Use the character device for scanning, the block device 937 * is busy if there are already wedges attached. 938 */ 939 error = dkwedge_compute_pdev(pdk->dk_name, &pdev, VCHR); 940 if (error) { 941 aprint_error("%s: unable to compute pdev, error = %d\n", 942 pdk->dk_name, error); 943 goto out; 944 } 945 946 error = cdevvp(pdev, &vp); 947 if (error) { 948 aprint_error("%s: unable to find vnode for pdev, error = %d\n", 949 pdk->dk_name, error); 950 goto out; 951 } 952 953 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 954 if (error) { 955 aprint_error("%s: unable to lock vnode for pdev, error = %d\n", 956 pdk->dk_name, error); 957 vrele(vp); 958 goto out; 959 } 960 961 error = VOP_OPEN(vp, FREAD | FSILENT, NOCRED); 962 if (error) { 963 if (error != ENODEV) 964 aprint_error("%s: unable to open device, error = %d\n", 965 pdk->dk_name, error); 966 vput(vp); 967 goto out; 968 } 969 VOP_UNLOCK(vp); 970 971 /* 972 * Remove unused wedges 973 */ 974 dkwedge_delall1(pdk, true); 975 976 /* 977 * For each supported partition map type, look to see if 978 * this map type exists. If so, parse it and add the 979 * corresponding wedges. 980 */ 981 LIST_FOREACH(ddm, &dkwedge_discovery_methods, ddm_list) { 982 error = (*ddm->ddm_discover)(pdk, vp); 983 if (error == 0) { 984 /* Successfully created wedges; we're done. */ 985 break; 986 } 987 } 988 989 error = vn_close(vp, FREAD, NOCRED); 990 if (error) { 991 aprint_error("%s: unable to close device, error = %d\n", 992 pdk->dk_name, error); 993 /* We'll just assume the vnode has been cleaned up. */ 994 } 995 996 out: 997 rw_exit(&dkwedge_discovery_methods_lock); 998 } 999 1000 /* 1001 * dkwedge_read: 1002 * 1003 * Read some data from the specified disk, used for 1004 * partition discovery. 1005 */ 1006 int 1007 dkwedge_read(struct disk *pdk, struct vnode *vp, daddr_t blkno, 1008 void *tbuf, size_t len) 1009 { 1010 buf_t *bp; 1011 int error; 1012 bool isopen; 1013 dev_t bdev; 1014 struct vnode *bdvp; 1015 1016 /* 1017 * The kernel cannot read from a character device vnode 1018 * as physio() only handles user memory. 1019 * 1020 * If the block device has already been opened by a wedge 1021 * use that vnode and temporarily bump the open counter. 1022 * 1023 * Otherwise try to open the block device. 1024 */ 1025 1026 bdev = devsw_chr2blk(vp->v_rdev); 1027 1028 mutex_enter(&pdk->dk_rawlock); 1029 if (pdk->dk_rawopens != 0) { 1030 KASSERT(pdk->dk_rawvp != NULL); 1031 isopen = true; 1032 ++pdk->dk_rawopens; 1033 bdvp = pdk->dk_rawvp; 1034 error = 0; 1035 } else { 1036 isopen = false; 1037 error = dk_open_parent(bdev, FREAD, &bdvp); 1038 } 1039 mutex_exit(&pdk->dk_rawlock); 1040 1041 if (error) 1042 return error; 1043 1044 bp = getiobuf(bdvp, true); 1045 bp->b_flags = B_READ; 1046 bp->b_cflags = BC_BUSY; 1047 bp->b_dev = bdev; 1048 bp->b_data = tbuf; 1049 bp->b_bufsize = bp->b_bcount = len; 1050 bp->b_blkno = blkno; 1051 bp->b_cylinder = 0; 1052 bp->b_error = 0; 1053 1054 VOP_STRATEGY(bdvp, bp); 1055 error = biowait(bp); 1056 putiobuf(bp); 1057 1058 mutex_enter(&pdk->dk_rawlock); 1059 if (isopen) { 1060 --pdk->dk_rawopens; 1061 } else { 1062 dk_close_parent(bdvp, FREAD); 1063 } 1064 mutex_exit(&pdk->dk_rawlock); 1065 1066 return error; 1067 } 1068 1069 /* 1070 * dkwedge_lookup: 1071 * 1072 * Look up a dkwedge_softc based on the provided dev_t. 1073 */ 1074 static struct dkwedge_softc * 1075 dkwedge_lookup(dev_t dev) 1076 { 1077 int unit = minor(dev); 1078 1079 if (unit >= ndkwedges) 1080 return (NULL); 1081 1082 KASSERT(dkwedges != NULL); 1083 1084 return (dkwedges[unit]); 1085 } 1086 1087 static int 1088 dk_open_parent(dev_t dev, int mode, struct vnode **vpp) 1089 { 1090 struct vnode *vp; 1091 int error; 1092 1093 error = bdevvp(dev, &vp); 1094 if (error) 1095 return error; 1096 1097 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1098 if (error) { 1099 vrele(vp); 1100 return error; 1101 } 1102 error = VOP_OPEN(vp, mode, NOCRED); 1103 if (error) { 1104 vput(vp); 1105 return error; 1106 } 1107 1108 /* VOP_OPEN() doesn't do this for us. */ 1109 if (mode & FWRITE) { 1110 mutex_enter(vp->v_interlock); 1111 vp->v_writecount++; 1112 mutex_exit(vp->v_interlock); 1113 } 1114 1115 VOP_UNLOCK(vp); 1116 1117 *vpp = vp; 1118 1119 return 0; 1120 } 1121 1122 static int 1123 dk_close_parent(struct vnode *vp, int mode) 1124 { 1125 int error; 1126 1127 error = vn_close(vp, mode, NOCRED); 1128 return error; 1129 } 1130 1131 /* 1132 * dkopen: [devsw entry point] 1133 * 1134 * Open a wedge. 1135 */ 1136 static int 1137 dkopen(dev_t dev, int flags, int fmt, struct lwp *l) 1138 { 1139 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1140 struct vnode *vp; 1141 int error = 0; 1142 int mode; 1143 1144 if (sc == NULL) 1145 return (ENODEV); 1146 if (sc->sc_state != DKW_STATE_RUNNING) 1147 return (ENXIO); 1148 1149 /* 1150 * We go through a complicated little dance to only open the parent 1151 * vnode once per wedge, no matter how many times the wedge is 1152 * opened. The reason? We see one dkopen() per open call, but 1153 * only dkclose() on the last close. 1154 */ 1155 mutex_enter(&sc->sc_dk.dk_openlock); 1156 mutex_enter(&sc->sc_parent->dk_rawlock); 1157 if (sc->sc_dk.dk_openmask == 0) { 1158 if (sc->sc_parent->dk_rawopens == 0) { 1159 KASSERT(sc->sc_parent->dk_rawvp == NULL); 1160 /* 1161 * Try open read-write. If this fails for EROFS 1162 * and wedge is read-only, retry to open read-only. 1163 */ 1164 mode = FREAD | FWRITE; 1165 error = dk_open_parent(sc->sc_pdev, mode, &vp); 1166 if (error == EROFS && (flags & FWRITE) == 0) { 1167 mode &= ~FWRITE; 1168 error = dk_open_parent(sc->sc_pdev, mode, &vp); 1169 } 1170 if (error) 1171 goto popen_fail; 1172 /* remember open mode */ 1173 sc->sc_mode = mode; 1174 sc->sc_parent->dk_rawvp = vp; 1175 } 1176 sc->sc_parent->dk_rawopens++; 1177 } else if (flags & ~sc->sc_mode & FWRITE) { 1178 /* parent is opened read-only, cannot open read-write */ 1179 error = EROFS; 1180 goto popen_fail; 1181 } 1182 if (fmt == S_IFCHR) 1183 sc->sc_dk.dk_copenmask |= 1; 1184 else 1185 sc->sc_dk.dk_bopenmask |= 1; 1186 sc->sc_dk.dk_openmask = 1187 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1188 1189 popen_fail: 1190 mutex_exit(&sc->sc_parent->dk_rawlock); 1191 mutex_exit(&sc->sc_dk.dk_openlock); 1192 return (error); 1193 } 1194 1195 /* 1196 * Caller must hold sc->sc_dk.dk_openlock and sc->sc_parent->dk_rawlock. 1197 */ 1198 static int 1199 dklastclose(struct dkwedge_softc *sc) 1200 { 1201 struct vnode *vp; 1202 int error = 0; 1203 1204 vp = NULL; 1205 if (sc->sc_parent->dk_rawopens > 0) { 1206 if (--sc->sc_parent->dk_rawopens == 0) { 1207 KASSERT(sc->sc_parent->dk_rawvp != NULL); 1208 vp = sc->sc_parent->dk_rawvp; 1209 sc->sc_parent->dk_rawvp = NULL; 1210 } 1211 } 1212 1213 mutex_exit(&sc->sc_parent->dk_rawlock); 1214 mutex_exit(&sc->sc_dk.dk_openlock); 1215 1216 if (vp) { 1217 dk_close_parent(vp, sc->sc_mode); 1218 } 1219 1220 return error; 1221 } 1222 1223 /* 1224 * dkclose: [devsw entry point] 1225 * 1226 * Close a wedge. 1227 */ 1228 static int 1229 dkclose(dev_t dev, int flags, int fmt, struct lwp *l) 1230 { 1231 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1232 int error = 0; 1233 1234 if (sc == NULL) 1235 return (ENODEV); 1236 if (sc->sc_state != DKW_STATE_RUNNING) 1237 return (ENXIO); 1238 1239 KASSERT(sc->sc_dk.dk_openmask != 0); 1240 1241 mutex_enter(&sc->sc_dk.dk_openlock); 1242 mutex_enter(&sc->sc_parent->dk_rawlock); 1243 1244 if (fmt == S_IFCHR) 1245 sc->sc_dk.dk_copenmask &= ~1; 1246 else 1247 sc->sc_dk.dk_bopenmask &= ~1; 1248 sc->sc_dk.dk_openmask = 1249 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 1250 1251 if (sc->sc_dk.dk_openmask == 0) 1252 error = dklastclose(sc); /* releases locks */ 1253 else { 1254 mutex_exit(&sc->sc_parent->dk_rawlock); 1255 mutex_exit(&sc->sc_dk.dk_openlock); 1256 } 1257 1258 return (error); 1259 } 1260 1261 /* 1262 * dkstragegy: [devsw entry point] 1263 * 1264 * Perform I/O based on the wedge I/O strategy. 1265 */ 1266 static void 1267 dkstrategy(struct buf *bp) 1268 { 1269 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1270 uint64_t p_size, p_offset; 1271 1272 if (sc == NULL) { 1273 bp->b_error = ENODEV; 1274 goto done; 1275 } 1276 1277 if (sc->sc_state != DKW_STATE_RUNNING || 1278 sc->sc_parent->dk_rawvp == NULL) { 1279 bp->b_error = ENXIO; 1280 goto done; 1281 } 1282 1283 /* If it's an empty transfer, wake up the top half now. */ 1284 if (bp->b_bcount == 0) 1285 goto done; 1286 1287 p_offset = sc->sc_offset << sc->sc_parent->dk_blkshift; 1288 p_size = sc->sc_size << sc->sc_parent->dk_blkshift; 1289 1290 /* Make sure it's in-range. */ 1291 if (bounds_check_with_mediasize(bp, DEV_BSIZE, p_size) <= 0) 1292 goto done; 1293 1294 /* Translate it to the parent's raw LBA. */ 1295 bp->b_rawblkno = bp->b_blkno + p_offset; 1296 1297 /* Place it in the queue and start I/O on the unit. */ 1298 mutex_enter(&sc->sc_iolock); 1299 sc->sc_iopend++; 1300 disk_wait(&sc->sc_dk); 1301 bufq_put(sc->sc_bufq, bp); 1302 mutex_exit(&sc->sc_iolock); 1303 1304 dkstart(sc); 1305 return; 1306 1307 done: 1308 bp->b_resid = bp->b_bcount; 1309 biodone(bp); 1310 } 1311 1312 /* 1313 * dkstart: 1314 * 1315 * Start I/O that has been enqueued on the wedge. 1316 */ 1317 static void 1318 dkstart(struct dkwedge_softc *sc) 1319 { 1320 struct vnode *vp; 1321 struct buf *bp, *nbp; 1322 1323 mutex_enter(&sc->sc_iolock); 1324 1325 /* Do as much work as has been enqueued. */ 1326 while ((bp = bufq_peek(sc->sc_bufq)) != NULL) { 1327 1328 if (sc->sc_state != DKW_STATE_RUNNING) { 1329 (void) bufq_get(sc->sc_bufq); 1330 if (sc->sc_iopend-- == 1 && 1331 (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1332 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1333 cv_broadcast(&sc->sc_dkdrn); 1334 } 1335 mutex_exit(&sc->sc_iolock); 1336 bp->b_error = ENXIO; 1337 bp->b_resid = bp->b_bcount; 1338 biodone(bp); 1339 mutex_enter(&sc->sc_iolock); 1340 continue; 1341 } 1342 1343 /* fetch an I/O buf with sc_iolock dropped */ 1344 mutex_exit(&sc->sc_iolock); 1345 nbp = getiobuf(sc->sc_parent->dk_rawvp, false); 1346 mutex_enter(&sc->sc_iolock); 1347 if (nbp == NULL) { 1348 /* 1349 * No resources to run this request; leave the 1350 * buffer queued up, and schedule a timer to 1351 * restart the queue in 1/2 a second. 1352 */ 1353 callout_schedule(&sc->sc_restart_ch, hz / 2); 1354 break; 1355 } 1356 1357 /* 1358 * fetch buf, this can fail if another thread 1359 * has already processed the queue, it can also 1360 * return a completely different buf. 1361 */ 1362 bp = bufq_get(sc->sc_bufq); 1363 if (bp == NULL) { 1364 mutex_exit(&sc->sc_iolock); 1365 putiobuf(nbp); 1366 mutex_enter(&sc->sc_iolock); 1367 continue; 1368 } 1369 1370 /* Instrumentation. */ 1371 disk_busy(&sc->sc_dk); 1372 1373 /* release lock for VOP_STRATEGY */ 1374 mutex_exit(&sc->sc_iolock); 1375 1376 nbp->b_data = bp->b_data; 1377 nbp->b_flags = bp->b_flags; 1378 nbp->b_oflags = bp->b_oflags; 1379 nbp->b_cflags = bp->b_cflags; 1380 nbp->b_iodone = dkiodone; 1381 nbp->b_proc = bp->b_proc; 1382 nbp->b_blkno = bp->b_rawblkno; 1383 nbp->b_dev = sc->sc_parent->dk_rawvp->v_rdev; 1384 nbp->b_bcount = bp->b_bcount; 1385 nbp->b_private = bp; 1386 BIO_COPYPRIO(nbp, bp); 1387 1388 vp = nbp->b_vp; 1389 if ((nbp->b_flags & B_READ) == 0) { 1390 mutex_enter(vp->v_interlock); 1391 vp->v_numoutput++; 1392 mutex_exit(vp->v_interlock); 1393 } 1394 VOP_STRATEGY(vp, nbp); 1395 1396 mutex_enter(&sc->sc_iolock); 1397 } 1398 1399 mutex_exit(&sc->sc_iolock); 1400 } 1401 1402 /* 1403 * dkiodone: 1404 * 1405 * I/O to a wedge has completed; alert the top half. 1406 */ 1407 static void 1408 dkiodone(struct buf *bp) 1409 { 1410 struct buf *obp = bp->b_private; 1411 struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); 1412 1413 if (bp->b_error != 0) 1414 obp->b_error = bp->b_error; 1415 obp->b_resid = bp->b_resid; 1416 putiobuf(bp); 1417 1418 mutex_enter(&sc->sc_iolock); 1419 if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1420 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1421 cv_broadcast(&sc->sc_dkdrn); 1422 } 1423 1424 disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, 1425 obp->b_flags & B_READ); 1426 mutex_exit(&sc->sc_iolock); 1427 1428 biodone(obp); 1429 1430 /* Kick the queue in case there is more work we can do. */ 1431 dkstart(sc); 1432 } 1433 1434 /* 1435 * dkrestart: 1436 * 1437 * Restart the work queue after it was stalled due to 1438 * a resource shortage. Invoked via a callout. 1439 */ 1440 static void 1441 dkrestart(void *v) 1442 { 1443 struct dkwedge_softc *sc = v; 1444 1445 dkstart(sc); 1446 } 1447 1448 /* 1449 * dkminphys: 1450 * 1451 * Call parent's minphys function. 1452 */ 1453 static void 1454 dkminphys(struct buf *bp) 1455 { 1456 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1457 dev_t dev; 1458 1459 dev = bp->b_dev; 1460 bp->b_dev = sc->sc_pdev; 1461 if (sc->sc_parent->dk_driver && sc->sc_parent->dk_driver->d_minphys) 1462 (*sc->sc_parent->dk_driver->d_minphys)(bp); 1463 else 1464 minphys(bp); 1465 bp->b_dev = dev; 1466 } 1467 1468 /* 1469 * dkread: [devsw entry point] 1470 * 1471 * Read from a wedge. 1472 */ 1473 static int 1474 dkread(dev_t dev, struct uio *uio, int flags) 1475 { 1476 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1477 1478 if (sc == NULL) 1479 return (ENODEV); 1480 if (sc->sc_state != DKW_STATE_RUNNING) 1481 return (ENXIO); 1482 1483 return (physio(dkstrategy, NULL, dev, B_READ, dkminphys, uio)); 1484 } 1485 1486 /* 1487 * dkwrite: [devsw entry point] 1488 * 1489 * Write to a wedge. 1490 */ 1491 static int 1492 dkwrite(dev_t dev, struct uio *uio, int flags) 1493 { 1494 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1495 1496 if (sc == NULL) 1497 return (ENODEV); 1498 if (sc->sc_state != DKW_STATE_RUNNING) 1499 return (ENXIO); 1500 1501 return (physio(dkstrategy, NULL, dev, B_WRITE, dkminphys, uio)); 1502 } 1503 1504 /* 1505 * dkioctl: [devsw entry point] 1506 * 1507 * Perform an ioctl request on a wedge. 1508 */ 1509 static int 1510 dkioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1511 { 1512 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1513 int error = 0; 1514 1515 if (sc == NULL) 1516 return (ENODEV); 1517 if (sc->sc_state != DKW_STATE_RUNNING) 1518 return (ENXIO); 1519 if (sc->sc_parent->dk_rawvp == NULL) 1520 return (ENXIO); 1521 1522 /* 1523 * We pass NODEV instead of our device to indicate we don't 1524 * want to handle disklabel ioctls 1525 */ 1526 error = disk_ioctl(&sc->sc_dk, NODEV, cmd, data, flag, l); 1527 if (error != EPASSTHROUGH) 1528 return (error); 1529 1530 error = 0; 1531 1532 switch (cmd) { 1533 case DIOCGSTRATEGY: 1534 case DIOCGCACHE: 1535 case DIOCCACHESYNC: 1536 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, data, flag, 1537 l != NULL ? l->l_cred : NOCRED); 1538 break; 1539 case DIOCGWEDGEINFO: 1540 { 1541 struct dkwedge_info *dkw = (void *) data; 1542 1543 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 1544 sizeof(dkw->dkw_devname)); 1545 memcpy(dkw->dkw_wname, sc->sc_wname, sizeof(dkw->dkw_wname)); 1546 dkw->dkw_wname[sizeof(dkw->dkw_wname) - 1] = '\0'; 1547 strlcpy(dkw->dkw_parent, sc->sc_parent->dk_name, 1548 sizeof(dkw->dkw_parent)); 1549 dkw->dkw_offset = sc->sc_offset; 1550 dkw->dkw_size = sc->sc_size; 1551 strlcpy(dkw->dkw_ptype, sc->sc_ptype, sizeof(dkw->dkw_ptype)); 1552 1553 break; 1554 } 1555 case DIOCGSECTORALIGN: 1556 { 1557 struct disk_sectoralign *dsa = data; 1558 uint32_t r; 1559 1560 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, dsa, flag, 1561 l != NULL ? l->l_cred : NOCRED); 1562 if (error) 1563 break; 1564 1565 r = sc->sc_offset % dsa->dsa_alignment; 1566 if (r < dsa->dsa_firstaligned) 1567 dsa->dsa_firstaligned = dsa->dsa_firstaligned - r; 1568 else 1569 dsa->dsa_firstaligned = (dsa->dsa_firstaligned + 1570 dsa->dsa_alignment) - r; 1571 break; 1572 } 1573 default: 1574 error = ENOTTY; 1575 } 1576 1577 return (error); 1578 } 1579 1580 /* 1581 * dkdiscard: [devsw entry point] 1582 * 1583 * Perform a discard-range request on a wedge. 1584 */ 1585 static int 1586 dkdiscard(dev_t dev, off_t pos, off_t len) 1587 { 1588 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1589 unsigned shift; 1590 off_t offset, maxlen; 1591 1592 if (sc == NULL) 1593 return (ENODEV); 1594 if (sc->sc_state != DKW_STATE_RUNNING) 1595 return (ENXIO); 1596 if (sc->sc_parent->dk_rawvp == NULL) 1597 return (ENXIO); 1598 1599 shift = (sc->sc_parent->dk_blkshift + DEV_BSHIFT); 1600 KASSERT(__type_fit(off_t, sc->sc_size)); 1601 KASSERT(__type_fit(off_t, sc->sc_offset)); 1602 KASSERT(0 <= sc->sc_offset); 1603 KASSERT(sc->sc_size <= (__type_max(off_t) >> shift)); 1604 KASSERT(sc->sc_offset <= ((__type_max(off_t) >> shift) - sc->sc_size)); 1605 offset = ((off_t)sc->sc_offset << shift); 1606 maxlen = ((off_t)sc->sc_size << shift); 1607 1608 if (len > maxlen) 1609 return (EINVAL); 1610 if (pos > (maxlen - len)) 1611 return (EINVAL); 1612 1613 pos += offset; 1614 return VOP_FDISCARD(sc->sc_parent->dk_rawvp, pos, len); 1615 } 1616 1617 /* 1618 * dksize: [devsw entry point] 1619 * 1620 * Query the size of a wedge for the purpose of performing a dump 1621 * or for swapping to. 1622 */ 1623 static int 1624 dksize(dev_t dev) 1625 { 1626 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1627 int rv = -1; 1628 1629 if (sc == NULL) 1630 return (-1); 1631 if (sc->sc_state != DKW_STATE_RUNNING) 1632 return (-1); 1633 1634 mutex_enter(&sc->sc_dk.dk_openlock); 1635 mutex_enter(&sc->sc_parent->dk_rawlock); 1636 1637 /* Our content type is static, no need to open the device. */ 1638 1639 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) { 1640 /* Saturate if we are larger than INT_MAX. */ 1641 if (sc->sc_size > INT_MAX) 1642 rv = INT_MAX; 1643 else 1644 rv = (int) sc->sc_size; 1645 } 1646 1647 mutex_exit(&sc->sc_parent->dk_rawlock); 1648 mutex_exit(&sc->sc_dk.dk_openlock); 1649 1650 return (rv); 1651 } 1652 1653 /* 1654 * dkdump: [devsw entry point] 1655 * 1656 * Perform a crash dump to a wedge. 1657 */ 1658 static int 1659 dkdump(dev_t dev, daddr_t blkno, void *va, size_t size) 1660 { 1661 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1662 const struct bdevsw *bdev; 1663 int rv = 0; 1664 1665 if (sc == NULL) 1666 return (ENODEV); 1667 if (sc->sc_state != DKW_STATE_RUNNING) 1668 return (ENXIO); 1669 1670 mutex_enter(&sc->sc_dk.dk_openlock); 1671 mutex_enter(&sc->sc_parent->dk_rawlock); 1672 1673 /* Our content type is static, no need to open the device. */ 1674 1675 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) != 0 && 1676 strcmp(sc->sc_ptype, DKW_PTYPE_RAID) != 0 && 1677 strcmp(sc->sc_ptype, DKW_PTYPE_CGD) != 0) { 1678 rv = ENXIO; 1679 goto out; 1680 } 1681 if (size % DEV_BSIZE != 0) { 1682 rv = EINVAL; 1683 goto out; 1684 } 1685 if (blkno < 0 || blkno + size / DEV_BSIZE > sc->sc_size) { 1686 printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > " 1687 "sc->sc_size (%" PRIu64 ")\n", __func__, blkno, 1688 size / DEV_BSIZE, sc->sc_size); 1689 rv = EINVAL; 1690 goto out; 1691 } 1692 1693 bdev = bdevsw_lookup(sc->sc_pdev); 1694 rv = (*bdev->d_dump)(sc->sc_pdev, blkno + sc->sc_offset, va, size); 1695 1696 out: 1697 mutex_exit(&sc->sc_parent->dk_rawlock); 1698 mutex_exit(&sc->sc_dk.dk_openlock); 1699 1700 return rv; 1701 } 1702 1703 /* 1704 * config glue 1705 */ 1706 1707 /* 1708 * dkwedge_find_partition 1709 * 1710 * Find wedge corresponding to the specified parent name 1711 * and offset/length. 1712 */ 1713 device_t 1714 dkwedge_find_partition(device_t parent, daddr_t startblk, uint64_t nblks) 1715 { 1716 struct dkwedge_softc *sc; 1717 int i; 1718 device_t wedge = NULL; 1719 1720 rw_enter(&dkwedges_lock, RW_READER); 1721 for (i = 0; i < ndkwedges; i++) { 1722 if ((sc = dkwedges[i]) == NULL) 1723 continue; 1724 if (strcmp(sc->sc_parent->dk_name, device_xname(parent)) == 0 && 1725 sc->sc_offset == startblk && 1726 sc->sc_size == nblks) { 1727 if (wedge) { 1728 printf("WARNING: double match for boot wedge " 1729 "(%s, %s)\n", 1730 device_xname(wedge), 1731 device_xname(sc->sc_dev)); 1732 continue; 1733 } 1734 wedge = sc->sc_dev; 1735 } 1736 } 1737 rw_exit(&dkwedges_lock); 1738 1739 return wedge; 1740 } 1741 1742 const char * 1743 dkwedge_get_parent_name(dev_t dev) 1744 { 1745 /* XXX: perhaps do this in lookup? */ 1746 int bmaj = bdevsw_lookup_major(&dk_bdevsw); 1747 int cmaj = cdevsw_lookup_major(&dk_cdevsw); 1748 if (major(dev) != bmaj && major(dev) != cmaj) 1749 return NULL; 1750 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1751 if (sc == NULL) 1752 return NULL; 1753 return sc->sc_parent->dk_name; 1754 } 1755 1756