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 5*2912Sartem * Common Development and Distribution License (the "License"). 6*2912Sartem * 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*2912Sartem * Copyright 2006 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 /* 2910Sstevel@tonic-gate * Since availrmem is in pages (and is a long), this won't overflow. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate rd_max_physmem = (availrmem * rd_percent_physmem) / 100; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * Allocate enough physical pages to hold `size' bytes. 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 * This code stolen from the NCA driver. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate page_t ** 3040Sstevel@tonic-gate rd_phys_alloc(pgcnt_t npages) 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate page_t *pp, **ppa; 3070Sstevel@tonic-gate pgcnt_t i; 3080Sstevel@tonic-gate size_t ppalen = npages * sizeof (struct page_t *); 3090Sstevel@tonic-gate struct seg kseg; 3100Sstevel@tonic-gate char *addr; /* For the purposes of coloring */ 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate if (rd_tot_physmem + npages > rd_max_physmem) { 3130Sstevel@tonic-gate return (NULL); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate ppa = kmem_zalloc(ppalen, KM_SLEEP); 3160Sstevel@tonic-gate (void) page_resv(npages, KM_SLEEP); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate for (i = 0, addr = NULL; i < npages; ++i, addr += PAGESIZE) { 3190Sstevel@tonic-gate if (!page_create_wait(1, KM_SLEEP)) { 3200Sstevel@tonic-gate goto out; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate kseg.s_as = &kas; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate if ((pp = page_get_freelist(&kvp, 0, &kseg, addr, PAGESIZE, 3260Sstevel@tonic-gate KM_SLEEP, NULL)) == NULL) { 3270Sstevel@tonic-gate if ((pp = page_get_cachelist(&kvp, 0, &kseg, addr, 3280Sstevel@tonic-gate KM_SLEEP, NULL)) == NULL) { 3290Sstevel@tonic-gate goto out; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate if (PP_ISAGED(pp) == 0) { 3320Sstevel@tonic-gate page_hashout(pp, NULL); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate PP_CLRFREE(pp); 3370Sstevel@tonic-gate PP_CLRAGED(pp); 3380Sstevel@tonic-gate ppa[i] = pp; 3390Sstevel@tonic-gate page_downgrade(pp); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate rd_tot_physmem += npages; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate return (ppa); 3440Sstevel@tonic-gate out: 3450Sstevel@tonic-gate for (i = 0; ppa[i] != NULL && i < npages; ++i) { 3460Sstevel@tonic-gate page_free(ppa[i], 0); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate page_create_putback(i); 3500Sstevel@tonic-gate kmem_free(ppa, ppalen); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate page_unresv(npages); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate return (NULL); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * Free physical pages previously allocated via rd_phys_alloc(); note that 3590Sstevel@tonic-gate * this function may block as it has to wait until it can exclusively lock 3600Sstevel@tonic-gate * all the pages first. 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate static void 3630Sstevel@tonic-gate rd_phys_free(page_t **ppa, pgcnt_t npages) 3640Sstevel@tonic-gate { 3650Sstevel@tonic-gate pgcnt_t i; 3660Sstevel@tonic-gate size_t ppalen = npages * sizeof (struct page_t *); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate for (i = 0; i < npages; ++i) { 3690Sstevel@tonic-gate if (! page_tryupgrade(ppa[i])) { 3700Sstevel@tonic-gate page_unlock(ppa[i]); 3710Sstevel@tonic-gate while (! page_lock(ppa[i], SE_EXCL, NULL, P_RECLAIM)) 3720Sstevel@tonic-gate ; 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate page_free(ppa[i], 0); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate kmem_free(ppa, ppalen); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate page_unresv(npages); 3800Sstevel@tonic-gate rd_tot_physmem -= npages; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * Remove a window mapping (if present). 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate static void 3870Sstevel@tonic-gate rd_unmap_window(rd_devstate_t *rsp) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 3900Sstevel@tonic-gate hat_unload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 3910Sstevel@tonic-gate HAT_UNLOAD_UNLOCK); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * Map a portion of the ramdisk into the virtual window. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate static void 3990Sstevel@tonic-gate rd_map_window(rd_devstate_t *rsp, off_t offset) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate pgcnt_t offpgs = btop(offset); 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 4040Sstevel@tonic-gate /* 4050Sstevel@tonic-gate * Already mapped; is offset within our window? 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate if (offset >= rsp->rd_window_base && 4080Sstevel@tonic-gate offset < rsp->rd_window_base + rsp->rd_window_size) { 4090Sstevel@tonic-gate return; 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * No, we need to re-map; toss the old mapping. 4140Sstevel@tonic-gate */ 4150Sstevel@tonic-gate rd_unmap_window(rsp); 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate rsp->rd_window_base = ptob(offpgs); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * Different algorithms depending on whether this is a real 4210Sstevel@tonic-gate * OBP-created ramdisk, or a pseudo ramdisk. 4220Sstevel@tonic-gate */ 4230Sstevel@tonic-gate if (rsp->rd_dip == rd_dip) { 4240Sstevel@tonic-gate pgcnt_t pi, lastpi; 4250Sstevel@tonic-gate caddr_t vaddr; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * Find the range of pages which should be mapped. 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate pi = offpgs; 4310Sstevel@tonic-gate lastpi = pi + btopr(rsp->rd_window_size); 4320Sstevel@tonic-gate if (lastpi > rsp->rd_npages) { 4330Sstevel@tonic-gate lastpi = rsp->rd_npages; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * Load the mapping. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate vaddr = rsp->rd_window_virt; 4400Sstevel@tonic-gate for (; pi < lastpi; ++pi) { 4410Sstevel@tonic-gate hat_memload(kas.a_hat, vaddr, rsp->rd_ppa[pi], 4420Sstevel@tonic-gate (PROT_READ | PROT_WRITE) | HAT_NOSYNC, 4430Sstevel@tonic-gate HAT_LOAD_LOCK); 4440Sstevel@tonic-gate vaddr += ptob(1); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate } else { 4470Sstevel@tonic-gate uint_t i; 4480Sstevel@tonic-gate pfn_t pfn; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Real OBP-created ramdisk: locate the physical range which 4520Sstevel@tonic-gate * contains this offset. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate for (i = 0; i < rsp->rd_nexisting; ++i) { 4550Sstevel@tonic-gate if (offset < rsp->rd_existing[i].size) { 4560Sstevel@tonic-gate break; 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate offset -= rsp->rd_existing[i].size; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate ASSERT(i < rsp->rd_nexisting); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * Load the mapping. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate pfn = btop(rsp->rd_existing[i].phys + offset); 4660Sstevel@tonic-gate hat_devload(kas.a_hat, rsp->rd_window_virt, rsp->rd_window_size, 4670Sstevel@tonic-gate pfn, (PROT_READ | PROT_WRITE), 4680Sstevel@tonic-gate HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * Fakes up a disk geometry, and one big partition, based on the size 4740Sstevel@tonic-gate * of the file. This is needed because we allow newfs'ing the device, 4750Sstevel@tonic-gate * and newfs will do several disk ioctls to figure out the geometry and 4760Sstevel@tonic-gate * partition information. It uses that information to determine the parameters 4770Sstevel@tonic-gate * to pass to mkfs. Geometry is pretty much irrelevent these days, but we 4780Sstevel@tonic-gate * have to support it. 4790Sstevel@tonic-gate * 4800Sstevel@tonic-gate * Stolen from lofi.c - should maybe split out common code sometime. 4810Sstevel@tonic-gate */ 4820Sstevel@tonic-gate static void 4830Sstevel@tonic-gate rd_fake_disk_geometry(rd_devstate_t *rsp) 4840Sstevel@tonic-gate { 4850Sstevel@tonic-gate /* dk_geom - see dkio(7I) */ 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * dkg_ncyl _could_ be set to one here (one big cylinder with gobs 4880Sstevel@tonic-gate * of sectors), but that breaks programs like fdisk which want to 4890Sstevel@tonic-gate * partition a disk by cylinder. With one cylinder, you can't create 4900Sstevel@tonic-gate * an fdisk partition and put pcfs on it for testing (hard to pick 4910Sstevel@tonic-gate * a number between one and one). 4920Sstevel@tonic-gate * 4930Sstevel@tonic-gate * The cheezy floppy test is an attempt to not have too few cylinders 4940Sstevel@tonic-gate * for a small file, or so many on a big file that you waste space 4950Sstevel@tonic-gate * for backup superblocks or cylinder group structures. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate if (rsp->rd_size < (2 * 1024 * 1024)) /* floppy? */ 4980Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (100 * 1024); 4990Sstevel@tonic-gate else 5000Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = rsp->rd_size / (300 * 1024); 5010Sstevel@tonic-gate /* in case file file is < 100k */ 5020Sstevel@tonic-gate if (rsp->rd_dkg.dkg_ncyl == 0) 5030Sstevel@tonic-gate rsp->rd_dkg.dkg_ncyl = 1; 5040Sstevel@tonic-gate rsp->rd_dkg.dkg_acyl = 0; 5050Sstevel@tonic-gate rsp->rd_dkg.dkg_bcyl = 0; 5060Sstevel@tonic-gate rsp->rd_dkg.dkg_nhead = 1; 5070Sstevel@tonic-gate rsp->rd_dkg.dkg_obs1 = 0; 5080Sstevel@tonic-gate rsp->rd_dkg.dkg_intrlv = 0; 5090Sstevel@tonic-gate rsp->rd_dkg.dkg_obs2 = 0; 5100Sstevel@tonic-gate rsp->rd_dkg.dkg_obs3 = 0; 5110Sstevel@tonic-gate rsp->rd_dkg.dkg_apc = 0; 5120Sstevel@tonic-gate rsp->rd_dkg.dkg_rpm = 7200; 5130Sstevel@tonic-gate rsp->rd_dkg.dkg_pcyl = rsp->rd_dkg.dkg_ncyl + rsp->rd_dkg.dkg_acyl; 5140Sstevel@tonic-gate rsp->rd_dkg.dkg_nsect = rsp->rd_size / 5150Sstevel@tonic-gate (DEV_BSIZE * rsp->rd_dkg.dkg_ncyl); 5160Sstevel@tonic-gate rsp->rd_dkg.dkg_write_reinstruct = 0; 5170Sstevel@tonic-gate rsp->rd_dkg.dkg_read_reinstruct = 0; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate /* vtoc - see dkio(7I) */ 5200Sstevel@tonic-gate bzero(&rsp->rd_vtoc, sizeof (struct vtoc)); 5210Sstevel@tonic-gate rsp->rd_vtoc.v_sanity = VTOC_SANE; 5220Sstevel@tonic-gate rsp->rd_vtoc.v_version = V_VERSION; 5230Sstevel@tonic-gate bcopy(RD_DRIVER_NAME, rsp->rd_vtoc.v_volume, 7); 5240Sstevel@tonic-gate rsp->rd_vtoc.v_sectorsz = DEV_BSIZE; 5250Sstevel@tonic-gate rsp->rd_vtoc.v_nparts = 1; 5260Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_tag = V_UNASSIGNED; 5270Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_flag = V_UNMNT; 5280Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_start = (daddr_t)0; 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * The partition size cannot just be the number of sectors, because 5310Sstevel@tonic-gate * that might not end on a cylinder boundary. And if that's the case, 5320Sstevel@tonic-gate * newfs/mkfs will print a scary warning. So just figure the size 5330Sstevel@tonic-gate * based on the number of cylinders and sectors/cylinder. 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate rsp->rd_vtoc.v_part[0].p_size = rsp->rd_dkg.dkg_pcyl * 5360Sstevel@tonic-gate rsp->rd_dkg.dkg_nsect * rsp->rd_dkg.dkg_nhead; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* dk_cinfo - see dkio(7I) */ 5390Sstevel@tonic-gate bzero(&rsp->rd_ci, sizeof (struct dk_cinfo)); 5400Sstevel@tonic-gate (void) strcpy(rsp->rd_ci.dki_cname, RD_DRIVER_NAME); 5410Sstevel@tonic-gate rsp->rd_ci.dki_ctype = DKC_MD; 5420Sstevel@tonic-gate rsp->rd_ci.dki_flags = 0; 5430Sstevel@tonic-gate rsp->rd_ci.dki_cnum = 0; 5440Sstevel@tonic-gate rsp->rd_ci.dki_addr = 0; 5450Sstevel@tonic-gate rsp->rd_ci.dki_space = 0; 5460Sstevel@tonic-gate rsp->rd_ci.dki_prio = 0; 5470Sstevel@tonic-gate rsp->rd_ci.dki_vec = 0; 5480Sstevel@tonic-gate (void) strcpy(rsp->rd_ci.dki_dname, RD_DRIVER_NAME); 5490Sstevel@tonic-gate rsp->rd_ci.dki_unit = 0; 5500Sstevel@tonic-gate rsp->rd_ci.dki_slave = 0; 5510Sstevel@tonic-gate rsp->rd_ci.dki_partition = 0; 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * newfs uses this to set maxcontig. Must not be < 16, or it 5540Sstevel@tonic-gate * will be 0 when newfs multiplies it by DEV_BSIZE and divides 5550Sstevel@tonic-gate * it by the block size. Then tunefs doesn't work because 5560Sstevel@tonic-gate * maxcontig is 0. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate rsp->rd_ci.dki_maxtransfer = 16; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate /* 5620Sstevel@tonic-gate * Deallocate resources (virtual and physical, device nodes, structures) 5630Sstevel@tonic-gate * from a ramdisk. 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate static void 5660Sstevel@tonic-gate rd_dealloc_resources(rd_devstate_t *rsp) 5670Sstevel@tonic-gate { 5680Sstevel@tonic-gate dev_info_t *dip = rsp->rd_dip; 5690Sstevel@tonic-gate char namebuf[RD_NAME_LEN + 5]; 5700Sstevel@tonic-gate dev_t fulldev; 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if (rsp->rd_window_virt != NULL) { 5730Sstevel@tonic-gate if (rsp->rd_window_base != RD_WINDOW_NOT_MAPPED) { 5740Sstevel@tonic-gate rd_unmap_window(rsp); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate vmem_free(heap_arena, rsp->rd_window_virt, rsp->rd_window_size); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate mutex_destroy(&rsp->rd_device_lock); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (rsp->rd_existing) { 5810Sstevel@tonic-gate ddi_prop_free(rsp->rd_existing); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate if (rsp->rd_ppa != NULL) { 5840Sstevel@tonic-gate rd_phys_free(rsp->rd_ppa, rsp->rd_npages); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * Remove the block and raw device nodes. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate if (dip == rd_dip) { 5910Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s", 5920Sstevel@tonic-gate rsp->rd_name); 5930Sstevel@tonic-gate ddi_remove_minor_node(dip, namebuf); 5940Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 5950Sstevel@tonic-gate rsp->rd_name); 5960Sstevel@tonic-gate ddi_remove_minor_node(dip, namebuf); 5970Sstevel@tonic-gate } else { 5980Sstevel@tonic-gate ddi_remove_minor_node(dip, "a"); 5990Sstevel@tonic-gate ddi_remove_minor_node(dip, "a,raw"); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* 6030Sstevel@tonic-gate * Remove the "Size" and "Nblocks" properties. 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate fulldev = makedevice(ddi_driver_major(dip), rsp->rd_minor); 6060Sstevel@tonic-gate (void) ddi_prop_remove(fulldev, dip, SIZE_PROP_NAME); 6070Sstevel@tonic-gate (void) ddi_prop_remove(fulldev, dip, NBLOCKS_PROP_NAME); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate if (rsp->rd_kstat) { 6100Sstevel@tonic-gate kstat_delete(rsp->rd_kstat); 6110Sstevel@tonic-gate mutex_destroy(&rsp->rd_kstat_lock); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate ddi_soft_state_free(rd_statep, rsp->rd_minor); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * Allocate resources (virtual and physical, device nodes, structures) 6190Sstevel@tonic-gate * to a ramdisk. 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate static rd_devstate_t * 6220Sstevel@tonic-gate rd_alloc_resources(char *name, size_t size, dev_info_t *dip) 6230Sstevel@tonic-gate { 6240Sstevel@tonic-gate minor_t minor; 6250Sstevel@tonic-gate rd_devstate_t *rsp; 6260Sstevel@tonic-gate char namebuf[RD_NAME_LEN + 5]; 6270Sstevel@tonic-gate dev_t fulldev; 6280Sstevel@tonic-gate int64_t Nblocks_prop_val; 6290Sstevel@tonic-gate int64_t Size_prop_val; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate minor = rd_find_free_minor(); 6320Sstevel@tonic-gate if (ddi_soft_state_zalloc(rd_statep, minor) == DDI_FAILURE) { 6330Sstevel@tonic-gate return (NULL); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate (void) strcpy(rsp->rd_name, name); 6380Sstevel@tonic-gate rsp->rd_dip = dip; 6390Sstevel@tonic-gate rsp->rd_minor = minor; 6400Sstevel@tonic-gate rsp->rd_size = size; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * Allocate virtual window onto ramdisk. 6440Sstevel@tonic-gate */ 6450Sstevel@tonic-gate mutex_init(&rsp->rd_device_lock, NULL, MUTEX_DRIVER, NULL); 6460Sstevel@tonic-gate rsp->rd_window_base = RD_WINDOW_NOT_MAPPED; 6470Sstevel@tonic-gate rsp->rd_window_size = PAGESIZE; 6480Sstevel@tonic-gate rsp->rd_window_virt = vmem_alloc(heap_arena, 6490Sstevel@tonic-gate rsp->rd_window_size, VM_SLEEP); 6500Sstevel@tonic-gate if (rsp->rd_window_virt == NULL) { 6510Sstevel@tonic-gate goto create_failed; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * Allocate physical memory for non-OBP ramdisks. 6560Sstevel@tonic-gate * Create pseudo block and raw device nodes. 6570Sstevel@tonic-gate */ 6580Sstevel@tonic-gate if (dip == rd_dip) { 6590Sstevel@tonic-gate rsp->rd_npages = btopr(size); 6600Sstevel@tonic-gate rsp->rd_ppa = rd_phys_alloc(rsp->rd_npages); 6610Sstevel@tonic-gate if (rsp->rd_ppa == NULL) { 6620Sstevel@tonic-gate goto create_failed; 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * For non-OBP ramdisks the device nodes are: 6670Sstevel@tonic-gate * 6680Sstevel@tonic-gate * /devices/pseudo/ramdisk@0:<diskname> 6690Sstevel@tonic-gate * /devices/pseudo/ramdisk@0:<diskname>,raw 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s", 6720Sstevel@tonic-gate rsp->rd_name); 6730Sstevel@tonic-gate if (ddi_create_minor_node(dip, namebuf, S_IFBLK, minor, 6740Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6750Sstevel@tonic-gate goto create_failed; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s,raw", 6780Sstevel@tonic-gate rsp->rd_name); 6790Sstevel@tonic-gate if (ddi_create_minor_node(dip, namebuf, S_IFCHR, minor, 6800Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6810Sstevel@tonic-gate goto create_failed; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate } else { 6840Sstevel@tonic-gate /* 6850Sstevel@tonic-gate * For OBP-created ramdisks the device nodes are: 6860Sstevel@tonic-gate * 6870Sstevel@tonic-gate * /devices/ramdisk-<diskname>:a 6880Sstevel@tonic-gate * /devices/ramdisk-<diskname>:a,raw 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate if (ddi_create_minor_node(dip, "a", S_IFBLK, minor, 6910Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6920Sstevel@tonic-gate goto create_failed; 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate if (ddi_create_minor_node(dip, "a,raw", S_IFCHR, minor, 6950Sstevel@tonic-gate DDI_PSEUDO, 0) == DDI_FAILURE) { 6960Sstevel@tonic-gate goto create_failed; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Create the "Size" and "Nblocks" properties. 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate fulldev = makedevice(ddi_driver_major(dip), minor); 7040Sstevel@tonic-gate Size_prop_val = size; 7050Sstevel@tonic-gate if ((ddi_prop_update_int64(fulldev, dip, 7060Sstevel@tonic-gate SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) { 7070Sstevel@tonic-gate goto create_failed; 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate Nblocks_prop_val = size / DEV_BSIZE; 7100Sstevel@tonic-gate if ((ddi_prop_update_int64(fulldev, dip, 7110Sstevel@tonic-gate NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) { 7120Sstevel@tonic-gate goto create_failed; 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * Allocate kstat stuff. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate rsp->rd_kstat = kstat_create(RD_DRIVER_NAME, minor, NULL, 7190Sstevel@tonic-gate "disk", KSTAT_TYPE_IO, 1, 0); 7200Sstevel@tonic-gate if (rsp->rd_kstat) { 7210Sstevel@tonic-gate mutex_init(&rsp->rd_kstat_lock, NULL, 7220Sstevel@tonic-gate MUTEX_DRIVER, NULL); 7230Sstevel@tonic-gate rsp->rd_kstat->ks_lock = &rsp->rd_kstat_lock; 7240Sstevel@tonic-gate kstat_install(rsp->rd_kstat); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate rd_fake_disk_geometry(rsp); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate return (rsp); 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate create_failed: 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Cleanup. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate rd_dealloc_resources(rsp); 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate return (NULL); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * Undo what we did in rd_attach, freeing resources and removing things which 7420Sstevel@tonic-gate * we installed. The system framework guarantees we are not active with this 7430Sstevel@tonic-gate * devinfo node in any other entry points at this time. 7440Sstevel@tonic-gate */ 7450Sstevel@tonic-gate static int 7460Sstevel@tonic-gate rd_common_detach(dev_info_t *dip) 7470Sstevel@tonic-gate { 7480Sstevel@tonic-gate if (dip == rd_dip) { 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Pseudo node: can't detach if any pseudo ramdisks exist. 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate if (rd_is_busy()) { 7530Sstevel@tonic-gate return (DDI_FAILURE); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate ddi_soft_state_free(rd_statep, RD_CTL_MINOR); 7560Sstevel@tonic-gate rd_dip = NULL; 7570Sstevel@tonic-gate } else { 7580Sstevel@tonic-gate /* 7590Sstevel@tonic-gate * A 'real' ramdisk; find the state and free resources. 7600Sstevel@tonic-gate */ 7610Sstevel@tonic-gate rd_devstate_t *rsp; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if ((rsp = rd_find_dip_state(dip)) != NULL) { 7640Sstevel@tonic-gate rd_dealloc_resources(rsp); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate return (DDI_SUCCESS); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate static int 7730Sstevel@tonic-gate rd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7740Sstevel@tonic-gate { 7750Sstevel@tonic-gate char *name; 7760Sstevel@tonic-gate rd_existing_t *ep = NULL; 7770Sstevel@tonic-gate uint_t nep, i; 7780Sstevel@tonic-gate size_t size = 0; 7790Sstevel@tonic-gate rd_devstate_t *rsp; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate switch (cmd) { 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate case DDI_ATTACH: 7840Sstevel@tonic-gate mutex_enter(&rd_lock); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate /* 7870Sstevel@tonic-gate * For pseudo ramdisk devinfo set up state 0 and :ctl device; 7880Sstevel@tonic-gate * else it's an OBP-created ramdisk. 7890Sstevel@tonic-gate */ 7900Sstevel@tonic-gate if (is_pseudo_device(dip)) { 7910Sstevel@tonic-gate rd_dip = dip; 7920Sstevel@tonic-gate rd_init_tuneables(); 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate /* 7950Sstevel@tonic-gate * The zeroth minor is reserved for the ramdisk 7960Sstevel@tonic-gate * 'control' device. 7970Sstevel@tonic-gate */ 7980Sstevel@tonic-gate if (ddi_soft_state_zalloc(rd_statep, RD_CTL_MINOR) == 7990Sstevel@tonic-gate DDI_FAILURE) { 8000Sstevel@tonic-gate goto attach_failed; 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 8030Sstevel@tonic-gate rsp->rd_dip = dip; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate if (ddi_create_minor_node(dip, RD_CTL_NODE, 8060Sstevel@tonic-gate S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 8070Sstevel@tonic-gate goto attach_failed; 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate } else { 8100Sstevel@tonic-gate RD_STRIP_PREFIX(name, ddi_node_name(dip)); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if (strlen(name) > RD_NAME_LEN) { 8130Sstevel@tonic-gate cmn_err(CE_CONT, 8140Sstevel@tonic-gate "%s: name too long - ignoring\n", name); 8150Sstevel@tonic-gate goto attach_failed; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate /* 8190Sstevel@tonic-gate * An OBP-created ramdisk must have an 'existing' 8200Sstevel@tonic-gate * property; get and check it. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 8230Sstevel@tonic-gate DDI_PROP_DONTPASS, RD_EXISTING_PROP_NAME, 8240Sstevel@tonic-gate (uchar_t **)&ep, &nep) != DDI_SUCCESS) { 8250Sstevel@tonic-gate cmn_err(CE_CONT, 8260Sstevel@tonic-gate "%s: " RD_EXISTING_PROP_NAME 8270Sstevel@tonic-gate " property missing\n", name); 8280Sstevel@tonic-gate goto attach_failed; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate if (nep == 0 || (nep % sizeof (*ep)) != 0) { 8310Sstevel@tonic-gate cmn_err(CE_CONT, 8320Sstevel@tonic-gate "%s: " RD_EXISTING_PROP_NAME 8330Sstevel@tonic-gate " illegal size\n", name); 8340Sstevel@tonic-gate goto attach_failed; 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate nep /= sizeof (*ep); 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * Calculate the size of the ramdisk. 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate for (i = 0; i < nep; ++i) { 8420Sstevel@tonic-gate size += ep[i].size; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate /* 8460Sstevel@tonic-gate * Allocate driver resources for the ramdisk. 8470Sstevel@tonic-gate */ 8480Sstevel@tonic-gate if ((rsp = rd_alloc_resources(name, size, 8490Sstevel@tonic-gate dip)) == NULL) { 8500Sstevel@tonic-gate goto attach_failed; 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate rsp->rd_existing = ep; 8540Sstevel@tonic-gate rsp->rd_nexisting = nep; 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate mutex_exit(&rd_lock); 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate ddi_report_dev(dip); 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate return (DDI_SUCCESS); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate case DDI_RESUME: 8640Sstevel@tonic-gate return (DDI_SUCCESS); 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate default: 8670Sstevel@tonic-gate return (DDI_FAILURE); 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate attach_failed: 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * Use our common detach routine to unallocate any stuff which 8730Sstevel@tonic-gate * was allocated above. 8740Sstevel@tonic-gate */ 8750Sstevel@tonic-gate (void) rd_common_detach(dip); 8760Sstevel@tonic-gate mutex_exit(&rd_lock); 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate if (ep != NULL) { 8790Sstevel@tonic-gate ddi_prop_free(ep); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate return (DDI_FAILURE); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate static int 8850Sstevel@tonic-gate rd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 8860Sstevel@tonic-gate { 8870Sstevel@tonic-gate int e; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate switch (cmd) { 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate case DDI_DETACH: 8920Sstevel@tonic-gate mutex_enter(&rd_lock); 8930Sstevel@tonic-gate e = rd_common_detach(dip); 8940Sstevel@tonic-gate mutex_exit(&rd_lock); 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate return (e); 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate case DDI_SUSPEND: 8990Sstevel@tonic-gate return (DDI_SUCCESS); 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate default: 9020Sstevel@tonic-gate return (DDI_FAILURE); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /*ARGSUSED*/ 9070Sstevel@tonic-gate static int 9080Sstevel@tonic-gate rd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 9090Sstevel@tonic-gate { 9100Sstevel@tonic-gate rd_devstate_t *rsp; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate switch (infocmd) { 9130Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 9140Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, 9150Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 9160Sstevel@tonic-gate *result = rsp->rd_dip; 9170Sstevel@tonic-gate return (DDI_SUCCESS); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate *result = NULL; 9200Sstevel@tonic-gate return (DDI_FAILURE); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 9230Sstevel@tonic-gate if ((rsp = ddi_get_soft_state(rd_statep, 9240Sstevel@tonic-gate getminor((dev_t)arg))) != NULL) { 9250Sstevel@tonic-gate *result = (void *)(uintptr_t) 9260Sstevel@tonic-gate ddi_get_instance(rsp->rd_dip); 9270Sstevel@tonic-gate return (DDI_SUCCESS); 9280Sstevel@tonic-gate } 9290Sstevel@tonic-gate *result = NULL; 9300Sstevel@tonic-gate return (DDI_FAILURE); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate default: 9330Sstevel@tonic-gate return (DDI_FAILURE); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate /*ARGSUSED3*/ 9380Sstevel@tonic-gate static int 9390Sstevel@tonic-gate rd_open(dev_t *devp, int flag, int otyp, cred_t *credp) 9400Sstevel@tonic-gate { 9410Sstevel@tonic-gate minor_t minor; 9420Sstevel@tonic-gate rd_devstate_t *rsp; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate mutex_enter(&rd_lock); 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate minor = getminor(*devp); 9470Sstevel@tonic-gate if (minor == RD_CTL_MINOR) { 9480Sstevel@tonic-gate /* 9490Sstevel@tonic-gate * Master control device; must be opened exclusively. 9500Sstevel@tonic-gate */ 9510Sstevel@tonic-gate if ((flag & FEXCL) != FEXCL || otyp != OTYP_CHR) { 9520Sstevel@tonic-gate mutex_exit(&rd_lock); 9530Sstevel@tonic-gate return (EINVAL); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, RD_CTL_MINOR); 9570Sstevel@tonic-gate if (rsp == NULL) { 9580Sstevel@tonic-gate mutex_exit(&rd_lock); 9590Sstevel@tonic-gate return (ENXIO); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate if (rd_is_open(rsp)) { 9630Sstevel@tonic-gate mutex_exit(&rd_lock); 9640Sstevel@tonic-gate return (EBUSY); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate (void) rd_opened(rsp, OTYP_CHR); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate mutex_exit(&rd_lock); 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate return (0); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 9740Sstevel@tonic-gate if (rsp == NULL) { 9750Sstevel@tonic-gate mutex_exit(&rd_lock); 9760Sstevel@tonic-gate return (ENXIO); 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate if (rd_opened(rsp, otyp) == -1) { 9800Sstevel@tonic-gate mutex_exit(&rd_lock); 9810Sstevel@tonic-gate return (EINVAL); 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate mutex_exit(&rd_lock); 9850Sstevel@tonic-gate return (0); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /*ARGSUSED*/ 9890Sstevel@tonic-gate static int 9900Sstevel@tonic-gate rd_close(dev_t dev, int flag, int otyp, struct cred *credp) 9910Sstevel@tonic-gate { 9920Sstevel@tonic-gate minor_t minor; 9930Sstevel@tonic-gate rd_devstate_t *rsp; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate mutex_enter(&rd_lock); 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate minor = getminor(dev); 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 10000Sstevel@tonic-gate if (rsp == NULL) { 10010Sstevel@tonic-gate mutex_exit(&rd_lock); 10020Sstevel@tonic-gate return (EINVAL); 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate rd_closed(rsp, otyp); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate mutex_exit(&rd_lock); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate return (0); 10100Sstevel@tonic-gate } 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate static void 10130Sstevel@tonic-gate rd_minphys(struct buf *bp) 10140Sstevel@tonic-gate { 10150Sstevel@tonic-gate if (bp->b_bcount > rd_maxphys) { 10160Sstevel@tonic-gate bp->b_bcount = rd_maxphys; 10170Sstevel@tonic-gate } 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate static void 10210Sstevel@tonic-gate rd_rw(rd_devstate_t *rsp, struct buf *bp, offset_t offset, size_t nbytes) 10220Sstevel@tonic-gate { 10230Sstevel@tonic-gate int reading = bp->b_flags & B_READ; 10240Sstevel@tonic-gate caddr_t buf_addr; 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate bp_mapin(bp); 10270Sstevel@tonic-gate buf_addr = bp->b_un.b_addr; 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate while (nbytes > 0) { 10300Sstevel@tonic-gate offset_t off_in_window; 10310Sstevel@tonic-gate size_t rem_in_window, copy_bytes; 10320Sstevel@tonic-gate caddr_t raddr; 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate mutex_enter(&rsp->rd_device_lock); 10350Sstevel@tonic-gate rd_map_window(rsp, offset); 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate off_in_window = offset - rsp->rd_window_base; 10380Sstevel@tonic-gate rem_in_window = rsp->rd_window_size - off_in_window; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate raddr = rsp->rd_window_virt + off_in_window; 10410Sstevel@tonic-gate copy_bytes = MIN(nbytes, rem_in_window); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate if (reading) { 10440Sstevel@tonic-gate (void) bcopy(raddr, buf_addr, copy_bytes); 10450Sstevel@tonic-gate } else { 10460Sstevel@tonic-gate (void) bcopy(buf_addr, raddr, copy_bytes); 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate mutex_exit(&rsp->rd_device_lock); 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate offset += copy_bytes; 10510Sstevel@tonic-gate buf_addr += copy_bytes; 10520Sstevel@tonic-gate nbytes -= copy_bytes; 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate static int 10570Sstevel@tonic-gate rd_strategy(struct buf *bp) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate rd_devstate_t *rsp; 10600Sstevel@tonic-gate offset_t offset; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(bp->b_edev)); 10630Sstevel@tonic-gate offset = bp->b_blkno * DEV_BSIZE; 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate if (rsp == NULL) { 10660Sstevel@tonic-gate bp->b_error = ENXIO; 10670Sstevel@tonic-gate bp->b_flags |= B_ERROR; 10680Sstevel@tonic-gate } else if (offset >= rsp->rd_size) { 10690Sstevel@tonic-gate bp->b_error = EINVAL; 10700Sstevel@tonic-gate bp->b_flags |= B_ERROR; 10710Sstevel@tonic-gate } else { 10720Sstevel@tonic-gate size_t nbytes; 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate if (rsp->rd_kstat) { 10750Sstevel@tonic-gate mutex_enter(rsp->rd_kstat->ks_lock); 10760Sstevel@tonic-gate kstat_runq_enter(KSTAT_IO_PTR(rsp->rd_kstat)); 10770Sstevel@tonic-gate mutex_exit(rsp->rd_kstat->ks_lock); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate nbytes = min(bp->b_bcount, rsp->rd_size - offset); 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate rd_rw(rsp, bp, offset, nbytes); 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate bp->b_resid = bp->b_bcount - nbytes; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate if (rsp->rd_kstat) { 10870Sstevel@tonic-gate kstat_io_t *kioptr; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate mutex_enter(rsp->rd_kstat->ks_lock); 10900Sstevel@tonic-gate kioptr = KSTAT_IO_PTR(rsp->rd_kstat); 10910Sstevel@tonic-gate if (bp->b_flags & B_READ) { 10920Sstevel@tonic-gate kioptr->nread += nbytes; 10930Sstevel@tonic-gate kioptr->reads++; 10940Sstevel@tonic-gate } else { 10950Sstevel@tonic-gate kioptr->nwritten += nbytes; 10960Sstevel@tonic-gate kioptr->writes++; 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate kstat_runq_exit(kioptr); 10990Sstevel@tonic-gate mutex_exit(rsp->rd_kstat->ks_lock); 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate biodone(bp); 11040Sstevel@tonic-gate return (0); 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate /*ARGSUSED*/ 11080Sstevel@tonic-gate static int 11090Sstevel@tonic-gate rd_read(dev_t dev, struct uio *uiop, cred_t *credp) 11100Sstevel@tonic-gate { 11110Sstevel@tonic-gate rd_devstate_t *rsp; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate if (uiop->uio_offset >= rsp->rd_size) 11160Sstevel@tonic-gate return (EINVAL); 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate return (physio(rd_strategy, NULL, dev, B_READ, rd_minphys, uiop)); 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /*ARGSUSED*/ 11220Sstevel@tonic-gate static int 11230Sstevel@tonic-gate rd_write(dev_t dev, register struct uio *uiop, cred_t *credp) 11240Sstevel@tonic-gate { 11250Sstevel@tonic-gate rd_devstate_t *rsp; 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, getminor(dev)); 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate if (uiop->uio_offset >= rsp->rd_size) 11300Sstevel@tonic-gate return (EINVAL); 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate return (physio(rd_strategy, NULL, dev, B_WRITE, rd_minphys, uiop)); 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate /*ARGSUSED*/ 11360Sstevel@tonic-gate static int 11370Sstevel@tonic-gate rd_create_disk(dev_t dev, struct rd_ioctl *urip, int mode, int *rvalp) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate struct rd_ioctl kri; 11400Sstevel@tonic-gate size_t size; 11410Sstevel@tonic-gate rd_devstate_t *rsp; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 11440Sstevel@tonic-gate return (EFAULT); 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate kri.ri_name[RD_NAME_LEN] = '\0'; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate size = kri.ri_size; 11500Sstevel@tonic-gate if (size == 0) { 11510Sstevel@tonic-gate return (EINVAL); 11520Sstevel@tonic-gate } 11530Sstevel@tonic-gate size = ptob(btopr(size)); 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate mutex_enter(&rd_lock); 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate if (rd_find_named_disk(kri.ri_name) != NULL) { 11580Sstevel@tonic-gate mutex_exit(&rd_lock); 11590Sstevel@tonic-gate return (EEXIST); 11600Sstevel@tonic-gate } 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate rsp = rd_alloc_resources(kri.ri_name, size, rd_dip); 11630Sstevel@tonic-gate if (rsp == NULL) { 11640Sstevel@tonic-gate mutex_exit(&rd_lock); 11650Sstevel@tonic-gate return (EAGAIN); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate mutex_exit(&rd_lock); 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate return (ddi_copyout(&kri, urip, sizeof (kri), mode) == -1 ? EFAULT : 0); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate /*ARGSUSED*/ 11740Sstevel@tonic-gate static int 11750Sstevel@tonic-gate rd_delete_disk(dev_t dev, struct rd_ioctl *urip, int mode) 11760Sstevel@tonic-gate { 11770Sstevel@tonic-gate struct rd_ioctl kri; 11780Sstevel@tonic-gate rd_devstate_t *rsp; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate if (ddi_copyin(urip, &kri, sizeof (kri), mode) == -1) { 11810Sstevel@tonic-gate return (EFAULT); 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate kri.ri_name[RD_NAME_LEN] = '\0'; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate mutex_enter(&rd_lock); 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate rsp = rd_find_named_disk(kri.ri_name); 11890Sstevel@tonic-gate if (rsp == NULL || rsp->rd_dip != rd_dip) { 11900Sstevel@tonic-gate mutex_exit(&rd_lock); 11910Sstevel@tonic-gate return (EINVAL); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate if (rd_is_open(rsp)) { 11940Sstevel@tonic-gate mutex_exit(&rd_lock); 11950Sstevel@tonic-gate return (EBUSY); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate rd_dealloc_resources(rsp); 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate mutex_exit(&rd_lock); 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate return (0); 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate /*ARGSUSED*/ 12060Sstevel@tonic-gate static int 12070Sstevel@tonic-gate rd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate minor_t minor; 12100Sstevel@tonic-gate int error; 12110Sstevel@tonic-gate enum dkio_state dkstate; 12120Sstevel@tonic-gate rd_devstate_t *rsp; 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate minor = getminor(dev); 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate /* 12170Sstevel@tonic-gate * Ramdisk ioctls only apply to the master device. 12180Sstevel@tonic-gate */ 12190Sstevel@tonic-gate if (minor == RD_CTL_MINOR) { 12200Sstevel@tonic-gate struct rd_ioctl *rip = (struct rd_ioctl *)arg; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * The query commands only need read-access - i.e., normal 12240Sstevel@tonic-gate * users are allowed to do those on the controlling device 12250Sstevel@tonic-gate * as long as they can open it read-only. 12260Sstevel@tonic-gate */ 12270Sstevel@tonic-gate switch (cmd) { 12280Sstevel@tonic-gate case RD_CREATE_DISK: 12290Sstevel@tonic-gate if ((mode & FWRITE) == 0) 12300Sstevel@tonic-gate return (EPERM); 12310Sstevel@tonic-gate return (rd_create_disk(dev, rip, mode, rvalp)); 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate case RD_DELETE_DISK: 12340Sstevel@tonic-gate if ((mode & FWRITE) == 0) 12350Sstevel@tonic-gate return (EPERM); 12360Sstevel@tonic-gate return (rd_delete_disk(dev, rip, mode)); 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate default: 12390Sstevel@tonic-gate return (EINVAL); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate rsp = ddi_get_soft_state(rd_statep, minor); 12440Sstevel@tonic-gate if (rsp == NULL) { 12450Sstevel@tonic-gate return (ENXIO); 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate /* 12490Sstevel@tonic-gate * These are for faking out utilities like newfs. 12500Sstevel@tonic-gate */ 12510Sstevel@tonic-gate switch (cmd) { 12520Sstevel@tonic-gate case DKIOCGVTOC: 12530Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) { 12540Sstevel@tonic-gate case DDI_MODEL_ILP32: { 12550Sstevel@tonic-gate struct vtoc32 vtoc32; 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate vtoctovtoc32(rsp->rd_vtoc, vtoc32); 12580Sstevel@tonic-gate if (ddi_copyout(&vtoc32, (void *)arg, 12590Sstevel@tonic-gate sizeof (struct vtoc32), mode)) 12600Sstevel@tonic-gate return (EFAULT); 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate break; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate case DDI_MODEL_NONE: 12650Sstevel@tonic-gate if (ddi_copyout(&rsp->rd_vtoc, (void *)arg, 12660Sstevel@tonic-gate sizeof (struct vtoc), mode)) 12670Sstevel@tonic-gate return (EFAULT); 12680Sstevel@tonic-gate break; 12690Sstevel@tonic-gate } 12700Sstevel@tonic-gate return (0); 12710Sstevel@tonic-gate case DKIOCINFO: 12720Sstevel@tonic-gate error = ddi_copyout(&rsp->rd_ci, (void *)arg, 12730Sstevel@tonic-gate sizeof (struct dk_cinfo), mode); 12740Sstevel@tonic-gate if (error) 12750Sstevel@tonic-gate return (EFAULT); 12760Sstevel@tonic-gate return (0); 12770Sstevel@tonic-gate case DKIOCG_VIRTGEOM: 12780Sstevel@tonic-gate case DKIOCG_PHYGEOM: 12790Sstevel@tonic-gate case DKIOCGGEOM: 12800Sstevel@tonic-gate error = ddi_copyout(&rsp->rd_dkg, (void *)arg, 12810Sstevel@tonic-gate sizeof (struct dk_geom), mode); 12820Sstevel@tonic-gate if (error) 12830Sstevel@tonic-gate return (EFAULT); 12840Sstevel@tonic-gate return (0); 12850Sstevel@tonic-gate case DKIOCSTATE: 12860Sstevel@tonic-gate /* the file is always there */ 12870Sstevel@tonic-gate dkstate = DKIO_INSERTED; 12880Sstevel@tonic-gate error = ddi_copyout(&dkstate, (void *)arg, 12890Sstevel@tonic-gate sizeof (enum dkio_state), mode); 12900Sstevel@tonic-gate if (error) 12910Sstevel@tonic-gate return (EFAULT); 12920Sstevel@tonic-gate return (0); 12930Sstevel@tonic-gate default: 12940Sstevel@tonic-gate return (ENOTTY); 12950Sstevel@tonic-gate } 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate static struct cb_ops rd_cb_ops = { 13000Sstevel@tonic-gate rd_open, 13010Sstevel@tonic-gate rd_close, 13020Sstevel@tonic-gate rd_strategy, 13030Sstevel@tonic-gate nodev, 13040Sstevel@tonic-gate nodev, /* dump */ 13050Sstevel@tonic-gate rd_read, 13060Sstevel@tonic-gate rd_write, 13070Sstevel@tonic-gate rd_ioctl, 13080Sstevel@tonic-gate nodev, /* devmap */ 13090Sstevel@tonic-gate nodev, /* mmap */ 13100Sstevel@tonic-gate nodev, /* segmap */ 13110Sstevel@tonic-gate nochpoll, /* poll */ 13120Sstevel@tonic-gate ddi_prop_op, 13130Sstevel@tonic-gate NULL, 13140Sstevel@tonic-gate D_NEW | D_MP 13150Sstevel@tonic-gate }; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate static struct dev_ops rd_ops = { 13180Sstevel@tonic-gate DEVO_REV, 13190Sstevel@tonic-gate 0, 13200Sstevel@tonic-gate rd_getinfo, 13210Sstevel@tonic-gate nulldev, /* identify */ 13220Sstevel@tonic-gate nulldev, /* probe */ 13230Sstevel@tonic-gate rd_attach, 13240Sstevel@tonic-gate rd_detach, 13250Sstevel@tonic-gate nodev, /* reset */ 13260Sstevel@tonic-gate &rd_cb_ops, 13270Sstevel@tonic-gate (struct bus_ops *)0 13280Sstevel@tonic-gate }; 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate extern struct mod_ops mod_driverops; 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate static struct modldrv modldrv = { 13340Sstevel@tonic-gate &mod_driverops, 13350Sstevel@tonic-gate "ramdisk driver v%I%", 13360Sstevel@tonic-gate &rd_ops 13370Sstevel@tonic-gate }; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate static struct modlinkage modlinkage = { 13400Sstevel@tonic-gate MODREV_1, 13410Sstevel@tonic-gate &modldrv, 13420Sstevel@tonic-gate 0 13430Sstevel@tonic-gate }; 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate int 13460Sstevel@tonic-gate _init(void) 13470Sstevel@tonic-gate { 13480Sstevel@tonic-gate int e; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate if ((e = ddi_soft_state_init(&rd_statep, 13510Sstevel@tonic-gate sizeof (rd_devstate_t), 0)) != 0) { 13520Sstevel@tonic-gate return (e); 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate mutex_init(&rd_lock, NULL, MUTEX_DRIVER, NULL); 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) { 13580Sstevel@tonic-gate mutex_destroy(&rd_lock); 13590Sstevel@tonic-gate ddi_soft_state_fini(&rd_statep); 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate return (e); 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate int 13660Sstevel@tonic-gate _fini(void) 13670Sstevel@tonic-gate { 13680Sstevel@tonic-gate int e; 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) { 13710Sstevel@tonic-gate return (e); 13720Sstevel@tonic-gate } 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate ddi_soft_state_fini(&rd_statep); 13750Sstevel@tonic-gate mutex_destroy(&rd_lock); 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate return (e); 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate int 13810Sstevel@tonic-gate _info(struct modinfo *modinfop) 13820Sstevel@tonic-gate { 13830Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 13840Sstevel@tonic-gate } 1385