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