xref: /titanic_50/usr/src/lib/librdc/common/rdcconfig.c (revision f0e308969424e7466232f0795ba1891698c3adf7)
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 
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <strings.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <netdb.h>
34 #include <sys/stream.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <ctype.h>
39 #include <thread.h>
40 #include <pthread.h>
41 
42 #include <sys/unistat/spcs_s.h>
43 #include <sys/unistat/spcs_s_u.h>
44 #include <sys/unistat/spcs_s_impl.h>
45 #include <sys/unistat/spcs_errors.h>
46 
47 #include <sys/nsctl/rdc_io.h>
48 #include <sys/nsctl/rdc_ioctl.h>
49 #include <sys/nsctl/rdc_prot.h>
50 #include <sys/nsctl/librdc.h>
51 #include <sys/nsctl/rdcrules.h>
52 #include <sys/nsctl/rdcerr.h>
53 #include <sys/nsctl/cfg.h>
54 
55 #include <sys/unistat/spcs_dtrinkets.h>
56 #include <sys/unistat/spcs_etrinkets.h>
57 
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #include <netinet/tcp.h>
62 #include <rpc/rpc_com.h>
63 #include <rpc/rpc.h>
64 
65 struct netbuf svaddr, *svp;
66 struct netconfig nconf, *conf;
67 struct knetconfig knconf;
68 
69 /*
70  * libdscfg type stuff here
71  */
72 extern int sv_enable(CFGFILE *cfg, rdcconfig_t *rdc);
73 extern int add_to_rdc_cfg(rdcconfig_t *rdcs);
74 extern int remove_from_rdc_cfg(rdcconfig_t *rdcs);
75 extern int replace_cfgfield(rdcconfig_t *rdcs, char *field, char *value);
76 extern int reverse_in_cfg(rdcconfig_t *rdcs);
77 
78 rdcconfig_t *
79 rdc_dup_config(rdcconfig_t *orig)
80 {
81 	rdcconfig_t *rc;
82 
83 	rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
84 	if (!rc) {
85 		rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
86 		return (NULL);
87 	}
88 
89 	*rc = *orig;
90 	rc->next = NULL; /* don't want to hook into wrong chaing */
91 	return (rc);
92 }
93 
94 /*
95  * takes in a chain of rdcconfig_t's and a chain
96  * of rdc_rc_t's, checks for success in the rdc_rc_t,
97  * then adds the corresponding rdcconfig_t to the return
98  * chain.
99  */
100 rdcconfig_t *
101 chain_successful(rdcconfig_t *rdcs, rdc_rc_t *rcs)
102 {
103 	rdc_rc_t *rcp;
104 	rdcconfig_t *rdcp;
105 	rdcconfig_t *ret = NULL;
106 	rdcconfig_t *retp = NULL;
107 
108 	rcp = rcs;
109 	rdcp = rdcs;
110 
111 	while (rcp) {
112 		if (rcp->rc == 0) {
113 			if ((ret == NULL) && (rdcp->persist)) {
114 				retp = ret = rdc_dup_config(rdcp);
115 
116 			} else if ((ret) && (rdcp->persist)) {
117 				retp->next = rdc_dup_config(rdcp);
118 				retp = retp->next;
119 			}
120 		}
121 		rcp = rcp->next;
122 		rdcp = rdcp->next;
123 	}
124 	return (ret);
125 
126 }
127 
128 rdc_set_t
129 config2set(rdcconfig_t *rdc)
130 {
131 	rdc_set_t urdc;
132 
133 	bzero(&urdc, sizeof (rdc_set_t));
134 	strncpy(urdc.primary.intf, rdc->phost, MAX_RDC_HOST_SIZE);
135 	strncpy(urdc.primary.file, rdc->pfile, NSC_MAXPATH);
136 	strncpy(urdc.primary.bitmap, rdc->pbmp, NSC_MAXPATH);
137 	strncpy(urdc.secondary.intf, rdc->shost, MAX_RDC_HOST_SIZE);
138 	strncpy(urdc.secondary.file, rdc->sfile, NSC_MAXPATH);
139 	strncpy(urdc.secondary.bitmap, rdc->sbmp, NSC_MAXPATH);
140 	strncpy(urdc.group_name, rdc->group, NSC_MAXPATH);
141 
142 	return (urdc);
143 }
144 
145 rdc_rc_t *
146 new_rc()
147 {
148 	rdc_rc_t *rc;
149 
150 	rc = (rdc_rc_t *)calloc(1, sizeof (*rc));
151 	if (rc == NULL) {
152 		rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
153 		return (NULL);
154 	}
155 	return (rc);
156 }
157 
158 rdc_rc_t
159 rdc_config(rdc_config_t *rdccfg)
160 {
161 	rdc_rc_t rc;
162 	rdc_set_t *set;
163 	spcs_s_info_t ustatus;
164 
165 	bzero(&rc, sizeof (rc));
166 	ustatus = spcs_s_ucreate();
167 
168 	if (self_check(rdccfg->rdc_set->primary.intf)) {
169 		rdccfg->options |= RDC_OPT_PRIMARY;
170 		/* this needs changin if we do campus */
171 		rdccfg->rdc_set->direct_file[0] = 0;
172 	} else {
173 		rdccfg->options |= RDC_OPT_SECONDARY;
174 	}
175 
176 	/* set up return stuff.. */
177 	set = &rdccfg->rdc_set[0];
178 	strncpy(rc.set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
179 	strncpy(rc.set.pfile, set->primary.file, NSC_MAXPATH);
180 	strncpy(rc.set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
181 	strncpy(rc.set.sfile, set->secondary.file, NSC_MAXPATH);
182 
183 	rc.rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
184 
185 	if (rc.rc < 0) {
186 		rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
187 		strncpy(rc.msg, rdc_error(NULL), RDC_ERR_SIZE);
188 	}
189 
190 	return (rc);
191 }
192 
193 void *
194 rdc_mtconfig(void *rdc)
195 {
196 	rdc_rc_t *rc[1];
197 	rdc_set_t *set;
198 	spcs_s_info_t ustatus;
199 	rdc_config_t *rdccfg = (rdc_config_t *)rdc;
200 
201 	ustatus = spcs_s_ucreate();
202 
203 	if (self_check(rdccfg->rdc_set->primary.intf)) {
204 		rdccfg->options |= RDC_OPT_PRIMARY;
205 		/* this needs changin if we do campus */
206 		rdccfg->rdc_set->direct_file[0] = 0;
207 	} else {
208 		rdccfg->options |= RDC_OPT_SECONDARY;
209 	}
210 
211 	set = &rdccfg->rdc_set[0];
212 	*rc = new_rc();
213 
214 	strncpy(rc[0]->set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
215 	strncpy(rc[0]->set.pfile, set->primary.file, NSC_MAXPATH);
216 	strncpy(rc[0]->set.pbmp, set->primary.bitmap, NSC_MAXPATH);
217 	strncpy(rc[0]->set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
218 	strncpy(rc[0]->set.sfile, set->secondary.file, NSC_MAXPATH);
219 	strncpy(rc[0]->set.sbmp, set->secondary.bitmap, NSC_MAXPATH);
220 
221 	rc[0]->rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
222 
223 	if (rc[0]->rc < 0) {
224 		rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
225 		strncpy(rc[0]->msg, rdc_error(NULL), RDC_ERR_SIZE);
226 	}
227 
228 	sleep(1); /* give thr_join a chance to be called */
229 	free(rdccfg);
230 	thr_exit((void **) *rc);
231 	return (NULL);
232 }
233 int
234 populate_addrs(rdc_set_t *urdc, int isenable)
235 {
236 	struct t_info tinfo;
237 	struct hostent *hp;
238 	char toname[MAX_RDC_HOST_SIZE];
239 	char fromname[MAX_RDC_HOST_SIZE];
240 
241 	strncpy(fromname, urdc->primary.intf, MAX_RDC_HOST_SIZE);
242 	strncpy(toname, urdc->secondary.intf, MAX_RDC_HOST_SIZE);
243 
244 	if ((fromname[0] == '\0') || (fromname[0] == '\0')) {
245 		rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL,
246 		    "NULL hostname recieved");
247 		    return (-1);
248 	}
249 
250 	hp = gethost_byname(fromname);
251 	strncpy(fromname, hp->h_name, MAX_RDC_HOST_SIZE);
252 	hp = gethost_byname(toname);
253 	strncpy(toname, hp->h_name, MAX_RDC_HOST_SIZE);
254 
255 	if (self_check(fromname) && self_check(toname)) {
256 		rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL, "");
257 	}
258 
259 	if (isenable) {
260 		svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
261 		    &conf, NULL, "rdc", &tinfo, 0);
262 		if (svp == NULL)
263 			return (-1);
264 		svaddr = *svp;
265 	} else {
266 		bzero(&svaddr, sizeof (svaddr));
267 	}
268 
269 	urdc->secondary.addr.len = svaddr.len;
270 	urdc->secondary.addr.maxlen = svaddr.maxlen;
271 	urdc->secondary.addr.buf = (void*)svaddr.buf;
272 
273 	if (isenable) {
274 		svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
275 		    &conf, NULL, "rdc", &tinfo, 0);
276 		if (svp == NULL)
277 			return (-1);
278 		svaddr = *svp;
279 	} else {
280 		bzero(&svaddr, sizeof (svaddr));
281 	}
282 
283 	urdc->primary.addr.len = svaddr.len;
284 	urdc->primary.addr.maxlen = svaddr.maxlen;
285 	urdc->primary.addr.buf = (void*)svaddr.buf;
286 
287 	if (isenable) {
288 		convert_nconf_to_knconf(conf, &knconf);
289 		urdc->netconfig = &knconf;
290 	} else {
291 		urdc->netconfig = NULL;
292 	}
293 	urdc->syshostid = (int32_t)gethostid();
294 
295 	return (1);
296 
297 }
298 void
299 rdc_free_config(rdcconfig_t *rdc, int all)
300 {
301 	rdcconfig_t *rdcp;
302 	rdcconfig_t *rdcq;
303 
304 	rdcp = rdc;
305 	if (all == RDC_FREEONE) {
306 		free(rdcp);
307 	} else while (rdcp) {
308 		rdcq = rdcp->next;
309 		free(rdcp);
310 		rdcp = rdcq;
311 	}
312 	rdc = NULL;
313 }
314 
315 void
316 rdc_free_rclist(rdc_rc_t *rc) {
317 	rdc_rc_t *rcp, *rcq;
318 
319 	rcp = rc;
320 	while (rcp) {
321 		rcq = rcp->next;
322 		free(rcp);
323 		rcp = rcq;
324 	}
325 
326 }
327 /*ARGSUSED*/
328 rdcconfig_t *
329 rdc_alloc_config(const char *phost, const char *pfile,
330     const char *pbmp, const char *shost, const char *sfile, const char *sbmp,
331     const char *mode, const char *group, const char *ctag, const char *options,
332     int persist)
333 {
334 	rdcconfig_t *rc;
335 
336 	rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
337 	if (!rc) {
338 		rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
339 		return (NULL);
340 	}
341 	if (phost)
342 		strncpy(rc->phost, phost, NSC_MAXPATH);
343 	if (pfile)
344 		strncpy(rc->pfile, pfile, NSC_MAXPATH);
345 	if (pbmp)
346 		strncpy(rc->pbmp, pbmp, NSC_MAXPATH);
347 	if (shost)
348 		strncpy(rc->shost, shost, NSC_MAXPATH);
349 	if (sfile)
350 		strncpy(rc->sfile, sfile, NSC_MAXPATH);
351 	if (sbmp)
352 		strncpy(rc->sbmp, sbmp, NSC_MAXPATH);
353 
354 	strncpy(rc->direct, "ip", 2);
355 
356 	if (mode)
357 		strncpy(rc->mode, mode, NSC_MAXPATH);
358 	if (ctag)
359 		strncpy(rc->ctag, ctag, NSC_MAXPATH);
360 	if (options)
361 		strncpy(rc->options, options, NSC_MAXPATH);
362 
363 	rc->persist = persist;
364 	rc->next = NULL;
365 
366 	return (rc);
367 
368 }
369 
370 void
371 populate_rc(rdc_rc_t *rcp, rdcconfig_t *rdcp)
372 {
373 	rcp->rc = -1;
374 	strncpy(rcp->msg, rdc_error(NULL), RDC_ERR_SIZE);
375 	strncpy(rcp->set.phost, rdcp->phost, NSC_MAXPATH);
376 	strncpy(rcp->set.pfile, rdcp->pfile, NSC_MAXPATH);
377 	strncpy(rcp->set.shost, rdcp->shost, NSC_MAXPATH);
378 	strncpy(rcp->set.sfile, rdcp->sfile, NSC_MAXPATH);
379 }
380 
381 /*
382  * rdc_enable
383  * return values
384  * NULL on error
385  * pointer to rdc_rc_t list of return values
386  */
387 rdc_rc_t *
388 rdc_enable(rdcconfig_t *rdc)
389 {
390 	rdc_config_t 	rdccfg;
391 	rdcconfig_t 	*rdcp = NULL;
392 	rdcconfig_t	*cfg_rdcs = NULL;
393 	rdc_rc_t	*rc = NULL;
394 	rdc_rc_t	*rcp = NULL;
395 
396 	rdcp = rdc;
397 	rc = new_rc();
398 	if (!rc) { /* error already set */
399 		return (NULL);
400 	}
401 	rcp = rc;
402 	while (rdcp) {
403 		if (!rdcp->mode) {
404 			rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
405 			    RDC_EINVAL);
406 			return (NULL);
407 		}
408 		bzero(&rdccfg, sizeof (rdc_config_t));
409 		rdccfg.rdc_set[0] = config2set(rdcp);
410 		rdccfg.command = RDC_CMD_ENABLE;
411 		rdccfg.options = RDC_OPT_SETBMP;
412 		if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
413 			rdccfg.options |= RDC_OPT_SYNC;
414 		} else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
415 			rdccfg.options |= RDC_OPT_ASYNC;
416 		} else {
417 			rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
418 			    RDC_EINVAL);
419 			return (NULL);
420 		}
421 
422 		populate_addrs(&rdccfg.rdc_set[0], 1);
423 
424 		if (can_enable(rdcp)) {
425 			/* do the operation */
426 			*rcp = rdc_config(&rdccfg);
427 
428 		} else { /* set up what rdc_config would've set up */
429 
430 			populate_rc(rcp, rdcp);
431 
432 		}
433 		if ((rcp->rc == 0) && (!rdcp->persist)) {
434 			/*
435 			 * if we are not persisting, do this now,
436 			 * otherwise we will do it when
437 			 * we have a lock on the cfg in add_to_rdc_cfg
438 			 */
439 			sv_enable(NULL, rdcp);
440 		}
441 
442 		rdcp = rdcp->next;
443 		if (!rdcp)
444 			break;
445 
446 		rcp->next = new_rc();
447 		rcp = rcp->next;
448 		if (!rcp) {
449 			/* dont free here, return what you have */
450 			break;
451 		}
452 	}
453 
454 	/*
455 	 * travel the rc chain and rdc chain checking results,
456 	 * building a new chain, and updating dscfg
457 	 */
458 	rcp = rc;
459 	rdcp = rdc;
460 
461 	cfg_rdcs = chain_successful(rdcp, rcp);
462 
463 	if (add_to_rdc_cfg(cfg_rdcs) < 0) {
464 		/* XXX should disable or something here */
465 		return (rc);
466 	}
467 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
468 	return (rc);
469 
470 }
471 
472 rdc_rc_t *
473 rdc_enable_clrbmp(rdcconfig_t *rdc)
474 {
475 	rdc_config_t 	rdccfg;
476 	rdcconfig_t 	*rdcp = NULL;
477 	rdcconfig_t	*cfg_rdcs = NULL;
478 	rdc_rc_t	*rc = NULL;
479 	rdc_rc_t	*rcp = NULL;
480 
481 	rdcp = rdc;
482 	rc = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
483 	if (!rc) {
484 		rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
485 		return (NULL);
486 	}
487 	rcp = rc;
488 	while (rdcp) {
489 		if (!rdcp->mode) {
490 			rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
491 			    RDC_EINVAL);
492 			return (NULL);
493 		}
494 		bzero(&rdccfg, sizeof (rdc_config_t));
495 		rdccfg.rdc_set[0] = config2set(rdcp);
496 		rdccfg.command = RDC_CMD_ENABLE;
497 		rdccfg.options = RDC_OPT_CLRBMP;
498 		if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
499 			rdccfg.options |= RDC_OPT_SYNC;
500 		} else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
501 			rdccfg.options |= RDC_OPT_ASYNC;
502 		} else {
503 			rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
504 			    RDC_EINVAL);
505 			return (NULL);
506 		}
507 
508 		populate_addrs(&rdccfg.rdc_set[0], 1);
509 
510 		if (can_enable(rdcp)) {
511 			/* do the operation */
512 			*rcp = rdc_config(&rdccfg);
513 
514 		} else { /* set up what rdc_config would've set up */
515 
516 			populate_rc(rcp, rdcp);
517 
518 		}
519 		rdcp = rdcp->next;
520 		if (!rdcp)
521 			break;
522 
523 		rcp->next = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
524 		rcp = rcp->next;
525 		if (!rcp)
526 			break;
527 	}
528 
529 	/*
530 	 * travel the rc chain and rdc chain checking results,
531 	 * building a new chain, and updating dscfg
532 	 */
533 	rcp = rc;
534 	rdcp = rdc;
535 
536 	cfg_rdcs = chain_successful(rdcp, rcp);
537 
538 	if (add_to_rdc_cfg(cfg_rdcs) < 0) {
539 		/* XXX should disable or something here */
540 		return (rc);
541 	}
542 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
543 
544 	return (rc);
545 
546 }
547 
548 rdc_rc_t *
549 rdc_disable(rdcconfig_t *rdc)
550 {
551 	rdc_config_t	rdccfg;
552 	rdcconfig_t	*rdcp = NULL;
553 	rdcconfig_t	*cfg_rdcs = NULL;
554 	rdc_rc_t	*rc = NULL;
555 	rdc_rc_t	*rcp = NULL;
556 
557 	rdcp = rdc;
558 	rc = new_rc();
559 	if (!rc) {
560 		return (NULL);
561 	}
562 	rcp = rc;
563 
564 	while (rdcp) {
565 
566 		bzero(&rdccfg, sizeof (rdc_config_t));
567 		rdccfg.rdc_set[0] = config2set(rdcp);
568 		rdccfg.command = RDC_CMD_DISABLE;
569 		populate_addrs(&rdccfg.rdc_set[0], 0);
570 
571 		*rcp = rdc_config(&rdccfg);
572 
573 		rdcp = rdcp->next;
574 		if (!rdcp)
575 			break;
576 
577 		rcp->next = new_rc();
578 		rcp = rcp->next;
579 		if (!rcp)
580 			return (rc);
581 
582 	}
583 	rcp = rc;
584 	rdcp = rdc;
585 
586 	cfg_rdcs = chain_successful(rdcp, rcp);
587 
588 	remove_from_rdc_cfg(cfg_rdcs);
589 
590 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
591 
592 	return (rc);
593 }
594 
595 rdc_rc_t *
596 rdc_log(rdcconfig_t *rdc)
597 {
598 	rdc_config_t rdccfg;
599 	rdcconfig_t	*rdcp = NULL;
600 	rdc_rc_t	*rc = NULL;
601 	rdc_rc_t	*rcp = NULL;
602 
603 	rdcp = rdc;
604 	rc = new_rc();
605 	if (!rc) {
606 		return (NULL);
607 	}
608 	rcp = rc;
609 
610 	while (rdcp) {
611 		bzero(&rdccfg, sizeof (rdc_config_t));
612 		rdccfg.rdc_set[0] = config2set(rdcp);
613 		rdccfg.command = RDC_CMD_LOG;
614 		populate_addrs(&rdccfg.rdc_set[0], 0);
615 
616 		*rcp = rdc_config(&rdccfg);
617 
618 		rdcp = rdcp->next;
619 		if (!rdcp)
620 			break;
621 
622 		rcp->next = new_rc();
623 		rcp = rcp->next;
624 		if (!rcp)
625 			break;
626 	}
627 	return (rc);
628 }
629 
630 rdc_rc_t *
631 rdc_usync(rdcconfig_t *rdc)
632 {
633 	rdc_config_t *rdccfg;
634 	rdcconfig_t	*rdcp = NULL;
635 	rdc_rc_t	*rc = NULL;
636 	rdc_rc_t	*rcp = NULL;
637 	rdc_rc_t	*tmprc;
638 	int trc;
639 
640 	rdcp = rdc;
641 
642 	while (rdcp) {
643 		/* freed in rdc_mtconfig */
644 		rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
645 		rdccfg->rdc_set[0] = config2set(rdcp);
646 		rdccfg->command = RDC_CMD_COPY;
647 		rdccfg->options = RDC_OPT_UPDATE|RDC_OPT_FORWARD;
648 		populate_addrs(&rdccfg->rdc_set[0], 0);
649 		trc = thr_create(NULL, 0, rdc_mtconfig,
650 		    (void **) rdccfg, THR_BOUND, NULL);
651 		rdcp = rdcp->next;
652 		if (!rdcp)
653 			break;
654 
655 	}
656 
657 	/*
658 	 * collect status here from thr_join-status,
659 	 * and add to rdc_rc_t chain ?
660 	 * this will block, but caller could always thread too
661 	 */
662 	while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
663 		if (rc == NULL) {
664 			rcp = rc = (rdc_rc_t *)tmprc;
665 		} else {
666 			rcp->next = (rdc_rc_t *)tmprc;
667 			rcp = rcp->next;
668 		}
669 	}
670 
671 	return (rc);
672 }
673 
674 rdc_rc_t *
675 rdc_fsync(rdcconfig_t *rdc)
676 {
677 	rdc_config_t *rdccfg;
678 	rdcconfig_t	*rdcp = NULL;
679 	rdc_rc_t	*rc = NULL;
680 	rdc_rc_t	*rcp = NULL;
681 	rdc_rc_t	*tmprc = NULL;
682 	int trc;
683 
684 	rdcp = rdc;
685 	rc = new_rc();
686 	if (!rc) {
687 		return (NULL);
688 	}
689 	rcp = rc;
690 
691 	while (rdcp) {
692 		/* freed in rdc_mtconfig */
693 		rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
694 		rdccfg->rdc_set[0] = config2set(rdcp);
695 		rdccfg->command = RDC_CMD_COPY;
696 		rdccfg->options = RDC_OPT_FULL|RDC_OPT_FORWARD;
697 		populate_addrs(&rdccfg->rdc_set[0], 0);
698 		trc = thr_create(NULL, 0, rdc_mtconfig,
699 		    (void **) rdccfg, THR_BOUND, NULL);
700 		rdcp = rdcp->next;
701 		if (!rdcp)
702 			break;
703 
704 	}
705 
706 	/*
707 	 * collect status here from thr_join-status,
708 	 * and add to rdc_rc_t chain ?
709 	 * this will block, but caller could always thread too
710 	 */
711 	while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
712 		if (rc == NULL) {
713 			rcp = rc = (rdc_rc_t *)tmprc;
714 		} else {
715 			rcp->next = (rdc_rc_t *)tmprc;
716 			rcp = rcp->next;
717 		}
718 	}
719 
720 	return (rc);
721 }
722 
723 rdc_rc_t *
724 rdc_rsync(rdcconfig_t *rdc)
725 {
726 	rdc_config_t *rdccfg;
727 	rdcconfig_t	*rdcp = NULL;
728 	rdc_rc_t	*rc = NULL;
729 	rdc_rc_t	*rcp = NULL;
730 	rdc_rc_t	*tmprc = NULL;
731 	int trc;
732 
733 	rdcp = rdc;
734 	rc = new_rc();
735 	if (!rc) {
736 		return (NULL);
737 	}
738 	rcp = rc;
739 
740 	while (rdcp) {
741 		tmprc = cant_rsync(rdcp);
742 		if (tmprc != NULL) {
743 			if (rc == NULL) {
744 				rcp = rc = tmprc;
745 			} else {
746 				rcp->next = tmprc;
747 				rcp = rcp->next;
748 			}
749 			goto next;
750 		}
751 
752 		/* freed in rdc_mtconfig */
753 		rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
754 		rdccfg->rdc_set[0] = config2set(rdcp);
755 		rdccfg->command = RDC_CMD_COPY;
756 		rdccfg->options = RDC_OPT_REVERSE|RDC_OPT_FULL;
757 		populate_addrs(&rdccfg->rdc_set[0], 0);
758 		trc = thr_create(NULL, 0, rdc_mtconfig,
759 		    (void **) rdccfg, THR_BOUND, NULL);
760 next:
761 		rdcp = rdcp->next;
762 		if (!rdcp)
763 			break;
764 	}
765 
766 	/*
767 	 * collect status here from thr_join-status,
768 	 * and add to rdc_rc_t chain ?
769 	 * this will block, but caller could always thread too
770 	 */
771 	while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
772 		if (rc == NULL) {
773 			rcp = rc = (rdc_rc_t *)tmprc;
774 		} else {
775 			rcp->next = (rdc_rc_t *)tmprc;
776 			rcp = rcp->next;
777 		}
778 	}
779 
780 	return (rc);
781 }
782 
783 rdc_rc_t *
784 rdc_ursync(rdcconfig_t *rdc)
785 {
786 	rdc_config_t *rdccfg;
787 	rdcconfig_t	*rdcp = NULL;
788 	rdc_rc_t	*rc = NULL;
789 	rdc_rc_t	*rcp = NULL;
790 	rdc_rc_t	*tmprc = NULL;
791 	int trc;
792 
793 	rdcp = rdc;
794 
795 	while (rdcp) {
796 		tmprc = cant_rsync(rdcp);
797 		if (tmprc != NULL) {
798 			if (rc == NULL) {
799 				rcp = rc = tmprc;
800 			} else {
801 				rcp->next = tmprc;
802 				rcp = rcp->next;
803 			}
804 			goto next;
805 		}
806 
807 		/* freed in rdc_mtconfig */
808 		rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
809 		rdccfg->rdc_set[0] = config2set(rdcp);
810 		rdccfg->command = RDC_CMD_COPY;
811 		rdccfg->options = RDC_OPT_REVERSE | RDC_OPT_UPDATE;
812 		populate_addrs(&rdccfg->rdc_set[0], 0);
813 		trc = thr_create(NULL, 0, rdc_mtconfig,
814 		    (void **) rdccfg, THR_BOUND, NULL);
815 next:
816 		rdcp = rdcp->next;
817 		if (!rdcp)
818 			break;
819 
820 	}
821 
822 	/*
823 	 * collect status here from thr_join-status,
824 	 * and add to rdc_rc_t chain ?
825 	 * this will block, but caller could always thread too
826 	 */
827 	while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
828 		if (rc == NULL) {
829 			rcp = rc = (rdc_rc_t *)tmprc;
830 		} else {
831 			rcp->next = (rdc_rc_t *)tmprc;
832 			rcp = rcp->next;
833 		}
834 	}
835 
836 	return (rc);
837 }
838 
839 rdc_rc_t *
840 rdc_wait(rdcconfig_t *rdc)
841 {
842 	rdc_config_t rdccfg;
843 	rdcconfig_t	*rdcp = NULL;
844 	rdc_rc_t	*rc = NULL;
845 	rdc_rc_t	*rcp = NULL;
846 
847 	rdcp = rdc;
848 	rc = new_rc();
849 	if (!rc) {
850 		return (NULL);
851 	}
852 	rcp = rc;
853 
854 	while (rdcp) {
855 		bzero(&rdccfg, sizeof (rdc_config_t));
856 		rdccfg.rdc_set[0] = config2set(rdcp);
857 		rdccfg.command = RDC_CMD_WAIT;
858 		populate_addrs(&rdccfg.rdc_set[0], 0);
859 
860 		*rcp = rdc_config(&rdccfg);
861 
862 		rdcp = rdcp->next;
863 		if (!rdcp)
864 			break;
865 
866 		rcp->next = new_rc();
867 		rcp = rcp->next;
868 		if (!rcp)
869 			break;
870 	}
871 	return (rc);
872 }
873 
874 rdc_rc_t *
875 rdc_set_autosync(rdcconfig_t *rdc, int autosync)
876 {
877 	rdc_config_t rdccfg;
878 	rdcconfig_t	*rdcp = NULL;
879 	rdc_rc_t	*rc = NULL;
880 	rdc_rc_t	*rcp = NULL;
881 
882 	rdcp = rdc;
883 	rc = new_rc();
884 	if (!rc) {
885 		return (NULL);
886 	}
887 	rcp = rc;
888 
889 	while (rdcp) {
890 		bzero(&rdccfg, sizeof (rdc_config_t));
891 		rdccfg.rdc_set[0] = config2set(rdcp);
892 		rdccfg.command = RDC_CMD_TUNABLE;
893 		rdccfg.rdc_set[0].autosync = autosync;
894 		rdccfg.rdc_set[0].maxqitems = -1;
895 		rdccfg.rdc_set[0].maxqfbas = -1;
896 		populate_addrs(&rdccfg.rdc_set[0], 0);
897 
898 		*rcp = rdc_config(&rdccfg);
899 
900 		rdcp = rdcp->next;
901 		if (!rdcp)
902 			break;
903 
904 		rcp->next = new_rc();
905 		rcp = rcp->next;
906 		if (!rcp)
907 			break;
908 	}
909 	return (rc);
910 }
911 
912 rdc_rc_t *
913 rdc_set_maxqfbas(rdcconfig_t *rdc, int maxqfbas)
914 {
915 	rdc_config_t rdccfg;
916 	rdcconfig_t	*rdcp = NULL;
917 	rdc_rc_t	*rc = NULL;
918 	rdc_rc_t	*rcp = NULL;
919 
920 	rdcp = rdc;
921 	rc = new_rc();
922 	if (!rc) {
923 		return (NULL);
924 	}
925 	rcp = rc;
926 
927 	while (rdcp) {
928 		bzero(&rdccfg, sizeof (rdc_config_t));
929 		rdccfg.rdc_set[0] = config2set(rdcp);
930 		rdccfg.command = RDC_CMD_TUNABLE;
931 		rdccfg.rdc_set[0].autosync = -1;
932 		rdccfg.rdc_set[0].maxqitems = -1;
933 		rdccfg.rdc_set[0].maxqfbas = maxqfbas;
934 		populate_addrs(&rdccfg.rdc_set[0], 0);
935 
936 		*rcp = rdc_config(&rdccfg);
937 
938 		rdcp = rdcp->next;
939 		if (!rdcp)
940 			break;
941 
942 		rcp->next = new_rc();
943 		rcp = rcp->next;
944 		if (!rcp)
945 			break;
946 	}
947 	return (rc);
948 }
949 
950 rdc_rc_t *
951 rdc_set_maxqitems(rdcconfig_t *rdc, int maxqitems)
952 {
953 	rdc_config_t rdccfg;
954 	rdcconfig_t	*rdcp = NULL;
955 	rdc_rc_t	*rc = NULL;
956 	rdc_rc_t	*rcp = NULL;
957 
958 	rdcp = rdc;
959 	rc = new_rc();
960 
961 	if (!rc) {
962 		return (NULL);
963 	}
964 	rcp = rc;
965 
966 	while (rdcp) {
967 		bzero(&rdccfg, sizeof (rdc_config_t));
968 		rdccfg.rdc_set[0] = config2set(rdc);
969 		rdccfg.command = RDC_CMD_TUNABLE;
970 		rdccfg.rdc_set[0].autosync = -1;
971 		rdccfg.rdc_set[0].maxqitems = maxqitems;
972 		rdccfg.rdc_set[0].maxqfbas = -1;
973 		populate_addrs(&rdccfg.rdc_set[0], 0);
974 
975 		*rcp = rdc_config(&rdccfg);
976 
977 		rdcp = rdcp->next;
978 		if (!rdcp)
979 			break;
980 
981 		rcp->next = new_rc();
982 		rcp = rcp->next;
983 		if (!rcp)
984 			break;
985 	}
986 	return (rc);
987 }
988 
989 rdc_set_t
990 rdc_status(rdcconfig_t *rdc)
991 {
992 	rdc_config_t rdccfg;
993 
994 	bzero(&rdccfg, sizeof (rdc_config_t));
995 	rdccfg.rdc_set[0] = config2set(rdc);
996 	rdccfg.command = RDC_CMD_STATUS;
997 	populate_addrs(&rdccfg.rdc_set[0], 0);
998 	rdc_config(&rdccfg);
999 
1000 	return (rdccfg.rdc_set[0]);
1001 }
1002 
1003 int
1004 rdc_get_autosync(rdcconfig_t *rdc)
1005 {
1006 	rdc_set_t rdcset;
1007 
1008 	rdcset = rdc_status(rdc);
1009 	return (rdcset.autosync);
1010 }
1011 
1012 int
1013 rdc_get_maxqfbas(rdcconfig_t *rdc)
1014 {
1015 	rdc_set_t rdcset;
1016 
1017 	rdcset = rdc_status(rdc);
1018 	return (rdcset.maxqfbas);
1019 
1020 }
1021 
1022 int
1023 rdc_get_maxqitems(rdcconfig_t *rdc)
1024 {
1025 	rdc_set_t rdcset;
1026 
1027 	rdcset = rdc_status(rdc);
1028 	return (rdcset.maxqitems);
1029 
1030 }
1031 
1032 int
1033 set_mode(rdcconfig_t *rdc)
1034 {
1035 	if (strcmp(rdc->mode, "async") == 0)
1036 		return (RDC_OPT_ASYNC);
1037 	else
1038 		return (RDC_OPT_SYNC);
1039 }
1040 
1041 /*
1042  * reconfig bitmaps are single set only ops
1043  * for obvious reasons
1044  */
1045 rdc_rc_t *
1046 rdc_reconfig_pbmp(rdcconfig_t *rdc, char *pbmp)
1047 {
1048 	rdc_config_t rdccfg;
1049 	rdc_rc_t *rc;
1050 
1051 	rc = new_rc();
1052 	if ((!rc) || (!pbmp))
1053 		return (NULL);
1054 
1055 	bzero(&rdccfg, sizeof (rdc_config_t));
1056 	rdccfg.rdc_set[0] = config2set(rdc);
1057 	strncpy(rdccfg.rdc_set[0].primary.bitmap, pbmp, NSC_MAXPATH);
1058 	rdccfg.command = RDC_CMD_RECONFIG;
1059 	rdccfg.options |= set_mode(rdc);
1060 	populate_addrs(&rdccfg.rdc_set[0], 0);
1061 
1062 	if (can_reconfig_pbmp(rdc, pbmp))
1063 		*rc = rdc_config(&rdccfg);
1064 	else
1065 		populate_rc(rc, rdc);
1066 
1067 	if ((rc->rc == 0) && (rdc->persist))
1068 		if (replace_cfgfield(rdc, "pbitmap", pbmp) < 0) {
1069 			rc->rc = -1;
1070 			strncpy(rc->msg, rdc_error(NULL), RDC_ERR_SIZE);
1071 		}
1072 	return (rc);
1073 }
1074 
1075 rdc_rc_t *
1076 rdc_reconfig_sbmp(rdcconfig_t *rdc, char *sbmp)
1077 {
1078 	rdc_config_t rdccfg;
1079 	rdc_rc_t *rc;
1080 
1081 	rc = new_rc();
1082 	if (!rc)
1083 		return (NULL);
1084 
1085 	bzero(&rdccfg, sizeof (rdc_config_t));
1086 	rdccfg.rdc_set[0] = config2set(rdc);
1087 	strncpy(rdccfg.rdc_set[0].secondary.bitmap, sbmp, NSC_MAXPATH);
1088 	rdccfg.command = RDC_CMD_RECONFIG;
1089 	rdccfg.options |= set_mode(rdc);
1090 	populate_addrs(&rdccfg.rdc_set[0], 0);
1091 
1092 	if (can_reconfig_sbmp(rdc, sbmp))
1093 		*rc = rdc_config(&rdccfg);
1094 	else
1095 		populate_rc(rc, rdc);
1096 
1097 	if ((rc->rc == 0) && (rdc->persist))
1098 		replace_cfgfield(rdc, "sbitmap", sbmp);
1099 
1100 	return (rc);
1101 }
1102 
1103 rdc_rc_t *
1104 rdc_reconfig_group(rdcconfig_t *rdc, char *group)
1105 {
1106 	rdc_config_t rdccfg;
1107 	rdcconfig_t	*rdcp = NULL;
1108 	rdcconfig_t	*cfg_rdcs = NULL;
1109 	rdc_rc_t	*rc = NULL;
1110 	rdc_rc_t	*rcp = NULL;
1111 
1112 	rdcp = rdc;
1113 	rc = new_rc();
1114 	if (!rc) {
1115 		return (NULL);
1116 	}
1117 	rcp = rc;
1118 
1119 	while (rdcp) {
1120 		bzero(&rdccfg, sizeof (rdc_config_t));
1121 		/* just in case */
1122 		strncpy(rdcp->group, group, NSC_MAXPATH);
1123 		rdccfg.rdc_set[0] = config2set(rdcp);
1124 		rdccfg.command = RDC_CMD_RECONFIG;
1125 		rdccfg.options |= set_mode(rdcp);
1126 		populate_addrs(&rdccfg.rdc_set[0], 0);
1127 
1128 		/* reconfig group rules enforced in kernel */
1129 		*rcp = rdc_config(&rdccfg);
1130 
1131 		rdcp = rdcp->next;
1132 		if (!rdcp)
1133 			break;
1134 
1135 		rcp->next = new_rc();
1136 		rcp = rcp->next;
1137 		if (!rcp)
1138 			break;
1139 	}
1140 	rcp = rc;
1141 	rdcp = rdc;
1142 	cfg_rdcs = chain_successful(rdcp, rcp);
1143 	replace_cfgfield(cfg_rdcs, "group", group);
1144 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
1145 
1146 	return (rc);
1147 }
1148 /*ARGSUSED*/
1149 rdc_rc_t *
1150 rdc_reconfig_ctag(rdcconfig_t *rdc, char *ctag)
1151 {
1152 	return (NULL);
1153 }
1154 
1155 rdc_rc_t *
1156 rdc_set_sync(rdcconfig_t *rdc)
1157 {
1158 	rdc_config_t rdccfg;
1159 	rdcconfig_t	*rdcp = NULL;
1160 	rdcconfig_t	*cfg_rdcs = NULL;
1161 	rdc_rc_t	*rc = NULL;
1162 	rdc_rc_t	*rcp = NULL;
1163 
1164 	rdcp = rdc;
1165 	rc = new_rc();
1166 	if (!rc) {
1167 		return (NULL);
1168 	}
1169 	rcp = rc;
1170 
1171 	while (rdcp) {
1172 		bzero(&rdccfg, sizeof (rdc_config_t));
1173 		rdccfg.rdc_set[0] = config2set(rdc);
1174 		rdccfg.command = RDC_CMD_RECONFIG;
1175 		rdccfg.options |= RDC_OPT_SYNC;
1176 		populate_addrs(&rdccfg.rdc_set[0], 0);
1177 
1178 		*rcp = rdc_config(&rdccfg);
1179 
1180 		rdcp = rdcp->next;
1181 		if (!rdcp)
1182 			break;
1183 
1184 		rcp->next = new_rc();
1185 		rcp = rcp->next;
1186 		if (!rcp)
1187 			break;
1188 	}
1189 
1190 	rcp = rc;
1191 	rdcp = rdc;
1192 	cfg_rdcs = chain_successful(rdcp, rcp);
1193 	replace_cfgfield(cfg_rdcs, "mode", "sync");
1194 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
1195 
1196 	return (rc);
1197 }
1198 
1199 rdc_rc_t *
1200 rdc_set_async(rdcconfig_t *rdc)
1201 {
1202 	rdc_config_t rdccfg;
1203 	rdcconfig_t	*rdcp = NULL;
1204 	rdcconfig_t	*cfg_rdcs = NULL;
1205 	rdc_rc_t	*rc = NULL;
1206 	rdc_rc_t	*rcp = NULL;
1207 
1208 	rdcp = rdc;
1209 	rc = new_rc();
1210 	if (!rc) {
1211 		return (NULL);
1212 	}
1213 	rcp = rc;
1214 
1215 	while (rdcp) {
1216 		bzero(&rdccfg, sizeof (rdc_config_t));
1217 		rdccfg.rdc_set[0] = config2set(rdcp);
1218 		rdccfg.command = RDC_CMD_RECONFIG;
1219 		rdccfg.options |= RDC_OPT_ASYNC;
1220 		populate_addrs(&rdccfg.rdc_set[0], 0);
1221 
1222 		*rcp = rdc_config(&rdccfg);
1223 
1224 		rdcp = rdcp->next;
1225 		if (!rdcp)
1226 			break;
1227 
1228 		rcp->next = new_rc();
1229 		rcp = rcp->next;
1230 		if (!rcp)
1231 			break;
1232 	}
1233 	rcp = rc;
1234 	rdcp = rdc;
1235 	cfg_rdcs = chain_successful(rdcp, rcp);
1236 	replace_cfgfield(cfg_rdcs, "mode", "async");
1237 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
1238 
1239 	return (rc);
1240 }
1241 
1242 rdc_rc_t *
1243 rdc_health(rdcconfig_t *rdc)
1244 {
1245 	rdc_config_t rdccfg;
1246 	rdcconfig_t	*rdcp = NULL;
1247 	rdc_rc_t	*rc = NULL;
1248 	rdc_rc_t	*rcp = NULL;
1249 
1250 	rdcp = rdc;
1251 	rc = new_rc();
1252 	if (!rc) {
1253 		return (NULL);
1254 	}
1255 	rcp = rc;
1256 
1257 	while (rdcp) {
1258 		bzero(&rdccfg, sizeof (rdc_config_t));
1259 		rdccfg.rdc_set[0] = config2set(rdcp);
1260 		rdccfg.command = RDC_CMD_HEALTH;
1261 		populate_addrs(&rdccfg.rdc_set[0], 0);
1262 
1263 		*rcp = rdc_config(&rdccfg);
1264 
1265 		rdcp = rdcp->next;
1266 		if (!rdcp)
1267 			break;
1268 
1269 		rcp->next = new_rc();
1270 		rcp = rcp->next;
1271 
1272 		if (!rcp)
1273 			break;
1274 
1275 	}
1276 	return (rc);
1277 }
1278 
1279 rdc_rc_t *
1280 rdc_reverse_role(rdcconfig_t *rdc)
1281 {
1282 	rdc_config_t rdccfg;
1283 	rdcconfig_t	*rdcp = NULL;
1284 	rdcconfig_t	*cfg_rdcs = NULL;
1285 	rdc_rc_t	*rc = NULL;
1286 	rdc_rc_t	*rcp = NULL;
1287 
1288 	rdcp = rdc;
1289 	rc = new_rc();
1290 	if (!rc) {
1291 		return (NULL);
1292 	}
1293 	rcp = rc;
1294 
1295 	while (rdcp) {
1296 		bzero(&rdccfg, sizeof (rdc_config_t));
1297 		rdccfg.rdc_set[0] = config2set(rdcp);
1298 		rdccfg.command = RDC_CMD_RECONFIG;
1299 		rdccfg.options |= RDC_OPT_REVERSE_ROLE;
1300 		rdccfg.options |= set_mode(rdcp);
1301 		populate_addrs(&rdccfg.rdc_set[0], 0);
1302 
1303 		*rcp = rdc_config(&rdccfg);
1304 
1305 		rdcp = rdcp->next;
1306 		if (!rdcp)
1307 			break;
1308 
1309 		rcp->next = new_rc();
1310 		rcp = rcp->next;
1311 		if (!rcp)
1312 			break;
1313 	}
1314 	rcp = rc;
1315 	rdcp = rdc;
1316 	cfg_rdcs = chain_successful(rdcp, rcp);
1317 	reverse_in_cfg(cfg_rdcs);
1318 	rdc_free_config(cfg_rdcs, RDC_FREEALL);
1319 
1320 	return (rc);
1321 }
1322