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