1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Ramdisk device driver. 29 * 30 * There are two types of ramdisk: 'real' OBP-created ramdisks, and 'pseudo' 31 * ramdisks created at runtime with no corresponding OBP device node. The 32 * ramdisk(7D) driver is capable of dealing with both, and with the creation 33 * and deletion of 'pseudo' ramdisks. 34 * 35 * Every ramdisk has a single 'state' structure which maintains data for 36 * that ramdisk, and is assigned a single minor number. The bottom 10-bits 37 * of the minor number index the state structures; the top 8-bits give a 38 * 'real OBP disk' number, i.e. they are zero for 'pseudo' ramdisks. Thus 39 * it is possible to distinguish 'real' from 'pseudo' ramdisks using the 40 * top 8-bits of the minor number. 41 * 42 * Each OBP-created ramdisk has its own node in the device tree with an 43 * "existing" property which describes the one-or-more physical address ranges 44 * assigned to the ramdisk. All 'pseudo' ramdisks share a common devinfo 45 * structure. 46 * 47 * A single character device node is used by ramdiskadm(1M) to communicate 48 * with the ramdisk driver, with minor number 0: 49 * 50 * /dev/ramdiskctl -> /devices/pseudo/ramdisk@0:ctl 51 * 52 * For consistent access, block and raw device nodes are created for *every* 53 * ramdisk. For 'pseudo' ramdisks: 54 * 55 * /dev/ramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname> 56 * /dev/rramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname>,raw 57 * 58 * For OBP-created ramdisks: 59 * 60 * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a 61 * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a,raw 62 * 63 * This allows the transition from the standalone to the kernel to proceed 64 * when booting from a ramdisk, and for the installation to correctly identify 65 * the root device. 66 */ 67 68 #include <sys/types.h> 69 #include <sys/param.h> 70 #include <sys/sysmacros.h> 71 #include <sys/errno.h> 72 #include <sys/uio.h> 73 #include <sys/buf.h> 74 #include <sys/modctl.h> 75 #include <sys/open.h> 76 #include <sys/kmem.h> 77 #include <sys/poll.h> 78 #include <sys/conf.h> 79 #include <sys/cmn_err.h> 80 #include <sys/stat.h> 81 #include <sys/file.h> 82 #include <sys/ddi.h> 83 #include <sys/sunddi.h> 84 #include <sys/ramdisk.h> 85 #include <vm/seg_kmem.h> 86 87 /* 88 * Flag to disable the use of real ramdisks (in the OBP - on Sparc) when 89 * the associated memory is no longer available - set in the bootops section. 90 */ 91 #ifdef __sparc 92 extern int bootops_obp_ramdisk_disabled; 93 #endif /* __sparc */ 94 95 /* 96 * An opaque handle where information about our set of ramdisk devices lives. 97 */ 98 static void *rd_statep; 99 100 /* 101 * Pointer to devinfo for the 'pseudo' ramdisks. Real OBP-created ramdisks 102 * get their own individual devinfo. 103 */ 104 static dev_info_t *rd_dip = NULL; 105 106 /* 107 * Global state lock. 108 */ 109 static kmutex_t rd_lock; 110 111 /* 112 * Maximum number of ramdisks supported by this driver. 113 */ 114 static uint32_t rd_max_disks = RD_DFLT_DISKS; 115 116 /* 117 * Percentage of physical memory which can be assigned to pseudo ramdisks, 118 * what that equates to in pages, and how many pages are currently assigned. 119 */ 120 static uint_t rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 121 static pgcnt_t rd_max_physmem; 122 static pgcnt_t rd_tot_physmem; 123 124 static uint_t rd_maxphys = RD_DEFAULT_MAXPHYS; 125 126 /* 127 * Is the driver busy, i.e. are there any pseudo ramdisk devices in existence? 128 */ 129 static int 130 rd_is_busy(void) 131 { 132 minor_t minor; 133 rd_devstate_t *rsp; 134 135 ASSERT(mutex_owned(&rd_lock)); 136 for (minor = 1; minor <= rd_max_disks; ++minor) { 137 if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 138 rsp->rd_dip == rd_dip) { 139 return (EBUSY); 140 } 141 } 142 return (0); 143 } 144 145 /* 146 * Find the first free minor number; returns zero if there isn't one. 147 */ 148 static minor_t 149 rd_find_free_minor(void) 150 { 151 minor_t minor; 152 153 ASSERT(mutex_owned(&rd_lock)); 154 for (minor = 1; minor <= rd_max_disks; ++minor) { 155 if (ddi_get_soft_state(rd_statep, minor) == NULL) { 156 return (minor); 157 } 158 } 159 return (0); 160 } 161 162 /* 163 * Locate the rd_devstate for the named ramdisk; returns NULL if not found. 164 * Each ramdisk is identified uniquely by name, i.e. an OBP-created ramdisk 165 * cannot have the same name as a pseudo ramdisk. 166 */ 167 static rd_devstate_t * 168 rd_find_named_disk(char *name) 169 { 170 minor_t minor; 171 rd_devstate_t *rsp; 172 173 ASSERT(mutex_owned(&rd_lock)); 174 for (minor = 1; minor <= rd_max_disks; ++minor) { 175 if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 176 strcmp(rsp->rd_name, name) == 0) { 177 return (rsp); 178 } 179 } 180 return (NULL); 181 } 182 183 /* 184 * Locate the rd_devstate for the real OBP-created ramdisk whose devinfo 185 * is referenced by 'dip'; returns NULL if not found (shouldn't happen). 186 */ 187 static rd_devstate_t * 188 rd_find_dip_state(dev_info_t *dip) 189 { 190 minor_t minor; 191 rd_devstate_t *rsp; 192 193 ASSERT(mutex_owned(&rd_lock)); 194 for (minor = 1; minor <= rd_max_disks; ++minor) { 195 if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 196 rsp->rd_dip == dip) { 197 return (rsp); 198 } 199 } 200 return (NULL); 201 } 202 203 /* 204 * Is the ramdisk open? 205 */ 206 static int 207 rd_is_open(rd_devstate_t *rsp) 208 { 209 ASSERT(mutex_owned(&rd_lock)); 210 return (rsp->rd_chr_open || rsp->rd_blk_open || rsp->rd_lyr_open_cnt); 211 } 212 213 /* 214 * Mark the ramdisk open. 215 */ 216 static int 217 rd_opened(rd_devstate_t *rsp, int otyp) 218 { 219 ASSERT(mutex_owned(&rd_lock)); 220 switch (otyp) { 221 case OTYP_CHR: 222 rsp->rd_chr_open = 1; 223 break; 224 case OTYP_BLK: 225 rsp->rd_blk_open = 1; 226 break; 227 case OTYP_LYR: 228 rsp->rd_lyr_open_cnt++; 229 break; 230 default: 231 return (-1); 232 } 233 return (0); 234 } 235 236 /* 237 * Mark the ramdisk closed. 238 */ 239 static void 240 rd_closed(rd_devstate_t *rsp, int otyp) 241 { 242 ASSERT(mutex_owned(&rd_lock)); 243 switch (otyp) { 244 case OTYP_CHR: 245 rsp->rd_chr_open = 0; 246 break; 247 case OTYP_BLK: 248 rsp->rd_blk_open = 0; 249 break; 250 case OTYP_LYR: 251 rsp->rd_lyr_open_cnt--; 252 break; 253 default: 254 break; 255 } 256 } 257 258 static void 259 rd_init_tuneables(void) 260 { 261 char *prop, *p; 262 263 /* 264 * Ensure sanity of 'rd_max_disks', which may be tuned in ramdisk.conf. 265 */ 266 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 267 "max_disks", &prop) == DDI_PROP_SUCCESS) { 268 p = prop; 269 rd_max_disks = (uint32_t)stoi(&p); 270 ddi_prop_free(prop); 271 } 272 if (rd_max_disks >= RD_MAX_DISKS) { 273 cmn_err(CE_WARN, "ramdisk: rd_max_disks (%u) too big;" 274 " using default (%u).", rd_max_disks, RD_MAX_DISKS - 1); 275 276 rd_max_disks = RD_MAX_DISKS - 1; 277 } 278 279 /* 280 * Ensure sanity of 'rd_percent_physmem', which may be tuned 281 * in ramdisk.conf. 282 */ 283 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 284 "percent_physmem", &prop) == DDI_PROP_SUCCESS) { 285 p = prop; 286 rd_percent_physmem = (uint_t)stoi(&p); 287 ddi_prop_free(prop); 288 } 289 if (rd_percent_physmem >= 100) { 290 cmn_err(CE_WARN, "ramdisk: rd_percent_physmem (%u) >= 100;" 291 " using default (%u%%).", rd_percent_physmem, 292 RD_DEFAULT_PERCENT_PHYSMEM); 293 294 rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 295 } 296 297 /* 298 * Since availrmem_initial is a long, this won't overflow. 299 */ 300 rd_max_physmem = (availrmem_initial * rd_percent_physmem) / 100; 301 } 302 303 /* 304 * Allocate enough physical pages to hold "npages" pages. Returns an 305 * array of page_t * pointers that can later be mapped in or out via 306 * rd_{un}map_window() but is otherwise opaque, or NULL on failure. 307 */ 308 page_t ** 309 rd_phys_alloc(pgcnt_t npages) 310 { 311 page_t *pp, **ppa; 312 spgcnt_t i; 313 size_t ppalen; 314 struct seg kseg; 315 caddr_t addr; /* For coloring */ 316 317 if (rd_tot_physmem + npages > rd_max_physmem) 318 return (NULL); 319 320 if (!page_resv(npages, KM_NOSLEEP)) 321 return (NULL); 322 323 if (!page_create_wait(npages, 0)) { 324 page_unresv(npages); 325 return (NULL); 326 } 327 328 ppalen = npages * sizeof (struct page_t *); 329 ppa = kmem_zalloc(ppalen, KM_NOSLEEP); 330 if (ppa == NULL) { 331 page_create_putback(npages); 332 page_unresv(npages); 333 return (NULL); 334 } 335 336 kseg.s_as = &kas; 337 for (i = 0, addr = NULL; i < npages; ++i, addr += PAGESIZE) { 338 pp = page_get_freelist(&kvp, 0, &kseg, addr, PAGESIZE, 0, NULL); 339 if (pp == NULL) { 340 pp = page_get_cachelist(&kvp, 0, &kseg, addr, 0, NULL); 341 if (pp == NULL) 342 goto out; 343 if (!PP_ISAGED(pp)) 344 page_hashout(pp, NULL); 345 } 346 347 PP_CLRFREE(pp); 348 PP_CLRAGED(pp); 349 ppa[i] = pp; 350 } 351 352 for (i = 0; i < npages; i++) 353 page_downgrade(ppa[i]); 354 rd_tot_physmem += npages; 355 356 return (ppa); 357 358 out: 359 ASSERT(i < npages); 360 page_create_putback(npages - i); 361 while (--i >= 0) 362 page_free(ppa[i], 0); 363 kmem_free(ppa, ppalen); 364 page_unresv(npages); 365 366 return (NULL); 367 } 368 369 /* 370 * Free physical pages previously allocated via rd_phys_alloc(); note that 371 * this function may block as it has to wait until it can exclusively lock 372 * all the pages first. 373 */ 374 static void 375 rd_phys_free(page_t **ppa, pgcnt_t npages) 376 { 377 pgcnt_t i; 378 size_t ppalen = npages * sizeof (struct page_t *); 379 380 for (i = 0; i < npages; ++i) { 381 if (! page_tryupgrade(ppa[i])) { 382 page_unlock(ppa[i]); 383 while (! page_lock(ppa[i], SE_EXCL, NULL, P_RECLAIM)) 384 ; 385 } 386 page_free(ppa[i], 0); 387 } 388 389 kmem_free(ppa, ppalen); 390 391 page_unresv(npages); 392 rd_tot_physmem -= npages; 393 } 394 395 /* 396 * Remove a window mapping (if present). 397 */ 398 static void 399 rd_unmap_window(rd_devstate_t *rsp) 400 { 401 ASSERT(rsp->rd_window_obp == 0); 402 if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 403 hat_unload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 404 HAT_UNLOAD_UNLOCK); 405 } 406 } 407 408 /* 409 * Map a portion of the ramdisk into the virtual window. 410 */ 411 static void 412 rd_map_window(rd_devstate_t *rsp, off_t offset) 413 { 414 pgcnt_t offpgs = btop(offset); 415 416 if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 417 /* 418 * Already mapped; is offset within our window? 419 */ 420 if (offset >= rsp->rd_window_base && 421 offset < rsp->rd_window_base + rsp->rd_window_size) { 422 return; 423 } 424 425 /* 426 * No, we need to re-map; toss the old mapping. 427 */ 428 rd_unmap_window(rsp); 429 } 430 rsp->rd_window_base = ptob(offpgs); 431 432 /* 433 * Different algorithms depending on whether this is a real 434 * OBP-created ramdisk, or a pseudo ramdisk. 435 */ 436 if (rsp->rd_dip == rd_dip) { 437 pgcnt_t pi, lastpi; 438 caddr_t vaddr; 439 440 /* 441 * Find the range of pages which should be mapped. 442 */ 443 pi = offpgs; 444 lastpi = pi + btopr(rsp->rd_window_size); 445 if (lastpi > rsp->rd_npages) { 446 lastpi = rsp->rd_npages; 447 } 448 449 /* 450 * Load the mapping. 451 */ 452 vaddr = rsp->rd_window_virt; 453 for (; pi < lastpi; ++pi) { 454 hat_memload(kas.a_hat, vaddr, rsp->rd_ppa[pi], 455 (PROT_READ | PROT_WRITE) | HAT_NOSYNC, 456 HAT_LOAD_LOCK); 457 vaddr += ptob(1); 458 } 459 } else { 460 uint_t i; 461 pfn_t pfn; 462 463 /* 464 * Real OBP-created ramdisk: locate the physical range which 465 * contains this offset. 466 */ 467 for (i = 0; i < rsp->rd_nexisting; ++i) { 468 if (offset < rsp->rd_existing[i].size) { 469 break; 470 } 471 offset -= rsp->rd_existing[i].size; 472 } 473 ASSERT(i < rsp->rd_nexisting); 474 475 /* 476 * Load the mapping. 477 */ 478 pfn = btop(rsp->rd_existing[i].phys + offset); 479 hat_devload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 480 pfn, (PROT_READ | PROT_WRITE), 481 HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 482 } 483 } 484 485 /* 486 * Fakes up a disk geometry, and one big partition, based on the size 487 * of the file. This is needed because we allow newfs'ing the device, 488 * and newfs will do several disk ioctls to figure out the geometry and 489 * partition information. It uses that information to determine the parameters 490 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we 491 * have to support it. 492 * 493 * Stolen from lofi.c - should maybe split out common code sometime. 494 */ 495 static void 496 rd_fake_disk_geometry(rd_devstate_t *rsp) 497 { 498 /* dk_geom - see dkio(7I) */ 499 /* 500 * dkg_ncyl _could_ be set to one here (one big cylinder with gobs 501 * of sectors), but that breaks programs like fdisk which want to 502 * partition a disk by cylinder. With one cylinder, you can't create 503 * an fdisk partition and put pcfs on it for testing (hard to pick 504 * a number between one and one). 505 * 506 * The cheezy floppy test is an attempt to not have too few cylinders 507 * for a small file, or so many on a big file that you waste space 508 * for backup superblocks or cylinder group structures. 509 */ 510 if (rsp->rd_size < (2 * 1024 * 1024)) /* floppy? */ 511 rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (100 * 1024); 512 else 513 rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (300 * 1024); 514 /* in case file file is < 100k */ 515 if (rsp->rd_dkg.dkg_ncyl == 0) 516 rsp->rd_dkg.dkg_ncyl = 1; 517 rsp->rd_dkg.dkg_acyl = 0; 518 rsp->rd_dkg.dkg_bcyl = 0; 519 rsp->rd_dkg.dkg_nhead = 1; 520 rsp->rd_dkg.dkg_obs1 = 0; 521 rsp->rd_dkg.dkg_intrlv = 0; 522 rsp->rd_dkg.dkg_obs2 = 0; 523 rsp->rd_dkg.dkg_obs3 = 0; 524 rsp->rd_dkg.dkg_apc = 0; 525 rsp->rd_dkg.dkg_rpm = 7200; 526 rsp->rd_dkg.dkg_pcyl = rsp->rd_dkg.dkg_ncyl + rsp->rd_dkg.dkg_acyl; 527 rsp->rd_dkg.dkg_nsect = rsp->rd_size / 528 (DEV_BSIZE * rsp->rd_dkg.dkg_ncyl); 529 rsp->rd_dkg.dkg_write_reinstruct = 0; 530 rsp->rd_dkg.dkg_read_reinstruct = 0; 531 532 /* vtoc - see dkio(7I) */ 533 bzero(&rsp->rd_vtoc, sizeof (struct vtoc)); 534 rsp->rd_vtoc.v_sanity = VTOC_SANE; 535 rsp->rd_vtoc.v_version = V_VERSION; 536 bcopy(RD_DRIVER_NAME, rsp->rd_vtoc.v_volume, 7); 537 rsp->rd_vtoc.v_sectorsz = DEV_BSIZE; 538 rsp->rd_vtoc.v_nparts = 1; 539 rsp->rd_vtoc.v_part[0].p_tag = V_UNASSIGNED; 540 rsp->rd_vtoc.v_part[0].p_flag = V_UNMNT; 541 rsp->rd_vtoc.v_part[0].p_start = (daddr_t)0; 542 /* 543 * The partition size cannot just be the number of sectors, because 544 * that might not end on a cylinder boundary. And if that's the case, 545 * newfs/mkfs will print a scary warning. So just figure the size 546 * based on the number of cylinders and sectors/cylinder. 547 */ 548 rsp->rd_vtoc.v_part[0].p_size = rsp->rd_dkg.dkg_pcyl * 549 rsp->rd_dkg.dkg_nsect * rsp->rd_dkg.dkg_nhead; 550 551 /* dk_cinfo - see dkio(7I) */ 552 bzero(&rsp->rd_ci, sizeof (struct dk_cinfo)); 553 (void) strcpy(rsp->rd_ci.dki_cname, RD_DRIVER_NAME); 554 rsp->rd_ci.dki_ctype = DKC_MD; 555 rsp->rd_ci.dki_flags = 0; 556 rsp->rd_ci.dki_cnum = 0; 557 rsp->rd_ci.dki_addr = 0; 558 rsp->rd_ci.dki_space = 0; 559 rsp->rd_ci.dki_prio = 0; 560 rsp->rd_ci.dki_vec = 0; 561 (void) strcpy(rsp->rd_ci.dki_dname, RD_DRIVER_NAME); 562 rsp->rd_ci.dki_unit = 0; 563 rsp->rd_ci.dki_slave = 0; 564 rsp->rd_ci.dki_partition = 0; 565 /* 566 * newfs uses this to set maxcontig. Must not be < 16, or it 567 * will be 0 when newfs multiplies it by DEV_BSIZE and divides 568 * it by the block size. Then tunefs doesn't work because 569 * maxcontig is 0. 570 */ 571 rsp->rd_ci.dki_maxtransfer = 16; 572 } 573 574 /* 575 * Deallocate resources (virtual and physical, device nodes, structures) 576 * from a ramdisk. 577 */ 578 static void 579 rd_dealloc_resources(rd_devstate_t *rsp) 580 { 581 dev_info_t *dip = rsp->rd_dip; 582 char namebuf[RD_NAME_LEN + 5]; 583 dev_t fulldev; 584 585 if (rsp->rd_window_obp == 0 && rsp->rd_window_virt != NULL) { 586 if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 587 rd_unmap_window(rsp); 588 } 589 vmem_free(heap_arena, rsp->rd_window_virt, rsp->rd_window_size); 590 } 591 mutex_destroy(&rsp->rd_device_lock); 592 593 if (rsp->rd_existing) { 594 ddi_prop_free(rsp->rd_existing); 595 } 596 if (rsp->rd_ppa != NULL) { 597 rd_phys_free(rsp->rd_ppa, rsp->rd_npages); 598 } 599 600 /* 601 * Remove the block and raw device nodes. 602 */ 603 if (dip == rd_dip) { 604 (void) snprintf(namebuf, sizeof (namebuf), "%s", 605 rsp->rd_name); 606 ddi_remove_minor_node(dip, namebuf); 607 (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 608 rsp->rd_name); 609 ddi_remove_minor_node(dip, namebuf); 610 } else { 611 ddi_remove_minor_node(dip, "a"); 612 ddi_remove_minor_node(dip, "a,raw"); 613 } 614 615 /* 616 * Remove the "Size" and "Nblocks" properties. 617 */ 618 fulldev = makedevice(ddi_driver_major(dip), rsp->rd_minor); 619 (void) ddi_prop_remove(fulldev, dip, SIZE_PROP_NAME); 620 (void) ddi_prop_remove(fulldev, dip, NBLOCKS_PROP_NAME); 621 622 if (rsp->rd_kstat) { 623 kstat_delete(rsp->rd_kstat); 624 mutex_destroy(&rsp->rd_kstat_lock); 625 } 626 627 ddi_soft_state_free(rd_statep, rsp->rd_minor); 628 } 629 630 /* 631 * Allocate resources (virtual and physical, device nodes, structures) 632 * to a ramdisk. 633 */ 634 static rd_devstate_t * 635 rd_alloc_resources(char *name, uint_t addr, size_t size, dev_info_t *dip) 636 { 637 minor_t minor; 638 rd_devstate_t *rsp; 639 char namebuf[RD_NAME_LEN + 5]; 640 dev_t fulldev; 641 int64_t Nblocks_prop_val; 642 int64_t Size_prop_val; 643 644 minor = rd_find_free_minor(); 645 if (ddi_soft_state_zalloc(rd_statep, minor) == DDI_FAILURE) { 646 return (NULL); 647 } 648 rsp = ddi_get_soft_state(rd_statep, minor); 649 650 (void) strcpy(rsp->rd_name, name); 651 rsp->rd_dip = dip; 652 rsp->rd_minor = minor; 653 rsp->rd_size = size; 654 655 /* 656 * Allocate virtual window onto ramdisk. 657 */ 658 mutex_init(&rsp->rd_device_lock, NULL, MUTEX_DRIVER, NULL); 659 if (addr == 0) { 660 rsp->rd_window_obp = 0; 661 rsp->rd_window_base = RD_WINDOW_NOT_MAPPED; 662 rsp->rd_window_size = PAGESIZE; 663 rsp->rd_window_virt = vmem_alloc(heap_arena, 664 rsp->rd_window_size, VM_SLEEP); 665 if (rsp->rd_window_virt == NULL) { 666 goto create_failed; 667 } 668 } else { 669 rsp->rd_window_obp = 1; 670 rsp->rd_window_base = 0; 671 rsp->rd_window_size = size; 672 rsp->rd_window_virt = (caddr_t)((ulong_t)addr); 673 } 674 675 /* 676 * Allocate physical memory for non-OBP ramdisks. 677 * Create pseudo block and raw device nodes. 678 */ 679 if (dip == rd_dip) { 680 rsp->rd_npages = btopr(size); 681 rsp->rd_ppa = rd_phys_alloc(rsp->rd_npages); 682 if (rsp->rd_ppa == NULL) { 683 goto create_failed; 684 } 685 686 /* 687 * For non-OBP ramdisks the device nodes are: 688 * 689 * /devices/pseudo/ramdisk@0:<diskname> 690 * /devices/pseudo/ramdisk@0:<diskname>,raw 691 */ 692 (void) snprintf(namebuf, sizeof (namebuf), "%s", 693 rsp->rd_name); 694 if (ddi_create_minor_node(dip, namebuf, S_IFBLK, minor, 695 DDI_PSEUDO, 0) == DDI_FAILURE) { 696 goto create_failed; 697 } 698 (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 699 rsp->rd_name); 700 if (ddi_create_minor_node(dip, namebuf, S_IFCHR, minor, 701 DDI_PSEUDO, 0) == DDI_FAILURE) { 702 goto create_failed; 703 } 704 } else { 705 /* 706 * For OBP-created ramdisks the device nodes are: 707 * 708 * /devices/ramdisk-<diskname>:a 709 * /devices/ramdisk-<diskname>:a,raw 710 */ 711 if (ddi_create_minor_node(dip, "a", S_IFBLK, minor, 712 DDI_PSEUDO, 0) == DDI_FAILURE) { 713 goto create_failed; 714 } 715 if (ddi_create_minor_node(dip, "a,raw", S_IFCHR, minor, 716 DDI_PSEUDO, 0) == DDI_FAILURE) { 717 goto create_failed; 718 } 719 } 720 721 /* 722 * Create the "Size" and "Nblocks" properties. 723 */ 724 fulldev = makedevice(ddi_driver_major(dip), minor); 725 Size_prop_val = size; 726 if ((ddi_prop_update_int64(fulldev, dip, 727 SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) { 728 goto create_failed; 729 } 730 Nblocks_prop_val = size / DEV_BSIZE; 731 if ((ddi_prop_update_int64(fulldev, dip, 732 NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) { 733 goto create_failed; 734 } 735 736 /* 737 * Allocate kstat stuff. 738 */ 739 rsp->rd_kstat = kstat_create(RD_DRIVER_NAME, minor, NULL, 740 "disk", KSTAT_TYPE_IO, 1, 0); 741 if (rsp->rd_kstat) { 742 mutex_init(&rsp->rd_kstat_lock, NULL, 743 MUTEX_DRIVER, NULL); 744 rsp->rd_kstat->ks_lock = &rsp->rd_kstat_lock; 745 kstat_install(rsp->rd_kstat); 746 } 747 748 rd_fake_disk_geometry(rsp); 749 750 return (rsp); 751 752 create_failed: 753 /* 754 * Cleanup. 755 */ 756 rd_dealloc_resources(rsp); 757 758 return (NULL); 759 } 760 761 /* 762 * Undo what we did in rd_attach, freeing resources and removing things which 763 * we installed. The system framework guarantees we are not active with this 764 * devinfo node in any other entry points at this time. 765 */ 766 static int 767 rd_common_detach(dev_info_t *dip) 768 { 769 if (dip == rd_dip) { 770 /* 771 * Pseudo node: can't detach if any pseudo ramdisks exist. 772 */ 773 if (rd_is_busy()) { 774 return (DDI_FAILURE); 775 } 776 ddi_soft_state_free(rd_statep, RD_CTL_MINOR); 777 rd_dip = NULL; 778 } else { 779 /* 780 * A 'real' ramdisk; find the state and free resources. 781 */ 782 rd_devstate_t *rsp; 783 784 if ((rsp = rd_find_dip_state(dip)) != NULL) { 785 rd_dealloc_resources(rsp); 786 } 787 } 788 ddi_remove_minor_node(dip, NULL); 789 790 return (DDI_SUCCESS); 791 } 792 793 static int 794 rd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 795 { 796 char *name; 797 rd_existing_t *ep = NULL; 798 uint_t obpaddr = 0, nep, i; 799 size_t size = 0; 800 rd_devstate_t *rsp; 801 802 switch (cmd) { 803 804 case DDI_ATTACH: 805 mutex_enter(&rd_lock); 806 807 /* 808 * For pseudo ramdisk devinfo set up state 0 and :ctl device; 809 * else it's an OBP-created ramdisk. 810 */ 811 if (is_pseudo_device(dip)) { 812 rd_dip = dip; 813 rd_init_tuneables(); 814 815 /* 816 * The zeroth minor is reserved for the ramdisk 817 * 'control' device. 818 */ 819 if (ddi_soft_state_zalloc(rd_statep, RD_CTL_MINOR) == 820 DDI_FAILURE) { 821 goto attach_failed; 822 } 823 rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 824 rsp->rd_dip = dip; 825 826 if (ddi_create_minor_node(dip, RD_CTL_NODE, 827 S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 828 goto attach_failed; 829 } 830 } else { 831 #ifdef __sparc 832 if (bootops_obp_ramdisk_disabled) 833 goto attach_failed; 834 #endif /* __sparc */ 835 836 RD_STRIP_PREFIX(name, ddi_node_name(dip)); 837 838 if (strlen(name) > RD_NAME_LEN) { 839 cmn_err(CE_CONT, 840 "%s: name too long - ignoring\n", name); 841 goto attach_failed; 842 } 843 844 /* 845 * An OBP-created ramdisk must have an 'existing' 846 * property; get and check it. 847 */ 848 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 849 DDI_PROP_DONTPASS, OBP_EXISTING_PROP_NAME, 850 (uchar_t **)&ep, &nep) == DDI_SUCCESS) { 851 852 if (nep == 0 || (nep % sizeof (*ep)) != 0) { 853 cmn_err(CE_CONT, 854 "%s: " OBP_EXISTING_PROP_NAME 855 " illegal size\n", name); 856 goto attach_failed; 857 } 858 nep /= sizeof (*ep); 859 860 /* 861 * Calculate the size of the ramdisk. 862 */ 863 for (i = 0; i < nep; ++i) { 864 size += ep[i].size; 865 } 866 } else if ((obpaddr = ddi_prop_get_int(DDI_DEV_T_ANY, 867 dip, DDI_PROP_DONTPASS, OBP_ADDRESS_PROP_NAME, 868 0)) != 0) { 869 870 size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 871 DDI_PROP_DONTPASS, OBP_SIZE_PROP_NAME, 0); 872 } else { 873 cmn_err(CE_CONT, "%s: missing OBP properties\n", 874 name); 875 goto attach_failed; 876 } 877 878 /* 879 * Allocate driver resources for the ramdisk. 880 */ 881 if ((rsp = rd_alloc_resources(name, obpaddr, size, 882 dip)) == NULL) { 883 goto attach_failed; 884 } 885 886 rsp->rd_existing = ep; 887 rsp->rd_nexisting = nep; 888 } 889 890 mutex_exit(&rd_lock); 891 892 ddi_report_dev(dip); 893 894 return (DDI_SUCCESS); 895 896 case DDI_RESUME: 897 return (DDI_SUCCESS); 898 899 default: 900 return (DDI_FAILURE); 901 } 902 903 attach_failed: 904 /* 905 * Use our common detach routine to unallocate any stuff which 906 * was allocated above. 907 */ 908 (void) rd_common_detach(dip); 909 mutex_exit(&rd_lock); 910 911 if (ep != NULL) { 912 ddi_prop_free(ep); 913 } 914 return (DDI_FAILURE); 915 } 916 917 static int 918 rd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 919 { 920 int e; 921 922 switch (cmd) { 923 924 case DDI_DETACH: 925 mutex_enter(&rd_lock); 926 e = rd_common_detach(dip); 927 mutex_exit(&rd_lock); 928 929 return (e); 930 931 case DDI_SUSPEND: 932 return (DDI_SUCCESS); 933 934 default: 935 return (DDI_FAILURE); 936 } 937 } 938 939 /*ARGSUSED*/ 940 static int 941 rd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 942 { 943 rd_devstate_t *rsp; 944 945 switch (infocmd) { 946 case DDI_INFO_DEVT2DEVINFO: 947 if ((rsp = ddi_get_soft_state(rd_statep, 948 getminor((dev_t)arg))) != NULL) { 949 *result = rsp->rd_dip; 950 return (DDI_SUCCESS); 951 } 952 *result = NULL; 953 return (DDI_FAILURE); 954 955 case DDI_INFO_DEVT2INSTANCE: 956 if ((rsp = ddi_get_soft_state(rd_statep, 957 getminor((dev_t)arg))) != NULL) { 958 *result = (void *)(uintptr_t) 959 ddi_get_instance(rsp->rd_dip); 960 return (DDI_SUCCESS); 961 } 962 *result = NULL; 963 return (DDI_FAILURE); 964 965 default: 966 return (DDI_FAILURE); 967 } 968 } 969 970 /*ARGSUSED3*/ 971 static int 972 rd_open(dev_t *devp, int flag, int otyp, cred_t *credp) 973 { 974 minor_t minor; 975 rd_devstate_t *rsp; 976 977 mutex_enter(&rd_lock); 978 979 minor = getminor(*devp); 980 if (minor == RD_CTL_MINOR) { 981 /* 982 * Master control device; must be opened exclusively. 983 */ 984 if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) { 985 mutex_exit(&rd_lock); 986 return (EINVAL); 987 } 988 989 rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 990 if (rsp == NULL) { 991 mutex_exit(&rd_lock); 992 return (ENXIO); 993 } 994 995 if (rd_is_open(rsp)) { 996 mutex_exit(&rd_lock); 997 return (EBUSY); 998 } 999 (void) rd_opened(rsp, OTYP_CHR); 1000 1001 mutex_exit(&rd_lock); 1002 1003 return (0); 1004 } 1005 1006 rsp = ddi_get_soft_state(rd_statep, minor); 1007 if (rsp == NULL) { 1008 mutex_exit(&rd_lock); 1009 return (ENXIO); 1010 } 1011 1012 if (rd_opened(rsp, otyp) == -1) { 1013 mutex_exit(&rd_lock); 1014 return (EINVAL); 1015 } 1016 1017 mutex_exit(&rd_lock); 1018 return (0); 1019 } 1020 1021 /*ARGSUSED*/ 1022 static int 1023 rd_close(dev_t dev, int flag, int otyp, struct cred *credp) 1024 { 1025 minor_t minor; 1026 rd_devstate_t *rsp; 1027 1028 mutex_enter(&rd_lock); 1029 1030 minor = getminor(dev); 1031 1032 rsp = ddi_get_soft_state(rd_statep, minor); 1033 if (rsp == NULL) { 1034 mutex_exit(&rd_lock); 1035 return (EINVAL); 1036 } 1037 1038 rd_closed(rsp, otyp); 1039 1040 mutex_exit(&rd_lock); 1041 1042 return (0); 1043 } 1044 1045 static void 1046 rd_minphys(struct buf *bp) 1047 { 1048 if (bp->b_bcount > rd_maxphys) { 1049 bp->b_bcount = rd_maxphys; 1050 } 1051 } 1052 1053 static void 1054 rd_rw(rd_devstate_t *rsp, struct buf *bp, offset_t offset, size_t nbytes) 1055 { 1056 int reading = bp->b_flags & B_READ; 1057 caddr_t buf_addr; 1058 1059 bp_mapin(bp); 1060 buf_addr = bp->b_un.b_addr; 1061 1062 while (nbytes > 0) { 1063 offset_t off_in_window; 1064 size_t rem_in_window, copy_bytes; 1065 caddr_t raddr; 1066 1067 mutex_enter(&rsp->rd_device_lock); 1068 rd_map_window(rsp, offset); 1069 1070 off_in_window = offset - rsp->rd_window_base; 1071 rem_in_window = rsp->rd_window_size - off_in_window; 1072 1073 raddr = rsp->rd_window_virt + off_in_window; 1074 copy_bytes = MIN(nbytes, rem_in_window); 1075 1076 if (reading) { 1077 (void) bcopy(raddr, buf_addr, copy_bytes); 1078 } else { 1079 (void) bcopy(buf_addr, raddr, copy_bytes); 1080 } 1081 mutex_exit(&rsp->rd_device_lock); 1082 1083 offset += copy_bytes; 1084 buf_addr += copy_bytes; 1085 nbytes -= copy_bytes; 1086 } 1087 } 1088 1089 /* 1090 * On Sparc, this function deals with both pseudo ramdisks and OBP ramdisks. 1091 * In the case where we freed the "bootarchive" ramdisk in bop_free_archive(), 1092 * we stop allowing access to the OBP ramdisks. To do so, we set the 1093 * bootops_obp_ramdisk_disabled flag to true, and we check if the operation 1094 * is for an OBP ramdisk. In this case we indicate an ENXIO error. 1095 */ 1096 static int 1097 rd_strategy(struct buf *bp) 1098 { 1099 rd_devstate_t *rsp; 1100 offset_t offset; 1101 1102 rsp = ddi_get_soft_state(rd_statep, getminor(bp->b_edev)); 1103 offset = bp->b_blkno * DEV_BSIZE; 1104 1105 #ifdef __sparc 1106 if (rsp == NULL || 1107 (bootops_obp_ramdisk_disabled && 1108 (rsp->rd_dip != rd_dip || rd_dip == NULL))) { /* OBP ramdisk */ 1109 #else /* __sparc */ 1110 if (rsp == NULL) { 1111 #endif /* __sparc */ 1112 bp->b_error = ENXIO; 1113 bp->b_flags |= B_ERROR; 1114 } else if (offset >= rsp->rd_size) { 1115 bp->b_error = EINVAL; 1116 bp->b_flags |= B_ERROR; 1117 } else { 1118 size_t nbytes; 1119 1120 if (rsp->rd_kstat) { 1121 mutex_enter(rsp->rd_kstat->ks_lock); 1122 kstat_runq_enter(KSTAT_IO_PTR(rsp->rd_kstat)); 1123 mutex_exit(rsp->rd_kstat->ks_lock); 1124 } 1125 1126 nbytes = min(bp->b_bcount, rsp->rd_size - offset); 1127 1128 rd_rw(rsp, bp, offset, nbytes); 1129 1130 bp->b_resid = bp->b_bcount - nbytes; 1131 1132 if (rsp->rd_kstat) { 1133 kstat_io_t *kioptr; 1134 1135 mutex_enter(rsp->rd_kstat->ks_lock); 1136 kioptr = KSTAT_IO_PTR(rsp->rd_kstat); 1137 if (bp->b_flags & B_READ) { 1138 kioptr->nread += nbytes; 1139 kioptr->reads++; 1140 } else { 1141 kioptr->nwritten += nbytes; 1142 kioptr->writes++; 1143 } 1144 kstat_runq_exit(kioptr); 1145 mutex_exit(rsp->rd_kstat->ks_lock); 1146 } 1147 } 1148 1149 biodone(bp); 1150 return (0); 1151 } 1152 1153 /*ARGSUSED*/ 1154 static int 1155 rd_read(dev_t dev, struct uio *uiop, cred_t *credp) 1156 { 1157 rd_devstate_t *rsp; 1158 1159 rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 1160 1161 if (uiop->uio_offset >= rsp->rd_size) 1162 return (EINVAL); 1163 1164 return (physio(rd_strategy, NULL, dev, B_READ, rd_minphys, uiop)); 1165 } 1166 1167 /*ARGSUSED*/ 1168 static int 1169 rd_write(dev_t dev, register struct uio *uiop, cred_t *credp) 1170 { 1171 rd_devstate_t *rsp; 1172 1173 rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 1174 1175 if (uiop->uio_offset >= rsp->rd_size) 1176 return (EINVAL); 1177 1178 return (physio(rd_strategy, NULL, dev, B_WRITE, rd_minphys, uiop)); 1179 } 1180 1181 /*ARGSUSED*/ 1182 static int 1183 rd_create_disk(dev_t dev, struct rd_ioctl *urip, int mode, int *rvalp) 1184 { 1185 struct rd_ioctl kri; 1186 size_t size; 1187 rd_devstate_t *rsp; 1188 1189 if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 1190 return (EFAULT); 1191 } 1192 1193 kri.ri_name[RD_NAME_LEN] = '\0'; 1194 1195 size = kri.ri_size; 1196 if (size == 0) { 1197 return (EINVAL); 1198 } 1199 size = ptob(btopr(size)); 1200 1201 mutex_enter(&rd_lock); 1202 1203 if (rd_find_named_disk(kri.ri_name) != NULL) { 1204 mutex_exit(&rd_lock); 1205 return (EEXIST); 1206 } 1207 1208 rsp = rd_alloc_resources(kri.ri_name, 0, size, rd_dip); 1209 if (rsp == NULL) { 1210 mutex_exit(&rd_lock); 1211 return (EAGAIN); 1212 } 1213 1214 mutex_exit(&rd_lock); 1215 1216 return (ddi_copyout(&kri, urip, sizeof (kri), mode) == -1 ? EFAULT : 0); 1217 } 1218 1219 /*ARGSUSED*/ 1220 static int 1221 rd_delete_disk(dev_t dev, struct rd_ioctl *urip, int mode) 1222 { 1223 struct rd_ioctl kri; 1224 rd_devstate_t *rsp; 1225 1226 if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 1227 return (EFAULT); 1228 } 1229 1230 kri.ri_name[RD_NAME_LEN] = '\0'; 1231 1232 mutex_enter(&rd_lock); 1233 1234 rsp = rd_find_named_disk(kri.ri_name); 1235 if (rsp == NULL || rsp->rd_dip != rd_dip) { 1236 mutex_exit(&rd_lock); 1237 return (EINVAL); 1238 } 1239 if (rd_is_open(rsp)) { 1240 mutex_exit(&rd_lock); 1241 return (EBUSY); 1242 } 1243 1244 rd_dealloc_resources(rsp); 1245 1246 mutex_exit(&rd_lock); 1247 1248 return (0); 1249 } 1250 1251 /*ARGSUSED*/ 1252 static int 1253 rd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 1254 { 1255 minor_t minor; 1256 int error; 1257 enum dkio_state dkstate; 1258 rd_devstate_t *rsp; 1259 1260 minor = getminor(dev); 1261 1262 /* 1263 * Ramdisk ioctls only apply to the master device. 1264 */ 1265 if (minor == RD_CTL_MINOR) { 1266 struct rd_ioctl *rip = (struct rd_ioctl *)arg; 1267 1268 /* 1269 * The query commands only need read-access - i.e., normal 1270 * users are allowed to do those on the controlling device 1271 * as long as they can open it read-only. 1272 */ 1273 switch (cmd) { 1274 case RD_CREATE_DISK: 1275 if ((mode & FWRITE) == 0) 1276 return (EPERM); 1277 return (rd_create_disk(dev, rip, mode, rvalp)); 1278 1279 case RD_DELETE_DISK: 1280 if ((mode & FWRITE) == 0) 1281 return (EPERM); 1282 return (rd_delete_disk(dev, rip, mode)); 1283 1284 default: 1285 return (EINVAL); 1286 } 1287 } 1288 1289 rsp = ddi_get_soft_state(rd_statep, minor); 1290 if (rsp == NULL) { 1291 return (ENXIO); 1292 } 1293 1294 /* 1295 * These are for faking out utilities like newfs. 1296 */ 1297 switch (cmd) { 1298 case DKIOCGVTOC: 1299 switch (ddi_model_convert_from(mode & FMODELS)) { 1300 case DDI_MODEL_ILP32: { 1301 struct vtoc32 vtoc32; 1302 1303 vtoctovtoc32(rsp->rd_vtoc, vtoc32); 1304 if (ddi_copyout(&vtoc32, (void *)arg, 1305 sizeof (struct vtoc32), mode)) 1306 return (EFAULT); 1307 } 1308 break; 1309 1310 case DDI_MODEL_NONE: 1311 if (ddi_copyout(&rsp->rd_vtoc, (void *)arg, 1312 sizeof (struct vtoc), mode)) 1313 return (EFAULT); 1314 break; 1315 } 1316 return (0); 1317 case DKIOCINFO: 1318 error = ddi_copyout(&rsp->rd_ci, (void *)arg, 1319 sizeof (struct dk_cinfo), mode); 1320 if (error) 1321 return (EFAULT); 1322 return (0); 1323 case DKIOCG_VIRTGEOM: 1324 case DKIOCG_PHYGEOM: 1325 case DKIOCGGEOM: 1326 error = ddi_copyout(&rsp->rd_dkg, (void *)arg, 1327 sizeof (struct dk_geom), mode); 1328 if (error) 1329 return (EFAULT); 1330 return (0); 1331 case DKIOCSTATE: 1332 /* the file is always there */ 1333 dkstate = DKIO_INSERTED; 1334 error = ddi_copyout(&dkstate, (void *)arg, 1335 sizeof (enum dkio_state), mode); 1336 if (error) 1337 return (EFAULT); 1338 return (0); 1339 default: 1340 return (ENOTTY); 1341 } 1342 } 1343 1344 1345 static struct cb_ops rd_cb_ops = { 1346 rd_open, 1347 rd_close, 1348 rd_strategy, 1349 nodev, 1350 nodev, /* dump */ 1351 rd_read, 1352 rd_write, 1353 rd_ioctl, 1354 nodev, /* devmap */ 1355 nodev, /* mmap */ 1356 nodev, /* segmap */ 1357 nochpoll, /* poll */ 1358 ddi_prop_op, 1359 NULL, 1360 D_NEW | D_MP 1361 }; 1362 1363 static struct dev_ops rd_ops = { 1364 DEVO_REV, 1365 0, 1366 rd_getinfo, 1367 nulldev, /* identify */ 1368 nulldev, /* probe */ 1369 rd_attach, 1370 rd_detach, 1371 nodev, /* reset */ 1372 &rd_cb_ops, 1373 (struct bus_ops *)0, 1374 NULL, 1375 ddi_quiesce_not_needed, /* quiesce */ 1376 }; 1377 1378 1379 extern struct mod_ops mod_driverops; 1380 1381 static struct modldrv modldrv = { 1382 &mod_driverops, 1383 "ramdisk driver", 1384 &rd_ops 1385 }; 1386 1387 static struct modlinkage modlinkage = { 1388 MODREV_1, 1389 { &modldrv, NULL } 1390 }; 1391 1392 int 1393 _init(void) 1394 { 1395 int e; 1396 1397 if ((e = ddi_soft_state_init(&rd_statep, 1398 sizeof (rd_devstate_t), 0)) != 0) { 1399 return (e); 1400 } 1401 1402 mutex_init(&rd_lock, NULL, MUTEX_DRIVER, NULL); 1403 1404 if ((e = mod_install(&modlinkage)) != 0) { 1405 mutex_destroy(&rd_lock); 1406 ddi_soft_state_fini(&rd_statep); 1407 } 1408 1409 return (e); 1410 } 1411 1412 int 1413 _fini(void) 1414 { 1415 int e; 1416 1417 if ((e = mod_remove(&modlinkage)) != 0) { 1418 return (e); 1419 } 1420 1421 ddi_soft_state_fini(&rd_statep); 1422 mutex_destroy(&rd_lock); 1423 1424 return (e); 1425 } 1426 1427 int 1428 _info(struct modinfo *modinfop) 1429 { 1430 return (mod_info(&modlinkage, modinfop)); 1431 }