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