1 /* $NetBSD: dk.c,v 1.31 2007/12/09 20:27:56 jmcneill 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.31 2007/12/09 20:27:56 jmcneill Exp $"); 41 42 #include "opt_dkwedge.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/proc.h> 47 #include <sys/errno.h> 48 #include <sys/pool.h> 49 #include <sys/ioctl.h> 50 #include <sys/disklabel.h> 51 #include <sys/disk.h> 52 #include <sys/fcntl.h> 53 #include <sys/buf.h> 54 #include <sys/bufq.h> 55 #include <sys/vnode.h> 56 #include <sys/stat.h> 57 #include <sys/conf.h> 58 #include <sys/callout.h> 59 #include <sys/kernel.h> 60 #include <sys/malloc.h> 61 #include <sys/device.h> 62 #include <sys/kauth.h> 63 64 #include <miscfs/specfs/specdev.h> 65 66 MALLOC_DEFINE(M_DKWEDGE, "dkwedge", "Disk wedge structures"); 67 68 typedef enum { 69 DKW_STATE_LARVAL = 0, 70 DKW_STATE_RUNNING = 1, 71 DKW_STATE_DYING = 2, 72 DKW_STATE_DEAD = 666 73 } dkwedge_state_t; 74 75 struct dkwedge_softc { 76 struct device *sc_dev; /* pointer to our pseudo-device */ 77 struct cfdata sc_cfdata; /* our cfdata structure */ 78 uint8_t sc_wname[128]; /* wedge name (Unicode, UTF-8) */ 79 80 dkwedge_state_t sc_state; /* state this wedge is in */ 81 82 struct disk *sc_parent; /* parent disk */ 83 daddr_t sc_offset; /* LBA offset of wedge in parent */ 84 uint64_t sc_size; /* size of wedge in blocks */ 85 char sc_ptype[32]; /* partition type */ 86 dev_t sc_pdev; /* cached parent's dev_t */ 87 /* link on parent's wedge list */ 88 LIST_ENTRY(dkwedge_softc) sc_plink; 89 90 struct disk sc_dk; /* our own disk structure */ 91 struct bufq_state *sc_bufq; /* buffer queue */ 92 struct callout sc_restart_ch; /* callout to restart I/O */ 93 94 u_int sc_iopend; /* I/Os pending */ 95 int sc_flags; /* flags (splbio) */ 96 }; 97 98 #define DK_F_WAIT_DRAIN 0x0001 /* waiting for I/O to drain */ 99 100 static void dkstart(struct dkwedge_softc *); 101 static void dkiodone(struct buf *); 102 static void dkrestart(void *); 103 104 static dev_type_open(dkopen); 105 static dev_type_close(dkclose); 106 static dev_type_read(dkread); 107 static dev_type_write(dkwrite); 108 static dev_type_ioctl(dkioctl); 109 static dev_type_strategy(dkstrategy); 110 static dev_type_dump(dkdump); 111 static dev_type_size(dksize); 112 113 const struct bdevsw dk_bdevsw = { 114 dkopen, dkclose, dkstrategy, dkioctl, dkdump, dksize, D_DISK 115 }; 116 117 const struct cdevsw dk_cdevsw = { 118 dkopen, dkclose, dkread, dkwrite, dkioctl, 119 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 120 }; 121 122 static struct dkwedge_softc **dkwedges; 123 static u_int ndkwedges; 124 static krwlock_t dkwedges_lock; 125 126 static LIST_HEAD(, dkwedge_discovery_method) dkwedge_discovery_methods; 127 static krwlock_t dkwedge_discovery_methods_lock; 128 129 /* 130 * dkwedge_match: 131 * 132 * Autoconfiguration match function for pseudo-device glue. 133 */ 134 static int 135 dkwedge_match(struct device *parent, struct cfdata *match, 136 void *aux) 137 { 138 139 /* Pseudo-device; always present. */ 140 return (1); 141 } 142 143 /* 144 * dkwedge_attach: 145 * 146 * Autoconfiguration attach function for pseudo-device glue. 147 */ 148 static void 149 dkwedge_attach(struct device *parent, struct device *self, 150 void *aux) 151 { 152 153 if (!pmf_device_register(self, NULL, NULL)) 154 aprint_error_dev(self, "couldn't establish power handler\n"); 155 } 156 157 /* 158 * dkwedge_detach: 159 * 160 * Autoconfiguration detach function for pseudo-device glue. 161 */ 162 static int 163 dkwedge_detach(struct device *self, int flags) 164 { 165 166 pmf_device_deregister(self); 167 /* Always succeeds. */ 168 return (0); 169 } 170 171 CFDRIVER_DECL(dk, DV_DISK, NULL); 172 CFATTACH_DECL(dk, sizeof(struct device), 173 dkwedge_match, dkwedge_attach, dkwedge_detach, NULL); 174 175 /* 176 * dkwedge_wait_drain: 177 * 178 * Wait for I/O on the wedge to drain. 179 * NOTE: Must be called at splbio()! 180 */ 181 static void 182 dkwedge_wait_drain(struct dkwedge_softc *sc) 183 { 184 185 while (sc->sc_iopend != 0) { 186 sc->sc_flags |= DK_F_WAIT_DRAIN; 187 (void) tsleep(&sc->sc_iopend, PRIBIO, "dkdrn", 0); 188 } 189 } 190 191 /* 192 * dkwedge_compute_pdev: 193 * 194 * Compute the parent disk's dev_t. 195 */ 196 static int 197 dkwedge_compute_pdev(const char *pname, dev_t *pdevp) 198 { 199 const char *name, *cp; 200 int punit, pmaj; 201 char devname[16]; 202 203 name = pname; 204 if ((pmaj = devsw_name2blk(name, devname, sizeof(devname))) == -1) 205 return (ENODEV); 206 207 name += strlen(devname); 208 for (cp = name, punit = 0; *cp >= '0' && *cp <= '9'; cp++) 209 punit = (punit * 10) + (*cp - '0'); 210 if (cp == name) { 211 /* Invalid parent disk name. */ 212 return (ENODEV); 213 } 214 215 *pdevp = MAKEDISKDEV(pmaj, punit, RAW_PART); 216 217 return (0); 218 } 219 220 /* 221 * dkwedge_array_expand: 222 * 223 * Expand the dkwedges array. 224 */ 225 static void 226 dkwedge_array_expand(void) 227 { 228 int newcnt = ndkwedges + 16; 229 struct dkwedge_softc **newarray, **oldarray; 230 231 newarray = malloc(newcnt * sizeof(*newarray), M_DKWEDGE, 232 M_WAITOK|M_ZERO); 233 if ((oldarray = dkwedges) != NULL) 234 memcpy(newarray, dkwedges, ndkwedges * sizeof(*newarray)); 235 dkwedges = newarray; 236 ndkwedges = newcnt; 237 if (oldarray != NULL) 238 free(oldarray, M_DKWEDGE); 239 } 240 241 /* 242 * dkwedge_add: [exported function] 243 * 244 * Add a disk wedge based on the provided information. 245 * 246 * The incoming dkw_devname[] is ignored, instead being 247 * filled in and returned to the caller. 248 */ 249 int 250 dkwedge_add(struct dkwedge_info *dkw) 251 { 252 struct dkwedge_softc *sc, *lsc; 253 struct disk *pdk; 254 u_int unit; 255 int error; 256 dev_t pdev; 257 258 dkw->dkw_parent[sizeof(dkw->dkw_parent) - 1] = '\0'; 259 pdk = disk_find(dkw->dkw_parent); 260 if (pdk == NULL) 261 return (ENODEV); 262 263 error = dkwedge_compute_pdev(pdk->dk_name, &pdev); 264 if (error) 265 return (error); 266 267 if (dkw->dkw_offset < 0) 268 return (EINVAL); 269 270 sc = malloc(sizeof(*sc), M_DKWEDGE, M_WAITOK|M_ZERO); 271 sc->sc_state = DKW_STATE_LARVAL; 272 sc->sc_parent = pdk; 273 sc->sc_pdev = pdev; 274 sc->sc_offset = dkw->dkw_offset; 275 sc->sc_size = dkw->dkw_size; 276 277 memcpy(sc->sc_wname, dkw->dkw_wname, sizeof(sc->sc_wname)); 278 sc->sc_wname[sizeof(sc->sc_wname) - 1] = '\0'; 279 280 memcpy(sc->sc_ptype, dkw->dkw_ptype, sizeof(sc->sc_ptype)); 281 sc->sc_ptype[sizeof(sc->sc_ptype) - 1] = '\0'; 282 283 bufq_alloc(&sc->sc_bufq, "fcfs", 0); 284 285 callout_init(&sc->sc_restart_ch, 0); 286 callout_setfunc(&sc->sc_restart_ch, dkrestart, sc); 287 288 /* 289 * Wedge will be added; increment the wedge count for the parent. 290 * Only allow this to happend if RAW_PART is the only thing open. 291 */ 292 mutex_enter(&pdk->dk_openlock); 293 if (pdk->dk_openmask & ~(1 << RAW_PART)) 294 error = EBUSY; 295 else { 296 /* Check for wedge overlap. */ 297 LIST_FOREACH(lsc, &pdk->dk_wedges, sc_plink) { 298 daddr_t lastblk = sc->sc_offset + sc->sc_size - 1; 299 daddr_t llastblk = lsc->sc_offset + lsc->sc_size - 1; 300 301 if (sc->sc_offset >= lsc->sc_offset && 302 sc->sc_offset <= llastblk) { 303 /* Overlaps the tail of the exsiting wedge. */ 304 break; 305 } 306 if (lastblk >= lsc->sc_offset && 307 lastblk <= llastblk) { 308 /* Overlaps the head of the existing wedge. */ 309 break; 310 } 311 } 312 if (lsc != NULL) 313 error = EINVAL; 314 else { 315 pdk->dk_nwedges++; 316 LIST_INSERT_HEAD(&pdk->dk_wedges, sc, sc_plink); 317 } 318 } 319 mutex_exit(&pdk->dk_openlock); 320 if (error) { 321 bufq_free(sc->sc_bufq); 322 free(sc, M_DKWEDGE); 323 return (error); 324 } 325 326 /* Fill in our cfdata for the pseudo-device glue. */ 327 sc->sc_cfdata.cf_name = dk_cd.cd_name; 328 sc->sc_cfdata.cf_atname = dk_ca.ca_name; 329 /* sc->sc_cfdata.cf_unit set below */ 330 sc->sc_cfdata.cf_fstate = FSTATE_STAR; 331 332 /* Insert the larval wedge into the array. */ 333 rw_enter(&dkwedges_lock, RW_WRITER); 334 for (error = 0;;) { 335 struct dkwedge_softc **scpp; 336 337 /* 338 * Check for a duplicate wname while searching for 339 * a slot. 340 */ 341 for (scpp = NULL, unit = 0; unit < ndkwedges; unit++) { 342 if (dkwedges[unit] == NULL) { 343 if (scpp == NULL) { 344 scpp = &dkwedges[unit]; 345 sc->sc_cfdata.cf_unit = unit; 346 } 347 } else { 348 /* XXX Unicode. */ 349 if (strcmp(dkwedges[unit]->sc_wname, 350 sc->sc_wname) == 0) { 351 error = EEXIST; 352 break; 353 } 354 } 355 } 356 if (error) 357 break; 358 KASSERT(unit == ndkwedges); 359 if (scpp == NULL) 360 dkwedge_array_expand(); 361 else { 362 KASSERT(scpp == &dkwedges[sc->sc_cfdata.cf_unit]); 363 *scpp = sc; 364 break; 365 } 366 } 367 rw_exit(&dkwedges_lock); 368 if (error) { 369 mutex_enter(&pdk->dk_openlock); 370 pdk->dk_nwedges--; 371 LIST_REMOVE(sc, sc_plink); 372 mutex_exit(&pdk->dk_openlock); 373 374 bufq_free(sc->sc_bufq); 375 free(sc, M_DKWEDGE); 376 return (error); 377 } 378 379 /* 380 * Now that we know the unit #, attach a pseudo-device for 381 * this wedge instance. This will provide us with the 382 * "struct device" necessary for glue to other parts of the 383 * system. 384 * 385 * This should never fail, unless we're almost totally out of 386 * memory. 387 */ 388 if ((sc->sc_dev = config_attach_pseudo(&sc->sc_cfdata)) == NULL) { 389 aprint_error("%s%u: unable to attach pseudo-device\n", 390 sc->sc_cfdata.cf_name, sc->sc_cfdata.cf_unit); 391 392 rw_enter(&dkwedges_lock, RW_WRITER); 393 dkwedges[sc->sc_cfdata.cf_unit] = NULL; 394 rw_exit(&dkwedges_lock); 395 396 mutex_enter(&pdk->dk_openlock); 397 pdk->dk_nwedges--; 398 LIST_REMOVE(sc, sc_plink); 399 mutex_exit(&pdk->dk_openlock); 400 401 bufq_free(sc->sc_bufq); 402 free(sc, M_DKWEDGE); 403 return (ENOMEM); 404 } 405 406 /* Return the devname to the caller. */ 407 strcpy(dkw->dkw_devname, sc->sc_dev->dv_xname); 408 409 /* 410 * XXX Really ought to make the disk_attach() and the changing 411 * of state to RUNNING atomic. 412 */ 413 414 disk_init(&sc->sc_dk, sc->sc_dev->dv_xname, NULL); 415 disk_attach(&sc->sc_dk); 416 417 /* Disk wedge is ready for use! */ 418 sc->sc_state = DKW_STATE_RUNNING; 419 420 /* Announce our arrival. */ 421 aprint_normal("%s at %s: %s\n", sc->sc_dev->dv_xname, pdk->dk_name, 422 sc->sc_wname); /* XXX Unicode */ 423 aprint_normal("%s: %"PRIu64" blocks at %"PRId64", type: %s\n", 424 sc->sc_dev->dv_xname, sc->sc_size, sc->sc_offset, sc->sc_ptype); 425 426 return (0); 427 } 428 429 /* 430 * dkwedge_del: [exported function] 431 * 432 * Delete a disk wedge based on the provided information. 433 * NOTE: We look up the wedge based on the wedge devname, 434 * not wname. 435 */ 436 int 437 dkwedge_del(struct dkwedge_info *dkw) 438 { 439 struct dkwedge_softc *sc = NULL; 440 u_int unit; 441 int bmaj, cmaj, s; 442 443 /* Find our softc. */ 444 dkw->dkw_devname[sizeof(dkw->dkw_devname) - 1] = '\0'; 445 rw_enter(&dkwedges_lock, RW_WRITER); 446 for (unit = 0; unit < ndkwedges; unit++) { 447 if ((sc = dkwedges[unit]) != NULL && 448 strcmp(sc->sc_dev->dv_xname, dkw->dkw_devname) == 0 && 449 strcmp(sc->sc_parent->dk_name, dkw->dkw_parent) == 0) { 450 /* Mark the wedge as dying. */ 451 sc->sc_state = DKW_STATE_DYING; 452 break; 453 } 454 } 455 rw_exit(&dkwedges_lock); 456 if (unit == ndkwedges) 457 return (ESRCH); 458 459 KASSERT(sc != NULL); 460 461 /* Locate the wedge major numbers. */ 462 bmaj = bdevsw_lookup_major(&dk_bdevsw); 463 cmaj = cdevsw_lookup_major(&dk_cdevsw); 464 465 /* Kill any pending restart. */ 466 callout_stop(&sc->sc_restart_ch); 467 468 /* 469 * dkstart() will kill any queued buffers now that the 470 * state of the wedge is not RUNNING. Once we've done 471 * that, wait for any other pending I/O to complete. 472 */ 473 s = splbio(); 474 dkstart(sc); 475 dkwedge_wait_drain(sc); 476 splx(s); 477 478 /* Nuke the vnodes for any open instances. */ 479 vdevgone(bmaj, unit, unit, VBLK); 480 vdevgone(cmaj, unit, unit, VCHR); 481 482 /* Clean up the parent. */ 483 mutex_enter(&sc->sc_dk.dk_openlock); 484 mutex_enter(&sc->sc_parent->dk_rawlock); 485 if (sc->sc_dk.dk_openmask) { 486 if (sc->sc_parent->dk_rawopens-- == 1) { 487 KASSERT(sc->sc_parent->dk_rawvp != NULL); 488 (void) vn_close(sc->sc_parent->dk_rawvp, FREAD | FWRITE, 489 NOCRED, curlwp); 490 sc->sc_parent->dk_rawvp = NULL; 491 } 492 sc->sc_dk.dk_openmask = 0; 493 } 494 mutex_exit(&sc->sc_parent->dk_rawlock); 495 mutex_exit(&sc->sc_dk.dk_openlock); 496 497 /* Announce our departure. */ 498 aprint_normal("%s at %s (%s) deleted\n", sc->sc_dev->dv_xname, 499 sc->sc_parent->dk_name, 500 sc->sc_wname); /* XXX Unicode */ 501 502 /* Delete our pseudo-device. */ 503 (void) config_detach(sc->sc_dev, DETACH_FORCE | DETACH_QUIET); 504 505 mutex_enter(&sc->sc_parent->dk_openlock); 506 sc->sc_parent->dk_nwedges--; 507 LIST_REMOVE(sc, sc_plink); 508 mutex_exit(&sc->sc_parent->dk_openlock); 509 510 /* Delete our buffer queue. */ 511 bufq_free(sc->sc_bufq); 512 513 /* Detach from the disk list. */ 514 disk_detach(&sc->sc_dk); 515 516 /* Poof. */ 517 rw_enter(&dkwedges_lock, RW_WRITER); 518 dkwedges[unit] = NULL; 519 sc->sc_state = DKW_STATE_DEAD; 520 rw_exit(&dkwedges_lock); 521 522 free(sc, M_DKWEDGE); 523 524 return (0); 525 } 526 527 /* 528 * dkwedge_delall: [exported function] 529 * 530 * Delete all of the wedges on the specified disk. Used when 531 * a disk is being detached. 532 */ 533 void 534 dkwedge_delall(struct disk *pdk) 535 { 536 struct dkwedge_info dkw; 537 struct dkwedge_softc *sc; 538 539 for (;;) { 540 mutex_enter(&pdk->dk_openlock); 541 if ((sc = LIST_FIRST(&pdk->dk_wedges)) == NULL) { 542 KASSERT(pdk->dk_nwedges == 0); 543 mutex_exit(&pdk->dk_openlock); 544 return; 545 } 546 strcpy(dkw.dkw_parent, pdk->dk_name); 547 strcpy(dkw.dkw_devname, sc->sc_dev->dv_xname); 548 mutex_exit(&pdk->dk_openlock); 549 (void) dkwedge_del(&dkw); 550 } 551 } 552 553 /* 554 * dkwedge_list: [exported function] 555 * 556 * List all of the wedges on a particular disk. 557 * If p == NULL, the buffer is in kernel space. Otherwise, it is 558 * in user space of the specified process. 559 */ 560 int 561 dkwedge_list(struct disk *pdk, struct dkwedge_list *dkwl, struct lwp *l) 562 { 563 struct uio uio; 564 struct iovec iov; 565 struct dkwedge_softc *sc; 566 struct dkwedge_info dkw; 567 struct vmspace *vm; 568 int error = 0; 569 570 iov.iov_base = dkwl->dkwl_buf; 571 iov.iov_len = dkwl->dkwl_bufsize; 572 573 uio.uio_iov = &iov; 574 uio.uio_iovcnt = 1; 575 uio.uio_offset = 0; 576 uio.uio_resid = dkwl->dkwl_bufsize; 577 uio.uio_rw = UIO_READ; 578 if (l == NULL) { 579 UIO_SETUP_SYSSPACE(&uio); 580 } else { 581 error = proc_vmspace_getref(l->l_proc, &vm); 582 if (error) { 583 return error; 584 } 585 uio.uio_vmspace = vm; 586 } 587 588 dkwl->dkwl_ncopied = 0; 589 590 mutex_enter(&pdk->dk_openlock); 591 LIST_FOREACH(sc, &pdk->dk_wedges, sc_plink) { 592 if (uio.uio_resid < sizeof(dkw)) 593 break; 594 595 if (sc->sc_state != DKW_STATE_RUNNING) 596 continue; 597 598 strcpy(dkw.dkw_devname, sc->sc_dev->dv_xname); 599 memcpy(dkw.dkw_wname, sc->sc_wname, sizeof(dkw.dkw_wname)); 600 dkw.dkw_wname[sizeof(dkw.dkw_wname) - 1] = '\0'; 601 strcpy(dkw.dkw_parent, sc->sc_parent->dk_name); 602 dkw.dkw_offset = sc->sc_offset; 603 dkw.dkw_size = sc->sc_size; 604 strcpy(dkw.dkw_ptype, sc->sc_ptype); 605 606 error = uiomove(&dkw, sizeof(dkw), &uio); 607 if (error) 608 break; 609 dkwl->dkwl_ncopied++; 610 } 611 dkwl->dkwl_nwedges = pdk->dk_nwedges; 612 mutex_exit(&pdk->dk_openlock); 613 614 if (l != NULL) { 615 uvmspace_free(vm); 616 } 617 618 return (error); 619 } 620 621 device_t 622 dkwedge_find_by_wname(const char *wname) 623 { 624 device_t dv = NULL; 625 struct dkwedge_softc *sc; 626 int i; 627 628 rw_enter(&dkwedges_lock, RW_WRITER); 629 for (i = 0; i < ndkwedges; i++) { 630 if ((sc = dkwedges[i]) == NULL) 631 continue; 632 if (strcmp(sc->sc_wname, wname) == 0) { 633 if (dv != NULL) { 634 printf( 635 "WARNING: double match for wedge name %s " 636 "(%s, %s)\n", wname, device_xname(dv), 637 device_xname(sc->sc_dev)); 638 continue; 639 } 640 dv = sc->sc_dev; 641 } 642 } 643 rw_exit(&dkwedges_lock); 644 return dv; 645 } 646 647 void 648 dkwedge_print_wnames(void) 649 { 650 struct dkwedge_softc *sc; 651 int i; 652 653 rw_enter(&dkwedges_lock, RW_WRITER); 654 for (i = 0; i < ndkwedges; i++) { 655 if ((sc = dkwedges[i]) == NULL) 656 continue; 657 printf(" wedge:%s", sc->sc_wname); 658 } 659 rw_exit(&dkwedges_lock); 660 } 661 662 /* 663 * dkwedge_set_bootwedge 664 * 665 * Set the booted_wedge global based on the specified parent name 666 * and offset/length. 667 */ 668 void 669 dkwedge_set_bootwedge(struct device *parent, daddr_t startblk, uint64_t nblks) 670 { 671 struct dkwedge_softc *sc; 672 int i; 673 674 rw_enter(&dkwedges_lock, RW_WRITER); 675 for (i = 0; i < ndkwedges; i++) { 676 if ((sc = dkwedges[i]) == NULL) 677 continue; 678 if (strcmp(sc->sc_parent->dk_name, parent->dv_xname) == 0 && 679 sc->sc_offset == startblk && 680 sc->sc_size == nblks) { 681 if (booted_wedge) { 682 printf("WARNING: double match for boot wedge " 683 "(%s, %s)\n", 684 booted_wedge->dv_xname, 685 sc->sc_dev->dv_xname); 686 continue; 687 } 688 booted_device = parent; 689 booted_wedge = sc->sc_dev; 690 booted_partition = 0; 691 } 692 } 693 /* 694 * XXX What if we don't find one? Should we create a special 695 * XXX root wedge? 696 */ 697 rw_exit(&dkwedges_lock); 698 } 699 700 /* 701 * We need a dummy object to stuff into the dkwedge discovery method link 702 * set to ensure that there is always at least one object in the set. 703 */ 704 static struct dkwedge_discovery_method dummy_discovery_method; 705 __link_set_add_bss(dkwedge_methods, dummy_discovery_method); 706 707 /* 708 * dkwedge_init: 709 * 710 * Initialize the disk wedge subsystem. 711 */ 712 void 713 dkwedge_init(void) 714 { 715 __link_set_decl(dkwedge_methods, struct dkwedge_discovery_method); 716 struct dkwedge_discovery_method * const *ddmp; 717 struct dkwedge_discovery_method *lddm, *ddm; 718 719 rw_init(&dkwedges_lock); 720 rw_init(&dkwedge_discovery_methods_lock); 721 722 if (config_cfdriver_attach(&dk_cd) != 0) 723 panic("dkwedge: unable to attach cfdriver"); 724 if (config_cfattach_attach(dk_cd.cd_name, &dk_ca) != 0) 725 panic("dkwedge: unable to attach cfattach"); 726 727 rw_enter(&dkwedge_discovery_methods_lock, RW_WRITER); 728 729 LIST_INIT(&dkwedge_discovery_methods); 730 731 __link_set_foreach(ddmp, dkwedge_methods) { 732 ddm = *ddmp; 733 if (ddm == &dummy_discovery_method) 734 continue; 735 if (LIST_EMPTY(&dkwedge_discovery_methods)) { 736 LIST_INSERT_HEAD(&dkwedge_discovery_methods, 737 ddm, ddm_list); 738 continue; 739 } 740 LIST_FOREACH(lddm, &dkwedge_discovery_methods, ddm_list) { 741 if (ddm->ddm_priority == lddm->ddm_priority) { 742 aprint_error("dk-method-%s: method \"%s\" " 743 "already exists at priority %d\n", 744 ddm->ddm_name, lddm->ddm_name, 745 lddm->ddm_priority); 746 /* Not inserted. */ 747 break; 748 } 749 if (ddm->ddm_priority < lddm->ddm_priority) { 750 /* Higher priority; insert before. */ 751 LIST_INSERT_BEFORE(lddm, ddm, ddm_list); 752 break; 753 } 754 if (LIST_NEXT(lddm, ddm_list) == NULL) { 755 /* Last one; insert after. */ 756 KASSERT(lddm->ddm_priority < ddm->ddm_priority); 757 LIST_INSERT_AFTER(lddm, ddm, ddm_list); 758 break; 759 } 760 } 761 } 762 763 rw_exit(&dkwedge_discovery_methods_lock); 764 } 765 766 #ifdef DKWEDGE_AUTODISCOVER 767 int dkwedge_autodiscover = 1; 768 #else 769 int dkwedge_autodiscover = 0; 770 #endif 771 772 /* 773 * dkwedge_discover: [exported function] 774 * 775 * Discover the wedges on a newly attached disk. 776 */ 777 void 778 dkwedge_discover(struct disk *pdk) 779 { 780 struct dkwedge_discovery_method *ddm; 781 struct vnode *vp; 782 int error; 783 dev_t pdev; 784 785 /* 786 * Require people playing with wedges to enable this explicitly. 787 */ 788 if (dkwedge_autodiscover == 0) 789 return; 790 791 rw_enter(&dkwedge_discovery_methods_lock, RW_READER); 792 793 error = dkwedge_compute_pdev(pdk->dk_name, &pdev); 794 if (error) { 795 aprint_error("%s: unable to compute pdev, error = %d\n", 796 pdk->dk_name, error); 797 goto out; 798 } 799 800 error = bdevvp(pdev, &vp); 801 if (error) { 802 aprint_error("%s: unable to find vnode for pdev, error = %d\n", 803 pdk->dk_name, error); 804 goto out; 805 } 806 807 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 808 if (error) { 809 aprint_error("%s: unable to lock vnode for pdev, error = %d\n", 810 pdk->dk_name, error); 811 vrele(vp); 812 goto out; 813 } 814 815 error = VOP_OPEN(vp, FREAD, NOCRED); 816 if (error) { 817 aprint_error("%s: unable to open device, error = %d\n", 818 pdk->dk_name, error); 819 vput(vp); 820 goto out; 821 } 822 VOP_UNLOCK(vp, 0); 823 824 /* 825 * For each supported partition map type, look to see if 826 * this map type exists. If so, parse it and add the 827 * corresponding wedges. 828 */ 829 LIST_FOREACH(ddm, &dkwedge_discovery_methods, ddm_list) { 830 error = (*ddm->ddm_discover)(pdk, vp); 831 if (error == 0) { 832 /* Successfully created wedges; we're done. */ 833 break; 834 } 835 } 836 837 error = vn_close(vp, FREAD, NOCRED, curlwp); 838 if (error) { 839 aprint_error("%s: unable to close device, error = %d\n", 840 pdk->dk_name, error); 841 /* We'll just assume the vnode has been cleaned up. */ 842 } 843 out: 844 rw_exit(&dkwedge_discovery_methods_lock); 845 } 846 847 /* 848 * dkwedge_read: 849 * 850 * Read the some data from the specified disk, used for 851 * partition discovery. 852 */ 853 int 854 dkwedge_read(struct disk *pdk, struct vnode *vp, daddr_t blkno, 855 void *tbuf, size_t len) 856 { 857 struct buf b; 858 859 BUF_INIT(&b); 860 861 b.b_vp = vp; 862 b.b_dev = vp->v_rdev; 863 b.b_blkno = blkno; 864 b.b_bcount = b.b_resid = len; 865 b.b_flags = B_READ; 866 b.b_proc = curproc; 867 b.b_data = tbuf; 868 869 VOP_STRATEGY(vp, &b); 870 return (biowait(&b)); 871 } 872 873 /* 874 * dkwedge_lookup: 875 * 876 * Look up a dkwedge_softc based on the provided dev_t. 877 */ 878 static struct dkwedge_softc * 879 dkwedge_lookup(dev_t dev) 880 { 881 int unit = minor(dev); 882 883 if (unit >= ndkwedges) 884 return (NULL); 885 886 KASSERT(dkwedges != NULL); 887 888 return (dkwedges[unit]); 889 } 890 891 /* 892 * dkopen: [devsw entry point] 893 * 894 * Open a wedge. 895 */ 896 static int 897 dkopen(dev_t dev, int flags, int fmt, struct lwp *l) 898 { 899 struct dkwedge_softc *sc = dkwedge_lookup(dev); 900 struct vnode *vp; 901 int error = 0; 902 903 if (sc == NULL) 904 return (ENODEV); 905 906 if (sc->sc_state != DKW_STATE_RUNNING) 907 return (ENXIO); 908 909 /* 910 * We go through a complicated little dance to only open the parent 911 * vnode once per wedge, no matter how many times the wedge is 912 * opened. The reason? We see one dkopen() per open call, but 913 * only dkclose() on the last close. 914 */ 915 mutex_enter(&sc->sc_dk.dk_openlock); 916 mutex_enter(&sc->sc_parent->dk_rawlock); 917 if (sc->sc_dk.dk_openmask == 0) { 918 if (sc->sc_parent->dk_rawopens == 0) { 919 KASSERT(sc->sc_parent->dk_rawvp == NULL); 920 error = bdevvp(sc->sc_pdev, &vp); 921 if (error) 922 goto popen_fail; 923 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 924 if (error) { 925 vrele(vp); 926 goto popen_fail; 927 } 928 error = VOP_OPEN(vp, FREAD | FWRITE, NOCRED); 929 if (error) { 930 vput(vp); 931 goto popen_fail; 932 } 933 /* VOP_OPEN() doesn't do this for us. */ 934 vp->v_writecount++; 935 VOP_UNLOCK(vp, 0); 936 sc->sc_parent->dk_rawvp = vp; 937 } 938 sc->sc_parent->dk_rawopens++; 939 } 940 if (fmt == S_IFCHR) 941 sc->sc_dk.dk_copenmask |= 1; 942 else 943 sc->sc_dk.dk_bopenmask |= 1; 944 sc->sc_dk.dk_openmask = 945 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 946 947 popen_fail: 948 mutex_exit(&sc->sc_parent->dk_rawlock); 949 mutex_exit(&sc->sc_dk.dk_openlock); 950 return (error); 951 } 952 953 /* 954 * dkclose: [devsw entry point] 955 * 956 * Close a wedge. 957 */ 958 static int 959 dkclose(dev_t dev, int flags, int fmt, struct lwp *l) 960 { 961 struct dkwedge_softc *sc = dkwedge_lookup(dev); 962 int error = 0; 963 964 KASSERT(sc->sc_dk.dk_openmask != 0); 965 966 mutex_enter(&sc->sc_dk.dk_openlock); 967 mutex_enter(&sc->sc_parent->dk_rawlock); 968 969 if (fmt == S_IFCHR) 970 sc->sc_dk.dk_copenmask &= ~1; 971 else 972 sc->sc_dk.dk_bopenmask &= ~1; 973 sc->sc_dk.dk_openmask = 974 sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; 975 976 if (sc->sc_dk.dk_openmask == 0) { 977 if (sc->sc_parent->dk_rawopens-- == 1) { 978 KASSERT(sc->sc_parent->dk_rawvp != NULL); 979 error = vn_close(sc->sc_parent->dk_rawvp, 980 FREAD | FWRITE, NOCRED, l); 981 sc->sc_parent->dk_rawvp = NULL; 982 } 983 } 984 985 mutex_exit(&sc->sc_parent->dk_rawlock); 986 mutex_exit(&sc->sc_dk.dk_openlock); 987 988 return (error); 989 } 990 991 /* 992 * dkstragegy: [devsw entry point] 993 * 994 * Perform I/O based on the wedge I/O strategy. 995 */ 996 static void 997 dkstrategy(struct buf *bp) 998 { 999 struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev); 1000 int s; 1001 1002 if (sc->sc_state != DKW_STATE_RUNNING) { 1003 bp->b_error = ENXIO; 1004 goto done; 1005 } 1006 1007 /* If it's an empty transfer, wake up the top half now. */ 1008 if (bp->b_bcount == 0) 1009 goto done; 1010 1011 /* Make sure it's in-range. */ 1012 if (bounds_check_with_mediasize(bp, DEV_BSIZE, sc->sc_size) <= 0) 1013 goto done; 1014 1015 /* Translate it to the parent's raw LBA. */ 1016 bp->b_rawblkno = bp->b_blkno + sc->sc_offset; 1017 1018 /* Place it in the queue and start I/O on the unit. */ 1019 s = splbio(); 1020 sc->sc_iopend++; 1021 BUFQ_PUT(sc->sc_bufq, bp); 1022 dkstart(sc); 1023 splx(s); 1024 return; 1025 1026 done: 1027 bp->b_resid = bp->b_bcount; 1028 biodone(bp); 1029 } 1030 1031 /* 1032 * dkstart: 1033 * 1034 * Start I/O that has been enqueued on the wedge. 1035 * NOTE: Must be called at splbio()! 1036 */ 1037 static void 1038 dkstart(struct dkwedge_softc *sc) 1039 { 1040 struct buf *bp, *nbp; 1041 1042 /* Do as much work as has been enqueued. */ 1043 while ((bp = BUFQ_PEEK(sc->sc_bufq)) != NULL) { 1044 if (sc->sc_state != DKW_STATE_RUNNING) { 1045 (void) BUFQ_GET(sc->sc_bufq); 1046 if (sc->sc_iopend-- == 1 && 1047 (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1048 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1049 wakeup(&sc->sc_iopend); 1050 } 1051 bp->b_error = ENXIO; 1052 bp->b_resid = bp->b_bcount; 1053 biodone(bp); 1054 } 1055 1056 /* Instrumentation. */ 1057 disk_busy(&sc->sc_dk); 1058 1059 nbp = getiobuf_nowait(); 1060 if (nbp == NULL) { 1061 /* 1062 * No resources to run this request; leave the 1063 * buffer queued up, and schedule a timer to 1064 * restart the queue in 1/2 a second. 1065 */ 1066 disk_unbusy(&sc->sc_dk, 0, bp->b_flags & B_READ); 1067 callout_schedule(&sc->sc_restart_ch, hz / 2); 1068 return; 1069 } 1070 1071 (void) BUFQ_GET(sc->sc_bufq); 1072 1073 BUF_INIT(nbp); 1074 nbp->b_data = bp->b_data; 1075 nbp->b_flags = bp->b_flags | B_CALL; 1076 nbp->b_iodone = dkiodone; 1077 nbp->b_proc = bp->b_proc; 1078 nbp->b_blkno = bp->b_rawblkno; 1079 nbp->b_dev = sc->sc_parent->dk_rawvp->v_rdev; 1080 nbp->b_vp = sc->sc_parent->dk_rawvp; 1081 nbp->b_bcount = bp->b_bcount; 1082 nbp->b_private = bp; 1083 BIO_COPYPRIO(nbp, bp); 1084 1085 if ((nbp->b_flags & B_READ) == 0) 1086 V_INCR_NUMOUTPUT(nbp->b_vp); 1087 VOP_STRATEGY(nbp->b_vp, nbp); 1088 } 1089 } 1090 1091 /* 1092 * dkiodone: 1093 * 1094 * I/O to a wedge has completed; alert the top half. 1095 * NOTE: Must be called at splbio()! 1096 */ 1097 static void 1098 dkiodone(struct buf *bp) 1099 { 1100 struct buf *obp = bp->b_private; 1101 struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev); 1102 1103 if (bp->b_error != 0) 1104 obp->b_error = bp->b_error; 1105 obp->b_resid = bp->b_resid; 1106 putiobuf(bp); 1107 1108 if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) { 1109 sc->sc_flags &= ~DK_F_WAIT_DRAIN; 1110 wakeup(&sc->sc_iopend); 1111 } 1112 1113 disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid, 1114 obp->b_flags & B_READ); 1115 1116 biodone(obp); 1117 1118 /* Kick the queue in case there is more work we can do. */ 1119 dkstart(sc); 1120 } 1121 1122 /* 1123 * dkrestart: 1124 * 1125 * Restart the work queue after it was stalled due to 1126 * a resource shortage. Invoked via a callout. 1127 */ 1128 static void 1129 dkrestart(void *v) 1130 { 1131 struct dkwedge_softc *sc = v; 1132 int s; 1133 1134 s = splbio(); 1135 dkstart(sc); 1136 splx(s); 1137 } 1138 1139 /* 1140 * dkread: [devsw entry point] 1141 * 1142 * Read from a wedge. 1143 */ 1144 static int 1145 dkread(dev_t dev, struct uio *uio, int flags) 1146 { 1147 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1148 1149 if (sc->sc_state != DKW_STATE_RUNNING) 1150 return (ENXIO); 1151 1152 return (physio(dkstrategy, NULL, dev, B_READ, 1153 sc->sc_parent->dk_driver->d_minphys, uio)); 1154 } 1155 1156 /* 1157 * dkwrite: [devsw entry point] 1158 * 1159 * Write to a wedge. 1160 */ 1161 static int 1162 dkwrite(dev_t dev, struct uio *uio, int flags) 1163 { 1164 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1165 1166 if (sc->sc_state != DKW_STATE_RUNNING) 1167 return (ENXIO); 1168 1169 return (physio(dkstrategy, NULL, dev, B_WRITE, 1170 sc->sc_parent->dk_driver->d_minphys, uio)); 1171 } 1172 1173 /* 1174 * dkioctl: [devsw entry point] 1175 * 1176 * Perform an ioctl request on a wedge. 1177 */ 1178 static int 1179 dkioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1180 { 1181 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1182 int error = 0; 1183 1184 if (sc->sc_state != DKW_STATE_RUNNING) 1185 return (ENXIO); 1186 1187 switch (cmd) { 1188 case DIOCCACHESYNC: 1189 /* 1190 * XXX Do we really need to care about having a writable 1191 * file descriptor here? 1192 */ 1193 if ((flag & FWRITE) == 0) 1194 error = EBADF; 1195 else 1196 error = VOP_IOCTL(sc->sc_parent->dk_rawvp, 1197 cmd, data, flag, 1198 l != NULL ? l->l_cred : NOCRED); 1199 break; 1200 case DIOCGWEDGEINFO: 1201 { 1202 struct dkwedge_info *dkw = (void *) data; 1203 1204 strcpy(dkw->dkw_devname, sc->sc_dev->dv_xname); 1205 memcpy(dkw->dkw_wname, sc->sc_wname, sizeof(dkw->dkw_wname)); 1206 dkw->dkw_wname[sizeof(dkw->dkw_wname) - 1] = '\0'; 1207 strcpy(dkw->dkw_parent, sc->sc_parent->dk_name); 1208 dkw->dkw_offset = sc->sc_offset; 1209 dkw->dkw_size = sc->sc_size; 1210 strcpy(dkw->dkw_ptype, sc->sc_ptype); 1211 1212 break; 1213 } 1214 1215 default: 1216 error = ENOTTY; 1217 } 1218 1219 return (error); 1220 } 1221 1222 /* 1223 * dksize: [devsw entry point] 1224 * 1225 * Query the size of a wedge for the purpose of performing a dump 1226 * or for swapping to. 1227 */ 1228 static int 1229 dksize(dev_t dev) 1230 { 1231 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1232 int rv = -1; 1233 1234 if (sc == NULL) 1235 return (-1); 1236 1237 if (sc->sc_state != DKW_STATE_RUNNING) 1238 return (ENXIO); 1239 1240 mutex_enter(&sc->sc_dk.dk_openlock); 1241 mutex_enter(&sc->sc_parent->dk_rawlock); 1242 1243 /* Our content type is static, no need to open the device. */ 1244 1245 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) { 1246 /* Saturate if we are larger than INT_MAX. */ 1247 if (sc->sc_size > INT_MAX) 1248 rv = INT_MAX; 1249 else 1250 rv = (int) sc->sc_size; 1251 } 1252 1253 mutex_exit(&sc->sc_parent->dk_rawlock); 1254 mutex_exit(&sc->sc_dk.dk_openlock); 1255 1256 return (rv); 1257 } 1258 1259 /* 1260 * dkdump: [devsw entry point] 1261 * 1262 * Perform a crash dump to a wedge. 1263 */ 1264 static int 1265 dkdump(dev_t dev, daddr_t blkno, void *va, size_t size) 1266 { 1267 struct dkwedge_softc *sc = dkwedge_lookup(dev); 1268 const struct bdevsw *bdev; 1269 int rv = 0; 1270 1271 if (sc == NULL) 1272 return (-1); 1273 1274 if (sc->sc_state != DKW_STATE_RUNNING) 1275 return (ENXIO); 1276 1277 mutex_enter(&sc->sc_dk.dk_openlock); 1278 mutex_enter(&sc->sc_parent->dk_rawlock); 1279 1280 /* Our content type is static, no need to open the device. */ 1281 1282 if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) != 0) { 1283 rv = ENXIO; 1284 goto out; 1285 } 1286 if (size % DEV_BSIZE != 0) { 1287 rv = EINVAL; 1288 goto out; 1289 } 1290 if (blkno + size / DEV_BSIZE > sc->sc_size) { 1291 printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > " 1292 "sc->sc_size (%" PRIu64 ")\n", __func__, blkno, 1293 size / DEV_BSIZE, sc->sc_size); 1294 rv = EINVAL; 1295 goto out; 1296 } 1297 1298 bdev = bdevsw_lookup(sc->sc_pdev); 1299 rv = (*bdev->d_dump)(sc->sc_pdev, blkno + sc->sc_offset, va, size); 1300 1301 out: 1302 mutex_exit(&sc->sc_parent->dk_rawlock); 1303 mutex_exit(&sc->sc_dk.dk_openlock); 1304 1305 return rv; 1306 } 1307