10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52912Sartem * Common Development and Distribution License (the "License"). 62912Sartem * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4363Sblakej * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Ramdisk device driver. 300Sstevel@tonic-gate * 310Sstevel@tonic-gate * There are two types of ramdisk: 'real' OBP-created ramdisks, and 'pseudo' 320Sstevel@tonic-gate * ramdisks created at runtime with no corresponding OBP device node. The 330Sstevel@tonic-gate * ramdisk(7D) driver is capable of dealing with both, and with the creation 340Sstevel@tonic-gate * and deletion of 'pseudo' ramdisks. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * Every ramdisk has a single 'state' structure which maintains data for 370Sstevel@tonic-gate * that ramdisk, and is assigned a single minor number. The bottom 10-bits 380Sstevel@tonic-gate * of the minor number index the state structures; the top 8-bits give a 390Sstevel@tonic-gate * 'real OBP disk' number, i.e. they are zero for 'pseudo' ramdisks. Thus 400Sstevel@tonic-gate * it is possible to distinguish 'real' from 'pseudo' ramdisks using the 410Sstevel@tonic-gate * top 8-bits of the minor number. 420Sstevel@tonic-gate * 430Sstevel@tonic-gate * Each OBP-created ramdisk has its own node in the device tree with an 440Sstevel@tonic-gate * "existing" property which describes the one-or-more physical address ranges 450Sstevel@tonic-gate * assigned to the ramdisk. All 'pseudo' ramdisks share a common devinfo 460Sstevel@tonic-gate * structure. 470Sstevel@tonic-gate * 480Sstevel@tonic-gate * A single character device node is used by ramdiskadm(1M) to communicate 490Sstevel@tonic-gate * with the ramdisk driver, with minor number 0: 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * /dev/ramdiskctl -> /devices/pseudo/ramdisk@0:ctl 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * For consistent access, block and raw device nodes are created for *every* 540Sstevel@tonic-gate * ramdisk. For 'pseudo' ramdisks: 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * /dev/ramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname> 570Sstevel@tonic-gate * /dev/rramdisk/<diskname> -> /devices/pseudo/ramdisk@0:<diskname>,raw 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * For OBP-created ramdisks: 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a 620Sstevel@tonic-gate * /dev/ramdisk/<diskname> -> /devices/ramdisk-<diskname>:a,raw 630Sstevel@tonic-gate * 640Sstevel@tonic-gate * This allows the transition from the standalone to the kernel to proceed 650Sstevel@tonic-gate * when booting from a ramdisk, and for the installation to correctly identify 660Sstevel@tonic-gate * the root device. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate 690Sstevel@tonic-gate #include <sys/types.h> 700Sstevel@tonic-gate #include <sys/param.h> 710Sstevel@tonic-gate #include <sys/sysmacros.h> 720Sstevel@tonic-gate #include <sys/errno.h> 730Sstevel@tonic-gate #include <sys/uio.h> 740Sstevel@tonic-gate #include <sys/buf.h> 750Sstevel@tonic-gate #include <sys/modctl.h> 760Sstevel@tonic-gate #include <sys/open.h> 770Sstevel@tonic-gate #include <sys/kmem.h> 780Sstevel@tonic-gate #include <sys/poll.h> 790Sstevel@tonic-gate #include <sys/conf.h> 800Sstevel@tonic-gate #include <sys/cmn_err.h> 810Sstevel@tonic-gate #include <sys/stat.h> 820Sstevel@tonic-gate #include <sys/file.h> 830Sstevel@tonic-gate #include <sys/ddi.h> 840Sstevel@tonic-gate #include <sys/sunddi.h> 850Sstevel@tonic-gate #include <sys/ramdisk.h> 860Sstevel@tonic-gate #include <vm/seg_kmem.h> 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * An opaque handle where information about our set of ramdisk devices lives. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate static void *rd_statep; 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Pointer to devinfo for the 'pseudo' ramdisks. Real OBP-created ramdisks 950Sstevel@tonic-gate * get their own individual devinfo. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate static dev_info_t *rd_dip = NULL; 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * Global state lock. 1010Sstevel@tonic-gate */ 1020Sstevel@tonic-gate static kmutex_t rd_lock; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* 1050Sstevel@tonic-gate * Maximum number of ramdisks supported by this driver. 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate static uint32_t rd_max_disks = RD_DFLT_DISKS; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate /* 1100Sstevel@tonic-gate * Percentage of physical memory which can be assigned to pseudo ramdisks, 1110Sstevel@tonic-gate * what that equates to in pages, and how many pages are currently assigned. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate static uint_t rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 1140Sstevel@tonic-gate static pgcnt_t rd_max_physmem; 1150Sstevel@tonic-gate static pgcnt_t rd_tot_physmem; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate static uint_t rd_maxphys = RD_DEFAULT_MAXPHYS; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Is the driver busy, i.e. are there any pseudo ramdisk devices in existence? 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate static int 1230Sstevel@tonic-gate rd_is_busy(void) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate minor_t minor; 1260Sstevel@tonic-gate rd_devstate_t *rsp; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 1290Sstevel@tonic-gate for (minor = 1; minor <= rd_max_disks; ++minor) { 1300Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 1310Sstevel@tonic-gate rsp->rd_dip == rd_dip) { 1320Sstevel@tonic-gate return (EBUSY); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate return (0); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * Find the first free minor number; returns zero if there isn't one. 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate static minor_t 1420Sstevel@tonic-gate rd_find_free_minor(void) 1430Sstevel@tonic-gate { 1440Sstevel@tonic-gate minor_t minor; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 1470Sstevel@tonic-gate for (minor = 1; minor <= rd_max_disks; ++minor) { 1480Sstevel@tonic-gate if (ddi_get_soft_state(rd_statep, minor) == NULL) { 1490Sstevel@tonic-gate return (minor); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate return (0); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* 1560Sstevel@tonic-gate * Locate the rd_devstate for the named ramdisk; returns NULL if not found. 1570Sstevel@tonic-gate * Each ramdisk is identified uniquely by name, i.e. an OBP-created ramdisk 1580Sstevel@tonic-gate * cannot have the same name as a pseudo ramdisk. 1590Sstevel@tonic-gate */ 1600Sstevel@tonic-gate static rd_devstate_t * 1610Sstevel@tonic-gate rd_find_named_disk(char *name) 1620Sstevel@tonic-gate { 1630Sstevel@tonic-gate minor_t minor; 1640Sstevel@tonic-gate rd_devstate_t *rsp; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 1670Sstevel@tonic-gate for (minor = 1; minor <= rd_max_disks; ++minor) { 1680Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 1690Sstevel@tonic-gate strcmp(rsp->rd_name, name) == 0) { 1700Sstevel@tonic-gate return (rsp); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate return (NULL); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Locate the rd_devstate for the real OBP-created ramdisk whose devinfo 1780Sstevel@tonic-gate * is referenced by 'dip'; returns NULL if not found (shouldn't happen). 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate static rd_devstate_t * 1810Sstevel@tonic-gate rd_find_dip_state(dev_info_t *dip) 1820Sstevel@tonic-gate { 1830Sstevel@tonic-gate minor_t minor; 1840Sstevel@tonic-gate rd_devstate_t *rsp; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 1870Sstevel@tonic-gate for (minor = 1; minor <= rd_max_disks; ++minor) { 1880Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, minor)) != NULL && 1890Sstevel@tonic-gate rsp->rd_dip == dip) { 1900Sstevel@tonic-gate return (rsp); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate return (NULL); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * Is the ramdisk open? 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate static int 2000Sstevel@tonic-gate rd_is_open(rd_devstate_t *rsp) 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 2030Sstevel@tonic-gate return (rsp->rd_chr_open || rsp->rd_blk_open || rsp->rd_lyr_open_cnt); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * Mark the ramdisk open. 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate static int 2100Sstevel@tonic-gate rd_opened(rd_devstate_t *rsp, int otyp) 2110Sstevel@tonic-gate { 2120Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 2130Sstevel@tonic-gate switch (otyp) { 2140Sstevel@tonic-gate case OTYP_CHR: 2150Sstevel@tonic-gate rsp->rd_chr_open = 1; 2160Sstevel@tonic-gate break; 2170Sstevel@tonic-gate case OTYP_BLK: 2180Sstevel@tonic-gate rsp->rd_blk_open = 1; 2190Sstevel@tonic-gate break; 2200Sstevel@tonic-gate case OTYP_LYR: 2210Sstevel@tonic-gate rsp->rd_lyr_open_cnt++; 2220Sstevel@tonic-gate break; 2230Sstevel@tonic-gate default: 2240Sstevel@tonic-gate return (-1); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate return (0); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Mark the ramdisk closed. 2310Sstevel@tonic-gate */ 2320Sstevel@tonic-gate static void 2330Sstevel@tonic-gate rd_closed(rd_devstate_t *rsp, int otyp) 2340Sstevel@tonic-gate { 2350Sstevel@tonic-gate ASSERT(mutex_owned(&rd_lock)); 2360Sstevel@tonic-gate switch (otyp) { 2370Sstevel@tonic-gate case OTYP_CHR: 2380Sstevel@tonic-gate rsp->rd_chr_open = 0; 2390Sstevel@tonic-gate break; 2400Sstevel@tonic-gate case OTYP_BLK: 2410Sstevel@tonic-gate rsp->rd_blk_open = 0; 2420Sstevel@tonic-gate break; 2430Sstevel@tonic-gate case OTYP_LYR: 2440Sstevel@tonic-gate rsp->rd_lyr_open_cnt--; 2450Sstevel@tonic-gate break; 2460Sstevel@tonic-gate default: 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate static void 2520Sstevel@tonic-gate rd_init_tuneables(void) 2530Sstevel@tonic-gate { 2540Sstevel@tonic-gate char *prop, *p; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * Ensure sanity of 'rd_max_disks', which may be tuned in ramdisk.conf. 2580Sstevel@tonic-gate */ 2590Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 2600Sstevel@tonic-gate "max_disks", &prop) == DDI_PROP_SUCCESS) { 2610Sstevel@tonic-gate p = prop; 2620Sstevel@tonic-gate rd_max_disks = (uint32_t)stoi(&p); 2630Sstevel@tonic-gate ddi_prop_free(prop); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate if (rd_max_disks >= RD_MAX_DISKS) { 2660Sstevel@tonic-gate cmn_err(CE_WARN, "ramdisk: rd_max_disks (%u) too big;" 2670Sstevel@tonic-gate " using default (%u).", rd_max_disks, RD_MAX_DISKS - 1); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate rd_max_disks = RD_MAX_DISKS - 1; 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * Ensure sanity of 'rd_percent_physmem', which may be tuned 2740Sstevel@tonic-gate * in ramdisk.conf. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, rd_dip, 0, 2770Sstevel@tonic-gate "percent_physmem", &prop) == DDI_PROP_SUCCESS) { 2780Sstevel@tonic-gate p = prop; 2790Sstevel@tonic-gate rd_percent_physmem = (uint_t)stoi(&p); 2800Sstevel@tonic-gate ddi_prop_free(prop); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate if (rd_percent_physmem >= 100) { 2830Sstevel@tonic-gate cmn_err(CE_WARN, "ramdisk: rd_percent_physmem (%u) >= 100;" 2840Sstevel@tonic-gate " using default (%u%%).", rd_percent_physmem, 2850Sstevel@tonic-gate RD_DEFAULT_PERCENT_PHYSMEM); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate rd_percent_physmem = RD_DEFAULT_PERCENT_PHYSMEM; 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* 291*4363Sblakej * Since availrmem_initial is a long, this won't overflow. 2920Sstevel@tonic-gate */ 293*4363Sblakej rd_max_physmem = (availrmem_initial * rd_percent_physmem) / 100; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 297*4363Sblakej * Allocate enough physical pages to hold "npages" pages. Returns an 2980Sstevel@tonic-gate * array of page_t * pointers that can later be mapped in or out via 2990Sstevel@tonic-gate * rd_{un}map_window() but is otherwise opaque, or NULL on failure. 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate page_t ** 3020Sstevel@tonic-gate rd_phys_alloc(pgcnt_t npages) 3030Sstevel@tonic-gate { 3040Sstevel@tonic-gate page_t *pp, **ppa; 305*4363Sblakej spgcnt_t i; 306*4363Sblakej size_t ppalen; 3070Sstevel@tonic-gate struct seg kseg; 308*4363Sblakej caddr_t addr; /* For coloring */ 309*4363Sblakej 310*4363Sblakej if (rd_tot_physmem + npages > rd_max_physmem) 311*4363Sblakej return (NULL); 3120Sstevel@tonic-gate 313*4363Sblakej if (!page_resv(npages, KM_NOSLEEP)) 314*4363Sblakej return (NULL); 315*4363Sblakej 316*4363Sblakej if (!page_create_wait(npages, 0)) { 317*4363Sblakej page_unresv(npages); 3180Sstevel@tonic-gate return (NULL); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 321*4363Sblakej ppalen = npages * sizeof (struct page_t *); 322*4363Sblakej ppa = kmem_zalloc(ppalen, KM_NOSLEEP); 323*4363Sblakej if (ppa == NULL) { 324*4363Sblakej page_create_putback(npages); 325*4363Sblakej page_unresv(npages); 326*4363Sblakej return (NULL); 327*4363Sblakej } 3280Sstevel@tonic-gate 329*4363Sblakej kseg.s_as = &kas; 330*4363Sblakej for (i = 0, addr = NULL; i < npages; ++i, addr += PAGESIZE) { 331*4363Sblakej pp = page_get_freelist(&kvp, 0, &kseg, addr, PAGESIZE, 0, NULL); 332*4363Sblakej if (pp == NULL) { 333*4363Sblakej pp = page_get_cachelist(&kvp, 0, &kseg, addr, 0, NULL); 334*4363Sblakej if (pp == NULL) 3350Sstevel@tonic-gate goto out; 336*4363Sblakej if (!PP_ISAGED(pp)) 3370Sstevel@tonic-gate page_hashout(pp, NULL); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate PP_CLRFREE(pp); 3410Sstevel@tonic-gate PP_CLRAGED(pp); 3420Sstevel@tonic-gate ppa[i] = pp; 3430Sstevel@tonic-gate } 344*4363Sblakej 345*4363Sblakej for (i = 0; i < npages; i++) 346*4363Sblakej page_downgrade(ppa[i]); 3470Sstevel@tonic-gate rd_tot_physmem += npages; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate return (ppa); 350*4363Sblakej 3510Sstevel@tonic-gate out: 352*4363Sblakej ASSERT(i < npages); 353*4363Sblakej page_create_putback(npages - i); 354*4363Sblakej while (--i >= 0) 3550Sstevel@tonic-gate page_free(ppa[i], 0); 3560Sstevel@tonic-gate kmem_free(ppa, ppalen); 3570Sstevel@tonic-gate page_unresv(npages); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate return (NULL); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * Free physical pages previously allocated via rd_phys_alloc(); note that 3640Sstevel@tonic-gate * this function may block as it has to wait until it can exclusively lock 3650Sstevel@tonic-gate * all the pages first. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate static void 3680Sstevel@tonic-gate rd_phys_free(page_t **ppa, pgcnt_t npages) 3690Sstevel@tonic-gate { 3700Sstevel@tonic-gate pgcnt_t i; 3710Sstevel@tonic-gate size_t ppalen = npages * sizeof (struct page_t *); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate for (i = 0; i < npages; ++i) { 3740Sstevel@tonic-gate if (! page_tryupgrade(ppa[i])) { 3750Sstevel@tonic-gate page_unlock(ppa[i]); 3760Sstevel@tonic-gate while (! page_lock(ppa[i], SE_EXCL, NULL, P_RECLAIM)) 3770Sstevel@tonic-gate ; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate page_free(ppa[i], 0); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate kmem_free(ppa, ppalen); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate page_unresv(npages); 3850Sstevel@tonic-gate rd_tot_physmem -= npages; 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * Remove a window mapping (if present). 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate static void 3920Sstevel@tonic-gate rd_unmap_window(rd_devstate_t *rsp) 3930Sstevel@tonic-gate { 3940Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 3950Sstevel@tonic-gate hat_unload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 3960Sstevel@tonic-gate HAT_UNLOAD_UNLOCK); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * Map a portion of the ramdisk into the virtual window. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate static void 4040Sstevel@tonic-gate rd_map_window(rd_devstate_t *rsp, off_t offset) 4050Sstevel@tonic-gate { 4060Sstevel@tonic-gate pgcnt_t offpgs = btop(offset); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Already mapped; is offset within our window? 4110Sstevel@tonic-gate */ 4120Sstevel@tonic-gate if (offset >= rsp->rd_window_base && 4130Sstevel@tonic-gate offset < rsp->rd_window_base + rsp->rd_window_size) { 4140Sstevel@tonic-gate return; 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * No, we need to re-map; toss the old mapping. 4190Sstevel@tonic-gate */ 4200Sstevel@tonic-gate rd_unmap_window(rsp); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate rsp->rd_window_base = ptob(offpgs); 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * Different algorithms depending on whether this is a real 4260Sstevel@tonic-gate * OBP-created ramdisk, or a pseudo ramdisk. 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate if (rsp->rd_dip == rd_dip) { 4290Sstevel@tonic-gate pgcnt_t pi, lastpi; 4300Sstevel@tonic-gate caddr_t vaddr; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * Find the range of pages which should be mapped. 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate pi = offpgs; 4360Sstevel@tonic-gate lastpi = pi + btopr(rsp->rd_window_size); 4370Sstevel@tonic-gate if (lastpi > rsp->rd_npages) { 4380Sstevel@tonic-gate lastpi = rsp->rd_npages; 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate /* 4420Sstevel@tonic-gate * Load the mapping. 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate vaddr = rsp->rd_window_virt; 4450Sstevel@tonic-gate for (; pi < lastpi; ++pi) { 4460Sstevel@tonic-gate hat_memload(kas.a_hat, vaddr, rsp->rd_ppa[pi], 4470Sstevel@tonic-gate (PROT_READ | PROT_WRITE) | HAT_NOSYNC, 4480Sstevel@tonic-gate HAT_LOAD_LOCK); 4490Sstevel@tonic-gate vaddr += ptob(1); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate } else { 4520Sstevel@tonic-gate uint_t i; 4530Sstevel@tonic-gate pfn_t pfn; 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * Real OBP-created ramdisk: locate the physical range which 4570Sstevel@tonic-gate * contains this offset. 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate for (i = 0; i < rsp->rd_nexisting; ++i) { 4600Sstevel@tonic-gate if (offset < rsp->rd_existing[i].size) { 4610Sstevel@tonic-gate break; 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate offset -= rsp->rd_existing[i].size; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate ASSERT(i < rsp->rd_nexisting); 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Load the mapping. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate pfn = btop(rsp->rd_existing[i].phys + offset); 4710Sstevel@tonic-gate hat_devload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 4720Sstevel@tonic-gate pfn, (PROT_READ | PROT_WRITE), 4730Sstevel@tonic-gate HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * Fakes up a disk geometry, and one big partition, based on the size 4790Sstevel@tonic-gate * of the file. This is needed because we allow newfs'ing the device, 4800Sstevel@tonic-gate * and newfs will do several disk ioctls to figure out the geometry and 4810Sstevel@tonic-gate * partition information. It uses that information to determine the parameters 4823517Smp204432 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we 4830Sstevel@tonic-gate * have to support it. 4840Sstevel@tonic-gate * 4850Sstevel@tonic-gate * Stolen from lofi.c - should maybe split out common code sometime. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate static void 4880Sstevel@tonic-gate rd_fake_disk_geometry(rd_devstate_t *rsp) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate /* dk_geom - see dkio(7I) */ 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * dkg_ncyl _could_ be set to one here (one big cylinder with gobs 4930Sstevel@tonic-gate * of sectors), but that breaks programs like fdisk which want to 4940Sstevel@tonic-gate * partition a disk by cylinder. With one cylinder, you can't create 4950Sstevel@tonic-gate * an fdisk partition and put pcfs on it for testing (hard to pick 4960Sstevel@tonic-gate * a number between one and one). 4970Sstevel@tonic-gate * 4980Sstevel@tonic-gate * The cheezy floppy test is an attempt to not have too few cylinders 4990Sstevel@tonic-gate * for a small file, or so many on a big file that you waste space 5000Sstevel@tonic-gate * for backup superblocks or cylinder group structures. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate if (rsp->rd_size < (2 * 1024 * 1024)) /* floppy? */ 5030Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (100 * 1024); 5040Sstevel@tonic-gate else 5050Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (300 * 1024); 5060Sstevel@tonic-gate /* in case file file is < 100k */ 5070Sstevel@tonic-gate if (rsp->rd_dkg.dkg_ncyl == 0) 5080Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = 1; 5090Sstevel@tonic-gate rsp->rd_dkg.dkg_acyl = 0; 5100Sstevel@tonic-gate rsp->rd_dkg.dkg_bcyl = 0; 5110Sstevel@tonic-gate rsp->rd_dkg.dkg_nhead = 1; 5120Sstevel@tonic-gate rsp->rd_dkg.dkg_obs1 = 0; 5130Sstevel@tonic-gate rsp->rd_dkg.dkg_intrlv = 0; 5140Sstevel@tonic-gate rsp->rd_dkg.dkg_obs2 = 0; 5150Sstevel@tonic-gate rsp->rd_dkg.dkg_obs3 = 0; 5160Sstevel@tonic-gate rsp->rd_dkg.dkg_apc = 0; 5170Sstevel@tonic-gate rsp->rd_dkg.dkg_rpm = 7200; 5180Sstevel@tonic-gate rsp->rd_dkg.dkg_pcyl = rsp->rd_dkg.dkg_ncyl + rsp->rd_dkg.dkg_acyl; 5190Sstevel@tonic-gate rsp->rd_dkg.dkg_nsect = rsp->rd_size / 5200Sstevel@tonic-gate (DEV_BSIZE * rsp->rd_dkg.dkg_ncyl); 5210Sstevel@tonic-gate rsp->rd_dkg.dkg_write_reinstruct = 0; 5220Sstevel@tonic-gate rsp->rd_dkg.dkg_read_reinstruct = 0; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* vtoc - see dkio(7I) */ 5250Sstevel@tonic-gate bzero(&rsp->rd_vtoc, sizeof (struct vtoc)); 5260Sstevel@tonic-gate rsp->rd_vtoc.v_sanity = VTOC_SANE; 5270Sstevel@tonic-gate rsp->rd_vtoc.v_version = V_VERSION; 5280Sstevel@tonic-gate bcopy(RD_DRIVER_NAME, rsp->rd_vtoc.v_volume, 7); 5290Sstevel@tonic-gate rsp->rd_vtoc.v_sectorsz = DEV_BSIZE; 5300Sstevel@tonic-gate rsp->rd_vtoc.v_nparts = 1; 5310Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_tag = V_UNASSIGNED; 5320Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_flag = V_UNMNT; 5330Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_start = (daddr_t)0; 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * The partition size cannot just be the number of sectors, because 5360Sstevel@tonic-gate * that might not end on a cylinder boundary. And if that's the case, 5370Sstevel@tonic-gate * newfs/mkfs will print a scary warning. So just figure the size 5380Sstevel@tonic-gate * based on the number of cylinders and sectors/cylinder. 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_size = rsp->rd_dkg.dkg_pcyl * 5410Sstevel@tonic-gate rsp->rd_dkg.dkg_nsect * rsp->rd_dkg.dkg_nhead; 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* dk_cinfo - see dkio(7I) */ 5440Sstevel@tonic-gate bzero(&rsp->rd_ci, sizeof (struct dk_cinfo)); 5450Sstevel@tonic-gate (void) strcpy(rsp->rd_ci.dki_cname, RD_DRIVER_NAME); 5460Sstevel@tonic-gate rsp->rd_ci.dki_ctype = DKC_MD; 5470Sstevel@tonic-gate rsp->rd_ci.dki_flags = 0; 5480Sstevel@tonic-gate rsp->rd_ci.dki_cnum = 0; 5490Sstevel@tonic-gate rsp->rd_ci.dki_addr = 0; 5500Sstevel@tonic-gate rsp->rd_ci.dki_space = 0; 5510Sstevel@tonic-gate rsp->rd_ci.dki_prio = 0; 5520Sstevel@tonic-gate rsp->rd_ci.dki_vec = 0; 5530Sstevel@tonic-gate (void) strcpy(rsp->rd_ci.dki_dname, RD_DRIVER_NAME); 5540Sstevel@tonic-gate rsp->rd_ci.dki_unit = 0; 5550Sstevel@tonic-gate rsp->rd_ci.dki_slave = 0; 5560Sstevel@tonic-gate rsp->rd_ci.dki_partition = 0; 5570Sstevel@tonic-gate /* 5580Sstevel@tonic-gate * newfs uses this to set maxcontig. Must not be < 16, or it 5590Sstevel@tonic-gate * will be 0 when newfs multiplies it by DEV_BSIZE and divides 5600Sstevel@tonic-gate * it by the block size. Then tunefs doesn't work because 5610Sstevel@tonic-gate * maxcontig is 0. 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate rsp->rd_ci.dki_maxtransfer = 16; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * Deallocate resources (virtual and physical, device nodes, structures) 5680Sstevel@tonic-gate * from a ramdisk. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate static void 5710Sstevel@tonic-gate rd_dealloc_resources(rd_devstate_t *rsp) 5720Sstevel@tonic-gate { 5730Sstevel@tonic-gate dev_info_t *dip = rsp->rd_dip; 5740Sstevel@tonic-gate char namebuf[RD_NAME_LEN + 5]; 5750Sstevel@tonic-gate dev_t fulldev; 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if (rsp->rd_window_virt != NULL) { 5780Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 5790Sstevel@tonic-gate rd_unmap_window(rsp); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate vmem_free(heap_arena, rsp->rd_window_virt, rsp->rd_window_size); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate mutex_destroy(&rsp->rd_device_lock); 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate if (rsp->rd_existing) { 5860Sstevel@tonic-gate ddi_prop_free(rsp->rd_existing); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate if (rsp->rd_ppa != NULL) { 5890Sstevel@tonic-gate rd_phys_free(rsp->rd_ppa, rsp->rd_npages); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * Remove the block and raw device nodes. 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate if (dip == rd_dip) { 5960Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s", 5970Sstevel@tonic-gate rsp->rd_name); 5980Sstevel@tonic-gate ddi_remove_minor_node(dip, namebuf); 5990Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 6000Sstevel@tonic-gate rsp->rd_name); 6010Sstevel@tonic-gate ddi_remove_minor_node(dip, namebuf); 6020Sstevel@tonic-gate } else { 6030Sstevel@tonic-gate ddi_remove_minor_node(dip, "a"); 6040Sstevel@tonic-gate ddi_remove_minor_node(dip, "a,raw"); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * Remove the "Size" and "Nblocks" properties. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate fulldev = makedevice(ddi_driver_major(dip), rsp->rd_minor); 6110Sstevel@tonic-gate (void) ddi_prop_remove(fulldev, dip, SIZE_PROP_NAME); 6120Sstevel@tonic-gate (void) ddi_prop_remove(fulldev, dip, NBLOCKS_PROP_NAME); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (rsp->rd_kstat) { 6150Sstevel@tonic-gate kstat_delete(rsp->rd_kstat); 6160Sstevel@tonic-gate mutex_destroy(&rsp->rd_kstat_lock); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate ddi_soft_state_free(rd_statep, rsp->rd_minor); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate /* 6230Sstevel@tonic-gate * Allocate resources (virtual and physical, device nodes, structures) 6240Sstevel@tonic-gate * to a ramdisk. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate static rd_devstate_t * 6270Sstevel@tonic-gate rd_alloc_resources(char *name, size_t size, dev_info_t *dip) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate minor_t minor; 6300Sstevel@tonic-gate rd_devstate_t *rsp; 6310Sstevel@tonic-gate char namebuf[RD_NAME_LEN + 5]; 6320Sstevel@tonic-gate dev_t fulldev; 6330Sstevel@tonic-gate int64_t Nblocks_prop_val; 6340Sstevel@tonic-gate int64_t Size_prop_val; 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate minor = rd_find_free_minor(); 6370Sstevel@tonic-gate if (ddi_soft_state_zalloc(rd_statep, minor) == DDI_FAILURE) { 6380Sstevel@tonic-gate return (NULL); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate (void) strcpy(rsp->rd_name, name); 6430Sstevel@tonic-gate rsp->rd_dip = dip; 6440Sstevel@tonic-gate rsp->rd_minor = minor; 6450Sstevel@tonic-gate rsp->rd_size = size; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * Allocate virtual window onto ramdisk. 6490Sstevel@tonic-gate */ 6500Sstevel@tonic-gate mutex_init(&rsp->rd_device_lock, NULL, MUTEX_DRIVER, NULL); 6510Sstevel@tonic-gate rsp->rd_window_base = RD_WINDOW_NOT_MAPPED; 6520Sstevel@tonic-gate rsp->rd_window_size = PAGESIZE; 6530Sstevel@tonic-gate rsp->rd_window_virt = vmem_alloc(heap_arena, 6540Sstevel@tonic-gate rsp->rd_window_size, VM_SLEEP); 6550Sstevel@tonic-gate if (rsp->rd_window_virt == NULL) { 6560Sstevel@tonic-gate goto create_failed; 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate /* 6600Sstevel@tonic-gate * Allocate physical memory for non-OBP ramdisks. 6610Sstevel@tonic-gate * Create pseudo block and raw device nodes. 6620Sstevel@tonic-gate */ 6630Sstevel@tonic-gate if (dip == rd_dip) { 6640Sstevel@tonic-gate rsp->rd_npages = btopr(size); 6650Sstevel@tonic-gate rsp->rd_ppa = rd_phys_alloc(rsp->rd_npages); 6660Sstevel@tonic-gate if (rsp->rd_ppa == NULL) { 6670Sstevel@tonic-gate goto create_failed; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * For non-OBP ramdisks the device nodes are: 6720Sstevel@tonic-gate * 6730Sstevel@tonic-gate * /devices/pseudo/ramdisk@0:<diskname> 6740Sstevel@tonic-gate * /devices/pseudo/ramdisk@0:<diskname>,raw 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s", 6770Sstevel@tonic-gate rsp->rd_name); 6780Sstevel@tonic-gate if (ddi_create_minor_node(dip, namebuf, S_IFBLK, minor, 6790Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6800Sstevel@tonic-gate goto create_failed; 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 6830Sstevel@tonic-gate rsp->rd_name); 6840Sstevel@tonic-gate if (ddi_create_minor_node(dip, namebuf, S_IFCHR, minor, 6850Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6860Sstevel@tonic-gate goto create_failed; 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate } else { 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * For OBP-created ramdisks the device nodes are: 6910Sstevel@tonic-gate * 6920Sstevel@tonic-gate * /devices/ramdisk-<diskname>:a 6930Sstevel@tonic-gate * /devices/ramdisk-<diskname>:a,raw 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate if (ddi_create_minor_node(dip, "a", S_IFBLK, minor, 6960Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6970Sstevel@tonic-gate goto create_failed; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate if (ddi_create_minor_node(dip, "a,raw", S_IFCHR, minor, 7000Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 7010Sstevel@tonic-gate goto create_failed; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * Create the "Size" and "Nblocks" properties. 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate fulldev = makedevice(ddi_driver_major(dip), minor); 7090Sstevel@tonic-gate Size_prop_val = size; 7100Sstevel@tonic-gate if ((ddi_prop_update_int64(fulldev, dip, 7110Sstevel@tonic-gate SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) { 7120Sstevel@tonic-gate goto create_failed; 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate Nblocks_prop_val = size / DEV_BSIZE; 7150Sstevel@tonic-gate if ((ddi_prop_update_int64(fulldev, dip, 7160Sstevel@tonic-gate NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) { 7170Sstevel@tonic-gate goto create_failed; 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * Allocate kstat stuff. 7220Sstevel@tonic-gate */ 7230Sstevel@tonic-gate rsp->rd_kstat = kstat_create(RD_DRIVER_NAME, minor, NULL, 724*4363Sblakej "disk", KSTAT_TYPE_IO, 1, 0); 7250Sstevel@tonic-gate if (rsp->rd_kstat) { 7260Sstevel@tonic-gate mutex_init(&rsp->rd_kstat_lock, NULL, 7270Sstevel@tonic-gate MUTEX_DRIVER, NULL); 7280Sstevel@tonic-gate rsp->rd_kstat->ks_lock = &rsp->rd_kstat_lock; 7290Sstevel@tonic-gate kstat_install(rsp->rd_kstat); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate rd_fake_disk_geometry(rsp); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate return (rsp); 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate create_failed: 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Cleanup. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate rd_dealloc_resources(rsp); 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate return (NULL); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate /* 7460Sstevel@tonic-gate * Undo what we did in rd_attach, freeing resources and removing things which 7470Sstevel@tonic-gate * we installed. The system framework guarantees we are not active with this 7480Sstevel@tonic-gate * devinfo node in any other entry points at this time. 7490Sstevel@tonic-gate */ 7500Sstevel@tonic-gate static int 7510Sstevel@tonic-gate rd_common_detach(dev_info_t *dip) 7520Sstevel@tonic-gate { 7530Sstevel@tonic-gate if (dip == rd_dip) { 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * Pseudo node: can't detach if any pseudo ramdisks exist. 7560Sstevel@tonic-gate */ 7570Sstevel@tonic-gate if (rd_is_busy()) { 7580Sstevel@tonic-gate return (DDI_FAILURE); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate ddi_soft_state_free(rd_statep, RD_CTL_MINOR); 7610Sstevel@tonic-gate rd_dip = NULL; 7620Sstevel@tonic-gate } else { 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * A 'real' ramdisk; find the state and free resources. 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate rd_devstate_t *rsp; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if ((rsp = rd_find_dip_state(dip)) != NULL) { 7690Sstevel@tonic-gate rd_dealloc_resources(rsp); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate return (DDI_SUCCESS); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate static int 7780Sstevel@tonic-gate rd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate char *name; 7810Sstevel@tonic-gate rd_existing_t *ep = NULL; 7820Sstevel@tonic-gate uint_t nep, i; 7830Sstevel@tonic-gate size_t size = 0; 7840Sstevel@tonic-gate rd_devstate_t *rsp; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate switch (cmd) { 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate case DDI_ATTACH: 7890Sstevel@tonic-gate mutex_enter(&rd_lock); 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate /* 7920Sstevel@tonic-gate * For pseudo ramdisk devinfo set up state 0 and :ctl device; 7930Sstevel@tonic-gate * else it's an OBP-created ramdisk. 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate if (is_pseudo_device(dip)) { 7960Sstevel@tonic-gate rd_dip = dip; 7970Sstevel@tonic-gate rd_init_tuneables(); 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* 8000Sstevel@tonic-gate * The zeroth minor is reserved for the ramdisk 8010Sstevel@tonic-gate * 'control' device. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate if (ddi_soft_state_zalloc(rd_statep, RD_CTL_MINOR) == 8040Sstevel@tonic-gate DDI_FAILURE) { 8050Sstevel@tonic-gate goto attach_failed; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 8080Sstevel@tonic-gate rsp->rd_dip = dip; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate if (ddi_create_minor_node(dip, RD_CTL_NODE, 8110Sstevel@tonic-gate S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 8120Sstevel@tonic-gate goto attach_failed; 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate } else { 8150Sstevel@tonic-gate RD_STRIP_PREFIX(name, ddi_node_name(dip)); 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate if (strlen(name) > RD_NAME_LEN) { 8180Sstevel@tonic-gate cmn_err(CE_CONT, 8190Sstevel@tonic-gate "%s: name too long - ignoring\n", name); 8200Sstevel@tonic-gate goto attach_failed; 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * An OBP-created ramdisk must have an 'existing' 8250Sstevel@tonic-gate * property; get and check it. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 8280Sstevel@tonic-gate DDI_PROP_DONTPASS, RD_EXISTING_PROP_NAME, 8290Sstevel@tonic-gate (uchar_t **)&ep, &nep) != DDI_SUCCESS) { 8300Sstevel@tonic-gate cmn_err(CE_CONT, 8310Sstevel@tonic-gate "%s: " RD_EXISTING_PROP_NAME 8320Sstevel@tonic-gate " property missing\n", name); 8330Sstevel@tonic-gate goto attach_failed; 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate if (nep == 0 || (nep % sizeof (*ep)) != 0) { 8360Sstevel@tonic-gate cmn_err(CE_CONT, 8370Sstevel@tonic-gate "%s: " RD_EXISTING_PROP_NAME 8380Sstevel@tonic-gate " illegal size\n", name); 8390Sstevel@tonic-gate goto attach_failed; 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate nep /= sizeof (*ep); 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* 8440Sstevel@tonic-gate * Calculate the size of the ramdisk. 8450Sstevel@tonic-gate */ 8460Sstevel@tonic-gate for (i = 0; i < nep; ++i) { 8470Sstevel@tonic-gate size += ep[i].size; 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * Allocate driver resources for the ramdisk. 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate if ((rsp = rd_alloc_resources(name, size, 8540Sstevel@tonic-gate dip)) == NULL) { 8550Sstevel@tonic-gate goto attach_failed; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate rsp->rd_existing = ep; 8590Sstevel@tonic-gate rsp->rd_nexisting = nep; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate mutex_exit(&rd_lock); 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate ddi_report_dev(dip); 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate return (DDI_SUCCESS); 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate case DDI_RESUME: 8690Sstevel@tonic-gate return (DDI_SUCCESS); 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate default: 8720Sstevel@tonic-gate return (DDI_FAILURE); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate attach_failed: 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * Use our common detach routine to unallocate any stuff which 8780Sstevel@tonic-gate * was allocated above. 8790Sstevel@tonic-gate */ 8800Sstevel@tonic-gate (void) rd_common_detach(dip); 8810Sstevel@tonic-gate mutex_exit(&rd_lock); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate if (ep != NULL) { 8840Sstevel@tonic-gate ddi_prop_free(ep); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate return (DDI_FAILURE); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate static int 8900Sstevel@tonic-gate rd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate int e; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate switch (cmd) { 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate case DDI_DETACH: 8970Sstevel@tonic-gate mutex_enter(&rd_lock); 8980Sstevel@tonic-gate e = rd_common_detach(dip); 8990Sstevel@tonic-gate mutex_exit(&rd_lock); 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate return (e); 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate case DDI_SUSPEND: 9040Sstevel@tonic-gate return (DDI_SUCCESS); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate default: 9070Sstevel@tonic-gate return (DDI_FAILURE); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate /*ARGSUSED*/ 9120Sstevel@tonic-gate static int 9130Sstevel@tonic-gate rd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 9140Sstevel@tonic-gate { 9150Sstevel@tonic-gate rd_devstate_t *rsp; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate switch (infocmd) { 9180Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 9190Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, 9200Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 9210Sstevel@tonic-gate *result = rsp->rd_dip; 9220Sstevel@tonic-gate return (DDI_SUCCESS); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate *result = NULL; 9250Sstevel@tonic-gate return (DDI_FAILURE); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 9280Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, 9290Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 9300Sstevel@tonic-gate *result = (void *)(uintptr_t) 9310Sstevel@tonic-gate ddi_get_instance(rsp->rd_dip); 9320Sstevel@tonic-gate return (DDI_SUCCESS); 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate *result = NULL; 9350Sstevel@tonic-gate return (DDI_FAILURE); 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate default: 9380Sstevel@tonic-gate return (DDI_FAILURE); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /*ARGSUSED3*/ 9430Sstevel@tonic-gate static int 9440Sstevel@tonic-gate rd_open(dev_t *devp, int flag, int otyp, cred_t *credp) 9450Sstevel@tonic-gate { 9460Sstevel@tonic-gate minor_t minor; 9470Sstevel@tonic-gate rd_devstate_t *rsp; 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate mutex_enter(&rd_lock); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate minor = getminor(*devp); 9520Sstevel@tonic-gate if (minor == RD_CTL_MINOR) { 9530Sstevel@tonic-gate /* 9540Sstevel@tonic-gate * Master control device; must be opened exclusively. 9550Sstevel@tonic-gate */ 9560Sstevel@tonic-gate if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) { 9570Sstevel@tonic-gate mutex_exit(&rd_lock); 9580Sstevel@tonic-gate return (EINVAL); 9590Sstevel@tonic-gate } 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 9620Sstevel@tonic-gate if (rsp == NULL) { 9630Sstevel@tonic-gate mutex_exit(&rd_lock); 9640Sstevel@tonic-gate return (ENXIO); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if (rd_is_open(rsp)) { 9680Sstevel@tonic-gate mutex_exit(&rd_lock); 9690Sstevel@tonic-gate return (EBUSY); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate (void) rd_opened(rsp, OTYP_CHR); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate mutex_exit(&rd_lock); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate return (0); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 9790Sstevel@tonic-gate if (rsp == NULL) { 9800Sstevel@tonic-gate mutex_exit(&rd_lock); 9810Sstevel@tonic-gate return (ENXIO); 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate if (rd_opened(rsp, otyp) == -1) { 9850Sstevel@tonic-gate mutex_exit(&rd_lock); 9860Sstevel@tonic-gate return (EINVAL); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate mutex_exit(&rd_lock); 9900Sstevel@tonic-gate return (0); 9910Sstevel@tonic-gate } 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /*ARGSUSED*/ 9940Sstevel@tonic-gate static int 9950Sstevel@tonic-gate rd_close(dev_t dev, int flag, int otyp, struct cred *credp) 9960Sstevel@tonic-gate { 9970Sstevel@tonic-gate minor_t minor; 9980Sstevel@tonic-gate rd_devstate_t *rsp; 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate mutex_enter(&rd_lock); 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate minor = getminor(dev); 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 10050Sstevel@tonic-gate if (rsp == NULL) { 10060Sstevel@tonic-gate mutex_exit(&rd_lock); 10070Sstevel@tonic-gate return (EINVAL); 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate rd_closed(rsp, otyp); 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate mutex_exit(&rd_lock); 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate return (0); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate static void 10180Sstevel@tonic-gate rd_minphys(struct buf *bp) 10190Sstevel@tonic-gate { 10200Sstevel@tonic-gate if (bp->b_bcount > rd_maxphys) { 10210Sstevel@tonic-gate bp->b_bcount = rd_maxphys; 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate static void 10260Sstevel@tonic-gate rd_rw(rd_devstate_t *rsp, struct buf *bp, offset_t offset, size_t nbytes) 10270Sstevel@tonic-gate { 10280Sstevel@tonic-gate int reading = bp->b_flags & B_READ; 10290Sstevel@tonic-gate caddr_t buf_addr; 10300Sstevel@tonic-gate 10310Sstevel@tonic-gate bp_mapin(bp); 10320Sstevel@tonic-gate buf_addr = bp->b_un.b_addr; 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate while (nbytes > 0) { 10350Sstevel@tonic-gate offset_t off_in_window; 10360Sstevel@tonic-gate size_t rem_in_window, copy_bytes; 10370Sstevel@tonic-gate caddr_t raddr; 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate mutex_enter(&rsp->rd_device_lock); 10400Sstevel@tonic-gate rd_map_window(rsp, offset); 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate off_in_window = offset - rsp->rd_window_base; 10430Sstevel@tonic-gate rem_in_window = rsp->rd_window_size - off_in_window; 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate raddr = rsp->rd_window_virt + off_in_window; 10460Sstevel@tonic-gate copy_bytes = MIN(nbytes, rem_in_window); 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate if (reading) { 10490Sstevel@tonic-gate (void) bcopy(raddr, buf_addr, copy_bytes); 10500Sstevel@tonic-gate } else { 10510Sstevel@tonic-gate (void) bcopy(buf_addr, raddr, copy_bytes); 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate mutex_exit(&rsp->rd_device_lock); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate offset += copy_bytes; 10560Sstevel@tonic-gate buf_addr += copy_bytes; 10570Sstevel@tonic-gate nbytes -= copy_bytes; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate static int 10620Sstevel@tonic-gate rd_strategy(struct buf *bp) 10630Sstevel@tonic-gate { 10640Sstevel@tonic-gate rd_devstate_t *rsp; 10650Sstevel@tonic-gate offset_t offset; 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(bp->b_edev)); 10680Sstevel@tonic-gate offset = bp->b_blkno * DEV_BSIZE; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate if (rsp == NULL) { 10710Sstevel@tonic-gate bp->b_error = ENXIO; 10720Sstevel@tonic-gate bp->b_flags |= B_ERROR; 10730Sstevel@tonic-gate } else if (offset >= rsp->rd_size) { 10740Sstevel@tonic-gate bp->b_error = EINVAL; 10750Sstevel@tonic-gate bp->b_flags |= B_ERROR; 10760Sstevel@tonic-gate } else { 10770Sstevel@tonic-gate size_t nbytes; 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate if (rsp->rd_kstat) { 10800Sstevel@tonic-gate mutex_enter(rsp->rd_kstat->ks_lock); 10810Sstevel@tonic-gate kstat_runq_enter(KSTAT_IO_PTR(rsp->rd_kstat)); 10820Sstevel@tonic-gate mutex_exit(rsp->rd_kstat->ks_lock); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate nbytes = min(bp->b_bcount, rsp->rd_size - offset); 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate rd_rw(rsp, bp, offset, nbytes); 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate bp->b_resid = bp->b_bcount - nbytes; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate if (rsp->rd_kstat) { 10920Sstevel@tonic-gate kstat_io_t *kioptr; 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate mutex_enter(rsp->rd_kstat->ks_lock); 10950Sstevel@tonic-gate kioptr = KSTAT_IO_PTR(rsp->rd_kstat); 10960Sstevel@tonic-gate if (bp->b_flags & B_READ) { 10970Sstevel@tonic-gate kioptr->nread += nbytes; 10980Sstevel@tonic-gate kioptr->reads++; 10990Sstevel@tonic-gate } else { 11000Sstevel@tonic-gate kioptr->nwritten += nbytes; 11010Sstevel@tonic-gate kioptr->writes++; 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate kstat_runq_exit(kioptr); 11040Sstevel@tonic-gate mutex_exit(rsp->rd_kstat->ks_lock); 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate biodone(bp); 11090Sstevel@tonic-gate return (0); 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate /*ARGSUSED*/ 11130Sstevel@tonic-gate static int 11140Sstevel@tonic-gate rd_read(dev_t dev, struct uio *uiop, cred_t *credp) 11150Sstevel@tonic-gate { 11160Sstevel@tonic-gate rd_devstate_t *rsp; 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate if (uiop->uio_offset >= rsp->rd_size) 11210Sstevel@tonic-gate return (EINVAL); 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate return (physio(rd_strategy, NULL, dev, B_READ, rd_minphys, uiop)); 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate /*ARGSUSED*/ 11270Sstevel@tonic-gate static int 11280Sstevel@tonic-gate rd_write(dev_t dev, register struct uio *uiop, cred_t *credp) 11290Sstevel@tonic-gate { 11300Sstevel@tonic-gate rd_devstate_t *rsp; 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate if (uiop->uio_offset >= rsp->rd_size) 11350Sstevel@tonic-gate return (EINVAL); 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate return (physio(rd_strategy, NULL, dev, B_WRITE, rd_minphys, uiop)); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate /*ARGSUSED*/ 11410Sstevel@tonic-gate static int 11420Sstevel@tonic-gate rd_create_disk(dev_t dev, struct rd_ioctl *urip, int mode, int *rvalp) 11430Sstevel@tonic-gate { 11440Sstevel@tonic-gate struct rd_ioctl kri; 11450Sstevel@tonic-gate size_t size; 11460Sstevel@tonic-gate rd_devstate_t *rsp; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 11490Sstevel@tonic-gate return (EFAULT); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate kri.ri_name[RD_NAME_LEN] = '\0'; 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate size = kri.ri_size; 11550Sstevel@tonic-gate if (size == 0) { 11560Sstevel@tonic-gate return (EINVAL); 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate size = ptob(btopr(size)); 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate mutex_enter(&rd_lock); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate if (rd_find_named_disk(kri.ri_name) != NULL) { 11630Sstevel@tonic-gate mutex_exit(&rd_lock); 11640Sstevel@tonic-gate return (EEXIST); 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate rsp = rd_alloc_resources(kri.ri_name, size, rd_dip); 11680Sstevel@tonic-gate if (rsp == NULL) { 11690Sstevel@tonic-gate mutex_exit(&rd_lock); 11700Sstevel@tonic-gate return (EAGAIN); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate mutex_exit(&rd_lock); 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate return (ddi_copyout(&kri, urip, sizeof (kri), mode) == -1 ? EFAULT : 0); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate /*ARGSUSED*/ 11790Sstevel@tonic-gate static int 11800Sstevel@tonic-gate rd_delete_disk(dev_t dev, struct rd_ioctl *urip, int mode) 11810Sstevel@tonic-gate { 11820Sstevel@tonic-gate struct rd_ioctl kri; 11830Sstevel@tonic-gate rd_devstate_t *rsp; 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 11860Sstevel@tonic-gate return (EFAULT); 11870Sstevel@tonic-gate } 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate kri.ri_name[RD_NAME_LEN] = '\0'; 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate mutex_enter(&rd_lock); 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate rsp = rd_find_named_disk(kri.ri_name); 11940Sstevel@tonic-gate if (rsp == NULL || rsp->rd_dip != rd_dip) { 11950Sstevel@tonic-gate mutex_exit(&rd_lock); 11960Sstevel@tonic-gate return (EINVAL); 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate if (rd_is_open(rsp)) { 11990Sstevel@tonic-gate mutex_exit(&rd_lock); 12000Sstevel@tonic-gate return (EBUSY); 12010Sstevel@tonic-gate } 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate rd_dealloc_resources(rsp); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate mutex_exit(&rd_lock); 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate return (0); 12080Sstevel@tonic-gate } 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate /*ARGSUSED*/ 12110Sstevel@tonic-gate static int 12120Sstevel@tonic-gate rd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 12130Sstevel@tonic-gate { 12140Sstevel@tonic-gate minor_t minor; 12150Sstevel@tonic-gate int error; 12160Sstevel@tonic-gate enum dkio_state dkstate; 12170Sstevel@tonic-gate rd_devstate_t *rsp; 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate minor = getminor(dev); 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate /* 12220Sstevel@tonic-gate * Ramdisk ioctls only apply to the master device. 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate if (minor == RD_CTL_MINOR) { 12250Sstevel@tonic-gate struct rd_ioctl *rip = (struct rd_ioctl *)arg; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* 12280Sstevel@tonic-gate * The query commands only need read-access - i.e., normal 12290Sstevel@tonic-gate * users are allowed to do those on the controlling device 12300Sstevel@tonic-gate * as long as they can open it read-only. 12310Sstevel@tonic-gate */ 12320Sstevel@tonic-gate switch (cmd) { 12330Sstevel@tonic-gate case RD_CREATE_DISK: 12340Sstevel@tonic-gate if ((mode & FWRITE) == 0) 12350Sstevel@tonic-gate return (EPERM); 12360Sstevel@tonic-gate return (rd_create_disk(dev, rip, mode, rvalp)); 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate case RD_DELETE_DISK: 12390Sstevel@tonic-gate if ((mode & FWRITE) == 0) 12400Sstevel@tonic-gate return (EPERM); 12410Sstevel@tonic-gate return (rd_delete_disk(dev, rip, mode)); 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate default: 12440Sstevel@tonic-gate return (EINVAL); 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 12490Sstevel@tonic-gate if (rsp == NULL) { 12500Sstevel@tonic-gate return (ENXIO); 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * These are for faking out utilities like newfs. 12550Sstevel@tonic-gate */ 12560Sstevel@tonic-gate switch (cmd) { 12570Sstevel@tonic-gate case DKIOCGVTOC: 12580Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12590Sstevel@tonic-gate case DDI_MODEL_ILP32: { 12600Sstevel@tonic-gate struct vtoc32 vtoc32; 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate vtoctovtoc32(rsp->rd_vtoc, vtoc32); 12630Sstevel@tonic-gate if (ddi_copyout(&vtoc32, (void *)arg, 12640Sstevel@tonic-gate sizeof (struct vtoc32), mode)) 12650Sstevel@tonic-gate return (EFAULT); 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate break; 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate case DDI_MODEL_NONE: 12700Sstevel@tonic-gate if (ddi_copyout(&rsp->rd_vtoc, (void *)arg, 12710Sstevel@tonic-gate sizeof (struct vtoc), mode)) 12720Sstevel@tonic-gate return (EFAULT); 12730Sstevel@tonic-gate break; 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate return (0); 12760Sstevel@tonic-gate case DKIOCINFO: 12770Sstevel@tonic-gate error = ddi_copyout(&rsp->rd_ci, (void *)arg, 12780Sstevel@tonic-gate sizeof (struct dk_cinfo), mode); 12790Sstevel@tonic-gate if (error) 12800Sstevel@tonic-gate return (EFAULT); 12810Sstevel@tonic-gate return (0); 12820Sstevel@tonic-gate case DKIOCG_VIRTGEOM: 12830Sstevel@tonic-gate case DKIOCG_PHYGEOM: 12840Sstevel@tonic-gate case DKIOCGGEOM: 12850Sstevel@tonic-gate error = ddi_copyout(&rsp->rd_dkg, (void *)arg, 12860Sstevel@tonic-gate sizeof (struct dk_geom), mode); 12870Sstevel@tonic-gate if (error) 12880Sstevel@tonic-gate return (EFAULT); 12890Sstevel@tonic-gate return (0); 12900Sstevel@tonic-gate case DKIOCSTATE: 12910Sstevel@tonic-gate /* the file is always there */ 12920Sstevel@tonic-gate dkstate = DKIO_INSERTED; 12930Sstevel@tonic-gate error = ddi_copyout(&dkstate, (void *)arg, 12940Sstevel@tonic-gate sizeof (enum dkio_state), mode); 12950Sstevel@tonic-gate if (error) 12960Sstevel@tonic-gate return (EFAULT); 12970Sstevel@tonic-gate return (0); 12980Sstevel@tonic-gate default: 12990Sstevel@tonic-gate return (ENOTTY); 13000Sstevel@tonic-gate } 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate static struct cb_ops rd_cb_ops = { 13050Sstevel@tonic-gate rd_open, 13060Sstevel@tonic-gate rd_close, 13070Sstevel@tonic-gate rd_strategy, 13080Sstevel@tonic-gate nodev, 13090Sstevel@tonic-gate nodev, /* dump */ 13100Sstevel@tonic-gate rd_read, 13110Sstevel@tonic-gate rd_write, 13120Sstevel@tonic-gate rd_ioctl, 13130Sstevel@tonic-gate nodev, /* devmap */ 13140Sstevel@tonic-gate nodev, /* mmap */ 13150Sstevel@tonic-gate nodev, /* segmap */ 13160Sstevel@tonic-gate nochpoll, /* poll */ 13170Sstevel@tonic-gate ddi_prop_op, 13180Sstevel@tonic-gate NULL, 13190Sstevel@tonic-gate D_NEW | D_MP 13200Sstevel@tonic-gate }; 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate static struct dev_ops rd_ops = { 13230Sstevel@tonic-gate DEVO_REV, 13240Sstevel@tonic-gate 0, 13250Sstevel@tonic-gate rd_getinfo, 13260Sstevel@tonic-gate nulldev, /* identify */ 13270Sstevel@tonic-gate nulldev, /* probe */ 13280Sstevel@tonic-gate rd_attach, 13290Sstevel@tonic-gate rd_detach, 13300Sstevel@tonic-gate nodev, /* reset */ 13310Sstevel@tonic-gate &rd_cb_ops, 13320Sstevel@tonic-gate (struct bus_ops *)0 13330Sstevel@tonic-gate }; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate extern struct mod_ops mod_driverops; 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate static struct modldrv modldrv = { 13390Sstevel@tonic-gate &mod_driverops, 13400Sstevel@tonic-gate "ramdisk driver v%I%", 13410Sstevel@tonic-gate &rd_ops 13420Sstevel@tonic-gate }; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate static struct modlinkage modlinkage = { 13450Sstevel@tonic-gate MODREV_1, 13460Sstevel@tonic-gate &modldrv, 13470Sstevel@tonic-gate 0 13480Sstevel@tonic-gate }; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate int 13510Sstevel@tonic-gate _init(void) 13520Sstevel@tonic-gate { 13530Sstevel@tonic-gate int e; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if ((e = ddi_soft_state_init(&rd_statep, 13560Sstevel@tonic-gate sizeof (rd_devstate_t), 0)) != 0) { 13570Sstevel@tonic-gate return (e); 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate mutex_init(&rd_lock, NULL, MUTEX_DRIVER, NULL); 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) { 13630Sstevel@tonic-gate mutex_destroy(&rd_lock); 13640Sstevel@tonic-gate ddi_soft_state_fini(&rd_statep); 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate return (e); 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate int 13710Sstevel@tonic-gate _fini(void) 13720Sstevel@tonic-gate { 13730Sstevel@tonic-gate int e; 13740Sstevel@tonic-gate 13750Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) { 13760Sstevel@tonic-gate return (e); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate ddi_soft_state_fini(&rd_statep); 13800Sstevel@tonic-gate mutex_destroy(&rd_lock); 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate return (e); 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate int 13860Sstevel@tonic-gate _info(struct modinfo *modinfop) 13870Sstevel@tonic-gate { 13880Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 13890Sstevel@tonic-gate } 1390