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 {
 318         rdc_rc_t *rcp, *rcq;
 319 
 320         rcp = rc;
 321         while (rcp) {
 322                 rcq = rcp->next;
 323                 free(rcp);
 324                 rcp = rcq;
 325         }
 326 
 327 }
 328 /*ARGSUSED*/
 329 rdcconfig_t *
 330 rdc_alloc_config(const char *phost, const char *pfile,
 331     const char *pbmp, const char *shost, const char *sfile, const char *sbmp,
 332     const char *mode, const char *group, const char *ctag, const char *options,
 333     int persist)
 334 {
 335         rdcconfig_t *rc;
 336 
 337         rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
 338         if (!rc) {
 339                 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
 340                 return (NULL);
 341         }
 342         if (phost)
 343                 strncpy(rc->phost, phost, NSC_MAXPATH);
 344         if (pfile)
 345                 strncpy(rc->pfile, pfile, NSC_MAXPATH);
 346         if (pbmp)
 347                 strncpy(rc->pbmp, pbmp, NSC_MAXPATH);
 348         if (shost)
 349                 strncpy(rc->shost, shost, NSC_MAXPATH);
 350         if (sfile)
 351                 strncpy(rc->sfile, sfile, NSC_MAXPATH);
 352         if (sbmp)
 353                 strncpy(rc->sbmp, sbmp, NSC_MAXPATH);
 354 
 355         strncpy(rc->direct, "ip", 2);
 356 
 357         if (mode)
 358                 strncpy(rc->mode, mode, NSC_MAXPATH);
 359         if (ctag)
 360                 strncpy(rc->ctag, ctag, NSC_MAXPATH);
 361         if (options)
 362                 strncpy(rc->options, options, NSC_MAXPATH);
 363 
 364         rc->persist = persist;
 365         rc->next = NULL;
 366 
 367         return (rc);
 368 
 369 }
 370 
 371 void
 372 populate_rc(rdc_rc_t *rcp, rdcconfig_t *rdcp)
 373 {
 374         rcp->rc = -1;
 375         strncpy(rcp->msg, rdc_error(NULL), RDC_ERR_SIZE);
 376         strncpy(rcp->set.phost, rdcp->phost, NSC_MAXPATH);
 377         strncpy(rcp->set.pfile, rdcp->pfile, NSC_MAXPATH);
 378         strncpy(rcp->set.shost, rdcp->shost, NSC_MAXPATH);
 379         strncpy(rcp->set.sfile, rdcp->sfile, NSC_MAXPATH);
 380 }
 381 
 382 /*
 383  * rdc_enable
 384  * return values
 385  * NULL on error
 386  * pointer to rdc_rc_t list of return values
 387  */
 388 rdc_rc_t *
 389 rdc_enable(rdcconfig_t *rdc)
 390 {
 391         rdc_config_t    rdccfg;
 392         rdcconfig_t     *rdcp = NULL;
 393         rdcconfig_t     *cfg_rdcs = NULL;
 394         rdc_rc_t        *rc = NULL;
 395         rdc_rc_t        *rcp = NULL;
 396 
 397         rdcp = rdc;
 398         rc = new_rc();
 399         if (!rc) { /* error already set */
 400                 return (NULL);
 401         }
 402         rcp = rc;
 403         while (rdcp) {
 404                 if (!rdcp->mode) {
 405                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 406                             RDC_EINVAL);
 407                         return (NULL);
 408                 }
 409                 bzero(&rdccfg, sizeof (rdc_config_t));
 410                 rdccfg.rdc_set[0] = config2set(rdcp);
 411                 rdccfg.command = RDC_CMD_ENABLE;
 412                 rdccfg.options = RDC_OPT_SETBMP;
 413                 if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
 414                         rdccfg.options |= RDC_OPT_SYNC;
 415                 } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
 416                         rdccfg.options |= RDC_OPT_ASYNC;
 417                 } else {
 418                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 419                             RDC_EINVAL);
 420                         return (NULL);
 421                 }
 422 
 423                 populate_addrs(&rdccfg.rdc_set[0], 1);
 424 
 425                 if (can_enable(rdcp)) {
 426                         /* do the operation */
 427                         *rcp = rdc_config(&rdccfg);
 428 
 429                 } else { /* set up what rdc_config would've set up */
 430 
 431                         populate_rc(rcp, rdcp);
 432 
 433                 }
 434                 if ((rcp->rc == 0) && (!rdcp->persist)) {
 435                         /*
 436                          * if we are not persisting, do this now,
 437                          * otherwise we will do it when
 438                          * we have a lock on the cfg in add_to_rdc_cfg
 439                          */
 440                         sv_enable(NULL, rdcp);
 441                 }
 442 
 443                 rdcp = rdcp->next;
 444                 if (!rdcp)
 445                         break;
 446 
 447                 rcp->next = new_rc();
 448                 rcp = rcp->next;
 449                 if (!rcp) {
 450                         /* dont free here, return what you have */
 451                         break;
 452                 }
 453         }
 454 
 455         /*
 456          * travel the rc chain and rdc chain checking results,
 457          * building a new chain, and updating dscfg
 458          */
 459         rcp = rc;
 460         rdcp = rdc;
 461 
 462         cfg_rdcs = chain_successful(rdcp, rcp);
 463 
 464         if (add_to_rdc_cfg(cfg_rdcs) < 0) {
 465                 /* XXX should disable or something here */
 466                 return (rc);
 467         }
 468         rdc_free_config(cfg_rdcs, RDC_FREEALL);
 469         return (rc);
 470 
 471 }
 472 
 473 rdc_rc_t *
 474 rdc_enable_clrbmp(rdcconfig_t *rdc)
 475 {
 476         rdc_config_t    rdccfg;
 477         rdcconfig_t     *rdcp = NULL;
 478         rdcconfig_t     *cfg_rdcs = NULL;
 479         rdc_rc_t        *rc = NULL;
 480         rdc_rc_t        *rcp = NULL;
 481 
 482         rdcp = rdc;
 483         rc = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
 484         if (!rc) {
 485                 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
 486                 return (NULL);
 487         }
 488         rcp = rc;
 489         while (rdcp) {
 490                 if (!rdcp->mode) {
 491                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 492                             RDC_EINVAL);
 493                         return (NULL);
 494                 }
 495                 bzero(&rdccfg, sizeof (rdc_config_t));
 496                 rdccfg.rdc_set[0] = config2set(rdcp);
 497                 rdccfg.command = RDC_CMD_ENABLE;
 498                 rdccfg.options = RDC_OPT_CLRBMP;
 499                 if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
 500                         rdccfg.options |= RDC_OPT_SYNC;
 501                 } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
 502                         rdccfg.options |= RDC_OPT_ASYNC;
 503                 } else {
 504                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 505                             RDC_EINVAL);
 506                         return (NULL);
 507                 }
 508 
 509                 populate_addrs(&rdccfg.rdc_set[0], 1);
 510 
 511                 if (can_enable(rdcp)) {
 512                         /* do the operation */
 513                         *rcp = rdc_config(&rdccfg);
 514 
 515                 } else { /* set up what rdc_config would've set up */
 516 
 517                         populate_rc(rcp, rdcp);
 518 
 519                 }
 520                 rdcp = rdcp->next;
 521                 if (!rdcp)
 522                         break;
 523 
 524                 rcp->next = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
 525                 rcp = rcp->next;
 526                 if (!rcp)
 527                         break;
 528         }
 529 
 530         /*
 531          * travel the rc chain and rdc chain checking results,
 532          * building a new chain, and updating dscfg
 533          */
 534         rcp = rc;
 535         rdcp = rdc;
 536 
 537         cfg_rdcs = chain_successful(rdcp, rcp);
 538 
 539         if (add_to_rdc_cfg(cfg_rdcs) < 0) {
 540                 /* XXX should disable or something here */
 541                 return (rc);
 542         }
 543         rdc_free_config(cfg_rdcs, RDC_FREEALL);
 544 
 545         return (rc);
 546 
 547 }
 548 
 549 rdc_rc_t *
 550 rdc_disable(rdcconfig_t *rdc)
 551 {
 552         rdc_config_t    rdccfg;
 553         rdcconfig_t     *rdcp = NULL;
 554         rdcconfig_t     *cfg_rdcs = NULL;
 555         rdc_rc_t        *rc = NULL;
 556         rdc_rc_t        *rcp = NULL;
 557 
 558         rdcp = rdc;
 559         rc = new_rc();
 560         if (!rc) {
 561                 return (NULL);
 562         }
 563         rcp = rc;
 564 
 565         while (rdcp) {
 566 
 567                 bzero(&rdccfg, sizeof (rdc_config_t));
 568                 rdccfg.rdc_set[0] = config2set(rdcp);
 569                 rdccfg.command = RDC_CMD_DISABLE;
 570                 populate_addrs(&rdccfg.rdc_set[0], 0);
 571 
 572                 *rcp = rdc_config(&rdccfg);
 573 
 574                 rdcp = rdcp->next;
 575                 if (!rdcp)
 576                         break;
 577 
 578                 rcp->next = new_rc();
 579                 rcp = rcp->next;
 580                 if (!rcp)
 581                         return (rc);
 582 
 583         }
 584         rcp = rc;
 585         rdcp = rdc;
 586 
 587         cfg_rdcs = chain_successful(rdcp, rcp);
 588 
 589         remove_from_rdc_cfg(cfg_rdcs);
 590 
 591         rdc_free_config(cfg_rdcs, RDC_FREEALL);
 592 
 593         return (rc);
 594 }
 595 
 596 rdc_rc_t *
 597 rdc_log(rdcconfig_t *rdc)
 598 {
 599         rdc_config_t rdccfg;
 600         rdcconfig_t     *rdcp = NULL;
 601         rdc_rc_t        *rc = NULL;
 602         rdc_rc_t        *rcp = NULL;
 603 
 604         rdcp = rdc;
 605         rc = new_rc();
 606         if (!rc) {
 607                 return (NULL);
 608         }
 609         rcp = rc;
 610 
 611         while (rdcp) {
 612                 bzero(&rdccfg, sizeof (rdc_config_t));
 613                 rdccfg.rdc_set[0] = config2set(rdcp);
 614                 rdccfg.command = RDC_CMD_LOG;
 615                 populate_addrs(&rdccfg.rdc_set[0], 0);
 616 
 617                 *rcp = rdc_config(&rdccfg);
 618 
 619                 rdcp = rdcp->next;
 620                 if (!rdcp)
 621                         break;
 622 
 623                 rcp->next = new_rc();
 624                 rcp = rcp->next;
 625                 if (!rcp)
 626                         break;
 627         }
 628         return (rc);
 629 }
 630 
 631 rdc_rc_t *
 632 rdc_usync(rdcconfig_t *rdc)
 633 {
 634         rdc_config_t *rdccfg;
 635         rdcconfig_t     *rdcp = NULL;
 636         rdc_rc_t        *rc = NULL;
 637         rdc_rc_t        *rcp = NULL;
 638         rdc_rc_t        *tmprc;
 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                 (void) 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 
 683         rdcp = rdc;
 684         rc = new_rc();
 685         if (!rc) {
 686                 return (NULL);
 687         }
 688         rcp = rc;
 689 
 690         while (rdcp) {
 691                 /* freed in rdc_mtconfig */
 692                 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
 693                 rdccfg->rdc_set[0] = config2set(rdcp);
 694                 rdccfg->command = RDC_CMD_COPY;
 695                 rdccfg->options = RDC_OPT_FULL|RDC_OPT_FORWARD;
 696                 populate_addrs(&rdccfg->rdc_set[0], 0);
 697                 (void) thr_create(NULL, 0, rdc_mtconfig,
 698                     (void **) rdccfg, THR_BOUND, NULL);
 699                 rdcp = rdcp->next;
 700                 if (!rdcp)
 701                         break;
 702 
 703         }
 704 
 705         /*
 706          * collect status here from thr_join-status,
 707          * and add to rdc_rc_t chain ?
 708          * this will block, but caller could always thread too
 709          */
 710         while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
 711                 if (rc == NULL) {
 712                         rcp = rc = (rdc_rc_t *)tmprc;
 713                 } else {
 714                         rcp->next = (rdc_rc_t *)tmprc;
 715                         rcp = rcp->next;
 716                 }
 717         }
 718 
 719         return (rc);
 720 }
 721 
 722 rdc_rc_t *
 723 rdc_rsync(rdcconfig_t *rdc)
 724 {
 725         rdc_config_t *rdccfg;
 726         rdcconfig_t     *rdcp = NULL;
 727         rdc_rc_t        *rc = NULL;
 728         rdc_rc_t        *rcp = NULL;
 729         rdc_rc_t        *tmprc = NULL;
 730 
 731         rdcp = rdc;
 732         rc = new_rc();
 733         if (!rc) {
 734                 return (NULL);
 735         }
 736         rcp = rc;
 737 
 738         while (rdcp) {
 739                 tmprc = cant_rsync(rdcp);
 740                 if (tmprc != NULL) {
 741                         if (rc == NULL) {
 742                                 rcp = rc = tmprc;
 743                         } else {
 744                                 rcp->next = tmprc;
 745                                 rcp = rcp->next;
 746                         }
 747                         goto next;
 748                 }
 749 
 750                 /* freed in rdc_mtconfig */
 751                 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
 752                 rdccfg->rdc_set[0] = config2set(rdcp);
 753                 rdccfg->command = RDC_CMD_COPY;
 754                 rdccfg->options = RDC_OPT_REVERSE|RDC_OPT_FULL;
 755                 populate_addrs(&rdccfg->rdc_set[0], 0);
 756                 (void) thr_create(NULL, 0, rdc_mtconfig,
 757                     (void **) rdccfg, THR_BOUND, NULL);
 758 next:
 759                 rdcp = rdcp->next;
 760                 if (!rdcp)
 761                         break;
 762         }
 763 
 764         /*
 765          * collect status here from thr_join-status,
 766          * and add to rdc_rc_t chain ?
 767          * this will block, but caller could always thread too
 768          */
 769         while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
 770                 if (rc == NULL) {
 771                         rcp = rc = (rdc_rc_t *)tmprc;
 772                 } else {
 773                         rcp->next = (rdc_rc_t *)tmprc;
 774                         rcp = rcp->next;
 775                 }
 776         }
 777 
 778         return (rc);
 779 }
 780 
 781 rdc_rc_t *
 782 rdc_ursync(rdcconfig_t *rdc)
 783 {
 784         rdc_config_t *rdccfg;
 785         rdcconfig_t     *rdcp = NULL;
 786         rdc_rc_t        *rc = NULL;
 787         rdc_rc_t        *rcp = NULL;
 788         rdc_rc_t        *tmprc = NULL;
 789 
 790         rdcp = rdc;
 791 
 792         while (rdcp) {
 793                 tmprc = cant_rsync(rdcp);
 794                 if (tmprc != NULL) {
 795                         if (rc == NULL) {
 796                                 rcp = rc = tmprc;
 797                         } else {
 798                                 rcp->next = tmprc;
 799                                 rcp = rcp->next;
 800                         }
 801                         goto next;
 802                 }
 803 
 804                 /* freed in rdc_mtconfig */
 805                 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
 806                 rdccfg->rdc_set[0] = config2set(rdcp);
 807                 rdccfg->command = RDC_CMD_COPY;
 808                 rdccfg->options = RDC_OPT_REVERSE | RDC_OPT_UPDATE;
 809                 populate_addrs(&rdccfg->rdc_set[0], 0);
 810                 (void) thr_create(NULL, 0, rdc_mtconfig,
 811                     (void **) rdccfg, THR_BOUND, NULL);
 812 next:
 813                 rdcp = rdcp->next;
 814                 if (!rdcp)
 815                         break;
 816 
 817         }
 818 
 819         /*
 820          * collect status here from thr_join-status,
 821          * and add to rdc_rc_t chain ?
 822          * this will block, but caller could always thread too
 823          */
 824         while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
 825                 if (rc == NULL) {
 826                         rcp = rc = (rdc_rc_t *)tmprc;
 827                 } else {
 828                         rcp->next = (rdc_rc_t *)tmprc;
 829                         rcp = rcp->next;
 830                 }
 831         }
 832 
 833         return (rc);
 834 }
 835 
 836 rdc_rc_t *
 837 rdc_wait(rdcconfig_t *rdc)
 838 {
 839         rdc_config_t rdccfg;
 840         rdcconfig_t     *rdcp = NULL;
 841         rdc_rc_t        *rc = NULL;
 842         rdc_rc_t        *rcp = NULL;
 843 
 844         rdcp = rdc;
 845         rc = new_rc();
 846         if (!rc) {
 847                 return (NULL);
 848         }
 849         rcp = rc;
 850 
 851         while (rdcp) {
 852                 bzero(&rdccfg, sizeof (rdc_config_t));
 853                 rdccfg.rdc_set[0] = config2set(rdcp);
 854                 rdccfg.command = RDC_CMD_WAIT;
 855                 populate_addrs(&rdccfg.rdc_set[0], 0);
 856 
 857                 *rcp = rdc_config(&rdccfg);
 858 
 859                 rdcp = rdcp->next;
 860                 if (!rdcp)
 861                         break;
 862 
 863                 rcp->next = new_rc();
 864                 rcp = rcp->next;
 865                 if (!rcp)
 866                         break;
 867         }
 868         return (rc);
 869 }
 870 
 871 rdc_rc_t *
 872 rdc_set_autosync(rdcconfig_t *rdc, int autosync)
 873 {
 874         rdc_config_t rdccfg;
 875         rdcconfig_t     *rdcp = NULL;
 876         rdc_rc_t        *rc = NULL;
 877         rdc_rc_t        *rcp = NULL;
 878 
 879         rdcp = rdc;
 880         rc = new_rc();
 881         if (!rc) {
 882                 return (NULL);
 883         }
 884         rcp = rc;
 885 
 886         while (rdcp) {
 887                 bzero(&rdccfg, sizeof (rdc_config_t));
 888                 rdccfg.rdc_set[0] = config2set(rdcp);
 889                 rdccfg.command = RDC_CMD_TUNABLE;
 890                 rdccfg.rdc_set[0].autosync = autosync;
 891                 rdccfg.rdc_set[0].maxqitems = -1;
 892                 rdccfg.rdc_set[0].maxqfbas = -1;
 893                 populate_addrs(&rdccfg.rdc_set[0], 0);
 894 
 895                 *rcp = rdc_config(&rdccfg);
 896 
 897                 rdcp = rdcp->next;
 898                 if (!rdcp)
 899                         break;
 900 
 901                 rcp->next = new_rc();
 902                 rcp = rcp->next;
 903                 if (!rcp)
 904                         break;
 905         }
 906         return (rc);
 907 }
 908 
 909 rdc_rc_t *
 910 rdc_set_maxqfbas(rdcconfig_t *rdc, int maxqfbas)
 911 {
 912         rdc_config_t rdccfg;
 913         rdcconfig_t     *rdcp = NULL;
 914         rdc_rc_t        *rc = NULL;
 915         rdc_rc_t        *rcp = NULL;
 916 
 917         rdcp = rdc;
 918         rc = new_rc();
 919         if (!rc) {
 920                 return (NULL);
 921         }
 922         rcp = rc;
 923 
 924         while (rdcp) {
 925                 bzero(&rdccfg, sizeof (rdc_config_t));
 926                 rdccfg.rdc_set[0] = config2set(rdcp);
 927                 rdccfg.command = RDC_CMD_TUNABLE;
 928                 rdccfg.rdc_set[0].autosync = -1;
 929                 rdccfg.rdc_set[0].maxqitems = -1;
 930                 rdccfg.rdc_set[0].maxqfbas = maxqfbas;
 931                 populate_addrs(&rdccfg.rdc_set[0], 0);
 932 
 933                 *rcp = rdc_config(&rdccfg);
 934 
 935                 rdcp = rdcp->next;
 936                 if (!rdcp)
 937                         break;
 938 
 939                 rcp->next = new_rc();
 940                 rcp = rcp->next;
 941                 if (!rcp)
 942                         break;
 943         }
 944         return (rc);
 945 }
 946 
 947 rdc_rc_t *
 948 rdc_set_maxqitems(rdcconfig_t *rdc, int maxqitems)
 949 {
 950         rdc_config_t rdccfg;
 951         rdcconfig_t     *rdcp = NULL;
 952         rdc_rc_t        *rc = NULL;
 953         rdc_rc_t        *rcp = NULL;
 954 
 955         rdcp = rdc;
 956         rc = new_rc();
 957 
 958         if (!rc) {
 959                 return (NULL);
 960         }
 961         rcp = rc;
 962 
 963         while (rdcp) {
 964                 bzero(&rdccfg, sizeof (rdc_config_t));
 965                 rdccfg.rdc_set[0] = config2set(rdc);
 966                 rdccfg.command = RDC_CMD_TUNABLE;
 967                 rdccfg.rdc_set[0].autosync = -1;
 968                 rdccfg.rdc_set[0].maxqitems = maxqitems;
 969                 rdccfg.rdc_set[0].maxqfbas = -1;
 970                 populate_addrs(&rdccfg.rdc_set[0], 0);
 971 
 972                 *rcp = rdc_config(&rdccfg);
 973 
 974                 rdcp = rdcp->next;
 975                 if (!rdcp)
 976                         break;
 977 
 978                 rcp->next = new_rc();
 979                 rcp = rcp->next;
 980                 if (!rcp)
 981                         break;
 982         }
 983         return (rc);
 984 }
 985 
 986 rdc_set_t
 987 rdc_status(rdcconfig_t *rdc)
 988 {
 989         rdc_config_t rdccfg;
 990 
 991         bzero(&rdccfg, sizeof (rdc_config_t));
 992         rdccfg.rdc_set[0] = config2set(rdc);
 993         rdccfg.command = RDC_CMD_STATUS;
 994         populate_addrs(&rdccfg.rdc_set[0], 0);
 995         rdc_config(&rdccfg);
 996 
 997         return (rdccfg.rdc_set[0]);
 998 }
 999 
1000 int
1001 rdc_get_autosync(rdcconfig_t *rdc)
1002 {
1003         rdc_set_t rdcset;
1004 
1005         rdcset = rdc_status(rdc);
1006         return (rdcset.autosync);
1007 }
1008 
1009 int
1010 rdc_get_maxqfbas(rdcconfig_t *rdc)
1011 {
1012         rdc_set_t rdcset;
1013 
1014         rdcset = rdc_status(rdc);
1015         return (rdcset.maxqfbas);
1016 
1017 }
1018 
1019 int
1020 rdc_get_maxqitems(rdcconfig_t *rdc)
1021 {
1022         rdc_set_t rdcset;
1023 
1024         rdcset = rdc_status(rdc);
1025         return (rdcset.maxqitems);
1026 
1027 }
1028 
1029 int
1030 set_mode(rdcconfig_t *rdc)
1031 {
1032         if (strcmp(rdc->mode, "async") == 0)
1033                 return (RDC_OPT_ASYNC);
1034         else
1035                 return (RDC_OPT_SYNC);
1036 }
1037 
1038 /*
1039  * reconfig bitmaps are single set only ops
1040  * for obvious reasons
1041  */
1042 rdc_rc_t *
1043 rdc_reconfig_pbmp(rdcconfig_t *rdc, char *pbmp)
1044 {
1045         rdc_config_t rdccfg;
1046         rdc_rc_t *rc;
1047 
1048         rc = new_rc();
1049         if ((!rc) || (!pbmp))
1050                 return (NULL);
1051 
1052         bzero(&rdccfg, sizeof (rdc_config_t));
1053         rdccfg.rdc_set[0] = config2set(rdc);
1054         strncpy(rdccfg.rdc_set[0].primary.bitmap, pbmp, NSC_MAXPATH);
1055         rdccfg.command = RDC_CMD_RECONFIG;
1056         rdccfg.options |= set_mode(rdc);
1057         populate_addrs(&rdccfg.rdc_set[0], 0);
1058 
1059         if (can_reconfig_pbmp(rdc, pbmp))
1060                 *rc = rdc_config(&rdccfg);
1061         else
1062                 populate_rc(rc, rdc);
1063 
1064         if ((rc->rc == 0) && (rdc->persist))
1065                 if (replace_cfgfield(rdc, "pbitmap", pbmp) < 0) {
1066                         rc->rc = -1;
1067                         strncpy(rc->msg, rdc_error(NULL), RDC_ERR_SIZE);
1068                 }
1069         return (rc);
1070 }
1071 
1072 rdc_rc_t *
1073 rdc_reconfig_sbmp(rdcconfig_t *rdc, char *sbmp)
1074 {
1075         rdc_config_t rdccfg;
1076         rdc_rc_t *rc;
1077 
1078         rc = new_rc();
1079         if (!rc)
1080                 return (NULL);
1081 
1082         bzero(&rdccfg, sizeof (rdc_config_t));
1083         rdccfg.rdc_set[0] = config2set(rdc);
1084         strncpy(rdccfg.rdc_set[0].secondary.bitmap, sbmp, NSC_MAXPATH);
1085         rdccfg.command = RDC_CMD_RECONFIG;
1086         rdccfg.options |= set_mode(rdc);
1087         populate_addrs(&rdccfg.rdc_set[0], 0);
1088 
1089         if (can_reconfig_sbmp(rdc, sbmp))
1090                 *rc = rdc_config(&rdccfg);
1091         else
1092                 populate_rc(rc, rdc);
1093 
1094         if ((rc->rc == 0) && (rdc->persist))
1095                 replace_cfgfield(rdc, "sbitmap", sbmp);
1096 
1097         return (rc);
1098 }
1099 
1100 rdc_rc_t *
1101 rdc_reconfig_group(rdcconfig_t *rdc, char *group)
1102 {
1103         rdc_config_t rdccfg;
1104         rdcconfig_t     *rdcp = NULL;
1105         rdcconfig_t     *cfg_rdcs = NULL;
1106         rdc_rc_t        *rc = NULL;
1107         rdc_rc_t        *rcp = NULL;
1108 
1109         rdcp = rdc;
1110         rc = new_rc();
1111         if (!rc) {
1112                 return (NULL);
1113         }
1114         rcp = rc;
1115 
1116         while (rdcp) {
1117                 bzero(&rdccfg, sizeof (rdc_config_t));
1118                 /* just in case */
1119                 strncpy(rdcp->group, group, NSC_MAXPATH);
1120                 rdccfg.rdc_set[0] = config2set(rdcp);
1121                 rdccfg.command = RDC_CMD_RECONFIG;
1122                 rdccfg.options |= set_mode(rdcp);
1123                 populate_addrs(&rdccfg.rdc_set[0], 0);
1124 
1125                 /* reconfig group rules enforced in kernel */
1126                 *rcp = rdc_config(&rdccfg);
1127 
1128                 rdcp = rdcp->next;
1129                 if (!rdcp)
1130                         break;
1131 
1132                 rcp->next = new_rc();
1133                 rcp = rcp->next;
1134                 if (!rcp)
1135                         break;
1136         }
1137         rcp = rc;
1138         rdcp = rdc;
1139         cfg_rdcs = chain_successful(rdcp, rcp);
1140         replace_cfgfield(cfg_rdcs, "group", group);
1141         rdc_free_config(cfg_rdcs, RDC_FREEALL);
1142 
1143         return (rc);
1144 }
1145 /*ARGSUSED*/
1146 rdc_rc_t *
1147 rdc_reconfig_ctag(rdcconfig_t *rdc, char *ctag)
1148 {
1149         return (NULL);
1150 }
1151 
1152 rdc_rc_t *
1153 rdc_set_sync(rdcconfig_t *rdc)
1154 {
1155         rdc_config_t rdccfg;
1156         rdcconfig_t     *rdcp = NULL;
1157         rdcconfig_t     *cfg_rdcs = NULL;
1158         rdc_rc_t        *rc = NULL;
1159         rdc_rc_t        *rcp = NULL;
1160 
1161         rdcp = rdc;
1162         rc = new_rc();
1163         if (!rc) {
1164                 return (NULL);
1165         }
1166         rcp = rc;
1167 
1168         while (rdcp) {
1169                 bzero(&rdccfg, sizeof (rdc_config_t));
1170                 rdccfg.rdc_set[0] = config2set(rdc);
1171                 rdccfg.command = RDC_CMD_RECONFIG;
1172                 rdccfg.options |= RDC_OPT_SYNC;
1173                 populate_addrs(&rdccfg.rdc_set[0], 0);
1174 
1175                 *rcp = rdc_config(&rdccfg);
1176 
1177                 rdcp = rdcp->next;
1178                 if (!rdcp)
1179                         break;
1180 
1181                 rcp->next = new_rc();
1182                 rcp = rcp->next;
1183                 if (!rcp)
1184                         break;
1185         }
1186 
1187         rcp = rc;
1188         rdcp = rdc;
1189         cfg_rdcs = chain_successful(rdcp, rcp);
1190         replace_cfgfield(cfg_rdcs, "mode", "sync");
1191         rdc_free_config(cfg_rdcs, RDC_FREEALL);
1192 
1193         return (rc);
1194 }
1195 
1196 rdc_rc_t *
1197 rdc_set_async(rdcconfig_t *rdc)
1198 {
1199         rdc_config_t rdccfg;
1200         rdcconfig_t     *rdcp = NULL;
1201         rdcconfig_t     *cfg_rdcs = NULL;
1202         rdc_rc_t        *rc = NULL;
1203         rdc_rc_t        *rcp = NULL;
1204 
1205         rdcp = rdc;
1206         rc = new_rc();
1207         if (!rc) {
1208                 return (NULL);
1209         }
1210         rcp = rc;
1211 
1212         while (rdcp) {
1213                 bzero(&rdccfg, sizeof (rdc_config_t));
1214                 rdccfg.rdc_set[0] = config2set(rdcp);
1215                 rdccfg.command = RDC_CMD_RECONFIG;
1216                 rdccfg.options |= RDC_OPT_ASYNC;
1217                 populate_addrs(&rdccfg.rdc_set[0], 0);
1218 
1219                 *rcp = rdc_config(&rdccfg);
1220 
1221                 rdcp = rdcp->next;
1222                 if (!rdcp)
1223                         break;
1224 
1225                 rcp->next = new_rc();
1226                 rcp = rcp->next;
1227                 if (!rcp)
1228                         break;
1229         }
1230         rcp = rc;
1231         rdcp = rdc;
1232         cfg_rdcs = chain_successful(rdcp, rcp);
1233         replace_cfgfield(cfg_rdcs, "mode", "async");
1234         rdc_free_config(cfg_rdcs, RDC_FREEALL);
1235 
1236         return (rc);
1237 }
1238 
1239 rdc_rc_t *
1240 rdc_health(rdcconfig_t *rdc)
1241 {
1242         rdc_config_t rdccfg;
1243         rdcconfig_t     *rdcp = NULL;
1244         rdc_rc_t        *rc = NULL;
1245         rdc_rc_t        *rcp = NULL;
1246 
1247         rdcp = rdc;
1248         rc = new_rc();
1249         if (!rc) {
1250                 return (NULL);
1251         }
1252         rcp = rc;
1253 
1254         while (rdcp) {
1255                 bzero(&rdccfg, sizeof (rdc_config_t));
1256                 rdccfg.rdc_set[0] = config2set(rdcp);
1257                 rdccfg.command = RDC_CMD_HEALTH;
1258                 populate_addrs(&rdccfg.rdc_set[0], 0);
1259 
1260                 *rcp = rdc_config(&rdccfg);
1261 
1262                 rdcp = rdcp->next;
1263                 if (!rdcp)
1264                         break;
1265 
1266                 rcp->next = new_rc();
1267                 rcp = rcp->next;
1268 
1269                 if (!rcp)
1270                         break;
1271 
1272         }
1273         return (rc);
1274 }
1275 
1276 rdc_rc_t *
1277 rdc_reverse_role(rdcconfig_t *rdc)
1278 {
1279         rdc_config_t rdccfg;
1280         rdcconfig_t     *rdcp = NULL;
1281         rdcconfig_t     *cfg_rdcs = NULL;
1282         rdc_rc_t        *rc = NULL;
1283         rdc_rc_t        *rcp = NULL;
1284 
1285         rdcp = rdc;
1286         rc = new_rc();
1287         if (!rc) {
1288                 return (NULL);
1289         }
1290         rcp = rc;
1291 
1292         while (rdcp) {
1293                 bzero(&rdccfg, sizeof (rdc_config_t));
1294                 rdccfg.rdc_set[0] = config2set(rdcp);
1295                 rdccfg.command = RDC_CMD_RECONFIG;
1296                 rdccfg.options |= RDC_OPT_REVERSE_ROLE;
1297                 rdccfg.options |= set_mode(rdcp);
1298                 populate_addrs(&rdccfg.rdc_set[0], 0);
1299 
1300                 *rcp = rdc_config(&rdccfg);
1301 
1302                 rdcp = rdcp->next;
1303                 if (!rdcp)
1304                         break;
1305 
1306                 rcp->next = new_rc();
1307                 rcp = rcp->next;
1308                 if (!rcp)
1309                         break;
1310         }
1311         rcp = rc;
1312         rdcp = rdc;
1313         cfg_rdcs = chain_successful(rdcp, rcp);
1314         reverse_in_cfg(cfg_rdcs);
1315         rdc_free_config(cfg_rdcs, RDC_FREEALL);
1316 
1317         return (rc);
1318 }