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