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