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