1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/ksynch.h>
  28 #include <sys/cmn_err.h>
  29 #include <sys/kmem.h>
  30 #include <sys/conf.h>
  31 #include <sys/errno.h>
  32 
  33 #ifdef _SunOS_5_6
  34 /*
  35  * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
  36  * define enum_t here as it is all we need from rpc/types.h
  37  * anyway and make it look like we included it. Yuck.
  38  */
  39 #define _RPC_TYPES_H
  40 typedef int enum_t;
  41 #else
  42 #ifndef DS_DDICT
  43 #include <rpc/types.h>
  44 #endif
  45 #endif /* _SunOS_5_6 */
  46 
  47 #include <sys/ddi.h>
  48 
  49 #include <sys/nsc_thread.h>
  50 #include <sys/nsctl/nsctl.h>
  51 
  52 #include <sys/sdt.h>              /* dtrace is S10 or later */
  53 
  54 #include "rdc_io.h"
  55 #include "rdc_bitmap.h"
  56 #include "rdc_update.h"
  57 #include "rdc_ioctl.h"
  58 #include "rdcsrv.h"
  59 #include "rdc_diskq.h"
  60 
  61 #include <sys/unistat/spcs_s.h>
  62 #include <sys/unistat/spcs_s_k.h>
  63 #include <sys/unistat/spcs_errors.h>
  64 
  65 volatile int net_exit;
  66 nsc_size_t MAX_RDC_FBAS;
  67 
  68 #ifdef DEBUG
  69 int RDC_MAX_SYNC_THREADS = 8;
  70 int rdc_maxthreads_last = 8;
  71 #endif
  72 
  73 kmutex_t rdc_ping_lock;         /* Ping lock */
  74 static kmutex_t net_blk_lock;
  75 
  76 /*
  77  * rdc_conf_lock is used as a global device configuration lock.
  78  * It is also used by enable/resume and disable/suspend code to ensure that
  79  * the transition of an rdc set between configured and unconfigured is
  80  * atomic.
  81  *
  82  * krdc->group->lock is used to protect state changes of a configured rdc
  83  * set (e.g. changes to urdc->flags), such as enabled to disabled and vice
  84  * versa.
  85  *
  86  * rdc_many_lock is also used to protect changes in group membership. A group
  87  * linked list cannot change while this lock is held. The many list and the
  88  * multi-hop list are both protected by rdc_many_lock.
  89  */
  90 kmutex_t rdc_conf_lock;
  91 kmutex_t rdc_many_lock;                 /* Many/multi-list lock */
  92 
  93 static kmutex_t rdc_net_hnd_id_lock;    /* Network handle id lock */
  94 int rdc_debug = 0;
  95 int rdc_debug_sleep = 0;
  96 
  97 static int rdc_net_hnd_id = 1;
  98 
  99 extern kmutex_t rdc_clnt_lock;
 100 
 101 static void rdc_ditemsfree(rdc_net_dataset_t *);
 102 void rdc_clnt_destroy(void);
 103 
 104 rdc_k_info_t *rdc_k_info;
 105 rdc_u_info_t *rdc_u_info;
 106 
 107 unsigned long rdc_async_timeout;
 108 
 109 nsc_size_t rdc_maxthres_queue = RDC_MAXTHRES_QUEUE;
 110 int rdc_max_qitems = RDC_MAX_QITEMS;
 111 int rdc_asyncthr = RDC_ASYNCTHR;
 112 static nsc_svc_t *rdc_volume_update;
 113 static int rdc_prealloc_handle = 1;
 114 
 115 extern int _rdc_rsrv_diskq(rdc_group_t *group);
 116 extern void _rdc_rlse_diskq(rdc_group_t *group);
 117 
 118 /*
 119  * Forward declare all statics that are used before defined
 120  * to enforce parameter checking
 121  *
 122  * Some (if not all) of these could be removed if the code were reordered
 123  */
 124 
 125 static void rdc_volume_update_svc(intptr_t);
 126 static void halt_sync(rdc_k_info_t *krdc);
 127 void rdc_kstat_create(int index);
 128 void rdc_kstat_delete(int index);
 129 static int rdc_checkforbitmap(int, nsc_off_t);
 130 static int rdc_installbitmap(int, void *, int, nsc_off_t, int, int *, int);
 131 static rdc_group_t *rdc_newgroup();
 132 
 133 int rdc_enable_diskq(rdc_k_info_t *krdc);
 134 void rdc_close_diskq(rdc_group_t *group);
 135 int rdc_suspend_diskq(rdc_k_info_t *krdc);
 136 int rdc_resume_diskq(rdc_k_info_t *krdc);
 137 void rdc_init_diskq_header(rdc_group_t *grp, dqheader *header);
 138 void rdc_fail_diskq(rdc_k_info_t *krdc, int wait, int dolog);
 139 void rdc_unfail_diskq(rdc_k_info_t *krdc);
 140 void rdc_unintercept_diskq(rdc_group_t *grp);
 141 int rdc_stamp_diskq(rdc_k_info_t *krdc, int rsrvd, int flags);
 142 void rdc_qfiller_thr(rdc_k_info_t *krdc);
 143 
 144 nstset_t *_rdc_ioset;
 145 nstset_t *_rdc_flset;
 146 
 147 /*
 148  * RDC threadset tunables
 149  */
 150 int rdc_threads = 64;           /* default number of threads */
 151 int rdc_threads_inc = 8;        /* increment for changing the size of the set */
 152 
 153 /*
 154  * Private threadset manipulation variables
 155  */
 156 static int rdc_threads_hysteresis = 2;
 157                                 /* hysteresis for threadset resizing */
 158 static int rdc_sets_active;     /* number of sets currently enabled */
 159 
 160 #ifdef DEBUG
 161 kmutex_t rdc_cntlock;
 162 #endif
 163 
 164 /*
 165  * rdc_thread_deconfigure - rdc is being deconfigured, stop any
 166  * thread activity.
 167  *
 168  * Inherently single-threaded by the Solaris module unloading code.
 169  */
 170 static void
 171 rdc_thread_deconfigure(void)
 172 {
 173         nst_destroy(_rdc_ioset);
 174         _rdc_ioset = NULL;
 175 
 176         nst_destroy(_rdc_flset);
 177         _rdc_flset = NULL;
 178 
 179         nst_destroy(sync_info.rdc_syncset);
 180         sync_info.rdc_syncset = NULL;
 181 }
 182 
 183 /*
 184  * rdc_thread_configure - rdc is being configured, initialize the
 185  * threads we need for flushing aync volumes.
 186  *
 187  * Must be called with rdc_conf_lock held.
 188  */
 189 static int
 190 rdc_thread_configure(void)
 191 {
 192         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 193 
 194         if ((_rdc_ioset = nst_init("rdc_thr", rdc_threads)) == NULL)
 195                 return (EINVAL);
 196 
 197         if ((_rdc_flset = nst_init("rdc_flushthr", 2)) == NULL)
 198                 return (EINVAL);
 199 
 200         if ((sync_info.rdc_syncset =
 201             nst_init("rdc_syncthr", RDC_MAX_SYNC_THREADS)) == NULL)
 202                 return (EINVAL);
 203 
 204         return (0);
 205 }
 206 
 207 
 208 /*
 209  * rdc_thread_tune - called to tune the size of the rdc threadset.
 210  *
 211  * Called from the config code when an rdc_set has been enabled or disabled.
 212  * 'sets' is the increment to the number of active rdc_sets.
 213  *
 214  * Must be called with rdc_conf_lock held.
 215  */
 216 static void
 217 rdc_thread_tune(int sets)
 218 {
 219         int incr = (sets > 0) ? 1 : -1;
 220         int change = 0;
 221         int nthreads;
 222 
 223         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 224 
 225         if (sets < 0)
 226                 sets = -sets;
 227 
 228         while (sets--) {
 229                 nthreads = nst_nthread(_rdc_ioset);
 230                 rdc_sets_active += incr;
 231 
 232                 if (rdc_sets_active >= nthreads)
 233                         change += nst_add_thread(_rdc_ioset, rdc_threads_inc);
 234                 else if ((rdc_sets_active <
 235                     (nthreads - (rdc_threads_inc + rdc_threads_hysteresis))) &&
 236                     ((nthreads - rdc_threads_inc) >= rdc_threads))
 237                         change -= nst_del_thread(_rdc_ioset, rdc_threads_inc);
 238         }
 239 
 240 #ifdef DEBUG
 241         if (change) {
 242                 cmn_err(CE_NOTE, "!rdc_thread_tune: "
 243                     "nsets %d, nthreads %d, nthreads change %d",
 244                     rdc_sets_active, nst_nthread(_rdc_ioset), change);
 245         }
 246 #endif
 247 }
 248 
 249 
 250 /*
 251  * _rdc_unload() - cache is being unloaded,
 252  * deallocate any dual copy structures allocated during cache
 253  * loading.
 254  */
 255 void
 256 _rdc_unload(void)
 257 {
 258         int i;
 259         rdc_k_info_t *krdc;
 260 
 261         if (rdc_volume_update) {
 262                 (void) nsc_unregister_svc(rdc_volume_update);
 263                 rdc_volume_update = NULL;
 264         }
 265 
 266         rdc_thread_deconfigure();
 267 
 268         if (rdc_k_info != NULL) {
 269                 for (i = 0; i < rdc_max_sets; i++) {
 270                         krdc = &rdc_k_info[i];
 271                         mutex_destroy(&krdc->dc_sleep);
 272                         mutex_destroy(&krdc->bmapmutex);
 273                         mutex_destroy(&krdc->kstat_mutex);
 274                         mutex_destroy(&krdc->bmp_kstat_mutex);
 275                         mutex_destroy(&krdc->syncbitmutex);
 276                         cv_destroy(&krdc->busycv);
 277                         cv_destroy(&krdc->closingcv);
 278                         cv_destroy(&krdc->haltcv);
 279                         cv_destroy(&krdc->synccv);
 280                 }
 281         }
 282 
 283         mutex_destroy(&sync_info.lock);
 284         mutex_destroy(&rdc_ping_lock);
 285         mutex_destroy(&net_blk_lock);
 286         mutex_destroy(&rdc_conf_lock);
 287         mutex_destroy(&rdc_many_lock);
 288         mutex_destroy(&rdc_net_hnd_id_lock);
 289         mutex_destroy(&rdc_clnt_lock);
 290 #ifdef DEBUG
 291         mutex_destroy(&rdc_cntlock);
 292 #endif
 293         net_exit = ATM_EXIT;
 294 
 295         if (rdc_k_info != NULL)
 296                 kmem_free(rdc_k_info, sizeof (*rdc_k_info) * rdc_max_sets);
 297         if (rdc_u_info != NULL)
 298                 kmem_free(rdc_u_info, sizeof (*rdc_u_info) * rdc_max_sets);
 299         rdc_k_info = NULL;
 300         rdc_u_info = NULL;
 301         rdc_max_sets = 0;
 302 }
 303 
 304 
 305 /*
 306  * _rdc_load() - rdc is being loaded, Allocate anything
 307  * that will be needed while the cache is loaded but doesn't really
 308  * depend on configuration parameters.
 309  *
 310  */
 311 int
 312 _rdc_load(void)
 313 {
 314         int i;
 315         rdc_k_info_t *krdc;
 316 
 317         mutex_init(&rdc_ping_lock, NULL, MUTEX_DRIVER, NULL);
 318         mutex_init(&net_blk_lock, NULL, MUTEX_DRIVER, NULL);
 319         mutex_init(&rdc_conf_lock, NULL, MUTEX_DRIVER, NULL);
 320         mutex_init(&rdc_many_lock, NULL, MUTEX_DRIVER, NULL);
 321         mutex_init(&rdc_net_hnd_id_lock, NULL, MUTEX_DRIVER, NULL);
 322         mutex_init(&rdc_clnt_lock, NULL, MUTEX_DRIVER, NULL);
 323         mutex_init(&sync_info.lock, NULL, MUTEX_DRIVER, NULL);
 324 
 325 #ifdef DEBUG
 326         mutex_init(&rdc_cntlock, NULL, MUTEX_DRIVER, NULL);
 327 #endif
 328 
 329         if ((i = nsc_max_devices()) < rdc_max_sets)
 330                 rdc_max_sets = i;
 331         /* following case for partial installs that may fail */
 332         if (!rdc_max_sets)
 333                 rdc_max_sets = 1024;
 334 
 335         rdc_k_info = kmem_zalloc(sizeof (*rdc_k_info) * rdc_max_sets, KM_SLEEP);
 336         if (!rdc_k_info)
 337                 return (ENOMEM);
 338 
 339         rdc_u_info = kmem_zalloc(sizeof (*rdc_u_info) * rdc_max_sets, KM_SLEEP);
 340         if (!rdc_u_info) {
 341                 kmem_free(rdc_k_info, sizeof (*rdc_k_info) * rdc_max_sets);
 342                 return (ENOMEM);
 343         }
 344 
 345         net_exit = ATM_NONE;
 346         for (i = 0; i < rdc_max_sets; i++) {
 347                 krdc = &rdc_k_info[i];
 348                 bzero(krdc, sizeof (*krdc));
 349                 krdc->index = i;
 350                 mutex_init(&krdc->dc_sleep, NULL, MUTEX_DRIVER, NULL);
 351                 mutex_init(&krdc->bmapmutex, NULL, MUTEX_DRIVER, NULL);
 352                 mutex_init(&krdc->kstat_mutex, NULL, MUTEX_DRIVER, NULL);
 353                 mutex_init(&krdc->bmp_kstat_mutex, NULL, MUTEX_DRIVER, NULL);
 354                 mutex_init(&krdc->syncbitmutex, NULL, MUTEX_DRIVER, NULL);
 355                 cv_init(&krdc->busycv, NULL, CV_DRIVER, NULL);
 356                 cv_init(&krdc->closingcv, NULL, CV_DRIVER, NULL);
 357                 cv_init(&krdc->haltcv, NULL, CV_DRIVER, NULL);
 358                 cv_init(&krdc->synccv, NULL, CV_DRIVER, NULL);
 359         }
 360 
 361         rdc_volume_update = nsc_register_svc("RDCVolumeUpdated",
 362             rdc_volume_update_svc);
 363 
 364         return (0);
 365 }
 366 
 367 static void
 368 rdc_u_init(rdc_u_info_t *urdc)
 369 {
 370         const int index = (int)(urdc - &rdc_u_info[0]);
 371 
 372         if (urdc->secondary.addr.maxlen)
 373                 free_rdc_netbuf(&urdc->secondary.addr);
 374         if (urdc->primary.addr.maxlen)
 375                 free_rdc_netbuf(&urdc->primary.addr);
 376 
 377         bzero(urdc, sizeof (rdc_u_info_t));
 378 
 379         urdc->index = index;
 380         urdc->maxqfbas = rdc_maxthres_queue;
 381         urdc->maxqitems = rdc_max_qitems;
 382         urdc->asyncthr = rdc_asyncthr;
 383 }
 384 
 385 /*
 386  * _rdc_configure() - cache is being configured.
 387  *
 388  * Initialize dual copy structures
 389  */
 390 int
 391 _rdc_configure(void)
 392 {
 393         int index;
 394         rdc_k_info_t *krdc;
 395 
 396         for (index = 0; index < rdc_max_sets; index++) {
 397                 krdc = &rdc_k_info[index];
 398 
 399                 krdc->remote_index = -1;
 400                 krdc->dcio_bitmap = NULL;
 401                 krdc->bitmap_ref = NULL;
 402                 krdc->bitmap_size = 0;
 403                 krdc->bitmap_write = 0;
 404                 krdc->disk_status = 0;
 405                 krdc->many_next = krdc;
 406 
 407                 rdc_u_init(&rdc_u_info[index]);
 408         }
 409 
 410         rdc_async_timeout = 120 * HZ;   /* Seconds * HZ */
 411         MAX_RDC_FBAS = FBA_LEN(RDC_MAXDATA);
 412         if (net_exit != ATM_INIT) {
 413                 net_exit = ATM_INIT;
 414                 return (0);
 415         }
 416         return (0);
 417 }
 418 
 419 /*
 420  * _rdc_deconfigure - rdc is being deconfigured, shut down any
 421  * dual copy operations and return to an unconfigured state.
 422  */
 423 void
 424 _rdc_deconfigure(void)
 425 {
 426         rdc_k_info_t *krdc;
 427         rdc_u_info_t *urdc;
 428         int index;
 429 
 430         for (index = 0; index < rdc_max_sets; index++) {
 431                 krdc = &rdc_k_info[index];
 432                 urdc = &rdc_u_info[index];
 433 
 434                 krdc->remote_index = -1;
 435                 krdc->dcio_bitmap = NULL;
 436                 krdc->bitmap_ref = NULL;
 437                 krdc->bitmap_size = 0;
 438                 krdc->bitmap_write = 0;
 439                 krdc->disk_status = 0;
 440                 krdc->many_next = krdc;
 441 
 442                 if (urdc->primary.addr.maxlen)
 443                         free_rdc_netbuf(&(urdc->primary.addr));
 444 
 445                 if (urdc->secondary.addr.maxlen)
 446                         free_rdc_netbuf(&(urdc->secondary.addr));
 447 
 448                 bzero(urdc, sizeof (rdc_u_info_t));
 449                 urdc->index = index;
 450         }
 451         net_exit = ATM_EXIT;
 452         rdc_clnt_destroy();
 453 
 454 }
 455 
 456 
 457 /*
 458  * Lock primitives, containing checks that lock ordering isn't broken
 459  */
 460 /*ARGSUSED*/
 461 void
 462 rdc_many_enter(rdc_k_info_t *krdc)
 463 {
 464         ASSERT(!MUTEX_HELD(&krdc->bmapmutex));
 465 
 466         mutex_enter(&rdc_many_lock);
 467 }
 468 
 469 /* ARGSUSED */
 470 void
 471 rdc_many_exit(rdc_k_info_t *krdc)
 472 {
 473         mutex_exit(&rdc_many_lock);
 474 }
 475 
 476 void
 477 rdc_group_enter(rdc_k_info_t *krdc)
 478 {
 479         ASSERT(!MUTEX_HELD(&rdc_many_lock));
 480         ASSERT(!MUTEX_HELD(&rdc_conf_lock));
 481         ASSERT(!MUTEX_HELD(&krdc->bmapmutex));
 482 
 483         mutex_enter(&krdc->group->lock);
 484 }
 485 
 486 void
 487 rdc_group_exit(rdc_k_info_t *krdc)
 488 {
 489         mutex_exit(&krdc->group->lock);
 490 }
 491 
 492 /*
 493  * Suspend and disable operations use this function to wait until it is safe
 494  * to do continue, without trashing data structures used by other ioctls.
 495  */
 496 static void
 497 wait_busy(rdc_k_info_t *krdc)
 498 {
 499         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 500 
 501         while (krdc->busy_count > 0)
 502                 cv_wait(&krdc->busycv, &rdc_conf_lock);
 503 }
 504 
 505 
 506 /*
 507  * Other ioctls use this function to hold off disable and suspend.
 508  */
 509 void
 510 set_busy(rdc_k_info_t *krdc)
 511 {
 512         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 513 
 514         wait_busy(krdc);
 515 
 516         krdc->busy_count++;
 517 }
 518 
 519 
 520 /*
 521  * Other ioctls use this function to allow disable and suspend to continue.
 522  */
 523 void
 524 wakeup_busy(rdc_k_info_t *krdc)
 525 {
 526         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 527 
 528         if (krdc->busy_count <= 0)
 529                 return;
 530 
 531         krdc->busy_count--;
 532         cv_broadcast(&krdc->busycv);
 533 }
 534 
 535 
 536 /*
 537  * Remove the rdc set from its group, and destroy the group if no longer in
 538  * use.
 539  */
 540 static void
 541 remove_from_group(rdc_k_info_t *krdc)
 542 {
 543         rdc_k_info_t *p;
 544         rdc_group_t *group;
 545 
 546         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 547 
 548         rdc_many_enter(krdc);
 549         group = krdc->group;
 550 
 551         group->count--;
 552 
 553         /*
 554          * lock queue while looking at thrnum
 555          */
 556         mutex_enter(&group->ra_queue.net_qlock);
 557         if ((group->rdc_thrnum == 0) && (group->count == 0)) {
 558 
 559                 /*
 560                  * Assure the we've stopped and the flusher thread has not
 561                  * fallen back to sleep
 562                  */
 563                 if (krdc->group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) {
 564                         group->ra_queue.qfflags |= RDC_QFILLSTOP;
 565                         while (krdc->group->ra_queue.qfflags & RDC_QFILLSTOP) {
 566                                 if (krdc->group->ra_queue.qfill_sleeping ==
 567                                     RDC_QFILL_ASLEEP)
 568                                         cv_broadcast(&group->ra_queue.qfcv);
 569                                 mutex_exit(&group->ra_queue.net_qlock);
 570                                 delay(2);
 571                                 mutex_enter(&group->ra_queue.net_qlock);
 572                         }
 573                 }
 574                 mutex_exit(&group->ra_queue.net_qlock);
 575 
 576                 mutex_enter(&group->diskqmutex);
 577                 rdc_close_diskq(group);
 578                 mutex_exit(&group->diskqmutex);
 579                 rdc_delgroup(group);
 580                 rdc_many_exit(krdc);
 581                 krdc->group = NULL;
 582                 return;
 583         }
 584         mutex_exit(&group->ra_queue.net_qlock);
 585         /*
 586          * Always clear the group field.
 587          * no, you need it set in rdc_flush_memq().
 588          * to call rdc_group_log()
 589          * krdc->group = NULL;
 590          */
 591 
 592         /* Take this rdc structure off the group list */
 593 
 594         for (p = krdc->group_next; p->group_next != krdc; p = p->group_next)
 595         ;
 596         p->group_next = krdc->group_next;
 597 
 598         rdc_many_exit(krdc);
 599 }
 600 
 601 
 602 /*
 603  * Add the rdc set to its group, setting up a new group if it's the first one.
 604  */
 605 static int
 606 add_to_group(rdc_k_info_t *krdc, int options, int cmd)
 607 {
 608         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
 609         rdc_u_info_t *utmp;
 610         rdc_k_info_t *ktmp;
 611         int index;
 612         rdc_group_t *group;
 613         int rc = 0;
 614         nsthread_t *trc;
 615 
 616         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 617 
 618         /*
 619          * Look for matching group name, primary host name and secondary
 620          * host name.
 621          */
 622 
 623         rdc_many_enter(krdc);
 624         for (index = 0; index < rdc_max_sets; index++) {
 625                 utmp = &rdc_u_info[index];
 626                 ktmp = &rdc_k_info[index];
 627 
 628                 if (urdc->group_name[0] == 0)
 629                         break;
 630 
 631                 if (!IS_CONFIGURED(ktmp))
 632                         continue;
 633 
 634                 if (strncmp(utmp->group_name, urdc->group_name,
 635                     NSC_MAXPATH) != 0)
 636                         continue;
 637                 if (strncmp(utmp->primary.intf, urdc->primary.intf,
 638                     MAX_RDC_HOST_SIZE) != 0) {
 639                         /* Same group name, different primary interface */
 640                         rdc_many_exit(krdc);
 641                         return (-1);
 642                 }
 643                 if (strncmp(utmp->secondary.intf, urdc->secondary.intf,
 644                     MAX_RDC_HOST_SIZE) != 0) {
 645                         /* Same group name, different secondary interface */
 646                         rdc_many_exit(krdc);
 647                         return (-1);
 648                 }
 649 
 650                 /* Group already exists, so add this set to the group */
 651 
 652                 if (((options & RDC_OPT_ASYNC) == 0) &&
 653                     ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) {
 654                         /* Must be same mode as existing group members */
 655                         rdc_many_exit(krdc);
 656                         return (-1);
 657                 }
 658                 if (((options & RDC_OPT_ASYNC) != 0) &&
 659                     ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) {
 660                         /* Must be same mode as existing group members */
 661                         rdc_many_exit(krdc);
 662                         return (-1);
 663                 }
 664 
 665                 /* cannont reconfigure existing group into new queue this way */
 666                 if ((cmd != RDC_CMD_RESUME) &&
 667                     !RDC_IS_DISKQ(ktmp->group) && urdc->disk_queue[0] != '\0') {
 668                         rdc_many_exit(krdc);
 669                         return (RDC_EQNOADD);
 670                 }
 671 
 672                 ktmp->group->count++;
 673                 krdc->group = ktmp->group;
 674                 krdc->group_next = ktmp->group_next;
 675                 ktmp->group_next = krdc;
 676 
 677                 urdc->autosync = utmp->autosync;  /* Same as rest */
 678 
 679                 (void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH);
 680 
 681                 rdc_many_exit(krdc);
 682                 return (0);
 683         }
 684 
 685         /* This must be a new group */
 686         group = rdc_newgroup();
 687         krdc->group = group;
 688         krdc->group_next = krdc;
 689         urdc->autosync = -1; /* Unknown */
 690 
 691         /*
 692          * Tune the thread set by one for each thread created
 693          */
 694         rdc_thread_tune(1);
 695 
 696         trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP);
 697         if (trc == NULL) {
 698                 rc = -1;
 699                 cmn_err(CE_NOTE, "!unable to create queue filler daemon");
 700                 goto fail;
 701         }
 702 
 703         if (urdc->disk_queue[0] == '\0') {
 704                 krdc->group->flags |= RDC_MEMQUE;
 705         } else {
 706                 krdc->group->flags |= RDC_DISKQUE;
 707 
 708                 /* XXX check here for resume or enable and act accordingly */
 709 
 710                 if (cmd == RDC_CMD_RESUME) {
 711                         rc = rdc_resume_diskq(krdc);
 712 
 713                 } else if (cmd == RDC_CMD_ENABLE) {
 714                         rc = rdc_enable_diskq(krdc);
 715                         if ((rc == RDC_EQNOADD) && (cmd != RDC_CMD_ENABLE)) {
 716                                 cmn_err(CE_WARN, "!disk queue %s enable failed,"
 717                                     " enabling memory queue",
 718                                     urdc->disk_queue);
 719                                 krdc->group->flags &= ~RDC_DISKQUE;
 720                                 krdc->group->flags |= RDC_MEMQUE;
 721                                 bzero(urdc->disk_queue, NSC_MAXPATH);
 722                         }
 723                 }
 724         }
 725 fail:
 726         rdc_many_exit(krdc);
 727         return (rc);
 728 }
 729 
 730 
 731 /*
 732  * Move the set to a new group if possible
 733  */
 734 static int
 735 change_group(rdc_k_info_t *krdc, int options)
 736 {
 737         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
 738         rdc_u_info_t *utmp;
 739         rdc_k_info_t *ktmp;
 740         rdc_k_info_t *next;
 741         char tmpq[NSC_MAXPATH];
 742         int index;
 743         int rc = -1;
 744         rdc_group_t *group, *old_group;
 745         nsthread_t *trc;
 746 
 747         ASSERT(MUTEX_HELD(&rdc_conf_lock));
 748 
 749         /*
 750          * Look for matching group name, primary host name and secondary
 751          * host name.
 752          */
 753 
 754         bzero(&tmpq, sizeof (tmpq));
 755         rdc_many_enter(krdc);
 756 
 757         old_group = krdc->group;
 758         next = krdc->group_next;
 759 
 760         if (RDC_IS_DISKQ(old_group)) { /* can't keep your own queue */
 761                 (void) strncpy(tmpq, urdc->disk_queue, NSC_MAXPATH);
 762                 bzero(urdc->disk_queue, sizeof (urdc->disk_queue));
 763         }
 764         for (index = 0; index < rdc_max_sets; index++) {
 765                 utmp = &rdc_u_info[index];
 766                 ktmp = &rdc_k_info[index];
 767 
 768                 if (ktmp == krdc)
 769                         continue;
 770 
 771                 if (urdc->group_name[0] == 0)
 772                         break;
 773 
 774                 if (!IS_CONFIGURED(ktmp))
 775                         continue;
 776 
 777                 if (strncmp(utmp->group_name, urdc->group_name,
 778                     NSC_MAXPATH) != 0)
 779                         continue;
 780                 if (strncmp(utmp->primary.intf, urdc->primary.intf,
 781                     MAX_RDC_HOST_SIZE) != 0)
 782                         goto bad;
 783                 if (strncmp(utmp->secondary.intf, urdc->secondary.intf,
 784                     MAX_RDC_HOST_SIZE) != 0)
 785                         goto bad;
 786 
 787                 /* Group already exists, so add this set to the group */
 788 
 789                 if (((options & RDC_OPT_ASYNC) == 0) &&
 790                     ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) {
 791                         /* Must be same mode as existing group members */
 792                         goto bad;
 793                 }
 794                 if (((options & RDC_OPT_ASYNC) != 0) &&
 795                     ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) {
 796                         /* Must be same mode as existing group members */
 797                         goto bad;
 798                 }
 799 
 800                 ktmp->group->count++;
 801                 krdc->group = ktmp->group;
 802                 krdc->group_next = ktmp->group_next;
 803                 ktmp->group_next = krdc;
 804                 bzero(urdc->disk_queue, sizeof (urdc->disk_queue));
 805                 (void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH);
 806 
 807                 goto good;
 808         }
 809 
 810         /* This must be a new group */
 811         group = rdc_newgroup();
 812         krdc->group = group;
 813         krdc->group_next = krdc;
 814 
 815         trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP);
 816         if (trc == NULL) {
 817                 rc = -1;
 818                 cmn_err(CE_NOTE, "!unable to create queue filler daemon");
 819                 goto bad;
 820         }
 821 
 822         if (urdc->disk_queue[0] == 0) {
 823                 krdc->group->flags |= RDC_MEMQUE;
 824         } else {
 825                 krdc->group->flags |= RDC_DISKQUE;
 826                 if ((rc = rdc_enable_diskq(krdc)) < 0)
 827                         goto bad;
 828         }
 829 good:
 830         if (options & RDC_OPT_ASYNC) {
 831                 krdc->type_flag |= RDC_ASYNCMODE;
 832                 rdc_set_flags(urdc, RDC_ASYNC);
 833         } else {
 834                 krdc->type_flag &= ~RDC_ASYNCMODE;
 835                 rdc_clr_flags(urdc, RDC_ASYNC);
 836         }
 837 
 838         old_group->count--;
 839         if (!old_group->rdc_writer && old_group->count == 0) {
 840                 /* Group now empty, so destroy */
 841                 if (RDC_IS_DISKQ(old_group)) {
 842                         rdc_unintercept_diskq(old_group);
 843                         mutex_enter(&old_group->diskqmutex);
 844                         rdc_close_diskq(old_group);
 845                         mutex_exit(&old_group->diskqmutex);
 846                 }
 847 
 848                 mutex_enter(&old_group->ra_queue.net_qlock);
 849 
 850                 /*
 851                  * Assure the we've stopped and the flusher thread has not
 852                  * fallen back to sleep
 853                  */
 854                 if (old_group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) {
 855                         old_group->ra_queue.qfflags |= RDC_QFILLSTOP;
 856                         while (old_group->ra_queue.qfflags & RDC_QFILLSTOP) {
 857                                 if (old_group->ra_queue.qfill_sleeping ==
 858                                     RDC_QFILL_ASLEEP)
 859                                         cv_broadcast(&old_group->ra_queue.qfcv);
 860                                 mutex_exit(&old_group->ra_queue.net_qlock);
 861                                 delay(2);
 862                                 mutex_enter(&old_group->ra_queue.net_qlock);
 863                         }
 864                 }
 865                 mutex_exit(&old_group->ra_queue.net_qlock);
 866 
 867                 rdc_delgroup(old_group);
 868                 rdc_many_exit(krdc);
 869                 return (0);
 870         }
 871 
 872         /* Take this rdc structure off the old group list */
 873 
 874         for (ktmp = next; ktmp->group_next != krdc; ktmp = ktmp->group_next)
 875         ;
 876         ktmp->group_next = next;
 877 
 878         rdc_many_exit(krdc);
 879         return (0);
 880 
 881 bad:
 882         /* Leave existing group status alone */
 883         (void) strncpy(urdc->disk_queue, tmpq, NSC_MAXPATH);
 884         rdc_many_exit(krdc);
 885         return (rc);
 886 }
 887 
 888 
 889 /*
 890  * Set flags for an rdc set, setting the group flags as necessary.
 891  */
 892 void
 893 rdc_set_flags(rdc_u_info_t *urdc, int flags)
 894 {
 895         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
 896         int vflags, sflags, bflags, ssflags;
 897 
 898         DTRACE_PROBE2(rdc_set_flags, int, krdc->index, int, flags);
 899         vflags = flags & RDC_VFLAGS;
 900         sflags = flags & RDC_SFLAGS;
 901         bflags = flags & RDC_BFLAGS;
 902         ssflags = flags & RDC_SYNC_STATE_FLAGS;
 903 
 904         if (vflags) {
 905                 /* normal volume flags */
 906                 ASSERT(MUTEX_HELD(&rdc_conf_lock) ||
 907                     MUTEX_HELD(&krdc->group->lock));
 908                 if (ssflags)
 909                         mutex_enter(&krdc->bmapmutex);
 910 
 911                 urdc->flags |= vflags;
 912 
 913                 if (ssflags)
 914                         mutex_exit(&krdc->bmapmutex);
 915         }
 916 
 917         if (sflags) {
 918                 /* Sync state flags that are protected by a different lock */
 919                 ASSERT(MUTEX_HELD(&rdc_many_lock));
 920                 urdc->sync_flags |= sflags;
 921         }
 922 
 923         if (bflags) {
 924                 /* Bmap state flags that are protected by a different lock */
 925                 ASSERT(MUTEX_HELD(&krdc->bmapmutex));
 926                 urdc->bmap_flags |= bflags;
 927         }
 928 
 929 }
 930 
 931 
 932 /*
 933  * Clear flags for an rdc set, clearing the group flags as necessary.
 934  */
 935 void
 936 rdc_clr_flags(rdc_u_info_t *urdc, int flags)
 937 {
 938         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
 939         int vflags, sflags, bflags;
 940 
 941         DTRACE_PROBE2(rdc_clr_flags, int, krdc->index, int, flags);
 942         vflags = flags & RDC_VFLAGS;
 943         sflags = flags & RDC_SFLAGS;
 944         bflags = flags & RDC_BFLAGS;
 945 
 946         if (vflags) {
 947                 /* normal volume flags */
 948                 ASSERT(MUTEX_HELD(&rdc_conf_lock) ||
 949                     MUTEX_HELD(&krdc->group->lock));
 950                 urdc->flags &= ~vflags;
 951 
 952         }
 953 
 954         if (sflags) {
 955                 /* Sync state flags that are protected by a different lock */
 956                 ASSERT(MUTEX_HELD(&rdc_many_lock));
 957                 urdc->sync_flags &= ~sflags;
 958         }
 959 
 960         if (bflags) {
 961                 /* Bmap state flags that are protected by a different lock */
 962                 ASSERT(MUTEX_HELD(&krdc->bmapmutex));
 963                 urdc->bmap_flags &= ~bflags;
 964         }
 965 }
 966 
 967 
 968 /*
 969  * Get the flags for an rdc set.
 970  */
 971 int
 972 rdc_get_vflags(rdc_u_info_t *urdc)
 973 {
 974         return (urdc->flags | urdc->sync_flags | urdc->bmap_flags);
 975 }
 976 
 977 
 978 /*
 979  * Initialise flags for an rdc set.
 980  */
 981 static void
 982 rdc_init_flags(rdc_u_info_t *urdc)
 983 {
 984         urdc->flags = 0;
 985         urdc->mflags = 0;
 986         urdc->sync_flags = 0;
 987         urdc->bmap_flags = 0;
 988 }
 989 
 990 
 991 /*
 992  * Set flags for a many group.
 993  */
 994 void
 995 rdc_set_mflags(rdc_u_info_t *urdc, int flags)
 996 {
 997         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
 998         rdc_k_info_t *this = krdc;
 999 
1000         ASSERT(!(flags & ~RDC_MFLAGS));
1001 
1002         if (flags == 0)
1003                 return;
1004 
1005         ASSERT(MUTEX_HELD(&rdc_many_lock));
1006 
1007         rdc_set_flags(urdc, flags);     /* set flags on local urdc */
1008 
1009         urdc->mflags |= flags;
1010         for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) {
1011                 urdc = &rdc_u_info[krdc->index];
1012                 if (!IS_ENABLED(urdc))
1013                         continue;
1014                 urdc->mflags |= flags;
1015         }
1016 }
1017 
1018 
1019 /*
1020  * Clear flags for a many group.
1021  */
1022 void
1023 rdc_clr_mflags(rdc_u_info_t *urdc, int flags)
1024 {
1025         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
1026         rdc_k_info_t *this = krdc;
1027         rdc_u_info_t *utmp;
1028 
1029         ASSERT(!(flags & ~RDC_MFLAGS));
1030 
1031         if (flags == 0)
1032                 return;
1033 
1034         ASSERT(MUTEX_HELD(&rdc_many_lock));
1035 
1036         rdc_clr_flags(urdc, flags);     /* clear flags on local urdc */
1037 
1038         /*
1039          * We must maintain the mflags based on the set of flags for
1040          * all the urdc's that are chained up.
1041          */
1042 
1043         /*
1044          * First look through all the urdc's and remove bits from
1045          * the 'flags' variable that are in use elsewhere.
1046          */
1047 
1048         for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) {
1049                 utmp = &rdc_u_info[krdc->index];
1050                 if (!IS_ENABLED(utmp))
1051                         continue;
1052                 flags &= ~(rdc_get_vflags(utmp) & RDC_MFLAGS);
1053                 if (flags == 0)
1054                         break;
1055         }
1056 
1057         /*
1058          * Now clear flags as necessary.
1059          */
1060 
1061         if (flags != 0) {
1062                 urdc->mflags &= ~flags;
1063                 for (krdc = krdc->many_next; krdc != this;
1064                     krdc = krdc->many_next) {
1065                         utmp = &rdc_u_info[krdc->index];
1066                         if (!IS_ENABLED(utmp))
1067                                 continue;
1068                         utmp->mflags &= ~flags;
1069                 }
1070         }
1071 }
1072 
1073 
1074 int
1075 rdc_get_mflags(rdc_u_info_t *urdc)
1076 {
1077         return (urdc->mflags);
1078 }
1079 
1080 
1081 void
1082 rdc_set_flags_log(rdc_u_info_t *urdc, int flags, char *why)
1083 {
1084         DTRACE_PROBE2(rdc_set_flags_log, int, urdc->index, int, flags);
1085 
1086         rdc_set_flags(urdc, flags);
1087 
1088         if (why == NULL)
1089                 return;
1090 
1091         if (flags & RDC_LOGGING)
1092                 cmn_err(CE_NOTE, "!sndr: %s:%s entered logging mode: %s",
1093                     urdc->secondary.intf, urdc->secondary.file, why);
1094         if (flags & RDC_VOL_FAILED)
1095                 cmn_err(CE_NOTE, "!sndr: %s:%s volume failed: %s",
1096                     urdc->secondary.intf, urdc->secondary.file, why);
1097         if (flags & RDC_BMP_FAILED)
1098                 cmn_err(CE_NOTE, "!sndr: %s:%s bitmap failed: %s",
1099                     urdc->secondary.intf, urdc->secondary.file, why);
1100 }
1101 /*
1102  * rdc_lor(source, dest, len)
1103  * logically OR memory pointed to by source and dest, copying result into dest.
1104  */
1105 void
1106 rdc_lor(const uchar_t *source, uchar_t *dest, int len)
1107 {
1108         int i;
1109 
1110         if (source == NULL)
1111                 return;
1112 
1113         for (i = 0; i < len; i++)
1114                 *dest++ |= *source++;
1115 }
1116 
1117 
1118 static int
1119 check_filesize(int index, spcs_s_info_t kstatus)
1120 {
1121         uint64_t remote_size;
1122         char tmp1[16], tmp2[16];
1123         rdc_u_info_t *urdc = &rdc_u_info[index];
1124         int status;
1125 
1126         status = rdc_net_getsize(index, &remote_size);
1127         if (status) {
1128                 (void) spcs_s_inttostring(status, tmp1, sizeof (tmp1), 0);
1129                 spcs_s_add(kstatus, RDC_EGETSIZE, urdc->secondary.intf,
1130                     urdc->secondary.file, tmp1);
1131                 (void) rdc_net_state(index, CCIO_ENABLELOG);
1132                 return (RDC_EGETSIZE);
1133         }
1134         if (remote_size < (unsigned long long)urdc->volume_size) {
1135                 (void) spcs_s_inttostring(
1136                     urdc->volume_size, tmp1, sizeof (tmp1), 0);
1137                 /*
1138                  * Cheat, and covert to int, until we have
1139                  * spcs_s_unsignedlonginttostring().
1140                  */
1141                 status = (int)remote_size;
1142                 (void) spcs_s_inttostring(status, tmp2, sizeof (tmp2), 0);
1143                 spcs_s_add(kstatus, RDC_ESIZE, urdc->primary.intf,
1144                     urdc->primary.file, tmp1, urdc->secondary.intf,
1145                     urdc->secondary.file, tmp2);
1146                 (void) rdc_net_state(index, CCIO_ENABLELOG);
1147                 return (RDC_ESIZE);
1148         }
1149         return (0);
1150 }
1151 
1152 
1153 static void
1154 rdc_volume_update_svc(intptr_t arg)
1155 {
1156         rdc_update_t *update = (rdc_update_t *)arg;
1157         rdc_k_info_t *krdc;
1158         rdc_k_info_t *this;
1159         rdc_u_info_t *urdc;
1160         struct net_bdata6 bd;
1161         int index;
1162         int rc;
1163 
1164 #ifdef DEBUG_IIUPDATE
1165         cmn_err(CE_NOTE, "!SNDR received update request for %s",
1166             update->volume);
1167 #endif
1168 
1169         if ((update->protocol != RDC_SVC_ONRETURN) &&
1170             (update->protocol != RDC_SVC_VOL_ENABLED)) {
1171                 /* don't understand what the client intends to do */
1172                 update->denied = 1;
1173                 spcs_s_add(update->status, RDC_EVERSION);
1174                 return;
1175         }
1176 
1177         index = rdc_lookup_enabled(update->volume, 0);
1178         if (index < 0)
1179                 return;
1180 
1181         /*
1182          * warn II that this volume is in use by sndr so
1183          * II can validate the sizes of the master vs shadow
1184          * and avoid trouble later down the line with
1185          * size mis-matches between urdc->volume_size and
1186          * what is returned from nsc_partsize() which may
1187          * be the size of the master when replicating the shadow
1188          */
1189         if (update->protocol == RDC_SVC_VOL_ENABLED) {
1190                 if (index >= 0)
1191                         update->denied = 1;
1192                 return;
1193         }
1194 
1195         krdc = &rdc_k_info[index];
1196         urdc = &rdc_u_info[index];
1197         this = krdc;
1198 
1199         do {
1200                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
1201 #ifdef DEBUG_IIUPDATE
1202                 cmn_err(CE_NOTE, "!SNDR refused update request for %s",
1203                     update->volume);
1204 #endif
1205                 update->denied = 1;
1206                 spcs_s_add(update->status, RDC_EMIRRORUP);
1207                 return;
1208                 }
1209                 /* 1->many - all must be logging */
1210                 if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) {
1211                         rdc_many_enter(krdc);
1212                         for (krdc = krdc->many_next; krdc != this;
1213                             krdc = krdc->many_next) {
1214                                 urdc = &rdc_u_info[krdc->index];
1215                                 if (!IS_ENABLED(urdc))
1216                                         continue;
1217                                 break;
1218                         }
1219                         rdc_many_exit(krdc);
1220                 }
1221         } while (krdc != this);
1222 
1223 #ifdef DEBUG_IIUPDATE
1224         cmn_err(CE_NOTE, "!SNDR allowed update request for %s", update->volume);
1225 #endif
1226         urdc = &rdc_u_info[krdc->index];
1227         do {
1228 
1229                 bd.size = min(krdc->bitmap_size, (nsc_size_t)update->size);
1230                 bd.data.data_val = (char *)update->bitmap;
1231                 bd.offset = 0;
1232                 bd.cd = index;
1233 
1234                 if ((rc = RDC_OR_BITMAP(&bd)) != 0) {
1235                         update->denied = 1;
1236                         spcs_s_add(update->status, rc);
1237                         return;
1238                 }
1239                 urdc = &rdc_u_info[index];
1240                 urdc->bits_set = RDC_COUNT_BITMAP(krdc);
1241                 if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) {
1242                         rdc_many_enter(krdc);
1243                         for (krdc = krdc->many_next; krdc != this;
1244                             krdc = krdc->many_next) {
1245                                 index = krdc->index;
1246                                 if (!IS_ENABLED(urdc))
1247                                         continue;
1248                                 break;
1249                         }
1250                         rdc_many_exit(krdc);
1251                 }
1252         } while (krdc != this);
1253 
1254 
1255         /* II (or something else) has updated us, so no need for a sync */
1256         if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED)) {
1257                 rdc_many_enter(krdc);
1258                 rdc_clr_flags(urdc, RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED);
1259                 rdc_many_exit(krdc);
1260         }
1261 
1262         if (krdc->bitmap_write > 0)
1263                 (void) rdc_write_bitmap(krdc);
1264 }
1265 
1266 
1267 /*
1268  * rdc_check()
1269  *
1270  * Return 0 if the set is configured, enabled and the supplied
1271  * addressing information matches the in-kernel config, otherwise
1272  * return 1.
1273  */
1274 static int
1275 rdc_check(rdc_k_info_t *krdc, rdc_set_t *rdc_set)
1276 {
1277         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1278 
1279         ASSERT(MUTEX_HELD(&krdc->group->lock));
1280 
1281         if (!IS_ENABLED(urdc))
1282                 return (1);
1283 
1284         if (strncmp(urdc->primary.file, rdc_set->primary.file,
1285             NSC_MAXPATH) != 0) {
1286 #ifdef DEBUG
1287                 cmn_err(CE_WARN, "!rdc_check: primary file mismatch %s vs %s",
1288                     urdc->primary.file, rdc_set->primary.file);
1289 #endif
1290                 return (1);
1291         }
1292 
1293         if (rdc_set->primary.addr.len != 0 &&
1294             bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf,
1295             urdc->primary.addr.len) != 0) {
1296 #ifdef DEBUG
1297                 cmn_err(CE_WARN, "!rdc_check: primary address mismatch for %s",
1298                     urdc->primary.file);
1299 #endif
1300                 return (1);
1301         }
1302 
1303         if (strncmp(urdc->secondary.file, rdc_set->secondary.file,
1304             NSC_MAXPATH) != 0) {
1305 #ifdef DEBUG
1306                 cmn_err(CE_WARN, "!rdc_check: secondary file mismatch %s vs %s",
1307                     urdc->secondary.file, rdc_set->secondary.file);
1308 #endif
1309                 return (1);
1310         }
1311 
1312         if (rdc_set->secondary.addr.len != 0 &&
1313             bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf,
1314             urdc->secondary.addr.len) != 0) {
1315 #ifdef DEBUG
1316                 cmn_err(CE_WARN, "!rdc_check: secondary addr mismatch for %s",
1317                     urdc->secondary.file);
1318 #endif
1319                 return (1);
1320         }
1321 
1322         return (0);
1323 }
1324 
1325 
1326 /*
1327  * Lookup enabled sets for a bitmap match
1328  */
1329 
1330 int
1331 rdc_lookup_bitmap(char *pathname)
1332 {
1333         rdc_u_info_t *urdc;
1334 #ifdef DEBUG
1335         rdc_k_info_t *krdc;
1336 #endif
1337         int index;
1338 
1339         for (index = 0; index < rdc_max_sets; index++) {
1340                 urdc = &rdc_u_info[index];
1341 #ifdef DEBUG
1342                 krdc = &rdc_k_info[index];
1343 #endif
1344                 ASSERT(krdc->index == index);
1345                 ASSERT(urdc->index == index);
1346 
1347                 if (!IS_ENABLED(urdc))
1348                         continue;
1349 
1350                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1351                         if (strncmp(pathname, urdc->primary.bitmap,
1352                             NSC_MAXPATH) == 0)
1353                                 return (index);
1354                 } else {
1355                         if (strncmp(pathname, urdc->secondary.bitmap,
1356                             NSC_MAXPATH) == 0)
1357                                 return (index);
1358                 }
1359         }
1360 
1361         return (-1);
1362 }
1363 
1364 
1365 /*
1366  * Translate a pathname to index into rdc_k_info[].
1367  * Returns first match that is enabled.
1368  */
1369 
1370 int
1371 rdc_lookup_enabled(char *pathname, int allow_disabling)
1372 {
1373         rdc_u_info_t *urdc;
1374         rdc_k_info_t *krdc;
1375         int index;
1376 
1377 restart:
1378         for (index = 0; index < rdc_max_sets; index++) {
1379                 urdc = &rdc_u_info[index];
1380                 krdc = &rdc_k_info[index];
1381 
1382                 ASSERT(krdc->index == index);
1383                 ASSERT(urdc->index == index);
1384 
1385                 if (!IS_ENABLED(urdc))
1386                         continue;
1387 
1388                 if (allow_disabling == 0 && krdc->type_flag & RDC_UNREGISTER)
1389                         continue;
1390 
1391                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1392                         if (strncmp(pathname, urdc->primary.file,
1393                             NSC_MAXPATH) == 0)
1394                                 return (index);
1395                 } else {
1396                         if (strncmp(pathname, urdc->secondary.file,
1397                             NSC_MAXPATH) == 0)
1398                                 return (index);
1399                 }
1400         }
1401 
1402         if (allow_disabling == 0) {
1403                 /* None found, or only a disabling one found, so try again */
1404                 allow_disabling = 1;
1405                 goto restart;
1406         }
1407 
1408         return (-1);
1409 }
1410 
1411 
1412 /*
1413  * Translate a pathname to index into rdc_k_info[].
1414  * Returns first match that is configured.
1415  *
1416  * Used by enable & resume code.
1417  * Must be called with rdc_conf_lock held.
1418  */
1419 
1420 int
1421 rdc_lookup_configured(char *pathname)
1422 {
1423         rdc_u_info_t *urdc;
1424         rdc_k_info_t *krdc;
1425         int index;
1426 
1427         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1428 
1429         for (index = 0; index < rdc_max_sets; index++) {
1430                 urdc = &rdc_u_info[index];
1431                 krdc = &rdc_k_info[index];
1432 
1433                 ASSERT(krdc->index == index);
1434                 ASSERT(urdc->index == index);
1435 
1436                 if (!IS_CONFIGURED(krdc))
1437                         continue;
1438 
1439                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1440                         if (strncmp(pathname, urdc->primary.file,
1441                             NSC_MAXPATH) == 0)
1442                                 return (index);
1443                 } else {
1444                         if (strncmp(pathname, urdc->secondary.file,
1445                             NSC_MAXPATH) == 0)
1446                                 return (index);
1447                 }
1448         }
1449 
1450         return (-1);
1451 }
1452 
1453 
1454 /*
1455  * Looks up a configured set with matching secondary interface:volume
1456  * to check for illegal many-to-one volume configs.  To be used during
1457  * enable and resume processing.
1458  *
1459  * Must be called with rdc_conf_lock held.
1460  */
1461 
1462 static int
1463 rdc_lookup_many2one(rdc_set_t *rdc_set)
1464 {
1465         rdc_u_info_t *urdc;
1466         rdc_k_info_t *krdc;
1467         int index;
1468 
1469         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1470 
1471         for (index = 0; index < rdc_max_sets; index++) {
1472                 urdc = &rdc_u_info[index];
1473                 krdc = &rdc_k_info[index];
1474 
1475                 if (!IS_CONFIGURED(krdc))
1476                         continue;
1477 
1478                 if (strncmp(urdc->secondary.file,
1479                     rdc_set->secondary.file, NSC_MAXPATH) != 0)
1480                         continue;
1481                 if (strncmp(urdc->secondary.intf,
1482                     rdc_set->secondary.intf, MAX_RDC_HOST_SIZE) != 0)
1483                         continue;
1484 
1485                 break;
1486         }
1487 
1488         if (index < rdc_max_sets)
1489                 return (index);
1490         else
1491                 return (-1);
1492 }
1493 
1494 
1495 /*
1496  * Looks up an rdc set to check if it is already configured, to be used from
1497  * functions called from the config ioctl where the interface names can be
1498  * used for comparison.
1499  *
1500  * Must be called with rdc_conf_lock held.
1501  */
1502 
1503 int
1504 rdc_lookup_byname(rdc_set_t *rdc_set)
1505 {
1506         rdc_u_info_t *urdc;
1507         rdc_k_info_t *krdc;
1508         int index;
1509 
1510         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1511 
1512         for (index = 0; index < rdc_max_sets; index++) {
1513                 urdc = &rdc_u_info[index];
1514                 krdc = &rdc_k_info[index];
1515 
1516                 ASSERT(krdc->index == index);
1517                 ASSERT(urdc->index == index);
1518 
1519                 if (!IS_CONFIGURED(krdc))
1520                         continue;
1521 
1522                 if (strncmp(urdc->primary.file, rdc_set->primary.file,
1523                     NSC_MAXPATH) != 0)
1524                         continue;
1525                 if (strncmp(urdc->primary.intf, rdc_set->primary.intf,
1526                     MAX_RDC_HOST_SIZE) != 0)
1527                         continue;
1528                 if (strncmp(urdc->secondary.file, rdc_set->secondary.file,
1529                     NSC_MAXPATH) != 0)
1530                         continue;
1531                 if (strncmp(urdc->secondary.intf, rdc_set->secondary.intf,
1532                     MAX_RDC_HOST_SIZE) != 0)
1533                         continue;
1534 
1535                 break;
1536         }
1537 
1538         if (index < rdc_max_sets)
1539                 return (index);
1540         else
1541                 return (-1);
1542 }
1543 
1544 /*
1545  * Looks up a secondary hostname and device, to be used from
1546  * functions called from the config ioctl where the interface names can be
1547  * used for comparison.
1548  *
1549  * Must be called with rdc_conf_lock held.
1550  */
1551 
1552 int
1553 rdc_lookup_byhostdev(char *intf, char *file)
1554 {
1555         rdc_u_info_t *urdc;
1556         rdc_k_info_t *krdc;
1557         int index;
1558 
1559         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1560 
1561         for (index = 0; index < rdc_max_sets; index++) {
1562                 urdc = &rdc_u_info[index];
1563                 krdc = &rdc_k_info[index];
1564 
1565                 ASSERT(krdc->index == index);
1566                 ASSERT(urdc->index == index);
1567 
1568                 if (!IS_CONFIGURED(krdc))
1569                         continue;
1570 
1571                 if (strncmp(urdc->secondary.file, file,
1572                     NSC_MAXPATH) != 0)
1573                         continue;
1574                 if (strncmp(urdc->secondary.intf, intf,
1575                     MAX_RDC_HOST_SIZE) != 0)
1576                         continue;
1577                 break;
1578         }
1579 
1580         if (index < rdc_max_sets)
1581                 return (index);
1582         else
1583                 return (-1);
1584 }
1585 
1586 
1587 /*
1588  * Looks up an rdc set to see if it is currently enabled, to be used on the
1589  * server so that the interface addresses must be used for comparison, as
1590  * the interface names may differ from those used on the client.
1591  *
1592  */
1593 
1594 int
1595 rdc_lookup_byaddr(rdc_set_t *rdc_set)
1596 {
1597         rdc_u_info_t *urdc;
1598 #ifdef DEBUG
1599         rdc_k_info_t *krdc;
1600 #endif
1601         int index;
1602 
1603         for (index = 0; index < rdc_max_sets; index++) {
1604                 urdc = &rdc_u_info[index];
1605 #ifdef DEBUG
1606                 krdc = &rdc_k_info[index];
1607 #endif
1608                 ASSERT(krdc->index == index);
1609                 ASSERT(urdc->index == index);
1610 
1611                 if (!IS_ENABLED(urdc))
1612                         continue;
1613 
1614                 if (strcmp(urdc->primary.file, rdc_set->primary.file) != 0)
1615                         continue;
1616 
1617                 if (strcmp(urdc->secondary.file, rdc_set->secondary.file) != 0)
1618                         continue;
1619 
1620                 if (bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf,
1621                     urdc->primary.addr.len) != 0) {
1622                         continue;
1623                 }
1624 
1625                 if (bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf,
1626                     urdc->secondary.addr.len) != 0) {
1627                         continue;
1628                 }
1629 
1630                 break;
1631         }
1632 
1633         if (index < rdc_max_sets)
1634                 return (index);
1635         else
1636                 return (-1);
1637 }
1638 
1639 
1640 /*
1641  * Return index of first multihop or 1-to-many
1642  * Behavior controlled by setting ismany.
1643  * ismany TRUE (one-to-many)
1644  * ismany FALSE (multihops)
1645  *
1646  */
1647 static int
1648 rdc_lookup_multimany(rdc_k_info_t *krdc, const int ismany)
1649 {
1650         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1651         rdc_u_info_t *utmp;
1652         rdc_k_info_t *ktmp;
1653         char *pathname;
1654         int index;
1655         int role;
1656 
1657         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1658         ASSERT(MUTEX_HELD(&rdc_many_lock));
1659 
1660         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1661                 /* this host is the primary of the krdc set */
1662                 pathname = urdc->primary.file;
1663                 if (ismany) {
1664                         /*
1665                          * 1-many sets are linked by primary :
1666                          * look for matching primary on this host
1667                          */
1668                         role = RDC_PRIMARY;
1669                 } else {
1670                         /*
1671                          * multihop sets link primary to secondary :
1672                          * look for matching secondary on this host
1673                          */
1674                         role = 0;
1675                 }
1676         } else {
1677                 /* this host is the secondary of the krdc set */
1678                 pathname = urdc->secondary.file;
1679                 if (ismany) {
1680                         /*
1681                          * 1-many sets are linked by primary, so if
1682                          * this host is the secondary of the set this
1683                          * cannot require 1-many linkage.
1684                          */
1685                         return (-1);
1686                 } else {
1687                         /*
1688                          * multihop sets link primary to secondary :
1689                          * look for matching primary on this host
1690                          */
1691                         role = RDC_PRIMARY;
1692                 }
1693         }
1694 
1695         for (index = 0; index < rdc_max_sets; index++) {
1696                 utmp = &rdc_u_info[index];
1697                 ktmp = &rdc_k_info[index];
1698 
1699                 if (!IS_CONFIGURED(ktmp)) {
1700                         continue;
1701                 }
1702 
1703                 if (role == RDC_PRIMARY) {
1704                         /*
1705                          * Find a primary that is this host and is not
1706                          * krdc but shares the same data volume as krdc.
1707                          */
1708                         if ((rdc_get_vflags(utmp) & RDC_PRIMARY) &&
1709                             strncmp(utmp->primary.file, pathname,
1710                             NSC_MAXPATH) == 0 && (krdc != ktmp)) {
1711                                 break;
1712                         }
1713                 } else {
1714                         /*
1715                          * Find a secondary that is this host and is not
1716                          * krdc but shares the same data volume as krdc.
1717                          */
1718                         if (!(rdc_get_vflags(utmp) & RDC_PRIMARY) &&
1719                             strncmp(utmp->secondary.file, pathname,
1720                             NSC_MAXPATH) == 0 && (krdc != ktmp)) {
1721                                 break;
1722                         }
1723                 }
1724         }
1725 
1726         if (index < rdc_max_sets)
1727                 return (index);
1728         else
1729                 return (-1);
1730 }
1731 
1732 /*
1733  * Returns secondary match that is configured.
1734  *
1735  * Used by enable & resume code.
1736  * Must be called with rdc_conf_lock held.
1737  */
1738 
1739 static int
1740 rdc_lookup_secondary(char *pathname)
1741 {
1742         rdc_u_info_t *urdc;
1743         rdc_k_info_t *krdc;
1744         int index;
1745 
1746         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1747 
1748         for (index = 0; index < rdc_max_sets; index++) {
1749                 urdc = &rdc_u_info[index];
1750                 krdc = &rdc_k_info[index];
1751 
1752                 ASSERT(krdc->index == index);
1753                 ASSERT(urdc->index == index);
1754 
1755                 if (!IS_CONFIGURED(krdc))
1756                         continue;
1757 
1758                 if (!IS_STATE(urdc, RDC_PRIMARY)) {
1759                         if (strncmp(pathname, urdc->secondary.file,
1760                             NSC_MAXPATH) == 0)
1761                         return (index);
1762                 }
1763         }
1764 
1765         return (-1);
1766 }
1767 
1768 
1769 static nsc_fd_t *
1770 rdc_open_direct(rdc_k_info_t *krdc)
1771 {
1772         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1773         int rc;
1774 
1775         if (krdc->remote_fd == NULL)
1776                 krdc->remote_fd = nsc_open(urdc->direct_file,
1777                     NSC_RDCHR_ID|NSC_DEVICE|NSC_RDWR, 0, 0, &rc);
1778         return (krdc->remote_fd);
1779 }
1780 
1781 static void
1782 rdc_close_direct(rdc_k_info_t *krdc)
1783 {
1784         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1785 
1786         urdc->direct_file[0] = 0;
1787         if (krdc->remote_fd) {
1788                 if (nsc_close(krdc->remote_fd) == 0) {
1789                         krdc->remote_fd = NULL;
1790                 }
1791         }
1792 }
1793 
1794 
1795 #ifdef DEBUG_MANY
1796 static void
1797 print_many(rdc_k_info_t *start)
1798 {
1799         rdc_k_info_t *p = start;
1800         rdc_u_info_t *q = &rdc_u_info[p->index];
1801 
1802         do {
1803                 cmn_err(CE_CONT, "!krdc %p, %s %s (many_nxt %p multi_nxt %p)\n",
1804                     p, q->primary.file, q->secondary.file, p->many_next,
1805                     p->multi_next);
1806                 delay(10);
1807                 p = p->many_next;
1808                 q = &rdc_u_info[p->index];
1809         } while (p && p != start);
1810 }
1811 #endif /* DEBUG_MANY */
1812 
1813 
1814 static int
1815 add_to_multi(rdc_k_info_t *krdc)
1816 {
1817         rdc_u_info_t *urdc;
1818         rdc_k_info_t *ktmp;
1819         rdc_u_info_t *utmp;
1820         int mindex;
1821         int domulti;
1822 
1823         urdc = &rdc_u_info[krdc->index];
1824 
1825         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1826         ASSERT(MUTEX_HELD(&rdc_many_lock));
1827 
1828         /* Now find companion krdc */
1829         mindex = rdc_lookup_multimany(krdc, FALSE);
1830 
1831 #ifdef DEBUG_MANY
1832         cmn_err(CE_NOTE,
1833             "!add_to_multi: lookup_multimany: mindex %d prim %s sec %s",
1834             mindex, urdc->primary.file, urdc->secondary.file);
1835 #endif
1836 
1837         if (mindex >= 0) {
1838                 ktmp = &rdc_k_info[mindex];
1839                 utmp = &rdc_u_info[mindex];
1840 
1841                 domulti = 1;
1842 
1843                 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
1844                     ktmp->multi_next != NULL) {
1845                         /*
1846                          * We are adding a new primary to a many
1847                          * group that is the target of a multihop, just
1848                          * ignore it since we are linked in elsewhere.
1849                          */
1850                         domulti = 0;
1851                 }
1852 
1853                 if (domulti) {
1854                         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1855                                 /* Is previous leg using direct file I/O? */
1856                                 if (utmp->direct_file[0] != 0) {
1857                                         /* It is, so cannot proceed */
1858                                         return (-1);
1859                                 }
1860                         } else {
1861                                 /* Is this leg using direct file I/O? */
1862                                 if (urdc->direct_file[0] != 0) {
1863                                         /* It is, so cannot proceed */
1864                                         return (-1);
1865                                 }
1866                         }
1867                         krdc->multi_next = ktmp;
1868                         ktmp->multi_next = krdc;
1869                 }
1870         } else {
1871                 krdc->multi_next = NULL;
1872 #ifdef DEBUG_MANY
1873                 cmn_err(CE_NOTE, "!add_to_multi: NULL multi_next index %d",
1874                     krdc->index);
1875 #endif
1876         }
1877 
1878         return (0);
1879 }
1880 
1881 
1882 /*
1883  * Add a new set to the circular list of 1-to-many primaries and chain
1884  * up any multihop as well.
1885  */
1886 static int
1887 add_to_many(rdc_k_info_t *krdc)
1888 {
1889         rdc_k_info_t *okrdc;
1890         int oindex;
1891 
1892         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1893 
1894         rdc_many_enter(krdc);
1895 
1896         if (add_to_multi(krdc) < 0) {
1897                 rdc_many_exit(krdc);
1898                 return (-1);
1899         }
1900 
1901         oindex = rdc_lookup_multimany(krdc, TRUE);
1902         if (oindex < 0) {
1903 #ifdef DEBUG_MANY
1904                 print_many(krdc);
1905 #endif
1906                 rdc_many_exit(krdc);
1907                 return (0);
1908         }
1909 
1910         okrdc = &rdc_k_info[oindex];
1911 
1912 #ifdef DEBUG_MANY
1913         print_many(okrdc);
1914 #endif
1915         krdc->many_next = okrdc->many_next;
1916         okrdc->many_next = krdc;
1917 
1918 #ifdef DEBUG_MANY
1919         print_many(okrdc);
1920 #endif
1921         rdc_many_exit(krdc);
1922         return (0);
1923 }
1924 
1925 
1926 /*
1927  * Remove a set from the circular list of 1-to-many primaries.
1928  */
1929 static void
1930 remove_from_many(rdc_k_info_t *old)
1931 {
1932         rdc_u_info_t *uold = &rdc_u_info[old->index];
1933         rdc_k_info_t *p, *q;
1934 
1935         ASSERT(MUTEX_HELD(&rdc_conf_lock));
1936 
1937         rdc_many_enter(old);
1938 
1939 #ifdef DEBUG_MANY
1940         cmn_err(CE_NOTE, "!rdc: before remove_from_many");
1941         print_many(old);
1942 #endif
1943 
1944         if (old->many_next == old) {
1945                 /* remove from multihop */
1946                 if ((q = old->multi_next) != NULL) {
1947                         ASSERT(q->multi_next == old);
1948                         q->multi_next = NULL;
1949                         old->multi_next = NULL;
1950                 }
1951 
1952                 rdc_many_exit(old);
1953                 return;
1954         }
1955 
1956         /* search */
1957         for (p = old->many_next; p->many_next != old; p = p->many_next)
1958         ;
1959 
1960         p->many_next = old->many_next;
1961         old->many_next = old;
1962 
1963         if ((q = old->multi_next) != NULL) {
1964                 /*
1965                  * old was part of a multihop, so switch multi pointers
1966                  * to someone remaining on the many chain
1967                  */
1968                 ASSERT(p->multi_next == NULL);
1969 
1970                 q->multi_next = p;
1971                 p->multi_next = q;
1972                 old->multi_next = NULL;
1973         }
1974 
1975 #ifdef DEBUG_MANY
1976         if (p == old) {
1977                 cmn_err(CE_NOTE, "!rdc: after remove_from_many empty");
1978         } else {
1979                 cmn_err(CE_NOTE, "!rdc: after remove_from_many");
1980                 print_many(p);
1981         }
1982 #endif
1983 
1984         rdc_clr_mflags(&rdc_u_info[p->index],
1985             (rdc_get_vflags(uold) & RDC_MFLAGS));
1986 
1987         rdc_many_exit(old);
1988 }
1989 
1990 
1991 static int
1992 _rdc_enable(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus)
1993 {
1994         int index;
1995         char *rhost;
1996         struct netbuf *addrp;
1997         rdc_k_info_t *krdc;
1998         rdc_u_info_t *urdc;
1999         rdc_srv_t *svp = NULL;
2000         char *local_file;
2001         char *local_bitmap;
2002         char *diskq;
2003         int rc;
2004         nsc_size_t maxfbas;
2005         rdc_group_t *grp;
2006 
2007         if ((rdc_set->primary.intf[0] == 0) ||
2008             (rdc_set->primary.addr.len == 0) ||
2009             (rdc_set->primary.file[0] == 0) ||
2010             (rdc_set->primary.bitmap[0] == 0) ||
2011             (rdc_set->secondary.intf[0] == 0) ||
2012             (rdc_set->secondary.addr.len == 0) ||
2013             (rdc_set->secondary.file[0] == 0) ||
2014             (rdc_set->secondary.bitmap[0] == 0)) {
2015                 spcs_s_add(kstatus, RDC_EEMPTY);
2016                 return (RDC_EEMPTY);
2017         }
2018 
2019         /* Next check there aren't any enabled rdc sets which match. */
2020 
2021         mutex_enter(&rdc_conf_lock);
2022 
2023         if (rdc_lookup_byname(rdc_set) >= 0) {
2024                 mutex_exit(&rdc_conf_lock);
2025                 spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf,
2026                     rdc_set->primary.file, rdc_set->secondary.intf,
2027                     rdc_set->secondary.file);
2028                 return (RDC_EENABLED);
2029         }
2030 
2031         if (rdc_lookup_many2one(rdc_set) >= 0) {
2032                 mutex_exit(&rdc_conf_lock);
2033                 spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf,
2034                     rdc_set->primary.file, rdc_set->secondary.intf,
2035                     rdc_set->secondary.file);
2036                 return (RDC_EMANY2ONE);
2037         }
2038 
2039         if (rdc_set->netconfig->knc_proto == NULL) {
2040                 mutex_exit(&rdc_conf_lock);
2041                 spcs_s_add(kstatus, RDC_ENETCONFIG);
2042                 return (RDC_ENETCONFIG);
2043         }
2044 
2045         if (rdc_set->primary.addr.len == 0) {
2046                 mutex_exit(&rdc_conf_lock);
2047                 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file);
2048                 return (RDC_ENETBUF);
2049         }
2050 
2051         if (rdc_set->secondary.addr.len == 0) {
2052                 mutex_exit(&rdc_conf_lock);
2053                 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file);
2054                 return (RDC_ENETBUF);
2055         }
2056 
2057         /* Check that the local data volume isn't in use as a bitmap */
2058         if (options & RDC_OPT_PRIMARY)
2059                 local_file = rdc_set->primary.file;
2060         else
2061                 local_file = rdc_set->secondary.file;
2062         if (rdc_lookup_bitmap(local_file) >= 0) {
2063                 mutex_exit(&rdc_conf_lock);
2064                 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
2065                 return (RDC_EVOLINUSE);
2066         }
2067 
2068         /* check that the secondary data volume isn't in use */
2069         if (!(options & RDC_OPT_PRIMARY)) {
2070                 local_file = rdc_set->secondary.file;
2071                 if (rdc_lookup_secondary(local_file) >= 0) {
2072                         mutex_exit(&rdc_conf_lock);
2073                         spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
2074                         return (RDC_EVOLINUSE);
2075                 }
2076         }
2077 
2078         /* check that the local data vol is not in use as a diskqueue */
2079         if (options & RDC_OPT_PRIMARY) {
2080                 if (rdc_lookup_diskq(rdc_set->primary.file) >= 0) {
2081                         mutex_exit(&rdc_conf_lock);
2082                         spcs_s_add(kstatus,
2083                             RDC_EVOLINUSE, rdc_set->primary.file);
2084                         return (RDC_EVOLINUSE);
2085                 }
2086         }
2087 
2088         /* Check that the bitmap isn't in use as a data volume */
2089         if (options & RDC_OPT_PRIMARY)
2090                 local_bitmap = rdc_set->primary.bitmap;
2091         else
2092                 local_bitmap = rdc_set->secondary.bitmap;
2093         if (rdc_lookup_configured(local_bitmap) >= 0) {
2094                 mutex_exit(&rdc_conf_lock);
2095                 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
2096                 return (RDC_EBMPINUSE);
2097         }
2098 
2099         /* Check that the bitmap isn't already in use as a bitmap */
2100         if (rdc_lookup_bitmap(local_bitmap) >= 0) {
2101                 mutex_exit(&rdc_conf_lock);
2102                 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
2103                 return (RDC_EBMPINUSE);
2104         }
2105 
2106         /* check that the diskq (if here) is not in use */
2107         diskq = rdc_set->disk_queue;
2108         if (diskq[0] && rdc_diskq_inuse(rdc_set, diskq)) {
2109                 mutex_exit(&rdc_conf_lock);
2110                 spcs_s_add(kstatus, RDC_EDISKQINUSE, diskq);
2111                 return (RDC_EDISKQINUSE);
2112         }
2113 
2114 
2115         /* Set urdc->volume_size */
2116         index = rdc_dev_open(rdc_set, options);
2117         if (index < 0) {
2118                 mutex_exit(&rdc_conf_lock);
2119                 if (options & RDC_OPT_PRIMARY)
2120                         spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf,
2121                             rdc_set->primary.file);
2122                 else
2123                         spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf,
2124                             rdc_set->secondary.file);
2125                 return (RDC_EOPEN);
2126         }
2127 
2128         urdc = &rdc_u_info[index];
2129         krdc = &rdc_k_info[index];
2130 
2131         /* copy relevant parts of rdc_set to urdc field by field */
2132 
2133         (void) strncpy(urdc->primary.intf, rdc_set->primary.intf,
2134             MAX_RDC_HOST_SIZE);
2135         (void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf,
2136             MAX_RDC_HOST_SIZE);
2137 
2138         (void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH);
2139         (void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH);
2140 
2141         dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr);
2142         (void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH);
2143         (void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap,
2144             NSC_MAXPATH);
2145 
2146         dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr);
2147         (void) strncpy(urdc->secondary.file, rdc_set->secondary.file,
2148             NSC_MAXPATH);
2149         (void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap,
2150             NSC_MAXPATH);
2151 
2152         urdc->setid = rdc_set->setid;
2153 
2154         /*
2155          * before we try to add to group, or create one, check out
2156          * if we are doing the wrong thing with the diskq
2157          */
2158 
2159         if (urdc->disk_queue[0] && (options & RDC_OPT_SYNC)) {
2160                 mutex_exit(&rdc_conf_lock);
2161                 rdc_dev_close(krdc);
2162                 spcs_s_add(kstatus, RDC_EQWRONGMODE);
2163                 return (RDC_EQWRONGMODE);
2164         }
2165 
2166         if ((rc = add_to_group(krdc, options, RDC_CMD_ENABLE)) != 0) {
2167                 mutex_exit(&rdc_conf_lock);
2168                 rdc_dev_close(krdc);
2169                 if (rc == RDC_EQNOADD) {
2170                         spcs_s_add(kstatus, RDC_EQNOADD, rdc_set->disk_queue);
2171                         return (RDC_EQNOADD);
2172                 } else {
2173                         spcs_s_add(kstatus, RDC_EGROUP,
2174                             rdc_set->primary.intf, rdc_set->primary.file,
2175                             rdc_set->secondary.intf, rdc_set->secondary.file,
2176                             rdc_set->group_name);
2177                         return (RDC_EGROUP);
2178                 }
2179         }
2180 
2181         /*
2182          * maxfbas was set in rdc_dev_open as primary's maxfbas.
2183          * If diskq's maxfbas is smaller, then use diskq's.
2184          */
2185         grp = krdc->group;
2186         if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) {
2187                 rc = _rdc_rsrv_diskq(grp);
2188                 if (RDC_SUCCESS(rc)) {
2189                         rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas);
2190                         if (rc == 0) {
2191 #ifdef DEBUG
2192                                 if (krdc->maxfbas != maxfbas)
2193                                         cmn_err(CE_NOTE,
2194                                             "!_rdc_enable: diskq maxfbas = %"
2195                                             NSC_SZFMT ", primary maxfbas = %"
2196                                             NSC_SZFMT, maxfbas, krdc->maxfbas);
2197 #endif
2198                                 krdc->maxfbas = min(krdc->maxfbas, maxfbas);
2199                         } else {
2200                                 cmn_err(CE_WARN,
2201                                     "!_rdc_enable: diskq maxfbas failed (%d)",
2202                                     rc);
2203                         }
2204                         _rdc_rlse_diskq(grp);
2205                 } else {
2206                         cmn_err(CE_WARN,
2207                             "!_rdc_enable: diskq reserve failed (%d)", rc);
2208                 }
2209         }
2210 
2211         rdc_init_flags(urdc);
2212         (void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH);
2213         if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) {
2214                 if (rdc_open_direct(krdc) == NULL)
2215                         rdc_set_flags(urdc, RDC_FCAL_FAILED);
2216         }
2217 
2218         krdc->many_next = krdc;
2219 
2220         ASSERT(krdc->type_flag == 0);
2221         krdc->type_flag = RDC_CONFIGURED;
2222 
2223         if (options & RDC_OPT_PRIMARY)
2224                 rdc_set_flags(urdc, RDC_PRIMARY);
2225 
2226         if (options & RDC_OPT_ASYNC)
2227                 krdc->type_flag |= RDC_ASYNCMODE;
2228 
2229         set_busy(krdc);
2230         urdc->syshostid = rdc_set->syshostid;
2231 
2232         if (add_to_many(krdc) < 0) {
2233                 mutex_exit(&rdc_conf_lock);
2234 
2235                 rdc_group_enter(krdc);
2236 
2237                 spcs_s_add(kstatus, RDC_EMULTI);
2238                 rc = RDC_EMULTI;
2239                 goto fail;
2240         }
2241 
2242         /* Configured but not enabled */
2243         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2244 
2245         mutex_exit(&rdc_conf_lock);
2246 
2247         rdc_group_enter(krdc);
2248 
2249         /* Configured but not enabled */
2250         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2251 
2252         /*
2253          * The rdc set is configured but not yet enabled. Other operations must
2254          * ignore this set until it is enabled.
2255          */
2256 
2257         urdc->sync_pos = 0;
2258 
2259         if (rdc_set->maxqfbas > 0)
2260                 urdc->maxqfbas = rdc_set->maxqfbas;
2261         else
2262                 urdc->maxqfbas = rdc_maxthres_queue;
2263 
2264         if (rdc_set->maxqitems > 0)
2265                 urdc->maxqitems = rdc_set->maxqitems;
2266         else
2267                 urdc->maxqitems = rdc_max_qitems;
2268 
2269         if (rdc_set->asyncthr > 0)
2270                 urdc->asyncthr = rdc_set->asyncthr;
2271         else
2272                 urdc->asyncthr = rdc_asyncthr;
2273 
2274         if (urdc->autosync == -1) {
2275                 /* Still unknown */
2276                 if (rdc_set->autosync > 0)
2277                         urdc->autosync = 1;
2278                 else
2279                         urdc->autosync = 0;
2280         }
2281 
2282         urdc->netconfig = rdc_set->netconfig;
2283 
2284         if (options & RDC_OPT_PRIMARY) {
2285                 rhost = rdc_set->secondary.intf;
2286                 addrp = &rdc_set->secondary.addr;
2287         } else {
2288                 rhost = rdc_set->primary.intf;
2289                 addrp = &rdc_set->primary.addr;
2290         }
2291 
2292         if (options & RDC_OPT_ASYNC)
2293                 rdc_set_flags(urdc, RDC_ASYNC);
2294 
2295         svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig);
2296         if (svp == NULL) {
2297                 spcs_s_add(kstatus, ENOMEM);
2298                 rc = ENOMEM;
2299                 goto fail;
2300         }
2301         urdc->netconfig = NULL;              /* This will be no good soon */
2302 
2303         rdc_kstat_create(index);
2304 
2305         /* Don't set krdc->intf here */
2306 
2307         if (rdc_enable_bitmap(krdc, options & RDC_OPT_SETBMP) < 0)
2308                 goto bmpfail;
2309 
2310         RDC_ZERO_BITREF(krdc);
2311         if (krdc->lsrv == NULL)
2312                 krdc->lsrv = svp;
2313         else {
2314 #ifdef DEBUG
2315                 cmn_err(CE_WARN, "!_rdc_enable: krdc->lsrv already set: %p",
2316                     (void *) krdc->lsrv);
2317 #endif
2318                 rdc_destroy_svinfo(svp);
2319         }
2320         svp = NULL;
2321 
2322         /* Configured but not enabled */
2323         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2324 
2325         /* And finally */
2326 
2327         krdc->remote_index = -1;
2328         /* Should we set the whole group logging? */
2329         rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING);
2330 
2331         rdc_group_exit(krdc);
2332 
2333         if (rdc_intercept(krdc) != 0) {
2334                 rdc_group_enter(krdc);
2335                 rdc_clr_flags(urdc, RDC_ENABLED);
2336                 if (options & RDC_OPT_PRIMARY)
2337                         spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file);
2338                 else
2339                         spcs_s_add(kstatus, RDC_EREGISTER,
2340                             urdc->secondary.file);
2341 #ifdef DEBUG
2342                 cmn_err(CE_NOTE, "!nsc_register_path failed %s",
2343                     urdc->primary.file);
2344 #endif
2345                 rc = RDC_EREGISTER;
2346                 goto bmpfail;
2347         }
2348 #ifdef DEBUG
2349         cmn_err(CE_NOTE, "!SNDR: enabled %s %s", urdc->primary.file,
2350             urdc->secondary.file);
2351 #endif
2352 
2353         rdc_write_state(urdc);
2354 
2355         mutex_enter(&rdc_conf_lock);
2356         wakeup_busy(krdc);
2357         mutex_exit(&rdc_conf_lock);
2358 
2359         return (0);
2360 
2361 bmpfail:
2362         if (options & RDC_OPT_PRIMARY)
2363                 spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->primary.bitmap);
2364         else
2365                 spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->secondary.bitmap);
2366         rc = RDC_EBITMAP;
2367         if (rdc_get_vflags(urdc) & RDC_ENABLED) {
2368                 rdc_group_exit(krdc);
2369                 (void) rdc_unintercept(krdc);
2370                 rdc_group_enter(krdc);
2371         }
2372 
2373 fail:
2374         rdc_kstat_delete(index);
2375         rdc_group_exit(krdc);
2376         if (krdc->intf) {
2377                 rdc_if_t *ip = krdc->intf;
2378                 mutex_enter(&rdc_conf_lock);
2379                 krdc->intf = NULL;
2380                 rdc_remove_from_if(ip);
2381                 mutex_exit(&rdc_conf_lock);
2382         }
2383         rdc_group_enter(krdc);
2384         /* Configured but not enabled */
2385         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2386 
2387         rdc_dev_close(krdc);
2388         rdc_close_direct(krdc);
2389         rdc_destroy_svinfo(svp);
2390 
2391         /* Configured but not enabled */
2392         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2393 
2394         rdc_group_exit(krdc);
2395 
2396         mutex_enter(&rdc_conf_lock);
2397 
2398         /* Configured but not enabled */
2399         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2400 
2401         remove_from_group(krdc);
2402 
2403         if (IS_MANY(krdc) || IS_MULTI(krdc))
2404                 remove_from_many(krdc);
2405 
2406         rdc_u_init(urdc);
2407 
2408         ASSERT(krdc->type_flag & RDC_CONFIGURED);
2409         krdc->type_flag = 0;
2410         wakeup_busy(krdc);
2411 
2412         mutex_exit(&rdc_conf_lock);
2413 
2414         return (rc);
2415 }
2416 
2417 static int
2418 rdc_enable(rdc_config_t *uparms, spcs_s_info_t kstatus)
2419 {
2420         int rc;
2421         char itmp[10];
2422 
2423         if (!(uparms->options & RDC_OPT_SYNC) &&
2424             !(uparms->options & RDC_OPT_ASYNC)) {
2425                 rc = RDC_EEINVAL;
2426                 (void) spcs_s_inttostring(
2427                     uparms->options, itmp, sizeof (itmp), 1);
2428                 spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2429                 goto done;
2430         }
2431 
2432         if (!(uparms->options & RDC_OPT_PRIMARY) &&
2433             !(uparms->options & RDC_OPT_SECONDARY)) {
2434                 rc = RDC_EEINVAL;
2435                 (void) spcs_s_inttostring(
2436                     uparms->options, itmp, sizeof (itmp), 1);
2437                 spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2438                 goto done;
2439         }
2440 
2441         if (!(uparms->options & RDC_OPT_SETBMP) &&
2442             !(uparms->options & RDC_OPT_CLRBMP)) {
2443                 rc = RDC_EEINVAL;
2444                 (void) spcs_s_inttostring(
2445                     uparms->options, itmp, sizeof (itmp), 1);
2446                 spcs_s_add(kstatus, RDC_EEINVAL, itmp);
2447                 goto done;
2448         }
2449 
2450         rc = _rdc_enable(uparms->rdc_set, uparms->options, kstatus);
2451 done:
2452         return (rc);
2453 }
2454 
2455 /* ARGSUSED */
2456 static int
2457 _rdc_disable(rdc_k_info_t *krdc, rdc_config_t *uap, spcs_s_info_t kstatus)
2458 {
2459         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2460         rdc_if_t *ip;
2461         int index = krdc->index;
2462         disk_queue *q;
2463         rdc_set_t *rdc_set = uap->rdc_set;
2464 
2465         ASSERT(krdc->group != NULL);
2466         rdc_group_enter(krdc);
2467 #ifdef DEBUG
2468         ASSERT(rdc_check(krdc, rdc_set) == 0);
2469 #else
2470         if (((uap->options & RDC_OPT_FORCE_DISABLE) == 0) &&
2471             rdc_check(krdc, rdc_set)) {
2472                 rdc_group_exit(krdc);
2473                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
2474                     rdc_set->secondary.file);
2475                 return (RDC_EALREADY);
2476         }
2477 #endif
2478 
2479         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
2480                 halt_sync(krdc);
2481                 ASSERT(IS_ENABLED(urdc));
2482         }
2483         q = &krdc->group->diskq;
2484 
2485         if (IS_ASYNC(urdc) && RDC_IS_DISKQ(krdc->group) &&
2486             ((!IS_STATE(urdc, RDC_LOGGING)) && (!QEMPTY(q)))) {
2487                 krdc->type_flag &= ~RDC_DISABLEPEND;
2488                 rdc_group_exit(krdc);
2489                 spcs_s_add(kstatus, RDC_EQNOTEMPTY, urdc->disk_queue);
2490                 return (RDC_EQNOTEMPTY);
2491         }
2492         rdc_group_exit(krdc);
2493         (void) rdc_unintercept(krdc);
2494 
2495 #ifdef DEBUG
2496         cmn_err(CE_NOTE, "!SNDR: disabled %s %s", urdc->primary.file,
2497             urdc->secondary.file);
2498 #endif
2499 
2500         /* Configured but not enabled */
2501         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2502 
2503         /*
2504          * No new io can come in through the io provider.
2505          * Wait for the async flusher to finish.
2506          */
2507 
2508         if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) {
2509                 int tries = 2; /* in case of hopelessly stuck flusher threads */
2510 #ifdef DEBUG
2511                 net_queue *qp = &krdc->group->ra_queue;
2512 #endif
2513                 do {
2514                         if (!krdc->group->rdc_writer)
2515                                 (void) rdc_writer(krdc->index);
2516 
2517                         (void) rdc_drain_queue(krdc->index);
2518 
2519                 } while (krdc->group->rdc_writer && tries--);
2520 
2521                 /* ok, force it to happen... */
2522                 if (rdc_drain_queue(krdc->index) != 0) {
2523                         do {
2524                                 mutex_enter(&krdc->group->ra_queue.net_qlock);
2525                                 krdc->group->asyncdis = 1;
2526                                 cv_broadcast(&krdc->group->asyncqcv);
2527                                 mutex_exit(&krdc->group->ra_queue.net_qlock);
2528                                 cmn_err(CE_WARN,
2529                                     "!SNDR: async I/O pending and not flushed "
2530                                     "for %s during disable",
2531                                     urdc->primary.file);
2532 #ifdef DEBUG
2533                                 cmn_err(CE_WARN,
2534                                     "!nitems: %" NSC_SZFMT " nblocks: %"
2535                                     NSC_SZFMT " head: 0x%p tail: 0x%p",
2536                                     qp->nitems, qp->blocks,
2537                                     (void *)qp->net_qhead,
2538                                     (void *)qp->net_qtail);
2539 #endif
2540                         } while (krdc->group->rdc_thrnum > 0);
2541                 }
2542         }
2543 
2544         mutex_enter(&rdc_conf_lock);
2545         ip = krdc->intf;
2546         krdc->intf = 0;
2547 
2548         if (ip) {
2549                 rdc_remove_from_if(ip);
2550         }
2551 
2552         mutex_exit(&rdc_conf_lock);
2553 
2554         rdc_group_enter(krdc);
2555 
2556         /* Configured but not enabled */
2557         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2558 
2559         /* Must not hold group lock during this function */
2560         rdc_group_exit(krdc);
2561         while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
2562                 delay(2);
2563         rdc_group_enter(krdc);
2564 
2565         (void) rdc_clear_state(krdc);
2566 
2567         rdc_free_bitmap(krdc, RDC_CMD_DISABLE);
2568         rdc_close_bitmap(krdc);
2569 
2570         rdc_dev_close(krdc);
2571         rdc_close_direct(krdc);
2572 
2573         /* Configured but not enabled */
2574         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2575 
2576         rdc_group_exit(krdc);
2577 
2578         /*
2579          * we should now unregister the queue, with no conflicting
2580          * locks held. This is the last(only) member of the group
2581          */
2582         if (krdc->group && RDC_IS_DISKQ(krdc->group) &&
2583             krdc->group->count == 1) { /* stop protecting queue */
2584                 rdc_unintercept_diskq(krdc->group);
2585         }
2586 
2587         mutex_enter(&rdc_conf_lock);
2588 
2589         /* Configured but not enabled */
2590         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
2591 
2592         wait_busy(krdc);
2593 
2594         if (IS_MANY(krdc) || IS_MULTI(krdc))
2595                 remove_from_many(krdc);
2596 
2597         remove_from_group(krdc);
2598 
2599         krdc->remote_index = -1;
2600         ASSERT(krdc->type_flag & RDC_CONFIGURED);
2601         ASSERT(krdc->type_flag & RDC_DISABLEPEND);
2602         krdc->type_flag = 0;
2603 #ifdef  DEBUG
2604         if (krdc->dcio_bitmap)
2605                 cmn_err(CE_WARN, "!_rdc_disable: possible mem leak, "
2606                     "dcio_bitmap");
2607 #endif
2608         krdc->dcio_bitmap = NULL;
2609         krdc->bitmap_ref = NULL;
2610         krdc->bitmap_size = 0;
2611         krdc->maxfbas = 0;
2612         krdc->bitmap_write = 0;
2613         krdc->disk_status = 0;
2614         rdc_destroy_svinfo(krdc->lsrv);
2615         krdc->lsrv = NULL;
2616         krdc->multi_next = NULL;
2617 
2618         rdc_u_init(urdc);
2619 
2620         mutex_exit(&rdc_conf_lock);
2621         rdc_kstat_delete(index);
2622 
2623         return (0);
2624 }
2625 
2626 static int
2627 rdc_disable(rdc_config_t *uparms, spcs_s_info_t kstatus)
2628 {
2629         rdc_k_info_t *krdc;
2630         int index;
2631         int rc;
2632 
2633         mutex_enter(&rdc_conf_lock);
2634 
2635         index = rdc_lookup_byname(uparms->rdc_set);
2636         if (index >= 0)
2637                 krdc = &rdc_k_info[index];
2638         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
2639                 mutex_exit(&rdc_conf_lock);
2640                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
2641                     uparms->rdc_set->secondary.file);
2642                 return (RDC_EALREADY);
2643         }
2644 
2645         krdc->type_flag |= RDC_DISABLEPEND;
2646         wait_busy(krdc);
2647         if (krdc->type_flag == 0) {
2648                 /* A resume or enable failed */
2649                 mutex_exit(&rdc_conf_lock);
2650                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
2651                     uparms->rdc_set->secondary.file);
2652                 return (RDC_EALREADY);
2653         }
2654         mutex_exit(&rdc_conf_lock);
2655 
2656         rc = _rdc_disable(krdc, uparms, kstatus);
2657         return (rc);
2658 }
2659 
2660 
2661 /*
2662  * Checks whether the state of one of the other sets in the 1-many or
2663  * multi-hop config should prevent a sync from starting on this one.
2664  * Return NULL if no just cause or impediment is found, otherwise return
2665  * a pointer to the offending set.
2666  */
2667 static rdc_u_info_t *
2668 rdc_allow_pri_sync(rdc_u_info_t *urdc, int options)
2669 {
2670         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
2671         rdc_k_info_t *ktmp;
2672         rdc_u_info_t *utmp;
2673         rdc_k_info_t *kmulti = NULL;
2674 
2675         ASSERT(rdc_get_vflags(urdc) & RDC_PRIMARY);
2676 
2677         rdc_many_enter(krdc);
2678 
2679         /*
2680          * In the reverse sync case we need to check the previous leg of
2681          * the multi-hop config. The link to that set can be from any of
2682          * the 1-many list, so as we go through we keep an eye open for it.
2683          */
2684         if ((options & RDC_OPT_REVERSE) && (IS_MULTI(krdc))) {
2685                 /* This set links to the first leg */
2686                 ktmp = krdc->multi_next;
2687                 utmp = &rdc_u_info[ktmp->index];
2688                 if (IS_ENABLED(utmp))
2689                         kmulti = ktmp;
2690         }
2691 
2692         if (IS_MANY(krdc)) {
2693                 for (ktmp = krdc->many_next; ktmp != krdc;
2694                     ktmp = ktmp->many_next) {
2695                         utmp = &rdc_u_info[ktmp->index];
2696 
2697                         if (!IS_ENABLED(utmp))
2698                                 continue;
2699 
2700                         if (options & RDC_OPT_FORWARD) {
2701                                 /*
2702                                  * Reverse sync needed is bad, as it means a
2703                                  * reverse sync in progress or started and
2704                                  * didn't complete, so this primary volume
2705                                  * is not consistent. So we shouldn't copy
2706                                  * it to its secondary.
2707                                  */
2708                                 if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) {
2709                                         rdc_many_exit(krdc);
2710                                         return (utmp);
2711                                 }
2712                         } else {
2713                                 /* Reverse, so see if we need to spot kmulti */
2714                                 if ((kmulti == NULL) && (IS_MULTI(ktmp))) {
2715                                         /* This set links to the first leg */
2716                                         kmulti = ktmp->multi_next;
2717                                         if (!IS_ENABLED(
2718                                             &rdc_u_info[kmulti->index]))
2719                                                 kmulti = NULL;
2720                                 }
2721 
2722                                 /*
2723                                  * Non-logging is bad, as the bitmap will
2724                                  * be updated with the bits for this sync.
2725                                  */
2726                                 if (!(rdc_get_vflags(utmp) & RDC_LOGGING)) {
2727                                         rdc_many_exit(krdc);
2728                                         return (utmp);
2729                                 }
2730                         }
2731                 }
2732         }
2733 
2734         if (kmulti) {
2735                 utmp = &rdc_u_info[kmulti->index];
2736                 ktmp = kmulti;  /* In case we decide we do need to use ktmp */
2737 
2738                 ASSERT(options & RDC_OPT_REVERSE);
2739 
2740                 if (IS_REPLICATING(utmp)) {
2741                         /*
2742                          * Replicating is bad as data is already flowing to
2743                          * the target of the requested sync operation.
2744                          */
2745                         rdc_many_exit(krdc);
2746                         return (utmp);
2747                 }
2748 
2749                 if (rdc_get_vflags(utmp) & RDC_SYNCING) {
2750                         /*
2751                          * Forward sync in progress is bad, as data is
2752                          * already flowing to the target of the requested
2753                          * sync operation.
2754                          * Reverse sync in progress is bad, as the primary
2755                          * has already decided which data to copy.
2756                          */
2757                         rdc_many_exit(krdc);
2758                         return (utmp);
2759                 }
2760 
2761                 /*
2762                  * Clear the "sync needed" flags, as the multi-hop secondary
2763                  * will be updated via this requested sync operation, so does
2764                  * not need to complete its aborted forward sync.
2765                  */
2766                 if (rdc_get_vflags(utmp) & RDC_SYNC_NEEDED)
2767                         rdc_clr_flags(utmp, RDC_SYNC_NEEDED);
2768         }
2769 
2770         if (IS_MANY(krdc) && (options & RDC_OPT_REVERSE)) {
2771                 for (ktmp = krdc->many_next; ktmp != krdc;
2772                     ktmp = ktmp->many_next) {
2773                         utmp = &rdc_u_info[ktmp->index];
2774                         if (!IS_ENABLED(utmp))
2775                                 continue;
2776 
2777                         /*
2778                          * Clear any "reverse sync needed" flags, as the
2779                          * volume will be updated via this requested
2780                          * sync operation, so does not need to complete
2781                          * its aborted reverse sync.
2782                          */
2783                         if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED)
2784                                 rdc_clr_mflags(utmp, RDC_RSYNC_NEEDED);
2785                 }
2786         }
2787 
2788         rdc_many_exit(krdc);
2789 
2790         return (NULL);
2791 }
2792 
2793 static void
2794 _rdc_sync_wrthr(void *thrinfo)
2795 {
2796         rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2797         nsc_buf_t *handle = NULL;
2798         rdc_k_info_t *krdc = syncinfo->krdc;
2799         int rc;
2800         int tries = 0;
2801 
2802         DTRACE_PROBE2(rdc_sync_loop_netwrite_start, int, krdc->index,
2803             nsc_buf_t *, handle);
2804 
2805 retry:
2806         rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len,
2807             NSC_READ | NSC_NOCACHE, &handle);
2808 
2809         if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) {
2810                 DTRACE_PROBE(rdc_sync_wrthr_alloc_buf_err);
2811                 goto failed;
2812         }
2813 
2814         rdc_group_enter(krdc);
2815         if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) {
2816                 rdc_group_exit(krdc);
2817                 goto failed;
2818         }
2819         rdc_group_exit(krdc);
2820 
2821         if ((rc = rdc_net_write(krdc->index, krdc->remote_index, handle,
2822             handle->sb_pos, handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) {
2823                 rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2824 
2825                 /*
2826                  * The following is to handle
2827                  * the case where the secondary side
2828                  * has thrown our buffer handle token away in a
2829                  * attempt to preserve its health on restart
2830                  */
2831                 if ((rc == EPROTO) && (tries < 3)) {
2832                         (void) nsc_free_buf(handle);
2833                         handle = NULL;
2834                         tries++;
2835                         delay(HZ >> 2);
2836                         goto retry;
2837                 }
2838 
2839                 DTRACE_PROBE(rdc_sync_wrthr_remote_write_err);
2840                 cmn_err(CE_WARN, "!rdc_sync_wrthr: remote write failed (%d) "
2841                     "0x%x", rc, rdc_get_vflags(urdc));
2842 
2843                 goto failed;
2844         }
2845         (void) nsc_free_buf(handle);
2846         handle = NULL;
2847 
2848         return;
2849 failed:
2850         (void) nsc_free_buf(handle);
2851         syncinfo->status->offset = syncinfo->offset;
2852 }
2853 
2854 /*
2855  * see above comments on _rdc_sync_wrthr
2856  */
2857 static void
2858 _rdc_sync_rdthr(void *thrinfo)
2859 {
2860         rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2861         nsc_buf_t *handle = NULL;
2862         rdc_k_info_t *krdc = syncinfo->krdc;
2863         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2864         int rc;
2865 
2866         rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len,
2867             NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle);
2868 
2869         if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) {
2870                 goto failed;
2871         }
2872         rdc_group_enter(krdc);
2873         if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) {
2874                 rdc_group_exit(krdc);
2875                 goto failed;
2876         }
2877         rdc_group_exit(krdc);
2878 
2879         rc = rdc_net_read(krdc->index, krdc->remote_index, handle,
2880             handle->sb_pos, handle->sb_len);
2881 
2882         if (!RDC_SUCCESS(rc)) {
2883                 cmn_err(CE_WARN, "!rdc_sync_rdthr: remote read failed(%d)", rc);
2884                 goto failed;
2885         }
2886         if (!IS_STATE(urdc, RDC_FULL))
2887                 rdc_set_bitmap_many(krdc, handle->sb_pos, handle->sb_len);
2888 
2889         rc = nsc_write(handle, handle->sb_pos, handle->sb_len, 0);
2890 
2891         if (!RDC_SUCCESS(rc)) {
2892                 rdc_many_enter(krdc);
2893                 rdc_set_flags_log(urdc, RDC_VOL_FAILED, "nsc_write failed");
2894                 rdc_many_exit(krdc);
2895                 rdc_write_state(urdc);
2896                 goto failed;
2897         }
2898 
2899         (void) nsc_free_buf(handle);
2900         handle = NULL;
2901 
2902         return;
2903 failed:
2904         (void) nsc_free_buf(handle);
2905         syncinfo->status->offset = syncinfo->offset;
2906 }
2907 
2908 /*
2909  * _rdc_sync_wrthr
2910  * sync loop write thread
2911  * if there are avail threads, we have not
2912  * used up the pipe, so the sync loop will, if
2913  * possible use these to multithread the write/read
2914  */
2915 void
2916 _rdc_sync_thread(void *thrinfo)
2917 {
2918         rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo;
2919         rdc_k_info_t *krdc = syncinfo->krdc;
2920         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
2921         rdc_thrsync_t *sync = &krdc->syncs;
2922         uint_t bitmask;
2923         int rc;
2924 
2925         rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL);
2926         if (!RDC_SUCCESS(rc))
2927                 goto failed;
2928 
2929         if (IS_STATE(urdc, RDC_SLAVE))
2930                 _rdc_sync_rdthr(thrinfo);
2931         else
2932                 _rdc_sync_wrthr(thrinfo);
2933 
2934         _rdc_rlse_devs(krdc, RDC_RAW);
2935 
2936         if (krdc->dcio_bitmap == NULL) {
2937 #ifdef DEBUG
2938                 cmn_err(CE_NOTE, "!_rdc_sync_wrthr: NULL bitmap");
2939 #else
2940         /*EMPTY*/
2941 #endif
2942         } else if (syncinfo->status->offset < 0) {
2943 
2944                 RDC_SET_BITMASK(syncinfo->offset, syncinfo->len, &bitmask);
2945                 RDC_CLR_BITMAP(krdc, syncinfo->offset, syncinfo->len, \
2946                     bitmask, RDC_BIT_FORCE);
2947         }
2948 
2949 failed:
2950         /*
2951          * done with this, get rid of it.
2952          * the status is not freed, it should still be a status chain
2953          * that _rdc_sync() has the head of
2954          */
2955         kmem_free(syncinfo, sizeof (*syncinfo));
2956 
2957         /*
2958          * decrement the global sync thread num
2959          */
2960         mutex_enter(&sync_info.lock);
2961         sync_info.active_thr--;
2962         /* LINTED */
2963         RDC_AVAIL_THR_TUNE(sync_info);
2964         mutex_exit(&sync_info.lock);
2965 
2966         /*
2967          * krdc specific stuff
2968          */
2969         mutex_enter(&sync->lock);
2970         sync->complete++;
2971         cv_broadcast(&sync->cv);
2972         mutex_exit(&sync->lock);
2973 }
2974 
2975 int
2976 _rdc_setup_syncthr(rdc_syncthr_t **synthr, nsc_off_t offset,
2977     nsc_size_t len, rdc_k_info_t *krdc, sync_status_t *stats)
2978 {
2979         rdc_syncthr_t *tmp;
2980         /* alloc here, free in the sync thread */
2981         tmp =
2982             (rdc_syncthr_t *)kmem_zalloc(sizeof (rdc_syncthr_t), KM_NOSLEEP);
2983 
2984         if (tmp == NULL)
2985                 return (-1);
2986         tmp->offset = offset;
2987         tmp->len = len;
2988         tmp->status = stats;
2989         tmp->krdc = krdc;
2990 
2991         *synthr = tmp;
2992         return (0);
2993 }
2994 
2995 sync_status_t *
2996 _rdc_new_sync_status()
2997 {
2998         sync_status_t *s;
2999 
3000         s = (sync_status_t *)kmem_zalloc(sizeof (*s), KM_NOSLEEP);
3001         s->offset = -1;
3002         return (s);
3003 }
3004 
3005 void
3006 _rdc_free_sync_status(sync_status_t *status)
3007 {
3008         sync_status_t *s;
3009 
3010         while (status) {
3011                 s = status->next;
3012                 kmem_free(status, sizeof (*status));
3013                 status = s;
3014         }
3015 }
3016 int
3017 _rdc_sync_status_ok(sync_status_t *status, int *offset)
3018 {
3019 #ifdef DEBUG_SYNCSTATUS
3020         int i = 0;
3021 #endif
3022         while (status) {
3023                 if (status->offset >= 0) {
3024                         *offset = status->offset;
3025                         return (-1);
3026                 }
3027                 status = status->next;
3028 #ifdef DEBUG_SYNCSTATUS
3029                 i++;
3030 #endif
3031         }
3032 #ifdef DEBUGSYNCSTATUS
3033         cmn_err(CE_NOTE, "!rdc_sync_status_ok: checked %d statuses", i);
3034 #endif
3035         return (0);
3036 }
3037 
3038 int mtsync = 1;
3039 /*
3040  * _rdc_sync() : rdc sync loop
3041  *
3042  */
3043 static void
3044 _rdc_sync(rdc_k_info_t *krdc)
3045 {
3046         nsc_size_t size = 0;
3047         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
3048         int rtype;
3049         int sts;
3050         int reserved = 0;
3051         nsc_buf_t *alloc_h = NULL;
3052         nsc_buf_t *handle = NULL;
3053         nsc_off_t mask;
3054         nsc_size_t maxbit;
3055         nsc_size_t len;
3056         nsc_off_t offset = 0;
3057         int sync_completed = 0;
3058         int tries = 0;
3059         int rc;
3060         int queuing = 0;
3061         uint_t bitmask;
3062         sync_status_t *ss, *sync_status = NULL;
3063         rdc_thrsync_t *sync = &krdc->syncs;
3064         rdc_syncthr_t *syncinfo;
3065         nsthread_t *trc = NULL;
3066 
3067         if (IS_STATE(urdc, RDC_QUEUING) && !IS_STATE(urdc, RDC_FULL)) {
3068                 /* flusher is handling the sync in the update case */
3069                 queuing = 1;
3070                 goto sync_done;
3071         }
3072 
3073         /*
3074          * Main sync/resync loop
3075          */
3076         DTRACE_PROBE(rdc_sync_loop_start);
3077 
3078         rtype = RDC_RAW;
3079         sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
3080 
3081         DTRACE_PROBE(rdc_sync_loop_rsrv);
3082 
3083         if (sts != 0)
3084                 goto failed_noincr;
3085 
3086         reserved = 1;
3087 
3088         /*
3089          * pre-allocate a handle if we can - speeds up the sync.
3090          */
3091 
3092         if (rdc_prealloc_handle) {
3093                 alloc_h = nsc_alloc_handle(RDC_U_FD(krdc), NULL, NULL, NULL);
3094 #ifdef DEBUG
3095                 if (!alloc_h) {
3096                         cmn_err(CE_WARN,
3097                             "!rdc sync: failed to pre-alloc handle");
3098                 }
3099 #endif
3100         } else {
3101                 alloc_h = NULL;
3102         }
3103 
3104         ASSERT(urdc->volume_size != 0);
3105         size = urdc->volume_size;
3106         mask = ~(LOG_TO_FBA_NUM(1) - 1);
3107         maxbit = FBA_TO_LOG_NUM(size - 1);
3108 
3109         /*
3110          * as this while loop can also move data, it is counted as a
3111          * sync loop thread
3112          */
3113         rdc_group_enter(krdc);
3114         rdc_clr_flags(urdc, RDC_LOGGING);
3115         rdc_set_flags(urdc, RDC_SYNCING);
3116         krdc->group->synccount++;
3117         rdc_group_exit(krdc);
3118         mutex_enter(&sync_info.lock);
3119         sync_info.active_thr++;
3120         /* LINTED */
3121         RDC_AVAIL_THR_TUNE(sync_info);
3122         mutex_exit(&sync_info.lock);
3123 
3124         while (offset < size) {
3125                 rdc_group_enter(krdc);
3126                 ASSERT(krdc->aux_state & RDC_AUXSYNCIP);
3127                 if (krdc->disk_status == 1 || krdc->dcio_bitmap == NULL) {
3128                         rdc_group_exit(krdc);
3129                         if (krdc->disk_status == 1) {
3130                                 DTRACE_PROBE(rdc_sync_loop_disk_status_err);
3131                         } else {
3132                                 DTRACE_PROBE(rdc_sync_loop_dcio_bitmap_err);
3133                         }
3134                         goto failed;            /* halt sync */
3135                 }
3136                 rdc_group_exit(krdc);
3137 
3138                 if (!(rdc_get_vflags(urdc) & RDC_FULL)) {
3139                         mutex_enter(&krdc->syncbitmutex);
3140                         krdc->syncbitpos = FBA_TO_LOG_NUM(offset);
3141                         len = 0;
3142 
3143                         /* skip unnecessary chunks */
3144 
3145                         while (krdc->syncbitpos <= maxbit &&
3146                             !RDC_BIT_ISSET(krdc, krdc->syncbitpos)) {
3147                                 offset += LOG_TO_FBA_NUM(1);
3148                                 krdc->syncbitpos++;
3149                         }
3150 
3151                         /* check for boundary */
3152 
3153                         if (offset >= size) {
3154                                 mutex_exit(&krdc->syncbitmutex);
3155                                 goto sync_done;
3156                         }
3157 
3158                         /* find maximal length we can transfer */
3159 
3160                         while (krdc->syncbitpos <= maxbit &&
3161                             RDC_BIT_ISSET(krdc, krdc->syncbitpos)) {
3162                                 len += LOG_TO_FBA_NUM(1);
3163                                 krdc->syncbitpos++;
3164                                 /* we can only read maxfbas anyways */
3165                                 if (len >= krdc->maxfbas)
3166                                         break;
3167                         }
3168 
3169                         len = min(len, (size - offset));
3170 
3171                 } else {
3172                         len = size - offset;
3173                 }
3174 
3175                 /* truncate to the io provider limit */
3176                 ASSERT(krdc->maxfbas != 0);
3177                 len = min(len, krdc->maxfbas);
3178 
3179                 if (len > LOG_TO_FBA_NUM(1)) {
3180                         /*
3181                          * If the update is larger than a bitmap chunk,
3182                          * then truncate to a whole number of bitmap
3183                          * chunks.
3184                          *
3185                          * If the update is smaller than a bitmap
3186                          * chunk, this must be the last write.
3187                          */
3188                         len &= mask;
3189                 }
3190 
3191                 if (!(rdc_get_vflags(urdc) & RDC_FULL)) {
3192                         krdc->syncbitpos = FBA_TO_LOG_NUM(offset + len);
3193                         mutex_exit(&krdc->syncbitmutex);
3194                 }
3195 
3196                 /*
3197                  * Find out if we can reserve a thread here ...
3198                  * note: skip the mutex for the first check, if the number
3199                  * is up there, why bother even grabbing the mutex to
3200                  * only realize that we can't have a thread anyways
3201                  */
3202 
3203                 if (mtsync && sync_info.active_thr < RDC_MAX_SYNC_THREADS) {
3204 
3205                         mutex_enter(&sync_info.lock);
3206                         if (sync_info.avail_thr >= 1) {
3207                                 if (sync_status == NULL) {
3208                                         ss = sync_status =
3209                                             _rdc_new_sync_status();
3210                                 } else {
3211                                         ss = ss->next = _rdc_new_sync_status();
3212                                 }
3213                                 if (ss == NULL) {
3214                                         mutex_exit(&sync_info.lock);
3215 #ifdef DEBUG
3216                                         cmn_err(CE_WARN, "!rdc_sync: can't "
3217                                             "allocate status for mt sync");
3218 #endif
3219                                         goto retry;
3220                                 }
3221                                 /*
3222                                  * syncinfo protected by sync_info lock but
3223                                  * not part of the sync_info structure
3224                                  * be careful if moving
3225                                  */
3226                                 if (_rdc_setup_syncthr(&syncinfo,
3227                                     offset, len, krdc, ss) < 0) {
3228                                         _rdc_free_sync_status(ss);
3229                                 }
3230 
3231                                 trc = nst_create(sync_info.rdc_syncset,
3232                                     _rdc_sync_thread, syncinfo, NST_SLEEP);
3233 
3234                                 if (trc == NULL) {
3235                                         mutex_exit(&sync_info.lock);
3236 #ifdef DEBUG
3237                                         cmn_err(CE_NOTE, "!rdc_sync: unable to "
3238                                             "mt sync");
3239 #endif
3240                                         _rdc_free_sync_status(ss);
3241                                         kmem_free(syncinfo, sizeof (*syncinfo));
3242                                         syncinfo = NULL;
3243                                         goto retry;
3244                                 } else {
3245                                         mutex_enter(&sync->lock);
3246                                         sync->threads++;
3247                                         mutex_exit(&sync->lock);
3248                                 }
3249 
3250                                 sync_info.active_thr++;
3251                                 /* LINTED */
3252                                 RDC_AVAIL_THR_TUNE(sync_info);
3253 
3254                                 mutex_exit(&sync_info.lock);
3255                                 goto threaded;
3256                         }
3257                         mutex_exit(&sync_info.lock);
3258                 }
3259 retry:
3260                 handle = alloc_h;
3261                 DTRACE_PROBE(rdc_sync_loop_allocbuf_start);
3262                 if (rdc_get_vflags(urdc) & RDC_SLAVE)
3263                         sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len,
3264                             NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle);
3265                 else
3266                         sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len,
3267                             NSC_READ | NSC_NOCACHE, &handle);
3268 
3269                 DTRACE_PROBE(rdc_sync_loop_allocbuf_end);
3270                 if (sts > 0) {
3271                         if (handle && handle != alloc_h) {
3272                                 (void) nsc_free_buf(handle);
3273                         }
3274 
3275                         handle = NULL;
3276                         DTRACE_PROBE(rdc_sync_loop_allocbuf_err);
3277                         goto failed;
3278                 }
3279 
3280                 if (rdc_get_vflags(urdc) & RDC_SLAVE) {
3281                         /* overwrite buffer with remote data */
3282                         sts = rdc_net_read(krdc->index, krdc->remote_index,
3283                             handle, handle->sb_pos, handle->sb_len);
3284 
3285                         if (!RDC_SUCCESS(sts)) {
3286 #ifdef DEBUG
3287                                 cmn_err(CE_WARN,
3288                                     "!rdc sync: remote read failed (%d)", sts);
3289 #endif
3290                                 DTRACE_PROBE(rdc_sync_loop_remote_read_err);
3291                                 goto failed;
3292                         }
3293                         if (!(rdc_get_vflags(urdc) & RDC_FULL))
3294                                 rdc_set_bitmap_many(krdc, handle->sb_pos,
3295                                     handle->sb_len);
3296 
3297                         /* commit locally */
3298 
3299                         sts = nsc_write(handle, handle->sb_pos,
3300                             handle->sb_len, 0);
3301 
3302                         if (!RDC_SUCCESS(sts)) {
3303                                 /* reverse sync needed already set */
3304                                 rdc_many_enter(krdc);
3305                                 rdc_set_flags_log(urdc, RDC_VOL_FAILED,
3306                                     "write failed during sync");
3307                                 rdc_many_exit(krdc);
3308                                 rdc_write_state(urdc);
3309                                 DTRACE_PROBE(rdc_sync_loop_nsc_write_err);
3310                                 goto failed;
3311                         }
3312                 } else {
3313                         /* send local data to remote */
3314                         DTRACE_PROBE2(rdc_sync_loop_netwrite_start,
3315                             int, krdc->index, nsc_buf_t *, handle);
3316 
3317                         if ((sts = rdc_net_write(krdc->index,
3318                             krdc->remote_index, handle, handle->sb_pos,
3319                             handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) {
3320 
3321                                 /*
3322                                  * The following is to handle
3323                                  * the case where the secondary side
3324                                  * has thrown our buffer handle token away in a
3325                                  * attempt to preserve its health on restart
3326                                  */
3327                                 if ((sts == EPROTO) && (tries < 3)) {
3328                                         (void) nsc_free_buf(handle);
3329                                         handle = NULL;
3330                                         tries++;
3331                                         delay(HZ >> 2);
3332                                         goto retry;
3333                                 }
3334 #ifdef DEBUG
3335                                 cmn_err(CE_WARN,
3336                                     "!rdc sync: remote write failed (%d) 0x%x",
3337                                     sts, rdc_get_vflags(urdc));
3338 #endif
3339                                 DTRACE_PROBE(rdc_sync_loop_netwrite_err);
3340                                 goto failed;
3341                         }
3342                         DTRACE_PROBE(rdc_sync_loop_netwrite_end);
3343                 }
3344 
3345                 (void) nsc_free_buf(handle);
3346                 handle = NULL;
3347 
3348                 if (krdc->dcio_bitmap == NULL) {
3349 #ifdef DEBUG
3350                         cmn_err(CE_NOTE, "!_rdc_sync: NULL bitmap");
3351 #else
3352                 ;
3353                 /*EMPTY*/
3354 #endif
3355                 } else {
3356 
3357                         RDC_SET_BITMASK(offset, len, &bitmask);
3358                         RDC_CLR_BITMAP(krdc, offset, len, bitmask, \
3359                             RDC_BIT_FORCE);
3360                         ASSERT(!IS_ASYNC(urdc));
3361                 }
3362 
3363                 /*
3364                  * Only release/reserve if someone is waiting
3365                  */
3366                 if (krdc->devices->id_release || nsc_waiting(RDC_U_FD(krdc))) {
3367                         DTRACE_PROBE(rdc_sync_loop_rlse_start);
3368                         if (alloc_h) {
3369                                 (void) nsc_free_handle(alloc_h);
3370                                 alloc_h = NULL;
3371                         }
3372 
3373                         _rdc_rlse_devs(krdc, rtype);
3374                         reserved = 0;
3375                         delay(2);
3376 
3377                         rtype = RDC_RAW;
3378                         sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
3379                         if (sts != 0) {
3380                                 handle = NULL;
3381                                 DTRACE_PROBE(rdc_sync_loop_rdc_rsrv_err);
3382                                 goto failed;
3383                         }
3384 
3385                         reserved = 1;
3386 
3387                         if (rdc_prealloc_handle) {
3388                                 alloc_h = nsc_alloc_handle(RDC_U_FD(krdc),
3389                                     NULL, NULL, NULL);
3390 #ifdef DEBUG
3391                                 if (!alloc_h) {
3392                                         cmn_err(CE_WARN, "!rdc_sync: "
3393                                             "failed to pre-alloc handle");
3394                                 }
3395 #endif
3396                         }
3397                         DTRACE_PROBE(rdc_sync_loop_rlse_end);
3398                 }
3399 threaded:
3400                 offset += len;
3401                 urdc->sync_pos = offset;
3402         }
3403 
3404 sync_done:
3405         sync_completed = 1;
3406 
3407 failed:
3408         krdc->group->synccount--;
3409 failed_noincr:
3410         mutex_enter(&sync->lock);
3411         while (sync->complete != sync->threads) {
3412                 cv_wait(&sync->cv, &sync->lock);
3413         }
3414         sync->complete = 0;
3415         sync->threads = 0;
3416         mutex_exit(&sync->lock);
3417 
3418         /*
3419          * if sync_completed is 0 here,
3420          * we know that the main sync thread failed anyway
3421          * so just free the statuses and fail
3422          */
3423         if (sync_completed && (_rdc_sync_status_ok(sync_status, &rc) < 0)) {
3424                 urdc->sync_pos = rc;
3425                 sync_completed = 0; /* at least 1 thread failed */
3426         }
3427 
3428         _rdc_free_sync_status(sync_status);
3429 
3430         /*
3431          * we didn't increment, we didn't even sync,
3432          * so don't dec sync_info.active_thr
3433          */
3434         if (!queuing) {
3435                 mutex_enter(&sync_info.lock);
3436                 sync_info.active_thr--;
3437                 /* LINTED */
3438                 RDC_AVAIL_THR_TUNE(sync_info);
3439                 mutex_exit(&sync_info.lock);
3440         }
3441 
3442         if (handle) {
3443                 (void) nsc_free_buf(handle);
3444         }
3445 
3446         if (alloc_h) {
3447                 (void) nsc_free_handle(alloc_h);
3448         }
3449 
3450         if (reserved) {
3451                 _rdc_rlse_devs(krdc, rtype);
3452         }
3453 
3454 notstarted:
3455         rdc_group_enter(krdc);
3456         ASSERT(krdc->aux_state & RDC_AUXSYNCIP);
3457         if (IS_STATE(urdc, RDC_QUEUING))
3458                 rdc_clr_flags(urdc, RDC_QUEUING);
3459 
3460         if (sync_completed) {
3461                 (void) rdc_net_state(krdc->index, CCIO_DONE);
3462         } else {
3463                 (void) rdc_net_state(krdc->index, CCIO_ENABLELOG);
3464         }
3465 
3466         rdc_clr_flags(urdc, RDC_SYNCING);
3467         if (rdc_get_vflags(urdc) & RDC_SLAVE) {
3468                 rdc_many_enter(krdc);
3469                 rdc_clr_mflags(urdc, RDC_SLAVE);
3470                 rdc_many_exit(krdc);
3471         }
3472         if (krdc->type_flag & RDC_ASYNCMODE)
3473                 rdc_set_flags(urdc, RDC_ASYNC);
3474         if (sync_completed) {
3475                 rdc_many_enter(krdc);
3476                 rdc_clr_mflags(urdc, RDC_RSYNC_NEEDED);
3477                 rdc_many_exit(krdc);
3478         } else {
3479                 krdc->remote_index = -1;
3480                 rdc_set_flags_log(urdc, RDC_LOGGING, "sync failed to complete");
3481         }
3482         rdc_group_exit(krdc);
3483         rdc_write_state(urdc);
3484 
3485         mutex_enter(&net_blk_lock);
3486         if (sync_completed)
3487                 krdc->sync_done = RDC_COMPLETED;
3488         else
3489                 krdc->sync_done = RDC_FAILED;
3490         cv_broadcast(&krdc->synccv);
3491         mutex_exit(&net_blk_lock);
3492 
3493 }
3494 
3495 
3496 static int
3497 rdc_sync(rdc_config_t *uparms, spcs_s_info_t kstatus)
3498 {
3499         rdc_set_t *rdc_set = uparms->rdc_set;
3500         int options = uparms->options;
3501         int rc = 0;
3502         int busy = 0;
3503         int index;
3504         rdc_k_info_t *krdc;
3505         rdc_u_info_t *urdc;
3506         rdc_k_info_t *kmulti;
3507         rdc_u_info_t *umulti;
3508         rdc_group_t *group;
3509         rdc_srv_t *svp;
3510         int sm, um, md;
3511         int sync_completed = 0;
3512         int thrcount;
3513 
3514         mutex_enter(&rdc_conf_lock);
3515         index = rdc_lookup_byname(rdc_set);
3516         if (index >= 0)
3517                 krdc = &rdc_k_info[index];
3518         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
3519                 mutex_exit(&rdc_conf_lock);
3520                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3521                     rdc_set->secondary.file);
3522                 rc = RDC_EALREADY;
3523                 goto notstarted;
3524         }
3525 
3526         urdc = &rdc_u_info[index];
3527         group = krdc->group;
3528         set_busy(krdc);
3529         busy = 1;
3530         if ((krdc->type_flag == 0) || (krdc->type_flag & RDC_DISABLEPEND)) {
3531                 /* A resume or enable failed  or we raced with a teardown */
3532                 mutex_exit(&rdc_conf_lock);
3533                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3534                     rdc_set->secondary.file);
3535                 rc = RDC_EALREADY;
3536                 goto notstarted;
3537         }
3538         mutex_exit(&rdc_conf_lock);
3539         rdc_group_enter(krdc);
3540 
3541         if (!IS_STATE(urdc, RDC_LOGGING)) {
3542                 spcs_s_add(kstatus, RDC_ESETNOTLOGGING, urdc->secondary.intf,
3543                     urdc->secondary.file);
3544                 rc = RDC_ENOTLOGGING;
3545                 goto notstarted_unlock;
3546         }
3547 
3548         if (rdc_check(krdc, rdc_set)) {
3549                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3550                     rdc_set->secondary.file);
3551                 rc = RDC_EALREADY;
3552                 goto notstarted_unlock;
3553         }
3554 
3555         if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
3556                 spcs_s_add(kstatus, RDC_ENOTPRIMARY, rdc_set->primary.intf,
3557                     rdc_set->primary.file, rdc_set->secondary.intf,
3558                     rdc_set->secondary.file);
3559                 rc = RDC_ENOTPRIMARY;
3560                 goto notstarted_unlock;
3561         }
3562 
3563         if ((options & RDC_OPT_REVERSE) && (IS_STATE(urdc, RDC_QUEUING))) {
3564                 /*
3565                  * cannot reverse sync when queuing, need to go logging first
3566                  */
3567                 spcs_s_add(kstatus, RDC_EQNORSYNC, rdc_set->primary.intf,
3568                     rdc_set->primary.file, rdc_set->secondary.intf,
3569                     rdc_set->secondary.file);
3570                 rc = RDC_EQNORSYNC;
3571                 goto notstarted_unlock;
3572         }
3573 
3574         svp = krdc->lsrv;
3575         krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr),
3576             &(urdc->secondary.addr), 1);
3577 
3578         if (!krdc->intf) {
3579                 spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf,
3580                     urdc->secondary.intf);
3581                 rc = RDC_EADDTOIF;
3582                 goto notstarted_unlock;
3583         }
3584 
3585         if (urdc->volume_size == 0) {
3586                 /* Implies reserve failed when previous resume was done */
3587                 rdc_get_details(krdc);
3588         }
3589         if (urdc->volume_size == 0) {
3590                 spcs_s_add(kstatus, RDC_ENOBMAP);
3591                 rc = RDC_ENOBMAP;
3592                 goto notstarted_unlock;
3593         }
3594 
3595         if (krdc->dcio_bitmap == NULL) {
3596                 if (rdc_resume_bitmap(krdc) < 0) {
3597                         spcs_s_add(kstatus, RDC_ENOBMAP);
3598                         rc = RDC_ENOBMAP;
3599                         goto notstarted_unlock;
3600                 }
3601         }
3602 
3603         if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) {
3604                 if (rdc_reset_bitmap(krdc)) {
3605                         spcs_s_add(kstatus, RDC_EBITMAP);
3606                         rc = RDC_EBITMAP;
3607                         goto notstarted_unlock;
3608                 }
3609         }
3610 
3611         if (IS_MANY(krdc) || IS_MULTI(krdc)) {
3612                 rdc_u_info_t *ubad;
3613 
3614                 if ((ubad = rdc_allow_pri_sync(urdc, options)) != NULL) {
3615                         spcs_s_add(kstatus, RDC_ESTATE,
3616                             ubad->primary.intf, ubad->primary.file,
3617                             ubad->secondary.intf, ubad->secondary.file);
3618                         rc = RDC_ESTATE;
3619                         goto notstarted_unlock;
3620                 }
3621         }
3622 
3623         /*
3624          * there is a small window where _rdc_sync is still
3625          * running, but has cleared the RDC_SYNCING flag.
3626          * Use aux_state which is only cleared
3627          * after _rdc_sync had done its 'death' broadcast.
3628          */
3629         if (krdc->aux_state & RDC_AUXSYNCIP) {
3630 #ifdef DEBUG
3631                 if (!rdc_get_vflags(urdc) & RDC_SYNCING) {
3632                         cmn_err(CE_WARN, "!rdc_sync: "
3633                             "RDC_AUXSYNCIP set, SYNCING off");
3634                 }
3635 #endif
3636                 spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file);
3637                 rc = RDC_ESYNCING;
3638                 goto notstarted_unlock;
3639         }
3640         if (krdc->disk_status == 1) {
3641                 spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file);
3642                 rc = RDC_ESYNCING;
3643                 goto notstarted_unlock;
3644         }
3645 
3646         if ((options & RDC_OPT_FORWARD) &&
3647             (rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED)) {
3648                 /* cannot forward sync if a reverse sync is needed */
3649                 spcs_s_add(kstatus, RDC_ERSYNCNEEDED, rdc_set->primary.intf,
3650                     rdc_set->primary.file, rdc_set->secondary.intf,
3651                     rdc_set->secondary.file);
3652                 rc = RDC_ERSYNCNEEDED;
3653                 goto notstarted_unlock;
3654         }
3655 
3656         urdc->sync_pos = 0;
3657 
3658         /* Check if the rdc set is accessible on the remote node */
3659         if (rdc_net_getstate(krdc, &sm, &um, &md, FALSE) < 0) {
3660                 /*
3661                  * Remote end may be inaccessible, or the rdc set is not
3662                  * enabled at the remote end.
3663                  */
3664                 spcs_s_add(kstatus, RDC_ECONNOPEN, urdc->secondary.intf,
3665                     urdc->secondary.file);
3666                 rc = RDC_ECONNOPEN;
3667                 goto notstarted_unlock;
3668         }
3669         if (options & RDC_OPT_REVERSE)
3670                 krdc->remote_index = rdc_net_state(index, CCIO_RSYNC);
3671         else
3672                 krdc->remote_index = rdc_net_state(index, CCIO_SLAVE);
3673         if (krdc->remote_index < 0) {
3674                 /*
3675                  * Remote note probably not in a valid state to be synced,
3676                  * as the state was fetched OK above.
3677                  */
3678                 spcs_s_add(kstatus, RDC_ERSTATE, urdc->secondary.intf,
3679                     urdc->secondary.file, urdc->primary.intf,
3680                     urdc->primary.file);
3681                 rc = RDC_ERSTATE;
3682                 goto notstarted_unlock;
3683         }
3684 
3685         rc = check_filesize(index, kstatus);
3686         if (rc != 0) {
3687                 (void) rdc_net_state(krdc->index, CCIO_ENABLELOG);
3688                 goto notstarted_unlock;
3689         }
3690 
3691         krdc->sync_done = 0;
3692 
3693         mutex_enter(&krdc->bmapmutex);
3694         krdc->aux_state |= RDC_AUXSYNCIP;
3695         mutex_exit(&krdc->bmapmutex);
3696 
3697         if (options & RDC_OPT_REVERSE) {
3698                 rdc_many_enter(krdc);
3699                 rdc_set_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
3700                 mutex_enter(&krdc->bmapmutex);
3701                 rdc_clr_flags(urdc, RDC_VOL_FAILED);
3702                 mutex_exit(&krdc->bmapmutex);
3703                 rdc_write_state(urdc);
3704                 /* LINTED */
3705                 if (kmulti = krdc->multi_next) {
3706                         umulti = &rdc_u_info[kmulti->index];
3707                         if (IS_ENABLED(umulti) && (rdc_get_vflags(umulti) &
3708                             (RDC_VOL_FAILED | RDC_SYNC_NEEDED))) {
3709                                 rdc_clr_flags(umulti, RDC_SYNC_NEEDED);
3710                                 rdc_clr_flags(umulti, RDC_VOL_FAILED);
3711                                 rdc_write_state(umulti);
3712                         }
3713                 }
3714                 rdc_many_exit(krdc);
3715         } else {
3716                 rdc_clr_flags(urdc, RDC_FCAL_FAILED);
3717                 rdc_write_state(urdc);
3718         }
3719 
3720         if (options & RDC_OPT_UPDATE) {
3721                 ASSERT(urdc->volume_size != 0);
3722                 if (rdc_net_getbmap(index,
3723                     BMAP_LOG_BYTES(urdc->volume_size)) > 0) {
3724                         spcs_s_add(kstatus, RDC_ENOBMAP);
3725                         rc = RDC_ENOBMAP;
3726 
3727                         (void) rdc_net_state(index, CCIO_ENABLELOG);
3728 
3729                         rdc_clr_flags(urdc, RDC_SYNCING);
3730                         if (options & RDC_OPT_REVERSE) {
3731                                 rdc_many_enter(krdc);
3732                                 rdc_clr_mflags(urdc, RDC_SLAVE);
3733                                 rdc_many_exit(krdc);
3734                         }
3735                         if (krdc->type_flag & RDC_ASYNCMODE)
3736                                 rdc_set_flags(urdc, RDC_ASYNC);
3737                         krdc->remote_index = -1;
3738                         rdc_set_flags_log(urdc, RDC_LOGGING,
3739                             "failed to read remote bitmap");
3740                         rdc_write_state(urdc);
3741                         goto failed;
3742                 }
3743                 rdc_clr_flags(urdc, RDC_FULL);
3744         } else {
3745                 /*
3746                  * This is a full sync (not an update sync), mark the
3747                  * entire bitmap dirty
3748                  */
3749                 (void) RDC_FILL_BITMAP(krdc, FALSE);
3750 
3751                 rdc_set_flags(urdc, RDC_FULL);
3752         }
3753 
3754         rdc_group_exit(krdc);
3755 
3756         /*
3757          * allow diskq->memq flusher to wake up
3758          */
3759         mutex_enter(&krdc->group->ra_queue.net_qlock);
3760         krdc->group->ra_queue.qfflags &= ~RDC_QFILLSLEEP;
3761         mutex_exit(&krdc->group->ra_queue.net_qlock);
3762 
3763         /*
3764          * if this is a full sync on a non-diskq set or
3765          * a diskq set that has failed, clear the async flag
3766          */
3767         if (krdc->type_flag & RDC_ASYNCMODE) {
3768                 if ((!(options & RDC_OPT_UPDATE)) ||
3769                     (!RDC_IS_DISKQ(krdc->group)) ||
3770                     (!(IS_STATE(urdc, RDC_QUEUING)))) {
3771                         /* full syncs, or core queue are synchronous */
3772                         rdc_group_enter(krdc);
3773                         rdc_clr_flags(urdc, RDC_ASYNC);
3774                         rdc_group_exit(krdc);
3775                 }
3776 
3777                 /*
3778                  * if the queue failed because it was full, lets see
3779                  * if we can restart it. After _rdc_sync() is done
3780                  * the modes will switch and we will begin disk
3781                  * queuing again. NOTE: this should only be called
3782                  * once per group, as it clears state for all group
3783                  * members, also clears the async flag for all members
3784                  */
3785                 if (IS_STATE(urdc, RDC_DISKQ_FAILED)) {
3786                         rdc_unfail_diskq(krdc);
3787                 } else {
3788                 /* don't add insult to injury by flushing a dead queue */
3789 
3790                         /*
3791                          * if we are updating, and a diskq and
3792                          * the async thread isn't active, start
3793                          * it up.
3794                          */
3795                         if ((options & RDC_OPT_UPDATE) &&
3796                             (IS_STATE(urdc, RDC_QUEUING))) {
3797                                 rdc_group_enter(krdc);
3798                                 rdc_clr_flags(urdc, RDC_SYNCING);
3799                                 rdc_group_exit(krdc);
3800                                 mutex_enter(&krdc->group->ra_queue.net_qlock);
3801                                 if (krdc->group->ra_queue.qfill_sleeping ==
3802                                     RDC_QFILL_ASLEEP)
3803                                         cv_broadcast(&group->ra_queue.qfcv);
3804                                 mutex_exit(&krdc->group->ra_queue.net_qlock);
3805                                 thrcount = urdc->asyncthr;
3806                                 while ((thrcount-- > 0) &&
3807                                     !krdc->group->rdc_writer) {
3808                                         (void) rdc_writer(krdc->index);
3809                                 }
3810                         }
3811                 }
3812         }
3813 
3814         /*
3815          * For a reverse sync, merge the current bitmap with all other sets
3816          * that share this volume.
3817          */
3818         if (options & RDC_OPT_REVERSE) {
3819 retry_many:
3820                 rdc_many_enter(krdc);
3821                 if (IS_MANY(krdc)) {
3822                         rdc_k_info_t *kmany;
3823                         rdc_u_info_t *umany;
3824 
3825                         for (kmany = krdc->many_next; kmany != krdc;
3826                             kmany = kmany->many_next) {
3827                                 umany = &rdc_u_info[kmany->index];
3828                                 if (!IS_ENABLED(umany))
3829                                         continue;
3830                                 ASSERT(umany->flags & RDC_PRIMARY);
3831 
3832                                 if (!mutex_tryenter(&kmany->group->lock)) {
3833                                         rdc_many_exit(krdc);
3834                                         /* May merge more than once */
3835                                         goto retry_many;
3836                                 }
3837                                 rdc_merge_bitmaps(krdc, kmany);
3838                                 mutex_exit(&kmany->group->lock);
3839                         }
3840                 }
3841                 rdc_many_exit(krdc);
3842 
3843 retry_multi:
3844                 rdc_many_enter(krdc);
3845                 if (IS_MULTI(krdc)) {
3846                         rdc_k_info_t *kmulti = krdc->multi_next;
3847                         rdc_u_info_t *umulti = &rdc_u_info[kmulti->index];
3848 
3849                         if (IS_ENABLED(umulti)) {
3850                                 ASSERT(!(umulti->flags & RDC_PRIMARY));
3851 
3852                                 if (!mutex_tryenter(&kmulti->group->lock)) {
3853                                         rdc_many_exit(krdc);
3854                                         goto retry_multi;
3855                                 }
3856                                 rdc_merge_bitmaps(krdc, kmulti);
3857                                 mutex_exit(&kmulti->group->lock);
3858                         }
3859                 }
3860                 rdc_many_exit(krdc);
3861         }
3862 
3863         rdc_group_enter(krdc);
3864 
3865         if (krdc->bitmap_write == 0) {
3866                 if (rdc_write_bitmap_fill(krdc) >= 0)
3867                         krdc->bitmap_write = -1;
3868         }
3869 
3870         if (krdc->bitmap_write > 0)
3871                 (void) rdc_write_bitmap(krdc);
3872 
3873         urdc->bits_set = RDC_COUNT_BITMAP(krdc);
3874 
3875         rdc_group_exit(krdc);
3876 
3877         if (options & RDC_OPT_REVERSE) {
3878                 (void) _rdc_sync_event_notify(RDC_SYNC_START,
3879                     urdc->primary.file, urdc->group_name);
3880         }
3881 
3882         /* Now set off the sync itself */
3883 
3884         mutex_enter(&net_blk_lock);
3885         if (nsc_create_process(
3886             (void (*)(void *))_rdc_sync, (void *)krdc, FALSE)) {
3887                 mutex_exit(&net_blk_lock);
3888                 spcs_s_add(kstatus, RDC_ENOPROC);
3889                 /*
3890                  * We used to just return here,
3891                  * but we need to clear the AUXSYNCIP bit
3892                  * and there is a very small chance that
3893                  * someone may be waiting on the disk_status flag.
3894                  */
3895                 rc = RDC_ENOPROC;
3896                 /*
3897                  * need the group lock held at failed.
3898                  */
3899                 rdc_group_enter(krdc);
3900                 goto failed;
3901         }
3902 
3903         mutex_enter(&rdc_conf_lock);
3904         wakeup_busy(krdc);
3905         busy = 0;
3906         mutex_exit(&rdc_conf_lock);
3907 
3908         while (krdc->sync_done == 0)
3909                 cv_wait(&krdc->synccv, &net_blk_lock);
3910         mutex_exit(&net_blk_lock);
3911 
3912         rdc_group_enter(krdc);
3913 
3914         if (krdc->sync_done == RDC_FAILED) {
3915                 char siztmp1[16];
3916                 (void) spcs_s_inttostring(
3917                     urdc->sync_pos, siztmp1, sizeof (siztmp1),
3918                     0);
3919                 spcs_s_add(kstatus, RDC_EFAIL, siztmp1);
3920                 rc = RDC_EFAIL;
3921         } else
3922                 sync_completed = 1;
3923 
3924 failed:
3925         /*
3926          * We use this flag now to make halt_sync() wait for
3927          * us to terminate and let us take the group lock.
3928          */
3929         krdc->aux_state &= ~RDC_AUXSYNCIP;
3930         if (krdc->disk_status == 1) {
3931                 krdc->disk_status = 0;
3932                 cv_broadcast(&krdc->haltcv);
3933         }
3934 
3935 notstarted_unlock:
3936         rdc_group_exit(krdc);
3937 
3938         if (sync_completed && (options & RDC_OPT_REVERSE)) {
3939                 (void) _rdc_sync_event_notify(RDC_SYNC_DONE,
3940                     urdc->primary.file, urdc->group_name);
3941         }
3942 
3943 notstarted:
3944         if (busy) {
3945                 mutex_enter(&rdc_conf_lock);
3946                 wakeup_busy(krdc);
3947                 mutex_exit(&rdc_conf_lock);
3948         }
3949 
3950         return (rc);
3951 }
3952 
3953 /* ARGSUSED */
3954 static int
3955 _rdc_suspend(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus)
3956 {
3957         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
3958         rdc_if_t *ip;
3959         int index = krdc->index;
3960 
3961         ASSERT(krdc->group != NULL);
3962         rdc_group_enter(krdc);
3963 #ifdef DEBUG
3964         ASSERT(rdc_check(krdc, rdc_set) == 0);
3965 #else
3966         if (rdc_check(krdc, rdc_set)) {
3967                 rdc_group_exit(krdc);
3968                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
3969                     rdc_set->secondary.file);
3970                 return (RDC_EALREADY);
3971         }
3972 #endif
3973 
3974         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
3975                 halt_sync(krdc);
3976                 ASSERT(IS_ENABLED(urdc));
3977         }
3978 
3979         rdc_group_exit(krdc);
3980         (void) rdc_unintercept(krdc);
3981 
3982 #ifdef DEBUG
3983         cmn_err(CE_NOTE, "!SNDR: suspended %s %s", urdc->primary.file,
3984             urdc->secondary.file);
3985 #endif
3986 
3987         /* Configured but not enabled */
3988         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
3989 
3990 
3991         if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) {
3992                 int tries = 2; /* in case of possibly stuck flusher threads */
3993 #ifdef DEBUG
3994                 net_queue *qp = &krdc->group->ra_queue;
3995 #endif
3996                 do {
3997                         if (!krdc->group->rdc_writer)
3998                                 (void) rdc_writer(krdc->index);
3999 
4000                         (void) rdc_drain_queue(krdc->index);
4001 
4002                 } while (krdc->group->rdc_writer && tries--);
4003 
4004                 /* ok, force it to happen... */
4005                 if (rdc_drain_queue(krdc->index) != 0) {
4006                         do {
4007                                 mutex_enter(&krdc->group->ra_queue.net_qlock);
4008                                 krdc->group->asyncdis = 1;
4009                                 cv_broadcast(&krdc->group->asyncqcv);
4010                                 mutex_exit(&krdc->group->ra_queue.net_qlock);
4011                                 cmn_err(CE_WARN,
4012                                     "!SNDR: async I/O pending and not flushed "
4013                                     "for %s during suspend",
4014                                     urdc->primary.file);
4015 #ifdef DEBUG
4016                                 cmn_err(CE_WARN,
4017                                     "!nitems: %" NSC_SZFMT " nblocks: %"
4018                                     NSC_SZFMT " head: 0x%p tail: 0x%p",
4019                                     qp->nitems, qp->blocks,
4020                                     (void *)qp->net_qhead,
4021                                     (void *)qp->net_qtail);
4022 #endif
4023                         } while (krdc->group->rdc_thrnum > 0);
4024                 }
4025         }
4026 
4027         mutex_enter(&rdc_conf_lock);
4028         ip = krdc->intf;
4029         krdc->intf = 0;
4030 
4031         if (ip) {
4032                 rdc_remove_from_if(ip);
4033         }
4034 
4035         mutex_exit(&rdc_conf_lock);
4036 
4037         rdc_group_enter(krdc);
4038 
4039         /* Configured but not enabled */
4040         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4041 
4042         rdc_group_exit(krdc);
4043         /* Must not hold group lock during this function */
4044         while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4045                 delay(2);
4046         rdc_group_enter(krdc);
4047 
4048         /* Don't rdc_clear_state, unlike _rdc_disable */
4049 
4050         rdc_free_bitmap(krdc, RDC_CMD_SUSPEND);
4051         rdc_close_bitmap(krdc);
4052 
4053         rdc_dev_close(krdc);
4054         rdc_close_direct(krdc);
4055 
4056         /* Configured but not enabled */
4057         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4058 
4059         rdc_group_exit(krdc);
4060 
4061         /*
4062          * we should now unregister the queue, with no conflicting
4063          * locks held. This is the last(only) member of the group
4064          */
4065         if (krdc->group && RDC_IS_DISKQ(krdc->group) &&
4066             krdc->group->count == 1) { /* stop protecting queue */
4067                 rdc_unintercept_diskq(krdc->group);
4068         }
4069 
4070         mutex_enter(&rdc_conf_lock);
4071 
4072         /* Configured but not enabled */
4073         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4074 
4075         wait_busy(krdc);
4076 
4077         if (IS_MANY(krdc) || IS_MULTI(krdc))
4078                 remove_from_many(krdc);
4079 
4080         remove_from_group(krdc);
4081 
4082         krdc->remote_index = -1;
4083         ASSERT(krdc->type_flag & RDC_CONFIGURED);
4084         ASSERT(krdc->type_flag & RDC_DISABLEPEND);
4085         krdc->type_flag = 0;
4086 #ifdef  DEBUG
4087         if (krdc->dcio_bitmap)
4088                 cmn_err(CE_WARN, "!_rdc_suspend: possible mem leak, "
4089                     "dcio_bitmap");
4090 #endif
4091         krdc->dcio_bitmap = NULL;
4092         krdc->bitmap_ref = NULL;
4093         krdc->bitmap_size = 0;
4094         krdc->maxfbas = 0;
4095         krdc->bitmap_write = 0;
4096         krdc->disk_status = 0;
4097         rdc_destroy_svinfo(krdc->lsrv);
4098         krdc->lsrv = NULL;
4099         krdc->multi_next = NULL;
4100 
4101         rdc_u_init(urdc);
4102 
4103         mutex_exit(&rdc_conf_lock);
4104         rdc_kstat_delete(index);
4105         return (0);
4106 }
4107 
4108 static int
4109 rdc_suspend(rdc_config_t *uparms, spcs_s_info_t kstatus)
4110 {
4111         rdc_k_info_t *krdc;
4112         int index;
4113         int rc;
4114 
4115         mutex_enter(&rdc_conf_lock);
4116 
4117         index = rdc_lookup_byname(uparms->rdc_set);
4118         if (index >= 0)
4119                 krdc = &rdc_k_info[index];
4120         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4121                 mutex_exit(&rdc_conf_lock);
4122                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4123                     uparms->rdc_set->secondary.file);
4124                 return (RDC_EALREADY);
4125         }
4126 
4127         krdc->type_flag |= RDC_DISABLEPEND;
4128         wait_busy(krdc);
4129         if (krdc->type_flag == 0) {
4130                 /* A resume or enable failed */
4131                 mutex_exit(&rdc_conf_lock);
4132                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4133                     uparms->rdc_set->secondary.file);
4134                 return (RDC_EALREADY);
4135         }
4136         mutex_exit(&rdc_conf_lock);
4137 
4138         rc = _rdc_suspend(krdc, uparms->rdc_set, kstatus);
4139         return (rc);
4140 }
4141 
4142 static int
4143 _rdc_resume(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus)
4144 {
4145         int index;
4146         char *rhost;
4147         struct netbuf *addrp;
4148         rdc_k_info_t *krdc;
4149         rdc_u_info_t *urdc;
4150         rdc_srv_t *svp = NULL;
4151         char *local_file;
4152         char *local_bitmap;
4153         int rc, rc1;
4154         nsc_size_t maxfbas;
4155         rdc_group_t *grp;
4156 
4157         if ((rdc_set->primary.intf[0] == 0) ||
4158             (rdc_set->primary.addr.len == 0) ||
4159             (rdc_set->primary.file[0] == 0) ||
4160             (rdc_set->primary.bitmap[0] == 0) ||
4161             (rdc_set->secondary.intf[0] == 0) ||
4162             (rdc_set->secondary.addr.len == 0) ||
4163             (rdc_set->secondary.file[0] == 0) ||
4164             (rdc_set->secondary.bitmap[0] == 0)) {
4165                 spcs_s_add(kstatus, RDC_EEMPTY);
4166                 return (RDC_EEMPTY);
4167         }
4168 
4169         /* Next check there aren't any enabled rdc sets which match. */
4170 
4171         mutex_enter(&rdc_conf_lock);
4172 
4173         if (rdc_lookup_byname(rdc_set) >= 0) {
4174                 mutex_exit(&rdc_conf_lock);
4175                 spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf,
4176                     rdc_set->primary.file, rdc_set->secondary.intf,
4177                     rdc_set->secondary.file);
4178                 return (RDC_EENABLED);
4179         }
4180 
4181         if (rdc_lookup_many2one(rdc_set) >= 0) {
4182                 mutex_exit(&rdc_conf_lock);
4183                 spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf,
4184                     rdc_set->primary.file, rdc_set->secondary.intf,
4185                     rdc_set->secondary.file);
4186                 return (RDC_EMANY2ONE);
4187         }
4188 
4189         if (rdc_set->netconfig->knc_proto == NULL) {
4190                 mutex_exit(&rdc_conf_lock);
4191                 spcs_s_add(kstatus, RDC_ENETCONFIG);
4192                 return (RDC_ENETCONFIG);
4193         }
4194 
4195         if (rdc_set->primary.addr.len == 0) {
4196                 mutex_exit(&rdc_conf_lock);
4197                 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file);
4198                 return (RDC_ENETBUF);
4199         }
4200 
4201         if (rdc_set->secondary.addr.len == 0) {
4202                 mutex_exit(&rdc_conf_lock);
4203                 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file);
4204                 return (RDC_ENETBUF);
4205         }
4206 
4207         /* Check that the local data volume isn't in use as a bitmap */
4208         if (options & RDC_OPT_PRIMARY)
4209                 local_file = rdc_set->primary.file;
4210         else
4211                 local_file = rdc_set->secondary.file;
4212         if (rdc_lookup_bitmap(local_file) >= 0) {
4213                 mutex_exit(&rdc_conf_lock);
4214                 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
4215                 return (RDC_EVOLINUSE);
4216         }
4217 
4218         /* check that the secondary data volume isn't in use */
4219         if (!(options & RDC_OPT_PRIMARY)) {
4220                 local_file = rdc_set->secondary.file;
4221                 if (rdc_lookup_secondary(local_file) >= 0) {
4222                         mutex_exit(&rdc_conf_lock);
4223                         spcs_s_add(kstatus, RDC_EVOLINUSE, local_file);
4224                         return (RDC_EVOLINUSE);
4225                 }
4226         }
4227 
4228         /* Check that the bitmap isn't in use as a data volume */
4229         if (options & RDC_OPT_PRIMARY)
4230                 local_bitmap = rdc_set->primary.bitmap;
4231         else
4232                 local_bitmap = rdc_set->secondary.bitmap;
4233         if (rdc_lookup_configured(local_bitmap) >= 0) {
4234                 mutex_exit(&rdc_conf_lock);
4235                 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
4236                 return (RDC_EBMPINUSE);
4237         }
4238 
4239         /* Check that the bitmap isn't already in use as a bitmap */
4240         if (rdc_lookup_bitmap(local_bitmap) >= 0) {
4241                 mutex_exit(&rdc_conf_lock);
4242                 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap);
4243                 return (RDC_EBMPINUSE);
4244         }
4245 
4246         /* Set urdc->volume_size */
4247         index = rdc_dev_open(rdc_set, options);
4248         if (index < 0) {
4249                 mutex_exit(&rdc_conf_lock);
4250                 if (options & RDC_OPT_PRIMARY)
4251                         spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf,
4252                             rdc_set->primary.file);
4253                 else
4254                         spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf,
4255                             rdc_set->secondary.file);
4256                 return (RDC_EOPEN);
4257         }
4258 
4259         urdc = &rdc_u_info[index];
4260         krdc = &rdc_k_info[index];
4261 
4262         /* copy relevant parts of rdc_set to urdc field by field */
4263 
4264         (void) strncpy(urdc->primary.intf, rdc_set->primary.intf,
4265             MAX_RDC_HOST_SIZE);
4266         (void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf,
4267             MAX_RDC_HOST_SIZE);
4268 
4269         (void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH);
4270 
4271         dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr);
4272         (void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH);
4273         (void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap,
4274             NSC_MAXPATH);
4275 
4276         dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr);
4277         (void) strncpy(urdc->secondary.file, rdc_set->secondary.file,
4278             NSC_MAXPATH);
4279         (void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap,
4280             NSC_MAXPATH);
4281         (void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH);
4282         urdc->setid = rdc_set->setid;
4283 
4284         if ((options & RDC_OPT_SYNC) && urdc->disk_queue[0]) {
4285                 mutex_exit(&rdc_conf_lock);
4286                 rdc_dev_close(krdc);
4287                 spcs_s_add(kstatus, RDC_EQWRONGMODE);
4288                 return (RDC_EQWRONGMODE);
4289         }
4290 
4291         /*
4292          * init flags now so that state left by failures in add_to_group()
4293          * are preserved.
4294          */
4295         rdc_init_flags(urdc);
4296 
4297         if ((rc1 = add_to_group(krdc, options, RDC_CMD_RESUME)) != 0) {
4298                 if (rc1 == RDC_EQNOADD) { /* something went wrong with queue */
4299                         rdc_fail_diskq(krdc, RDC_WAIT, RDC_NOLOG);
4300                         /* don't return a failure here, continue with resume */
4301 
4302                 } else { /* some other group add failure */
4303                         mutex_exit(&rdc_conf_lock);
4304                         rdc_dev_close(krdc);
4305                         spcs_s_add(kstatus, RDC_EGROUP,
4306                             rdc_set->primary.intf, rdc_set->primary.file,
4307                             rdc_set->secondary.intf, rdc_set->secondary.file,
4308                             rdc_set->group_name);
4309                         return (RDC_EGROUP);
4310                 }
4311         }
4312 
4313         /*
4314          * maxfbas was set in rdc_dev_open as primary's maxfbas.
4315          * If diskq's maxfbas is smaller, then use diskq's.
4316          */
4317         grp = krdc->group;
4318         if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) {
4319                 rc = _rdc_rsrv_diskq(grp);
4320                 if (RDC_SUCCESS(rc)) {
4321                         rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas);
4322                         if (rc == 0) {
4323 #ifdef DEBUG
4324                                 if (krdc->maxfbas != maxfbas)
4325                                         cmn_err(CE_NOTE,
4326                                             "!_rdc_resume: diskq maxfbas = %"
4327                                             NSC_SZFMT ", primary maxfbas = %"
4328                                             NSC_SZFMT, maxfbas, krdc->maxfbas);
4329 #endif
4330                                         krdc->maxfbas = min(krdc->maxfbas,
4331                                             maxfbas);
4332                         } else {
4333                                 cmn_err(CE_WARN,
4334                                     "!_rdc_resume: diskq maxfbas failed (%d)",
4335                                     rc);
4336                         }
4337                         _rdc_rlse_diskq(grp);
4338                 } else {
4339                         cmn_err(CE_WARN,
4340                             "!_rdc_resume: diskq reserve failed (%d)", rc);
4341                 }
4342         }
4343 
4344         (void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH);
4345         if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) {
4346                 if (rdc_open_direct(krdc) == NULL)
4347                         rdc_set_flags(urdc, RDC_FCAL_FAILED);
4348         }
4349 
4350         krdc->many_next = krdc;
4351 
4352         ASSERT(krdc->type_flag == 0);
4353         krdc->type_flag = RDC_CONFIGURED;
4354 
4355         if (options & RDC_OPT_PRIMARY)
4356                 rdc_set_flags(urdc, RDC_PRIMARY);
4357 
4358         if (options & RDC_OPT_ASYNC)
4359                 krdc->type_flag |= RDC_ASYNCMODE;
4360 
4361         set_busy(krdc);
4362 
4363         urdc->syshostid = rdc_set->syshostid;
4364 
4365         if (add_to_many(krdc) < 0) {
4366                 mutex_exit(&rdc_conf_lock);
4367 
4368                 rdc_group_enter(krdc);
4369 
4370                 spcs_s_add(kstatus, RDC_EMULTI);
4371                 rc = RDC_EMULTI;
4372                 goto fail;
4373         }
4374 
4375         /* Configured but not enabled */
4376         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4377 
4378         mutex_exit(&rdc_conf_lock);
4379 
4380         if (urdc->volume_size == 0) {
4381                 rdc_many_enter(krdc);
4382                 if (options & RDC_OPT_PRIMARY)
4383                         rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
4384                 else
4385                         rdc_set_flags(urdc, RDC_SYNC_NEEDED);
4386                 rdc_set_flags(urdc, RDC_VOL_FAILED);
4387                 rdc_many_exit(krdc);
4388         }
4389 
4390         rdc_group_enter(krdc);
4391 
4392         /* Configured but not enabled */
4393         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4394 
4395         /*
4396          * The rdc set is configured but not yet enabled. Other operations must
4397          * ignore this set until it is enabled.
4398          */
4399 
4400         urdc->sync_pos = 0;
4401 
4402         /* Set tunable defaults, we'll pick up tunables from the header later */
4403 
4404         urdc->maxqfbas = rdc_maxthres_queue;
4405         urdc->maxqitems = rdc_max_qitems;
4406         urdc->autosync = 0;
4407         urdc->asyncthr = rdc_asyncthr;
4408 
4409         urdc->netconfig = rdc_set->netconfig;
4410 
4411         if (options & RDC_OPT_PRIMARY) {
4412                 rhost = rdc_set->secondary.intf;
4413                 addrp = &rdc_set->secondary.addr;
4414         } else {
4415                 rhost = rdc_set->primary.intf;
4416                 addrp = &rdc_set->primary.addr;
4417         }
4418 
4419         if (options & RDC_OPT_ASYNC)
4420                 rdc_set_flags(urdc, RDC_ASYNC);
4421 
4422         svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig);
4423         if (svp == NULL) {
4424                 spcs_s_add(kstatus, ENOMEM);
4425                 rc = ENOMEM;
4426                 goto fail;
4427         }
4428 
4429         urdc->netconfig = NULL;              /* This will be no good soon */
4430 
4431         /* Don't set krdc->intf here */
4432         rdc_kstat_create(index);
4433 
4434         /* if the bitmap resume isn't clean, it will clear queuing flag */
4435 
4436         (void) rdc_resume_bitmap(krdc);
4437 
4438         if (RDC_IS_DISKQ(krdc->group)) {
4439                 disk_queue *q = &krdc->group->diskq;
4440                 if ((rc1 == RDC_EQNOADD) ||
4441                     IS_QSTATE(q, RDC_QBADRESUME)) {
4442                         rdc_clr_flags(urdc, RDC_QUEUING);
4443                         RDC_ZERO_BITREF(krdc);
4444                 }
4445         }
4446 
4447         if (krdc->lsrv == NULL)
4448                 krdc->lsrv = svp;
4449         else {
4450 #ifdef DEBUG
4451                 cmn_err(CE_WARN, "!_rdc_resume: krdc->lsrv already set: %p",
4452                     (void *) krdc->lsrv);
4453 #endif
4454                 rdc_destroy_svinfo(svp);
4455         }
4456         svp = NULL;
4457 
4458         /* Configured but not enabled */
4459         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4460 
4461         /* And finally */
4462 
4463         krdc->remote_index = -1;
4464 
4465         /* Should we set the whole group logging? */
4466         rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING);
4467 
4468         rdc_group_exit(krdc);
4469 
4470         if (rdc_intercept(krdc) != 0) {
4471                 rdc_group_enter(krdc);
4472                 rdc_clr_flags(urdc, RDC_ENABLED);
4473                 if (options & RDC_OPT_PRIMARY)
4474                         spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file);
4475                 else
4476                         spcs_s_add(kstatus, RDC_EREGISTER,
4477                             urdc->secondary.file);
4478 #ifdef DEBUG
4479                 cmn_err(CE_NOTE, "!nsc_register_path failed %s",
4480                     urdc->primary.file);
4481 #endif
4482                 rc = RDC_EREGISTER;
4483                 goto bmpfail;
4484         }
4485 #ifdef DEBUG
4486         cmn_err(CE_NOTE, "!SNDR: resumed %s %s", urdc->primary.file,
4487             urdc->secondary.file);
4488 #endif
4489 
4490         rdc_write_state(urdc);
4491 
4492         mutex_enter(&rdc_conf_lock);
4493         wakeup_busy(krdc);
4494         mutex_exit(&rdc_conf_lock);
4495 
4496         return (0);
4497 
4498 bmpfail:
4499         if (options & RDC_OPT_PRIMARY)
4500                 spcs_s_add(kstatus, RDC_EBITMAP, urdc->primary.bitmap);
4501         else
4502                 spcs_s_add(kstatus, RDC_EBITMAP, urdc->secondary.bitmap);
4503         rc = RDC_EBITMAP;
4504         if (rdc_get_vflags(urdc) & RDC_ENABLED) {
4505                 rdc_group_exit(krdc);
4506                 (void) rdc_unintercept(krdc);
4507                 rdc_group_enter(krdc);
4508         }
4509 
4510 fail:
4511         rdc_kstat_delete(index);
4512         /* Don't unset krdc->intf here, unlike _rdc_enable */
4513 
4514         /* Configured but not enabled */
4515         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4516 
4517         rdc_dev_close(krdc);
4518         rdc_close_direct(krdc);
4519         rdc_destroy_svinfo(svp);
4520 
4521         /* Configured but not enabled */
4522         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4523 
4524         rdc_group_exit(krdc);
4525 
4526         mutex_enter(&rdc_conf_lock);
4527 
4528         /* Configured but not enabled */
4529         ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc));
4530 
4531         remove_from_group(krdc);
4532 
4533         if (IS_MANY(krdc) || IS_MULTI(krdc))
4534                 remove_from_many(krdc);
4535 
4536         rdc_u_init(urdc);
4537 
4538         ASSERT(krdc->type_flag & RDC_CONFIGURED);
4539         krdc->type_flag = 0;
4540         wakeup_busy(krdc);
4541 
4542         mutex_exit(&rdc_conf_lock);
4543 
4544         return (rc);
4545 }
4546 
4547 static int
4548 rdc_resume(rdc_config_t *uparms, spcs_s_info_t kstatus)
4549 {
4550         char itmp[10];
4551         int rc;
4552 
4553         if (!(uparms->options & RDC_OPT_SYNC) &&
4554             !(uparms->options & RDC_OPT_ASYNC)) {
4555                 (void) spcs_s_inttostring(
4556                     uparms->options, itmp, sizeof (itmp), 1);
4557                 spcs_s_add(kstatus, RDC_EEINVAL, itmp);
4558                 rc = RDC_EEINVAL;
4559                 goto done;
4560         }
4561 
4562         if (!(uparms->options & RDC_OPT_PRIMARY) &&
4563             !(uparms->options & RDC_OPT_SECONDARY)) {
4564                 (void) spcs_s_inttostring(
4565                     uparms->options, itmp, sizeof (itmp), 1);
4566                 spcs_s_add(kstatus, RDC_EEINVAL, itmp);
4567                 rc = RDC_EEINVAL;
4568                 goto done;
4569         }
4570 
4571         rc = _rdc_resume(uparms->rdc_set, uparms->options, kstatus);
4572 done:
4573         return (rc);
4574 }
4575 
4576 /*
4577  * if rdc_group_log is called because a volume has failed,
4578  * we must disgard the queue to preserve write ordering.
4579  * later perhaps, we can keep queuing, but we would have to
4580  * rewrite the i/o path to acommodate that. currently, if there
4581  * is a volume failure, the buffers are satisfied remotely and
4582  * there is no way to satisfy them from the current diskq config
4583  * phew, if we do that.. it will be difficult
4584  */
4585 int
4586 rdc_can_queue(rdc_k_info_t *krdc)
4587 {
4588         rdc_k_info_t *p;
4589         rdc_u_info_t *q;
4590 
4591         for (p = krdc->group_next; ; p = p->group_next) {
4592                 q = &rdc_u_info[p->index];
4593                 if (IS_STATE(q, RDC_VOL_FAILED))
4594                         return (0);
4595                 if (p == krdc)
4596                         break;
4597         }
4598         return (1);
4599 }
4600 
4601 /*
4602  * wait here, until all in flight async i/o's have either
4603  * finished or failed. Avoid the race with r_net_state()
4604  * which tells remote end to log.
4605  */
4606 void
4607 rdc_inflwait(rdc_group_t *grp)
4608 {
4609         int bail = RDC_CLNT_TMOUT * 2; /* to include retries */
4610         volatile int *inflitems;
4611 
4612         if (RDC_IS_DISKQ(grp))
4613                 inflitems = (&(grp->diskq.inflitems));
4614         else
4615                 inflitems = (&(grp->ra_queue.inflitems));
4616 
4617         while (*inflitems && (--bail > 0))
4618                 delay(HZ);
4619 }
4620 
4621 void
4622 rdc_group_log(rdc_k_info_t *krdc, int flag, char *why)
4623 {
4624         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
4625         rdc_k_info_t *p;
4626         rdc_u_info_t *q;
4627         int do_group;
4628         int sm, um, md;
4629         disk_queue *dq;
4630 
4631         void (*flag_op)(rdc_u_info_t *urdc, int flag);
4632 
4633         ASSERT(MUTEX_HELD(&krdc->group->lock));
4634 
4635         if (!IS_ENABLED(urdc))
4636                 return;
4637 
4638         rdc_many_enter(krdc);
4639 
4640         if ((flag & RDC_QUEUING) && (!IS_STATE(urdc, RDC_SYNCING)) &&
4641             (rdc_can_queue(krdc))) {
4642                 flag_op = rdc_set_flags; /* keep queuing, link error */
4643                 flag &= ~RDC_FLUSH;
4644         } else {
4645                 flag_op = rdc_clr_flags; /* stop queuing, user request */
4646         }
4647 
4648         do_group = 1;
4649         if (!(rdc_get_vflags(urdc) & RDC_PRIMARY))
4650                 do_group = 0;
4651         else if ((urdc->group_name[0] == 0) ||
4652             (rdc_get_vflags(urdc) & RDC_LOGGING) ||
4653             (rdc_get_vflags(urdc) & RDC_SYNCING))
4654                 do_group = 0;
4655         if (do_group) {
4656                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
4657                         q = &rdc_u_info[p->index];
4658                         if (!IS_ENABLED(q))
4659                                 continue;
4660                         if ((rdc_get_vflags(q) & RDC_LOGGING) ||
4661                             (rdc_get_vflags(q) & RDC_SYNCING)) {
4662                                 do_group = 0;
4663                                 break;
4664                         }
4665                 }
4666         }
4667         if (!do_group && (flag & RDC_FORCE_GROUP))
4668                 do_group = 1;
4669 
4670         rdc_many_exit(krdc);
4671         dq = &krdc->group->diskq;
4672         if (do_group) {
4673 #ifdef DEBUG
4674                 cmn_err(CE_NOTE, "!SNDR:Group point-in-time for grp: %s %s:%s",
4675                     urdc->group_name, urdc->primary.intf, urdc->secondary.intf);
4676 #endif
4677                 DTRACE_PROBE(rdc_diskq_group_PIT);
4678 
4679                 /* Set group logging at the same PIT under rdc_many_lock */
4680                 rdc_many_enter(krdc);
4681                 rdc_set_flags_log(urdc, RDC_LOGGING, why);
4682                 if (RDC_IS_DISKQ(krdc->group))
4683                         flag_op(urdc, RDC_QUEUING);
4684                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
4685                         q = &rdc_u_info[p->index];
4686                         if (!IS_ENABLED(q))
4687                                 continue;
4688                         rdc_set_flags_log(q, RDC_LOGGING,
4689                             "consistency group member following leader");
4690                         if (RDC_IS_DISKQ(p->group))
4691                                 flag_op(q, RDC_QUEUING);
4692                 }
4693 
4694                 rdc_many_exit(krdc);
4695 
4696                 /*
4697                  * This can cause the async threads to fail,
4698                  * which in turn will call rdc_group_log()
4699                  * again. Release the lock and re-aquire.
4700                  */
4701                 rdc_group_exit(krdc);
4702 
4703                 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4704                         delay(2);
4705                 if (!RDC_IS_DISKQ(krdc->group))
4706                         RDC_ZERO_BITREF(krdc);
4707 
4708                 rdc_inflwait(krdc->group);
4709 
4710                 /*
4711                  * a little lazy, but neat. recall dump_alloc_bufs to
4712                  * ensure that the queue pointers & seq are reset properly
4713                  * after we have waited for inflight stuff
4714                  */
4715                 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4716                         delay(2);
4717 
4718                 rdc_group_enter(krdc);
4719                 if (RDC_IS_DISKQ(krdc->group) && (!(flag & RDC_QUEUING))) {
4720                         /* fail or user request */
4721                         RDC_ZERO_BITREF(krdc);
4722                         mutex_enter(&krdc->group->diskq.disk_qlock);
4723                         rdc_init_diskq_header(krdc->group,
4724                             &krdc->group->diskq.disk_hdr);
4725                         SET_QNXTIO(dq, QHEAD(dq));
4726                         mutex_exit(&krdc->group->diskq.disk_qlock);
4727                 }
4728 
4729                 if (flag & RDC_ALLREMOTE) {
4730                         /* Tell other node to start logging */
4731                         if (krdc->lsrv && krdc->intf && !krdc->intf->if_down)
4732                                 (void) rdc_net_state(krdc->index,
4733                                     CCIO_ENABLELOG);
4734                 }
4735 
4736                 if (flag & (RDC_ALLREMOTE | RDC_OTHERREMOTE)) {
4737                         rdc_many_enter(krdc);
4738                         for (p = krdc->group_next; p != krdc;
4739                             p = p->group_next) {
4740                                 if (p->lsrv && krdc->intf &&
4741                                     !krdc->intf->if_down) {
4742                                         (void) rdc_net_state(p->index,
4743                                             CCIO_ENABLELOG);
4744                                 }
4745                         }
4746                         rdc_many_exit(krdc);
4747                 }
4748 
4749                 rdc_write_state(urdc);
4750                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
4751                         q = &rdc_u_info[p->index];
4752                         if (!IS_ENABLED(q))
4753                                 continue;
4754                         rdc_write_state(q);
4755                 }
4756         } else {
4757                 /* No point in time is possible, just deal with single set */
4758 
4759                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
4760                         halt_sync(krdc);
4761                 } else {
4762                         if (rdc_net_getstate(krdc, &sm, &um, &md, TRUE) < 0) {
4763                                 rdc_clr_flags(urdc, RDC_SYNCING);
4764                                 rdc_set_flags_log(urdc, RDC_LOGGING,
4765                                     "failed to read remote state");
4766 
4767                                 rdc_write_state(urdc);
4768                                 while (rdc_dump_alloc_bufs_cd(krdc->index)
4769                                     == EAGAIN)
4770                                         delay(2);
4771                                 if ((RDC_IS_DISKQ(krdc->group)) &&
4772                                     (!(flag & RDC_QUEUING))) { /* fail! */
4773                                         mutex_enter(QLOCK(dq));
4774                                         rdc_init_diskq_header(krdc->group,
4775                                             &krdc->group->diskq.disk_hdr);
4776                                         SET_QNXTIO(dq, QHEAD(dq));
4777                                         mutex_exit(QLOCK(dq));
4778                                 }
4779 
4780                                 return;
4781                         }
4782                 }
4783 
4784                 if (rdc_get_vflags(urdc) & RDC_SYNCING)
4785                         return;
4786 
4787                 if (RDC_IS_DISKQ(krdc->group))
4788                         flag_op(urdc, RDC_QUEUING);
4789 
4790                 if ((RDC_IS_DISKQ(krdc->group)) &&
4791                     (!(flag & RDC_QUEUING))) { /* fail! */
4792                         RDC_ZERO_BITREF(krdc);
4793                         mutex_enter(QLOCK(dq));
4794                         rdc_init_diskq_header(krdc->group,
4795                             &krdc->group->diskq.disk_hdr);
4796                         SET_QNXTIO(dq, QHEAD(dq));
4797                         mutex_exit(QLOCK(dq));
4798                 }
4799 
4800                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
4801                         rdc_set_flags_log(urdc, RDC_LOGGING, why);
4802 
4803                         rdc_write_state(urdc);
4804 
4805                         while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4806                                 delay(2);
4807                         if (!RDC_IS_DISKQ(krdc->group))
4808                                 RDC_ZERO_BITREF(krdc);
4809 
4810                         rdc_inflwait(krdc->group);
4811                         /*
4812                          * a little lazy, but neat. recall dump_alloc_bufs to
4813                          * ensure that the queue pointers & seq are reset
4814                          * properly after we have waited for inflight stuff
4815                          */
4816                         while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN)
4817                                 delay(2);
4818 
4819                         if (flag & RDC_ALLREMOTE) {
4820                                 /* Tell other node to start logging */
4821                                 if (krdc->lsrv && krdc->intf &&
4822                                     !krdc->intf->if_down) {
4823                                         (void) rdc_net_state(krdc->index,
4824                                             CCIO_ENABLELOG);
4825                                 }
4826                         }
4827                 }
4828         }
4829         /*
4830          * just in case any threads were in flight during log cleanup
4831          */
4832         if (RDC_IS_DISKQ(krdc->group)) {
4833                 mutex_enter(QLOCK(dq));
4834                 cv_broadcast(&dq->qfullcv);
4835                 mutex_exit(QLOCK(dq));
4836         }
4837 }
4838 
4839 static int
4840 _rdc_log(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus)
4841 {
4842         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
4843         rdc_srv_t *svp;
4844 
4845         rdc_group_enter(krdc);
4846         if (rdc_check(krdc, rdc_set)) {
4847                 rdc_group_exit(krdc);
4848                 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file,
4849                     rdc_set->secondary.file);
4850                 return (RDC_EALREADY);
4851         }
4852 
4853         svp = krdc->lsrv;
4854         if (rdc_get_vflags(urdc) & RDC_PRIMARY)
4855                 krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr),
4856                     &(urdc->secondary.addr), 1);
4857         else
4858                 krdc->intf = rdc_add_to_if(svp, &(urdc->secondary.addr),
4859                     &(urdc->primary.addr), 0);
4860 
4861         if (!krdc->intf) {
4862                 rdc_group_exit(krdc);
4863                 spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf,
4864                     urdc->secondary.intf);
4865                 return (RDC_EADDTOIF);
4866         }
4867 
4868         rdc_group_log(krdc, RDC_FLUSH | RDC_ALLREMOTE, NULL);
4869 
4870         if (rdc_get_vflags(urdc) & RDC_SYNCING) {
4871                 rdc_group_exit(krdc);
4872                 spcs_s_add(kstatus, RDC_ESYNCING, urdc->primary.file);
4873                 return (RDC_ESYNCING);
4874         }
4875 
4876         rdc_group_exit(krdc);
4877 
4878         return (0);
4879 }
4880 
4881 static int
4882 rdc_log(rdc_config_t *uparms, spcs_s_info_t kstatus)
4883 {
4884         rdc_k_info_t *krdc;
4885         int rc = 0;
4886         int index;
4887 
4888         mutex_enter(&rdc_conf_lock);
4889         index = rdc_lookup_byname(uparms->rdc_set);
4890         if (index >= 0)
4891                 krdc = &rdc_k_info[index];
4892         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4893                 mutex_exit(&rdc_conf_lock);
4894                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4895                     uparms->rdc_set->secondary.file);
4896                 return (RDC_EALREADY);
4897         }
4898 
4899         set_busy(krdc);
4900         if (krdc->type_flag == 0) {
4901                 /* A resume or enable failed */
4902                 wakeup_busy(krdc);
4903                 mutex_exit(&rdc_conf_lock);
4904                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4905                     uparms->rdc_set->secondary.file);
4906                 return (RDC_EALREADY);
4907         }
4908         mutex_exit(&rdc_conf_lock);
4909 
4910         rc = _rdc_log(krdc, uparms->rdc_set, kstatus);
4911 
4912         mutex_enter(&rdc_conf_lock);
4913         wakeup_busy(krdc);
4914         mutex_exit(&rdc_conf_lock);
4915 
4916         return (rc);
4917 }
4918 
4919 
4920 static int
4921 rdc_wait(rdc_config_t *uparms, spcs_s_info_t kstatus)
4922 {
4923         rdc_k_info_t *krdc;
4924         rdc_u_info_t *urdc;
4925         int index;
4926         int need_check = 0;
4927 
4928         mutex_enter(&rdc_conf_lock);
4929         index = rdc_lookup_byname(uparms->rdc_set);
4930         if (index >= 0)
4931                 krdc = &rdc_k_info[index];
4932         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
4933                 mutex_exit(&rdc_conf_lock);
4934                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4935                     uparms->rdc_set->secondary.file);
4936                 return (RDC_EALREADY);
4937         }
4938 
4939         urdc = &rdc_u_info[index];
4940         if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
4941                 mutex_exit(&rdc_conf_lock);
4942                 return (0);
4943         }
4944 
4945         set_busy(krdc);
4946         if (krdc->type_flag == 0) {
4947                 /* A resume or enable failed */
4948                 wakeup_busy(krdc);
4949                 mutex_exit(&rdc_conf_lock);
4950                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4951                     uparms->rdc_set->secondary.file);
4952                 return (RDC_EALREADY);
4953         }
4954         mutex_exit(&rdc_conf_lock);
4955 
4956         rdc_group_enter(krdc);
4957         if (rdc_check(krdc, uparms->rdc_set)) {
4958                 rdc_group_exit(krdc);
4959                 mutex_enter(&rdc_conf_lock);
4960                 wakeup_busy(krdc);
4961                 mutex_exit(&rdc_conf_lock);
4962                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
4963                     uparms->rdc_set->secondary.file);
4964                 return (RDC_EALREADY);
4965         }
4966 
4967         if ((rdc_get_vflags(urdc) & (RDC_SYNCING | RDC_PRIMARY)) !=
4968             (RDC_SYNCING | RDC_PRIMARY)) {
4969                 rdc_group_exit(krdc);
4970                 mutex_enter(&rdc_conf_lock);
4971                 wakeup_busy(krdc);
4972                 mutex_exit(&rdc_conf_lock);
4973                 return (0);
4974         }
4975         if (rdc_get_vflags(urdc) & RDC_SYNCING) {
4976                 need_check = 1;
4977         }
4978         rdc_group_exit(krdc);
4979 
4980         mutex_enter(&net_blk_lock);
4981 
4982         mutex_enter(&rdc_conf_lock);
4983         wakeup_busy(krdc);
4984         mutex_exit(&rdc_conf_lock);
4985 
4986         (void) cv_wait_sig(&krdc->synccv, &net_blk_lock);
4987 
4988         mutex_exit(&net_blk_lock);
4989         if (need_check) {
4990                 if (krdc->sync_done == RDC_COMPLETED) {
4991                         return (0);
4992                 } else if (krdc->sync_done == RDC_FAILED) {
4993                         return (EIO);
4994                 }
4995         }
4996         return (0);
4997 }
4998 
4999 
5000 static int
5001 rdc_health(rdc_config_t *uparms, spcs_s_info_t kstatus, int *rvp)
5002 {
5003         rdc_k_info_t *krdc;
5004         rdc_u_info_t *urdc;
5005         int rc = 0;
5006         int index;
5007 
5008         mutex_enter(&rdc_conf_lock);
5009         index = rdc_lookup_byname(uparms->rdc_set);
5010         if (index >= 0)
5011                 krdc = &rdc_k_info[index];
5012         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5013                 mutex_exit(&rdc_conf_lock);
5014                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5015                     uparms->rdc_set->secondary.file);
5016                 return (RDC_EALREADY);
5017         }
5018 
5019         set_busy(krdc);
5020         if (krdc->type_flag == 0) {
5021                 /* A resume or enable failed */
5022                 wakeup_busy(krdc);
5023                 mutex_exit(&rdc_conf_lock);
5024                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5025                     uparms->rdc_set->secondary.file);
5026                 return (RDC_EALREADY);
5027         }
5028 
5029         mutex_exit(&rdc_conf_lock);
5030 
5031         rdc_group_enter(krdc);
5032         if (rdc_check(krdc, uparms->rdc_set)) {
5033                 rdc_group_exit(krdc);
5034                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5035                     uparms->rdc_set->secondary.file);
5036                 rc = RDC_EALREADY;
5037                 goto done;
5038         }
5039 
5040         urdc = &rdc_u_info[index];
5041         if (rdc_isactive_if(&(urdc->primary.addr), &(urdc->secondary.addr)))
5042                 *rvp = RDC_ACTIVE;
5043         else
5044                 *rvp = RDC_INACTIVE;
5045 
5046         rdc_group_exit(krdc);
5047 
5048 done:
5049         mutex_enter(&rdc_conf_lock);
5050         wakeup_busy(krdc);
5051         mutex_exit(&rdc_conf_lock);
5052 
5053         return (rc);
5054 }
5055 
5056 
5057 static int
5058 rdc_reconfig(rdc_config_t *uparms, spcs_s_info_t kstatus)
5059 {
5060         rdc_k_info_t *krdc;
5061         rdc_u_info_t *urdc;
5062         int rc = -2;
5063         int index;
5064 
5065         mutex_enter(&rdc_conf_lock);
5066         index = rdc_lookup_byname(uparms->rdc_set);
5067         if (index >= 0)
5068                 krdc = &rdc_k_info[index];
5069         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5070                 mutex_exit(&rdc_conf_lock);
5071                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5072                     uparms->rdc_set->secondary.file);
5073                 return (RDC_EALREADY);
5074         }
5075 
5076         urdc = &rdc_u_info[index];
5077         set_busy(krdc);
5078         if (krdc->type_flag == 0) {
5079                 /* A resume or enable failed */
5080                 wakeup_busy(krdc);
5081                 mutex_exit(&rdc_conf_lock);
5082                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5083                     uparms->rdc_set->secondary.file);
5084                 return (RDC_EALREADY);
5085         }
5086 
5087         mutex_exit(&rdc_conf_lock);
5088 
5089         rdc_group_enter(krdc);
5090         if (rdc_check(krdc, uparms->rdc_set)) {
5091                 rdc_group_exit(krdc);
5092                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5093                     uparms->rdc_set->secondary.file);
5094                 rc = RDC_EALREADY;
5095                 goto done;
5096         }
5097         if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd))
5098                 (void) rdc_reset_bitmap(krdc);
5099 
5100         /* Move to a new bitmap if necessary */
5101         if (strncmp(urdc->primary.bitmap, uparms->rdc_set->primary.bitmap,
5102             NSC_MAXPATH) != 0) {
5103                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5104                         rc = rdc_move_bitmap(krdc,
5105                             uparms->rdc_set->primary.bitmap);
5106                 } else {
5107                         (void) strncpy(urdc->primary.bitmap,
5108                             uparms->rdc_set->primary.bitmap, NSC_MAXPATH);
5109                         /* simulate a succesful rdc_move_bitmap */
5110                         rc = 0;
5111                 }
5112         }
5113         if (strncmp(urdc->secondary.bitmap, uparms->rdc_set->secondary.bitmap,
5114             NSC_MAXPATH) != 0) {
5115                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5116                         (void) strncpy(urdc->secondary.bitmap,
5117                             uparms->rdc_set->secondary.bitmap, NSC_MAXPATH);
5118                         /* simulate a succesful rdc_move_bitmap */
5119                         rc = 0;
5120                 } else {
5121                         rc = rdc_move_bitmap(krdc,
5122                             uparms->rdc_set->secondary.bitmap);
5123                 }
5124         }
5125         if (rc == -1) {
5126                 rdc_group_exit(krdc);
5127                 spcs_s_add(kstatus, RDC_EBMPRECONFIG,
5128                     uparms->rdc_set->secondary.intf,
5129                     uparms->rdc_set->secondary.file);
5130                 rc = RDC_EBMPRECONFIG;
5131                 goto done;
5132         }
5133 
5134         /*
5135          * At this point we fail any other type of reconfig
5136          * if not in logging mode and we did not do a bitmap reconfig
5137          */
5138 
5139         if (!(rdc_get_vflags(urdc) & RDC_LOGGING) && rc == -2) {
5140                 /* no other changes possible unless logging */
5141                 rdc_group_exit(krdc);
5142                 spcs_s_add(kstatus, RDC_ENOTLOGGING,
5143                     uparms->rdc_set->primary.intf,
5144                     uparms->rdc_set->primary.file,
5145                     uparms->rdc_set->secondary.intf,
5146                     uparms->rdc_set->secondary.file);
5147                 rc = RDC_ENOTLOGGING;
5148                 goto done;
5149         }
5150         rc = 0;
5151         /* Change direct file if necessary */
5152         if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5153             strncmp(urdc->direct_file, uparms->rdc_set->direct_file,
5154             NSC_MAXPATH)) {
5155                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
5156                         rdc_group_exit(krdc);
5157                         goto notlogging;
5158                 }
5159                 rdc_close_direct(krdc);
5160                 (void) strncpy(urdc->direct_file, uparms->rdc_set->direct_file,
5161                     NSC_MAXPATH);
5162 
5163                 if (urdc->direct_file[0]) {
5164                         if (rdc_open_direct(krdc) == NULL)
5165                                 rdc_set_flags(urdc, RDC_FCAL_FAILED);
5166                         else
5167                                 rdc_clr_flags(urdc, RDC_FCAL_FAILED);
5168                 }
5169         }
5170 
5171         rdc_group_exit(krdc);
5172 
5173         /* Change group if necessary */
5174         if (strncmp(urdc->group_name, uparms->rdc_set->group_name,
5175             NSC_MAXPATH) != 0) {
5176                 char orig_group[NSC_MAXPATH];
5177                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5178                         goto notlogging;
5179                 mutex_enter(&rdc_conf_lock);
5180 
5181                 (void) strncpy(orig_group, urdc->group_name, NSC_MAXPATH);
5182                 (void) strncpy(urdc->group_name, uparms->rdc_set->group_name,
5183                     NSC_MAXPATH);
5184 
5185                 rc = change_group(krdc, uparms->options);
5186                 if (rc == RDC_EQNOADD) {
5187                         mutex_exit(&rdc_conf_lock);
5188                         spcs_s_add(kstatus, RDC_EQNOADD,
5189                             uparms->rdc_set->disk_queue);
5190                         goto done;
5191                 } else if (rc < 0) {
5192                         (void) strncpy(urdc->group_name, orig_group,
5193                             NSC_MAXPATH);
5194                         mutex_exit(&rdc_conf_lock);
5195                         spcs_s_add(kstatus, RDC_EGROUP,
5196                             urdc->primary.intf, urdc->primary.file,
5197                             urdc->secondary.intf, urdc->secondary.file,
5198                             uparms->rdc_set->group_name);
5199                         rc = RDC_EGROUP;
5200                         goto done;
5201                 }
5202 
5203                 mutex_exit(&rdc_conf_lock);
5204 
5205                 if (rc >= 0) {
5206                         if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5207                                 goto notlogging;
5208                         if (uparms->options & RDC_OPT_ASYNC) {
5209                                 mutex_enter(&rdc_conf_lock);
5210                                 krdc->type_flag |= RDC_ASYNCMODE;
5211                                 mutex_exit(&rdc_conf_lock);
5212                                 if (uparms->options & RDC_OPT_PRIMARY)
5213                                         krdc->bitmap_ref =
5214                                             (uchar_t *)kmem_zalloc(
5215                                             (krdc->bitmap_size * BITS_IN_BYTE *
5216                                             BMAP_REF_PREF_SIZE), KM_SLEEP);
5217                                 rdc_group_enter(krdc);
5218                                 rdc_set_flags(urdc, RDC_ASYNC);
5219                                 rdc_group_exit(krdc);
5220                         } else {
5221                                 mutex_enter(&rdc_conf_lock);
5222                                 krdc->type_flag &= ~RDC_ASYNCMODE;
5223                                 mutex_exit(&rdc_conf_lock);
5224                                 rdc_group_enter(krdc);
5225                                 rdc_clr_flags(urdc, RDC_ASYNC);
5226                                 rdc_group_exit(krdc);
5227                                 if (krdc->bitmap_ref) {
5228                                         kmem_free(krdc->bitmap_ref,
5229                                             (krdc->bitmap_size * BITS_IN_BYTE *
5230                                             BMAP_REF_PREF_SIZE));
5231                                         krdc->bitmap_ref = NULL;
5232                                 }
5233                         }
5234                 }
5235         } else {
5236                 if ((((uparms->options & RDC_OPT_ASYNC) == 0) &&
5237                     ((krdc->type_flag & RDC_ASYNCMODE) != 0)) ||
5238                     (((uparms->options & RDC_OPT_ASYNC) != 0) &&
5239                     ((krdc->type_flag & RDC_ASYNCMODE) == 0))) {
5240                         if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5241                                 goto notlogging;
5242 
5243                         if (krdc->group->count > 1) {
5244                                 spcs_s_add(kstatus, RDC_EGROUPMODE);
5245                                 rc = RDC_EGROUPMODE;
5246                                 goto done;
5247                         }
5248                 }
5249 
5250                 /* Switch sync/async if necessary */
5251                 if (krdc->group->count == 1) {
5252                         /* Only member of group. Can change sync/async */
5253                         if (((uparms->options & RDC_OPT_ASYNC) == 0) &&
5254                             ((krdc->type_flag & RDC_ASYNCMODE) != 0)) {
5255                                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5256                                         goto notlogging;
5257                                 /* switch to sync */
5258                                 mutex_enter(&rdc_conf_lock);
5259                                 krdc->type_flag &= ~RDC_ASYNCMODE;
5260                                 if (RDC_IS_DISKQ(krdc->group)) {
5261                                         krdc->group->flags &= ~RDC_DISKQUE;
5262                                         krdc->group->flags |= RDC_MEMQUE;
5263                                         rdc_unintercept_diskq(krdc->group);
5264                                         mutex_enter(&krdc->group->diskqmutex);
5265                                         rdc_close_diskq(krdc->group);
5266                                         mutex_exit(&krdc->group->diskqmutex);
5267                                         bzero(&urdc->disk_queue,
5268                                             sizeof (urdc->disk_queue));
5269                                 }
5270                                 mutex_exit(&rdc_conf_lock);
5271                                 rdc_group_enter(krdc);
5272                                 rdc_clr_flags(urdc, RDC_ASYNC);
5273                                 rdc_group_exit(krdc);
5274                                 if (krdc->bitmap_ref) {
5275                                         kmem_free(krdc->bitmap_ref,
5276                                             (krdc->bitmap_size * BITS_IN_BYTE *
5277                                             BMAP_REF_PREF_SIZE));
5278                                         krdc->bitmap_ref = NULL;
5279                                 }
5280                         } else if (((uparms->options & RDC_OPT_ASYNC) != 0) &&
5281                             ((krdc->type_flag & RDC_ASYNCMODE) == 0)) {
5282                                 if (!(rdc_get_vflags(urdc) & RDC_LOGGING))
5283                                         goto notlogging;
5284                                 /* switch to async */
5285                                 mutex_enter(&rdc_conf_lock);
5286                                 krdc->type_flag |= RDC_ASYNCMODE;
5287                                 mutex_exit(&rdc_conf_lock);
5288                                 if (uparms->options & RDC_OPT_PRIMARY)
5289                                         krdc->bitmap_ref =
5290                                             (uchar_t *)kmem_zalloc(
5291                                             (krdc->bitmap_size * BITS_IN_BYTE *
5292                                             BMAP_REF_PREF_SIZE), KM_SLEEP);
5293                                 rdc_group_enter(krdc);
5294                                 rdc_set_flags(urdc, RDC_ASYNC);
5295                                 rdc_group_exit(krdc);
5296                         }
5297                 }
5298         }
5299         /* Reverse concept of primary and secondary */
5300         if ((uparms->options & RDC_OPT_REVERSE_ROLE) != 0) {
5301                 rdc_set_t rdc_set;
5302                 struct netbuf paddr, saddr;
5303 
5304                 mutex_enter(&rdc_conf_lock);
5305 
5306                 /*
5307                  * Disallow role reversal for advanced configurations
5308                  */
5309 
5310                 if (IS_MANY(krdc) || IS_MULTI(krdc)) {
5311                         mutex_exit(&rdc_conf_lock);
5312                         spcs_s_add(kstatus, RDC_EMASTER, urdc->primary.intf,
5313                             urdc->primary.file, urdc->secondary.intf,
5314                             urdc->secondary.file);
5315                         return (RDC_EMASTER);
5316                 }
5317                 bzero((void *) &rdc_set, sizeof (rdc_set_t));
5318                 dup_rdc_netbuf(&urdc->primary.addr, &saddr);
5319                 dup_rdc_netbuf(&urdc->secondary.addr, &paddr);
5320                 free_rdc_netbuf(&urdc->primary.addr);
5321                 free_rdc_netbuf(&urdc->secondary.addr);
5322                 dup_rdc_netbuf(&saddr, &urdc->secondary.addr);
5323                 dup_rdc_netbuf(&paddr, &urdc->primary.addr);
5324                 free_rdc_netbuf(&paddr);
5325                 free_rdc_netbuf(&saddr);
5326                 /* copy primary parts of urdc to rdc_set field by field */
5327                 (void) strncpy(rdc_set.primary.intf, urdc->primary.intf,
5328                     MAX_RDC_HOST_SIZE);
5329                 (void) strncpy(rdc_set.primary.file, urdc->primary.file,
5330                     NSC_MAXPATH);
5331                 (void) strncpy(rdc_set.primary.bitmap, urdc->primary.bitmap,
5332                     NSC_MAXPATH);
5333 
5334                 /* Now overwrite urdc primary */
5335                 (void) strncpy(urdc->primary.intf, urdc->secondary.intf,
5336                     MAX_RDC_HOST_SIZE);
5337                 (void) strncpy(urdc->primary.file, urdc->secondary.file,
5338                     NSC_MAXPATH);
5339                 (void) strncpy(urdc->primary.bitmap, urdc->secondary.bitmap,
5340                     NSC_MAXPATH);
5341 
5342                 /* Now ovwewrite urdc secondary */
5343                 (void) strncpy(urdc->secondary.intf, rdc_set.primary.intf,
5344                     MAX_RDC_HOST_SIZE);
5345                 (void) strncpy(urdc->secondary.file, rdc_set.primary.file,
5346                     NSC_MAXPATH);
5347                 (void) strncpy(urdc->secondary.bitmap, rdc_set.primary.bitmap,
5348                     NSC_MAXPATH);
5349 
5350                 if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
5351                         rdc_clr_flags(urdc, RDC_PRIMARY);
5352                         if (krdc->intf) {
5353                                 krdc->intf->issecondary = 1;
5354                                 krdc->intf->isprimary = 0;
5355                                 krdc->intf->if_down = 1;
5356                         }
5357                 } else {
5358                         rdc_set_flags(urdc, RDC_PRIMARY);
5359                         if (krdc->intf) {
5360                                 krdc->intf->issecondary = 0;
5361                                 krdc->intf->isprimary = 1;
5362                                 krdc->intf->if_down = 1;
5363                         }
5364                 }
5365 
5366                 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5367                     ((krdc->type_flag & RDC_ASYNCMODE) != 0)) {
5368                         if (!krdc->bitmap_ref)
5369                                 krdc->bitmap_ref =
5370                                     (uchar_t *)kmem_zalloc((krdc->bitmap_size *
5371                                     BITS_IN_BYTE * BMAP_REF_PREF_SIZE),
5372                                     KM_SLEEP);
5373                         if (krdc->bitmap_ref == NULL) {
5374                                 cmn_err(CE_WARN,
5375                                     "!rdc_reconfig: bitmap_ref alloc %"
5376                                     NSC_SZFMT " failed",
5377                                     krdc->bitmap_size * BITS_IN_BYTE *
5378                                     BMAP_REF_PREF_SIZE);
5379                                 mutex_exit(&rdc_conf_lock);
5380                                 return (-1);
5381                         }
5382                 }
5383 
5384                 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
5385                     (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)) {
5386                         /* Primary, so reverse sync needed */
5387                         rdc_many_enter(krdc);
5388                         rdc_clr_flags(urdc, RDC_SYNC_NEEDED);
5389                         rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
5390                         rdc_many_exit(krdc);
5391                 } else if (rdc_get_vflags(urdc) & RDC_RSYNC_NEEDED) {
5392                         /* Secondary, so forward sync needed */
5393                         rdc_many_enter(krdc);
5394                         rdc_clr_flags(urdc, RDC_RSYNC_NEEDED);
5395                         rdc_set_flags(urdc, RDC_SYNC_NEEDED);
5396                         rdc_many_exit(krdc);
5397                 }
5398 
5399                 /*
5400                  * rewrite bitmap header
5401                  */
5402                 rdc_write_state(urdc);
5403                 mutex_exit(&rdc_conf_lock);
5404         }
5405 
5406 done:
5407         mutex_enter(&rdc_conf_lock);
5408         wakeup_busy(krdc);
5409         mutex_exit(&rdc_conf_lock);
5410 
5411         return (rc);
5412 
5413 notlogging:
5414         /* no other changes possible unless logging */
5415         mutex_enter(&rdc_conf_lock);
5416         wakeup_busy(krdc);
5417         mutex_exit(&rdc_conf_lock);
5418         spcs_s_add(kstatus, RDC_ENOTLOGGING, urdc->primary.intf,
5419             urdc->primary.file, urdc->secondary.intf,
5420             urdc->secondary.file);
5421         return (RDC_ENOTLOGGING);
5422 }
5423 
5424 static int
5425 rdc_reset(rdc_config_t *uparms, spcs_s_info_t kstatus)
5426 {
5427         rdc_k_info_t *krdc;
5428         rdc_u_info_t *urdc;
5429         int rc = 0;
5430         int index;
5431         int cleared_error = 0;
5432 
5433         mutex_enter(&rdc_conf_lock);
5434         index = rdc_lookup_byname(uparms->rdc_set);
5435         if (index >= 0)
5436                 krdc = &rdc_k_info[index];
5437         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5438                 mutex_exit(&rdc_conf_lock);
5439                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5440                     uparms->rdc_set->secondary.file);
5441                 return (RDC_EALREADY);
5442         }
5443 
5444         urdc = &rdc_u_info[index];
5445         set_busy(krdc);
5446         if (krdc->type_flag == 0) {
5447                 /* A resume or enable failed */
5448                 wakeup_busy(krdc);
5449                 mutex_exit(&rdc_conf_lock);
5450                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5451                     uparms->rdc_set->secondary.file);
5452                 return (RDC_EALREADY);
5453         }
5454 
5455         mutex_exit(&rdc_conf_lock);
5456 
5457         rdc_group_enter(krdc);
5458         if (rdc_check(krdc, uparms->rdc_set)) {
5459                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5460                     uparms->rdc_set->secondary.file);
5461                 rc = RDC_EALREADY;
5462                 goto done;
5463         }
5464 
5465         if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) {
5466                 if (rdc_reset_bitmap(krdc) == 0)
5467                         cleared_error++;
5468         }
5469 
5470         /* Fix direct file if necessary */
5471         if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && urdc->direct_file[0]) {
5472                 if (rdc_open_direct(krdc) == NULL)
5473                         rdc_set_flags(urdc, RDC_FCAL_FAILED);
5474                 else {
5475                         rdc_clr_flags(urdc, RDC_FCAL_FAILED);
5476                         cleared_error++;
5477                 }
5478         }
5479 
5480         if ((rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
5481                 rdc_many_enter(krdc);
5482                 rdc_clr_flags(urdc, RDC_VOL_FAILED);
5483                 cleared_error++;
5484                 rdc_many_exit(krdc);
5485         }
5486 
5487         if (cleared_error) {
5488                 /* cleared an error so we should be in logging mode */
5489                 rdc_set_flags_log(urdc, RDC_LOGGING, "set reset");
5490         }
5491         rdc_group_exit(krdc);
5492 
5493         if ((rdc_get_vflags(urdc) & RDC_DISKQ_FAILED))
5494                 rdc_unfail_diskq(krdc);
5495 
5496 done:
5497         mutex_enter(&rdc_conf_lock);
5498         wakeup_busy(krdc);
5499         mutex_exit(&rdc_conf_lock);
5500 
5501         return (rc);
5502 }
5503 
5504 
5505 static int
5506 rdc_tunable(rdc_config_t *uparms, spcs_s_info_t kstatus)
5507 {
5508         rdc_k_info_t *krdc;
5509         rdc_u_info_t *urdc;
5510         rdc_k_info_t *p;
5511         rdc_u_info_t *q;
5512         int rc = 0;
5513         int index;
5514 
5515         mutex_enter(&rdc_conf_lock);
5516         index = rdc_lookup_byname(uparms->rdc_set);
5517         if (index >= 0)
5518                 krdc = &rdc_k_info[index];
5519         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5520                 mutex_exit(&rdc_conf_lock);
5521                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5522                     uparms->rdc_set->secondary.file);
5523                 return (RDC_EALREADY);
5524         }
5525 
5526         urdc = &rdc_u_info[index];
5527         set_busy(krdc);
5528         if (krdc->type_flag == 0) {
5529                 /* A resume or enable failed */
5530                 wakeup_busy(krdc);
5531                 mutex_exit(&rdc_conf_lock);
5532                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5533                     uparms->rdc_set->secondary.file);
5534                 return (RDC_EALREADY);
5535         }
5536 
5537         mutex_exit(&rdc_conf_lock);
5538 
5539         rdc_group_enter(krdc);
5540         if (rdc_check(krdc, uparms->rdc_set)) {
5541                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5542                     uparms->rdc_set->secondary.file);
5543                 rc = RDC_EALREADY;
5544                 goto done;
5545         }
5546 
5547         if (uparms->rdc_set->maxqfbas > 0) {
5548                 urdc->maxqfbas = uparms->rdc_set->maxqfbas;
5549                 rdc_write_state(urdc);
5550                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
5551                         q = &rdc_u_info[p->index];
5552                         q->maxqfbas = urdc->maxqfbas;
5553                         rdc_write_state(q);
5554                 }
5555         }
5556 
5557         if (uparms->rdc_set->maxqitems > 0) {
5558                 urdc->maxqitems = uparms->rdc_set->maxqitems;
5559                 rdc_write_state(urdc);
5560                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
5561                         q = &rdc_u_info[p->index];
5562                         q->maxqitems = urdc->maxqitems;
5563                         rdc_write_state(q);
5564                 }
5565         }
5566 
5567         if (uparms->options & RDC_OPT_SET_QNOBLOCK) {
5568                 disk_queue *que;
5569 
5570                 if (!RDC_IS_DISKQ(krdc->group)) {
5571                         spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf,
5572                             urdc->primary.file, urdc->secondary.intf,
5573                             urdc->secondary.file);
5574                         rc = RDC_EQNOQUEUE;
5575                         goto done;
5576                 }
5577 
5578                 que = &krdc->group->diskq;
5579                 mutex_enter(QLOCK(que));
5580                 SET_QSTATE(que, RDC_QNOBLOCK);
5581                 /* queue will fail if this fails */
5582                 (void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED);
5583                 mutex_exit(QLOCK(que));
5584 
5585         }
5586 
5587         if (uparms->options & RDC_OPT_CLR_QNOBLOCK) {
5588                 disk_queue *que;
5589 
5590                 if (!RDC_IS_DISKQ(krdc->group)) {
5591                         spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf,
5592                             urdc->primary.file, urdc->secondary.intf,
5593                             urdc->secondary.file);
5594                         rc = RDC_EQNOQUEUE;
5595                         goto done;
5596                 }
5597                 que = &krdc->group->diskq;
5598                 mutex_enter(QLOCK(que));
5599                 CLR_QSTATE(que, RDC_QNOBLOCK);
5600                 /* queue will fail if this fails */
5601                 (void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED);
5602                 mutex_exit(QLOCK(que));
5603 
5604         }
5605         if (uparms->rdc_set->asyncthr > 0) {
5606                 urdc->asyncthr = uparms->rdc_set->asyncthr;
5607                 rdc_write_state(urdc);
5608                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
5609                         q = &rdc_u_info[p->index];
5610                         q->asyncthr = urdc->asyncthr;
5611                         rdc_write_state(q);
5612                 }
5613         }
5614 
5615         if (uparms->rdc_set->autosync >= 0) {
5616                 if (uparms->rdc_set->autosync == 0)
5617                         urdc->autosync = 0;
5618                 else
5619                         urdc->autosync = 1;
5620 
5621                 rdc_write_state(urdc);
5622 
5623                 /* Changed autosync, so update rest of the group */
5624 
5625                 for (p = krdc->group_next; p != krdc; p = p->group_next) {
5626                         q = &rdc_u_info[p->index];
5627                         q->autosync = urdc->autosync;
5628                         rdc_write_state(q);
5629                 }
5630         }
5631 
5632 done:
5633         rdc_group_exit(krdc);
5634 
5635         mutex_enter(&rdc_conf_lock);
5636         wakeup_busy(krdc);
5637         mutex_exit(&rdc_conf_lock);
5638 
5639         return (rc);
5640 }
5641 
5642 /*
5643  * Yet another standard thing that is not standard ...
5644  */
5645 #ifndef offsetof
5646 #define offsetof(s, m)  ((size_t)(&((s *)0)->m))
5647 #endif
5648 
5649 static int
5650 rdc_status(void *arg, int mode, rdc_config_t *uparms, spcs_s_info_t kstatus)
5651 {
5652         rdc_k_info_t *krdc;
5653         rdc_u_info_t *urdc;
5654         disk_queue *dqp;
5655         int rc = 0;
5656         int index;
5657         char *ptr;
5658         extern int rdc_status_copy32(const void *, void *, size_t, int);
5659 
5660         mutex_enter(&rdc_conf_lock);
5661         index = rdc_lookup_byname(uparms->rdc_set);
5662         if (index >= 0)
5663                 krdc = &rdc_k_info[index];
5664         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5665                 mutex_exit(&rdc_conf_lock);
5666                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5667                     uparms->rdc_set->secondary.file);
5668                 return (RDC_EALREADY);
5669         }
5670 
5671         set_busy(krdc);
5672         if (krdc->type_flag == 0) {
5673                 /* A resume or enable failed */
5674                 wakeup_busy(krdc);
5675                 mutex_exit(&rdc_conf_lock);
5676                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5677                     uparms->rdc_set->secondary.file);
5678                 return (RDC_EALREADY);
5679         }
5680 
5681         mutex_exit(&rdc_conf_lock);
5682 
5683         rdc_group_enter(krdc);
5684         if (rdc_check(krdc, uparms->rdc_set)) {
5685                 rdc_group_exit(krdc);
5686                 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file,
5687                     uparms->rdc_set->secondary.file);
5688                 rc = RDC_EALREADY;
5689                 goto done;
5690         }
5691 
5692         urdc = &rdc_u_info[index];
5693 
5694         /*
5695          * sneak out qstate in urdc->flags
5696          * this is harmless because it's value is not used
5697          * in urdc->flags. the real qstate is kept in
5698          * group->diskq->disk_hdr.h.state
5699          */
5700         if (RDC_IS_DISKQ(krdc->group)) {
5701                 dqp = &krdc->group->diskq;
5702                 if (IS_QSTATE(dqp, RDC_QNOBLOCK))
5703                 urdc->flags |= RDC_QNOBLOCK;
5704         }
5705 
5706         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
5707                 ptr = (char *)arg + offsetof(struct rdc_config32, rdc_set);
5708                 rc = rdc_status_copy32(urdc, ptr, sizeof (struct rdc_set32),
5709                     mode);
5710         } else {
5711                 ptr = (char *)arg + offsetof(struct rdc_config, rdc_set);
5712                 rc = ddi_copyout(urdc, ptr, sizeof (struct rdc_set), mode);
5713         }
5714         /* clear out qstate from flags */
5715         urdc->flags &= ~RDC_QNOBLOCK;
5716 
5717         if (rc)
5718                 rc = EFAULT;
5719 
5720         rdc_group_exit(krdc);
5721 done:
5722         mutex_enter(&rdc_conf_lock);
5723         wakeup_busy(krdc);
5724         mutex_exit(&rdc_conf_lock);
5725 
5726         return (rc);
5727 }
5728 
5729 /*
5730  * Overwrite the bitmap with one supplied by the
5731  * user.
5732  * Copy into all bitmaps that are tracking this volume.
5733  */
5734 
5735 int
5736 rdc_bitmapset(int op, char *sechost, char *secdev, void *bmapaddr, int bmapsz,
5737     nsc_off_t off, int mode)
5738 {
5739         int rc;
5740         rdc_k_info_t *krdc;
5741         int *indexvec;
5742         int index;
5743         int indexit;
5744         kmutex_t **grouplocks;
5745         int i;
5746         int groupind;
5747 
5748         if (off % FBA_SIZE(1)) {
5749                 /* Must be modulo FBA */
5750                 cmn_err(CE_WARN, "!bitmapset: Offset is not on an FBA "
5751                     "boundary %llu", (unsigned long long)off);
5752                 return (EINVAL);
5753         }
5754         if (bmapsz % FBA_SIZE(1)) {
5755                 /* Must be modulo FBA */
5756                 cmn_err(CE_WARN, "!bitmapset: Size is not on an FBA "
5757                     "boundary %d", bmapsz);
5758                 return (EINVAL);
5759         }
5760 
5761         mutex_enter(&rdc_conf_lock);
5762         index = rdc_lookup_byhostdev(sechost, secdev);
5763         if (index >= 0) {
5764                 krdc = &rdc_k_info[index];
5765         }
5766         if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
5767                 rc = ENODEV;
5768                 mutex_exit(&rdc_conf_lock);
5769                 return (rc);
5770         }
5771         indexvec = kmem_alloc(rdc_max_sets * sizeof (int), KM_SLEEP);
5772         grouplocks = kmem_alloc(rdc_max_sets * sizeof (kmutex_t *), KM_SLEEP);
5773 
5774         /*
5775          * I now have this set, and I want to take the group
5776          * lock on it, and all the group locks of all the
5777          * sets on the many and multi-hop links.
5778          * I have to take the many lock while traversing the
5779          * many/multi links.
5780          * I think I also need to set the busy count on this
5781          * set, otherwise when I drop the conf_lock, what
5782          * will stop some other process from coming in and
5783          * issuing a disable?
5784          */
5785         set_busy(krdc);
5786         mutex_exit(&rdc_conf_lock);
5787 
5788 retrylock:
5789         groupind = 0;
5790         indexit = 0;
5791         rdc_many_enter(krdc);
5792         /*
5793          * Take this initial sets group lock first.
5794          */
5795         if (!mutex_tryenter(&krdc->group->lock)) {
5796                 rdc_many_exit(krdc);
5797                 goto retrylock;
5798         }
5799 
5800         grouplocks[groupind] = &krdc->group->lock;
5801         groupind++;
5802 
5803         rc = rdc_checkforbitmap(index, off + bmapsz);
5804         if (rc) {
5805                 goto done;
5806         }
5807         indexvec[indexit] = index;
5808         indexit++;
5809         if (IS_MANY(krdc)) {
5810                 rdc_k_info_t *ktmp;
5811 
5812                 for (ktmp = krdc->many_next; ktmp != krdc;
5813                     ktmp =  ktmp->many_next) {
5814                         /*
5815                          * attempt to take the group lock,
5816                          * if we don't already have it.
5817                          */
5818                         if (ktmp->group == NULL) {
5819                                 rc = ENODEV;
5820                                 goto done;
5821                         }
5822                         for (i = 0; i < groupind; i++) {
5823                                 if (grouplocks[i] == &ktmp->group->lock)
5824                                         /* already have the group lock */
5825                                         break;
5826                         }
5827                         /*
5828                          * didn't find our lock in our collection,
5829                          * attempt to take group lock.
5830                          */
5831                         if (i >= groupind) {
5832                                 if (!mutex_tryenter(&ktmp->group->lock)) {
5833                                         for (i = 0; i < groupind; i++) {
5834                                                 mutex_exit(grouplocks[i]);
5835                                         }
5836                                         rdc_many_exit(krdc);
5837                                         goto retrylock;
5838                                 }
5839                                 grouplocks[groupind] = &ktmp->group->lock;
5840                                 groupind++;
5841                         }
5842                         rc = rdc_checkforbitmap(ktmp->index, off + bmapsz);
5843                         if (rc == 0) {
5844                                 indexvec[indexit] = ktmp->index;
5845                                 indexit++;
5846                         } else {
5847                                 goto done;
5848                         }
5849                 }
5850         }
5851         if (IS_MULTI(krdc)) {
5852                 rdc_k_info_t *kmulti = krdc->multi_next;
5853 
5854                 if (kmulti->group == NULL) {
5855                         rc = ENODEV;
5856                         goto done;
5857                 }
5858                 /*
5859                  * This can't be in our group already.
5860                  */
5861                 if (!mutex_tryenter(&kmulti->group->lock)) {
5862                         for (i = 0; i < groupind; i++) {
5863                                 mutex_exit(grouplocks[i]);
5864                         }
5865                         rdc_many_exit(krdc);
5866                         goto retrylock;
5867                 }
5868                 grouplocks[groupind] = &kmulti->group->lock;
5869                 groupind++;
5870 
5871                 rc = rdc_checkforbitmap(kmulti->index, off + bmapsz);
5872                 if (rc == 0) {
5873                         indexvec[indexit] = kmulti->index;
5874                         indexit++;
5875                 } else {
5876                         goto done;
5877                 }
5878         }
5879         rc = rdc_installbitmap(op, bmapaddr, bmapsz, off, mode, indexvec,
5880             indexit);
5881 done:
5882         for (i = 0; i < groupind; i++) {
5883                 mutex_exit(grouplocks[i]);
5884         }
5885         rdc_many_exit(krdc);
5886         mutex_enter(&rdc_conf_lock);
5887         wakeup_busy(krdc);
5888         mutex_exit(&rdc_conf_lock);
5889         kmem_free(indexvec, rdc_max_sets * sizeof (int));
5890         kmem_free(grouplocks, rdc_max_sets * sizeof (kmutex_t *));
5891         return (rc);
5892 }
5893 
5894 static int
5895 rdc_checkforbitmap(int index, nsc_off_t limit)
5896 {
5897         rdc_k_info_t *krdc;
5898         rdc_u_info_t *urdc;
5899 
5900         krdc = &rdc_k_info[index];
5901         urdc = &rdc_u_info[index];
5902 
5903         if (!IS_ENABLED(urdc)) {
5904                 return (EIO);
5905         }
5906         if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) {
5907                 return (ENXIO);
5908         }
5909         if (krdc->dcio_bitmap == NULL) {
5910                 cmn_err(CE_WARN, "!checkforbitmap: No bitmap for set (%s:%s)",
5911                     urdc->secondary.intf, urdc->secondary.file);
5912                 return (ENOENT);
5913         }
5914         if (limit > krdc->bitmap_size) {
5915                 cmn_err(CE_WARN, "!checkbitmap: Bitmap exceeded, "
5916                     "incore %" NSC_SZFMT " user supplied %" NSC_SZFMT
5917                     " for set (%s:%s)", krdc->bitmap_size,
5918                     limit, urdc->secondary.intf, urdc->secondary.file);
5919                 return (ENOSPC);
5920         }
5921         return (0);
5922 }
5923 
5924 
5925 
5926 /*
5927  * Copy the user supplied bitmap to this set.
5928  */
5929 static int
5930 rdc_installbitmap(int op, void *bmapaddr, int bmapsz,
5931     nsc_off_t off, int mode, int *vec, int veccnt)
5932 {
5933         int rc;
5934         nsc_off_t sfba;
5935         nsc_off_t efba;
5936         nsc_off_t fba;
5937         void *ormem = NULL;
5938         int len;
5939         int left;
5940         int copied;
5941         int index;
5942         rdc_k_info_t *krdc;
5943         rdc_u_info_t *urdc;
5944 
5945         rc = 0;
5946         ormem = kmem_alloc(RDC_MAXDATA, KM_SLEEP);
5947         left = bmapsz;
5948         copied = 0;
5949         while (left > 0) {
5950                 if (left > RDC_MAXDATA) {
5951                         len = RDC_MAXDATA;
5952                 } else {
5953                         len = left;
5954                 }
5955                 if (ddi_copyin((char *)bmapaddr + copied, ormem,
5956                     len, mode)) {
5957                         cmn_err(CE_WARN, "!installbitmap: Copyin failed");
5958                         rc = EFAULT;
5959                         goto out;
5960                 }
5961                 sfba = FBA_NUM(off + copied);
5962                 efba = FBA_NUM(off + copied + len);
5963                 for (index = 0; index < veccnt; index++) {
5964                         krdc = &rdc_k_info[vec[index]];
5965                         urdc = &rdc_u_info[vec[index]];
5966 
5967                         mutex_enter(&krdc->bmapmutex);
5968                         if (op == RDC_BITMAPSET) {
5969                                 bcopy(ormem, krdc->dcio_bitmap + off + copied,
5970                                     len);
5971                         } else {
5972                                 rdc_lor(ormem,
5973                                     krdc->dcio_bitmap + off + copied, len);
5974                         }
5975                         /*
5976                          * Maybe this should be just done once outside of
5977                          * the the loop? (Less work, but leaves a window
5978                          * where the bits_set doesn't match the bitmap).
5979                          */
5980                         urdc->bits_set = RDC_COUNT_BITMAP(krdc);
5981                         mutex_exit(&krdc->bmapmutex);
5982                         if (krdc->bitmap_write > 0) {
5983                                 for (fba = sfba; fba < efba; fba++) {
5984                                         if (rc = rdc_write_bitmap_fba(krdc,
5985                                             fba)) {
5986 
5987                                                 cmn_err(CE_WARN,
5988                                                     "!installbitmap: "
5989                                                     "write_bitmap_fba failed "
5990                                                     "on fba number %" NSC_SZFMT
5991                                                     " set %s:%s", fba,
5992                                                     urdc->secondary.intf,
5993                                                     urdc->secondary.file);
5994                                                 goto out;
5995                                         }
5996                                 }
5997                         }
5998                 }
5999                 copied += len;
6000                 left -= len;
6001         }
6002 out:
6003         kmem_free(ormem, RDC_MAXDATA);
6004         return (rc);
6005 }
6006 
6007 /*
6008  * _rdc_config
6009  */
6010 int
6011 _rdc_config(void *arg, int mode, spcs_s_info_t kstatus, int *rvp)
6012 {
6013         int rc = 0;
6014         struct netbuf fsvaddr, tsvaddr;
6015         struct knetconfig *knconf;
6016         char *p = NULL, *pf = NULL;
6017         struct rdc_config *uap;
6018         STRUCT_DECL(knetconfig, knconf_tmp);
6019         STRUCT_DECL(rdc_config, uparms);
6020         int enable, disable;
6021         int cmd;
6022 
6023 
6024         STRUCT_HANDLE(rdc_set, rs);
6025         STRUCT_HANDLE(rdc_addr, pa);
6026         STRUCT_HANDLE(rdc_addr, sa);
6027 
6028         STRUCT_INIT(uparms, mode);
6029 
6030         bzero(STRUCT_BUF(uparms), STRUCT_SIZE(uparms));
6031         bzero(&fsvaddr, sizeof (fsvaddr));
6032         bzero(&tsvaddr, sizeof (tsvaddr));
6033 
6034         knconf = NULL;
6035 
6036         if (ddi_copyin(arg, STRUCT_BUF(uparms), STRUCT_SIZE(uparms), mode)) {
6037                 return (EFAULT);
6038         }
6039 
6040         STRUCT_SET_HANDLE(rs, mode, STRUCT_FGETP(uparms, rdc_set));
6041         STRUCT_SET_HANDLE(pa, mode, STRUCT_FADDR(rs, primary));
6042         STRUCT_SET_HANDLE(sa, mode, STRUCT_FADDR(rs, secondary));
6043         cmd = STRUCT_FGET(uparms, command);
6044         if (cmd == RDC_CMD_ENABLE || cmd == RDC_CMD_RESUME) {
6045                 fsvaddr.len = STRUCT_FGET(pa, addr.len);
6046                 fsvaddr.maxlen = STRUCT_FGET(pa, addr.maxlen);
6047                 fsvaddr.buf =  kmem_zalloc(fsvaddr.len, KM_SLEEP);
6048 
6049                 if (ddi_copyin(STRUCT_FGETP(pa, addr.buf),
6050                     fsvaddr.buf, fsvaddr.len, mode)) {
6051                         kmem_free(fsvaddr.buf, fsvaddr.len);
6052 #ifdef DEBUG
6053                         cmn_err(CE_WARN, "!copyin failed primary.addr 2");
6054 #endif
6055                         return (EFAULT);
6056                 }
6057 
6058 
6059                 tsvaddr.len = STRUCT_FGET(sa, addr.len);
6060                 tsvaddr.maxlen = STRUCT_FGET(sa, addr.maxlen);
6061                 tsvaddr.buf =  kmem_zalloc(tsvaddr.len, KM_SLEEP);
6062 
6063                 if (ddi_copyin(STRUCT_FGETP(sa, addr.buf),
6064                     tsvaddr.buf, tsvaddr.len, mode)) {
6065 #ifdef DEBUG
6066                         cmn_err(CE_WARN, "!copyin failed secondary addr");
6067 #endif
6068                         kmem_free(fsvaddr.buf, fsvaddr.len);
6069                         kmem_free(tsvaddr.buf, tsvaddr.len);
6070                         return (EFAULT);
6071                 }
6072         } else {
6073                 fsvaddr.len = 0;
6074                 fsvaddr.maxlen = 0;
6075                 fsvaddr.buf =  kmem_zalloc(fsvaddr.len, KM_SLEEP);
6076                 tsvaddr.len = 0;
6077                 tsvaddr.maxlen = 0;
6078                 tsvaddr.buf =  kmem_zalloc(tsvaddr.len, KM_SLEEP);
6079         }
6080 
6081         if (STRUCT_FGETP(uparms, rdc_set->netconfig) != NULL) {
6082                 STRUCT_INIT(knconf_tmp, mode);
6083                 knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP);
6084                 if (ddi_copyin(STRUCT_FGETP(uparms, rdc_set->netconfig),
6085                     STRUCT_BUF(knconf_tmp), STRUCT_SIZE(knconf_tmp), mode)) {
6086 #ifdef DEBUG
6087                         cmn_err(CE_WARN, "!copyin failed netconfig");
6088 #endif
6089                         kmem_free(fsvaddr.buf, fsvaddr.len);
6090                         kmem_free(tsvaddr.buf, tsvaddr.len);
6091                         kmem_free(knconf, sizeof (*knconf));
6092                         return (EFAULT);
6093                 }
6094 
6095                 knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics);
6096                 knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly);
6097                 knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto);
6098 
6099 #ifndef _SunOS_5_6
6100                 if ((mode & DATAMODEL_LP64) == 0) {
6101                         knconf->knc_rdev =
6102                             expldev(STRUCT_FGET(knconf_tmp, knc_rdev));
6103                 } else {
6104 #endif
6105                         knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev);
6106 #ifndef _SunOS_5_6
6107                 }
6108 #endif
6109 
6110                 pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6111                 p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
6112                 rc = ddi_copyin(knconf->knc_protofmly, pf, KNC_STRSIZE, mode);
6113                 if (rc) {
6114 #ifdef DEBUG
6115                         cmn_err(CE_WARN, "!copyin failed parms protofmly");
6116 #endif
6117                         rc = EFAULT;
6118                         goto out;
6119                 }
6120                 rc = ddi_copyin(knconf->knc_proto, p, KNC_STRSIZE, mode);
6121                 if (rc) {
6122 #ifdef DEBUG
6123                         cmn_err(CE_WARN, "!copyin failed parms proto");
6124 #endif
6125                         rc = EFAULT;
6126                         goto out;
6127                 }
6128                 knconf->knc_protofmly = pf;
6129                 knconf->knc_proto = p;
6130         } /* !NULL netconfig */
6131 
6132         uap = kmem_alloc(sizeof (*uap), KM_SLEEP);
6133 
6134         /* copy relevant parts of rdc_config to uap field by field */
6135 
6136         (void) strncpy(uap->rdc_set[0].primary.intf, STRUCT_FGETP(pa, intf),
6137             MAX_RDC_HOST_SIZE);
6138         (void) strncpy(uap->rdc_set[0].primary.file, STRUCT_FGETP(pa, file),
6139             NSC_MAXPATH);
6140         (void) strncpy(uap->rdc_set[0].primary.bitmap, STRUCT_FGETP(pa, bitmap),
6141             NSC_MAXPATH);
6142         uap->rdc_set[0].netconfig = knconf;
6143         uap->rdc_set[0].flags = STRUCT_FGET(uparms, rdc_set->flags);
6144         uap->rdc_set[0].index = STRUCT_FGET(uparms, rdc_set->index);
6145         uap->rdc_set[0].setid = STRUCT_FGET(uparms, rdc_set->setid);
6146         uap->rdc_set[0].sync_pos = STRUCT_FGET(uparms, rdc_set->sync_pos);
6147         uap->rdc_set[0].volume_size = STRUCT_FGET(uparms, rdc_set->volume_size);
6148         uap->rdc_set[0].bits_set = STRUCT_FGET(uparms, rdc_set->bits_set);
6149         uap->rdc_set[0].autosync = STRUCT_FGET(uparms, rdc_set->autosync);
6150         uap->rdc_set[0].maxqfbas = STRUCT_FGET(uparms, rdc_set->maxqfbas);
6151         uap->rdc_set[0].maxqitems = STRUCT_FGET(uparms, rdc_set->maxqitems);
6152         uap->rdc_set[0].asyncthr = STRUCT_FGET(uparms, rdc_set->asyncthr);
6153         uap->rdc_set[0].syshostid = STRUCT_FGET(uparms, rdc_set->syshostid);
6154         uap->rdc_set[0].primary.addr = fsvaddr;              /* struct copy */
6155         uap->rdc_set[0].secondary.addr = tsvaddr;    /* struct copy */
6156 
6157         (void) strncpy(uap->rdc_set[0].secondary.intf, STRUCT_FGETP(sa, intf),
6158             MAX_RDC_HOST_SIZE);
6159         (void) strncpy(uap->rdc_set[0].secondary.file, STRUCT_FGETP(sa, file),
6160             NSC_MAXPATH);
6161         (void) strncpy(uap->rdc_set[0].secondary.bitmap,
6162             STRUCT_FGETP(sa, bitmap), NSC_MAXPATH);
6163 
6164         (void) strncpy(uap->rdc_set[0].direct_file,
6165             STRUCT_FGETP(rs, direct_file), NSC_MAXPATH);
6166 
6167         (void) strncpy(uap->rdc_set[0].group_name, STRUCT_FGETP(rs, group_name),
6168             NSC_MAXPATH);
6169 
6170         (void) strncpy(uap->rdc_set[0].disk_queue, STRUCT_FGETP(rs, disk_queue),
6171             NSC_MAXPATH);
6172 
6173         uap->command = STRUCT_FGET(uparms, command);
6174         uap->options = STRUCT_FGET(uparms, options);
6175 
6176         enable = (uap->command == RDC_CMD_ENABLE ||
6177             uap->command == RDC_CMD_RESUME);
6178         disable = (uap->command == RDC_CMD_DISABLE ||
6179             uap->command == RDC_CMD_SUSPEND);
6180 
6181         /*
6182          * Initialise the threadset if it has not already been done.
6183          *
6184          * This has to be done now, not in rdcattach(), because
6185          * rdcattach() can be called before nskernd is running (eg.
6186          * boot -r) in which case the nst_init() would fail and hence
6187          * the attach would fail.
6188          *
6189          * Threadset creation is locked by the rdc_conf_lock,
6190          * destruction is inherently single threaded as it is done in
6191          * _rdc_unload() which must be the last thing performed by
6192          * rdcdetach().
6193          */
6194 
6195         if (enable && _rdc_ioset == NULL) {
6196                 mutex_enter(&rdc_conf_lock);
6197 
6198                 if (_rdc_ioset == NULL) {
6199                         rc = rdc_thread_configure();
6200                 }
6201 
6202                 mutex_exit(&rdc_conf_lock);
6203 
6204                 if (rc || _rdc_ioset == NULL) {
6205                         spcs_s_add(kstatus, RDC_ENOTHREADS);
6206                         rc = RDC_ENOTHREADS;
6207                         goto outuap;
6208                 }
6209         }
6210         switch (uap->command) {
6211         case RDC_CMD_ENABLE:
6212                 rc = rdc_enable(uap, kstatus);
6213                 break;
6214         case RDC_CMD_DISABLE:
6215                 rc = rdc_disable(uap, kstatus);
6216                 break;
6217         case RDC_CMD_COPY:
6218                 rc = rdc_sync(uap, kstatus);
6219                 break;
6220         case RDC_CMD_LOG:
6221                 rc = rdc_log(uap, kstatus);
6222                 break;
6223         case RDC_CMD_RECONFIG:
6224                 rc = rdc_reconfig(uap, kstatus);
6225                 break;
6226         case RDC_CMD_RESUME:
6227                 rc = rdc_resume(uap, kstatus);
6228                 break;
6229         case RDC_CMD_SUSPEND:
6230                 rc = rdc_suspend(uap, kstatus);
6231                 break;
6232         case RDC_CMD_TUNABLE:
6233                 rc = rdc_tunable(uap, kstatus);
6234                 break;
6235         case RDC_CMD_WAIT:
6236                 rc = rdc_wait(uap, kstatus);
6237                 break;
6238         case RDC_CMD_HEALTH:
6239                 rc = rdc_health(uap, kstatus, rvp);
6240                 break;
6241         case RDC_CMD_STATUS:
6242                 rc = rdc_status(arg, mode, uap, kstatus);
6243                 break;
6244         case RDC_CMD_RESET:
6245                 rc = rdc_reset(uap, kstatus);
6246                 break;
6247         case RDC_CMD_ADDQ:
6248                 rc = rdc_add_diskq(uap, kstatus);
6249                 break;
6250         case RDC_CMD_REMQ:
6251                 if ((rc = rdc_rem_diskq(uap, kstatus)) != 0)
6252                         break;
6253                 /* FALLTHRU */
6254         case RDC_CMD_KILLQ:
6255                 rc = rdc_kill_diskq(uap, kstatus);
6256                 break;
6257         case RDC_CMD_INITQ:
6258                 rc = rdc_init_diskq(uap, kstatus);
6259                 break;
6260 
6261         default:
6262                 rc = EINVAL;
6263                 break;
6264         }
6265 
6266         /*
6267          * Tune the threadset size after a successful rdc_set addition
6268          * or removal.
6269          */
6270         if ((enable || disable) && rc == 0) {
6271                 mutex_enter(&rdc_conf_lock);
6272                 rdc_thread_tune(enable ? 2 : -2);
6273                 mutex_exit(&rdc_conf_lock);
6274         }
6275 outuap:
6276         kmem_free(uap, sizeof (*uap));
6277 out:
6278         kmem_free(fsvaddr.buf, fsvaddr.len);
6279         kmem_free(tsvaddr.buf, tsvaddr.len);
6280         if (pf)
6281                 kmem_free(pf, KNC_STRSIZE);
6282         if (p)
6283                 kmem_free(p, KNC_STRSIZE);
6284         if (knconf)
6285                 kmem_free(knconf, sizeof (*knconf));
6286         return (rc);
6287 }
6288 
6289 
6290 /*
6291  * krdc->group->lock held on entry to halt_sync()
6292  */
6293 static void
6294 halt_sync(rdc_k_info_t *krdc)
6295 {
6296         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
6297 
6298         ASSERT(MUTEX_HELD(&krdc->group->lock));
6299         ASSERT(IS_ENABLED(urdc));
6300 
6301         /*
6302          * If a sync is in progress, halt it
6303          */
6304         if ((rdc_get_vflags(urdc) & RDC_PRIMARY) &&
6305             (krdc->aux_state & RDC_AUXSYNCIP)) {
6306                 krdc->disk_status = 1;
6307 
6308                 while (krdc->disk_status == 1) {
6309                         if (cv_wait_sig(&krdc->haltcv, &krdc->group->lock) == 0)
6310                                 break;
6311                 }
6312         }
6313 }
6314 
6315 /*
6316  * return size in blocks
6317  */
6318 uint64_t
6319 mirror_getsize(int index)
6320 {
6321         rdc_k_info_t *krdc;
6322         rdc_u_info_t *urdc;
6323         int rc, rs;
6324         nsc_size_t size;
6325 
6326         krdc = &rdc_k_info[index];
6327         urdc = &rdc_u_info[index];
6328 
6329         rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL);
6330         rs = nsc_partsize(RDC_U_FD(krdc), &size);
6331         urdc->volume_size = size;
6332         if (rc == 0)
6333                 _rdc_rlse_devs(krdc, RDC_RAW);
6334 
6335         return (rs == 0 ? urdc->volume_size : 0);
6336 }
6337 
6338 
6339 /*
6340  * Create a new dataset for this transfer, and add it to the list
6341  * of datasets via the net_dataset pointer in the krdc.
6342  */
6343 rdc_net_dataset_t *
6344 rdc_net_add_set(int index)
6345 {
6346         rdc_k_info_t *krdc;
6347         rdc_u_info_t *urdc;
6348         rdc_net_dataset_t *dset;
6349 
6350         if (index >= rdc_max_sets) {
6351                 cmn_err(CE_NOTE, "!rdc_net_add_set: bad index %d", index);
6352                 return (NULL);
6353         }
6354         krdc = &rdc_k_info[index];
6355         urdc = &rdc_u_info[index];
6356 
6357         dset = kmem_alloc(sizeof (*dset), KM_NOSLEEP);
6358         if (dset == NULL) {
6359                 cmn_err(CE_NOTE, "!rdc_net_add_set: kmem_alloc failed");
6360                 return (NULL);
6361         }
6362         RDC_DSMEMUSE(sizeof (*dset));
6363         dset->inuse = 1;
6364         dset->nitems = 0;
6365         dset->delpend = 0;
6366         dset->head = NULL;
6367         dset->tail = NULL;
6368         mutex_enter(&krdc->dc_sleep);
6369 
6370         if (!IS_ENABLED(urdc)) {
6371                 /* raced with a disable command */
6372                 kmem_free(dset, sizeof (*dset));
6373                 RDC_DSMEMUSE(-sizeof (*dset));
6374                 mutex_exit(&krdc->dc_sleep);
6375                 return (NULL);
6376         }
6377         /*
6378          * Shared the id generator, (and the locks).
6379          */
6380         mutex_enter(&rdc_net_hnd_id_lock);
6381         if (++rdc_net_hnd_id == 0)
6382                 rdc_net_hnd_id = 1;
6383         dset->id = rdc_net_hnd_id;
6384         mutex_exit(&rdc_net_hnd_id_lock);
6385 
6386 #ifdef DEBUG
6387         if (krdc->net_dataset != NULL) {
6388                 rdc_net_dataset_t *dset2;
6389                 for (dset2 = krdc->net_dataset; dset2; dset2 = dset2->next) {
6390                         if (dset2->id == dset->id) {
6391                                 cmn_err(CE_PANIC,
6392                                     "rdc_net_add_set duplicate id %p:%d %p:%d",
6393                                     (void *)dset, dset->id,
6394                                     (void *)dset2, dset2->id);
6395                         }
6396                 }
6397         }
6398 #endif
6399         dset->next = krdc->net_dataset;
6400         krdc->net_dataset = dset;
6401         mutex_exit(&krdc->dc_sleep);
6402 
6403         return (dset);
6404 }
6405 
6406 /*
6407  * fetch the previously added dataset.
6408  */
6409 rdc_net_dataset_t *
6410 rdc_net_get_set(int index, int id)
6411 {
6412         rdc_k_info_t *krdc;
6413         rdc_net_dataset_t *dset;
6414 
6415         if (index >= rdc_max_sets) {
6416                 cmn_err(CE_NOTE, "!rdc_net_get_set: bad index %d", index);
6417                 return (NULL);
6418         }
6419         krdc = &rdc_k_info[index];
6420 
6421         mutex_enter(&krdc->dc_sleep);
6422 
6423         dset = krdc->net_dataset;
6424         while (dset && (dset->id != id))
6425                 dset = dset->next;
6426 
6427         if (dset) {
6428                 dset->inuse++;
6429         }
6430 
6431         mutex_exit(&krdc->dc_sleep);
6432         return (dset);
6433 }
6434 
6435 /*
6436  * Decrement the inuse counter. Data may be freed.
6437  */
6438 void
6439 rdc_net_put_set(int index, rdc_net_dataset_t *dset)
6440 {
6441         rdc_k_info_t *krdc;
6442 
6443         if (index >= rdc_max_sets) {
6444                 cmn_err(CE_NOTE, "!rdc_net_put_set: bad index %d", index);
6445                 return;
6446         }
6447         krdc = &rdc_k_info[index];
6448 
6449         mutex_enter(&krdc->dc_sleep);
6450         dset->inuse--;
6451         ASSERT(dset->inuse >= 0);
6452         if ((dset->inuse == 0) && (dset->delpend)) {
6453                 rdc_net_free_set(krdc, dset);
6454         }
6455         mutex_exit(&krdc->dc_sleep);
6456 }
6457 
6458 /*
6459  * Mark that we are finished with this set. Decrement inuse
6460  * counter, mark as needing deletion, and
6461  * remove from linked list.
6462  */
6463 void
6464 rdc_net_del_set(int index, rdc_net_dataset_t *dset)
6465 {
6466         rdc_k_info_t *krdc;
6467 
6468         if (index >= rdc_max_sets) {
6469                 cmn_err(CE_NOTE, "!rdc_net_del_set: bad index %d", index);
6470                 return;
6471         }
6472         krdc = &rdc_k_info[index];
6473 
6474         mutex_enter(&krdc->dc_sleep);
6475         dset->inuse--;
6476         ASSERT(dset->inuse >= 0);
6477         dset->delpend = 1;
6478         if (dset->inuse == 0) {
6479                 rdc_net_free_set(krdc, dset);
6480         }
6481         mutex_exit(&krdc->dc_sleep);
6482 }
6483 
6484 /*
6485  * free all the memory associated with this set, and remove from
6486  * list.
6487  * Enters and exits with dc_sleep lock held.
6488  */
6489 
6490 void
6491 rdc_net_free_set(rdc_k_info_t *krdc, rdc_net_dataset_t *dset)
6492 {
6493         rdc_net_dataset_t **dsetp;
6494 #ifdef DEBUG
6495         int found = 0;
6496 #endif
6497 
6498         ASSERT(MUTEX_HELD(&krdc->dc_sleep));
6499         ASSERT(dset);
6500         for (dsetp = &krdc->net_dataset; *dsetp; dsetp = &((*dsetp)->next)) {
6501                 if (*dsetp == dset) {
6502                         *dsetp = dset->next;
6503 #ifdef DEBUG
6504                         found = 1;
6505 #endif
6506                         break;
6507                 }
6508         }
6509 
6510 #ifdef DEBUG
6511         if (found == 0) {
6512                 cmn_err(CE_WARN, "!rdc_net_free_set: Unable to find "
6513                     "dataset 0x%p in krdc list", (void *)dset);
6514         }
6515 #endif
6516         /*
6517          * unlinked from list. Free all the data
6518          */
6519         rdc_ditemsfree(dset);
6520         /*
6521          * free my core.
6522          */
6523         kmem_free(dset, sizeof (*dset));
6524         RDC_DSMEMUSE(-sizeof (*dset));
6525 }
6526 
6527 
6528 /*
6529  * Free all the dataitems and the data it points to.
6530  */
6531 static void
6532 rdc_ditemsfree(rdc_net_dataset_t *dset)
6533 {
6534         rdc_net_dataitem_t *ditem;
6535         rdc_net_dataitem_t *nitem;
6536 
6537         ditem = dset->head;
6538 
6539         while (ditem) {
6540                 nitem = ditem->next;
6541                 kmem_free(ditem->dptr, ditem->mlen);
6542                 RDC_DSMEMUSE(-ditem->mlen);
6543                 dset->nitems--;
6544                 kmem_free(ditem, sizeof (*ditem));
6545                 RDC_DSMEMUSE(-sizeof (*ditem));
6546                 ditem = nitem;
6547         }
6548         ASSERT(dset->nitems == 0);
6549 }
6550 
6551 /*
6552  * allocate and initialize a rdc_aio_t
6553  */
6554 rdc_aio_t *
6555 rdc_aio_tbuf_get(void *n, void *h, int pos, int len, int flag, int index, int s)
6556 {
6557         rdc_aio_t *p;
6558 
6559         p = kmem_zalloc(sizeof (rdc_aio_t), KM_NOSLEEP);
6560         if (p == NULL) {
6561 #ifdef DEBUG
6562                 cmn_err(CE_NOTE, "!_rdcaiotbufget: kmem_alloc failed bp aio");
6563 #endif
6564                 return (NULL);
6565         } else {
6566                 p->next = n; /* overload */
6567                 p->handle = h;
6568                 p->pos = pos;
6569                 p->qpos = -1;
6570                 p->len = len;
6571                 p->flag = flag;
6572                 p->index = index;
6573                 p->iostatus = s; /* overload */
6574                 /* set up seq later, in case thr create fails */
6575         }
6576         return (p);
6577 }
6578 
6579 /*
6580  * rdc_aio_buf_get
6581  * get an aio_buf
6582  */
6583 aio_buf_t *
6584 rdc_aio_buf_get(rdc_buf_t *h, int index)
6585 {
6586         aio_buf_t *p;
6587 
6588         if (index >= rdc_max_sets) {
6589                 cmn_err(CE_NOTE, "!rdc: rdc_aio_buf_get bad index %x", index);
6590                 return (NULL);
6591         }
6592 
6593         mutex_enter(&h->aio_lock);
6594 
6595         p = h->rdc_anon;
6596         while (p && (p->kindex != index))
6597                 p = p->next;
6598 
6599         mutex_exit(&h->aio_lock);
6600         return (p);
6601 }
6602 
6603 /*
6604  * rdc_aio_buf_del
6605  * delete a aio_buf
6606  */
6607 void
6608 rdc_aio_buf_del(rdc_buf_t *h, rdc_k_info_t *krdc)
6609 {
6610         aio_buf_t *p, **pp;
6611 
6612         mutex_enter(&h->aio_lock);
6613 
6614         p = NULL;
6615         for (pp = &h->rdc_anon; *pp; pp = &((*pp)->next)) {
6616                 if ((*pp)->kindex == krdc->index) {
6617                         p = *pp;
6618                         break;
6619                 }
6620         }
6621 
6622         if (p) {
6623                 *pp = p->next;
6624                 kmem_free(p, sizeof (*p));
6625         }
6626         mutex_exit(&h->aio_lock);
6627 }
6628 
6629 /*
6630  * rdc_aio_buf_add
6631  * Add a aio_buf.
6632  */
6633 aio_buf_t *
6634 rdc_aio_buf_add(int index, rdc_buf_t *h)
6635 {
6636         aio_buf_t *p;
6637 
6638         p = kmem_zalloc(sizeof (*p), KM_NOSLEEP);
6639         if (p == NULL) {
6640                 cmn_err(CE_NOTE, "!rdc_aio_buf_add: kmem_alloc failed");
6641                 return (NULL);
6642         }
6643 
6644         p->rdc_abufp = NULL;
6645         p->kindex = index;
6646 
6647         mutex_enter(&h->aio_lock);
6648         p->next = h->rdc_anon;
6649         h->rdc_anon = p;
6650         mutex_exit(&h->aio_lock);
6651         return (p);
6652 }
6653 
6654 /*
6655  * kmemalloc a new group structure and setup the common
6656  * fields.
6657  */
6658 static rdc_group_t *
6659 rdc_newgroup()
6660 {
6661         rdc_group_t *group;
6662 
6663         group = kmem_zalloc(sizeof (rdc_group_t), KM_SLEEP);
6664         group->diskq.lastio = kmem_zalloc(sizeof (rdc_aio_t), KM_SLEEP);
6665         group->count = 1;
6666         group->seq = RDC_NEWSEQ;
6667         group->seqack = RDC_NEWSEQ;
6668         mutex_init(&group->lock, NULL, MUTEX_DRIVER, NULL);
6669         mutex_init(&group->ra_queue.net_qlock, NULL, MUTEX_DRIVER, NULL);
6670         mutex_init(&group->diskqmutex, NULL, MUTEX_DRIVER, NULL);
6671         mutex_init(&group->diskq.disk_qlock, NULL, MUTEX_DRIVER, NULL);
6672         mutex_init(&group->diskq.head_lock, NULL, MUTEX_DRIVER, NULL);
6673         mutex_init(&group->addthrnumlk, NULL, MUTEX_DRIVER, NULL);
6674         cv_init(&group->unregistercv, NULL, CV_DRIVER, NULL);
6675         cv_init(&group->asyncqcv, NULL, CV_DRIVER, NULL);
6676         cv_init(&group->diskq.busycv, NULL, CV_DRIVER, NULL);
6677         cv_init(&group->diskq.qfullcv, NULL, CV_DRIVER, NULL);
6678         cv_init(&group->ra_queue.qfcv, NULL, CV_DRIVER, NULL);
6679         group->ra_queue.qfill_sleeping = RDC_QFILL_DEAD;
6680         group->diskq.busycnt = 0;
6681         ASSERT(group->synccount == 0);               /* group was kmem_zalloc'ed */
6682 
6683         /*
6684          * add default number of threads to the flusher thread set, plus
6685          * one extra thread for the disk queue flusher
6686          */
6687         if (nst_add_thread(_rdc_flset, 3) != 3)
6688                 cmn_err(CE_NOTE, "!rdc_newgroup: nst_add_thread failed");
6689 
6690         return (group);
6691 }
6692 
6693 void
6694 rdc_delgroup(rdc_group_t *group)
6695 {
6696 
6697         ASSERT(group->asyncstall == 0);
6698         ASSERT(group->rdc_thrnum == 0);
6699         ASSERT(group->count == 0);
6700         ASSERT(MUTEX_HELD(&rdc_many_lock));
6701 
6702         mutex_enter(&group->ra_queue.net_qlock);
6703         rdc_sleepqdiscard(group);
6704         mutex_exit(&group->ra_queue.net_qlock);
6705 
6706         /* try to remove flusher threads that this group added to _rdc_flset */
6707         if (nst_del_thread(_rdc_flset, group->rdc_addthrnum + 3) !=
6708             group->rdc_addthrnum + 3)
6709                 cmn_err(CE_NOTE, "!rdc_delgroup: nst_del_thread failed");
6710 
6711         mutex_destroy(&group->lock);
6712         mutex_destroy(&group->ra_queue.net_qlock);
6713         mutex_destroy(&group->diskqmutex);
6714         mutex_destroy(&group->diskq.disk_qlock);
6715         mutex_destroy(&group->diskq.head_lock);
6716         mutex_destroy(&group->addthrnumlk);
6717         cv_destroy(&group->unregistercv);
6718         cv_destroy(&group->asyncqcv);
6719         cv_destroy(&group->diskq.busycv);
6720         cv_destroy(&group->diskq.qfullcv);
6721         cv_destroy(&group->ra_queue.qfcv);
6722         kmem_free(group->diskq.lastio, sizeof (rdc_aio_t));
6723         kmem_free(group, sizeof (rdc_group_t));
6724 }