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