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