xref: /titanic_50/usr/src/uts/common/avs/ns/rdc/rdc.c (revision 356f72340a69936724c69f2f87fffa6f5887f885)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #define	_RDC_
27 #include <sys/types.h>
28 #include <sys/ksynch.h>
29 #include <sys/kmem.h>
30 #include <sys/errno.h>
31 #include <sys/conf.h>
32 #include <sys/cmn_err.h>
33 #include <sys/modctl.h>
34 #include <sys/cred.h>
35 #include <sys/ddi.h>
36 #include <sys/sysmacros.h>
37 #include <sys/unistat/spcs_s.h>
38 #include <sys/unistat/spcs_s_k.h>
39 #include <sys/unistat/spcs_errors.h>
40 
41 #include <sys/nsc_thread.h>
42 #ifdef DS_DDICT
43 #include "../contract.h"
44 #endif
45 #include <sys/nsctl/nsctl.h>
46 #include <sys/nsctl/nsvers.h>
47 
48 #include <sys/sdt.h>		/* dtrace is S10 or later */
49 
50 #include "rdc.h"
51 #include "rdc_io.h"
52 #include "rdc_bitmap.h"
53 #include "rdc_ioctl.h"
54 #include "rdcsrv.h"
55 #include "rdc_diskq.h"
56 
57 #define	DIDINIT		0x01
58 #define	DIDNODES	0x02
59 #define	DIDCONFIG	0x04
60 
61 static int rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp);
62 static int rdcclose(dev_t dev, int flag, int otyp, cred_t *crp);
63 static int rdcprint(dev_t dev, char *str);
64 static int rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp,
65 	int *rvp);
66 static int rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
67 static int rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
68 static int rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
69 	void **result);
70 #ifdef	DEBUG
71 static int rdc_clrkstat(void *);
72 #endif
73 
74 /*
75  * kstat interface
76  */
77 static kstat_t *sndr_kstats;
78 
79 int sndr_info_stats_update(kstat_t *ksp, int rw);
80 
81 static sndr_m_stats_t sndr_info_stats = {
82 	{RDC_MKSTAT_MAXSETS,			KSTAT_DATA_ULONG},
83 	{RDC_MKSTAT_MAXFBAS,			KSTAT_DATA_ULONG},
84 	{RDC_MKSTAT_RPC_TIMEOUT,		KSTAT_DATA_ULONG},
85 	{RDC_MKSTAT_HEALTH_THRES,		KSTAT_DATA_ULONG},
86 	{RDC_MKSTAT_BITMAP_WRITES,		KSTAT_DATA_ULONG},
87 	{RDC_MKSTAT_CLNT_COTS_CALLS,		KSTAT_DATA_ULONG},
88 	{RDC_MKSTAT_CLNT_CLTS_CALLS,		KSTAT_DATA_ULONG},
89 	{RDC_MKSTAT_SVC_COTS_CALLS,		KSTAT_DATA_ULONG},
90 	{RDC_MKSTAT_SVC_CLTS_CALLS,		KSTAT_DATA_ULONG},
91 	{RDC_MKSTAT_BITMAP_REF_DELAY,		KSTAT_DATA_ULONG}
92 };
93 
94 int rdc_info_stats_update(kstat_t *ksp, int rw);
95 
96 static rdc_info_stats_t rdc_info_stats = {
97 	{RDC_IKSTAT_FLAGS,		KSTAT_DATA_ULONG},
98 	{RDC_IKSTAT_SYNCFLAGS,		KSTAT_DATA_ULONG},
99 	{RDC_IKSTAT_BMPFLAGS,		KSTAT_DATA_ULONG},
100 	{RDC_IKSTAT_SYNCPOS,		KSTAT_DATA_ULONG},
101 	{RDC_IKSTAT_VOLSIZE,		KSTAT_DATA_ULONG},
102 	{RDC_IKSTAT_BITSSET,		KSTAT_DATA_ULONG},
103 	{RDC_IKSTAT_AUTOSYNC,		KSTAT_DATA_ULONG},
104 	{RDC_IKSTAT_MAXQFBAS,		KSTAT_DATA_ULONG},
105 	{RDC_IKSTAT_MAXQITEMS,		KSTAT_DATA_ULONG},
106 	{RDC_IKSTAT_FILE,		KSTAT_DATA_STRING},
107 	{RDC_IKSTAT_SECFILE,		KSTAT_DATA_STRING},
108 	{RDC_IKSTAT_BITMAP,		KSTAT_DATA_STRING},
109 	{RDC_IKSTAT_PRIMARY_HOST,	KSTAT_DATA_STRING},
110 	{RDC_IKSTAT_SECONDARY_HOST,	KSTAT_DATA_STRING},
111 	{RDC_IKSTAT_TYPE_FLAG,		KSTAT_DATA_ULONG},
112 	{RDC_IKSTAT_BMP_SIZE,		KSTAT_DATA_ULONG},
113 	{RDC_IKSTAT_DISK_STATUS,	KSTAT_DATA_ULONG},
114 	{RDC_IKSTAT_IF_DOWN,		KSTAT_DATA_ULONG},
115 	{RDC_IKSTAT_IF_RPC_VERSION,	KSTAT_DATA_ULONG},
116 	{RDC_IKSTAT_ASYNC_BLOCK_HWM,	KSTAT_DATA_ULONG},
117 	{RDC_IKSTAT_ASYNC_ITEM_HWM,	KSTAT_DATA_ULONG},
118 	{RDC_IKSTAT_ASYNC_THROTTLE_DELAY,	KSTAT_DATA_ULONG},
119 	{RDC_IKSTAT_ASYNC_ITEMS,	KSTAT_DATA_ULONG},
120 	{RDC_IKSTAT_ASYNC_BLOCKS,	KSTAT_DATA_ULONG},
121 	{RDC_IKSTAT_QUEUE_TYPE,		KSTAT_DATA_CHAR}
122 };
123 
124 static struct cb_ops rdc_cb_ops = {
125 	rdcopen,
126 	rdcclose,
127 	nulldev,		/* no strategy */
128 	rdcprint,
129 	nodev,			/* no dump */
130 	nodev,			/* no read */
131 	nodev,			/* no write */
132 	rdcioctl,
133 	nodev,			/* no devmap */
134 	nodev,			/* no mmap */
135 	nodev,			/* no segmap */
136 	nochpoll,
137 	ddi_prop_op,
138 	NULL,			/* not STREAMS */
139 	D_NEW | D_MP | D_64BIT,
140 	CB_REV,
141 	nodev,			/* no aread */
142 	nodev,			/* no awrite */
143 };
144 
145 static struct dev_ops rdc_ops = {
146 	DEVO_REV,
147 	0,
148 	rdcgetinfo,
149 	nulldev,		/* identify */
150 	nulldev,		/* probe */
151 	rdcattach,
152 	rdcdetach,
153 	nodev,			/* no reset */
154 	&rdc_cb_ops,
155 	(struct bus_ops *)NULL
156 };
157 
158 static struct modldrv rdc_ldrv = {
159 	&mod_driverops,
160 	"nws:Remote Mirror:" ISS_VERSION_STR,
161 	&rdc_ops
162 };
163 
164 static struct modlinkage rdc_modlinkage = {
165 	MODREV_1,
166 	&rdc_ldrv,
167 	NULL
168 };
169 
170 const	int sndr_major_rev = ISS_VERSION_MAJ;
171 const	int sndr_minor_rev = ISS_VERSION_MIN;
172 const	int sndr_micro_rev = ISS_VERSION_MIC;
173 const	int sndr_baseline_rev = ISS_VERSION_NUM;
174 static	char sndr_version[16];
175 
176 static void *rdc_dip;
177 
178 extern int _rdc_init_dev();
179 extern void _rdc_deinit_dev();
180 extern void rdc_link_down_free();
181 
182 int rdc_bitmap_mode;
183 int rdc_auto_sync;
184 int rdc_max_sets;
185 extern int rdc_health_thres;
186 
187 kmutex_t rdc_sync_mutex;
188 rdc_sync_event_t rdc_sync_event;
189 clock_t rdc_sync_event_timeout;
190 
191 static void
192 rdc_sync_event_init()
193 {
194 	mutex_init(&rdc_sync_mutex, NULL, MUTEX_DRIVER, NULL);
195 	mutex_init(&rdc_sync_event.mutex, NULL, MUTEX_DRIVER, NULL);
196 	cv_init(&rdc_sync_event.cv, NULL, CV_DRIVER, NULL);
197 	cv_init(&rdc_sync_event.done_cv, NULL, CV_DRIVER, NULL);
198 	rdc_sync_event.master[0] = 0;
199 	rdc_sync_event.lbolt = (clock_t)0;
200 	rdc_sync_event_timeout = RDC_SYNC_EVENT_TIMEOUT;
201 }
202 
203 
204 static void
205 rdc_sync_event_destroy()
206 {
207 	mutex_destroy(&rdc_sync_mutex);
208 	mutex_destroy(&rdc_sync_event.mutex);
209 	cv_destroy(&rdc_sync_event.cv);
210 	cv_destroy(&rdc_sync_event.done_cv);
211 }
212 
213 
214 
215 int
216 _init(void)
217 {
218 	return (mod_install(&rdc_modlinkage));
219 }
220 
221 int
222 _fini(void)
223 {
224 	return (mod_remove(&rdc_modlinkage));
225 }
226 
227 int
228 _info(struct modinfo *modinfop)
229 {
230 	return (mod_info(&rdc_modlinkage, modinfop));
231 }
232 
233 static int
234 rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
235 {
236 	intptr_t flags;
237 	int instance;
238 	int i;
239 
240 	/*CONSTCOND*/
241 	ASSERT(sizeof (u_longlong_t) == 8);
242 
243 	if (cmd != DDI_ATTACH)
244 		return (DDI_FAILURE);
245 
246 	(void) strncpy(sndr_version, _VERSION_, sizeof (sndr_version));
247 
248 	instance = ddi_get_instance(dip);
249 	rdc_dip = dip;
250 
251 	flags = 0;
252 
253 	rdc_sync_event_init();
254 
255 	/*
256 	 * rdc_max_sets must be set before calling _rdc_load().
257 	 */
258 
259 	rdc_max_sets = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
260 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "rdc_max_sets", 64);
261 
262 	if (_rdc_init_dev()) {
263 		cmn_err(CE_WARN, "!rdc: _rdc_init_dev failed");
264 		goto out;
265 	}
266 	flags |= DIDINIT;
267 
268 	if (_rdc_load() != 0) {
269 		cmn_err(CE_WARN, "!rdc: _rdc_load failed");
270 		goto out;
271 	}
272 
273 	if (_rdc_configure()) {
274 		cmn_err(CE_WARN, "!rdc: _rdc_configure failed");
275 		goto out;
276 	}
277 	flags |= DIDCONFIG;
278 
279 	if (ddi_create_minor_node(dip, "rdc", S_IFCHR, instance, DDI_PSEUDO, 0)
280 	    != DDI_SUCCESS) {
281 		cmn_err(CE_WARN, "!rdc: could not create node.");
282 		goto out;
283 	}
284 	flags |= DIDNODES;
285 
286 	rdc_bitmap_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
287 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
288 	    "rdc_bitmap_mode", 0);
289 
290 	switch (rdc_bitmap_mode) {
291 	case RDC_BMP_AUTO:		/* 0 */
292 		break;
293 	case RDC_BMP_ALWAYS:		/* 1 */
294 		break;
295 	case RDC_BMP_NEVER:		/* 2 */
296 		cmn_err(CE_NOTE, "!SNDR bitmap mode override");
297 		cmn_err(CE_CONT,
298 		    "!SNDR: bitmaps will only be written on shutdown\n");
299 		break;
300 	default:			/* unknown */
301 		cmn_err(CE_NOTE,
302 		    "!SNDR: unknown bitmap mode %d - autodetecting mode",
303 		    rdc_bitmap_mode);
304 		rdc_bitmap_mode = RDC_BMP_AUTO;
305 		break;
306 	}
307 
308 	rdc_bitmap_init();
309 
310 	rdc_auto_sync = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
311 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
312 	    "rdc_auto_sync", 0);
313 
314 	i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
315 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
316 	    "rdc_health_thres", RDC_HEALTH_THRESHOLD);
317 	if (i >= RDC_MIN_HEALTH_THRES)
318 		rdc_health_thres = i;
319 	else
320 		cmn_err(CE_WARN, "!value rdc_heath_thres from rdc.conf ignored "
321 		    "as it is smaller than the min value of %d",
322 		    RDC_MIN_HEALTH_THRES);
323 
324 	ddi_set_driver_private(dip, (caddr_t)flags);
325 	ddi_report_dev(dip);
326 
327 	sndr_kstats = kstat_create(RDC_KSTAT_MODULE, 0,
328 	    RDC_KSTAT_MINFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
329 	    sizeof (sndr_m_stats_t) / sizeof (kstat_named_t),
330 	    KSTAT_FLAG_VIRTUAL);
331 
332 	if (sndr_kstats) {
333 		sndr_kstats->ks_data = &sndr_info_stats;
334 		sndr_kstats->ks_update = sndr_info_stats_update;
335 		sndr_kstats->ks_private = &rdc_k_info[0];
336 		kstat_install(sndr_kstats);
337 	} else
338 			cmn_err(CE_WARN, "!SNDR: module kstats failed");
339 
340 	return (DDI_SUCCESS);
341 
342 out:
343 	DTRACE_PROBE(rdc_attach_failed);
344 	ddi_set_driver_private(dip, (caddr_t)flags);
345 	(void) rdcdetach(dip, DDI_DETACH);
346 	return (DDI_FAILURE);
347 }
348 
349 static int
350 rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
351 {
352 	rdc_k_info_t *krdc;
353 	rdc_u_info_t *urdc;
354 	int rdcd;
355 	intptr_t flags;
356 
357 
358 	if (cmd != DDI_DETACH) {
359 		DTRACE_PROBE(rdc_detach_unknown_cmd);
360 		return (DDI_FAILURE);
361 	}
362 
363 	if (rdc_k_info == NULL || rdc_u_info == NULL)
364 		goto cleanup;
365 
366 	mutex_enter(&rdc_conf_lock);
367 
368 	for (rdcd = 0; rdcd < rdc_max_sets; rdcd++) {
369 		krdc = &rdc_k_info[rdcd];
370 		urdc = &rdc_u_info[rdcd];
371 
372 		if (IS_ENABLED(urdc) || krdc->devices) {
373 #ifdef DEBUG
374 			cmn_err(CE_WARN,
375 			    "!rdc: cannot detach, rdcd %d still in use", rdcd);
376 #endif
377 			mutex_exit(&rdc_conf_lock);
378 			DTRACE_PROBE(rdc_detach_err_busy);
379 			return (DDI_FAILURE);
380 		}
381 	}
382 
383 	mutex_exit(&rdc_conf_lock);
384 
385 cleanup:
386 	flags = (intptr_t)ddi_get_driver_private(dip);
387 
388 	if (flags & DIDNODES)
389 		ddi_remove_minor_node(dip, NULL);
390 
391 	if (sndr_kstats) {
392 		kstat_delete(sndr_kstats);
393 	}
394 	if (flags & DIDINIT)
395 		_rdc_deinit_dev();
396 
397 	if (flags & DIDCONFIG) {
398 		(void) _rdc_deconfigure();
399 		(void) _rdc_unload();
400 		rdcsrv_unload();
401 	}
402 
403 	rdc_sync_event_destroy();
404 	rdc_link_down_free();
405 
406 	rdc_dip = NULL;
407 	return (DDI_SUCCESS);
408 }
409 
410 /* ARGSUSED */
411 static int
412 rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
413 {
414 	int rc = DDI_FAILURE;
415 
416 	switch (infocmd) {
417 
418 	case DDI_INFO_DEVT2DEVINFO:
419 		*result = rdc_dip;
420 		rc = DDI_SUCCESS;
421 		break;
422 
423 	case DDI_INFO_DEVT2INSTANCE:
424 		/* We only have a single instance */
425 		*result = 0;
426 		rc = DDI_SUCCESS;
427 		break;
428 
429 	default:
430 		break;
431 	}
432 
433 	return (rc);
434 }
435 
436 
437 /* ARGSUSED */
438 
439 static int
440 rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp)
441 {
442 	return (0);
443 }
444 
445 
446 /* ARGSUSED */
447 
448 static int
449 rdcclose(dev_t dev, int flag, int otyp, cred_t *crp)
450 {
451 	return (0);
452 }
453 
454 /* ARGSUSED */
455 
456 static int
457 rdcprint(dev_t dev, char *str)
458 {
459 	int instance = 0;
460 
461 	cmn_err(CE_WARN, "!rdc%d: %s", instance, str);
462 	return (0);
463 }
464 
465 
466 static int
467 convert_ioctl_args(int cmd, intptr_t arg, int mode, _rdc_ioctl_t *args)
468 {
469 	_rdc_ioctl32_t args32;
470 
471 	if (ddi_copyin((void *)arg, &args32, sizeof (_rdc_ioctl32_t), mode))
472 		return (EFAULT);
473 
474 	bzero((void *)args, sizeof (_rdc_ioctl_t));
475 
476 	switch (cmd) {
477 	case RDC_CONFIG:
478 		args->arg0 = (uint32_t)args32.arg0; /* _rdc_config_t * */
479 		args->arg1 = (uint32_t)args32.arg1; /* pointer */
480 		args->arg2 = (uint32_t)args32.arg2; /* size */
481 		args->ustatus = (spcs_s_info_t)args32.ustatus;
482 		break;
483 
484 	case RDC_STATUS:
485 		args->arg0 = (uint32_t)args32.arg0; /* pointer */
486 		args->ustatus = (spcs_s_info_t)args32.ustatus;
487 		break;
488 
489 	case RDC_ENABLE_SVR:
490 		args->arg0 = (uint32_t)args32.arg0; /* _rdc_svc_args *  */
491 		break;
492 
493 	case RDC_VERSION:
494 		args->arg0 = (uint32_t)args32.arg0; /* _rdc_version_t *  */
495 		args->ustatus = (spcs_s_info_t)args32.ustatus;
496 		break;
497 
498 	case RDC_SYNC_EVENT:
499 		args->arg0 = (uint32_t)args32.arg0; /* char *  */
500 		args->arg1 = (uint32_t)args32.arg1; /* char *  */
501 		args->ustatus = (spcs_s_info_t)args32.ustatus;
502 		break;
503 
504 	case RDC_LINK_DOWN:
505 		args->arg0 = (uint32_t)args32.arg0; /* char *  */
506 		args->ustatus = (spcs_s_info_t)args32.ustatus;
507 		break;
508 	case RDC_POOL_CREATE:
509 		args->arg0 = (uint32_t)args32.arg0; /* svcpool_args *  */
510 		break;
511 	case RDC_POOL_WAIT:
512 		args->arg0 = (uint32_t)args32.arg0; /* int */
513 		break;
514 	case RDC_POOL_RUN:
515 		args->arg0 = (uint32_t)args32.arg0; /* int */
516 		break;
517 
518 	default:
519 		return (EINVAL);
520 	}
521 
522 	return (0);
523 }
524 
525 /*
526  * Build a 32bit rdc_set structure and copyout to the user level.
527  */
528 int
529 rdc_status_copy32(const void *arg, void *usetp, size_t size, int mode)
530 {
531 	rdc_u_info_t *urdc = (rdc_u_info_t *)arg;
532 	struct rdc_set32 set32;
533 	size_t tailsize;
534 #ifdef DEBUG
535 	size_t tailsize32;
536 #endif
537 
538 	bzero(&set32, sizeof (set32));
539 
540 	tailsize = sizeof (struct rdc_addr32) -
541 	    offsetof(struct rdc_addr32, intf);
542 
543 	/* primary address structure, avoiding netbuf */
544 	bcopy(&urdc->primary.intf[0], &set32.primary.intf[0], tailsize);
545 
546 	/* secondary address structure, avoiding netbuf */
547 	bcopy(&urdc->secondary.intf[0], &set32.secondary.intf[0], tailsize);
548 
549 	/*
550 	 * the rest, avoiding netconfig
551 	 * note: the tail must be the same size in both structures
552 	 */
553 	tailsize = sizeof (struct rdc_set) - offsetof(struct rdc_set, flags);
554 #ifdef DEBUG
555 	/*
556 	 * ASSERT is calling for debug reason, and tailsize32 is only declared
557 	 * for ASSERT, put them under debug to avoid lint warning.
558 	 */
559 	tailsize32 = sizeof (struct rdc_set32) -
560 	    offsetof(struct rdc_set32, flags);
561 	ASSERT(tailsize == tailsize32);
562 #endif
563 
564 	bcopy(&urdc->flags, &set32.flags, tailsize);
565 
566 	/* copyout to user level */
567 	return (ddi_copyout(&set32, usetp, size, mode));
568 }
569 
570 
571 /*
572  * Status ioctl.
573  */
574 static int
575 rdcstatus(_rdc_ioctl_t *args, int mode)
576 {
577 	int (*copyout)(const void *, void *, size_t, int);
578 	rdc_u_info_t *urdc;
579 	rdc_k_info_t *krdc;
580 	disk_queue *dqp;
581 	char *usetp;			/* pointer to user rdc_set structure */
582 	size_t size;			/* sizeof user rdc_set structure */
583 	int32_t *maxsetsp;		/* address of status->maxsets; */
584 	int nset, max, i, j;
585 
586 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
587 		struct rdc_status32 status32;
588 
589 		if (ddi_copyin((void *)args->arg0, &status32,
590 		    sizeof (status32), mode)) {
591 			return (EFAULT);
592 		}
593 
594 		usetp = ((char *)args->arg0) +
595 		    offsetof(struct rdc_status32, rdc_set);
596 		maxsetsp = (int32_t *)((char *)args->arg0 +
597 		    offsetof(struct rdc_status32, maxsets));
598 		nset = status32.nset;
599 
600 		size = sizeof (struct rdc_set32);
601 		copyout = rdc_status_copy32;
602 	} else {
603 		struct rdc_status status;
604 
605 		if (ddi_copyin((void *)args->arg0, &status,
606 		    sizeof (status), mode)) {
607 			return (EFAULT);
608 		}
609 
610 		usetp = ((char *)args->arg0) +
611 		    offsetof(struct rdc_status, rdc_set);
612 		maxsetsp = (int32_t *)((char *)args->arg0 +
613 		    offsetof(struct rdc_status, maxsets));
614 		nset = status.nset;
615 
616 		size = sizeof (struct rdc_set);
617 		copyout = ddi_copyout;
618 	}
619 
620 	max = min(nset, rdc_max_sets);
621 
622 	for (i = 0, j = 0; i < max; i++) {
623 		urdc = &rdc_u_info[i];
624 		krdc = &rdc_k_info[i];
625 
626 		if (!IS_ENABLED(urdc))
627 			continue;
628 
629 		/*
630 		 * sneak out qstate in urdc->flags
631 		 * this is harmless because it's value is not used
632 		 * in urdc->flags. the real qstate is kept in
633 		 * group->diskq->disk_hdr.h.state
634 		 */
635 		if (RDC_IS_DISKQ(krdc->group)) {
636 			dqp = &krdc->group->diskq;
637 			if (IS_QSTATE(dqp, RDC_QNOBLOCK))
638 				urdc->flags |= RDC_QNOBLOCK;
639 		}
640 
641 		j++;
642 		if ((*copyout)(urdc, usetp, size, mode) != 0)
643 			return (EFAULT);
644 
645 		urdc->flags &= ~RDC_QNOBLOCK; /* clear qstate */
646 		usetp += size;
647 	}
648 
649 	/* copyout rdc_max_sets value */
650 
651 	if (ddi_copyout(&rdc_max_sets, maxsetsp, sizeof (*maxsetsp), mode) != 0)
652 		return (EFAULT);
653 
654 	/* copyout number of sets manipulated */
655 
656 	/*CONSTCOND*/
657 	ASSERT(offsetof(struct rdc_status32, nset) == 0);
658 	/*CONSTCOND*/
659 	ASSERT(offsetof(struct rdc_status, nset) == 0);
660 
661 	return (ddi_copyout(&j, (void *)args->arg0, sizeof (int), mode));
662 }
663 
664 
665 /* ARGSUSED */
666 
667 static int
668 rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
669 {
670 	spcs_s_info_t kstatus = NULL;
671 	_rdc_ioctl_t args;
672 	int error;
673 	int rc = 0;
674 
675 	if (cmd != RDC_STATUS) {
676 		if ((error = drv_priv(crp)) != 0)
677 			return (error);
678 	}
679 #ifdef	DEBUG
680 	if (cmd == RDC_ASYNC6) {
681 		rc = rdc_async6((void *)arg, mode, rvp);
682 		return (rc);
683 	}
684 
685 	if (cmd == RDC_CLRKSTAT) {
686 		rc = rdc_clrkstat((void *)arg);
687 		return (rc);
688 	}
689 
690 	if (cmd == RDC_STALL0) {
691 		if (((int)arg > 1) || ((int)arg < 0))
692 			return (EINVAL);
693 		rdc_stallzero((int)arg);
694 		return (0);
695 	}
696 	if (cmd == RDC_READGEN) {
697 		rc = rdc_readgen((void *)arg, mode, rvp);
698 		return (rc);
699 	}
700 #endif
701 	if (cmd == RDC_BITMAPOP) {
702 		rdc_bitmap_op_t bmop;
703 		rdc_bitmap_op32_t bmop32;
704 
705 		if (ddi_model_convert_from(mode & FMODELS)
706 		    == DDI_MODEL_ILP32) {
707 			if (ddi_copyin((void *)arg, &bmop32, sizeof (bmop32),
708 			    mode))
709 				return (EFAULT);
710 			bmop.offset = bmop32.offset;
711 			bmop.op = bmop32.op;
712 			(void) strncpy(bmop.sechost, bmop32.sechost,
713 			    MAX_RDC_HOST_SIZE);
714 			(void) strncpy(bmop.secfile, bmop32.secfile,
715 			    NSC_MAXPATH);
716 			bmop.len = bmop32.len;
717 			bmop.addr = (unsigned long)bmop32.addr;
718 		} else {
719 			if (ddi_copyin((void *)arg, &bmop, sizeof (bmop),
720 			    mode))
721 				return (EFAULT);
722 		}
723 		rc = rdc_bitmapset(bmop.op, bmop.sechost, bmop.secfile,
724 		    (void *)bmop.addr, bmop.len, bmop.offset, mode);
725 		return (rc);
726 	}
727 
728 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
729 		if ((rc = convert_ioctl_args(cmd, arg, mode, &args)) != 0)
730 			return (rc);
731 	} else {
732 		if (ddi_copyin((void *)arg, &args,
733 		    sizeof (_rdc_ioctl_t), mode)) {
734 			return (EFAULT);
735 		}
736 	}
737 
738 	kstatus = spcs_s_kcreate();
739 	if (!kstatus) {
740 		return (ENOMEM);
741 	}
742 
743 
744 	switch (cmd) {
745 
746 	case RDC_POOL_CREATE: {
747 		struct svcpool_args p;
748 
749 		if (ddi_copyin((void *)arg, &p, sizeof (p), mode)) {
750 			spcs_s_kfree(kstatus);
751 			return (EFAULT);
752 		}
753 		error = svc_pool_create(&p);
754 
755 		break;
756 	}
757 	case RDC_POOL_WAIT: {
758 		int id;
759 
760 		if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
761 			spcs_s_kfree(kstatus);
762 			return (EFAULT);
763 		}
764 
765 		error = svc_wait(id);
766 		break;
767 	}
768 	case RDC_POOL_RUN: {
769 		int id;
770 
771 		if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
772 			spcs_s_kfree(kstatus);
773 			return (EFAULT);
774 		}
775 		error = svc_do_run(id);
776 		break;
777 	}
778 	case RDC_ENABLE_SVR:
779 		{
780 			STRUCT_DECL(rdc_svc_args, parms);
781 
782 			STRUCT_INIT(parms, mode);
783 			/* Only used by sndrd which does not use unistat */
784 
785 			if (ddi_copyin((void *)args.arg0, STRUCT_BUF(parms),
786 			    STRUCT_SIZE(parms), mode)) {
787 				spcs_s_kfree(kstatus);
788 				return (EFAULT);
789 			}
790 			rc = rdc_start_server(STRUCT_BUF(parms), mode);
791 		}
792 		break;
793 
794 	case RDC_STATUS:
795 		rc = rdcstatus(&args, mode);
796 		break;
797 
798 	case RDC_CONFIG:
799 		rc = _rdc_config((void *)args.arg0, mode, kstatus, rvp);
800 		spcs_s_copyoutf(&kstatus, args.ustatus);
801 		return (rc);
802 
803 	case RDC_VERSION:
804 		{
805 			STRUCT_DECL(rdc_version, parms);
806 
807 			STRUCT_INIT(parms, mode);
808 
809 			STRUCT_FSET(parms, major, sndr_major_rev);
810 			STRUCT_FSET(parms, minor, sndr_minor_rev);
811 			STRUCT_FSET(parms, micro, sndr_micro_rev);
812 			STRUCT_FSET(parms, baseline, sndr_baseline_rev);
813 
814 			if (ddi_copyout(STRUCT_BUF(parms), (void *)args.arg0,
815 			    STRUCT_SIZE(parms), mode)) {
816 				spcs_s_kfree(kstatus);
817 				return (EFAULT);
818 			}
819 			break;
820 		}
821 
822 	case RDC_LINK_DOWN:
823 		/* char *host from user */
824 		rc = _rdc_link_down((void *)args.arg0, mode, kstatus, rvp);
825 		spcs_s_copyoutf(&kstatus, args.ustatus);
826 
827 		return (rc);
828 
829 	case RDC_SYNC_EVENT:
830 		rc = _rdc_sync_event_wait((void *)args.arg0, (void *)args.arg1,
831 		    mode, kstatus, rvp);
832 		spcs_s_copyoutf(&kstatus, args.ustatus);
833 
834 		return (rc);
835 
836 
837 	default:
838 		rc = EINVAL;
839 		break;
840 	}
841 
842 	spcs_s_kfree(kstatus);
843 	return (rc);
844 }
845 
846 int
847 sndr_info_stats_update(kstat_t *ksp, int rw)
848 {
849 	extern int rdc_rpc_tmout;
850 	extern int rdc_health_thres;
851 	extern int rdc_bitmap_delay;
852 	extern long rdc_clnt_count;
853 	extern long rdc_svc_count;
854 	sndr_m_stats_t	*info_stats;
855 	rdc_k_info_t	*krdc;
856 
857 	info_stats = (sndr_m_stats_t *)(ksp->ks_data);
858 	krdc = (rdc_k_info_t *)(ksp->ks_private);
859 
860 	/* no writes currently allowed */
861 
862 	if (rw == KSTAT_WRITE) {
863 		return (EACCES);
864 	}
865 
866 	/* default to READ */
867 	info_stats->m_maxsets.value.ul = rdc_max_sets;
868 	info_stats->m_maxfbas.value.ul = krdc->maxfbas;
869 	info_stats->m_rpc_timeout.value.ul = rdc_rpc_tmout;
870 	info_stats->m_health_thres.value.ul = rdc_health_thres;
871 	info_stats->m_bitmap_writes.value.ul = krdc->bitmap_write;
872 	info_stats->m_bitmap_ref_delay.value.ul = rdc_bitmap_delay;
873 
874 	/* clts counters not implemented yet */
875 	info_stats->m_clnt_cots_calls.value.ul = rdc_clnt_count;
876 	info_stats->m_clnt_clts_calls.value.ul = 0;
877 	info_stats->m_svc_cots_calls.value.ul = rdc_svc_count;
878 	info_stats->m_svc_clts_calls.value.ul = 0;
879 
880 	return (0);
881 }
882 
883 /*
884  * copy tailsize-1 bytes of tail of s to s1.
885  */
886 void
887 rdc_str_tail_cpy(char *s1, char *s, size_t tailsize)
888 {
889 	/* To avoid un-terminated string, max size is 16 - 1 */
890 	ssize_t offset = strlen(s) - (tailsize - 1);
891 
892 	offset = (offset > 0) ? offset : 0;
893 
894 	/* ensure it's null terminated */
895 	(void) strlcpy(s1, (const char *)(s + offset), tailsize);
896 }
897 
898 int
899 rdc_info_stats_update(kstat_t *ksp, int rw)
900 {
901 	rdc_info_stats_t	*rdc_info_stats;
902 	rdc_k_info_t		*krdc;
903 	rdc_u_info_t		*urdc;
904 
905 	rdc_info_stats = (rdc_info_stats_t *)(ksp->ks_data);
906 	krdc = (rdc_k_info_t *)(ksp->ks_private);
907 	urdc = &rdc_u_info[krdc->index];
908 
909 	/* no writes currently allowed */
910 
911 	if (rw == KSTAT_WRITE) {
912 		return (EACCES);
913 	}
914 
915 	/* default to READ */
916 	rdc_info_stats->s_flags.value.ul = urdc->flags;
917 	rdc_info_stats->s_syncflags.value.ul =
918 	    urdc->sync_flags;
919 	rdc_info_stats->s_bmpflags.value.ul =
920 	    urdc->bmap_flags;
921 	rdc_info_stats->s_syncpos.value.ul =
922 	    urdc->sync_pos;
923 	rdc_info_stats->s_volsize.value.ul =
924 	    urdc->volume_size;
925 	rdc_info_stats->s_bits_set.value.ul =
926 	    urdc->bits_set;
927 	rdc_info_stats->s_autosync.value.ul =
928 	    urdc->autosync;
929 	rdc_info_stats->s_maxqfbas.value.ul =
930 	    urdc->maxqfbas;
931 	rdc_info_stats->s_maxqitems.value.ul =
932 	    urdc->maxqitems;
933 
934 	kstat_named_setstr(&rdc_info_stats->s_primary_vol,
935 	    urdc->primary.file);
936 
937 	kstat_named_setstr(&rdc_info_stats->s_secondary_vol,
938 	    urdc->secondary.file);
939 
940 	if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
941 		kstat_named_setstr(&rdc_info_stats->s_bitmap,
942 		    urdc->primary.bitmap);
943 	} else {
944 		kstat_named_setstr(&rdc_info_stats->s_bitmap,
945 		    urdc->secondary.bitmap);
946 	}
947 
948 	kstat_named_setstr(&rdc_info_stats->s_primary_intf,
949 	    urdc->primary.intf);
950 
951 	kstat_named_setstr(&rdc_info_stats->s_secondary_intf,
952 	    urdc->secondary.intf);
953 
954 	rdc_info_stats->s_type_flag.value.ul = krdc->type_flag;
955 	rdc_info_stats->s_bitmap_size.value.ul = krdc->bitmap_size;
956 	rdc_info_stats->s_disk_status.value.ul = krdc->disk_status;
957 
958 	if (krdc->intf) {
959 		rdc_info_stats->s_if_if_down.value.ul = krdc->intf->if_down;
960 		rdc_info_stats->s_if_rpc_version.value.ul =
961 		    krdc->intf->rpc_version;
962 	}
963 
964 	/* the type can change without disable/re-enable so... */
965 	bzero(rdc_info_stats->s_aqueue_type.value.c, KSTAT_DATA_CHAR_LEN);
966 	if (RDC_IS_MEMQ(krdc->group)) {
967 		(void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "memory");
968 		rdc_info_stats->s_aqueue_blk_hwm.value.ul =
969 		    krdc->group->ra_queue.blocks_hwm;
970 		rdc_info_stats->s_aqueue_itm_hwm.value.ul =
971 		    krdc->group->ra_queue.nitems_hwm;
972 		rdc_info_stats->s_aqueue_throttle.value.ul =
973 		    krdc->group->ra_queue.throttle_delay;
974 		rdc_info_stats->s_aqueue_items.value.ul =
975 		    krdc->group->ra_queue.nitems;
976 		rdc_info_stats->s_aqueue_blocks.value.ul =
977 		    krdc->group->ra_queue.blocks;
978 
979 	} else if (RDC_IS_DISKQ(krdc->group)) {
980 		disk_queue *q = &krdc->group->diskq;
981 		rdc_info_stats->s_aqueue_blk_hwm.value.ul =
982 		    krdc->group->diskq.blocks_hwm;
983 		rdc_info_stats->s_aqueue_itm_hwm.value.ul =
984 		    krdc->group->diskq.nitems_hwm;
985 		rdc_info_stats->s_aqueue_throttle.value.ul =
986 		    krdc->group->diskq.throttle_delay;
987 		rdc_info_stats->s_aqueue_items.value.ul = QNITEMS(q);
988 		rdc_info_stats->s_aqueue_blocks.value.ul = QBLOCKS(q);
989 		(void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "disk");
990 	}
991 
992 	return (0);
993 }
994 
995 void
996 rdc_kstat_create(int index)
997 {
998 	int j = index;
999 	rdc_k_info_t *krdc = &rdc_k_info[index];
1000 	rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1001 	size_t varsize;
1002 
1003 	if (!krdc->set_kstats) {
1004 		krdc->set_kstats = kstat_create(RDC_KSTAT_MODULE, j,
1005 		    RDC_KSTAT_INFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1006 		    sizeof (rdc_info_stats_t) / sizeof (kstat_named_t),
1007 		    KSTAT_FLAG_VIRTUAL);
1008 #ifdef DEBUG
1009 		if (!krdc->set_kstats)
1010 			cmn_err(CE_NOTE, "!krdc:u_kstat null");
1011 #endif
1012 
1013 		if (krdc->set_kstats) {
1014 			/* calculate exact size of KSTAT_DATA_STRINGs */
1015 			varsize = strlen(urdc->primary.file) + 1
1016 			    + strlen(urdc->secondary.file) + 1
1017 			    + strlen(urdc->primary.intf) + 1
1018 			    + strlen(urdc->secondary.intf) + 1;
1019 			if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1020 				varsize += strlen(urdc->primary.bitmap) + 1;
1021 			} else {
1022 				varsize += strlen(urdc->secondary.bitmap) + 1;
1023 			}
1024 
1025 			krdc->set_kstats->ks_data_size += varsize;
1026 			krdc->set_kstats->ks_data = &rdc_info_stats;
1027 			krdc->set_kstats->ks_update = rdc_info_stats_update;
1028 			krdc->set_kstats->ks_private = &rdc_k_info[j];
1029 			kstat_install(krdc->set_kstats);
1030 		} else
1031 			cmn_err(CE_WARN, "!SNDR: k-kstats failed");
1032 	}
1033 
1034 	krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, j, NULL,
1035 	    "disk", KSTAT_TYPE_IO, 1, 0);
1036 	if (krdc->io_kstats) {
1037 		krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1038 		kstat_install(krdc->io_kstats);
1039 	}
1040 	krdc->bmp_kstats = kstat_create("sndrbmp", j, NULL,
1041 	    "disk", KSTAT_TYPE_IO, 1, 0);
1042 	if (krdc->bmp_kstats) {
1043 		krdc->bmp_kstats->ks_lock = &krdc->bmp_kstat_mutex;
1044 		kstat_install(krdc->bmp_kstats);
1045 	}
1046 }
1047 
1048 void
1049 rdc_kstat_delete(int index)
1050 {
1051 	rdc_k_info_t *krdc = &rdc_k_info[index];
1052 
1053 	if (krdc->set_kstats) {
1054 		kstat_delete(krdc->set_kstats);
1055 		krdc->set_kstats = NULL;
1056 	}
1057 
1058 	if (krdc->io_kstats) {
1059 		kstat_delete(krdc->io_kstats);
1060 		krdc->io_kstats = NULL;
1061 	}
1062 	if (krdc->bmp_kstats) {
1063 		kstat_delete(krdc->bmp_kstats);
1064 		krdc->bmp_kstats = NULL;
1065 	}
1066 }
1067 
1068 #ifdef	DEBUG
1069 /*
1070  * Reset the io_kstat structure of the krdc specified
1071  * by the arg index.
1072  */
1073 static int
1074 rdc_clrkstat(void *arg)
1075 {
1076 	int index;
1077 	rdc_k_info_t *krdc;
1078 
1079 	index = (int)(unsigned long)arg;
1080 	if ((index < 0) || (index >= rdc_max_sets)) {
1081 		return (EINVAL);
1082 	}
1083 	krdc = &rdc_k_info[index];
1084 	if (krdc->io_kstats) {
1085 		kstat_delete(krdc->io_kstats);
1086 		krdc->io_kstats = NULL;
1087 	} else {
1088 		return (EINVAL);
1089 	}
1090 	krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, index, NULL,
1091 	    "disk", KSTAT_TYPE_IO, 1, 0);
1092 	if (krdc->io_kstats) {
1093 		krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1094 		kstat_install(krdc->io_kstats);
1095 	} else {
1096 		return (EINVAL);
1097 	}
1098 	/*
1099 	 * clear the high water marks and throttle.
1100 	 */
1101 	if (krdc->group) {
1102 		krdc->group->ra_queue.nitems_hwm = 0;
1103 		krdc->group->ra_queue.blocks_hwm = 0;
1104 		krdc->group->ra_queue.throttle_delay = 0;
1105 	}
1106 	return (0);
1107 }
1108 #endif
1109