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