xref: /titanic_50/usr/src/uts/common/avs/ns/sv/sv.c (revision 5c5f137104b2d56181283389fa902220f2023809)
1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
223270659fSSrikanth, Ramana  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24b2514ea1SDan McDonald  *
25b2514ea1SDan McDonald  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte /*
29fcf3ce44SJohn Forte  * Storage Volume Character and Block Driver (SV)
30fcf3ce44SJohn Forte  *
31fcf3ce44SJohn Forte  * This driver implements a simplistic /dev/{r}dsk/ interface to a
32fcf3ce44SJohn Forte  * specified disk volume that is otherwise managed by the Prism
33fcf3ce44SJohn Forte  * software.  The SV driver layers itself onto the underlying disk
34fcf3ce44SJohn Forte  * device driver by changing function pointers in the cb_ops
35fcf3ce44SJohn Forte  * structure.
36fcf3ce44SJohn Forte  *
37fcf3ce44SJohn Forte  * CONFIGURATION:
38fcf3ce44SJohn Forte  *
39fcf3ce44SJohn Forte  * 1. Configure the driver using the svadm utility.
40fcf3ce44SJohn Forte  * 2. Access the device as before through /dev/rdsk/c?t?d?s?
41fcf3ce44SJohn Forte  *
42fcf3ce44SJohn Forte  * LIMITATIONS:
43fcf3ce44SJohn Forte  *
44fcf3ce44SJohn Forte  * This driver should NOT be used to share a device between another
45fcf3ce44SJohn Forte  * DataServices user interface module (e.g., STE) and a user accessing
46fcf3ce44SJohn Forte  * the device through the block device in O_WRITE mode.  This is because
47fcf3ce44SJohn Forte  * writes through the block device are asynchronous (due to the page
48fcf3ce44SJohn Forte  * cache) and so consistency between the block device user and the
49fcf3ce44SJohn Forte  * STE user cannot be guaranteed.
50fcf3ce44SJohn Forte  *
51fcf3ce44SJohn Forte  * Data is copied between system struct buf(9s) and nsc_vec_t.  This is
52fcf3ce44SJohn Forte  * wasteful and slow.
53fcf3ce44SJohn Forte  */
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte #include <sys/debug.h>
56fcf3ce44SJohn Forte #include <sys/types.h>
57fcf3ce44SJohn Forte 
58fcf3ce44SJohn Forte #include <sys/ksynch.h>
59fcf3ce44SJohn Forte #include <sys/kmem.h>
60fcf3ce44SJohn Forte #include <sys/errno.h>
61fcf3ce44SJohn Forte #include <sys/varargs.h>
62fcf3ce44SJohn Forte #include <sys/file.h>
63fcf3ce44SJohn Forte #include <sys/open.h>
64fcf3ce44SJohn Forte #include <sys/conf.h>
65fcf3ce44SJohn Forte #include <sys/cred.h>
66fcf3ce44SJohn Forte #include <sys/buf.h>
67fcf3ce44SJohn Forte #include <sys/uio.h>
68fcf3ce44SJohn Forte #ifndef DS_DDICT
69fcf3ce44SJohn Forte #include <sys/pathname.h>
70fcf3ce44SJohn Forte #endif
71fcf3ce44SJohn Forte #include <sys/aio_req.h>
72fcf3ce44SJohn Forte #include <sys/dkio.h>
73fcf3ce44SJohn Forte #include <sys/vtoc.h>
74fcf3ce44SJohn Forte #include <sys/cmn_err.h>
75fcf3ce44SJohn Forte #include <sys/modctl.h>
76fcf3ce44SJohn Forte #include <sys/ddi.h>
77*5c5f1371SRichard Lowe #include <sys/sysmacros.h>
78fcf3ce44SJohn Forte #include <sys/sunddi.h>
79fcf3ce44SJohn Forte #include <sys/sunldi.h>
80fcf3ce44SJohn Forte #include <sys/nsctl/nsvers.h>
81fcf3ce44SJohn Forte 
82fcf3ce44SJohn Forte #include <sys/nsc_thread.h>
83fcf3ce44SJohn Forte #include <sys/unistat/spcs_s.h>
84fcf3ce44SJohn Forte #include <sys/unistat/spcs_s_k.h>
85fcf3ce44SJohn Forte #include <sys/unistat/spcs_errors.h>
86fcf3ce44SJohn Forte 
87fcf3ce44SJohn Forte #ifdef DS_DDICT
88fcf3ce44SJohn Forte #include "../contract.h"
89fcf3ce44SJohn Forte #endif
90fcf3ce44SJohn Forte 
91fcf3ce44SJohn Forte #include "../nsctl.h"
92fcf3ce44SJohn Forte 
93fcf3ce44SJohn Forte 
94fcf3ce44SJohn Forte #include <sys/sdt.h>		/* dtrace is S10 or later */
95fcf3ce44SJohn Forte 
96fcf3ce44SJohn Forte #include "sv.h"
97fcf3ce44SJohn Forte #include "sv_impl.h"
98fcf3ce44SJohn Forte #include "sv_efi.h"
99fcf3ce44SJohn Forte 
100fcf3ce44SJohn Forte #define	MAX_EINTR_COUNT 1000
101fcf3ce44SJohn Forte 
102fcf3ce44SJohn Forte /*
103fcf3ce44SJohn Forte  * sv_mod_status
104fcf3ce44SJohn Forte  */
105fcf3ce44SJohn Forte #define	SV_PREVENT_UNLOAD 1
106fcf3ce44SJohn Forte #define	SV_ALLOW_UNLOAD	2
107fcf3ce44SJohn Forte 
108fcf3ce44SJohn Forte static const int sv_major_rev = ISS_VERSION_MAJ;	/* Major number */
109fcf3ce44SJohn Forte static const int sv_minor_rev = ISS_VERSION_MIN;	/* Minor number */
110fcf3ce44SJohn Forte static const int sv_micro_rev = ISS_VERSION_MIC;	/* Micro number */
111fcf3ce44SJohn Forte static const int sv_baseline_rev = ISS_VERSION_NUM;	/* Baseline number */
112fcf3ce44SJohn Forte 
113fcf3ce44SJohn Forte #ifdef DKIOCPARTITION
114fcf3ce44SJohn Forte /*
115fcf3ce44SJohn Forte  * CRC32 polynomial table needed for computing the checksums
116fcf3ce44SJohn Forte  * in an EFI vtoc.
117fcf3ce44SJohn Forte  */
118fcf3ce44SJohn Forte static const uint32_t sv_crc32_table[256] = { CRC32_TABLE };
119fcf3ce44SJohn Forte #endif
120fcf3ce44SJohn Forte 
121fcf3ce44SJohn Forte static clock_t sv_config_time;		/* Time of successful {en,dis}able */
122fcf3ce44SJohn Forte static int sv_debug;			/* Set non-zero for debug to syslog */
123fcf3ce44SJohn Forte static int sv_mod_status;		/* Set to prevent modunload */
124fcf3ce44SJohn Forte 
125fcf3ce44SJohn Forte static dev_info_t *sv_dip;		/* Single DIP for driver */
126fcf3ce44SJohn Forte static kmutex_t sv_mutex;		/* Protect global lists, etc. */
127fcf3ce44SJohn Forte 
128fcf3ce44SJohn Forte static nsc_mem_t	*sv_mem;	/* nsctl memory allocator token */
129fcf3ce44SJohn Forte 
130fcf3ce44SJohn Forte 
131fcf3ce44SJohn Forte /*
132fcf3ce44SJohn Forte  * Per device and per major state.
133fcf3ce44SJohn Forte  */
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte #ifndef _SunOS_5_6
136fcf3ce44SJohn Forte #define	UNSAFE_ENTER()
137fcf3ce44SJohn Forte #define	UNSAFE_EXIT()
138fcf3ce44SJohn Forte #else
139fcf3ce44SJohn Forte #define	UNSAFE_ENTER()	mutex_enter(&unsafe_driver)
140fcf3ce44SJohn Forte #define	UNSAFE_EXIT()	mutex_exit(&unsafe_driver)
141fcf3ce44SJohn Forte #endif
142fcf3ce44SJohn Forte 
143fcf3ce44SJohn Forte 					/* hash table of major dev structures */
144fcf3ce44SJohn Forte static sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT] = {0};
145fcf3ce44SJohn Forte static sv_dev_t *sv_devs;		/* array of per device structures */
146fcf3ce44SJohn Forte static int sv_max_devices;		/* SV version of nsc_max_devices() */
147fcf3ce44SJohn Forte static int sv_ndevices;			/* number of SV enabled devices */
148fcf3ce44SJohn Forte 
149fcf3ce44SJohn Forte /*
150fcf3ce44SJohn Forte  * Threading.
151fcf3ce44SJohn Forte  */
152fcf3ce44SJohn Forte 
153fcf3ce44SJohn Forte int sv_threads_max = 1024;		/* maximum # to dynamically alloc */
154fcf3ce44SJohn Forte int sv_threads = 32;			/* # to pre-allocate (see sv.conf) */
155fcf3ce44SJohn Forte int sv_threads_extra = 0;		/* addl # we would have alloc'ed */
156fcf3ce44SJohn Forte 
157fcf3ce44SJohn Forte static nstset_t *sv_tset;		/* the threadset pointer */
158fcf3ce44SJohn Forte 
159fcf3ce44SJohn Forte static int sv_threads_hysteresis = 4;	/* hysteresis for threadset resizing */
160fcf3ce44SJohn Forte static int sv_threads_dev = 2;		/* # of threads to alloc per device */
161fcf3ce44SJohn Forte static int sv_threads_inc = 8;		/* increment for changing the set */
162fcf3ce44SJohn Forte static int sv_threads_needed;		/* number of threads needed */
163fcf3ce44SJohn Forte static int sv_no_threads;		/* number of nsc_create errors */
164fcf3ce44SJohn Forte static int sv_max_nlive;		/* max number of threads running */
165fcf3ce44SJohn Forte 
166fcf3ce44SJohn Forte 
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte /*
169fcf3ce44SJohn Forte  * nsctl fd callbacks.
170fcf3ce44SJohn Forte  */
171fcf3ce44SJohn Forte 
172fcf3ce44SJohn Forte static int svattach_fd(blind_t);
173fcf3ce44SJohn Forte static int svdetach_fd(blind_t);
174fcf3ce44SJohn Forte 
175fcf3ce44SJohn Forte static nsc_def_t sv_fd_def[] = {
176fcf3ce44SJohn Forte 	{ "Attach",	(uintptr_t)svattach_fd, },
177fcf3ce44SJohn Forte 	{ "Detach",	(uintptr_t)svdetach_fd, },
178fcf3ce44SJohn Forte 	{ 0, 0, }
179fcf3ce44SJohn Forte };
180fcf3ce44SJohn Forte 
181fcf3ce44SJohn Forte /*
182fcf3ce44SJohn Forte  * cb_ops functions.
183fcf3ce44SJohn Forte  */
184fcf3ce44SJohn Forte 
185fcf3ce44SJohn Forte static int svopen(dev_t *, int, int, cred_t *);
186fcf3ce44SJohn Forte static int svclose(dev_t, int, int, cred_t *);
187fcf3ce44SJohn Forte static int svioctl(dev_t, int, intptr_t, int, cred_t *, int *);
188fcf3ce44SJohn Forte static int svprint(dev_t, char *);
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte /*
191fcf3ce44SJohn Forte  * These next functions are layered into the underlying driver's devops.
192fcf3ce44SJohn Forte  */
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte static int sv_lyr_open(dev_t *, int, int, cred_t *);
195fcf3ce44SJohn Forte static int sv_lyr_close(dev_t, int, int, cred_t *);
196fcf3ce44SJohn Forte static int sv_lyr_strategy(struct buf *);
197fcf3ce44SJohn Forte static int sv_lyr_read(dev_t, struct uio *, cred_t *);
198fcf3ce44SJohn Forte static int sv_lyr_write(dev_t, struct uio *, cred_t *);
199fcf3ce44SJohn Forte static int sv_lyr_aread(dev_t, struct aio_req *, cred_t *);
200fcf3ce44SJohn Forte static int sv_lyr_awrite(dev_t, struct aio_req *, cred_t *);
201fcf3ce44SJohn Forte static int sv_lyr_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
202fcf3ce44SJohn Forte 
203fcf3ce44SJohn Forte static struct cb_ops sv_cb_ops = {
204fcf3ce44SJohn Forte 	svopen,		/* open */
205fcf3ce44SJohn Forte 	svclose,	/* close */
206fcf3ce44SJohn Forte 	nulldev,	/* strategy */
207fcf3ce44SJohn Forte 	svprint,
208fcf3ce44SJohn Forte 	nodev,		/* dump */
209fcf3ce44SJohn Forte 	nodev,		/* read */
210fcf3ce44SJohn Forte 	nodev,		/* write */
211fcf3ce44SJohn Forte 	svioctl,
212fcf3ce44SJohn Forte 	nodev,		/* devmap */
213fcf3ce44SJohn Forte 	nodev,		/* mmap */
214fcf3ce44SJohn Forte 	nodev,		/* segmap */
215fcf3ce44SJohn Forte 	nochpoll,	/* poll */
216fcf3ce44SJohn Forte 	ddi_prop_op,
217fcf3ce44SJohn Forte 	NULL,		/* NOT a stream */
218fcf3ce44SJohn Forte 	D_NEW | D_MP | D_64BIT,
219fcf3ce44SJohn Forte 	CB_REV,
220fcf3ce44SJohn Forte 	nodev,		/* aread */
221fcf3ce44SJohn Forte 	nodev,		/* awrite */
222fcf3ce44SJohn Forte };
223fcf3ce44SJohn Forte 
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte /*
226fcf3ce44SJohn Forte  * dev_ops functions.
227fcf3ce44SJohn Forte  */
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte static int sv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
230fcf3ce44SJohn Forte static int sv_attach(dev_info_t *, ddi_attach_cmd_t);
231fcf3ce44SJohn Forte static int sv_detach(dev_info_t *, ddi_detach_cmd_t);
232fcf3ce44SJohn Forte 
233fcf3ce44SJohn Forte static struct dev_ops sv_ops = {
234fcf3ce44SJohn Forte 	DEVO_REV,
235fcf3ce44SJohn Forte 	0,
236fcf3ce44SJohn Forte 	sv_getinfo,
237fcf3ce44SJohn Forte 	nulldev,	/* identify */
238fcf3ce44SJohn Forte 	nulldev,	/* probe */
239fcf3ce44SJohn Forte 	sv_attach,
240fcf3ce44SJohn Forte 	sv_detach,
241fcf3ce44SJohn Forte 	nodev,		/* reset */
242fcf3ce44SJohn Forte 	&sv_cb_ops,
243fcf3ce44SJohn Forte 	(struct bus_ops *)0
244fcf3ce44SJohn Forte };
245fcf3ce44SJohn Forte 
246fcf3ce44SJohn Forte /*
247fcf3ce44SJohn Forte  * Module linkage.
248fcf3ce44SJohn Forte  */
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte extern struct mod_ops mod_driverops;
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte static struct modldrv modldrv = {
253fcf3ce44SJohn Forte 	&mod_driverops,
254fcf3ce44SJohn Forte 	"nws:Storage Volume:" ISS_VERSION_STR,
255fcf3ce44SJohn Forte 	&sv_ops
256fcf3ce44SJohn Forte };
257fcf3ce44SJohn Forte 
258fcf3ce44SJohn Forte static struct modlinkage modlinkage = {
259fcf3ce44SJohn Forte 	MODREV_1,
260fcf3ce44SJohn Forte 	&modldrv,
261fcf3ce44SJohn Forte 	0
262fcf3ce44SJohn Forte };
263fcf3ce44SJohn Forte 
264fcf3ce44SJohn Forte 
265fcf3ce44SJohn Forte int
_init(void)266fcf3ce44SJohn Forte _init(void)
267fcf3ce44SJohn Forte {
268fcf3ce44SJohn Forte 	int error;
269fcf3ce44SJohn Forte 
270fcf3ce44SJohn Forte 	mutex_init(&sv_mutex, NULL, MUTEX_DRIVER, NULL);
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte 	if ((error = mod_install(&modlinkage)) != 0) {
273fcf3ce44SJohn Forte 		mutex_destroy(&sv_mutex);
274fcf3ce44SJohn Forte 		return (error);
275fcf3ce44SJohn Forte 	}
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte #ifdef DEBUG
2783270659fSSrikanth, Ramana 	cmn_err(CE_CONT, "!sv (revision %d.%d.%d.%d, %s, %s)\n",
279fcf3ce44SJohn Forte 	    sv_major_rev, sv_minor_rev, sv_micro_rev, sv_baseline_rev,
280fcf3ce44SJohn Forte 	    ISS_VERSION_STR, BUILD_DATE_STR);
281fcf3ce44SJohn Forte #else
282fcf3ce44SJohn Forte 	if (sv_micro_rev) {
2833270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!sv (revision %d.%d.%d, %s, %s)\n",
284fcf3ce44SJohn Forte 		    sv_major_rev, sv_minor_rev, sv_micro_rev,
285fcf3ce44SJohn Forte 		    ISS_VERSION_STR, BUILD_DATE_STR);
286fcf3ce44SJohn Forte 	} else {
2873270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!sv (revision %d.%d, %s, %s)\n",
288fcf3ce44SJohn Forte 		    sv_major_rev, sv_minor_rev,
289fcf3ce44SJohn Forte 		    ISS_VERSION_STR, BUILD_DATE_STR);
290fcf3ce44SJohn Forte 	}
291fcf3ce44SJohn Forte #endif
292fcf3ce44SJohn Forte 
293fcf3ce44SJohn Forte 	return (error);
294fcf3ce44SJohn Forte }
295fcf3ce44SJohn Forte 
296fcf3ce44SJohn Forte 
297fcf3ce44SJohn Forte int
_fini(void)298fcf3ce44SJohn Forte _fini(void)
299fcf3ce44SJohn Forte {
300fcf3ce44SJohn Forte 	int error;
301fcf3ce44SJohn Forte 
302fcf3ce44SJohn Forte 	if ((error = mod_remove(&modlinkage)) != 0)
303fcf3ce44SJohn Forte 		return (error);
304fcf3ce44SJohn Forte 
305fcf3ce44SJohn Forte 	mutex_destroy(&sv_mutex);
306fcf3ce44SJohn Forte 
307fcf3ce44SJohn Forte 	return (error);
308fcf3ce44SJohn Forte }
309fcf3ce44SJohn Forte 
310fcf3ce44SJohn Forte 
311fcf3ce44SJohn Forte int
_info(struct modinfo * modinfop)312fcf3ce44SJohn Forte _info(struct modinfo *modinfop)
313fcf3ce44SJohn Forte {
314fcf3ce44SJohn Forte 	return (mod_info(&modlinkage, modinfop));
315fcf3ce44SJohn Forte }
316fcf3ce44SJohn Forte 
317fcf3ce44SJohn Forte 
318fcf3ce44SJohn Forte /*
319fcf3ce44SJohn Forte  * Locking & State.
320fcf3ce44SJohn Forte  *
321fcf3ce44SJohn Forte  * sv_mutex protects config information - sv_maj_t and sv_dev_t lists;
322fcf3ce44SJohn Forte  * threadset creation and sizing; sv_ndevices.
323fcf3ce44SJohn Forte  *
324fcf3ce44SJohn Forte  * If we need to hold both sv_mutex and sv_lock, then the sv_mutex
325fcf3ce44SJohn Forte  * must be acquired first.
326fcf3ce44SJohn Forte  *
327fcf3ce44SJohn Forte  * sv_lock protects the sv_dev_t structure for an individual device.
328fcf3ce44SJohn Forte  *
329fcf3ce44SJohn Forte  * sv_olock protects the otyp/open members of the sv_dev_t.  If we need
330fcf3ce44SJohn Forte  * to hold both sv_lock and sv_olock, then the sv_lock must be acquired
331fcf3ce44SJohn Forte  * first.
332fcf3ce44SJohn Forte  *
333fcf3ce44SJohn Forte  * nsc_reserve/nsc_release are used in NSC_MULTI mode to allow multiple
334fcf3ce44SJohn Forte  * I/O operations to a device simultaneously, as above.
335fcf3ce44SJohn Forte  *
336fcf3ce44SJohn Forte  * All nsc_open/nsc_close/nsc_reserve/nsc_release operations that occur
337fcf3ce44SJohn Forte  * with sv_lock write-locked must be done with (sv_state == SV_PENDING)
338fcf3ce44SJohn Forte  * and (sv_pending == curthread) so that any recursion through
339fcf3ce44SJohn Forte  * sv_lyr_open/sv_lyr_close can be detected.
340fcf3ce44SJohn Forte  */
341fcf3ce44SJohn Forte 
342fcf3ce44SJohn Forte 
343fcf3ce44SJohn Forte static int
sv_init_devs(void)344fcf3ce44SJohn Forte sv_init_devs(void)
345fcf3ce44SJohn Forte {
346fcf3ce44SJohn Forte 	int i;
347fcf3ce44SJohn Forte 
348fcf3ce44SJohn Forte 	ASSERT(MUTEX_HELD(&sv_mutex));
349fcf3ce44SJohn Forte 
350fcf3ce44SJohn Forte 	if (sv_max_devices > 0)
351fcf3ce44SJohn Forte 		return (0);
352fcf3ce44SJohn Forte 
353fcf3ce44SJohn Forte 	sv_max_devices = nsc_max_devices();
354fcf3ce44SJohn Forte 
355fcf3ce44SJohn Forte 	if (sv_max_devices <= 0) {
356fcf3ce44SJohn Forte 		/* nsctl is not attached (nskernd not running) */
357fcf3ce44SJohn Forte 		if (sv_debug > 0)
3583270659fSSrikanth, Ramana 			cmn_err(CE_CONT, "!sv: nsc_max_devices = 0\n");
359fcf3ce44SJohn Forte 		return (EAGAIN);
360fcf3ce44SJohn Forte 	}
361fcf3ce44SJohn Forte 
362fcf3ce44SJohn Forte 	sv_devs = nsc_kmem_zalloc((sv_max_devices * sizeof (*sv_devs)),
363fcf3ce44SJohn Forte 	    KM_NOSLEEP, sv_mem);
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte 	if (sv_devs == NULL) {
3663270659fSSrikanth, Ramana 		cmn_err(CE_WARN, "!sv: could not allocate sv_devs array");
367fcf3ce44SJohn Forte 		return (ENOMEM);
368fcf3ce44SJohn Forte 	}
369fcf3ce44SJohn Forte 
370fcf3ce44SJohn Forte 	for (i = 0; i < sv_max_devices; i++) {
371fcf3ce44SJohn Forte 		mutex_init(&sv_devs[i].sv_olock, NULL, MUTEX_DRIVER, NULL);
372fcf3ce44SJohn Forte 		rw_init(&sv_devs[i].sv_lock, NULL, RW_DRIVER, NULL);
373fcf3ce44SJohn Forte 	}
374fcf3ce44SJohn Forte 
375fcf3ce44SJohn Forte 	if (sv_debug > 0)
3763270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!sv: sv_init_devs successful\n");
377fcf3ce44SJohn Forte 
378fcf3ce44SJohn Forte 	return (0);
379fcf3ce44SJohn Forte }
380fcf3ce44SJohn Forte 
381fcf3ce44SJohn Forte 
382fcf3ce44SJohn Forte static int
sv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)383fcf3ce44SJohn Forte sv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
384fcf3ce44SJohn Forte {
385fcf3ce44SJohn Forte 	int rc;
386fcf3ce44SJohn Forte 
387fcf3ce44SJohn Forte 	switch (cmd) {
388fcf3ce44SJohn Forte 
389fcf3ce44SJohn Forte 	case DDI_ATTACH:
390fcf3ce44SJohn Forte 		sv_dip = dip;
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte 		if (ddi_create_minor_node(dip, "sv", S_IFCHR,
393fcf3ce44SJohn Forte 		    0, DDI_PSEUDO, 0) != DDI_SUCCESS)
394fcf3ce44SJohn Forte 			goto failed;
395fcf3ce44SJohn Forte 
396fcf3ce44SJohn Forte 		mutex_enter(&sv_mutex);
397fcf3ce44SJohn Forte 
398fcf3ce44SJohn Forte 		sv_mem = nsc_register_mem("SV", NSC_MEM_LOCAL, 0);
399fcf3ce44SJohn Forte 		if (sv_mem == NULL) {
400fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
401fcf3ce44SJohn Forte 			goto failed;
402fcf3ce44SJohn Forte 		}
403fcf3ce44SJohn Forte 
404fcf3ce44SJohn Forte 		rc = sv_init_devs();
405fcf3ce44SJohn Forte 		if (rc != 0 && rc != EAGAIN) {
406fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
407fcf3ce44SJohn Forte 			goto failed;
408fcf3ce44SJohn Forte 		}
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
411fcf3ce44SJohn Forte 
412fcf3ce44SJohn Forte 
413fcf3ce44SJohn Forte 		ddi_report_dev(dip);
414fcf3ce44SJohn Forte 
415fcf3ce44SJohn Forte 		sv_threads = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
416fcf3ce44SJohn Forte 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
417fcf3ce44SJohn Forte 		    "sv_threads", sv_threads);
418fcf3ce44SJohn Forte 
419fcf3ce44SJohn Forte 		if (sv_debug > 0)
4203270659fSSrikanth, Ramana 			cmn_err(CE_CONT, "!sv: sv_threads=%d\n", sv_threads);
421fcf3ce44SJohn Forte 
422fcf3ce44SJohn Forte 		if (sv_threads > sv_threads_max)
423fcf3ce44SJohn Forte 			sv_threads_max = sv_threads;
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
426fcf3ce44SJohn Forte 
427fcf3ce44SJohn Forte 	default:
428fcf3ce44SJohn Forte 		return (DDI_FAILURE);
429fcf3ce44SJohn Forte 	}
430fcf3ce44SJohn Forte 
431fcf3ce44SJohn Forte failed:
432fcf3ce44SJohn Forte 	DTRACE_PROBE(sv_attach_failed);
433fcf3ce44SJohn Forte 	(void) sv_detach(dip, DDI_DETACH);
434fcf3ce44SJohn Forte 	return (DDI_FAILURE);
435fcf3ce44SJohn Forte }
436fcf3ce44SJohn Forte 
437fcf3ce44SJohn Forte 
438fcf3ce44SJohn Forte static int
sv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)439fcf3ce44SJohn Forte sv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
440fcf3ce44SJohn Forte {
441fcf3ce44SJohn Forte 	sv_dev_t *svp;
442fcf3ce44SJohn Forte 	int i;
443fcf3ce44SJohn Forte 
444fcf3ce44SJohn Forte 	switch (cmd) {
445fcf3ce44SJohn Forte 
446fcf3ce44SJohn Forte 	case DDI_DETACH:
447fcf3ce44SJohn Forte 
448fcf3ce44SJohn Forte 		/*
449fcf3ce44SJohn Forte 		 * Check that everything is disabled.
450fcf3ce44SJohn Forte 		 */
451fcf3ce44SJohn Forte 
452fcf3ce44SJohn Forte 		mutex_enter(&sv_mutex);
453fcf3ce44SJohn Forte 
454fcf3ce44SJohn Forte 		if (sv_mod_status == SV_PREVENT_UNLOAD) {
455fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
456fcf3ce44SJohn Forte 			DTRACE_PROBE(sv_detach_err_prevent);
457fcf3ce44SJohn Forte 			return (DDI_FAILURE);
458fcf3ce44SJohn Forte 		}
459fcf3ce44SJohn Forte 
460fcf3ce44SJohn Forte 		for (i = 0; sv_devs && i < sv_max_devices; i++) {
461fcf3ce44SJohn Forte 			svp = &sv_devs[i];
462fcf3ce44SJohn Forte 
463fcf3ce44SJohn Forte 			if (svp->sv_state != SV_DISABLE) {
464fcf3ce44SJohn Forte 				mutex_exit(&sv_mutex);
465fcf3ce44SJohn Forte 				DTRACE_PROBE(sv_detach_err_busy);
466fcf3ce44SJohn Forte 				return (DDI_FAILURE);
467fcf3ce44SJohn Forte 			}
468fcf3ce44SJohn Forte 		}
469fcf3ce44SJohn Forte 
470fcf3ce44SJohn Forte 
471fcf3ce44SJohn Forte 		for (i = 0; sv_devs && i < sv_max_devices; i++) {
472fcf3ce44SJohn Forte 			mutex_destroy(&sv_devs[i].sv_olock);
473fcf3ce44SJohn Forte 			rw_destroy(&sv_devs[i].sv_lock);
474fcf3ce44SJohn Forte 		}
475fcf3ce44SJohn Forte 
476fcf3ce44SJohn Forte 		if (sv_devs) {
477fcf3ce44SJohn Forte 			nsc_kmem_free(sv_devs,
478fcf3ce44SJohn Forte 			    (sv_max_devices * sizeof (*sv_devs)));
479fcf3ce44SJohn Forte 			sv_devs = NULL;
480fcf3ce44SJohn Forte 		}
481fcf3ce44SJohn Forte 		sv_max_devices = 0;
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte 		if (sv_mem) {
484fcf3ce44SJohn Forte 			nsc_unregister_mem(sv_mem);
485fcf3ce44SJohn Forte 			sv_mem = NULL;
486fcf3ce44SJohn Forte 		}
487fcf3ce44SJohn Forte 
488fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
489fcf3ce44SJohn Forte 
490fcf3ce44SJohn Forte 		/*
491fcf3ce44SJohn Forte 		 * Remove all minor nodes.
492fcf3ce44SJohn Forte 		 */
493fcf3ce44SJohn Forte 
494fcf3ce44SJohn Forte 		ddi_remove_minor_node(dip, NULL);
495fcf3ce44SJohn Forte 		sv_dip = NULL;
496fcf3ce44SJohn Forte 
497fcf3ce44SJohn Forte 		return (DDI_SUCCESS);
498fcf3ce44SJohn Forte 
499fcf3ce44SJohn Forte 	default:
500fcf3ce44SJohn Forte 		return (DDI_FAILURE);
501fcf3ce44SJohn Forte 	}
502fcf3ce44SJohn Forte }
503fcf3ce44SJohn Forte 
504fcf3ce44SJohn Forte static sv_maj_t *
sv_getmajor(const dev_t dev)505fcf3ce44SJohn Forte sv_getmajor(const dev_t dev)
506fcf3ce44SJohn Forte {
507fcf3ce44SJohn Forte 	sv_maj_t **insert, *maj;
508fcf3ce44SJohn Forte 	major_t umaj = getmajor(dev);
509fcf3ce44SJohn Forte 
510fcf3ce44SJohn Forte 	/*
511fcf3ce44SJohn Forte 	 * See if the hash table entry, or one of the hash chains
512fcf3ce44SJohn Forte 	 * is already allocated for this major number
513fcf3ce44SJohn Forte 	 */
514fcf3ce44SJohn Forte 	if ((maj = sv_majors[SV_MAJOR_HASH(umaj)]) != 0) {
515fcf3ce44SJohn Forte 		do {
516fcf3ce44SJohn Forte 			if (maj->sm_major == umaj)
517fcf3ce44SJohn Forte 				return (maj);
518fcf3ce44SJohn Forte 		} while ((maj = maj->sm_next) != 0);
519fcf3ce44SJohn Forte 	}
520fcf3ce44SJohn Forte 
521fcf3ce44SJohn Forte 	/*
522fcf3ce44SJohn Forte 	 * If the sv_mutex is held, there is design flaw, as the only non-mutex
523fcf3ce44SJohn Forte 	 * held callers can be sv_enable() or sv_dev_to_sv()
524fcf3ce44SJohn Forte 	 * Return an error, instead of panicing the system
525fcf3ce44SJohn Forte 	 */
526fcf3ce44SJohn Forte 	if (MUTEX_HELD(&sv_mutex)) {
5273270659fSSrikanth, Ramana 		cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
528fcf3ce44SJohn Forte 		return (NULL);
529fcf3ce44SJohn Forte 	}
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	/*
532fcf3ce44SJohn Forte 	 * Determine where to allocate a new element in the hash table
533fcf3ce44SJohn Forte 	 */
534fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
535fcf3ce44SJohn Forte 	insert = &(sv_majors[SV_MAJOR_HASH(umaj)]);
536fcf3ce44SJohn Forte 	for (maj = *insert; maj; maj = maj->sm_next) {
537fcf3ce44SJohn Forte 
538fcf3ce44SJohn Forte 		/* Did another thread beat us to it? */
539fcf3ce44SJohn Forte 		if (maj->sm_major == umaj)
540fcf3ce44SJohn Forte 			return (maj);
541fcf3ce44SJohn Forte 
542fcf3ce44SJohn Forte 		/* Find a NULL insert point? */
543fcf3ce44SJohn Forte 		if (maj->sm_next == NULL)
544fcf3ce44SJohn Forte 			insert = &maj->sm_next;
545fcf3ce44SJohn Forte 	}
546fcf3ce44SJohn Forte 
547fcf3ce44SJohn Forte 	/*
548fcf3ce44SJohn Forte 	 * Located the new insert point
549fcf3ce44SJohn Forte 	 */
550fcf3ce44SJohn Forte 	*insert = nsc_kmem_zalloc(sizeof (*maj), KM_NOSLEEP, sv_mem);
551fcf3ce44SJohn Forte 	if ((maj = *insert) != 0)
552fcf3ce44SJohn Forte 		maj->sm_major = umaj;
553fcf3ce44SJohn Forte 	else
5543270659fSSrikanth, Ramana 		cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
555fcf3ce44SJohn Forte 
556fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
557fcf3ce44SJohn Forte 
558fcf3ce44SJohn Forte 	return (maj);
559fcf3ce44SJohn Forte }
560fcf3ce44SJohn Forte 
561fcf3ce44SJohn Forte /* ARGSUSED */
562fcf3ce44SJohn Forte 
563fcf3ce44SJohn Forte static int
sv_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)564fcf3ce44SJohn Forte sv_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
565fcf3ce44SJohn Forte {
566fcf3ce44SJohn Forte 	int rc = DDI_FAILURE;
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 	switch (infocmd) {
569fcf3ce44SJohn Forte 
570fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2DEVINFO:
571fcf3ce44SJohn Forte 		*result = sv_dip;
572fcf3ce44SJohn Forte 		rc = DDI_SUCCESS;
573fcf3ce44SJohn Forte 		break;
574fcf3ce44SJohn Forte 
575fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2INSTANCE:
576fcf3ce44SJohn Forte 		/*
577fcf3ce44SJohn Forte 		 * We only have a single instance.
578fcf3ce44SJohn Forte 		 */
579fcf3ce44SJohn Forte 		*result = 0;
580fcf3ce44SJohn Forte 		rc = DDI_SUCCESS;
581fcf3ce44SJohn Forte 		break;
582fcf3ce44SJohn Forte 
583fcf3ce44SJohn Forte 	default:
584fcf3ce44SJohn Forte 		break;
585fcf3ce44SJohn Forte 	}
586fcf3ce44SJohn Forte 
587fcf3ce44SJohn Forte 	return (rc);
588fcf3ce44SJohn Forte }
589fcf3ce44SJohn Forte 
590fcf3ce44SJohn Forte 
591fcf3ce44SJohn Forte /*
592fcf3ce44SJohn Forte  * Hashing of devices onto major device structures.
593fcf3ce44SJohn Forte  *
594fcf3ce44SJohn Forte  * Individual device structures are hashed onto one of the sm_hash[]
595fcf3ce44SJohn Forte  * buckets in the relevant major device structure.
596fcf3ce44SJohn Forte  *
597fcf3ce44SJohn Forte  * Hash insertion and deletion -must- be done with sv_mutex held.  Hash
598fcf3ce44SJohn Forte  * searching does not require the mutex because of the sm_seq member.
599fcf3ce44SJohn Forte  * sm_seq is incremented on each insertion (-after- hash chain pointer
600fcf3ce44SJohn Forte  * manipulation) and each deletion (-before- hash chain pointer
601fcf3ce44SJohn Forte  * manipulation).  When searching the hash chain, the seq number is
602fcf3ce44SJohn Forte  * checked before accessing each device structure, if the seq number has
603fcf3ce44SJohn Forte  * changed, then we restart the search from the top of the hash chain.
604fcf3ce44SJohn Forte  * If we restart more than SV_HASH_RETRY times, we take sv_mutex and search
605fcf3ce44SJohn Forte  * the hash chain (we are guaranteed that this search cannot be
606fcf3ce44SJohn Forte  * interrupted).
607fcf3ce44SJohn Forte  */
608fcf3ce44SJohn Forte 
609fcf3ce44SJohn Forte #define	SV_HASH_RETRY	16
610fcf3ce44SJohn Forte 
611fcf3ce44SJohn Forte static sv_dev_t *
sv_dev_to_sv(const dev_t dev,sv_maj_t ** majpp)612fcf3ce44SJohn Forte sv_dev_to_sv(const dev_t dev, sv_maj_t **majpp)
613fcf3ce44SJohn Forte {
614fcf3ce44SJohn Forte 	minor_t umin = getminor(dev);
615fcf3ce44SJohn Forte 	sv_dev_t **hb, *next, *svp;
616fcf3ce44SJohn Forte 	sv_maj_t *maj;
617fcf3ce44SJohn Forte 	int seq;
618fcf3ce44SJohn Forte 	int try;
619fcf3ce44SJohn Forte 
620fcf3ce44SJohn Forte 	/* Get major hash table */
621fcf3ce44SJohn Forte 	maj = sv_getmajor(dev);
622fcf3ce44SJohn Forte 	if (majpp)
623fcf3ce44SJohn Forte 		*majpp = maj;
624fcf3ce44SJohn Forte 	if (maj == NULL)
625fcf3ce44SJohn Forte 		return (NULL);
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 	if (maj->sm_inuse == 0) {
628fcf3ce44SJohn Forte 		DTRACE_PROBE1(
629fcf3ce44SJohn Forte 		    sv_dev_to_sv_end,
630fcf3ce44SJohn Forte 		    dev_t, dev);
631fcf3ce44SJohn Forte 		return (NULL);
632fcf3ce44SJohn Forte 	}
633fcf3ce44SJohn Forte 
634fcf3ce44SJohn Forte 	hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]);
635fcf3ce44SJohn Forte 	try = 0;
636fcf3ce44SJohn Forte 
637fcf3ce44SJohn Forte retry:
638fcf3ce44SJohn Forte 	if (try > SV_HASH_RETRY)
639fcf3ce44SJohn Forte 		mutex_enter(&sv_mutex);
640fcf3ce44SJohn Forte 
641fcf3ce44SJohn Forte 	seq = maj->sm_seq;
642fcf3ce44SJohn Forte 	for (svp = *hb; svp; svp = next) {
643fcf3ce44SJohn Forte 		next = svp->sv_hash;
644fcf3ce44SJohn Forte 
645fcf3ce44SJohn Forte 		nsc_membar_stld();	/* preserve register load order */
646fcf3ce44SJohn Forte 
647fcf3ce44SJohn Forte 		if (maj->sm_seq != seq) {
6483270659fSSrikanth, Ramana 			DTRACE_PROBE1(sv_dev_to_sv_retry, dev_t, dev);
649fcf3ce44SJohn Forte 			try++;
650fcf3ce44SJohn Forte 			goto retry;
651fcf3ce44SJohn Forte 		}
652fcf3ce44SJohn Forte 
653fcf3ce44SJohn Forte 		if (svp->sv_dev == dev)
654fcf3ce44SJohn Forte 			break;
655fcf3ce44SJohn Forte 	}
656fcf3ce44SJohn Forte 
657fcf3ce44SJohn Forte 	if (try > SV_HASH_RETRY)
658fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 	return (svp);
661fcf3ce44SJohn Forte }
662fcf3ce44SJohn Forte 
663fcf3ce44SJohn Forte 
664fcf3ce44SJohn Forte /*
665fcf3ce44SJohn Forte  * Must be called with sv_mutex held.
666fcf3ce44SJohn Forte  */
667fcf3ce44SJohn Forte 
668fcf3ce44SJohn Forte static int
sv_get_state(const dev_t udev,sv_dev_t ** svpp)669fcf3ce44SJohn Forte sv_get_state(const dev_t udev, sv_dev_t **svpp)
670fcf3ce44SJohn Forte {
671fcf3ce44SJohn Forte 	sv_dev_t **hb, **insert, *svp;
672fcf3ce44SJohn Forte 	sv_maj_t *maj;
673fcf3ce44SJohn Forte 	minor_t umin;
674fcf3ce44SJohn Forte 	int i;
675fcf3ce44SJohn Forte 
676fcf3ce44SJohn Forte 	/* Get major hash table */
677fcf3ce44SJohn Forte 	if ((maj = sv_getmajor(udev)) == NULL)
678fcf3ce44SJohn Forte 		return (NULL);
679fcf3ce44SJohn Forte 
680fcf3ce44SJohn Forte 	/* Determine which minor hash table */
681fcf3ce44SJohn Forte 	umin = getminor(udev);
682fcf3ce44SJohn Forte 	hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]);
683fcf3ce44SJohn Forte 
684fcf3ce44SJohn Forte 	/* look for clash */
685fcf3ce44SJohn Forte 
686fcf3ce44SJohn Forte 	insert = hb;
687fcf3ce44SJohn Forte 
688fcf3ce44SJohn Forte 	for (svp = *hb; svp; svp = svp->sv_hash) {
689fcf3ce44SJohn Forte 		if (svp->sv_dev == udev)
690fcf3ce44SJohn Forte 			break;
691fcf3ce44SJohn Forte 
692fcf3ce44SJohn Forte 		if (svp->sv_hash == NULL)
693fcf3ce44SJohn Forte 			insert = &svp->sv_hash;
694fcf3ce44SJohn Forte 	}
695fcf3ce44SJohn Forte 
696fcf3ce44SJohn Forte 	if (svp) {
697fcf3ce44SJohn Forte 		DTRACE_PROBE1(
698fcf3ce44SJohn Forte 		    sv_get_state_enabled,
699fcf3ce44SJohn Forte 		    dev_t, udev);
700fcf3ce44SJohn Forte 		return (SV_EENABLED);
701fcf3ce44SJohn Forte 	}
702fcf3ce44SJohn Forte 
703fcf3ce44SJohn Forte 	/* look for spare sv_devs slot */
704fcf3ce44SJohn Forte 
705fcf3ce44SJohn Forte 	for (i = 0; i < sv_max_devices; i++) {
706fcf3ce44SJohn Forte 		svp = &sv_devs[i];
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 		if (svp->sv_state == SV_DISABLE)
709fcf3ce44SJohn Forte 			break;
710fcf3ce44SJohn Forte 	}
711fcf3ce44SJohn Forte 
712fcf3ce44SJohn Forte 	if (i >= sv_max_devices) {
713fcf3ce44SJohn Forte 		DTRACE_PROBE1(
714fcf3ce44SJohn Forte 		    sv_get_state_noslots,
715fcf3ce44SJohn Forte 		    dev_t, udev);
716fcf3ce44SJohn Forte 		return (SV_ENOSLOTS);
717fcf3ce44SJohn Forte 	}
718fcf3ce44SJohn Forte 
719fcf3ce44SJohn Forte 	svp->sv_state = SV_PENDING;
720fcf3ce44SJohn Forte 	svp->sv_pending = curthread;
721fcf3ce44SJohn Forte 
722fcf3ce44SJohn Forte 	*insert = svp;
723fcf3ce44SJohn Forte 	svp->sv_hash = NULL;
724fcf3ce44SJohn Forte 	maj->sm_seq++;		/* must be after the store to the hash chain */
725fcf3ce44SJohn Forte 
726fcf3ce44SJohn Forte 	*svpp = svp;
727fcf3ce44SJohn Forte 
728fcf3ce44SJohn Forte 	/*
729fcf3ce44SJohn Forte 	 * We do not know the size of the underlying device at
730fcf3ce44SJohn Forte 	 * this stage, so initialise "nblocks" property to
731fcf3ce44SJohn Forte 	 * zero, and update it whenever we succeed in
732fcf3ce44SJohn Forte 	 * nsc_reserve'ing the underlying nsc_fd_t.
733fcf3ce44SJohn Forte 	 */
734fcf3ce44SJohn Forte 
735fcf3ce44SJohn Forte 	svp->sv_nblocks = 0;
736fcf3ce44SJohn Forte 
737fcf3ce44SJohn Forte 	return (0);
738fcf3ce44SJohn Forte }
739fcf3ce44SJohn Forte 
740fcf3ce44SJohn Forte 
741fcf3ce44SJohn Forte /*
742fcf3ce44SJohn Forte  * Remove a device structure from it's hash chain.
743fcf3ce44SJohn Forte  * Must be called with sv_mutex held.
744fcf3ce44SJohn Forte  */
745fcf3ce44SJohn Forte 
746fcf3ce44SJohn Forte static void
sv_rm_hash(sv_dev_t * svp)747fcf3ce44SJohn Forte sv_rm_hash(sv_dev_t *svp)
748fcf3ce44SJohn Forte {
749fcf3ce44SJohn Forte 	sv_dev_t **svpp;
750fcf3ce44SJohn Forte 	sv_maj_t *maj;
751fcf3ce44SJohn Forte 
752fcf3ce44SJohn Forte 	/* Get major hash table */
753fcf3ce44SJohn Forte 	if ((maj = sv_getmajor(svp->sv_dev)) == NULL)
754fcf3ce44SJohn Forte 		return;
755fcf3ce44SJohn Forte 
756fcf3ce44SJohn Forte 	/* remove svp from hash chain */
757fcf3ce44SJohn Forte 
758fcf3ce44SJohn Forte 	svpp = &(maj->sm_hash[SV_MINOR_HASH(getminor(svp->sv_dev))]);
759fcf3ce44SJohn Forte 	while (*svpp) {
760fcf3ce44SJohn Forte 		if (*svpp == svp) {
761fcf3ce44SJohn Forte 			/*
762fcf3ce44SJohn Forte 			 * increment of sm_seq must be before the
763fcf3ce44SJohn Forte 			 * removal from the hash chain
764fcf3ce44SJohn Forte 			 */
765fcf3ce44SJohn Forte 			maj->sm_seq++;
766fcf3ce44SJohn Forte 			*svpp = svp->sv_hash;
767fcf3ce44SJohn Forte 			break;
768fcf3ce44SJohn Forte 		}
769fcf3ce44SJohn Forte 
770fcf3ce44SJohn Forte 		svpp = &(*svpp)->sv_hash;
771fcf3ce44SJohn Forte 	}
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte 	svp->sv_hash = NULL;
774fcf3ce44SJohn Forte }
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte /*
777fcf3ce44SJohn Forte  * Free (disable) a device structure.
778fcf3ce44SJohn Forte  * Must be called with sv_lock(RW_WRITER) and sv_mutex held, and will
779fcf3ce44SJohn Forte  * perform the exits during its processing.
780fcf3ce44SJohn Forte  */
781fcf3ce44SJohn Forte 
782fcf3ce44SJohn Forte static int
sv_free(sv_dev_t * svp,const int error)783fcf3ce44SJohn Forte sv_free(sv_dev_t *svp, const int error)
784fcf3ce44SJohn Forte {
785fcf3ce44SJohn Forte 	struct cb_ops *cb_ops;
786fcf3ce44SJohn Forte 	sv_maj_t *maj;
787fcf3ce44SJohn Forte 
788fcf3ce44SJohn Forte 	/* Get major hash table */
789fcf3ce44SJohn Forte 	if ((maj = sv_getmajor(svp->sv_dev)) == NULL)
790fcf3ce44SJohn Forte 		return (NULL);
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 	svp->sv_state = SV_PENDING;
793fcf3ce44SJohn Forte 	svp->sv_pending = curthread;
794fcf3ce44SJohn Forte 
795fcf3ce44SJohn Forte 	/*
796fcf3ce44SJohn Forte 	 * Close the fd's before removing from the hash or swapping
797fcf3ce44SJohn Forte 	 * back the cb_ops pointers so that the cache flushes before new
798fcf3ce44SJohn Forte 	 * io can come in.
799fcf3ce44SJohn Forte 	 */
800fcf3ce44SJohn Forte 
801fcf3ce44SJohn Forte 	if (svp->sv_fd) {
802fcf3ce44SJohn Forte 		(void) nsc_close(svp->sv_fd);
803fcf3ce44SJohn Forte 		svp->sv_fd = 0;
804fcf3ce44SJohn Forte 	}
805fcf3ce44SJohn Forte 
806fcf3ce44SJohn Forte 	sv_rm_hash(svp);
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 	if (error != SV_ESDOPEN &&
809fcf3ce44SJohn Forte 	    error != SV_ELYROPEN && --maj->sm_inuse == 0) {
810fcf3ce44SJohn Forte 
811fcf3ce44SJohn Forte 		if (maj->sm_dev_ops)
812fcf3ce44SJohn Forte 			cb_ops = maj->sm_dev_ops->devo_cb_ops;
813fcf3ce44SJohn Forte 		else
814fcf3ce44SJohn Forte 			cb_ops = NULL;
815fcf3ce44SJohn Forte 
816fcf3ce44SJohn Forte 		if (cb_ops && maj->sm_strategy != NULL) {
817fcf3ce44SJohn Forte 			cb_ops->cb_strategy = maj->sm_strategy;
818fcf3ce44SJohn Forte 			cb_ops->cb_close = maj->sm_close;
819fcf3ce44SJohn Forte 			cb_ops->cb_ioctl = maj->sm_ioctl;
820fcf3ce44SJohn Forte 			cb_ops->cb_write = maj->sm_write;
821fcf3ce44SJohn Forte 			cb_ops->cb_open = maj->sm_open;
822fcf3ce44SJohn Forte 			cb_ops->cb_read = maj->sm_read;
823fcf3ce44SJohn Forte 			cb_ops->cb_flag = maj->sm_flag;
824fcf3ce44SJohn Forte 
825fcf3ce44SJohn Forte 			if (maj->sm_awrite)
826fcf3ce44SJohn Forte 				cb_ops->cb_awrite = maj->sm_awrite;
827fcf3ce44SJohn Forte 
828fcf3ce44SJohn Forte 			if (maj->sm_aread)
829fcf3ce44SJohn Forte 				cb_ops->cb_aread = maj->sm_aread;
830fcf3ce44SJohn Forte 
831fcf3ce44SJohn Forte 			/*
832fcf3ce44SJohn Forte 			 * corbin XXX
833fcf3ce44SJohn Forte 			 * Leave backing device ops in maj->sm_*
834fcf3ce44SJohn Forte 			 * to handle any requests that might come
835fcf3ce44SJohn Forte 			 * in during the disable.  This could be
836fcf3ce44SJohn Forte 			 * a problem however if the backing device
837fcf3ce44SJohn Forte 			 * driver is changed while we process these
838fcf3ce44SJohn Forte 			 * requests.
839fcf3ce44SJohn Forte 			 *
840fcf3ce44SJohn Forte 			 * maj->sm_strategy = 0;
841fcf3ce44SJohn Forte 			 * maj->sm_awrite = 0;
842fcf3ce44SJohn Forte 			 * maj->sm_write = 0;
843fcf3ce44SJohn Forte 			 * maj->sm_ioctl = 0;
844fcf3ce44SJohn Forte 			 * maj->sm_close = 0;
845fcf3ce44SJohn Forte 			 * maj->sm_aread = 0;
846fcf3ce44SJohn Forte 			 * maj->sm_read = 0;
847fcf3ce44SJohn Forte 			 * maj->sm_open = 0;
848fcf3ce44SJohn Forte 			 * maj->sm_flag = 0;
849fcf3ce44SJohn Forte 			 *
850fcf3ce44SJohn Forte 			 */
851fcf3ce44SJohn Forte 		}
852fcf3ce44SJohn Forte 
853fcf3ce44SJohn Forte 		if (maj->sm_dev_ops) {
854fcf3ce44SJohn Forte 			maj->sm_dev_ops = 0;
855fcf3ce44SJohn Forte 		}
856fcf3ce44SJohn Forte 	}
857fcf3ce44SJohn Forte 
858fcf3ce44SJohn Forte 	if (svp->sv_lh) {
859fcf3ce44SJohn Forte 		cred_t *crp = ddi_get_cred();
860fcf3ce44SJohn Forte 
861fcf3ce44SJohn Forte 		/*
862fcf3ce44SJohn Forte 		 * Close the protective layered driver open using the
863fcf3ce44SJohn Forte 		 * Sun Private layered driver i/f.
864fcf3ce44SJohn Forte 		 */
865fcf3ce44SJohn Forte 
866fcf3ce44SJohn Forte 		(void) ldi_close(svp->sv_lh, FREAD|FWRITE, crp);
867fcf3ce44SJohn Forte 		svp->sv_lh = NULL;
868fcf3ce44SJohn Forte 	}
869fcf3ce44SJohn Forte 
870fcf3ce44SJohn Forte 	svp->sv_timestamp = nsc_lbolt();
871fcf3ce44SJohn Forte 	svp->sv_state = SV_DISABLE;
872fcf3ce44SJohn Forte 	svp->sv_pending = NULL;
873fcf3ce44SJohn Forte 	rw_exit(&svp->sv_lock);
874fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
875fcf3ce44SJohn Forte 
876fcf3ce44SJohn Forte 	return (error);
877fcf3ce44SJohn Forte }
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte /*
880fcf3ce44SJohn Forte  * Reserve the device, taking into account the possibility that
881fcf3ce44SJohn Forte  * the reserve might have to be retried.
882fcf3ce44SJohn Forte  */
883fcf3ce44SJohn Forte static int
sv_reserve(nsc_fd_t * fd,int flags)884fcf3ce44SJohn Forte sv_reserve(nsc_fd_t *fd, int flags)
885fcf3ce44SJohn Forte {
886fcf3ce44SJohn Forte 	int eintr_count;
887fcf3ce44SJohn Forte 	int rc;
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 	eintr_count = 0;
890fcf3ce44SJohn Forte 	do {
891fcf3ce44SJohn Forte 		rc = nsc_reserve(fd, flags);
892fcf3ce44SJohn Forte 		if (rc == EINTR) {
893fcf3ce44SJohn Forte 			++eintr_count;
894fcf3ce44SJohn Forte 			delay(2);
895fcf3ce44SJohn Forte 		}
896fcf3ce44SJohn Forte 	} while ((rc == EINTR) && (eintr_count < MAX_EINTR_COUNT));
897fcf3ce44SJohn Forte 
898fcf3ce44SJohn Forte 	return (rc);
899fcf3ce44SJohn Forte }
900fcf3ce44SJohn Forte 
901fcf3ce44SJohn Forte static int
sv_enable(const caddr_t path,const int flag,const dev_t udev,spcs_s_info_t kstatus)902fcf3ce44SJohn Forte sv_enable(const caddr_t path, const int flag,
903fcf3ce44SJohn Forte     const dev_t udev, spcs_s_info_t kstatus)
904fcf3ce44SJohn Forte {
905fcf3ce44SJohn Forte 	struct dev_ops *dev_ops;
906fcf3ce44SJohn Forte 	struct cb_ops *cb_ops;
907fcf3ce44SJohn Forte 	sv_dev_t *svp;
908fcf3ce44SJohn Forte 	sv_maj_t *maj;
909fcf3ce44SJohn Forte 	nsc_size_t nblocks;
910fcf3ce44SJohn Forte 	int rc;
911fcf3ce44SJohn Forte 	cred_t *crp;
912fcf3ce44SJohn Forte 	ldi_ident_t	li;
913fcf3ce44SJohn Forte 
914fcf3ce44SJohn Forte 	if (udev == (dev_t)-1 || udev == 0) {
915fcf3ce44SJohn Forte 		DTRACE_PROBE1(
916fcf3ce44SJohn Forte 		    sv_enable_err_baddev,
917fcf3ce44SJohn Forte 		    dev_t, udev);
918fcf3ce44SJohn Forte 		return (SV_EBADDEV);
919fcf3ce44SJohn Forte 	}
920fcf3ce44SJohn Forte 
921fcf3ce44SJohn Forte 	if ((flag & ~(NSC_CACHE|NSC_DEVICE)) != 0) {
922fcf3ce44SJohn Forte 		DTRACE_PROBE1(sv_enable_err_amode, dev_t, udev);
923fcf3ce44SJohn Forte 		return (SV_EAMODE);
924fcf3ce44SJohn Forte 	}
925fcf3ce44SJohn Forte 
926fcf3ce44SJohn Forte 	/* Get major hash table */
927fcf3ce44SJohn Forte 	if ((maj = sv_getmajor(udev)) == NULL)
928fcf3ce44SJohn Forte 		return (SV_EBADDEV);
929fcf3ce44SJohn Forte 
930fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
931fcf3ce44SJohn Forte 
932fcf3ce44SJohn Forte 	rc = sv_get_state(udev, &svp);
933fcf3ce44SJohn Forte 	if (rc) {
934fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
9353270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_enable_err_state, dev_t, udev);
936fcf3ce44SJohn Forte 		return (rc);
937fcf3ce44SJohn Forte 	}
938fcf3ce44SJohn Forte 
939fcf3ce44SJohn Forte 	rw_enter(&svp->sv_lock, RW_WRITER);
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 	/*
942fcf3ce44SJohn Forte 	 * Get real fd used for io
943fcf3ce44SJohn Forte 	 */
944fcf3ce44SJohn Forte 
945fcf3ce44SJohn Forte 	svp->sv_dev = udev;
946fcf3ce44SJohn Forte 	svp->sv_flag = flag;
947fcf3ce44SJohn Forte 
948fcf3ce44SJohn Forte 	/*
949fcf3ce44SJohn Forte 	 * OR in NSC_DEVICE to ensure that nskern grabs the real strategy
950fcf3ce44SJohn Forte 	 * function pointer before sv swaps them out.
951fcf3ce44SJohn Forte 	 */
952fcf3ce44SJohn Forte 
953fcf3ce44SJohn Forte 	svp->sv_fd = nsc_open(path, (svp->sv_flag | NSC_DEVICE),
954fcf3ce44SJohn Forte 	    sv_fd_def, (blind_t)udev, &rc);
955fcf3ce44SJohn Forte 
956fcf3ce44SJohn Forte 	if (svp->sv_fd == NULL) {
957fcf3ce44SJohn Forte 		if (kstatus)
958fcf3ce44SJohn Forte 			spcs_s_add(kstatus, rc);
9593270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_enable_err_fd, dev_t, udev);
960fcf3ce44SJohn Forte 		return (sv_free(svp, SV_ESDOPEN));
961fcf3ce44SJohn Forte 	}
962fcf3ce44SJohn Forte 
963fcf3ce44SJohn Forte 	/*
964fcf3ce44SJohn Forte 	 * Perform a layered driver open using the Sun Private layered
965fcf3ce44SJohn Forte 	 * driver i/f to ensure that the cb_ops structure for the driver
966fcf3ce44SJohn Forte 	 * is not detached out from under us whilst sv is enabled.
967fcf3ce44SJohn Forte 	 *
968fcf3ce44SJohn Forte 	 */
969fcf3ce44SJohn Forte 
970fcf3ce44SJohn Forte 	crp = ddi_get_cred();
971fcf3ce44SJohn Forte 	svp->sv_lh = NULL;
972fcf3ce44SJohn Forte 
973fcf3ce44SJohn Forte 	if ((rc = ldi_ident_from_dev(svp->sv_dev, &li)) == 0) {
974fcf3ce44SJohn Forte 		rc = ldi_open_by_dev(&svp->sv_dev,
975fcf3ce44SJohn Forte 		    OTYP_BLK, FREAD|FWRITE, crp, &svp->sv_lh, li);
976fcf3ce44SJohn Forte 	}
977fcf3ce44SJohn Forte 
978fcf3ce44SJohn Forte 	if (rc != 0) {
979fcf3ce44SJohn Forte 		if (kstatus)
980fcf3ce44SJohn Forte 			spcs_s_add(kstatus, rc);
9813270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_enable_err_lyr_open, dev_t, udev);
982fcf3ce44SJohn Forte 		return (sv_free(svp, SV_ELYROPEN));
983fcf3ce44SJohn Forte 	}
984fcf3ce44SJohn Forte 
985fcf3ce44SJohn Forte 	/*
986fcf3ce44SJohn Forte 	 * Do layering if required - must happen after nsc_open().
987fcf3ce44SJohn Forte 	 */
988fcf3ce44SJohn Forte 
989fcf3ce44SJohn Forte 	if (maj->sm_inuse++ == 0) {
990fcf3ce44SJohn Forte 		maj->sm_dev_ops = nsc_get_devops(getmajor(udev));
991fcf3ce44SJohn Forte 
992fcf3ce44SJohn Forte 		if (maj->sm_dev_ops == NULL ||
993fcf3ce44SJohn Forte 		    maj->sm_dev_ops->devo_cb_ops == NULL) {
9943270659fSSrikanth, Ramana 			DTRACE_PROBE1(sv_enable_err_load, dev_t, udev);
995fcf3ce44SJohn Forte 			return (sv_free(svp, SV_ELOAD));
996fcf3ce44SJohn Forte 		}
997fcf3ce44SJohn Forte 
998fcf3ce44SJohn Forte 		dev_ops = maj->sm_dev_ops;
999fcf3ce44SJohn Forte 		cb_ops = dev_ops->devo_cb_ops;
1000fcf3ce44SJohn Forte 
1001fcf3ce44SJohn Forte 		if (cb_ops->cb_strategy == NULL ||
1002fcf3ce44SJohn Forte 		    cb_ops->cb_strategy == nodev ||
1003fcf3ce44SJohn Forte 		    cb_ops->cb_strategy == nulldev) {
10043270659fSSrikanth, Ramana 			DTRACE_PROBE1(sv_enable_err_nostrategy, dev_t, udev);
1005fcf3ce44SJohn Forte 			return (sv_free(svp, SV_ELOAD));
1006fcf3ce44SJohn Forte 		}
1007fcf3ce44SJohn Forte 
1008fcf3ce44SJohn Forte 		if (cb_ops->cb_strategy == sv_lyr_strategy) {
10093270659fSSrikanth, Ramana 			DTRACE_PROBE1(sv_enable_err_svstrategy, dev_t, udev);
1010fcf3ce44SJohn Forte 			return (sv_free(svp, SV_ESTRATEGY));
1011fcf3ce44SJohn Forte 		}
1012fcf3ce44SJohn Forte 
1013fcf3ce44SJohn Forte 		maj->sm_strategy = cb_ops->cb_strategy;
1014fcf3ce44SJohn Forte 		maj->sm_close = cb_ops->cb_close;
1015fcf3ce44SJohn Forte 		maj->sm_ioctl = cb_ops->cb_ioctl;
1016fcf3ce44SJohn Forte 		maj->sm_write = cb_ops->cb_write;
1017fcf3ce44SJohn Forte 		maj->sm_open = cb_ops->cb_open;
1018fcf3ce44SJohn Forte 		maj->sm_read = cb_ops->cb_read;
1019fcf3ce44SJohn Forte 		maj->sm_flag = cb_ops->cb_flag;
1020fcf3ce44SJohn Forte 
1021fcf3ce44SJohn Forte 		cb_ops->cb_flag = cb_ops->cb_flag | D_MP;
1022fcf3ce44SJohn Forte 		cb_ops->cb_strategy = sv_lyr_strategy;
1023fcf3ce44SJohn Forte 		cb_ops->cb_close = sv_lyr_close;
1024fcf3ce44SJohn Forte 		cb_ops->cb_ioctl = sv_lyr_ioctl;
1025fcf3ce44SJohn Forte 		cb_ops->cb_write = sv_lyr_write;
1026fcf3ce44SJohn Forte 		cb_ops->cb_open = sv_lyr_open;
1027fcf3ce44SJohn Forte 		cb_ops->cb_read = sv_lyr_read;
1028fcf3ce44SJohn Forte 
1029fcf3ce44SJohn Forte 		/*
1030fcf3ce44SJohn Forte 		 * Check that the driver has async I/O entry points
1031fcf3ce44SJohn Forte 		 * before changing them.
1032fcf3ce44SJohn Forte 		 */
1033fcf3ce44SJohn Forte 
1034fcf3ce44SJohn Forte 		if (dev_ops->devo_rev < 3 || cb_ops->cb_rev < 1) {
1035fcf3ce44SJohn Forte 			maj->sm_awrite = 0;
1036fcf3ce44SJohn Forte 			maj->sm_aread = 0;
1037fcf3ce44SJohn Forte 		} else {
1038fcf3ce44SJohn Forte 			maj->sm_awrite = cb_ops->cb_awrite;
1039fcf3ce44SJohn Forte 			maj->sm_aread = cb_ops->cb_aread;
1040fcf3ce44SJohn Forte 
1041fcf3ce44SJohn Forte 			cb_ops->cb_awrite = sv_lyr_awrite;
1042fcf3ce44SJohn Forte 			cb_ops->cb_aread = sv_lyr_aread;
1043fcf3ce44SJohn Forte 		}
1044fcf3ce44SJohn Forte 
1045fcf3ce44SJohn Forte 		/*
1046fcf3ce44SJohn Forte 		 * Bug 4645743
1047fcf3ce44SJohn Forte 		 *
1048fcf3ce44SJohn Forte 		 * Prevent sv from ever unloading after it has interposed
1049fcf3ce44SJohn Forte 		 * on a major device because there is a race between
1050fcf3ce44SJohn Forte 		 * sv removing its layered entry points from the target
1051fcf3ce44SJohn Forte 		 * dev_ops, a client coming in and accessing the driver,
1052fcf3ce44SJohn Forte 		 * and the kernel modunloading the sv text.
1053fcf3ce44SJohn Forte 		 *
1054fcf3ce44SJohn Forte 		 * To allow unload, do svboot -u, which only happens in
1055fcf3ce44SJohn Forte 		 * pkgrm time.
1056fcf3ce44SJohn Forte 		 */
1057fcf3ce44SJohn Forte 		ASSERT(MUTEX_HELD(&sv_mutex));
1058fcf3ce44SJohn Forte 		sv_mod_status = SV_PREVENT_UNLOAD;
1059fcf3ce44SJohn Forte 	}
1060fcf3ce44SJohn Forte 
1061fcf3ce44SJohn Forte 
1062fcf3ce44SJohn Forte 	svp->sv_timestamp = nsc_lbolt();
1063fcf3ce44SJohn Forte 	svp->sv_state = SV_ENABLE;
1064fcf3ce44SJohn Forte 	svp->sv_pending = NULL;
1065fcf3ce44SJohn Forte 	rw_exit(&svp->sv_lock);
1066fcf3ce44SJohn Forte 
1067fcf3ce44SJohn Forte 	sv_ndevices++;
1068fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
1069fcf3ce44SJohn Forte 
1070fcf3ce44SJohn Forte 	nblocks = 0;
1071fcf3ce44SJohn Forte 	if (sv_reserve(svp->sv_fd, NSC_READ|NSC_MULTI|NSC_PCATCH) == 0) {
1072fcf3ce44SJohn Forte 		nblocks = svp->sv_nblocks;
1073fcf3ce44SJohn Forte 		nsc_release(svp->sv_fd);
1074fcf3ce44SJohn Forte 	}
1075fcf3ce44SJohn Forte 
1076fcf3ce44SJohn Forte 	cmn_err(CE_CONT, "!sv: rdev 0x%lx, nblocks %" NSC_SZFMT "\n",
1077fcf3ce44SJohn Forte 	    svp->sv_dev, nblocks);
1078fcf3ce44SJohn Forte 
1079fcf3ce44SJohn Forte 	return (0);
1080fcf3ce44SJohn Forte }
1081fcf3ce44SJohn Forte 
1082fcf3ce44SJohn Forte 
1083fcf3ce44SJohn Forte static int
sv_prepare_unload()1084fcf3ce44SJohn Forte sv_prepare_unload()
1085fcf3ce44SJohn Forte {
1086fcf3ce44SJohn Forte 	int rc = 0;
1087fcf3ce44SJohn Forte 
1088fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
1089fcf3ce44SJohn Forte 
1090fcf3ce44SJohn Forte 	if (sv_mod_status == SV_PREVENT_UNLOAD) {
1091fcf3ce44SJohn Forte 		if ((sv_ndevices != 0) || (sv_tset != NULL)) {
1092fcf3ce44SJohn Forte 			rc = EBUSY;
1093fcf3ce44SJohn Forte 		} else {
1094fcf3ce44SJohn Forte 			sv_mod_status = SV_ALLOW_UNLOAD;
1095fcf3ce44SJohn Forte 			delay(SV_WAIT_UNLOAD * drv_usectohz(1000000));
1096fcf3ce44SJohn Forte 		}
1097fcf3ce44SJohn Forte 	}
1098fcf3ce44SJohn Forte 
1099fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
1100fcf3ce44SJohn Forte 	return (rc);
1101fcf3ce44SJohn Forte }
1102fcf3ce44SJohn Forte 
1103fcf3ce44SJohn Forte static int
svattach_fd(blind_t arg)1104fcf3ce44SJohn Forte svattach_fd(blind_t arg)
1105fcf3ce44SJohn Forte {
1106fcf3ce44SJohn Forte 	dev_t dev = (dev_t)arg;
1107fcf3ce44SJohn Forte 	sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
1108fcf3ce44SJohn Forte 	int rc;
1109fcf3ce44SJohn Forte 
1110fcf3ce44SJohn Forte 	if (sv_debug > 0)
11113270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!svattach_fd(%p, %p)\n", arg, (void *)svp);
1112fcf3ce44SJohn Forte 
1113fcf3ce44SJohn Forte 	if (svp == NULL) {
1114fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "!svattach_fd: no state (arg %p)", arg);
1115fcf3ce44SJohn Forte 		return (0);
1116fcf3ce44SJohn Forte 	}
1117fcf3ce44SJohn Forte 
1118fcf3ce44SJohn Forte 	if ((rc = nsc_partsize(svp->sv_fd, &svp->sv_nblocks)) != 0) {
1119fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
1120fcf3ce44SJohn Forte 		    "!svattach_fd: nsc_partsize() failed, rc %d", rc);
1121fcf3ce44SJohn Forte 		svp->sv_nblocks = 0;
1122fcf3ce44SJohn Forte 	}
1123fcf3ce44SJohn Forte 
1124fcf3ce44SJohn Forte 	if ((rc = nsc_maxfbas(svp->sv_fd, 0, &svp->sv_maxfbas)) != 0) {
1125fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
1126fcf3ce44SJohn Forte 		    "!svattach_fd: nsc_maxfbas() failed, rc %d", rc);
1127fcf3ce44SJohn Forte 		svp->sv_maxfbas = 0;
1128fcf3ce44SJohn Forte 	}
1129fcf3ce44SJohn Forte 
1130fcf3ce44SJohn Forte 	if (sv_debug > 0) {
1131fcf3ce44SJohn Forte 		cmn_err(CE_CONT,
11323270659fSSrikanth, Ramana 		    "!svattach_fd(%p): size %" NSC_SZFMT ", "
1133fcf3ce44SJohn Forte 		    "maxfbas %" NSC_SZFMT "\n",
1134fcf3ce44SJohn Forte 		    arg, svp->sv_nblocks, svp->sv_maxfbas);
1135fcf3ce44SJohn Forte 	}
1136fcf3ce44SJohn Forte 
1137fcf3ce44SJohn Forte 	return (0);
1138fcf3ce44SJohn Forte }
1139fcf3ce44SJohn Forte 
1140fcf3ce44SJohn Forte 
1141fcf3ce44SJohn Forte static int
svdetach_fd(blind_t arg)1142fcf3ce44SJohn Forte svdetach_fd(blind_t arg)
1143fcf3ce44SJohn Forte {
1144fcf3ce44SJohn Forte 	dev_t dev = (dev_t)arg;
1145fcf3ce44SJohn Forte 	sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
1146fcf3ce44SJohn Forte 
1147fcf3ce44SJohn Forte 	if (sv_debug > 0)
11483270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!svdetach_fd(%p, %p)\n", arg, (void *)svp);
1149fcf3ce44SJohn Forte 
1150fcf3ce44SJohn Forte 	/* svp can be NULL during disable of an sv */
1151fcf3ce44SJohn Forte 	if (svp == NULL)
1152fcf3ce44SJohn Forte 		return (0);
1153fcf3ce44SJohn Forte 
1154fcf3ce44SJohn Forte 	svp->sv_maxfbas = 0;
1155fcf3ce44SJohn Forte 	svp->sv_nblocks = 0;
1156fcf3ce44SJohn Forte 	return (0);
1157fcf3ce44SJohn Forte }
1158fcf3ce44SJohn Forte 
1159fcf3ce44SJohn Forte 
1160fcf3ce44SJohn Forte /*
1161fcf3ce44SJohn Forte  * Side effect: if called with (guard != 0), then expects both sv_mutex
1162fcf3ce44SJohn Forte  * and sv_lock(RW_WRITER) to be held, and will release them before returning.
1163fcf3ce44SJohn Forte  */
1164fcf3ce44SJohn Forte 
1165fcf3ce44SJohn Forte /* ARGSUSED */
1166fcf3ce44SJohn Forte static int
sv_disable(dev_t dev,spcs_s_info_t kstatus)1167fcf3ce44SJohn Forte sv_disable(dev_t dev, spcs_s_info_t kstatus)
1168fcf3ce44SJohn Forte {
1169fcf3ce44SJohn Forte 	sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
1170fcf3ce44SJohn Forte 
1171fcf3ce44SJohn Forte 	if (svp == NULL) {
1172fcf3ce44SJohn Forte 
1173fcf3ce44SJohn Forte 		DTRACE_PROBE1(sv_disable_err_nodev, sv_dev_t *, svp);
1174fcf3ce44SJohn Forte 		return (SV_ENODEV);
1175fcf3ce44SJohn Forte 	}
1176fcf3ce44SJohn Forte 
1177fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
1178fcf3ce44SJohn Forte 	rw_enter(&svp->sv_lock, RW_WRITER);
1179fcf3ce44SJohn Forte 
1180fcf3ce44SJohn Forte 	if (svp->sv_fd == NULL || svp->sv_state != SV_ENABLE) {
1181fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
1182fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
1183fcf3ce44SJohn Forte 
1184fcf3ce44SJohn Forte 		DTRACE_PROBE1(sv_disable_err_disabled, sv_dev_t *, svp);
1185fcf3ce44SJohn Forte 		return (SV_EDISABLED);
1186fcf3ce44SJohn Forte 	}
1187fcf3ce44SJohn Forte 
1188fcf3ce44SJohn Forte 
1189fcf3ce44SJohn Forte 	sv_ndevices--;
1190fcf3ce44SJohn Forte 	return (sv_free(svp, 0));
1191fcf3ce44SJohn Forte }
1192fcf3ce44SJohn Forte 
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 
1195fcf3ce44SJohn Forte static int
sv_lyr_open(dev_t * devp,int flag,int otyp,cred_t * crp)1196fcf3ce44SJohn Forte sv_lyr_open(dev_t *devp, int flag, int otyp, cred_t *crp)
1197fcf3ce44SJohn Forte {
1198fcf3ce44SJohn Forte 	nsc_buf_t *tmph;
1199fcf3ce44SJohn Forte 	sv_dev_t *svp;
1200fcf3ce44SJohn Forte 	sv_maj_t *maj;
1201fcf3ce44SJohn Forte 	int (*fn)();
1202fcf3ce44SJohn Forte 	dev_t odev;
1203fcf3ce44SJohn Forte 	int ret;
1204fcf3ce44SJohn Forte 	int rc;
1205fcf3ce44SJohn Forte 
1206fcf3ce44SJohn Forte 	svp = sv_dev_to_sv(*devp, &maj);
1207fcf3ce44SJohn Forte 
1208fcf3ce44SJohn Forte 	if (svp) {
1209fcf3ce44SJohn Forte 		if (svp->sv_state == SV_PENDING &&
1210fcf3ce44SJohn Forte 		    svp->sv_pending == curthread) {
1211fcf3ce44SJohn Forte 			/*
1212fcf3ce44SJohn Forte 			 * This is a recursive open from a call to
1213fcf3ce44SJohn Forte 			 * ddi_lyr_open_by_devt and so we just want
1214fcf3ce44SJohn Forte 			 * to pass it straight through to the
1215fcf3ce44SJohn Forte 			 * underlying driver.
1216fcf3ce44SJohn Forte 			 */
1217fcf3ce44SJohn Forte 			DTRACE_PROBE2(sv_lyr_open_recursive,
1218fcf3ce44SJohn Forte 			    sv_dev_t *, svp,
1219fcf3ce44SJohn Forte 			    dev_t, *devp);
1220fcf3ce44SJohn Forte 			svp = NULL;
1221fcf3ce44SJohn Forte 		} else
1222fcf3ce44SJohn Forte 			rw_enter(&svp->sv_lock, RW_READER);
1223fcf3ce44SJohn Forte 	}
1224fcf3ce44SJohn Forte 
1225fcf3ce44SJohn Forte 	odev = *devp;
1226fcf3ce44SJohn Forte 
1227fcf3ce44SJohn Forte 	if (maj && (fn = maj->sm_open) != 0) {
1228fcf3ce44SJohn Forte 		if (!(maj->sm_flag & D_MP)) {
1229fcf3ce44SJohn Forte 			UNSAFE_ENTER();
1230fcf3ce44SJohn Forte 			ret = (*fn)(devp, flag, otyp, crp);
1231fcf3ce44SJohn Forte 			UNSAFE_EXIT();
1232fcf3ce44SJohn Forte 		} else {
1233fcf3ce44SJohn Forte 			ret = (*fn)(devp, flag, otyp, crp);
1234fcf3ce44SJohn Forte 		}
1235fcf3ce44SJohn Forte 
1236fcf3ce44SJohn Forte 		if (ret == 0) {
1237fcf3ce44SJohn Forte 			/*
1238fcf3ce44SJohn Forte 			 * Re-acquire svp if the driver changed *devp.
1239fcf3ce44SJohn Forte 			 */
1240fcf3ce44SJohn Forte 
1241fcf3ce44SJohn Forte 			if (*devp != odev) {
1242b2514ea1SDan McDonald 				if (svp != NULL)
1243fcf3ce44SJohn Forte 					rw_exit(&svp->sv_lock);
1244fcf3ce44SJohn Forte 
1245fcf3ce44SJohn Forte 				svp = sv_dev_to_sv(*devp, NULL);
1246fcf3ce44SJohn Forte 
1247fcf3ce44SJohn Forte 				if (svp) {
1248fcf3ce44SJohn Forte 					rw_enter(&svp->sv_lock, RW_READER);
1249fcf3ce44SJohn Forte 				}
1250fcf3ce44SJohn Forte 			}
1251fcf3ce44SJohn Forte 		}
1252fcf3ce44SJohn Forte 	} else {
1253fcf3ce44SJohn Forte 		ret = ENODEV;
1254fcf3ce44SJohn Forte 	}
1255fcf3ce44SJohn Forte 
1256fcf3ce44SJohn Forte 	if (svp && ret != 0 && svp->sv_state == SV_ENABLE) {
1257fcf3ce44SJohn Forte 		/*
1258fcf3ce44SJohn Forte 		 * Underlying DDI open failed, but we have this
1259fcf3ce44SJohn Forte 		 * device SV enabled.  If we can read some data
1260fcf3ce44SJohn Forte 		 * from the device, fake a successful open (this
1261fcf3ce44SJohn Forte 		 * probably means that this device is RDC'd and we
1262fcf3ce44SJohn Forte 		 * are getting the data from the secondary node).
1263fcf3ce44SJohn Forte 		 *
1264fcf3ce44SJohn Forte 		 * The reserve must be done with NSC_TRY|NSC_NOWAIT to
1265fcf3ce44SJohn Forte 		 * ensure that it does not deadlock if this open is
1266fcf3ce44SJohn Forte 		 * coming from nskernd:get_bsize().
1267fcf3ce44SJohn Forte 		 */
1268fcf3ce44SJohn Forte 		rc = sv_reserve(svp->sv_fd,
1269fcf3ce44SJohn Forte 		    NSC_TRY | NSC_NOWAIT | NSC_MULTI | NSC_PCATCH);
1270fcf3ce44SJohn Forte 		if (rc == 0) {
1271fcf3ce44SJohn Forte 			tmph = NULL;
1272fcf3ce44SJohn Forte 
1273fcf3ce44SJohn Forte 			rc = nsc_alloc_buf(svp->sv_fd, 0, 1, NSC_READ, &tmph);
1274fcf3ce44SJohn Forte 			if (rc <= 0) {
1275fcf3ce44SJohn Forte 				/* success */
1276fcf3ce44SJohn Forte 				ret = 0;
1277fcf3ce44SJohn Forte 			}
1278fcf3ce44SJohn Forte 
1279fcf3ce44SJohn Forte 			if (tmph) {
1280fcf3ce44SJohn Forte 				(void) nsc_free_buf(tmph);
1281fcf3ce44SJohn Forte 				tmph = NULL;
1282fcf3ce44SJohn Forte 			}
1283fcf3ce44SJohn Forte 
1284fcf3ce44SJohn Forte 			nsc_release(svp->sv_fd);
1285fcf3ce44SJohn Forte 
1286fcf3ce44SJohn Forte 			/*
1287fcf3ce44SJohn Forte 			 * Count the number of layered opens that we
1288fcf3ce44SJohn Forte 			 * fake since we have to fake a matching number
1289fcf3ce44SJohn Forte 			 * of closes (OTYP_LYR open/close calls must be
1290fcf3ce44SJohn Forte 			 * paired).
1291fcf3ce44SJohn Forte 			 */
1292fcf3ce44SJohn Forte 
1293fcf3ce44SJohn Forte 			if (ret == 0 && otyp == OTYP_LYR) {
1294fcf3ce44SJohn Forte 				mutex_enter(&svp->sv_olock);
1295fcf3ce44SJohn Forte 				svp->sv_openlcnt++;
1296fcf3ce44SJohn Forte 				mutex_exit(&svp->sv_olock);
1297fcf3ce44SJohn Forte 			}
1298fcf3ce44SJohn Forte 		}
1299fcf3ce44SJohn Forte 	}
1300fcf3ce44SJohn Forte 
1301fcf3ce44SJohn Forte 	if (svp) {
1302fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
1303fcf3ce44SJohn Forte 	}
1304fcf3ce44SJohn Forte 
1305fcf3ce44SJohn Forte 	return (ret);
1306fcf3ce44SJohn Forte }
1307fcf3ce44SJohn Forte 
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte static int
sv_lyr_close(dev_t dev,int flag,int otyp,cred_t * crp)1310fcf3ce44SJohn Forte sv_lyr_close(dev_t dev, int flag, int otyp, cred_t *crp)
1311fcf3ce44SJohn Forte {
1312fcf3ce44SJohn Forte 	sv_dev_t *svp;
1313fcf3ce44SJohn Forte 	sv_maj_t *maj;
1314fcf3ce44SJohn Forte 	int (*fn)();
1315fcf3ce44SJohn Forte 	int ret;
1316fcf3ce44SJohn Forte 
1317fcf3ce44SJohn Forte 	svp = sv_dev_to_sv(dev, &maj);
1318fcf3ce44SJohn Forte 
1319fcf3ce44SJohn Forte 	if (svp &&
1320fcf3ce44SJohn Forte 	    svp->sv_state == SV_PENDING &&
1321fcf3ce44SJohn Forte 	    svp->sv_pending == curthread) {
1322fcf3ce44SJohn Forte 		/*
1323fcf3ce44SJohn Forte 		 * This is a recursive open from a call to
1324fcf3ce44SJohn Forte 		 * ddi_lyr_close and so we just want
1325fcf3ce44SJohn Forte 		 * to pass it straight through to the
1326fcf3ce44SJohn Forte 		 * underlying driver.
1327fcf3ce44SJohn Forte 		 */
13283270659fSSrikanth, Ramana 		DTRACE_PROBE2(sv_lyr_close_recursive, sv_dev_t *, svp,
1329fcf3ce44SJohn Forte 		    dev_t, dev);
1330fcf3ce44SJohn Forte 		svp = NULL;
1331fcf3ce44SJohn Forte 	}
1332fcf3ce44SJohn Forte 
1333fcf3ce44SJohn Forte 	if (svp) {
1334fcf3ce44SJohn Forte 		rw_enter(&svp->sv_lock, RW_READER);
1335fcf3ce44SJohn Forte 
1336fcf3ce44SJohn Forte 		if (otyp == OTYP_LYR) {
1337fcf3ce44SJohn Forte 			mutex_enter(&svp->sv_olock);
1338fcf3ce44SJohn Forte 
1339fcf3ce44SJohn Forte 			if (svp->sv_openlcnt) {
1340fcf3ce44SJohn Forte 				/*
1341fcf3ce44SJohn Forte 				 * Consume sufficient layered closes to
1342fcf3ce44SJohn Forte 				 * account for the opens that we faked
1343fcf3ce44SJohn Forte 				 * whilst the device was failed.
1344fcf3ce44SJohn Forte 				 */
1345fcf3ce44SJohn Forte 				svp->sv_openlcnt--;
1346fcf3ce44SJohn Forte 				mutex_exit(&svp->sv_olock);
1347fcf3ce44SJohn Forte 				rw_exit(&svp->sv_lock);
1348fcf3ce44SJohn Forte 
13493270659fSSrikanth, Ramana 				DTRACE_PROBE1(sv_lyr_close_end, dev_t, dev);
1350fcf3ce44SJohn Forte 
1351fcf3ce44SJohn Forte 				return (0);
1352fcf3ce44SJohn Forte 			}
1353fcf3ce44SJohn Forte 
1354fcf3ce44SJohn Forte 			mutex_exit(&svp->sv_olock);
1355fcf3ce44SJohn Forte 		}
1356fcf3ce44SJohn Forte 	}
1357fcf3ce44SJohn Forte 
1358fcf3ce44SJohn Forte 	if (maj && (fn = maj->sm_close) != 0) {
1359fcf3ce44SJohn Forte 		if (!(maj->sm_flag & D_MP)) {
1360fcf3ce44SJohn Forte 			UNSAFE_ENTER();
1361fcf3ce44SJohn Forte 			ret = (*fn)(dev, flag, otyp, crp);
1362fcf3ce44SJohn Forte 			UNSAFE_EXIT();
1363fcf3ce44SJohn Forte 		} else {
1364fcf3ce44SJohn Forte 			ret = (*fn)(dev, flag, otyp, crp);
1365fcf3ce44SJohn Forte 		}
1366fcf3ce44SJohn Forte 	} else {
1367fcf3ce44SJohn Forte 		ret = ENODEV;
1368fcf3ce44SJohn Forte 	}
1369fcf3ce44SJohn Forte 
1370fcf3ce44SJohn Forte 	if (svp) {
1371fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
1372fcf3ce44SJohn Forte 	}
1373fcf3ce44SJohn Forte 
1374fcf3ce44SJohn Forte 	return (ret);
1375fcf3ce44SJohn Forte }
1376fcf3ce44SJohn Forte 
1377fcf3ce44SJohn Forte 
1378fcf3ce44SJohn Forte /*
1379fcf3ce44SJohn Forte  * Convert the specified dev_t into a locked and enabled sv_dev_t, or
1380fcf3ce44SJohn Forte  * return NULL.
1381fcf3ce44SJohn Forte  */
1382fcf3ce44SJohn Forte static sv_dev_t *
sv_find_enabled(const dev_t dev,sv_maj_t ** majpp)1383fcf3ce44SJohn Forte sv_find_enabled(const dev_t dev, sv_maj_t **majpp)
1384fcf3ce44SJohn Forte {
1385fcf3ce44SJohn Forte 	sv_dev_t *svp;
1386fcf3ce44SJohn Forte 
1387fcf3ce44SJohn Forte 	while ((svp = sv_dev_to_sv(dev, majpp)) != NULL) {
1388fcf3ce44SJohn Forte 		rw_enter(&svp->sv_lock, RW_READER);
1389fcf3ce44SJohn Forte 
1390fcf3ce44SJohn Forte 		if (svp->sv_state == SV_ENABLE) {
1391fcf3ce44SJohn Forte 			/* locked and enabled */
1392fcf3ce44SJohn Forte 			break;
1393fcf3ce44SJohn Forte 		}
1394fcf3ce44SJohn Forte 
1395fcf3ce44SJohn Forte 		/*
1396fcf3ce44SJohn Forte 		 * State was changed while waiting on the lock.
1397fcf3ce44SJohn Forte 		 * Wait for a stable state.
1398fcf3ce44SJohn Forte 		 */
1399fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
1400fcf3ce44SJohn Forte 
14013270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_find_enabled_retry, dev_t, dev);
1402fcf3ce44SJohn Forte 
1403fcf3ce44SJohn Forte 		delay(2);
1404fcf3ce44SJohn Forte 	}
1405fcf3ce44SJohn Forte 
1406fcf3ce44SJohn Forte 	return (svp);
1407fcf3ce44SJohn Forte }
1408fcf3ce44SJohn Forte 
1409fcf3ce44SJohn Forte 
1410fcf3ce44SJohn Forte static int
sv_lyr_uio(dev_t dev,uio_t * uiop,cred_t * crp,int rw)1411fcf3ce44SJohn Forte sv_lyr_uio(dev_t dev, uio_t *uiop, cred_t *crp, int rw)
1412fcf3ce44SJohn Forte {
1413fcf3ce44SJohn Forte 	sv_dev_t *svp;
1414fcf3ce44SJohn Forte 	sv_maj_t *maj;
1415fcf3ce44SJohn Forte 	int (*fn)();
1416fcf3ce44SJohn Forte 	int rc;
1417fcf3ce44SJohn Forte 
1418fcf3ce44SJohn Forte 	svp = sv_find_enabled(dev, &maj);
1419fcf3ce44SJohn Forte 	if (svp == NULL) {
1420fcf3ce44SJohn Forte 		if (maj) {
1421fcf3ce44SJohn Forte 			if (rw == NSC_READ)
1422fcf3ce44SJohn Forte 				fn = maj->sm_read;
1423fcf3ce44SJohn Forte 			else
1424fcf3ce44SJohn Forte 				fn = maj->sm_write;
1425fcf3ce44SJohn Forte 
1426fcf3ce44SJohn Forte 			if (fn != 0) {
1427fcf3ce44SJohn Forte 				if (!(maj->sm_flag & D_MP)) {
1428fcf3ce44SJohn Forte 					UNSAFE_ENTER();
1429fcf3ce44SJohn Forte 					rc = (*fn)(dev, uiop, crp);
1430fcf3ce44SJohn Forte 					UNSAFE_EXIT();
1431fcf3ce44SJohn Forte 				} else {
1432fcf3ce44SJohn Forte 					rc = (*fn)(dev, uiop, crp);
1433fcf3ce44SJohn Forte 				}
1434fcf3ce44SJohn Forte 			}
1435fcf3ce44SJohn Forte 
1436fcf3ce44SJohn Forte 			return (rc);
1437fcf3ce44SJohn Forte 		} else {
1438fcf3ce44SJohn Forte 			return (ENODEV);
1439fcf3ce44SJohn Forte 		}
1440fcf3ce44SJohn Forte 	}
1441fcf3ce44SJohn Forte 
1442fcf3ce44SJohn Forte 	ASSERT(RW_READ_HELD(&svp->sv_lock));
1443fcf3ce44SJohn Forte 
1444fcf3ce44SJohn Forte 	if (svp->sv_flag == 0) {
1445fcf3ce44SJohn Forte 		/*
1446fcf3ce44SJohn Forte 		 * guard access mode
1447fcf3ce44SJohn Forte 		 * - prevent user level access to the device
1448fcf3ce44SJohn Forte 		 */
14493270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_uio_err_guard, uio_t *, uiop);
1450fcf3ce44SJohn Forte 		rc = EPERM;
1451fcf3ce44SJohn Forte 		goto out;
1452fcf3ce44SJohn Forte 	}
1453fcf3ce44SJohn Forte 
1454fcf3ce44SJohn Forte 	if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
14553270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_uio_err_rsrv, uio_t *, uiop);
1456fcf3ce44SJohn Forte 		goto out;
1457fcf3ce44SJohn Forte 	}
1458fcf3ce44SJohn Forte 
1459fcf3ce44SJohn Forte 	if (rw == NSC_READ)
1460fcf3ce44SJohn Forte 		rc = nsc_uread(svp->sv_fd, uiop, crp);
1461fcf3ce44SJohn Forte 	else
1462fcf3ce44SJohn Forte 		rc = nsc_uwrite(svp->sv_fd, uiop, crp);
1463fcf3ce44SJohn Forte 
1464fcf3ce44SJohn Forte 	nsc_release(svp->sv_fd);
1465fcf3ce44SJohn Forte 
1466fcf3ce44SJohn Forte out:
1467fcf3ce44SJohn Forte 	rw_exit(&svp->sv_lock);
1468fcf3ce44SJohn Forte 
1469fcf3ce44SJohn Forte 	return (rc);
1470fcf3ce44SJohn Forte }
1471fcf3ce44SJohn Forte 
1472fcf3ce44SJohn Forte 
1473fcf3ce44SJohn Forte static int
sv_lyr_read(dev_t dev,uio_t * uiop,cred_t * crp)1474fcf3ce44SJohn Forte sv_lyr_read(dev_t dev, uio_t *uiop, cred_t *crp)
1475fcf3ce44SJohn Forte {
1476fcf3ce44SJohn Forte 	return (sv_lyr_uio(dev, uiop, crp, NSC_READ));
1477fcf3ce44SJohn Forte }
1478fcf3ce44SJohn Forte 
1479fcf3ce44SJohn Forte 
1480fcf3ce44SJohn Forte static int
sv_lyr_write(dev_t dev,uio_t * uiop,cred_t * crp)1481fcf3ce44SJohn Forte sv_lyr_write(dev_t dev, uio_t *uiop, cred_t *crp)
1482fcf3ce44SJohn Forte {
1483fcf3ce44SJohn Forte 	return (sv_lyr_uio(dev, uiop, crp, NSC_WRITE));
1484fcf3ce44SJohn Forte }
1485fcf3ce44SJohn Forte 
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte /* ARGSUSED */
1488fcf3ce44SJohn Forte 
1489fcf3ce44SJohn Forte static int
sv_lyr_aread(dev_t dev,struct aio_req * aio,cred_t * crp)1490fcf3ce44SJohn Forte sv_lyr_aread(dev_t dev, struct aio_req *aio, cred_t *crp)
1491fcf3ce44SJohn Forte {
1492fcf3ce44SJohn Forte 	return (aphysio(sv_lyr_strategy,
1493fcf3ce44SJohn Forte 	    anocancel, dev, B_READ, minphys, aio));
1494fcf3ce44SJohn Forte }
1495fcf3ce44SJohn Forte 
1496fcf3ce44SJohn Forte 
1497fcf3ce44SJohn Forte /* ARGSUSED */
1498fcf3ce44SJohn Forte 
1499fcf3ce44SJohn Forte static int
sv_lyr_awrite(dev_t dev,struct aio_req * aio,cred_t * crp)1500fcf3ce44SJohn Forte sv_lyr_awrite(dev_t dev, struct aio_req *aio, cred_t *crp)
1501fcf3ce44SJohn Forte {
1502fcf3ce44SJohn Forte 	return (aphysio(sv_lyr_strategy,
1503fcf3ce44SJohn Forte 	    anocancel, dev, B_WRITE, minphys, aio));
1504fcf3ce44SJohn Forte }
1505fcf3ce44SJohn Forte 
1506fcf3ce44SJohn Forte 
1507fcf3ce44SJohn Forte /*
1508fcf3ce44SJohn Forte  * Set up an array containing the list of raw path names
1509fcf3ce44SJohn Forte  * The array for the paths is svl and the size of the array is
1510fcf3ce44SJohn Forte  * in size.
1511fcf3ce44SJohn Forte  *
1512fcf3ce44SJohn Forte  * If there are more layered devices than will fit in the array,
1513fcf3ce44SJohn Forte  * the number of extra layered devices is returned.  Otherwise
1514fcf3ce44SJohn Forte  * zero is return.
1515fcf3ce44SJohn Forte  *
1516fcf3ce44SJohn Forte  * Input:
1517fcf3ce44SJohn Forte  *	svn	: array for paths
1518fcf3ce44SJohn Forte  *	size	: size of the array
1519fcf3ce44SJohn Forte  *
1520fcf3ce44SJohn Forte  * Output (extra):
1521fcf3ce44SJohn Forte  *	zero	: All paths fit in array
1522fcf3ce44SJohn Forte  *	>0	: Number of defined layered devices don't fit in array
1523fcf3ce44SJohn Forte  */
1524fcf3ce44SJohn Forte 
1525fcf3ce44SJohn Forte static int
sv_list(void * ptr,const int size,int * extra,const int ilp32)1526fcf3ce44SJohn Forte sv_list(void *ptr, const int size, int *extra, const int ilp32)
1527fcf3ce44SJohn Forte {
1528fcf3ce44SJohn Forte 	sv_name32_t *svn32;
1529fcf3ce44SJohn Forte 	sv_name_t *svn;
1530fcf3ce44SJohn Forte 	sv_dev_t *svp;
1531fcf3ce44SJohn Forte 	int *mode, *nblocks;
1532fcf3ce44SJohn Forte 	int i, index;
1533fcf3ce44SJohn Forte 	char *path;
1534fcf3ce44SJohn Forte 
1535fcf3ce44SJohn Forte 	*extra = 0;
1536fcf3ce44SJohn Forte 	index = 0;
1537fcf3ce44SJohn Forte 
1538fcf3ce44SJohn Forte 	if (ilp32)
1539fcf3ce44SJohn Forte 		svn32 = ptr;
1540fcf3ce44SJohn Forte 	else
1541fcf3ce44SJohn Forte 		svn = ptr;
1542fcf3ce44SJohn Forte 
1543fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
1544fcf3ce44SJohn Forte 	for (i = 0; i < sv_max_devices; i++) {
1545fcf3ce44SJohn Forte 		svp = &sv_devs[i];
1546fcf3ce44SJohn Forte 
1547fcf3ce44SJohn Forte 		rw_enter(&svp->sv_lock, RW_READER);
1548fcf3ce44SJohn Forte 
1549fcf3ce44SJohn Forte 		if (svp->sv_state != SV_ENABLE) {
1550fcf3ce44SJohn Forte 			rw_exit(&svp->sv_lock);
1551fcf3ce44SJohn Forte 			continue;
1552fcf3ce44SJohn Forte 		}
1553fcf3ce44SJohn Forte 
1554fcf3ce44SJohn Forte 		if ((*extra) != 0 || ptr == NULL) {
1555fcf3ce44SJohn Forte 			/* Another overflow entry */
1556fcf3ce44SJohn Forte 			rw_exit(&svp->sv_lock);
1557fcf3ce44SJohn Forte 			(*extra)++;
1558fcf3ce44SJohn Forte 			continue;
1559fcf3ce44SJohn Forte 		}
1560fcf3ce44SJohn Forte 
1561fcf3ce44SJohn Forte 		if (ilp32) {
1562fcf3ce44SJohn Forte 			nblocks = &svn32->svn_nblocks;
1563fcf3ce44SJohn Forte 			mode = &svn32->svn_mode;
1564fcf3ce44SJohn Forte 			path = svn32->svn_path;
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 			svn32->svn_timestamp = (uint32_t)svp->sv_timestamp;
1567fcf3ce44SJohn Forte 			svn32++;
1568fcf3ce44SJohn Forte 		} else {
1569fcf3ce44SJohn Forte 			nblocks = &svn->svn_nblocks;
1570fcf3ce44SJohn Forte 			mode = &svn->svn_mode;
1571fcf3ce44SJohn Forte 			path = svn->svn_path;
1572fcf3ce44SJohn Forte 
1573fcf3ce44SJohn Forte 			svn->svn_timestamp = svp->sv_timestamp;
1574fcf3ce44SJohn Forte 			svn++;
1575fcf3ce44SJohn Forte 		}
1576fcf3ce44SJohn Forte 
1577fcf3ce44SJohn Forte 		(void) strcpy(path, nsc_pathname(svp->sv_fd));
1578fcf3ce44SJohn Forte 		*nblocks = svp->sv_nblocks;
1579fcf3ce44SJohn Forte 		*mode = svp->sv_flag;
1580fcf3ce44SJohn Forte 
1581fcf3ce44SJohn Forte 		if (*nblocks == 0) {
1582fcf3ce44SJohn Forte 			if (sv_debug > 3)
15833270659fSSrikanth, Ramana 				cmn_err(CE_CONT, "!sv_list: need to reserve\n");
1584fcf3ce44SJohn Forte 
15853270659fSSrikanth, Ramana 			if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
1586fcf3ce44SJohn Forte 				*nblocks = svp->sv_nblocks;
1587fcf3ce44SJohn Forte 				nsc_release(svp->sv_fd);
1588fcf3ce44SJohn Forte 			}
1589fcf3ce44SJohn Forte 		}
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte 		if (++index >= size) {
1592fcf3ce44SJohn Forte 			/* Out of space */
1593fcf3ce44SJohn Forte 			(*extra)++;
1594fcf3ce44SJohn Forte 		}
1595fcf3ce44SJohn Forte 
1596fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
1597fcf3ce44SJohn Forte 	}
1598fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
1599fcf3ce44SJohn Forte 
1600fcf3ce44SJohn Forte 	if (index < size) {
1601fcf3ce44SJohn Forte 		/* NULL terminated list */
1602fcf3ce44SJohn Forte 		if (ilp32)
1603fcf3ce44SJohn Forte 			svn32->svn_path[0] = '\0';
1604fcf3ce44SJohn Forte 		else
1605fcf3ce44SJohn Forte 			svn->svn_path[0] = '\0';
1606fcf3ce44SJohn Forte 	}
1607fcf3ce44SJohn Forte 
1608fcf3ce44SJohn Forte 	return (0);
1609fcf3ce44SJohn Forte }
1610fcf3ce44SJohn Forte 
1611fcf3ce44SJohn Forte 
1612fcf3ce44SJohn Forte static void
sv_thread_tune(int threads)1613fcf3ce44SJohn Forte sv_thread_tune(int threads)
1614fcf3ce44SJohn Forte {
1615fcf3ce44SJohn Forte 	int incr = (threads > 0) ? 1 : -1;
1616fcf3ce44SJohn Forte 	int change = 0;
1617fcf3ce44SJohn Forte 	int nthreads;
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 	ASSERT(MUTEX_HELD(&sv_mutex));
1620fcf3ce44SJohn Forte 
1621fcf3ce44SJohn Forte 	if (sv_threads_extra) {
1622fcf3ce44SJohn Forte 		/* keep track of any additional threads requested */
1623fcf3ce44SJohn Forte 		if (threads > 0) {
1624fcf3ce44SJohn Forte 			sv_threads_extra += threads;
1625fcf3ce44SJohn Forte 			return;
1626fcf3ce44SJohn Forte 		}
1627fcf3ce44SJohn Forte 		threads = -threads;
1628fcf3ce44SJohn Forte 		if (threads >= sv_threads_extra) {
1629fcf3ce44SJohn Forte 			threads -= sv_threads_extra;
1630fcf3ce44SJohn Forte 			sv_threads_extra = 0;
1631fcf3ce44SJohn Forte 			/* fall through to while loop */
1632fcf3ce44SJohn Forte 		} else {
1633fcf3ce44SJohn Forte 			sv_threads_extra -= threads;
1634fcf3ce44SJohn Forte 			return;
1635fcf3ce44SJohn Forte 		}
1636fcf3ce44SJohn Forte 	} else if (threads > 0) {
1637fcf3ce44SJohn Forte 		/*
1638fcf3ce44SJohn Forte 		 * do not increase the number of threads beyond
1639fcf3ce44SJohn Forte 		 * sv_threads_max when doing dynamic thread tuning
1640fcf3ce44SJohn Forte 		 */
1641fcf3ce44SJohn Forte 		nthreads = nst_nthread(sv_tset);
1642fcf3ce44SJohn Forte 		if ((nthreads + threads) > sv_threads_max) {
1643fcf3ce44SJohn Forte 			sv_threads_extra = nthreads + threads - sv_threads_max;
1644fcf3ce44SJohn Forte 			threads = sv_threads_max - nthreads;
1645fcf3ce44SJohn Forte 			if (threads <= 0)
1646fcf3ce44SJohn Forte 				return;
1647fcf3ce44SJohn Forte 		}
1648fcf3ce44SJohn Forte 	}
1649fcf3ce44SJohn Forte 
1650fcf3ce44SJohn Forte 	if (threads < 0)
1651fcf3ce44SJohn Forte 		threads = -threads;
1652fcf3ce44SJohn Forte 
1653fcf3ce44SJohn Forte 	while (threads--) {
1654fcf3ce44SJohn Forte 		nthreads = nst_nthread(sv_tset);
1655fcf3ce44SJohn Forte 		sv_threads_needed += incr;
1656fcf3ce44SJohn Forte 
1657fcf3ce44SJohn Forte 		if (sv_threads_needed >= nthreads)
1658fcf3ce44SJohn Forte 			change += nst_add_thread(sv_tset, sv_threads_inc);
1659fcf3ce44SJohn Forte 		else if ((sv_threads_needed <
1660fcf3ce44SJohn Forte 		    (nthreads - (sv_threads_inc + sv_threads_hysteresis))) &&
1661fcf3ce44SJohn Forte 		    ((nthreads - sv_threads_inc) >= sv_threads))
1662fcf3ce44SJohn Forte 			change -= nst_del_thread(sv_tset, sv_threads_inc);
1663fcf3ce44SJohn Forte 	}
1664fcf3ce44SJohn Forte 
1665fcf3ce44SJohn Forte #ifdef DEBUG
1666fcf3ce44SJohn Forte 	if (change) {
1667fcf3ce44SJohn Forte 		cmn_err(CE_NOTE,
16683270659fSSrikanth, Ramana 		    "!sv_thread_tune: threads needed %d, nthreads %d, "
1669fcf3ce44SJohn Forte 		    "nthreads change %d",
1670fcf3ce44SJohn Forte 		    sv_threads_needed, nst_nthread(sv_tset), change);
1671fcf3ce44SJohn Forte 	}
1672fcf3ce44SJohn Forte #endif
1673fcf3ce44SJohn Forte }
1674fcf3ce44SJohn Forte 
1675fcf3ce44SJohn Forte 
1676fcf3ce44SJohn Forte /* ARGSUSED */
1677fcf3ce44SJohn Forte static int
svopen(dev_t * devp,int flag,int otyp,cred_t * crp)1678fcf3ce44SJohn Forte svopen(dev_t *devp, int flag, int otyp, cred_t *crp)
1679fcf3ce44SJohn Forte {
1680fcf3ce44SJohn Forte 	int rc;
1681fcf3ce44SJohn Forte 
1682fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
1683fcf3ce44SJohn Forte 	rc = sv_init_devs();
1684fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte 	return (rc);
1687fcf3ce44SJohn Forte }
1688fcf3ce44SJohn Forte 
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte /* ARGSUSED */
1691fcf3ce44SJohn Forte static int
svclose(dev_t dev,int flag,int otyp,cred_t * crp)1692fcf3ce44SJohn Forte svclose(dev_t dev, int flag, int otyp, cred_t *crp)
1693fcf3ce44SJohn Forte {
1694fcf3ce44SJohn Forte 	const int secs = HZ * 5;
1695fcf3ce44SJohn Forte 	const int ticks = HZ / 10;
1696fcf3ce44SJohn Forte 	int loops = secs / ticks;
1697fcf3ce44SJohn Forte 
1698fcf3ce44SJohn Forte 	mutex_enter(&sv_mutex);
1699fcf3ce44SJohn Forte 	while (sv_ndevices <= 0 && sv_tset != NULL && loops > 0) {
1700fcf3ce44SJohn Forte 		if (nst_nlive(sv_tset) <= 0) {
1701fcf3ce44SJohn Forte 			nst_destroy(sv_tset);
1702fcf3ce44SJohn Forte 			sv_tset = NULL;
1703fcf3ce44SJohn Forte 			break;
1704fcf3ce44SJohn Forte 		}
1705fcf3ce44SJohn Forte 
1706fcf3ce44SJohn Forte 		/* threads still active - wait for them to exit */
1707fcf3ce44SJohn Forte 		mutex_exit(&sv_mutex);
1708fcf3ce44SJohn Forte 		delay(ticks);
1709fcf3ce44SJohn Forte 		loops--;
1710fcf3ce44SJohn Forte 		mutex_enter(&sv_mutex);
1711fcf3ce44SJohn Forte 	}
1712fcf3ce44SJohn Forte 	mutex_exit(&sv_mutex);
1713fcf3ce44SJohn Forte 
1714fcf3ce44SJohn Forte 	if (loops <= 0) {
1715fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
1716fcf3ce44SJohn Forte #ifndef DEBUG
1717fcf3ce44SJohn Forte 		    /* do not write to console when non-DEBUG */
1718fcf3ce44SJohn Forte 		    "!"
1719fcf3ce44SJohn Forte #endif
1720fcf3ce44SJohn Forte 		    "sv:svclose: threads still active "
1721fcf3ce44SJohn Forte 		    "after %d sec - leaking thread set", secs);
1722fcf3ce44SJohn Forte 	}
1723fcf3ce44SJohn Forte 
1724fcf3ce44SJohn Forte 	return (0);
1725fcf3ce44SJohn Forte }
1726fcf3ce44SJohn Forte 
1727fcf3ce44SJohn Forte 
1728fcf3ce44SJohn Forte static int
svioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * crp,int * rvalp)1729fcf3ce44SJohn Forte svioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvalp)
1730fcf3ce44SJohn Forte {
1731fcf3ce44SJohn Forte 	char itmp1[12], itmp2[12]; /* temp char array for editing ints */
1732fcf3ce44SJohn Forte 	spcs_s_info_t kstatus;	/* Kernel version of spcs status */
1733fcf3ce44SJohn Forte 	spcs_s_info_t ustatus;	/* Address of user version of spcs status */
1734fcf3ce44SJohn Forte 	sv_list32_t svl32;	/* 32 bit Initial structure for SVIOC_LIST */
1735fcf3ce44SJohn Forte 	sv_version_t svv;	/* Version structure */
1736fcf3ce44SJohn Forte 	sv_conf_t svc;		/* User config structure */
1737fcf3ce44SJohn Forte 	sv_list_t svl;		/* Initial structure for SVIOC_LIST */
1738fcf3ce44SJohn Forte 	void *usvn;		/* Address of user sv_name_t */
1739fcf3ce44SJohn Forte 	void *svn = NULL;	/* Array for SVIOC_LIST */
1740fcf3ce44SJohn Forte 	uint64_t phash;		/* pathname hash */
1741fcf3ce44SJohn Forte 	int rc = 0;		/* Return code -- errno */
1742fcf3ce44SJohn Forte 	int size;		/* Number of items in array */
1743fcf3ce44SJohn Forte 	int bytes;		/* Byte size of array */
1744fcf3ce44SJohn Forte 	int ilp32;		/* Convert data structures for ilp32 userland */
1745fcf3ce44SJohn Forte 
1746fcf3ce44SJohn Forte 	*rvalp = 0;
1747fcf3ce44SJohn Forte 
1748fcf3ce44SJohn Forte 	/*
1749fcf3ce44SJohn Forte 	 * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
1750fcf3ce44SJohn Forte 	 * else it means it previously was SV_PREVENT_UNLOAD, and now it's
1751fcf3ce44SJohn Forte 	 * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
1752fcf3ce44SJohn Forte 	 *
1753fcf3ce44SJohn Forte 	 * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
1754fcf3ce44SJohn Forte 	 */
1755fcf3ce44SJohn Forte 	if (sv_mod_status == SV_ALLOW_UNLOAD) {
1756fcf3ce44SJohn Forte 		return (EBUSY);
1757fcf3ce44SJohn Forte 	}
1758fcf3ce44SJohn Forte 
1759fcf3ce44SJohn Forte 	if ((cmd != SVIOC_LIST) && ((rc = drv_priv(crp)) != 0))
1760fcf3ce44SJohn Forte 		return (rc);
1761fcf3ce44SJohn Forte 
1762fcf3ce44SJohn Forte 	kstatus = spcs_s_kcreate();
1763fcf3ce44SJohn Forte 	if (!kstatus) {
17643270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_ioctl_err_kcreate, dev_t, dev);
1765fcf3ce44SJohn Forte 		return (ENOMEM);
1766fcf3ce44SJohn Forte 	}
1767fcf3ce44SJohn Forte 
1768fcf3ce44SJohn Forte 	ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
1769fcf3ce44SJohn Forte 
1770fcf3ce44SJohn Forte 	switch (cmd) {
1771fcf3ce44SJohn Forte 
1772fcf3ce44SJohn Forte 	case SVIOC_ENABLE:
1773fcf3ce44SJohn Forte 
1774fcf3ce44SJohn Forte 		if (ilp32) {
1775fcf3ce44SJohn Forte 			sv_conf32_t svc32;
1776fcf3ce44SJohn Forte 
1777fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svc32,
1778fcf3ce44SJohn Forte 			    sizeof (svc32), mode) < 0) {
1779fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1780fcf3ce44SJohn Forte 				return (EFAULT);
1781fcf3ce44SJohn Forte 			}
1782fcf3ce44SJohn Forte 
1783fcf3ce44SJohn Forte 			svc.svc_error = (spcs_s_info_t)svc32.svc_error;
1784fcf3ce44SJohn Forte 			(void) strcpy(svc.svc_path, svc32.svc_path);
1785fcf3ce44SJohn Forte 			svc.svc_flag  = svc32.svc_flag;
1786fcf3ce44SJohn Forte 			svc.svc_major = svc32.svc_major;
1787fcf3ce44SJohn Forte 			svc.svc_minor = svc32.svc_minor;
1788fcf3ce44SJohn Forte 		} else {
1789fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svc,
1790fcf3ce44SJohn Forte 			    sizeof (svc), mode) < 0) {
1791fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1792fcf3ce44SJohn Forte 				return (EFAULT);
1793fcf3ce44SJohn Forte 			}
1794fcf3ce44SJohn Forte 		}
1795fcf3ce44SJohn Forte 
1796fcf3ce44SJohn Forte 		/* force to raw access */
1797fcf3ce44SJohn Forte 		svc.svc_flag = NSC_DEVICE;
1798fcf3ce44SJohn Forte 
1799fcf3ce44SJohn Forte 		if (sv_tset == NULL) {
1800fcf3ce44SJohn Forte 			mutex_enter(&sv_mutex);
1801fcf3ce44SJohn Forte 
1802fcf3ce44SJohn Forte 			if (sv_tset == NULL) {
1803fcf3ce44SJohn Forte 				sv_tset = nst_init("sv_thr", sv_threads);
1804fcf3ce44SJohn Forte 			}
1805fcf3ce44SJohn Forte 
1806fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
1807fcf3ce44SJohn Forte 
1808fcf3ce44SJohn Forte 			if (sv_tset == NULL) {
1809fcf3ce44SJohn Forte 				cmn_err(CE_WARN,
18103270659fSSrikanth, Ramana 				    "!sv: could not allocate %d threads",
1811fcf3ce44SJohn Forte 				    sv_threads);
1812fcf3ce44SJohn Forte 			}
1813fcf3ce44SJohn Forte 		}
1814fcf3ce44SJohn Forte 
1815fcf3ce44SJohn Forte 		rc = sv_enable(svc.svc_path, svc.svc_flag,
18163270659fSSrikanth, Ramana 		    makedevice(svc.svc_major, svc.svc_minor), kstatus);
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 		if (rc == 0) {
1819fcf3ce44SJohn Forte 			sv_config_time = nsc_lbolt();
1820fcf3ce44SJohn Forte 
1821fcf3ce44SJohn Forte 			mutex_enter(&sv_mutex);
1822fcf3ce44SJohn Forte 			sv_thread_tune(sv_threads_dev);
1823fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
1824fcf3ce44SJohn Forte 		}
1825fcf3ce44SJohn Forte 
18263270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_ioctl_end, dev_t, dev, int, *rvalp, int, rc);
1827fcf3ce44SJohn Forte 
1828fcf3ce44SJohn Forte 		return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
1829fcf3ce44SJohn Forte 		/* NOTREACHED */
1830fcf3ce44SJohn Forte 
1831fcf3ce44SJohn Forte 	case SVIOC_DISABLE:
1832fcf3ce44SJohn Forte 
1833fcf3ce44SJohn Forte 		if (ilp32) {
1834fcf3ce44SJohn Forte 			sv_conf32_t svc32;
1835fcf3ce44SJohn Forte 
1836fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svc32,
1837fcf3ce44SJohn Forte 			    sizeof (svc32), mode) < 0) {
1838fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1839fcf3ce44SJohn Forte 				return (EFAULT);
1840fcf3ce44SJohn Forte 			}
1841fcf3ce44SJohn Forte 
1842fcf3ce44SJohn Forte 			svc.svc_error = (spcs_s_info_t)svc32.svc_error;
1843fcf3ce44SJohn Forte 			svc.svc_major = svc32.svc_major;
1844fcf3ce44SJohn Forte 			svc.svc_minor = svc32.svc_minor;
1845fcf3ce44SJohn Forte 			(void) strcpy(svc.svc_path, svc32.svc_path);
1846fcf3ce44SJohn Forte 			svc.svc_flag  = svc32.svc_flag;
1847fcf3ce44SJohn Forte 		} else {
1848fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svc,
1849fcf3ce44SJohn Forte 			    sizeof (svc), mode) < 0) {
1850fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1851fcf3ce44SJohn Forte 				return (EFAULT);
1852fcf3ce44SJohn Forte 			}
1853fcf3ce44SJohn Forte 		}
1854fcf3ce44SJohn Forte 
1855fcf3ce44SJohn Forte 		if (svc.svc_major == (major_t)-1 &&
1856fcf3ce44SJohn Forte 		    svc.svc_minor == (minor_t)-1) {
1857fcf3ce44SJohn Forte 			sv_dev_t *svp;
1858fcf3ce44SJohn Forte 			int i;
1859fcf3ce44SJohn Forte 
1860fcf3ce44SJohn Forte 			/*
1861fcf3ce44SJohn Forte 			 * User level could not find the minor device
1862fcf3ce44SJohn Forte 			 * node, so do this the slow way by searching
1863fcf3ce44SJohn Forte 			 * the entire sv config for a matching pathname.
1864fcf3ce44SJohn Forte 			 */
1865fcf3ce44SJohn Forte 
1866fcf3ce44SJohn Forte 			phash = nsc_strhash(svc.svc_path);
1867fcf3ce44SJohn Forte 
1868fcf3ce44SJohn Forte 			mutex_enter(&sv_mutex);
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 			for (i = 0; i < sv_max_devices; i++) {
1871fcf3ce44SJohn Forte 				svp = &sv_devs[i];
1872fcf3ce44SJohn Forte 
1873fcf3ce44SJohn Forte 				if (svp->sv_state == SV_DISABLE ||
1874fcf3ce44SJohn Forte 				    svp->sv_fd == NULL)
1875fcf3ce44SJohn Forte 					continue;
1876fcf3ce44SJohn Forte 
1877fcf3ce44SJohn Forte 				if (nsc_fdpathcmp(svp->sv_fd, phash,
1878fcf3ce44SJohn Forte 				    svc.svc_path) == 0) {
1879fcf3ce44SJohn Forte 					svc.svc_major = getmajor(svp->sv_dev);
1880fcf3ce44SJohn Forte 					svc.svc_minor = getminor(svp->sv_dev);
1881fcf3ce44SJohn Forte 					break;
1882fcf3ce44SJohn Forte 				}
1883fcf3ce44SJohn Forte 			}
1884fcf3ce44SJohn Forte 
1885fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
1886fcf3ce44SJohn Forte 
1887fcf3ce44SJohn Forte 			if (svc.svc_major == (major_t)-1 &&
1888fcf3ce44SJohn Forte 			    svc.svc_minor == (minor_t)-1)
1889fcf3ce44SJohn Forte 				return (spcs_s_ocopyoutf(&kstatus,
1890fcf3ce44SJohn Forte 				    svc.svc_error, SV_ENODEV));
1891fcf3ce44SJohn Forte 		}
1892fcf3ce44SJohn Forte 
1893fcf3ce44SJohn Forte 		rc = sv_disable(makedevice(svc.svc_major, svc.svc_minor),
1894fcf3ce44SJohn Forte 		    kstatus);
1895fcf3ce44SJohn Forte 
1896fcf3ce44SJohn Forte 		if (rc == 0) {
1897fcf3ce44SJohn Forte 			sv_config_time = nsc_lbolt();
1898fcf3ce44SJohn Forte 
1899fcf3ce44SJohn Forte 			mutex_enter(&sv_mutex);
1900fcf3ce44SJohn Forte 			sv_thread_tune(-sv_threads_dev);
1901fcf3ce44SJohn Forte 			mutex_exit(&sv_mutex);
1902fcf3ce44SJohn Forte 		}
1903fcf3ce44SJohn Forte 
19043270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_ioctl_2, dev_t, dev, int, *rvalp, int, rc);
1905fcf3ce44SJohn Forte 
1906fcf3ce44SJohn Forte 		return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
1907fcf3ce44SJohn Forte 		/* NOTREACHED */
1908fcf3ce44SJohn Forte 
1909fcf3ce44SJohn Forte 	case SVIOC_LIST:
1910fcf3ce44SJohn Forte 
1911fcf3ce44SJohn Forte 		if (ilp32) {
1912fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svl32,
1913fcf3ce44SJohn Forte 			    sizeof (svl32), mode) < 0) {
1914fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1915fcf3ce44SJohn Forte 				return (EFAULT);
1916fcf3ce44SJohn Forte 			}
1917fcf3ce44SJohn Forte 
1918fcf3ce44SJohn Forte 			ustatus = (spcs_s_info_t)svl32.svl_error;
1919fcf3ce44SJohn Forte 			size = svl32.svl_count;
1920fcf3ce44SJohn Forte 			usvn = (void *)(unsigned long)svl32.svl_names;
1921fcf3ce44SJohn Forte 		} else {
1922fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svl,
1923fcf3ce44SJohn Forte 			    sizeof (svl), mode) < 0) {
1924fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1925fcf3ce44SJohn Forte 				return (EFAULT);
1926fcf3ce44SJohn Forte 			}
1927fcf3ce44SJohn Forte 
1928fcf3ce44SJohn Forte 			ustatus = svl.svl_error;
1929fcf3ce44SJohn Forte 			size = svl.svl_count;
1930fcf3ce44SJohn Forte 			usvn = svl.svl_names;
1931fcf3ce44SJohn Forte 		}
1932fcf3ce44SJohn Forte 
1933fcf3ce44SJohn Forte 		/* Do some boundary checking */
1934fcf3ce44SJohn Forte 		if ((size < 0) || (size > sv_max_devices)) {
1935fcf3ce44SJohn Forte 			/* Array size is out of range */
1936fcf3ce44SJohn Forte 			return (spcs_s_ocopyoutf(&kstatus, ustatus,
1937fcf3ce44SJohn Forte 			    SV_EARRBOUNDS, "0",
1938fcf3ce44SJohn Forte 			    spcs_s_inttostring(sv_max_devices, itmp1,
1939fcf3ce44SJohn Forte 			    sizeof (itmp1), 0),
1940fcf3ce44SJohn Forte 			    spcs_s_inttostring(size, itmp2,
1941fcf3ce44SJohn Forte 			    sizeof (itmp2), 0)));
1942fcf3ce44SJohn Forte 		}
1943fcf3ce44SJohn Forte 
1944fcf3ce44SJohn Forte 		if (ilp32)
1945fcf3ce44SJohn Forte 			bytes = size * sizeof (sv_name32_t);
1946fcf3ce44SJohn Forte 		else
1947fcf3ce44SJohn Forte 			bytes = size * sizeof (sv_name_t);
1948fcf3ce44SJohn Forte 
1949fcf3ce44SJohn Forte 		/* Allocate memory for the array of structures */
1950fcf3ce44SJohn Forte 		if (bytes != 0) {
1951fcf3ce44SJohn Forte 			svn = kmem_zalloc(bytes, KM_SLEEP);
1952fcf3ce44SJohn Forte 			if (!svn) {
1953fcf3ce44SJohn Forte 				return (spcs_s_ocopyoutf(&kstatus,
1954fcf3ce44SJohn Forte 				    ustatus, ENOMEM));
1955fcf3ce44SJohn Forte 			}
1956fcf3ce44SJohn Forte 		}
1957fcf3ce44SJohn Forte 
1958fcf3ce44SJohn Forte 		rc = sv_list(svn, size, rvalp, ilp32);
1959fcf3ce44SJohn Forte 		if (rc) {
1960fcf3ce44SJohn Forte 			if (svn != NULL)
1961fcf3ce44SJohn Forte 				kmem_free(svn, bytes);
1962fcf3ce44SJohn Forte 			return (spcs_s_ocopyoutf(&kstatus, ustatus, rc));
1963fcf3ce44SJohn Forte 		}
1964fcf3ce44SJohn Forte 
1965fcf3ce44SJohn Forte 		if (ilp32) {
1966fcf3ce44SJohn Forte 			svl32.svl_timestamp = (uint32_t)sv_config_time;
1967fcf3ce44SJohn Forte 			svl32.svl_maxdevs = (int32_t)sv_max_devices;
1968fcf3ce44SJohn Forte 
1969fcf3ce44SJohn Forte 			/* Return the list structure */
1970fcf3ce44SJohn Forte 			if (ddi_copyout(&svl32, (void *)arg,
1971fcf3ce44SJohn Forte 			    sizeof (svl32), mode) < 0) {
1972fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1973fcf3ce44SJohn Forte 				if (svn != NULL)
1974fcf3ce44SJohn Forte 					kmem_free(svn, bytes);
1975fcf3ce44SJohn Forte 				return (EFAULT);
1976fcf3ce44SJohn Forte 			}
1977fcf3ce44SJohn Forte 		} else {
1978fcf3ce44SJohn Forte 			svl.svl_timestamp = sv_config_time;
1979fcf3ce44SJohn Forte 			svl.svl_maxdevs = sv_max_devices;
1980fcf3ce44SJohn Forte 
1981fcf3ce44SJohn Forte 			/* Return the list structure */
1982fcf3ce44SJohn Forte 			if (ddi_copyout(&svl, (void *)arg,
1983fcf3ce44SJohn Forte 			    sizeof (svl), mode) < 0) {
1984fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1985fcf3ce44SJohn Forte 				if (svn != NULL)
1986fcf3ce44SJohn Forte 					kmem_free(svn, bytes);
1987fcf3ce44SJohn Forte 				return (EFAULT);
1988fcf3ce44SJohn Forte 			}
1989fcf3ce44SJohn Forte 		}
1990fcf3ce44SJohn Forte 
1991fcf3ce44SJohn Forte 		/* Return the array */
1992fcf3ce44SJohn Forte 		if (svn != NULL) {
1993fcf3ce44SJohn Forte 			if (ddi_copyout(svn, usvn, bytes, mode) < 0) {
1994fcf3ce44SJohn Forte 				kmem_free(svn, bytes);
1995fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
1996fcf3ce44SJohn Forte 				return (EFAULT);
1997fcf3ce44SJohn Forte 			}
1998fcf3ce44SJohn Forte 			kmem_free(svn, bytes);
1999fcf3ce44SJohn Forte 		}
2000fcf3ce44SJohn Forte 
20013270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_ioctl_3, dev_t, dev, int, *rvalp, int, 0);
2002fcf3ce44SJohn Forte 
2003fcf3ce44SJohn Forte 		return (spcs_s_ocopyoutf(&kstatus, ustatus, 0));
2004fcf3ce44SJohn Forte 		/* NOTREACHED */
2005fcf3ce44SJohn Forte 
2006fcf3ce44SJohn Forte 	case SVIOC_VERSION:
2007fcf3ce44SJohn Forte 
2008fcf3ce44SJohn Forte 		if (ilp32) {
2009fcf3ce44SJohn Forte 			sv_version32_t svv32;
2010fcf3ce44SJohn Forte 
2011fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svv32,
2012fcf3ce44SJohn Forte 			    sizeof (svv32), mode) < 0) {
2013fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
2014fcf3ce44SJohn Forte 				return (EFAULT);
2015fcf3ce44SJohn Forte 			}
2016fcf3ce44SJohn Forte 
2017fcf3ce44SJohn Forte 			svv32.svv_major_rev = sv_major_rev;
2018fcf3ce44SJohn Forte 			svv32.svv_minor_rev = sv_minor_rev;
2019fcf3ce44SJohn Forte 			svv32.svv_micro_rev = sv_micro_rev;
2020fcf3ce44SJohn Forte 			svv32.svv_baseline_rev = sv_baseline_rev;
2021fcf3ce44SJohn Forte 
2022fcf3ce44SJohn Forte 			if (ddi_copyout(&svv32, (void *)arg,
2023fcf3ce44SJohn Forte 			    sizeof (svv32), mode) < 0) {
2024fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
2025fcf3ce44SJohn Forte 				return (EFAULT);
2026fcf3ce44SJohn Forte 			}
2027fcf3ce44SJohn Forte 
2028fcf3ce44SJohn Forte 			ustatus = (spcs_s_info_t)svv32.svv_error;
2029fcf3ce44SJohn Forte 		} else {
2030fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, &svv,
2031fcf3ce44SJohn Forte 			    sizeof (svv), mode) < 0) {
2032fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
2033fcf3ce44SJohn Forte 				return (EFAULT);
2034fcf3ce44SJohn Forte 			}
2035fcf3ce44SJohn Forte 
2036fcf3ce44SJohn Forte 			svv.svv_major_rev = sv_major_rev;
2037fcf3ce44SJohn Forte 			svv.svv_minor_rev = sv_minor_rev;
2038fcf3ce44SJohn Forte 			svv.svv_micro_rev = sv_micro_rev;
2039fcf3ce44SJohn Forte 			svv.svv_baseline_rev = sv_baseline_rev;
2040fcf3ce44SJohn Forte 
2041fcf3ce44SJohn Forte 			if (ddi_copyout(&svv, (void *)arg,
2042fcf3ce44SJohn Forte 			    sizeof (svv), mode) < 0) {
2043fcf3ce44SJohn Forte 				spcs_s_kfree(kstatus);
2044fcf3ce44SJohn Forte 				return (EFAULT);
2045fcf3ce44SJohn Forte 			}
2046fcf3ce44SJohn Forte 
2047fcf3ce44SJohn Forte 			ustatus = svv.svv_error;
2048fcf3ce44SJohn Forte 		}
2049fcf3ce44SJohn Forte 
20503270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, 0);
2051fcf3ce44SJohn Forte 
2052fcf3ce44SJohn Forte 		return (spcs_s_ocopyoutf(&kstatus, ustatus, 0));
2053fcf3ce44SJohn Forte 		/* NOTREACHED */
2054fcf3ce44SJohn Forte 
2055fcf3ce44SJohn Forte 	case SVIOC_UNLOAD:
2056fcf3ce44SJohn Forte 		rc = sv_prepare_unload();
2057fcf3ce44SJohn Forte 
20583270659fSSrikanth, Ramana 		if (ddi_copyout(&rc, (void *)arg, sizeof (rc), mode) < 0) {
2059fcf3ce44SJohn Forte 			rc = EFAULT;
2060fcf3ce44SJohn Forte 		}
2061fcf3ce44SJohn Forte 
2062fcf3ce44SJohn Forte 		spcs_s_kfree(kstatus);
2063fcf3ce44SJohn Forte 		return (rc);
2064fcf3ce44SJohn Forte 
2065fcf3ce44SJohn Forte 	default:
2066fcf3ce44SJohn Forte 		spcs_s_kfree(kstatus);
2067fcf3ce44SJohn Forte 
20683270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, EINVAL);
2069fcf3ce44SJohn Forte 
2070fcf3ce44SJohn Forte 		return (EINVAL);
2071fcf3ce44SJohn Forte 		/* NOTREACHED */
2072fcf3ce44SJohn Forte 	}
2073fcf3ce44SJohn Forte 
2074fcf3ce44SJohn Forte 	/* NOTREACHED */
2075fcf3ce44SJohn Forte }
2076fcf3ce44SJohn Forte 
2077fcf3ce44SJohn Forte 
2078fcf3ce44SJohn Forte /* ARGSUSED */
2079fcf3ce44SJohn Forte static int
svprint(dev_t dev,char * str)2080fcf3ce44SJohn Forte svprint(dev_t dev, char *str)
2081fcf3ce44SJohn Forte {
2082fcf3ce44SJohn Forte 	int instance = ddi_get_instance(sv_dip);
20833270659fSSrikanth, Ramana 	cmn_err(CE_WARN, "!%s%d: %s", ddi_get_name(sv_dip), instance, str);
2084fcf3ce44SJohn Forte 	return (0);
2085fcf3ce44SJohn Forte }
2086fcf3ce44SJohn Forte 
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte static void
_sv_lyr_strategy(struct buf * bp)2089fcf3ce44SJohn Forte _sv_lyr_strategy(struct buf *bp)
2090fcf3ce44SJohn Forte {
2091fcf3ce44SJohn Forte 	caddr_t buf_addr;		/* pointer to linear buffer in bp */
2092fcf3ce44SJohn Forte 	nsc_buf_t *bufh = NULL;
2093fcf3ce44SJohn Forte 	nsc_buf_t *hndl = NULL;
2094fcf3ce44SJohn Forte 	sv_dev_t *svp;
2095fcf3ce44SJohn Forte 	nsc_vec_t *v;
2096fcf3ce44SJohn Forte 	sv_maj_t *maj;
2097fcf3ce44SJohn Forte 	nsc_size_t fba_req, fba_len;	/* FBA lengths */
2098fcf3ce44SJohn Forte 	nsc_off_t fba_off;		/* FBA offset */
2099fcf3ce44SJohn Forte 	size_t tocopy, nbytes;		/* byte lengths */
2100fcf3ce44SJohn Forte 	int rw, rc;			/* flags and return codes */
2101fcf3ce44SJohn Forte 	int (*fn)();
2102fcf3ce44SJohn Forte 
2103fcf3ce44SJohn Forte 	rc = 0;
2104fcf3ce44SJohn Forte 
2105fcf3ce44SJohn Forte 	if (sv_debug > 5)
21063270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!_sv_lyr_strategy(%p)\n", (void *)bp);
2107fcf3ce44SJohn Forte 
2108fcf3ce44SJohn Forte 	svp = sv_find_enabled(bp->b_edev, &maj);
2109fcf3ce44SJohn Forte 	if (svp == NULL) {
2110fcf3ce44SJohn Forte 		if (maj && (fn = maj->sm_strategy) != 0) {
2111fcf3ce44SJohn Forte 			if (!(maj->sm_flag & D_MP)) {
2112fcf3ce44SJohn Forte 				UNSAFE_ENTER();
2113fcf3ce44SJohn Forte 				rc = (*fn)(bp);
2114fcf3ce44SJohn Forte 				UNSAFE_EXIT();
2115fcf3ce44SJohn Forte 			} else {
2116fcf3ce44SJohn Forte 				rc = (*fn)(bp);
2117fcf3ce44SJohn Forte 			}
2118fcf3ce44SJohn Forte 			return;
2119fcf3ce44SJohn Forte 		} else {
2120fcf3ce44SJohn Forte 			bioerror(bp, ENODEV);
2121fcf3ce44SJohn Forte 			biodone(bp);
2122fcf3ce44SJohn Forte 			return;
2123fcf3ce44SJohn Forte 		}
2124fcf3ce44SJohn Forte 	}
2125fcf3ce44SJohn Forte 
2126fcf3ce44SJohn Forte 	ASSERT(RW_READ_HELD(&svp->sv_lock));
2127fcf3ce44SJohn Forte 
2128fcf3ce44SJohn Forte 	if (svp->sv_flag == 0) {
2129fcf3ce44SJohn Forte 		/*
2130fcf3ce44SJohn Forte 		 * guard access mode
2131fcf3ce44SJohn Forte 		 * - prevent user level access to the device
2132fcf3ce44SJohn Forte 		 */
21333270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_err_guard, struct buf *, bp);
2134fcf3ce44SJohn Forte 		bioerror(bp, EPERM);
2135fcf3ce44SJohn Forte 		goto out;
2136fcf3ce44SJohn Forte 	}
2137fcf3ce44SJohn Forte 
2138fcf3ce44SJohn Forte 	if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
21393270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_err_rsrv, struct buf *, bp);
2140fcf3ce44SJohn Forte 
2141fcf3ce44SJohn Forte 		if (rc == EINTR)
21423270659fSSrikanth, Ramana 			cmn_err(CE_WARN, "!nsc_reserve() returned EINTR");
2143fcf3ce44SJohn Forte 		bioerror(bp, rc);
2144fcf3ce44SJohn Forte 		goto out;
2145fcf3ce44SJohn Forte 	}
2146fcf3ce44SJohn Forte 
2147fcf3ce44SJohn Forte 	if (bp->b_lblkno >= (diskaddr_t)svp->sv_nblocks) {
21483270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_eof, struct buf *, bp);
2149fcf3ce44SJohn Forte 
2150fcf3ce44SJohn Forte 		if (bp->b_flags & B_READ) {
2151fcf3ce44SJohn Forte 			/* return EOF, not an error */
2152fcf3ce44SJohn Forte 			bp->b_resid = bp->b_bcount;
2153fcf3ce44SJohn Forte 			bioerror(bp, 0);
2154fcf3ce44SJohn Forte 		} else
2155fcf3ce44SJohn Forte 			bioerror(bp, EINVAL);
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 		goto done;
2158fcf3ce44SJohn Forte 	}
2159fcf3ce44SJohn Forte 
2160fcf3ce44SJohn Forte 	/*
2161fcf3ce44SJohn Forte 	 * Preallocate a handle once per call to strategy.
2162fcf3ce44SJohn Forte 	 * If this fails, then the nsc_alloc_buf() will allocate
2163fcf3ce44SJohn Forte 	 * a temporary handle per allocation/free pair.
2164fcf3ce44SJohn Forte 	 */
2165fcf3ce44SJohn Forte 
21663270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_alloch_start, sv_dev_t *, svp);
2167fcf3ce44SJohn Forte 
2168fcf3ce44SJohn Forte 	bufh = nsc_alloc_handle(svp->sv_fd, NULL, NULL, NULL);
2169fcf3ce44SJohn Forte 
21703270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_alloch_end, sv_dev_t *, svp);
2171fcf3ce44SJohn Forte 
2172fcf3ce44SJohn Forte 	if (bufh && (bufh->sb_flag & NSC_HACTIVE) != 0) {
21733270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_err_hactive, struct buf *, bp);
2174fcf3ce44SJohn Forte 
2175fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
21763270659fSSrikanth, Ramana 		    "!sv: allocated active handle (bufh %p, flags %x)",
2177fcf3ce44SJohn Forte 		    (void *)bufh, bufh->sb_flag);
2178fcf3ce44SJohn Forte 
2179fcf3ce44SJohn Forte 		bioerror(bp, ENXIO);
2180fcf3ce44SJohn Forte 		goto done;
2181fcf3ce44SJohn Forte 	}
2182fcf3ce44SJohn Forte 
2183fcf3ce44SJohn Forte 	fba_req = FBA_LEN(bp->b_bcount);
2184fcf3ce44SJohn Forte 	if (fba_req + bp->b_lblkno > (diskaddr_t)svp->sv_nblocks)
2185fcf3ce44SJohn Forte 		fba_req = (nsc_size_t)(svp->sv_nblocks - bp->b_lblkno);
2186fcf3ce44SJohn Forte 
2187fcf3ce44SJohn Forte 	rw = (bp->b_flags & B_READ) ? NSC_READ : NSC_WRITE;
2188fcf3ce44SJohn Forte 
2189fcf3ce44SJohn Forte 	bp_mapin(bp);
2190fcf3ce44SJohn Forte 
2191fcf3ce44SJohn Forte 	bp->b_resid = bp->b_bcount;
2192fcf3ce44SJohn Forte 	buf_addr = bp->b_un.b_addr;
2193fcf3ce44SJohn Forte 	fba_off = 0;
2194fcf3ce44SJohn Forte 
2195fcf3ce44SJohn Forte 	/*
2196fcf3ce44SJohn Forte 	 * fba_req  - requested size of transfer in FBAs after
2197fcf3ce44SJohn Forte 	 *		truncation to device extent, and allowing for
2198fcf3ce44SJohn Forte 	 *		possible non-FBA bounded final chunk.
2199fcf3ce44SJohn Forte 	 * fba_off  - offset of start of chunk from start of bp in FBAs.
2200fcf3ce44SJohn Forte 	 * fba_len  - size of this chunk in FBAs.
2201fcf3ce44SJohn Forte 	 */
2202fcf3ce44SJohn Forte 
2203fcf3ce44SJohn Forte loop:
2204fcf3ce44SJohn Forte 	fba_len = min(fba_req, svp->sv_maxfbas);
2205fcf3ce44SJohn Forte 	hndl = bufh;
2206fcf3ce44SJohn Forte 
2207fcf3ce44SJohn Forte 	DTRACE_PROBE4(sv_dbg_allocb_start,
2208fcf3ce44SJohn Forte 	    sv_dev_t *, svp,
2209fcf3ce44SJohn Forte 	    uint64_t, (uint64_t)(bp->b_lblkno + fba_off),
2210fcf3ce44SJohn Forte 	    uint64_t, (uint64_t)fba_len,
2211fcf3ce44SJohn Forte 	    int, rw);
2212fcf3ce44SJohn Forte 
2213fcf3ce44SJohn Forte 	rc = nsc_alloc_buf(svp->sv_fd, (nsc_off_t)(bp->b_lblkno + fba_off),
2214fcf3ce44SJohn Forte 	    fba_len, rw, &hndl);
2215fcf3ce44SJohn Forte 
22163270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_allocb_end, sv_dev_t *, svp);
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 	if (rc > 0) {
22193270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_err_alloc, struct buf *, bp);
2220fcf3ce44SJohn Forte 		bioerror(bp, rc);
2221fcf3ce44SJohn Forte 		if (hndl != bufh)
2222fcf3ce44SJohn Forte 			(void) nsc_free_buf(hndl);
2223fcf3ce44SJohn Forte 		hndl = NULL;
2224fcf3ce44SJohn Forte 		goto done;
2225fcf3ce44SJohn Forte 	}
2226fcf3ce44SJohn Forte 
2227fcf3ce44SJohn Forte 	tocopy = min(FBA_SIZE(fba_len), bp->b_resid);
2228fcf3ce44SJohn Forte 	v = hndl->sb_vec;
2229fcf3ce44SJohn Forte 
2230fcf3ce44SJohn Forte 	if (rw == NSC_WRITE && FBA_OFF(tocopy) != 0) {
2231fcf3ce44SJohn Forte 		/*
2232fcf3ce44SJohn Forte 		 * Not overwriting all of the last FBA, so read in the
2233fcf3ce44SJohn Forte 		 * old contents now before we overwrite it with the new
2234fcf3ce44SJohn Forte 		 * data.
2235fcf3ce44SJohn Forte 		 */
2236fcf3ce44SJohn Forte 
22373270659fSSrikanth, Ramana 		DTRACE_PROBE2(sv_dbg_read_start, sv_dev_t *, svp,
2238fcf3ce44SJohn Forte 		    uint64_t, (uint64_t)(hndl->sb_pos + hndl->sb_len - 1));
2239fcf3ce44SJohn Forte 
2240fcf3ce44SJohn Forte 		rc = nsc_read(hndl, (hndl->sb_pos + hndl->sb_len - 1), 1, 0);
2241fcf3ce44SJohn Forte 		if (rc > 0) {
2242fcf3ce44SJohn Forte 			bioerror(bp, rc);
2243fcf3ce44SJohn Forte 			goto done;
2244fcf3ce44SJohn Forte 		}
2245fcf3ce44SJohn Forte 
22463270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_read_end, sv_dev_t *, svp);
2247fcf3ce44SJohn Forte 	}
2248fcf3ce44SJohn Forte 
22493270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_bcopy_start, sv_dev_t *, svp);
2250fcf3ce44SJohn Forte 
2251fcf3ce44SJohn Forte 	while (tocopy > 0) {
2252fcf3ce44SJohn Forte 		nbytes = min(tocopy, (nsc_size_t)v->sv_len);
2253fcf3ce44SJohn Forte 
2254fcf3ce44SJohn Forte 		if (bp->b_flags & B_READ)
2255fcf3ce44SJohn Forte 			(void) bcopy(v->sv_addr, buf_addr, nbytes);
2256fcf3ce44SJohn Forte 		else
2257fcf3ce44SJohn Forte 			(void) bcopy(buf_addr, v->sv_addr, nbytes);
2258fcf3ce44SJohn Forte 
2259fcf3ce44SJohn Forte 		bp->b_resid -= nbytes;
2260fcf3ce44SJohn Forte 		buf_addr += nbytes;
2261fcf3ce44SJohn Forte 		tocopy -= nbytes;
2262fcf3ce44SJohn Forte 		v++;
2263fcf3ce44SJohn Forte 	}
2264fcf3ce44SJohn Forte 
22653270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_bcopy_end, sv_dev_t *, svp);
2266fcf3ce44SJohn Forte 
2267fcf3ce44SJohn Forte 	if ((bp->b_flags & B_READ) == 0) {
22683270659fSSrikanth, Ramana 		DTRACE_PROBE3(sv_dbg_write_start, sv_dev_t *, svp,
2269fcf3ce44SJohn Forte 		    uint64_t, (uint64_t)hndl->sb_pos,
2270fcf3ce44SJohn Forte 		    uint64_t, (uint64_t)hndl->sb_len);
2271fcf3ce44SJohn Forte 
2272fcf3ce44SJohn Forte 		rc = nsc_write(hndl, hndl->sb_pos, hndl->sb_len, 0);
2273fcf3ce44SJohn Forte 
22743270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_write_end, sv_dev_t *, svp);
2275fcf3ce44SJohn Forte 
2276fcf3ce44SJohn Forte 		if (rc > 0) {
2277fcf3ce44SJohn Forte 			bioerror(bp, rc);
2278fcf3ce44SJohn Forte 			goto done;
2279fcf3ce44SJohn Forte 		}
2280fcf3ce44SJohn Forte 	}
2281fcf3ce44SJohn Forte 
2282fcf3ce44SJohn Forte 	/*
2283fcf3ce44SJohn Forte 	 * Adjust FBA offset and requested (ie. remaining) length,
2284fcf3ce44SJohn Forte 	 * loop if more data to transfer.
2285fcf3ce44SJohn Forte 	 */
2286fcf3ce44SJohn Forte 
2287fcf3ce44SJohn Forte 	fba_off += fba_len;
2288fcf3ce44SJohn Forte 	fba_req -= fba_len;
2289fcf3ce44SJohn Forte 
2290fcf3ce44SJohn Forte 	if (fba_req > 0) {
22913270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
2292fcf3ce44SJohn Forte 
2293fcf3ce44SJohn Forte 		rc = nsc_free_buf(hndl);
2294fcf3ce44SJohn Forte 
22953270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
2296fcf3ce44SJohn Forte 
2297fcf3ce44SJohn Forte 		if (rc > 0) {
2298fcf3ce44SJohn Forte 			DTRACE_PROBE1(sv_lyr_strategy_err_free,
2299fcf3ce44SJohn Forte 			    struct buf *, bp);
2300fcf3ce44SJohn Forte 			bioerror(bp, rc);
2301fcf3ce44SJohn Forte 		}
2302fcf3ce44SJohn Forte 
2303fcf3ce44SJohn Forte 		hndl = NULL;
2304fcf3ce44SJohn Forte 
2305fcf3ce44SJohn Forte 		if (rc <= 0)
2306fcf3ce44SJohn Forte 			goto loop;
2307fcf3ce44SJohn Forte 	}
2308fcf3ce44SJohn Forte 
2309fcf3ce44SJohn Forte done:
2310fcf3ce44SJohn Forte 	if (hndl != NULL) {
23113270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
2312fcf3ce44SJohn Forte 
2313fcf3ce44SJohn Forte 		rc = nsc_free_buf(hndl);
2314fcf3ce44SJohn Forte 
23153270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
2316fcf3ce44SJohn Forte 
2317fcf3ce44SJohn Forte 		if (rc > 0) {
2318fcf3ce44SJohn Forte 			DTRACE_PROBE1(sv_lyr_strategy_err_free,
2319fcf3ce44SJohn Forte 			    struct buf *, bp);
2320fcf3ce44SJohn Forte 			bioerror(bp, rc);
2321fcf3ce44SJohn Forte 		}
2322fcf3ce44SJohn Forte 
2323fcf3ce44SJohn Forte 		hndl = NULL;
2324fcf3ce44SJohn Forte 	}
2325fcf3ce44SJohn Forte 
2326fcf3ce44SJohn Forte 	if (bufh)
2327fcf3ce44SJohn Forte 		(void) nsc_free_handle(bufh);
2328fcf3ce44SJohn Forte 
23293270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_rlse_start, sv_dev_t *, svp);
2330fcf3ce44SJohn Forte 
2331fcf3ce44SJohn Forte 	nsc_release(svp->sv_fd);
2332fcf3ce44SJohn Forte 
23333270659fSSrikanth, Ramana 	DTRACE_PROBE1(sv_dbg_rlse_end, sv_dev_t *, svp);
2334fcf3ce44SJohn Forte 
2335fcf3ce44SJohn Forte out:
2336fcf3ce44SJohn Forte 	if (sv_debug > 5) {
2337fcf3ce44SJohn Forte 		cmn_err(CE_CONT,
23383270659fSSrikanth, Ramana 		    "!_sv_lyr_strategy: bp %p, bufh %p, bp->b_error %d\n",
2339fcf3ce44SJohn Forte 		    (void *)bp, (void *)bufh, bp->b_error);
2340fcf3ce44SJohn Forte 	}
2341fcf3ce44SJohn Forte 
23423270659fSSrikanth, Ramana 	DTRACE_PROBE2(sv_lyr_strategy_end, struct buf *, bp, int, bp->b_error);
2343fcf3ce44SJohn Forte 
2344fcf3ce44SJohn Forte 	rw_exit(&svp->sv_lock);
2345fcf3ce44SJohn Forte 	biodone(bp);
2346fcf3ce44SJohn Forte }
2347fcf3ce44SJohn Forte 
2348fcf3ce44SJohn Forte 
2349fcf3ce44SJohn Forte static void
sv_async_strategy(blind_t arg)2350fcf3ce44SJohn Forte sv_async_strategy(blind_t arg)
2351fcf3ce44SJohn Forte {
2352fcf3ce44SJohn Forte 	struct buf *bp = (struct buf *)arg;
2353fcf3ce44SJohn Forte 	_sv_lyr_strategy(bp);
2354fcf3ce44SJohn Forte }
2355fcf3ce44SJohn Forte 
2356fcf3ce44SJohn Forte 
2357fcf3ce44SJohn Forte static int
sv_lyr_strategy(struct buf * bp)2358fcf3ce44SJohn Forte sv_lyr_strategy(struct buf *bp)
2359fcf3ce44SJohn Forte {
2360fcf3ce44SJohn Forte 	nsthread_t *tp;
2361fcf3ce44SJohn Forte 	int nlive;
2362fcf3ce44SJohn Forte 
2363fcf3ce44SJohn Forte 	/*
2364fcf3ce44SJohn Forte 	 * If B_ASYNC was part of the DDI we could use it as a hint to
2365fcf3ce44SJohn Forte 	 * not create a thread for synchronous i/o.
2366fcf3ce44SJohn Forte 	 */
2367fcf3ce44SJohn Forte 	if (sv_dev_to_sv(bp->b_edev, NULL) == NULL) {
2368fcf3ce44SJohn Forte 		/* not sv enabled - just pass through */
23693270659fSSrikanth, Ramana 		DTRACE_PROBE1(sv_lyr_strategy_notsv, struct buf *, bp);
2370fcf3ce44SJohn Forte 		_sv_lyr_strategy(bp);
2371fcf3ce44SJohn Forte 		return (0);
2372fcf3ce44SJohn Forte 	}
2373fcf3ce44SJohn Forte 
2374fcf3ce44SJohn Forte 	if (sv_debug > 4) {
23753270659fSSrikanth, Ramana 		cmn_err(CE_CONT, "!sv_lyr_strategy: nthread %d nlive %d\n",
2376fcf3ce44SJohn Forte 		    nst_nthread(sv_tset), nst_nlive(sv_tset));
2377fcf3ce44SJohn Forte 	}
2378fcf3ce44SJohn Forte 
2379fcf3ce44SJohn Forte 	/*
2380fcf3ce44SJohn Forte 	 * If there are only guard devices enabled there
2381fcf3ce44SJohn Forte 	 * won't be a threadset, so don't try and use it.
2382fcf3ce44SJohn Forte 	 */
2383fcf3ce44SJohn Forte 	tp = NULL;
2384fcf3ce44SJohn Forte 	if (sv_tset != NULL) {
2385fcf3ce44SJohn Forte 		tp = nst_create(sv_tset, sv_async_strategy, (blind_t)bp, 0);
2386fcf3ce44SJohn Forte 	}
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte 	if (tp == NULL) {
2389fcf3ce44SJohn Forte 		/*
2390fcf3ce44SJohn Forte 		 * out of threads, so fall back to synchronous io.
2391fcf3ce44SJohn Forte 		 */
2392fcf3ce44SJohn Forte 		if (sv_debug > 0) {
2393fcf3ce44SJohn Forte 			cmn_err(CE_CONT,
23943270659fSSrikanth, Ramana 			    "!sv_lyr_strategy: thread alloc failed\n");
2395fcf3ce44SJohn Forte 		}
2396fcf3ce44SJohn Forte 
2397fcf3ce44SJohn Forte 		DTRACE_PROBE1(sv_lyr_strategy_no_thread,
2398fcf3ce44SJohn Forte 		    struct buf *, bp);
2399fcf3ce44SJohn Forte 
2400fcf3ce44SJohn Forte 		_sv_lyr_strategy(bp);
2401fcf3ce44SJohn Forte 		sv_no_threads++;
2402fcf3ce44SJohn Forte 	} else {
2403fcf3ce44SJohn Forte 		nlive = nst_nlive(sv_tset);
2404fcf3ce44SJohn Forte 		if (nlive > sv_max_nlive) {
2405fcf3ce44SJohn Forte 			if (sv_debug > 0) {
2406fcf3ce44SJohn Forte 				cmn_err(CE_CONT,
24073270659fSSrikanth, Ramana 				    "!sv_lyr_strategy: "
2408fcf3ce44SJohn Forte 				    "new max nlive %d (nthread %d)\n",
2409fcf3ce44SJohn Forte 				    nlive, nst_nthread(sv_tset));
2410fcf3ce44SJohn Forte 			}
2411fcf3ce44SJohn Forte 
2412fcf3ce44SJohn Forte 			sv_max_nlive = nlive;
2413fcf3ce44SJohn Forte 		}
2414fcf3ce44SJohn Forte 	}
2415fcf3ce44SJohn Forte 
2416fcf3ce44SJohn Forte 	return (0);
2417fcf3ce44SJohn Forte }
2418fcf3ce44SJohn Forte 
2419fcf3ce44SJohn Forte /*
2420fcf3ce44SJohn Forte  * re-write the size of the current partition
2421fcf3ce44SJohn Forte  */
2422fcf3ce44SJohn Forte static int
sv_fix_dkiocgvtoc(const intptr_t arg,const int mode,sv_dev_t * svp)2423fcf3ce44SJohn Forte sv_fix_dkiocgvtoc(const intptr_t arg, const int mode, sv_dev_t *svp)
2424fcf3ce44SJohn Forte {
2425fcf3ce44SJohn Forte 	size_t offset;
2426fcf3ce44SJohn Forte 	int ilp32;
2427fcf3ce44SJohn Forte 	int pnum;
2428fcf3ce44SJohn Forte 	int rc;
2429fcf3ce44SJohn Forte 
2430fcf3ce44SJohn Forte 	ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
2431fcf3ce44SJohn Forte 
2432fcf3ce44SJohn Forte 	rc = nskern_partition(svp->sv_dev, &pnum);
2433fcf3ce44SJohn Forte 	if (rc != 0) {
2434fcf3ce44SJohn Forte 		return (rc);
2435fcf3ce44SJohn Forte 	}
2436fcf3ce44SJohn Forte 
2437fcf3ce44SJohn Forte 	if (pnum < 0 || pnum >= V_NUMPAR) {
2438fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
24393270659fSSrikanth, Ramana 		    "!sv_gvtoc: unable to determine partition number "
2440fcf3ce44SJohn Forte 		    "for dev %lx", svp->sv_dev);
2441fcf3ce44SJohn Forte 		return (EINVAL);
2442fcf3ce44SJohn Forte 	}
2443fcf3ce44SJohn Forte 
2444fcf3ce44SJohn Forte 	if (ilp32) {
2445fcf3ce44SJohn Forte 		int32_t p_size;
2446fcf3ce44SJohn Forte 
2447fcf3ce44SJohn Forte #ifdef _SunOS_5_6
2448fcf3ce44SJohn Forte 		offset = offsetof(struct vtoc, v_part);
2449fcf3ce44SJohn Forte 		offset += sizeof (struct partition) * pnum;
2450fcf3ce44SJohn Forte 		offset += offsetof(struct partition, p_size);
2451fcf3ce44SJohn Forte #else
2452fcf3ce44SJohn Forte 		offset = offsetof(struct vtoc32, v_part);
2453fcf3ce44SJohn Forte 		offset += sizeof (struct partition32) * pnum;
2454fcf3ce44SJohn Forte 		offset += offsetof(struct partition32, p_size);
2455fcf3ce44SJohn Forte #endif
2456fcf3ce44SJohn Forte 
2457fcf3ce44SJohn Forte 		p_size = (int32_t)svp->sv_nblocks;
2458fcf3ce44SJohn Forte 		if (p_size == 0) {
2459fcf3ce44SJohn Forte 			if (sv_reserve(svp->sv_fd,
2460fcf3ce44SJohn Forte 			    NSC_MULTI|NSC_PCATCH) == 0) {
2461fcf3ce44SJohn Forte 				p_size = (int32_t)svp->sv_nblocks;
2462fcf3ce44SJohn Forte 				nsc_release(svp->sv_fd);
2463fcf3ce44SJohn Forte 			} else {
2464fcf3ce44SJohn Forte 				rc = EINTR;
2465fcf3ce44SJohn Forte 			}
2466fcf3ce44SJohn Forte 		}
2467fcf3ce44SJohn Forte 
2468fcf3ce44SJohn Forte 		if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
2469fcf3ce44SJohn Forte 		    sizeof (p_size), mode) != 0) {
2470fcf3ce44SJohn Forte 			rc = EFAULT;
2471fcf3ce44SJohn Forte 		}
2472fcf3ce44SJohn Forte 	} else {
2473fcf3ce44SJohn Forte 		long p_size;
2474fcf3ce44SJohn Forte 
2475fcf3ce44SJohn Forte 		offset = offsetof(struct vtoc, v_part);
2476fcf3ce44SJohn Forte 		offset += sizeof (struct partition) * pnum;
2477fcf3ce44SJohn Forte 		offset += offsetof(struct partition, p_size);
2478fcf3ce44SJohn Forte 
2479fcf3ce44SJohn Forte 		p_size = (long)svp->sv_nblocks;
2480fcf3ce44SJohn Forte 		if (p_size == 0) {
2481fcf3ce44SJohn Forte 			if (sv_reserve(svp->sv_fd,
2482fcf3ce44SJohn Forte 			    NSC_MULTI|NSC_PCATCH) == 0) {
2483fcf3ce44SJohn Forte 				p_size = (long)svp->sv_nblocks;
2484fcf3ce44SJohn Forte 				nsc_release(svp->sv_fd);
2485fcf3ce44SJohn Forte 			} else {
2486fcf3ce44SJohn Forte 				rc = EINTR;
2487fcf3ce44SJohn Forte 			}
2488fcf3ce44SJohn Forte 		}
2489fcf3ce44SJohn Forte 
2490fcf3ce44SJohn Forte 		if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
2491fcf3ce44SJohn Forte 		    sizeof (p_size), mode) != 0) {
2492fcf3ce44SJohn Forte 			rc = EFAULT;
2493fcf3ce44SJohn Forte 		}
2494fcf3ce44SJohn Forte 	}
2495fcf3ce44SJohn Forte 
2496fcf3ce44SJohn Forte 	return (rc);
2497fcf3ce44SJohn Forte }
2498fcf3ce44SJohn Forte 
2499fcf3ce44SJohn Forte 
2500fcf3ce44SJohn Forte #ifdef DKIOCPARTITION
2501fcf3ce44SJohn Forte /*
2502fcf3ce44SJohn Forte  * re-write the size of the current partition
2503fcf3ce44SJohn Forte  *
2504fcf3ce44SJohn Forte  * arg is dk_efi_t.
2505fcf3ce44SJohn Forte  *
2506fcf3ce44SJohn Forte  * dk_efi_t->dki_data = (void *)(uintptr_t)efi.dki_data_64;
2507fcf3ce44SJohn Forte  *
2508fcf3ce44SJohn Forte  * dk_efi_t->dki_data --> efi_gpt_t (label header)
2509fcf3ce44SJohn Forte  * dk_efi_t->dki_data + 1 --> efi_gpe_t[] (array of partitions)
2510fcf3ce44SJohn Forte  *
2511fcf3ce44SJohn Forte  * efi_gpt_t->efi_gpt_PartitionEntryArrayCRC32 --> CRC32 of array of parts
2512fcf3ce44SJohn Forte  * efi_gpt_t->efi_gpt_HeaderCRC32 --> CRC32 of header itself
2513fcf3ce44SJohn Forte  *
2514fcf3ce44SJohn Forte  * This assumes that sizeof (efi_gpt_t) is the same as the size of a
2515fcf3ce44SJohn Forte  * logical block on the disk.
2516fcf3ce44SJohn Forte  *
2517fcf3ce44SJohn Forte  * Everything is little endian (i.e. disk format).
2518fcf3ce44SJohn Forte  */
2519fcf3ce44SJohn Forte static int
sv_fix_dkiocgetefi(const intptr_t arg,const int mode,sv_dev_t * svp)2520fcf3ce44SJohn Forte sv_fix_dkiocgetefi(const intptr_t arg, const int mode, sv_dev_t *svp)
2521fcf3ce44SJohn Forte {
2522fcf3ce44SJohn Forte 	dk_efi_t efi;
2523fcf3ce44SJohn Forte 	efi_gpt_t gpt;
2524fcf3ce44SJohn Forte 	efi_gpe_t *gpe = NULL;
2525fcf3ce44SJohn Forte 	size_t sgpe;
2526fcf3ce44SJohn Forte 	uint64_t p_size;	/* virtual partition size from nsctl */
2527fcf3ce44SJohn Forte 	uint32_t crc;
2528fcf3ce44SJohn Forte 	int unparts;		/* number of parts in user's array */
2529fcf3ce44SJohn Forte 	int pnum;
2530fcf3ce44SJohn Forte 	int rc;
2531fcf3ce44SJohn Forte 
2532fcf3ce44SJohn Forte 	rc = nskern_partition(svp->sv_dev, &pnum);
2533fcf3ce44SJohn Forte 	if (rc != 0) {
2534fcf3ce44SJohn Forte 		return (rc);
2535fcf3ce44SJohn Forte 	}
2536fcf3ce44SJohn Forte 
2537fcf3ce44SJohn Forte 	if (pnum < 0) {
2538fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
25393270659fSSrikanth, Ramana 		    "!sv_efi: unable to determine partition number for dev %lx",
2540fcf3ce44SJohn Forte 		    svp->sv_dev);
2541fcf3ce44SJohn Forte 		return (EINVAL);
2542fcf3ce44SJohn Forte 	}
2543fcf3ce44SJohn Forte 
2544fcf3ce44SJohn Forte 	if (ddi_copyin((void *)arg, &efi, sizeof (efi), mode)) {
2545fcf3ce44SJohn Forte 		return (EFAULT);
2546fcf3ce44SJohn Forte 	}
2547fcf3ce44SJohn Forte 
2548fcf3ce44SJohn Forte 	efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
2549fcf3ce44SJohn Forte 
2550fcf3ce44SJohn Forte 	if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) {
2551fcf3ce44SJohn Forte 		return (EINVAL);
2552fcf3ce44SJohn Forte 	}
2553fcf3ce44SJohn Forte 
2554fcf3ce44SJohn Forte 	if (ddi_copyin((void *)efi.dki_data, &gpt, sizeof (gpt), mode)) {
2555fcf3ce44SJohn Forte 		rc = EFAULT;
2556fcf3ce44SJohn Forte 		goto out;
2557fcf3ce44SJohn Forte 	}
2558fcf3ce44SJohn Forte 
2559fcf3ce44SJohn Forte 	if ((unparts = LE_32(gpt.efi_gpt_NumberOfPartitionEntries)) == 0)
2560fcf3ce44SJohn Forte 		unparts = 1;
2561fcf3ce44SJohn Forte 	else if (pnum >= unparts) {
2562fcf3ce44SJohn Forte 		cmn_err(CE_WARN,
25633270659fSSrikanth, Ramana 		    "!sv_efi: partition# beyond end of user array (%d >= %d)",
2564fcf3ce44SJohn Forte 		    pnum, unparts);
2565fcf3ce44SJohn Forte 		return (EINVAL);
2566fcf3ce44SJohn Forte 	}
2567fcf3ce44SJohn Forte 
2568fcf3ce44SJohn Forte 	sgpe = sizeof (*gpe) * unparts;
2569fcf3ce44SJohn Forte 	gpe = kmem_alloc(sgpe, KM_SLEEP);
2570fcf3ce44SJohn Forte 
2571fcf3ce44SJohn Forte 	if (ddi_copyin((void *)(efi.dki_data + 1), gpe, sgpe, mode)) {
2572fcf3ce44SJohn Forte 		rc = EFAULT;
2573fcf3ce44SJohn Forte 		goto out;
2574fcf3ce44SJohn Forte 	}
2575fcf3ce44SJohn Forte 
2576fcf3ce44SJohn Forte 	p_size = svp->sv_nblocks;
2577fcf3ce44SJohn Forte 	if (p_size == 0) {
2578fcf3ce44SJohn Forte 		if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
2579fcf3ce44SJohn Forte 			p_size = (diskaddr_t)svp->sv_nblocks;
2580fcf3ce44SJohn Forte 			nsc_release(svp->sv_fd);
2581fcf3ce44SJohn Forte 		} else {
2582fcf3ce44SJohn Forte 			rc = EINTR;
2583fcf3ce44SJohn Forte 		}
2584fcf3ce44SJohn Forte 	}
2585fcf3ce44SJohn Forte 
2586fcf3ce44SJohn Forte 	gpe[pnum].efi_gpe_EndingLBA = LE_64(
2587fcf3ce44SJohn Forte 	    LE_64(gpe[pnum].efi_gpe_StartingLBA) + p_size - 1);
2588fcf3ce44SJohn Forte 
2589fcf3ce44SJohn Forte 	gpt.efi_gpt_PartitionEntryArrayCRC32 = 0;
2590fcf3ce44SJohn Forte 	CRC32(crc, gpe, sgpe, -1U, sv_crc32_table);
2591fcf3ce44SJohn Forte 	gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc);
2592fcf3ce44SJohn Forte 
2593fcf3ce44SJohn Forte 	gpt.efi_gpt_HeaderCRC32 = 0;
2594fcf3ce44SJohn Forte 	CRC32(crc, &gpt, sizeof (gpt), -1U, sv_crc32_table);
2595fcf3ce44SJohn Forte 	gpt.efi_gpt_HeaderCRC32 = LE_32(~crc);
2596fcf3ce44SJohn Forte 
2597fcf3ce44SJohn Forte 	if ((rc == 0) && ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), mode)) {
2598fcf3ce44SJohn Forte 		rc = EFAULT;
2599fcf3ce44SJohn Forte 		goto out;
2600fcf3ce44SJohn Forte 	}
2601fcf3ce44SJohn Forte 
2602fcf3ce44SJohn Forte 	if ((rc == 0) && ddi_copyout(gpe, efi.dki_data + 1, sgpe, mode)) {
2603fcf3ce44SJohn Forte 		rc = EFAULT;
2604fcf3ce44SJohn Forte 		goto out;
2605fcf3ce44SJohn Forte 	}
2606fcf3ce44SJohn Forte 
2607fcf3ce44SJohn Forte out:
2608fcf3ce44SJohn Forte 	if (gpe) {
2609fcf3ce44SJohn Forte 		kmem_free(gpe, sgpe);
2610fcf3ce44SJohn Forte 	}
2611fcf3ce44SJohn Forte 
2612fcf3ce44SJohn Forte 	return (rc);
2613fcf3ce44SJohn Forte }
2614fcf3ce44SJohn Forte 
2615fcf3ce44SJohn Forte 
2616fcf3ce44SJohn Forte /*
2617fcf3ce44SJohn Forte  * Re-write the size of the partition specified by p_partno
2618fcf3ce44SJohn Forte  *
2619fcf3ce44SJohn Forte  * Note that if a DKIOCPARTITION is issued to an fd opened against a
2620fcf3ce44SJohn Forte  * non-sv'd device, but p_partno requests the size for a different
2621fcf3ce44SJohn Forte  * device that is sv'd, this function will *not* be called as sv is
2622fcf3ce44SJohn Forte  * not interposed on the original device (the fd).
2623fcf3ce44SJohn Forte  *
2624fcf3ce44SJohn Forte  * It would not be easy to change this as we cannot get the partition
2625fcf3ce44SJohn Forte  * number for the non-sv'd device, so cannot compute the dev_t of the
2626fcf3ce44SJohn Forte  * (sv'd) p_partno device, and so cannot find out if it is sv'd or get
2627fcf3ce44SJohn Forte  * its size from nsctl.
2628fcf3ce44SJohn Forte  *
2629fcf3ce44SJohn Forte  * See also the "Bug 4755783" comment in sv_lyr_ioctl().
2630fcf3ce44SJohn Forte  */
2631fcf3ce44SJohn Forte static int
sv_fix_dkiocpartition(const intptr_t arg,const int mode,sv_dev_t * svp)2632fcf3ce44SJohn Forte sv_fix_dkiocpartition(const intptr_t arg, const int mode, sv_dev_t *svp)
2633fcf3ce44SJohn Forte {
2634fcf3ce44SJohn Forte 	struct partition64 p64;
2635fcf3ce44SJohn Forte 	sv_dev_t *nsvp = NULL;
2636fcf3ce44SJohn Forte 	diskaddr_t p_size;
2637fcf3ce44SJohn Forte 	minor_t nminor;
2638fcf3ce44SJohn Forte 	int pnum, rc;
2639fcf3ce44SJohn Forte 	dev_t ndev;
2640fcf3ce44SJohn Forte 
2641fcf3ce44SJohn Forte 	rc = nskern_partition(svp->sv_dev, &pnum);
2642fcf3ce44SJohn Forte 	if (rc != 0) {
2643fcf3ce44SJohn Forte 		return (rc);
2644fcf3ce44SJohn Forte 	}
2645fcf3ce44SJohn Forte 
2646fcf3ce44SJohn Forte 	if (ddi_copyin((void *)arg, &p64, sizeof (p64), mode)) {
2647fcf3ce44SJohn Forte 		return (EFAULT);
2648fcf3ce44SJohn Forte 	}
2649fcf3ce44SJohn Forte 
2650fcf3ce44SJohn Forte 	if (p64.p_partno != pnum) {
2651fcf3ce44SJohn Forte 		/* switch to requested partition, not the current one */
2652fcf3ce44SJohn Forte 		nminor = getminor(svp->sv_dev) + (p64.p_partno - pnum);
2653fcf3ce44SJohn Forte 		ndev = makedevice(getmajor(svp->sv_dev), nminor);
2654fcf3ce44SJohn Forte 		nsvp = sv_find_enabled(ndev, NULL);
2655fcf3ce44SJohn Forte 		if (nsvp == NULL) {
2656fcf3ce44SJohn Forte 			/* not sv device - just return */
2657fcf3ce44SJohn Forte 			return (0);
2658fcf3ce44SJohn Forte 		}
2659fcf3ce44SJohn Forte 
2660fcf3ce44SJohn Forte 		svp = nsvp;
2661fcf3ce44SJohn Forte 	}
2662fcf3ce44SJohn Forte 
2663fcf3ce44SJohn Forte 	p_size = svp->sv_nblocks;
2664fcf3ce44SJohn Forte 	if (p_size == 0) {
2665fcf3ce44SJohn Forte 		if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
2666fcf3ce44SJohn Forte 			p_size = (diskaddr_t)svp->sv_nblocks;
2667fcf3ce44SJohn Forte 			nsc_release(svp->sv_fd);
2668fcf3ce44SJohn Forte 		} else {
2669fcf3ce44SJohn Forte 			rc = EINTR;
2670fcf3ce44SJohn Forte 		}
2671fcf3ce44SJohn Forte 	}
2672fcf3ce44SJohn Forte 
2673fcf3ce44SJohn Forte 	if (nsvp != NULL) {
2674fcf3ce44SJohn Forte 		rw_exit(&nsvp->sv_lock);
2675fcf3ce44SJohn Forte 	}
2676fcf3ce44SJohn Forte 
2677fcf3ce44SJohn Forte 	if ((rc == 0) && ddi_copyout(&p_size,
2678fcf3ce44SJohn Forte 	    (void *)(arg + offsetof(struct partition64, p_size)),
2679fcf3ce44SJohn Forte 	    sizeof (p_size), mode) != 0) {
2680fcf3ce44SJohn Forte 		return (EFAULT);
2681fcf3ce44SJohn Forte 	}
2682fcf3ce44SJohn Forte 
2683fcf3ce44SJohn Forte 	return (rc);
2684fcf3ce44SJohn Forte }
2685fcf3ce44SJohn Forte #endif /* DKIOCPARTITION */
2686fcf3ce44SJohn Forte 
2687fcf3ce44SJohn Forte 
2688fcf3ce44SJohn Forte static int
sv_lyr_ioctl(const dev_t dev,const int cmd,const intptr_t arg,const int mode,cred_t * crp,int * rvalp)2689fcf3ce44SJohn Forte sv_lyr_ioctl(const dev_t dev, const int cmd, const intptr_t arg,
2690fcf3ce44SJohn Forte     const int mode, cred_t *crp, int *rvalp)
2691fcf3ce44SJohn Forte {
2692fcf3ce44SJohn Forte 	sv_dev_t *svp;
2693fcf3ce44SJohn Forte 	sv_maj_t *maj;
2694fcf3ce44SJohn Forte 	int (*fn)();
2695fcf3ce44SJohn Forte 	int rc = 0;
2696fcf3ce44SJohn Forte 
2697fcf3ce44SJohn Forte 	maj = 0;
2698fcf3ce44SJohn Forte 	fn = 0;
2699fcf3ce44SJohn Forte 
2700fcf3ce44SJohn Forte 	/*
2701fcf3ce44SJohn Forte 	 * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
2702fcf3ce44SJohn Forte 	 * else it means it previously was SV_PREVENT_UNLOAD, and now it's
2703fcf3ce44SJohn Forte 	 * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
2704fcf3ce44SJohn Forte 	 *
2705fcf3ce44SJohn Forte 	 * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
2706fcf3ce44SJohn Forte 	 */
2707fcf3ce44SJohn Forte 	if (sv_mod_status == SV_ALLOW_UNLOAD) {
2708fcf3ce44SJohn Forte 		return (EBUSY);
2709fcf3ce44SJohn Forte 	}
2710fcf3ce44SJohn Forte 
2711fcf3ce44SJohn Forte 	svp = sv_find_enabled(dev, &maj);
2712fcf3ce44SJohn Forte 	if (svp != NULL) {
2713fcf3ce44SJohn Forte 		if (nskernd_isdaemon()) {
2714fcf3ce44SJohn Forte 			/*
2715fcf3ce44SJohn Forte 			 * This is nskernd which always needs to see
2716fcf3ce44SJohn Forte 			 * the underlying disk device accurately.
2717fcf3ce44SJohn Forte 			 *
2718fcf3ce44SJohn Forte 			 * So just pass the ioctl straight through
2719fcf3ce44SJohn Forte 			 * to the underlying driver as though the device
2720fcf3ce44SJohn Forte 			 * was not sv enabled.
2721fcf3ce44SJohn Forte 			 */
27223270659fSSrikanth, Ramana 			DTRACE_PROBE2(sv_lyr_ioctl_nskernd, sv_dev_t *, svp,
2723fcf3ce44SJohn Forte 			    dev_t, dev);
2724fcf3ce44SJohn Forte 
2725fcf3ce44SJohn Forte 			rw_exit(&svp->sv_lock);
2726fcf3ce44SJohn Forte 			svp = NULL;
2727fcf3ce44SJohn Forte 		} else {
2728fcf3ce44SJohn Forte 			ASSERT(RW_READ_HELD(&svp->sv_lock));
2729fcf3ce44SJohn Forte 		}
2730fcf3ce44SJohn Forte 	}
2731fcf3ce44SJohn Forte 
2732fcf3ce44SJohn Forte 	/*
2733fcf3ce44SJohn Forte 	 * We now have a locked and enabled SV device, or a non-SV device.
2734fcf3ce44SJohn Forte 	 */
2735fcf3ce44SJohn Forte 
2736fcf3ce44SJohn Forte 	switch (cmd) {
2737fcf3ce44SJohn Forte 		/*
2738fcf3ce44SJohn Forte 		 * DKIOCGVTOC, DKIOCSVTOC, DKIOCPARTITION, DKIOCGETEFI
2739fcf3ce44SJohn Forte 		 * and DKIOCSETEFI are intercepted and faked up as some
2740fcf3ce44SJohn Forte 		 * i/o providers emulate volumes of a different size to
2741fcf3ce44SJohn Forte 		 * the underlying volume.
2742fcf3ce44SJohn Forte 		 *
2743fcf3ce44SJohn Forte 		 * Setting the size by rewriting the vtoc is not permitted.
2744fcf3ce44SJohn Forte 		 */
2745fcf3ce44SJohn Forte 
2746fcf3ce44SJohn Forte 	case DKIOCSVTOC:
2747fcf3ce44SJohn Forte #ifdef DKIOCPARTITION
2748fcf3ce44SJohn Forte 	case DKIOCSETEFI:
2749fcf3ce44SJohn Forte #endif
2750fcf3ce44SJohn Forte 		if (svp == NULL) {
2751fcf3ce44SJohn Forte 			/* not intercepted -- allow ioctl through */
2752fcf3ce44SJohn Forte 			break;
2753fcf3ce44SJohn Forte 		}
2754fcf3ce44SJohn Forte 
2755fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
2756fcf3ce44SJohn Forte 
27573270659fSSrikanth, Ramana 		DTRACE_PROBE2(sv_lyr_ioctl_svtoc, dev_t, dev, int, EPERM);
2758fcf3ce44SJohn Forte 
2759fcf3ce44SJohn Forte 		return (EPERM);
2760fcf3ce44SJohn Forte 
2761fcf3ce44SJohn Forte 	default:
2762fcf3ce44SJohn Forte 		break;
2763fcf3ce44SJohn Forte 	}
2764fcf3ce44SJohn Forte 
2765fcf3ce44SJohn Forte 	/*
2766fcf3ce44SJohn Forte 	 * Pass through the real ioctl command.
2767fcf3ce44SJohn Forte 	 */
2768fcf3ce44SJohn Forte 
2769fcf3ce44SJohn Forte 	if (maj && (fn = maj->sm_ioctl) != 0) {
2770fcf3ce44SJohn Forte 		if (!(maj->sm_flag & D_MP)) {
2771fcf3ce44SJohn Forte 			UNSAFE_ENTER();
2772fcf3ce44SJohn Forte 			rc = (*fn)(dev, cmd, arg, mode, crp, rvalp);
2773fcf3ce44SJohn Forte 			UNSAFE_EXIT();
2774fcf3ce44SJohn Forte 		} else {
2775fcf3ce44SJohn Forte 			rc = (*fn)(dev, cmd, arg, mode, crp, rvalp);
2776fcf3ce44SJohn Forte 		}
2777fcf3ce44SJohn Forte 	} else {
2778fcf3ce44SJohn Forte 		rc = ENODEV;
2779fcf3ce44SJohn Forte 	}
2780fcf3ce44SJohn Forte 
2781fcf3ce44SJohn Forte 	/*
2782fcf3ce44SJohn Forte 	 * Bug 4755783
2783fcf3ce44SJohn Forte 	 * Fix up the size of the current partition to allow
2784fcf3ce44SJohn Forte 	 * for the virtual volume to be a different size to the
2785fcf3ce44SJohn Forte 	 * physical volume (e.g. for II compact dependent shadows).
2786fcf3ce44SJohn Forte 	 *
2787fcf3ce44SJohn Forte 	 * Note that this only attempts to fix up the current partition
2788fcf3ce44SJohn Forte 	 * - the one that the ioctl was issued against.  There could be
2789fcf3ce44SJohn Forte 	 * other sv'd partitions in the same vtoc, but we cannot tell
2790fcf3ce44SJohn Forte 	 * so we don't attempt to fix them up.
2791fcf3ce44SJohn Forte 	 */
2792fcf3ce44SJohn Forte 
2793fcf3ce44SJohn Forte 	if (svp != NULL && rc == 0) {
2794fcf3ce44SJohn Forte 		switch (cmd) {
2795fcf3ce44SJohn Forte 		case DKIOCGVTOC:
2796fcf3ce44SJohn Forte 			rc = sv_fix_dkiocgvtoc(arg, mode, svp);
2797fcf3ce44SJohn Forte 			break;
2798fcf3ce44SJohn Forte 
2799fcf3ce44SJohn Forte #ifdef DKIOCPARTITION
2800fcf3ce44SJohn Forte 		case DKIOCGETEFI:
2801fcf3ce44SJohn Forte 			rc = sv_fix_dkiocgetefi(arg, mode, svp);
2802fcf3ce44SJohn Forte 			break;
2803fcf3ce44SJohn Forte 
2804fcf3ce44SJohn Forte 		case DKIOCPARTITION:
2805fcf3ce44SJohn Forte 			rc = sv_fix_dkiocpartition(arg, mode, svp);
2806fcf3ce44SJohn Forte 			break;
2807fcf3ce44SJohn Forte #endif /* DKIOCPARTITION */
2808fcf3ce44SJohn Forte 		}
2809fcf3ce44SJohn Forte 	}
2810fcf3ce44SJohn Forte 
2811fcf3ce44SJohn Forte 	if (svp != NULL) {
2812fcf3ce44SJohn Forte 		rw_exit(&svp->sv_lock);
2813fcf3ce44SJohn Forte 	}
2814fcf3ce44SJohn Forte 
2815fcf3ce44SJohn Forte 	return (rc);
2816fcf3ce44SJohn Forte }
2817