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 /*
  27  * kRPC Server for sndr
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/ksynch.h>
  32 #include <sys/cmn_err.h>
  33 #include <sys/kmem.h>
  34 #include <sys/cred.h>
  35 #include <sys/conf.h>
  36 #include <sys/stream.h>
  37 #include <sys/errno.h>
  38 
  39 #include <sys/unistat/spcs_s.h>
  40 #include <sys/unistat/spcs_s_k.h>
  41 #include <sys/unistat/spcs_errors.h>
  42 
  43 #ifdef _SunOS_2_6
  44 /*
  45  * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we
  46  * define enum_t here as it is all we need from rpc/types.h
  47  * anyway and make it look like we included it. Yuck.
  48  */
  49 #define _RPC_TYPES_H
  50 typedef int enum_t;
  51 #else
  52 #ifndef DS_DDICT
  53 #include <rpc/types.h>
  54 #endif
  55 #endif /* _SunOS_2_6 */
  56 
  57 #ifndef DS_DDICT
  58 #include <rpc/auth.h>
  59 #include <rpc/svc.h>
  60 #include <rpc/xdr.h>
  61 #endif
  62 #include <sys/ddi.h>
  63 #include <sys/nsc_thread.h>
  64 #ifdef DS_DDICT
  65 #include <sys/nsctl/contract.h>
  66 #endif
  67 #include <sys/nsctl/nsctl.h>
  68 #include <sys/ncall/ncall.h>
  69 
  70 #include <sys/sdt.h>              /* dtrace is S10 or later */
  71 
  72 #include "rdc_io.h"
  73 #include "rdc_bitmap.h"
  74 #include "rdcsrv.h"
  75 
  76 static rdc_sleepq_t *rdc_newsleepq();
  77 static void rdc_delsleepq(rdc_sleepq_t *);
  78 static int rdc_sleepq(rdc_group_t *, rdc_sleepq_t *);
  79 static int rdc_combywrite(rdc_k_info_t *, nsc_buf_t *);
  80 static int rdc_writemaxfba(rdc_k_info_t *, rdc_u_info_t *,
  81     rdc_net_dataset_t *, uint_t, int);
  82 static void rdc_setbitind(int *, net_pendvec_t *, rdc_net_dataset_t *, uint_t,
  83     int, int);
  84 static void rdc_dopending(rdc_group_t *, netwriteres *);
  85 static nsc_vec_t *rdc_dset2vec(rdc_net_dataset_t *);
  86 static int rdc_combyread(rdc_k_info_t *, rdc_u_info_t *, nsc_buf_t *);
  87 static int rdc_readmaxfba(int, nsc_off_t, nsc_size_t, int);
  88 static int rdc_dsetcopy(rdc_net_dataset_t *, nsc_vec_t *, nsc_off_t, nsc_size_t,
  89     char *, int, int);
  90 
  91 /* direction for dsetcopy() */
  92 #define COPY_IN         1       /* copy data into the rpc buffer */
  93 #define COPY_OUT        2       /* copy data out of the rpc buffer */
  94 
  95 #define MAX_EINTR_COUNT 1000
  96 
  97 static int rdc_rread_slow;
  98 static rdcsrv_t rdc_srvtab[];
  99 
 100 #ifdef  DEBUG
 101 static int rdc_netwrite6;
 102 static int rdc_stall0;
 103 static int rdc_sleepcnt;
 104 int rdc_datasetcnt;
 105 #endif
 106 
 107 
 108 int
 109 _rdc_sync_event_notify(int operation, char *volume, char *group)
 110 {
 111         int ack = 0;
 112         clock_t time;
 113 
 114         mutex_enter(&rdc_sync_mutex);
 115         mutex_enter(&rdc_sync_event.mutex);
 116 
 117         if (rdc_sync_event.daemon_waiting) {
 118                 rdc_sync_event.daemon_waiting = 0;
 119                 rdc_sync_event.event = operation;
 120                 (void) strncpy(rdc_sync_event.master, volume, NSC_MAXPATH);
 121                 (void) strncpy(rdc_sync_event.group, group, NSC_MAXPATH);
 122 
 123                 cv_signal(&rdc_sync_event.cv);
 124 
 125                 rdc_sync_event.kernel_waiting = 1;
 126                 time = cv_reltimedwait_sig(&rdc_sync_event.done_cv,
 127                     &rdc_sync_event.mutex, rdc_sync_event_timeout,
 128                     TR_CLOCK_TICK);
 129                 if (time == (clock_t)0 || time == (clock_t)-1) {
 130                         /* signalled or timed out */
 131                         ack = 0;
 132                 } else {
 133                         if (rdc_sync_event.ack)
 134                                 ack = 1;
 135                         else
 136                                 ack = -1;
 137                 }
 138         }
 139         mutex_exit(&rdc_sync_event.mutex);
 140         mutex_exit(&rdc_sync_mutex);
 141         return (ack);
 142 }
 143 
 144 
 145 int
 146 _rdc_sync_event_wait(void *arg0, void *arg1, int mode, spcs_s_info_t kstatus,
 147     int *rvp)
 148 {
 149         int rc = 0;
 150         static char master[NSC_MAXPATH];
 151 
 152         master[0] = '\0';
 153         *rvp = 0;
 154         if (ddi_copyin(arg0, master, NSC_MAXPATH, mode))
 155                 return (EFAULT);
 156 
 157         mutex_enter(&rdc_sync_event.mutex);
 158 
 159         if (rdc_sync_event.kernel_waiting &&
 160             (rdc_sync_event.lbolt - nsc_lbolt() < rdc_sync_event_timeout)) {
 161                 /* We haven't been away too long */
 162                 if (master[0])
 163                         rdc_sync_event.ack = 1;
 164                 else
 165                         rdc_sync_event.ack = 0;
 166                 rdc_sync_event.kernel_waiting = 0;
 167                 cv_signal(&rdc_sync_event.done_cv);
 168         }
 169 
 170         rdc_sync_event.daemon_waiting = 1;
 171         if (cv_wait_sig(&rdc_sync_event.cv, &rdc_sync_event.mutex) == 0) {
 172                 rdc_sync_event.daemon_waiting = 0;
 173                 rc = EAGAIN;
 174                 spcs_s_add(kstatus, rc);
 175         } else {
 176                 (void) ddi_copyout(rdc_sync_event.master, arg0, NSC_MAXPATH,
 177                     mode);
 178                 (void) ddi_copyout(rdc_sync_event.group, arg1, NSC_MAXPATH,
 179                     mode);
 180                 *rvp = rdc_sync_event.event;
 181         }
 182         rdc_sync_event.lbolt = nsc_lbolt();
 183         mutex_exit(&rdc_sync_event.mutex);
 184 
 185         return (rc);
 186 }
 187 
 188 
 189 static int
 190 rdc_allow_sec_sync(rdc_u_info_t *urdc, int option)
 191 {
 192         rdc_k_info_t *krdc = &rdc_k_info[urdc->index];
 193         rdc_k_info_t *ktmp;
 194         rdc_u_info_t *utmp;
 195 
 196         if (!IS_MULTI(krdc))
 197                 return (0);
 198 
 199         rdc_many_enter(krdc);
 200 
 201         krdc = krdc->multi_next;
 202         urdc = &rdc_u_info[krdc->index];
 203 
 204         if (!IS_ENABLED(urdc)) {
 205                 rdc_many_exit(krdc);
 206                 return (0);
 207         }
 208 
 209         if (option == CCIO_RSYNC) {
 210 
 211                 /* Reverse sync */
 212 
 213                 if (rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED) {
 214                         /*
 215                          * Reverse sync needed or in progress.
 216                          */
 217                         rdc_many_exit(krdc);
 218                         return (-1);
 219                 }
 220         } else {
 221                 ASSERT(option == CCIO_SLAVE);
 222 
 223                 /* Forward sync */
 224 
 225                 if (rdc_get_mflags(urdc) & RDC_SLAVE) {
 226                         /*
 227                          * Reverse syncing is bad, as that means that data
 228                          * is already flowing to the target of the requested
 229                          * sync operation.
 230                          */
 231                         rdc_many_exit(krdc);
 232                         return (-1);
 233                 }
 234 
 235                 /*
 236                  * Clear "reverse sync needed" on all 1-many volumes.
 237                  * The data on them will be updated from the primary of this
 238                  * requested sync operation, so the aborted reverse sync need
 239                  * not be completed.
 240                  */
 241 
 242                 if ((rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED) ||
 243                     (rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
 244                         rdc_clr_mflags(urdc, RDC_RSYNC_NEEDED);
 245                         rdc_clr_flags(urdc, RDC_VOL_FAILED);
 246                         rdc_write_state(urdc);
 247                 }
 248                 if (IS_MANY(krdc)) {
 249                         for (ktmp = krdc->many_next; ktmp != krdc;
 250                             ktmp = ktmp->many_next) {
 251                                 utmp = &rdc_u_info[ktmp->index];
 252                                 if (!IS_ENABLED(utmp))
 253                                         continue;
 254                                 if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) {
 255                                         rdc_clr_mflags(utmp, RDC_RSYNC_NEEDED);
 256                                         rdc_write_state(utmp);
 257                                 }
 258                         }
 259                 }
 260         }
 261 
 262         rdc_many_exit(krdc);
 263 
 264         return (0);
 265 }
 266 
 267 
 268 /*
 269  * r_net_null
 270  * Proc 0 Null action
 271  */
 272 static void
 273 r_net_null(SVCXPRT *xprt)
 274 {
 275         (void) svc_sendreply(xprt, xdr_void, 0);
 276 }
 277 
 278 /*
 279  * r_net_read
 280  */
 281 static void
 282 r_net_read(SVCXPRT *xprt)
 283 {
 284         readres resp;
 285         rdc_u_info_t *urdc;
 286         struct rread diskio;
 287         char *buffer = NULL;
 288         uchar_t *sv_addr;
 289         nsc_vec_t *vec;
 290         int pos, st;
 291         int nocache;
 292         int sv_len;
 293         nsc_vec_t *vector = NULL;
 294         rdc_net_dataset_t *dset = NULL;
 295         int vecsz = 0;
 296 
 297         st = SVC_GETARGS(xprt, xdr_rread, (char *)&diskio);
 298         if (!st) {
 299                 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
 300                 return;
 301         }
 302         nocache = (diskio.flag & RDC_RREAD_FAIL) ? 0 : NSC_NOCACHE;
 303 
 304         if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
 305                 resp.rr_status = RDCERR_NOENT;
 306                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 307 #ifdef DEBUG
 308                 cmn_err(CE_NOTE,
 309                     "!r_net_read: EPROTO cd out or not enabled");
 310 #endif
 311                 return;
 312         }
 313 
 314         urdc = &rdc_u_info[diskio.cd];
 315 
 316         if (diskio.flag & RDC_RREAD_START) {
 317                 /* setup rpc */
 318                 if (!IS_ENABLED(urdc)) {
 319                         st = 0;
 320                         (void) svc_sendreply(xprt, xdr_int, (char *)&st);
 321                         return;
 322                 }
 323                 st = rdc_readmaxfba(diskio.cd, diskio.pos, diskio.len,
 324                     nocache);
 325 
 326                 if (!svc_sendreply(xprt, xdr_int, (char *)&st)) {
 327                         if (st != 0) {
 328                                 rdc_net_dataset_t *dset;
 329                                 if (dset = rdc_net_get_set(diskio.cd, st)) {
 330                                         rdc_net_del_set(diskio.cd, dset);
 331                                 } else {
 332                                         cmn_err(CE_NOTE, "!r_net_read: get_set "
 333                                             "has failed in cleanup");
 334                                 }
 335                         }
 336                 }
 337                 return;
 338         }
 339 
 340         /* data rpc */
 341 
 342 #ifdef DEBUG
 343         if ((diskio.flag & RDC_RREAD_DATA) == 0) {
 344                 cmn_err(CE_WARN, "!r_net_read: received non-DATA rpc! flag %x",
 345                     diskio.flag);
 346         }
 347 #endif
 348 
 349         dset = rdc_net_get_set(diskio.cd, diskio.idx);
 350         if (dset) {
 351                 vector = rdc_dset2vec(dset);
 352         }
 353         if (vector == NULL) {
 354                 resp.rr_status = RDCERR_NOMEM;
 355                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 356                 goto cleanup;
 357         }
 358         vecsz = (dset->nitems + 1) * sizeof (nsc_vec_t);
 359 
 360         if (!IS_ENABLED(urdc)) {
 361                 resp.rr_status = RDCERR_NOENT;
 362                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 363                 goto cleanup;
 364         }
 365         resp.rr_status = RDC_OK;
 366 
 367         /* find place in vector */
 368         vec = vector;
 369         pos = diskio.pos - dset->pos;
 370 
 371         for (; pos >= FBA_NUM(vec->sv_len); vec++)
 372                 pos -= FBA_NUM(vec->sv_len);
 373 
 374         sv_addr = vec->sv_addr + FBA_SIZE(pos);
 375         sv_len = vec->sv_len - FBA_SIZE(pos);
 376 
 377         /*
 378          * IF the data is in a single sb_vec entry
 379          * THEN
 380          *      we can just point to that
 381          * ELSE
 382          *      we have to alloc a local buffer,
 383          *      copy the data in and the point to
 384          *      the local buffer.
 385          */
 386 
 387         if (sv_len >= FBA_SIZE(diskio.len)) {
 388                 /* fast */
 389                 resp.rr_data = (char *)sv_addr;
 390                 resp.rr_bufsize = FBA_SIZE(diskio.len);
 391         } else {
 392                 /* slow */
 393                 rdc_rread_slow++;       /* rough count */
 394                 resp.rr_bufsize = FBA_SIZE(diskio.len);
 395                 buffer = kmem_alloc(resp.rr_bufsize, KM_NOSLEEP);
 396                 if (!buffer) {
 397                         resp.rr_status = RDCERR_NOMEM;
 398                 } else {
 399                         resp.rr_data = buffer;
 400                         if (!rdc_dsetcopy(dset, vector, diskio.pos, diskio.len,
 401                             resp.rr_data, resp.rr_bufsize, COPY_IN)) {
 402                                 resp.rr_status = RDCERR_NOMEM; /* ??? */
 403                         }
 404                 }
 405         }
 406 
 407         st = svc_sendreply(xprt, xdr_readres, (char *)&resp); /* send data */
 408 
 409 cleanup:
 410 
 411         if (dset) {
 412                 if (!st ||
 413                     (diskio.flag & RDC_RREAD_END) ||
 414                     (resp.rr_status != RDC_OK)) {
 415                         /*
 416                          * RPC reply failed, OR
 417                          * Last RPC for this IO operation, OR
 418                          * We are failing this IO operation.
 419                          *
 420                          * Do cleanup.
 421                          */
 422                         rdc_net_del_set(diskio.cd, dset);
 423                 } else {
 424                         rdc_net_put_set(diskio.cd, dset);
 425                 }
 426         }
 427 
 428         if (buffer)
 429                 kmem_free(buffer, resp.rr_bufsize);
 430         if (vector) {
 431                 kmem_free(vector, vecsz);
 432                 RDC_DSMEMUSE(-vecsz);
 433         }
 434 }
 435 
 436 /*
 437  * r_net_read (v6)
 438  */
 439 static void
 440 r_net_read6(SVCXPRT *xprt)
 441 {
 442         readres resp;
 443         rdc_u_info_t *urdc;
 444         struct rread6 diskio;
 445         char *buffer = NULL;
 446         uchar_t *sv_addr;
 447         nsc_vec_t *vec;
 448         int pos, st;
 449         int nocache;
 450         int sv_len;
 451         nsc_vec_t *vector = NULL;
 452         rdc_net_dataset_t *dset = NULL;
 453         int vecsz = 0;
 454 
 455         st = SVC_GETARGS(xprt, xdr_rread6, (char *)&diskio);
 456         if (!st) {
 457                 (void) svc_sendreply(xprt, xdr_int, (char *)&st);
 458                 return;
 459         }
 460         nocache = (diskio.flag & RDC_RREAD_FAIL) ? 0 : NSC_NOCACHE;
 461 
 462         if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
 463                 resp.rr_status = RDCERR_NOENT;
 464                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 465 #ifdef DEBUG
 466                 cmn_err(CE_NOTE, "!r_net_read6: EPROTO cd out or not enabled");
 467 #endif
 468                 return;
 469         }
 470 
 471         urdc = &rdc_u_info[diskio.cd];
 472 
 473         if (diskio.flag & RDC_RREAD_START) {
 474                 /* setup rpc */
 475                 if (!IS_ENABLED(urdc)) {
 476                         st = 0;
 477                         (void) svc_sendreply(xprt, xdr_int, (char *)&st);
 478                         return;
 479                 }
 480                 st = rdc_readmaxfba(diskio.cd, diskio.pos, diskio.len,
 481                     nocache);
 482 
 483                 if (!svc_sendreply(xprt, xdr_int, (char *)&st)) {
 484                         if (st != 0) {
 485                                 rdc_net_dataset_t *dset;
 486                                 if (dset = rdc_net_get_set(diskio.cd, st)) {
 487                                         rdc_net_del_set(diskio.cd, dset);
 488                                 } else {
 489                                         cmn_err(CE_NOTE, "!read6: get_set "
 490                                             "has failed in cleanup");
 491                                 }
 492                         }
 493                 }
 494                 return;
 495         }
 496 
 497         /* data rpc */
 498 
 499 #ifdef DEBUG
 500         if ((diskio.flag & RDC_RREAD_DATA) == 0) {
 501                 cmn_err(CE_WARN, "!read6: received non-DATA rpc! flag %x",
 502                     diskio.flag);
 503         }
 504 #endif
 505 
 506         dset = rdc_net_get_set(diskio.cd, diskio.idx);
 507         if (dset) {
 508                 vector = rdc_dset2vec(dset);
 509         }
 510         if (vector == NULL) {
 511                 resp.rr_status = RDCERR_NOMEM;
 512                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 513                 goto cleanup;
 514         }
 515         vecsz = (dset->nitems + 1) * sizeof (nsc_vec_t);
 516 
 517         if (!IS_ENABLED(urdc)) {
 518                 resp.rr_status = RDCERR_NOENT;
 519                 (void) svc_sendreply(xprt, xdr_readres, (char *)&resp);
 520                 goto cleanup;
 521         }
 522         resp.rr_status = RDC_OK;
 523 
 524         /* find place in vector */
 525         vec = vector;
 526         pos = diskio.pos - dset->pos;
 527 
 528         for (; pos >= FBA_NUM(vec->sv_len); vec++)
 529                 pos -= FBA_NUM(vec->sv_len);
 530 
 531         sv_addr = vec->sv_addr + FBA_SIZE(pos);
 532         sv_len = vec->sv_len - FBA_SIZE(pos);
 533 
 534         /*
 535          * IF the data is in a single sb_vec entry
 536          * THEN
 537          *      we can just point to that
 538          * ELSE
 539          *      we have to alloc a local buffer,
 540          *      copy the data in and the point to
 541          *      the local buffer.
 542          */
 543 
 544         if (sv_len >= FBA_SIZE(diskio.len)) {
 545                 /* fast */
 546                 resp.rr_data = (char *)sv_addr;
 547                 resp.rr_bufsize = FBA_SIZE(diskio.len);
 548         } else {
 549                 /* slow */
 550                 rdc_rread_slow++;       /* rough count */
 551                 resp.rr_bufsize = FBA_SIZE(diskio.len);
 552                 buffer = kmem_alloc(resp.rr_bufsize, KM_NOSLEEP);
 553                 if (!buffer) {
 554                         resp.rr_status = RDCERR_NOMEM;
 555                 } else {
 556                         resp.rr_data = buffer;
 557                         if (!rdc_dsetcopy(dset, vector, diskio.pos, diskio.len,
 558                             resp.rr_data, resp.rr_bufsize, COPY_IN)) {
 559                                 resp.rr_status = RDCERR_NOMEM; /* ??? */
 560                         }
 561                 }
 562         }
 563 
 564         st = svc_sendreply(xprt, xdr_readres, (char *)&resp); /* send data */
 565 
 566 cleanup:
 567 
 568         if (dset) {
 569                 if (!st ||
 570                     (diskio.flag & RDC_RREAD_END) ||
 571                     (resp.rr_status != RDC_OK)) {
 572                         /*
 573                          * RPC reply failed, OR
 574                          * Last RPC for this IO operation, OR
 575                          * We are failing this IO operation.
 576                          *
 577                          * Do cleanup.
 578                          */
 579                         rdc_net_del_set(diskio.cd, dset);
 580                 } else {
 581                         rdc_net_put_set(diskio.cd, dset);
 582                 }
 583         }
 584 
 585         if (buffer)
 586                 kmem_free(buffer, resp.rr_bufsize);
 587         if (vector) {
 588                 kmem_free(vector, vecsz);
 589                 RDC_DSMEMUSE(-vecsz);
 590         }
 591 }
 592 
 593 /*
 594  * r_net_write (Version 5)
 595  * 0 reply indicates error
 596  * >0 reply indicates a net handle index
 597  * <0 reply indicates errno
 598  * ret net handle index
 599  * ret2 general error
 600  * ret3 multi-hop errors (never returned)
 601  */
 602 static void
 603 r_net_write5(SVCXPRT *xprt)
 604 {
 605         rdc_k_info_t *krdc;
 606         rdc_u_info_t *urdc;
 607         struct net_data5 diskio;
 608         rdc_net_dataset_t *dset;
 609         rdc_net_dataitem_t *ditem;
 610         int nocache;
 611         int ret = 0;
 612         int ret2 = 0;
 613         int st;
 614 
 615         krdc = NULL;
 616         diskio.data.data_val = kmem_alloc(RDC_MAXDATA, KM_NOSLEEP);
 617 
 618         if (!diskio.data.data_val) {
 619                 ret2 = ENOMEM;
 620                 goto out;
 621         }
 622         RDC_DSMEMUSE(RDC_MAXDATA);
 623         st = SVC_GETARGS(xprt, xdr_net_data5, (char *)&diskio);
 624         if (!st) {
 625                 ret2 = ENOMEM;
 626 #ifdef DEBUG
 627                 cmn_err(CE_NOTE, "!r_net_write5:SVC_GETARGS failed: st %d", st);
 628 #endif
 629                 goto out;
 630         }
 631         if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
 632                 ret2 = EPROTO;
 633 #ifdef DEBUG
 634                 cmn_err(CE_NOTE, "!r_net_write6: EPROTO cd out or not enabled");
 635 #endif
 636                 goto out;
 637         }
 638 
 639         nocache = (diskio.flag & RDC_RWRITE_FAIL) ? 0 : NSC_NOCACHE;
 640         krdc = &rdc_k_info[diskio.cd];
 641         urdc = &rdc_u_info[diskio.cd];
 642 
 643         if (!IS_ENABLED(urdc) || IS_STATE(urdc, RDC_LOGGING)) {
 644                 ret2 = EPROTO;
 645 #ifdef DEBUG
 646                 cmn_err(CE_NOTE, "!r_net_write6: cd logging / not enabled (%x)",
 647                     rdc_get_vflags(urdc));
 648 #endif
 649                 krdc = NULL; /* so we don't try to unqueue kstat entry */
 650                 goto out;
 651         }
 652 
 653         if (krdc->io_kstats) {
 654                 mutex_enter(krdc->io_kstats->ks_lock);
 655                 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
 656                 mutex_exit(krdc->io_kstats->ks_lock);
 657         }
 658 
 659 
 660         /* -1 index says allocate a buffer */
 661         if (diskio.idx < 0) {
 662                 dset = rdc_net_add_set(diskio.cd);
 663                 if (dset == NULL) {
 664 #ifdef DEBUG
 665                         cmn_err(CE_NOTE, "!r_net_write5: "
 666                             "failed to add dataset");
 667 #endif
 668                         ret2 = EIO;
 669                         goto out;
 670                 } else {
 671                         ret = dset->id;
 672                         dset->pos = diskio.pos;
 673                         dset->fbalen = diskio.len;
 674                         diskio.idx = ret;
 675                 }
 676                 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
 677                 if (ditem == NULL) {
 678                         ret2 = ENOMEM;
 679                         goto out;
 680                 }
 681                 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
 682                 /*
 683                  * If this is a single transfer, then we don't
 684                  * need to allocate any memory for the data,
 685                  * just point the ditem data pointer to the
 686                  * existing buffer.
 687                  */
 688                 ditem->next = NULL;
 689                 if (diskio.endoblk) {
 690                         ditem->dptr = diskio.data.data_val;
 691                         /*
 692                          * So we don't free it twice.
 693                          */
 694                         diskio.data.data_val = NULL;
 695                         ditem->len = diskio.data.data_len;
 696                         ditem->mlen = RDC_MAXDATA;
 697                 } else {
 698                         /*
 699                          * Allocate the memory for the complete
 700                          * transfer.
 701                          */
 702                         ditem->dptr = kmem_alloc(FBA_SIZE(diskio.len),
 703                             KM_NOSLEEP);
 704                         if (ditem->dptr == NULL) {
 705                                 ret2 = ENOMEM;
 706                                 goto out;
 707                         }
 708                         RDC_DSMEMUSE(FBA_SIZE(diskio.len));
 709                         ditem->len = FBA_SIZE(diskio.len);
 710                         ditem->mlen = ditem->len;
 711 
 712                         /*
 713                          * Copy the data to the new buffer.
 714                          */
 715                         ASSERT(diskio.data.data_len == FBA_SIZE(diskio.nfba));
 716                         bcopy(diskio.data.data_val, ditem->dptr,
 717                             diskio.data.data_len);
 718                         /*
 719                          * free the old data buffer.
 720                          */
 721                         kmem_free(diskio.data.data_val, RDC_MAXDATA);
 722                         RDC_DSMEMUSE(-RDC_MAXDATA);
 723                         diskio.data.data_val = NULL;
 724                 }
 725                 dset->head = ditem;
 726                 dset->tail = ditem;
 727                 dset->nitems++;
 728         } else {
 729                 ret = diskio.idx;
 730                 dset = rdc_net_get_set(diskio.cd, diskio.idx);
 731                 if (dset == NULL) {
 732                         ret2 = EPROTO;
 733 #ifdef DEBUG
 734                         cmn_err(CE_NOTE,
 735                             "!r_net_write5: net_get_set failed cd %d idx %d",
 736                             diskio.cd, diskio.idx);
 737 #endif
 738                         goto out;
 739                 }
 740                 /*
 741                  * We have to copy the data from the rpc buffer
 742                  * to the data in ditem.
 743                  */
 744                 ditem = dset->head;
 745                 bcopy(diskio.data.data_val, (char *)ditem->dptr +
 746                     FBA_SIZE(diskio.sfba - diskio.pos), diskio.data.data_len);
 747 
 748                 kmem_free(diskio.data.data_val, RDC_MAXDATA);
 749                 RDC_DSMEMUSE(-RDC_MAXDATA);
 750                 diskio.data.data_val = NULL;
 751         }
 752         ASSERT(dset);
 753 
 754         if (diskio.endoblk) {
 755                 ret2 = rdc_writemaxfba(krdc, urdc, dset, diskio.seq, nocache);
 756                 rdc_net_del_set(diskio.cd, dset);
 757                 dset = NULL;
 758         }
 759 out:
 760         if (!RDC_SUCCESS(ret2)) {
 761                 if (ret2 > 0)
 762                         ret2 = -ret2;
 763                 DTRACE_PROBE1(rdc_svcwrite5_err_ret2, int, ret2);
 764                 st = svc_sendreply(xprt, xdr_int, (char *)&ret2);
 765         } else
 766                 st = svc_sendreply(xprt, xdr_int, (char *)&ret);
 767 
 768         if (krdc && krdc->io_kstats && ret2 != ENOMEM) {
 769                 mutex_enter(krdc->io_kstats->ks_lock);
 770                 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
 771                 mutex_exit(krdc->io_kstats->ks_lock);
 772         }
 773         /*
 774          * On Error we must cleanup.
 775          * If we have a handle, free it.
 776          * If we have a network handle, free it.
 777          */
 778         if (!st || !RDC_SUCCESS(ret2)) {
 779 #ifdef DEBUG
 780                 cmn_err(CE_WARN, "!r_net_write5 error case? st %x ret %d",
 781                     st, ret2);
 782 #endif
 783                 if (dset) {
 784                         rdc_net_del_set(diskio.cd, dset);
 785                 }
 786 
 787         } else {
 788                 if (dset) {
 789                         rdc_net_put_set(diskio.cd, dset);
 790                 }
 791         }
 792         if (diskio.data.data_val) {
 793                 kmem_free(diskio.data.data_val, RDC_MAXDATA);
 794                 RDC_DSMEMUSE(-RDC_MAXDATA);
 795         }
 796 }
 797 
 798 /*
 799  * r_net_write (Version 6)
 800  * index 0 = error, or net handle index.
 801  * result = 0 , ok.
 802  * result = 1, pending write.
 803  * result < 0 error, and is the -errno.
 804  * ret net handle index.
 805  * ret2 general error.
 806  */
 807 static void
 808 r_net_write6(SVCXPRT *xprt)
 809 {
 810         rdc_k_info_t *krdc;
 811         rdc_u_info_t *urdc;
 812         rdc_group_t *group;
 813         struct net_data6 diskio;
 814         struct netwriteres netret;
 815         rdc_net_dataset_t *dset;
 816         rdc_net_dataitem_t *ditem;
 817         int ret = 0;
 818         int ret2 = 0;
 819         int st;
 820         int nocache;
 821 
 822         netret.vecdata.vecdata_val = NULL;
 823         netret.vecdata.vecdata_len = 0;
 824         dset = NULL;
 825         krdc = NULL;
 826         diskio.data.data_val = kmem_alloc(RDC_MAXDATA, KM_NOSLEEP);
 827 
 828         if (!diskio.data.data_val) {
 829                 ret2 = ENOMEM;
 830                 goto out;
 831         }
 832         RDC_DSMEMUSE(RDC_MAXDATA);
 833         st = SVC_GETARGS(xprt, xdr_net_data6, (char *)&diskio);
 834         if (!st) {
 835                 ret2 = ENOMEM;
 836 #ifdef DEBUG
 837                 cmn_err(CE_NOTE,
 838                     "!r_net_write6:SVC_GETARGS failed: st  %d", st);
 839 #endif
 840                 goto out;
 841         }
 842 
 843         if ((diskio.cd >= rdc_max_sets) || (diskio.cd < 0)) {
 844                 ret2 = EPROTO;
 845 #ifdef DEBUG
 846                 cmn_err(CE_NOTE, "!r_net_write6: EPROTO cd out or not enabled");
 847 #endif
 848                 goto out;
 849         }
 850 
 851         nocache = (diskio.flag & RDC_RWRITE_FAIL) ? 0 : NSC_NOCACHE;
 852         netret.seq = diskio.seq;
 853 
 854         krdc = &rdc_k_info[diskio.cd];
 855         urdc = &rdc_u_info[diskio.cd];
 856 
 857         if (!IS_ENABLED(urdc) || IS_STATE(urdc, RDC_LOGGING)) {
 858                 ret2 = EPROTO;
 859 #ifdef DEBUG
 860                 cmn_err(CE_NOTE,
 861                     "!r_net_write6: cd logging or not enabled (%x)",
 862                     rdc_get_vflags(urdc));
 863 #endif
 864                 krdc = NULL; /* so we don't try to unqueue kstat entry */
 865                 goto out;
 866         }
 867 
 868         group = krdc->group;
 869         if (group == NULL) {
 870                 ret2 = EIO;
 871 #ifdef DEBUG
 872                 cmn_err(CE_NOTE,
 873                     "!r_net_write6: No group structure for set %s:%s",
 874                     urdc->secondary.intf, urdc->secondary.file);
 875 #endif
 876                 krdc = NULL; /* so we don't try to unqueue kstat entry */
 877                 goto out;
 878         }
 879 
 880 #ifdef DEBUG
 881         if (rdc_netwrite6) {
 882                 cmn_err(CE_NOTE,
 883                     "!r_net_write6: idx %d seq %u current seq %u pos %llu "
 884                     "len %d sfba %llu nfba %d endoblk %d",
 885                     diskio.idx, diskio.seq, group->seq,
 886                     (unsigned long long)diskio.pos, diskio.len,
 887                     (unsigned long long)diskio.sfba, diskio.nfba,
 888                     diskio.endoblk);
 889         }
 890 #endif
 891 
 892         if (krdc->io_kstats) {
 893                 mutex_enter(krdc->io_kstats->ks_lock);
 894                 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
 895                 mutex_exit(krdc->io_kstats->ks_lock);
 896         }
 897 
 898         /* -1 index says allocate a net dataset */
 899         if (diskio.idx < 0) {
 900                 dset = rdc_net_add_set(diskio.cd);
 901                 if (dset == NULL) {
 902 #ifdef DEBUG
 903                         cmn_err(CE_NOTE,
 904                             "!r_net_write6: failed to add dataset");
 905 #endif
 906                         ret2 = EIO;
 907                         goto out;
 908                 } else {
 909                         ret = dset->id;
 910                         dset->pos = (nsc_off_t)diskio.pos; /* 64bit! */
 911                         dset->fbalen = diskio.len;
 912                         diskio.idx = ret;
 913                 }
 914                 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
 915                 if (ditem == NULL) {
 916                         ret2 = ENOMEM;
 917                         goto out;
 918                 }
 919                 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
 920                 /*
 921                  * If this is a single transfer, then we don't
 922                  * need to allocate any memory for the data,
 923                  * just point the ditem data pointer to the
 924                  * existing buffer.
 925                  */
 926                 ditem->next = NULL;
 927                 if (diskio.endoblk) {
 928                         ditem->dptr = diskio.data.data_val;
 929                         /*
 930                          * So we don't free it twice.
 931                          */
 932                         diskio.data.data_val = NULL;
 933                         ditem->len = diskio.data.data_len;
 934                         ditem->mlen = RDC_MAXDATA;
 935                 } else {
 936                         /*
 937                          * Allocate the memory for the complete
 938                          * transfer.
 939                          */
 940                         ditem->dptr = kmem_alloc(FBA_SIZE(diskio.len),
 941                             KM_NOSLEEP);
 942                         if (ditem->dptr == NULL) {
 943                                 ret2 = ENOMEM;
 944                                 goto out;
 945                         }
 946                         RDC_DSMEMUSE(FBA_SIZE(diskio.len));
 947                         ditem->len = FBA_SIZE(diskio.len);
 948                         ditem->mlen = ditem->len;
 949 
 950                         /*
 951                          * Copy the data to the new buffer.
 952                          */
 953                         ASSERT(diskio.data.data_len == FBA_SIZE(diskio.nfba));
 954                         bcopy(diskio.data.data_val, ditem->dptr,
 955                             diskio.data.data_len);
 956                         /*
 957                          * free the old data buffer.
 958                          */
 959                         kmem_free(diskio.data.data_val, RDC_MAXDATA);
 960                         RDC_DSMEMUSE(-RDC_MAXDATA);
 961                         diskio.data.data_val = NULL;
 962                 }
 963                 dset->head = ditem;
 964                 dset->tail = ditem;
 965                 dset->nitems++;
 966         } else {
 967                 ret = diskio.idx;
 968                 dset = rdc_net_get_set(diskio.cd, diskio.idx);
 969                 if (dset == NULL) {
 970                         ret2 = EPROTO;
 971 #ifdef DEBUG
 972                         cmn_err(CE_NOTE,
 973                             "!r_net_write6: net_get_set failed cd %d idx %d "
 974                             "packet sequence %u expected seq %u",
 975                             diskio.cd, diskio.idx, diskio.seq, group->seq);
 976 #endif
 977                         goto out;
 978                 }
 979                 /*
 980                  * We have to copy the data from the rpc buffer
 981                  * to the data in ditem.
 982                  */
 983                 ditem = dset->head;
 984                 bcopy(diskio.data.data_val, (char *)ditem->dptr +
 985                     FBA_SIZE(diskio.sfba - diskio.pos), diskio.data.data_len);
 986 
 987                 kmem_free(diskio.data.data_val, RDC_MAXDATA);
 988                 RDC_DSMEMUSE(-RDC_MAXDATA);
 989                 diskio.data.data_val = NULL;
 990         }
 991         ASSERT(dset);
 992 
 993         if (diskio.endoblk) {
 994 #ifdef DEBUG
 995                 if (diskio.seq == (RDC_NEWSEQ + 1)) {
 996                         rdc_stallzero(2);
 997                 }
 998 #endif
 999                 if (diskio.seq == RDC_NEWSEQ) {
1000                         /*
1001                          * magic marker, start of sequence.
1002                          */
1003                         mutex_enter(&group->ra_queue.net_qlock);
1004                         /*
1005                          * see if some threads are stuck.
1006                          */
1007                         if (group->sleepq) {
1008                                 rdc_sleepqdiscard(group);
1009                         }
1010                         group->seqack = RDC_NEWSEQ;
1011                         mutex_exit(&group->ra_queue.net_qlock);
1012                 }
1013 
1014                 if ((diskio.seq != RDC_NOSEQ) && (diskio.seq != RDC_NEWSEQ)) {
1015                         /*
1016                          * see if we are allowed through here to
1017                          * do the write, or if we have to q the
1018                          * request and send back a pending reply.
1019                          */
1020                         mutex_enter(&group->ra_queue.net_qlock);
1021                         if (diskio.seq != group->seq) {
1022                                 rdc_sleepq_t    *sq;
1023                                 int maxseq;
1024 
1025                                 /*
1026                                  * Check that we have room.
1027                                  */
1028                                 maxseq = group->seqack + RDC_MAXPENDQ + 1;
1029                                 if (maxseq < group->seqack) {
1030                                         /*
1031                                          * skip magic values.
1032                                          */
1033                                         maxseq += RDC_NEWSEQ + 1;
1034                                 }
1035                                 if (!RDC_INFRONT(diskio.seq, maxseq)) {
1036 #ifdef  DEBUG
1037                                         cmn_err(CE_WARN, "!net_write6: Queue "
1038                                             "size %d exceeded seqack %u "
1039                                             "this seq %u maxseq %u seq %u",
1040                                             RDC_MAXPENDQ, group->seqack,
1041                                             diskio.seq, maxseq, group->seq);
1042 #endif
1043                                 DTRACE_PROBE2(qsize_exceeded, int, diskio.seq,
1044                                     int, maxseq);
1045                                         if (!(rdc_get_vflags(urdc) &
1046                                             RDC_VOL_FAILED)) {
1047                                                 rdc_many_enter(krdc);
1048                                                 rdc_set_flags(urdc,
1049                                                     RDC_VOL_FAILED);
1050                                                 rdc_many_exit(krdc);
1051                                                 rdc_write_state(urdc);
1052                                         }
1053                                         ret2 = EIO;
1054                                         rdc_sleepqdiscard(group);
1055                                         group->seq = RDC_NEWSEQ;
1056                                         group->seqack = RDC_NEWSEQ;
1057                                         mutex_exit(&group->ra_queue.net_qlock);
1058                                         goto out;
1059                                 }
1060 
1061                                 sq = rdc_newsleepq();
1062                                 sq->seq = diskio.seq;
1063                                 sq->sindex = diskio.cd;
1064                                 sq->pindex = diskio.local_cd;
1065                                 sq->idx = diskio.idx;
1066                                 sq->qpos = diskio.qpos;
1067                                 sq->nocache = nocache;
1068                                 if (rdc_sleepq(group, sq)) {
1069                                         ret2 = EIO;
1070                                         group->seq = RDC_NEWSEQ;
1071                                         group->seqack = RDC_NEWSEQ;
1072                                         rdc_sleepqdiscard(group);
1073                                         mutex_exit(&group->ra_queue.net_qlock);
1074                                         goto out;
1075                                 }
1076                                 rdc_net_put_set(diskio.cd, dset);
1077                                 dset = NULL;
1078                                 if (krdc->io_kstats) {
1079                                         mutex_enter(krdc->io_kstats->ks_lock);
1080                                         kstat_waitq_enter(KSTAT_IO_PTR(krdc->
1081                                             io_kstats));
1082                                         mutex_exit(krdc->io_kstats->ks_lock);
1083                                 }
1084                                 mutex_exit(&group->ra_queue.net_qlock);
1085                                 /*
1086                                  * pending state.
1087                                  */
1088                                 netret.result = 1;
1089                                 netret.index = diskio.idx;
1090                                 st = svc_sendreply(xprt, xdr_netwriteres,
1091                                     (char *)&netret);
1092                                 if (krdc->io_kstats && ret2 != ENOMEM) {
1093                                         mutex_enter(krdc->io_kstats->ks_lock);
1094                                         kstat_runq_exit(KSTAT_IO_PTR(
1095                                             krdc->io_kstats));
1096                                         mutex_exit(krdc->io_kstats->ks_lock);
1097                                 }
1098                                 return;
1099                         }
1100                         mutex_exit(&group->ra_queue.net_qlock);
1101                 }
1102 
1103                 ret2 = rdc_writemaxfba(krdc, urdc, dset, diskio.seq, nocache);
1104                 rdc_net_del_set(diskio.cd, dset);
1105                 dset = NULL;
1106 #ifdef  DEBUG
1107                 if (!RDC_SUCCESS(ret2)) {
1108                         cmn_err(CE_WARN, "!r_net_write6: writemaxfba failed %d",
1109                             ret2);
1110                 }
1111 #endif
1112                 if (diskio.seq != RDC_NOSEQ) {
1113                         mutex_enter(&group->ra_queue.net_qlock);
1114                         group->seq = diskio.seq + 1;
1115                         if (group->seq < diskio.seq)
1116                                 group->seq = RDC_NEWSEQ + 1;
1117                         if (group->sleepq &&
1118                             (group->sleepq->seq == group->seq)) {
1119                                 rdc_dopending(group, &netret);
1120                         }
1121                         group->seqack = group->seq;
1122                         mutex_exit(&group->ra_queue.net_qlock);
1123                 }
1124         }
1125 out:
1126         if (!RDC_SUCCESS(ret2)) {
1127                 DTRACE_PROBE1(rdc_svcwrite6_err_ret2, int, ret2);
1128                 netret.result = -ret2;
1129         } else {
1130                 netret.result = 0;
1131                 netret.index = ret;
1132         }
1133         st = svc_sendreply(xprt, xdr_netwriteres, (char *)&netret);
1134         if (netret.vecdata.vecdata_val) {
1135                 kmem_free(netret.vecdata.vecdata_val,
1136                     netret.vecdata.vecdata_len * sizeof (net_pendvec_t));
1137         }
1138         if (krdc && krdc->io_kstats && ret2 != ENOMEM) {
1139                 mutex_enter(krdc->io_kstats->ks_lock);
1140                 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
1141                 mutex_exit(krdc->io_kstats->ks_lock);
1142         }
1143         /*
1144          * On Error we must cleanup.
1145          * If we have a handle, free it.
1146          * If we have a network handle, free it.
1147          * If we hold the main nsc buffer, free it.
1148          */
1149         if (!st || !RDC_SUCCESS(ret2)) {
1150 #ifdef DEBUG
1151                 cmn_err(CE_WARN, "!r_net_write6 error st %x ret %d seq %u",
1152                     st, ret2, diskio.seq);
1153 #endif
1154                 if (dset) {
1155                         rdc_net_del_set(diskio.cd, dset);
1156                 }
1157         } else {
1158                 if (dset) {
1159                         rdc_net_put_set(diskio.cd, dset);
1160                 }
1161         }
1162         if (diskio.data.data_val) {
1163                 kmem_free(diskio.data.data_val, RDC_MAXDATA);
1164                 RDC_DSMEMUSE(-RDC_MAXDATA);
1165         }
1166 }
1167 
1168 /*
1169  * r_net_ping4
1170  *
1171  * received on the primary.
1172  */
1173 static void
1174 r_net_ping4(SVCXPRT *xprt, struct svc_req *req)
1175 {
1176         struct rdc_ping6 ping;
1177         int e, ret = 0;
1178         rdc_if_t *ip;
1179 
1180         e = SVC_GETARGS(xprt, xdr_rdc_ping6, (char *)&ping);
1181         if (e) {
1182                 mutex_enter(&rdc_ping_lock);
1183 
1184                 /* update specified interface */
1185 
1186                 for (ip = rdc_if_top; ip; ip = ip->next) {
1187                         if ((bcmp(ping.p_ifaddr, ip->ifaddr.buf,
1188                             RDC_MAXADDR) == 0) &&
1189                             (bcmp(ping.s_ifaddr, ip->r_ifaddr.buf,
1190                             RDC_MAXADDR) == 0)) {
1191                                 ip->new_pulse++;
1192                                 ip->deadness = 1;
1193 
1194                                 /* Update the rpc protocol version to use */
1195 
1196                                 ip->rpc_version = req->rq_vers;
1197                                 break;
1198                         }
1199                 }
1200 
1201                 mutex_exit(&rdc_ping_lock);
1202         } else {
1203                 svcerr_decode(xprt);
1204 #ifdef DEBUG
1205                 cmn_err(CE_NOTE, "!SNDR: couldn't get ping4 arguments");
1206 #endif
1207         }
1208 
1209         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1210 }
1211 
1212 /*
1213  * r_net_ping7
1214  *
1215  * received on the primary.
1216  */
1217 static void
1218 r_net_ping7(SVCXPRT *xprt, struct svc_req *req)
1219 {
1220         struct rdc_ping ping;
1221         int e, ret = 0;
1222         rdc_if_t *ip;
1223         unsigned short *sp;
1224 
1225         bzero(&ping, sizeof (struct rdc_ping));
1226         e = SVC_GETARGS(xprt, xdr_rdc_ping, (char *)&ping);
1227         if (e) {
1228                 sp = (unsigned short *)ping.p_ifaddr.buf;
1229                 *sp = ntohs(*sp);
1230                 sp = (unsigned short *)ping.s_ifaddr.buf;
1231                 *sp = ntohs(*sp);
1232                 mutex_enter(&rdc_ping_lock);
1233 
1234                 /* update specified interface */
1235 
1236                 for (ip = rdc_if_top; ip; ip = ip->next) {
1237                         if ((bcmp(ping.p_ifaddr.buf, ip->ifaddr.buf,
1238                             ping.p_ifaddr.len) == 0) &&
1239                             (bcmp(ping.s_ifaddr.buf, ip->r_ifaddr.buf,
1240                             ping.s_ifaddr.len) == 0)) {
1241                                 ip->new_pulse++;
1242                                 ip->deadness = 1;
1243 
1244                                 /* Update the rpc protocol version to use */
1245 
1246                                 ip->rpc_version = req->rq_vers;
1247                                 break;
1248                         }
1249                 }
1250 
1251                 mutex_exit(&rdc_ping_lock);
1252         } else {
1253                 svcerr_decode(xprt);
1254 #ifdef DEBUG
1255                 cmn_err(CE_NOTE, "!SNDR: couldn't get ping7 arguments");
1256 #endif
1257         }
1258 
1259         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1260 }
1261 
1262 
1263 /*
1264  * r_net_bmap (v5)
1265  * WARNING acts as both client and server
1266  */
1267 static void
1268 r_net_bmap(SVCXPRT *xprt)
1269 {
1270         int e, ret = EINVAL;
1271         struct bmap b;
1272         rdc_k_info_t *krdc;
1273         rdc_u_info_t *urdc;
1274         struct bmap6 b6;
1275 
1276 
1277         e = SVC_GETARGS(xprt, xdr_bmap, (char *)&b);
1278         if (e == TRUE) {
1279                 krdc = &rdc_k_info[b.cd];
1280                 urdc = &rdc_u_info[b.cd];
1281                 if (b.cd >= 0 && b.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1282                     ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1283                         krdc->rpc_version = RDC_VERSION5;
1284                         b6.cd = b.cd;
1285                         b6.dual = b.dual;
1286                         b6.size = b.size;
1287                         ret = RDC_SEND_BITMAP(&b6);
1288                 }
1289         }
1290 
1291         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1292 }
1293 
1294 /*
1295  * r_net_bmap (v6)
1296  * WARNING acts as both client and server
1297  */
1298 static void
1299 r_net_bmap6(SVCXPRT *xprt)
1300 {
1301         int e, ret = EINVAL;
1302         struct bmap6 b;
1303         rdc_k_info_t *krdc;
1304         rdc_u_info_t *urdc;
1305 
1306         e = SVC_GETARGS(xprt, xdr_bmap6, (char *)&b);
1307         if (e == TRUE) {
1308                 krdc = &rdc_k_info[b.cd];
1309                 urdc = &rdc_u_info[b.cd];
1310                 if (b.cd >= 0 && b.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1311                     ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1312                         krdc->rpc_version = RDC_VERSION6;
1313                         ret = RDC_SEND_BITMAP(&b);
1314                 }
1315         }
1316         /*
1317          * If the bitmap send has succeeded, clear it.
1318          */
1319         if (ret == 0) {
1320 #ifdef DEBUG
1321                 cmn_err(CE_NOTE, "!Bitmap clear in r_net_bmap6");
1322 #endif
1323                 RDC_ZERO_BITMAP(krdc);
1324                 rdc_many_enter(krdc);
1325                 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1326                 rdc_many_exit(krdc);
1327         }
1328         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1329 }
1330 
1331 /*
1332  * r_net_bdata
1333  */
1334 static void
1335 r_net_bdata(SVCXPRT *xprt)
1336 {
1337         struct net_bdata bd;
1338         struct net_bdata6 bd6;
1339         int e, ret = -1;
1340         rdc_k_info_t *krdc;
1341         rdc_u_info_t *urdc;
1342 
1343         /*
1344          * We have to convert it to the internal form here,
1345          * net_data6, when we know that we will have to convert
1346          * it back to the v5 variant for transmission.
1347          */
1348 
1349         bd.data.data_val = kmem_alloc(BMAP_BLKSIZE, KM_NOSLEEP);
1350         if (bd.data.data_val == NULL)
1351                 goto out;
1352 
1353         e = SVC_GETARGS(xprt, xdr_net_bdata, (char *)&bd);
1354         if (e == TRUE) {
1355                 krdc = &rdc_k_info[bd.cd];
1356                 urdc = &rdc_u_info[bd.cd];
1357                 if (bd.cd >= 0 && bd.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1358                     ((krdc->type_flag & RDC_DISABLEPEND) == 0)) {
1359                         bd6.cd = bd.cd;
1360                         bd6.offset = bd.offset;
1361                         bd6.size = bd.size;
1362                         bd6.data.data_len = bd.data.data_len;
1363                         bd6.data.data_val = bd.data.data_val;
1364                         ret = RDC_OR_BITMAP(&bd6);
1365                 }
1366         }
1367         kmem_free(bd.data.data_val, BMAP_BLKSIZE);
1368 out:
1369         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1370 }
1371 
1372 /*
1373  * r_net_bdata v6
1374  */
1375 static void
1376 r_net_bdata6(SVCXPRT *xprt)
1377 {
1378         struct net_bdata6 bd;
1379         int e, ret = -1;
1380         rdc_k_info_t *krdc;
1381         rdc_u_info_t *urdc;
1382 
1383         /*
1384          * just allocate the bigger block, regardless of < V7
1385          * bd.size will dictate how much we lor into our bitmap
1386          * the other option would be write r_net_bdata7 that is identical
1387          * to this function, but a V7 alloc.
1388          */
1389         bd.data.data_val = kmem_alloc(BMAP_BLKSIZEV7, KM_NOSLEEP);
1390         if (bd.data.data_val == NULL)
1391                 goto out;
1392 
1393         e = SVC_GETARGS(xprt, xdr_net_bdata6, (char *)&bd);
1394         if (e == TRUE) {
1395                 krdc = &rdc_k_info[bd.cd];
1396                 urdc = &rdc_u_info[bd.cd];
1397                 if (bd.cd >= 0 && bd.cd < rdc_max_sets && IS_ENABLED(urdc) &&
1398                     ((krdc->type_flag & RDC_DISABLEPEND) == 0))
1399                         ret = RDC_OR_BITMAP(&bd);
1400         }
1401         /*
1402          * Write the merged bitmap.
1403          */
1404         if ((ret == 0) && bd.endoblk && (krdc->bitmap_write > 0)) {
1405 #ifdef DEBUG
1406                 cmn_err(CE_NOTE, "!r_net_bdata6: Written bitmap for %s:%s",
1407                     urdc->secondary.intf, urdc->secondary.file);
1408 #endif
1409                 ret = rdc_write_bitmap(krdc);
1410         }
1411         kmem_free(bd.data.data_val, BMAP_BLKSIZEV7);
1412 out:
1413         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1414 }
1415 
1416 /*
1417  * r_net_getsize (v5)
1418  */
1419 static void
1420 r_net_getsize(SVCXPRT *xprt)
1421 {
1422         int e, ret = -1, index;
1423         rdc_k_info_t *krdc;
1424 
1425         e = SVC_GETARGS(xprt, xdr_int, (char *)&index);
1426         if (e) {
1427                 krdc = &rdc_k_info[index];
1428                 if (IS_VALID_INDEX(index) && ((krdc->type_flag &
1429                     RDC_DISABLEPEND) == 0))
1430                         ret = mirror_getsize(index);
1431         }
1432         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1433 }
1434 
1435 /*
1436  * r_net_getsize (v6)
1437  */
1438 static void
1439 r_net_getsize6(SVCXPRT *xprt)
1440 {
1441         int e, index;
1442         rdc_k_info_t *krdc;
1443         uint64_t ret;
1444 
1445         /*
1446          * small change in semantics here, as we can't return
1447          * -1 over the wire anymore.
1448          */
1449         ret = 0;
1450 
1451         e = SVC_GETARGS(xprt, xdr_int, (char *)&index);
1452         if (e) {
1453                 krdc = &rdc_k_info[index];
1454                 if (IS_VALID_INDEX(index) && ((krdc->type_flag &
1455                     RDC_DISABLEPEND) == 0))
1456                         ret = mirror_getsize(index);
1457         }
1458         (void) svc_sendreply(xprt, xdr_u_longlong_t, (char *)&ret);
1459 }
1460 
1461 
1462 /*
1463  * r_net_state4
1464  */
1465 static void
1466 r_net_state4(SVCXPRT *xprt)
1467 {
1468         rdc_u_info_t *urdc;
1469         rdc_k_info_t *krdc;
1470         struct set_state4 state;
1471         rdc_set_t rdc_set;
1472         int e, index = -1;
1473         int options;
1474         int log = 0;
1475         int done = 0;
1476         int slave = 0;
1477         int rev_sync = 0;
1478 
1479         e = SVC_GETARGS(xprt, xdr_set_state4, (char *)&state);
1480         if (e) {
1481                 init_rdc_netbuf(&(rdc_set.primary.addr));
1482                 init_rdc_netbuf(&(rdc_set.secondary.addr));
1483                 bcopy(state.netaddr, rdc_set.primary.addr.buf,
1484                     state.netaddrlen);
1485                 bcopy(state.rnetaddr, rdc_set.secondary.addr.buf,
1486                     state.rnetaddrlen);
1487                 rdc_set.primary.addr.len = state.netaddrlen;
1488                 rdc_set.secondary.addr.len = state.rnetaddrlen;
1489                 (void) strncpy(rdc_set.primary.file, state.pfile,
1490                     RDC_MAXNAMLEN);
1491                 (void) strncpy(rdc_set.secondary.file, state.sfile,
1492                     RDC_MAXNAMLEN);
1493                 options = state.flag;
1494                 index = rdc_lookup_byaddr(&rdc_set);
1495 
1496                 krdc = &rdc_k_info[index];
1497 
1498                 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
1499 #ifdef DEBUG
1500                         cmn_err(CE_WARN,
1501                             "!r_net_state: no index or disable pending");
1502 #endif
1503                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1504                         return;
1505                 }
1506 
1507                 urdc = &rdc_u_info[index];
1508 
1509                 if (!IS_ENABLED(urdc)) {
1510                         index = -1;
1511 #ifdef DEBUG
1512                         cmn_err(CE_WARN, "!r_net_state: set not enabled ");
1513 #endif
1514                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1515                         return;
1516                 }
1517 
1518                 if (krdc->lsrv == NULL) {
1519                         cmn_err(CE_NOTE, "!r_net_state: no valid svp\n");
1520                         index = -1;
1521                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1522                         return;
1523                 }
1524                 if (!krdc || !krdc->group) {
1525 #ifdef DEBUG
1526                         cmn_err(CE_NOTE,
1527                             "!r_net_state: no valid krdc %p\n", (void*)krdc);
1528 #endif
1529                         index = -1;
1530                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1531                         return;
1532                 }
1533 
1534                 mutex_enter(&rdc_conf_lock);
1535                 if (krdc->type_flag & RDC_DISABLEPEND) {
1536                         mutex_exit(&rdc_conf_lock);
1537                         index = -1;
1538 #ifdef DEBUG
1539                         cmn_err(CE_WARN, "!r_net_state: disable pending");
1540 #endif
1541                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1542                         return;
1543                 }
1544                 set_busy(krdc);
1545                 mutex_exit(&rdc_conf_lock);
1546 
1547                 rdc_group_enter(krdc);
1548 
1549                 if (rdc_get_vflags(urdc) & RDC_PRIMARY)
1550                         krdc->intf = rdc_add_to_if(krdc->lsrv,
1551                             &(urdc->primary.addr), &(urdc->secondary.addr), 1);
1552                 else
1553                         krdc->intf = rdc_add_to_if(krdc->lsrv,
1554                             &(urdc->secondary.addr), &(urdc->primary.addr), 0);
1555 
1556                 if (options & CCIO_SLAVE) {
1557                         /*
1558                          * mark that the bitmap needs clearing.
1559                          */
1560                         rdc_many_enter(krdc);
1561                         rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1562                         rdc_many_exit(krdc);
1563 
1564                         /* Starting forward sync */
1565                         if (urdc->volume_size == 0)
1566                                 rdc_get_details(krdc);
1567                         if (urdc->volume_size == 0) {
1568                                 index = -1;
1569                                 goto out;
1570                         }
1571                         if (krdc->dcio_bitmap == NULL) {
1572                                 if (rdc_resume_bitmap(krdc) < 0) {
1573                                         index = -1;
1574                                         goto out;
1575                                 }
1576                         }
1577                         if (rdc_allow_sec_sync(urdc, CCIO_SLAVE) < 0) {
1578                                 index = -1;
1579                                 goto out;
1580                         }
1581                         rdc_dump_dsets(index);
1582                         slave = 1;
1583                 } else if (options & CCIO_RSYNC) {
1584                         /*
1585                          * mark that the bitmap needs clearing.
1586                          */
1587                         rdc_many_enter(krdc);
1588                         rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1589                         rdc_many_exit(krdc);
1590 
1591                         /* Starting reverse sync */
1592                         if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED |
1593                             RDC_VOL_FAILED | RDC_BMP_FAILED)) {
1594                                 index = -1;
1595                                 goto out;
1596                         }
1597                         if (rdc_allow_sec_sync(urdc, CCIO_RSYNC) < 0) {
1598                                 index = -1;
1599                                 goto out;
1600                         }
1601                         rdc_dump_dsets(index);
1602                         rev_sync = 1;
1603                 } else if (options & CCIO_DONE) {
1604                         /* Sync completed OK */
1605                         if (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)
1606                                 done = 1;       /* forward sync complete */
1607                         rdc_many_enter(krdc);
1608                         rdc_clr_flags(urdc, RDC_SYNCING | RDC_SYNC_NEEDED);
1609                         rdc_clr_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
1610                         rdc_many_exit(krdc);
1611                         rdc_write_state(urdc);
1612                         if (rdc_get_vflags(urdc) & RDC_CLR_AFTERSYNC) {
1613                                 RDC_ZERO_BITMAP(krdc);
1614                                 rdc_many_enter(krdc);
1615                                 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1616                                 rdc_many_exit(krdc);
1617                         }
1618                 } else if (options & CCIO_ENABLELOG) {
1619                         /* Sync aborted or logging started */
1620                         if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
1621                                 rdc_clr_flags(urdc, RDC_SYNCING);
1622                                 rdc_many_enter(krdc);
1623                                 rdc_clr_mflags(urdc, RDC_SLAVE);
1624                                 rdc_many_exit(krdc);
1625                         }
1626                         log = 1;
1627                 }
1628 out:
1629                 rdc_group_exit(krdc);
1630                 free_rdc_netbuf(&(rdc_set.primary.addr));
1631                 free_rdc_netbuf(&(rdc_set.secondary.addr));
1632 
1633                 if (slave) {
1634                         if (_rdc_sync_event_notify(RDC_SYNC_START,
1635                             urdc->secondary.file, urdc->group_name) >= 0) {
1636                                 rdc_group_enter(krdc);
1637                                 rdc_clr_flags(urdc, RDC_LOGGING);
1638                                 rdc_many_enter(krdc);
1639                                 rdc_clr_flags(urdc, RDC_VOL_FAILED);
1640                                 rdc_set_flags(urdc,
1641                                     RDC_SYNCING | RDC_SYNC_NEEDED);
1642                                 rdc_set_mflags(urdc, RDC_SLAVE);
1643                                 rdc_many_exit(krdc);
1644                                 rdc_write_state(urdc);
1645                                 rdc_group_exit(krdc);
1646                         } else {
1647                                 index = -1;
1648                         }
1649                 } else if (rev_sync) {
1650                         /* Check to see if volume is mounted */
1651                         if (_rdc_sync_event_notify(RDC_RSYNC_START,
1652                             urdc->secondary.file, urdc->group_name) >= 0) {
1653                                 rdc_group_enter(krdc);
1654                                 rdc_clr_flags(urdc, RDC_LOGGING);
1655                                 rdc_set_flags(urdc, RDC_SYNCING);
1656                                 rdc_write_state(urdc);
1657                                 rdc_group_exit(krdc);
1658                         } else {
1659                                 index = -1;
1660                         }
1661                 } else if (done) {
1662 
1663                         /*
1664                          * special case...
1665                          * if this set is in a group, then sndrsyncd will
1666                          * make sure that all sets in the group are REP
1667                          * before updating the config to "update", telling
1668                          * sndrsyncd that it is ok to take anther snapshot
1669                          * on a following sync. The important part about
1670                          * the whole thing is that syncd needs kernel stats.
1671                          * however, this thread must set the set busy to
1672                          * avoid disables. since this is the only
1673                          * sync_event_notify() that will cause a status
1674                          * call back into the kernel, and we will not be
1675                          * accessing the group structure, we have to wakeup now
1676                          */
1677 
1678                         mutex_enter(&rdc_conf_lock);
1679                         wakeup_busy(krdc);
1680                         mutex_exit(&rdc_conf_lock);
1681 
1682                         (void) _rdc_sync_event_notify(RDC_SYNC_DONE,
1683                             urdc->secondary.file, urdc->group_name);
1684                 }
1685         }
1686 
1687         if (!done) {
1688                 mutex_enter(&rdc_conf_lock);
1689                 wakeup_busy(krdc);
1690                 mutex_exit(&rdc_conf_lock);
1691         }
1692 
1693         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1694         if (log) {
1695                 rdc_group_enter(krdc);
1696                 rdc_group_log(krdc, RDC_NOFLUSH | RDC_OTHERREMOTE,
1697                     "Sync aborted or logging started");
1698                 rdc_group_exit(krdc);
1699         }
1700 }
1701 
1702 
1703 /*
1704  * r_net_state
1705  */
1706 static void
1707 r_net_state(SVCXPRT *xprt)
1708 {
1709         rdc_u_info_t *urdc;
1710         rdc_k_info_t *krdc;
1711         struct set_state state;
1712         rdc_set_t rdc_set;
1713         int e, index = -1;
1714         int options;
1715         int log = 0;
1716         int done = 0;
1717         int slave = 0;
1718         int rev_sync = 0;
1719         unsigned short *sp;
1720 
1721         bzero(&state, sizeof (struct set_state));
1722         e = SVC_GETARGS(xprt, xdr_set_state, (char *)&state);
1723         if (e) {
1724                 init_rdc_netbuf(&(rdc_set.primary.addr));
1725                 init_rdc_netbuf(&(rdc_set.secondary.addr));
1726                 sp = (unsigned short *)(state.netaddr.buf);
1727                 *sp = ntohs(*sp);
1728                 bcopy(state.netaddr.buf, rdc_set.primary.addr.buf,
1729                     state.netaddrlen);
1730                 sp = (unsigned short *)(state.rnetaddr.buf);
1731                 *sp = ntohs(*sp);
1732                 bcopy(state.rnetaddr.buf, rdc_set.secondary.addr.buf,
1733                     state.rnetaddrlen);
1734                 rdc_set.primary.addr.len = state.netaddrlen;
1735                 rdc_set.secondary.addr.len = state.rnetaddrlen;
1736                 (void) strncpy(rdc_set.primary.file, state.pfile,
1737                     RDC_MAXNAMLEN);
1738                 (void) strncpy(rdc_set.secondary.file, state.sfile,
1739                     RDC_MAXNAMLEN);
1740                 options = state.flag;
1741                 index = rdc_lookup_byaddr(&rdc_set);
1742 
1743                 krdc = &rdc_k_info[index];
1744 
1745                 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) {
1746 #ifdef DEBUG
1747                         cmn_err(CE_WARN,
1748                             "!r_net_state: no index or disable pending");
1749 #endif
1750                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1751                         return;
1752                 }
1753 
1754                 urdc = &rdc_u_info[index];
1755 
1756                 if (!IS_ENABLED(urdc)) {
1757                         index = -1;
1758 #ifdef DEBUG
1759                         cmn_err(CE_WARN, "!r_net_state: set not enabled ");
1760 #endif
1761                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1762                         return;
1763                 }
1764 
1765                 if (krdc->lsrv == NULL) {
1766                         cmn_err(CE_NOTE, "!r_net_state: no valid svp\n");
1767                         index = -1;
1768                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1769                         return;
1770                 }
1771                 if (!krdc || !krdc->group) {
1772 #ifdef DEBUG
1773                         cmn_err(CE_NOTE,
1774                             "!r_net_state: no valid krdc %p\n", (void*)krdc);
1775 #endif
1776                         index = -1;
1777                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1778                         return;
1779                 }
1780 
1781                 mutex_enter(&rdc_conf_lock);
1782                 if (krdc->type_flag & RDC_DISABLEPEND) {
1783                         mutex_exit(&rdc_conf_lock);
1784                         index = -1;
1785 #ifdef DEBUG
1786                         cmn_err(CE_WARN, "!r_net_state: disable pending");
1787 #endif
1788                         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1789                         return;
1790                 }
1791                 set_busy(krdc);
1792                 mutex_exit(&rdc_conf_lock);
1793 
1794                 rdc_group_enter(krdc);
1795 
1796                 if (rdc_get_vflags(urdc) & RDC_PRIMARY)
1797                         krdc->intf = rdc_add_to_if(krdc->lsrv,
1798                             &(urdc->primary.addr), &(urdc->secondary.addr), 1);
1799                 else
1800                         krdc->intf = rdc_add_to_if(krdc->lsrv,
1801                             &(urdc->secondary.addr), &(urdc->primary.addr), 0);
1802 
1803                 if (options & CCIO_SLAVE) {
1804                         /*
1805                          * mark that the bitmap needs clearing.
1806                          */
1807                         rdc_many_enter(krdc);
1808                         rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1809                         rdc_many_exit(krdc);
1810 
1811                         /* Starting forward sync */
1812                         if (urdc->volume_size == 0)
1813                                 rdc_get_details(krdc);
1814                         if (urdc->volume_size == 0) {
1815                                 index = -1;
1816                                 goto out;
1817                         }
1818                         if (krdc->dcio_bitmap == NULL) {
1819                                 if (rdc_resume_bitmap(krdc) < 0) {
1820                                         index = -1;
1821                                         goto out;
1822                                 }
1823                         }
1824                         if (rdc_allow_sec_sync(urdc, CCIO_SLAVE) < 0) {
1825                                 index = -1;
1826                                 goto out;
1827                         }
1828                         rdc_dump_dsets(index);
1829                         slave = 1;
1830                 } else if (options & CCIO_RSYNC) {
1831                         /*
1832                          * mark that the bitmap needs clearing.
1833                          */
1834                         rdc_many_enter(krdc);
1835                         rdc_set_flags(urdc, RDC_CLR_AFTERSYNC);
1836                         rdc_many_exit(krdc);
1837 
1838                         /* Starting reverse sync */
1839                         if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED |
1840                             RDC_VOL_FAILED | RDC_BMP_FAILED)) {
1841                                 index = -1;
1842                                 goto out;
1843                         }
1844                         if (rdc_allow_sec_sync(urdc, CCIO_RSYNC) < 0) {
1845                                 index = -1;
1846                                 goto out;
1847                         }
1848                         rdc_dump_dsets(index);
1849                         rev_sync = 1;
1850                 } else if (options & CCIO_DONE) {
1851                         /* Sync completed OK */
1852                         if (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)
1853                                 done = 1;       /* forward sync complete */
1854                         rdc_many_enter(krdc);
1855                         rdc_clr_flags(urdc, RDC_SYNCING | RDC_SYNC_NEEDED);
1856                         rdc_clr_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED);
1857                         rdc_many_exit(krdc);
1858                         rdc_write_state(urdc);
1859                         if (rdc_get_vflags(urdc) & RDC_CLR_AFTERSYNC) {
1860                                 RDC_ZERO_BITMAP(krdc);
1861                                 rdc_many_enter(krdc);
1862                                 rdc_clr_flags(urdc, RDC_CLR_AFTERSYNC);
1863                                 rdc_many_exit(krdc);
1864                         }
1865                 } else if (options & CCIO_ENABLELOG) {
1866                         /* Sync aborted or logging started */
1867                         if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) {
1868                                 rdc_clr_flags(urdc, RDC_SYNCING);
1869                                 rdc_many_enter(krdc);
1870                                 rdc_clr_mflags(urdc, RDC_SLAVE);
1871                                 rdc_many_exit(krdc);
1872                         }
1873                         log = 1;
1874                 }
1875 out:
1876                 rdc_group_exit(krdc);
1877                 free_rdc_netbuf(&(rdc_set.primary.addr));
1878                 free_rdc_netbuf(&(rdc_set.secondary.addr));
1879 
1880                 if (slave) {
1881                         if (_rdc_sync_event_notify(RDC_SYNC_START,
1882                             urdc->secondary.file, urdc->group_name) >= 0) {
1883                                 rdc_group_enter(krdc);
1884                                 rdc_clr_flags(urdc, RDC_LOGGING);
1885                                 rdc_many_enter(krdc);
1886                                 rdc_clr_flags(urdc, RDC_VOL_FAILED);
1887                                 rdc_set_flags(urdc,
1888                                     RDC_SYNCING | RDC_SYNC_NEEDED);
1889                                 rdc_set_mflags(urdc, RDC_SLAVE);
1890                                 rdc_many_exit(krdc);
1891                                 rdc_write_state(urdc);
1892                                 rdc_group_exit(krdc);
1893                         } else {
1894                                 index = -1;
1895                         }
1896                 } else if (rev_sync) {
1897                         /* Check to see if volume is mounted */
1898                         if (_rdc_sync_event_notify(RDC_RSYNC_START,
1899                             urdc->secondary.file, urdc->group_name) >= 0) {
1900                                 rdc_group_enter(krdc);
1901                                 rdc_clr_flags(urdc, RDC_LOGGING);
1902                                 rdc_set_flags(urdc, RDC_SYNCING);
1903                                 rdc_write_state(urdc);
1904                                 rdc_group_exit(krdc);
1905                         } else {
1906                                 index = -1;
1907                         }
1908                 } else if (done) {
1909 
1910                         /*
1911                          * special case...
1912                          * if this set is in a group, then sndrsyncd will
1913                          * make sure that all sets in the group are REP
1914                          * before updating the config to "update", telling
1915                          * sndrsyncd that it is ok to take anther snapshot
1916                          * on a following sync. The important part about
1917                          * the whole thing is that syncd needs kernel stats.
1918                          * however, this thread must set the set busy to
1919                          * avoid disables. since this is the only
1920                          * sync_event_notify() that will cause a status
1921                          * call back into the kernel, and we will not be
1922                          * accessing the group structure, we have to wakeup now
1923                          */
1924 
1925                         mutex_enter(&rdc_conf_lock);
1926                         wakeup_busy(krdc);
1927                         mutex_exit(&rdc_conf_lock);
1928 
1929                         (void) _rdc_sync_event_notify(RDC_SYNC_DONE,
1930                             urdc->secondary.file, urdc->group_name);
1931                 }
1932         }
1933 
1934         if (!done) {
1935                 mutex_enter(&rdc_conf_lock);
1936                 wakeup_busy(krdc);
1937                 mutex_exit(&rdc_conf_lock);
1938         }
1939 
1940         (void) svc_sendreply(xprt, xdr_int, (char *)&index);
1941         if (log) {
1942                 rdc_group_enter(krdc);
1943                 rdc_group_log(krdc, RDC_NOFLUSH | RDC_OTHERREMOTE,
1944                     "Sync aborted or logging started");
1945                 rdc_group_exit(krdc);
1946         }
1947         free_rdc_netbuf(&(state.netaddr));
1948         free_rdc_netbuf(&(state.rnetaddr));
1949 }
1950 
1951 /*
1952  * r_net_getstate4
1953  * Return our state to client
1954  */
1955 static void
1956 r_net_getstate4(SVCXPRT *xprt, struct svc_req *req)
1957 {
1958         int e, ret = -1, index = -1;
1959         struct set_state4 state;
1960         rdc_u_info_t *urdc;
1961         rdc_set_t rdc_set;
1962 
1963         bzero(&state, sizeof (struct set_state));
1964         e = SVC_GETARGS(xprt, xdr_set_state4, (char *)&state);
1965         if (e) {
1966                 init_rdc_netbuf(&(rdc_set.primary.addr));
1967                 init_rdc_netbuf(&(rdc_set.secondary.addr));
1968                 bcopy(state.netaddr, rdc_set.primary.addr.buf,
1969                     state.netaddrlen);
1970                 bcopy(state.rnetaddr, rdc_set.secondary.addr.buf,
1971                     state.rnetaddrlen);
1972                 rdc_set.primary.addr.len = state.netaddrlen;
1973                 rdc_set.secondary.addr.len = state.rnetaddrlen;
1974                 (void) strncpy(rdc_set.primary.file, state.pfile,
1975                     RDC_MAXNAMLEN);
1976                 (void) strncpy(rdc_set.secondary.file, state.sfile,
1977                     RDC_MAXNAMLEN);
1978                 index = rdc_lookup_byaddr(&rdc_set);
1979                 if (index >= 0) {
1980                         urdc = &rdc_u_info[index];
1981 
1982                         ret = 0;
1983                         if (rdc_get_vflags(urdc) & RDC_SYNCING)
1984                                 ret |= 4;
1985                         if (rdc_get_vflags(urdc) & RDC_SLAVE)
1986                                 ret |= 2;
1987                         if (rdc_get_vflags(urdc) & RDC_LOGGING)
1988                                 ret |= 1;
1989                         rdc_set_if_vers(urdc, req->rq_vers);
1990                 }
1991                 free_rdc_netbuf(&(rdc_set.primary.addr));
1992                 free_rdc_netbuf(&(rdc_set.secondary.addr));
1993         }
1994         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
1995 }
1996 
1997 /*
1998  * r_net_getstate7
1999  * Return our state to client
2000  */
2001 static void
2002 r_net_getstate7(SVCXPRT *xprt, struct svc_req *req)
2003 {
2004         int e, ret = -1, index = -1;
2005         struct set_state state;
2006         char pstr[RDC_MAXNAMLEN];
2007         char sstr[RDC_MAXNAMLEN];
2008         rdc_u_info_t *urdc;
2009         rdc_set_t rdc_set;
2010         unsigned short *sp;
2011 
2012         bzero(&state, sizeof (struct set_state));
2013         state.pfile = pstr;
2014         state.sfile = sstr;
2015 
2016         e = SVC_GETARGS(xprt, xdr_set_state, (char *)&state);
2017         if (e) {
2018                 init_rdc_netbuf(&(rdc_set.primary.addr));
2019                 init_rdc_netbuf(&(rdc_set.secondary.addr));
2020                 sp = (unsigned short *)(state.netaddr.buf);
2021                 *sp = ntohs(*sp);
2022                 bcopy(state.netaddr.buf, rdc_set.primary.addr.buf,
2023                     state.netaddrlen);
2024                 sp = (unsigned short *)(state.rnetaddr.buf);
2025                 *sp = ntohs(*sp);
2026                 bcopy(state.rnetaddr.buf, rdc_set.secondary.addr.buf,
2027                     state.rnetaddrlen);
2028                 rdc_set.primary.addr.len = state.netaddrlen;
2029                 rdc_set.secondary.addr.len = state.rnetaddrlen;
2030                 /*
2031                  * strncpy(rdc_set.primary.file, state.pfile, RDC_MAXNAMLEN);
2032                  * strncpy(rdc_set.secondary.file, state.sfile, RDC_MAXNAMLEN);
2033                  */
2034                 bcopy(state.pfile, rdc_set.primary.file, RDC_MAXNAMLEN);
2035                 bcopy(state.sfile, rdc_set.secondary.file, RDC_MAXNAMLEN);
2036                 index = rdc_lookup_byaddr(&rdc_set);
2037                 if (index >= 0) {
2038                         urdc = &rdc_u_info[index];
2039 
2040                         ret = 0;
2041                         if (rdc_get_vflags(urdc) & RDC_SYNCING)
2042                                 ret |= 4;
2043                         if (rdc_get_vflags(urdc) & RDC_SLAVE)
2044                                 ret |= 2;
2045                         if (rdc_get_vflags(urdc) & RDC_LOGGING)
2046                                 ret |= 1;
2047                         rdc_set_if_vers(urdc, req->rq_vers);
2048                 }
2049                 free_rdc_netbuf(&(rdc_set.primary.addr));
2050                 free_rdc_netbuf(&(rdc_set.secondary.addr));
2051         }
2052         (void) svc_sendreply(xprt, xdr_int, (char *)&ret);
2053 }
2054 
2055 /*
2056  * copy from/to a dset/vector combination to a network xdr buffer.
2057  */
2058 static int
2059 rdc_dsetcopy(rdc_net_dataset_t *dset, nsc_vec_t *invec, nsc_off_t fba_pos,
2060     nsc_size_t fba_len, char *bdata, int blen, int dir)
2061 {
2062         nsc_vec_t *vec;
2063         uchar_t *sv_addr;
2064         uchar_t *data;
2065         int sv_len;
2066         nsc_off_t fpos;
2067         int len;
2068         int n;
2069 
2070         if (!bdata || !dset || !invec) {
2071 #ifdef DEBUG
2072                 cmn_err(CE_NOTE,
2073                     "!rdc: dsetcopy: parameters failed bdata %p, dset %p "
2074                     "invec %p", (void *)bdata, (void *)dset, (void *)invec);
2075 #endif
2076                 return (FALSE);
2077         }
2078 
2079         if (fba_len > MAX_RDC_FBAS ||
2080             (dir != COPY_IN && dir != COPY_OUT)) {
2081 #ifdef DEBUG
2082                 cmn_err(CE_NOTE,
2083                     "!rdc: dsetcopy: params failed fba_len %" NSC_SZFMT
2084                     " fba_pos %" NSC_SZFMT ", dir %d", fba_len, fba_pos, dir);
2085 #endif
2086                 return (FALSE);
2087         }
2088 
2089         data = (uchar_t *)bdata;        /* pointer to data in rpc */
2090         len = FBA_SIZE(fba_len);        /* length of this transfer in bytes */
2091         fpos = fba_pos;                 /* start fba offset within buffer */
2092 
2093         if (!len) {
2094 #ifdef DEBUG
2095                 cmn_err(CE_NOTE, "!rdc: dsetcopy: len = 0");
2096 #endif
2097                 return (FALSE);
2098         }
2099 
2100         if (len != blen) {
2101 #ifdef DEBUG
2102                 cmn_err(CE_NOTE, "!rdc:dsetcopy: len %d != blen %d", len, blen);
2103 #endif
2104                 if (len > blen)
2105                         len = blen;
2106         }
2107 
2108         if (!RDC_DSET_LIMITS(dset, fba_pos, fba_len)) {
2109                 /* should never happen */
2110 #ifdef DEBUG
2111                 cmn_err(CE_NOTE,
2112                     "!rdc: dsetcopy: handle limits pos %" NSC_SZFMT " (%"
2113                     NSC_SZFMT ") len %" NSC_SZFMT " (%" NSC_SZFMT ")",
2114                     fba_pos, dset->pos, fba_len, dset->fbalen);
2115 #endif
2116                 return (FALSE); /* Don't overrun handle */
2117         }
2118 
2119         vec = invec;
2120         fpos -= dset->pos;
2121 
2122         /* find starting position in vector */
2123 
2124         for (; fpos >= FBA_NUM(vec->sv_len); vec++)
2125                 fpos -= FBA_NUM(vec->sv_len);
2126 
2127         /*
2128          * Copy data
2129          */
2130 
2131         sv_addr = vec->sv_addr + FBA_SIZE(fpos);
2132         sv_len = vec->sv_len - FBA_SIZE(fpos);
2133 
2134         while (len) {
2135                 if (!sv_addr)   /* end of vec - how did this happen? */
2136                         break;
2137 
2138                 n = min(sv_len, len);
2139 
2140                 if (dir == COPY_OUT)
2141                         bcopy(data, sv_addr, (size_t)n);
2142                 else
2143                         bcopy(sv_addr, data, (size_t)n);
2144 
2145                 sv_len -= n;
2146                 len -= n;
2147 
2148                 sv_addr += n;
2149                 data += n;
2150 
2151                 if (sv_len <= 0) {
2152                         /* goto next vector */
2153                         vec++;
2154                         sv_addr = vec->sv_addr;
2155                         sv_len = vec->sv_len;
2156                 }
2157         }
2158 
2159         return (TRUE);
2160 }
2161 
2162 
2163 /*
2164  * rdc_start_server
2165  * Starts the kRPC server for rdc. Uses tli file descriptor passed down
2166  * from user level rdc server.
2167  *
2168  * Returns: 0 or errno (NOT unistat!).
2169  */
2170 int
2171 rdc_start_server(struct rdc_svc_args *args, int mode)
2172 {
2173         file_t *fp;
2174         int ret;
2175         struct cred *cred;
2176         STRUCT_HANDLE(rdc_svc_args, rs);
2177 
2178         STRUCT_SET_HANDLE(rs, mode, args);
2179         cred = ddi_get_cred();
2180         if (drv_priv(cred) != 0)
2181                 return (EPERM);
2182         fp = getf(STRUCT_FGET(rs, fd));
2183         if (fp == NULL) {
2184 #ifdef DEBUG
2185                 cmn_err(CE_WARN, "!rdc_start_server fd %d, fp %p", args->fd,
2186                     (void *) fp);
2187 #endif
2188                 return (EBADF);
2189         }
2190 
2191         ret = rdcsrv_load(fp, rdc_srvtab, args, mode);
2192 
2193         releasef(STRUCT_FGET(rs, fd));
2194         return (ret);
2195 }
2196 
2197 /*
2198  * Allocate a new sleepq element.
2199  */
2200 
2201 static rdc_sleepq_t *
2202 rdc_newsleepq()
2203 {
2204         rdc_sleepq_t    *sq;
2205 
2206         sq = kmem_alloc(sizeof (rdc_sleepq_t), KM_SLEEP);
2207         sq->next = NULL;
2208 #ifdef DEBUG
2209         mutex_enter(&rdc_cntlock);
2210         rdc_sleepcnt++;
2211         mutex_exit(&rdc_cntlock);
2212 #endif
2213         return (sq);
2214 }
2215 
2216 /*
2217  * free memory/resources used by a sleepq element.
2218  */
2219 static void
2220 rdc_delsleepq(rdc_sleepq_t *sq)
2221 {
2222         rdc_net_dataset_t *dset;
2223 
2224         if (sq->idx != -1) {
2225                 dset = rdc_net_get_set(sq->sindex, sq->idx);
2226                 if (dset) {
2227                         rdc_net_del_set(sq->sindex, dset);
2228                 }
2229         }
2230         kmem_free(sq, sizeof (rdc_sleepq_t));
2231 #ifdef DEBUG
2232         mutex_enter(&rdc_cntlock);
2233         rdc_sleepcnt--;
2234         mutex_exit(&rdc_cntlock);
2235 #endif
2236 }
2237 
2238 
2239 /*
2240  * skip down the sleep q and insert the sleep request
2241  * in ascending order. Return 0 on success, 1 on failure.
2242  */
2243 static int
2244 rdc_sleepq(rdc_group_t *group, rdc_sleepq_t *sq)
2245 {
2246         rdc_sleepq_t *findsq;
2247 
2248 
2249         ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2250         if (group->sleepq == NULL) {
2251                 group->sleepq = sq;
2252         } else {
2253                 if (sq->seq == group->sleepq->seq) {
2254                         cmn_err(CE_WARN, "!rdc_sleepq: Attempt to "
2255                             "add duplicate request to queue %d", sq->seq);
2256                         return (1);
2257                 }
2258                 if (RDC_INFRONT(sq->seq, group->sleepq->seq)) {
2259                         sq->next = group->sleepq;
2260                         group->sleepq = sq;
2261                 } else {
2262                         findsq = group->sleepq;
2263 
2264                         while (findsq->next) {
2265                                 if (sq->seq == findsq->next->seq) {
2266                                         cmn_err(CE_WARN, "!rdc_sleepq: "
2267                                             "Attempt to add duplicate "
2268                                             "request to queue %d", sq->seq);
2269                                         return (1);
2270                                 }
2271                                 if (RDC_INFRONT(sq->seq, findsq->next->seq)) {
2272                                         sq->next = findsq->next;
2273                                         findsq->next = sq;
2274                                         break;
2275                                 }
2276                                 findsq = findsq->next;
2277                         }
2278                         if (findsq->next == NULL)
2279                                 findsq->next = sq;
2280                 }
2281         }
2282         return (0);
2283 }
2284 
2285 /*
2286  * run down the sleep q and discard all the sleepq elements.
2287  */
2288 void
2289 rdc_sleepqdiscard(rdc_group_t *group)
2290 {
2291         rdc_sleepq_t *sq;
2292         rdc_k_info_t *krdc;
2293 
2294         ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2295         sq = group->sleepq;
2296 
2297         while (sq) {
2298                 rdc_sleepq_t *dsq;
2299 
2300                 dsq = sq;
2301                 krdc = &rdc_k_info[dsq->sindex];
2302                 if (krdc->io_kstats) {
2303                         mutex_enter(krdc->io_kstats->ks_lock);
2304                         kstat_waitq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2305                         mutex_exit(krdc->io_kstats->ks_lock);
2306                 }
2307                 sq = sq->next;
2308                 rdc_delsleepq(dsq);
2309         }
2310         group->sleepq = NULL;
2311 }
2312 
2313 /*
2314  * split any write requests down to maxfba sized chunks.
2315  */
2316 /*ARGSUSED*/
2317 static int
2318 rdc_writemaxfba(rdc_k_info_t *krdc, rdc_u_info_t *urdc,
2319     rdc_net_dataset_t *dset, uint_t seq, int nocache)
2320 {
2321         int len;
2322         int ret;
2323         nsc_vec_t vector[2];
2324         nsc_buf_t *handle;
2325         int reserved;
2326         int rtype;
2327         nsc_size_t mfba;
2328         nsc_size_t wsize;
2329         nsc_off_t pos;
2330         int eintr_count;
2331         unsigned char *daddr;
2332         int kstat_len;
2333 
2334         kstat_len = len = dset->fbalen;
2335         ret = 0;
2336         handle = NULL;
2337         reserved = 0;
2338         rtype = RDC_RAW;
2339 
2340         ASSERT(dset->nitems == 1);
2341 
2342         eintr_count = 0;
2343         do {
2344                 ret = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
2345                 if (ret == EINTR) {
2346                         ++eintr_count;
2347                         delay(2);
2348                 }
2349         } while ((ret == EINTR) && (eintr_count < MAX_EINTR_COUNT));
2350         if (ret != 0) {
2351 #ifdef DEBUG
2352                 cmn_err(CE_NOTE, "!rdc_writemaxfba: reserve devs "
2353                     "failed %d", ret);
2354 #endif
2355                 goto out;
2356 
2357         }
2358         reserved = 1;
2359         /*
2360          * Perhaps we should cache mfba.
2361          */
2362         ret = nsc_maxfbas(RDC_U_FD(krdc), 0, &mfba);
2363         if (ret != 0) {
2364 #ifdef DEBUG
2365                 cmn_err(CE_NOTE, "!rdc_writemaxfba: msc_maxfbas failed %d",
2366                     ret);
2367 #endif
2368                 goto out;
2369         }
2370 
2371         ASSERT(urdc->volume_size != 0);
2372         if (dset->pos + len > urdc->volume_size) {
2373                 /* should never happen */
2374                 /*
2375                  * also need to trim down the vector
2376                  * sizes.
2377                  */
2378                 kstat_len = len = urdc->volume_size - dset->pos;
2379                 dset->head->len -= FBA_SIZE(len);
2380                 ASSERT(dset->head->len > 0);
2381         }
2382         daddr = dset->head->dptr;
2383         pos = dset->pos;
2384         vector[1].sv_addr = NULL;
2385         vector[1].sv_len = 0;
2386 
2387         while (len > 0) {
2388                 wsize = min((nsc_size_t)len, mfba);
2389                 vector[0].sv_addr = daddr;
2390                 vector[0].sv_len = FBA_SIZE(wsize);
2391 
2392                 if (handle) {
2393                         (void) nsc_free_buf(handle);
2394                         handle = NULL;
2395                 }
2396                 ret = nsc_alloc_buf(RDC_U_FD(krdc), pos, wsize,
2397                     NSC_WRBUF|NSC_NODATA|nocache, &handle);
2398                 if (ret != 0) {
2399 #ifdef DEBUG
2400                         cmn_err(CE_NOTE, "!rdc_writemaxfba: "
2401                             "nsc_alloc (d1) buf failed %d at "
2402                             "pos %" NSC_SZFMT " len %" NSC_SZFMT,
2403                             ret, pos, wsize);
2404 #endif
2405                         goto out;
2406                 }
2407                 handle->sb_vec = &vector[0];
2408                 ret = rdc_combywrite(krdc, handle);
2409                 if (ret != 0) {
2410 #ifdef DEBUG
2411                         cmn_err(CE_NOTE, "!rdc_writemaxfba: "
2412                             "write failed (d1) %d offset %" NSC_SZFMT " "
2413                             "length %" NSC_SZFMT, ret, pos, wsize);
2414 #endif
2415                         goto out;
2416                 }
2417                 pos += wsize;
2418                 len -= wsize;
2419                 daddr += FBA_SIZE(wsize);
2420         }
2421 out:
2422         if (!RDC_SUCCESS(ret)) {
2423                 if (!(rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
2424                         ASSERT(!(rdc_get_vflags(urdc) &
2425                             RDC_PRIMARY));
2426                         rdc_many_enter(krdc);
2427                         rdc_set_flags(urdc, RDC_SYNC_NEEDED);
2428                         rdc_set_flags_log(urdc, RDC_VOL_FAILED,
2429                             "svc write failed");
2430                         rdc_many_exit(krdc);
2431                         rdc_write_state(urdc);
2432                 }
2433         } else {
2434                 /* success */
2435 #ifdef  DEBUG
2436                 if (rdc_netwrite6) {
2437                         /*
2438                          * This string is used in the ZatoIchi MASNDR
2439                          * tests, if you change this, update the test.
2440                          */
2441                         cmn_err(CE_NOTE, "!writemaxfba: Write "
2442                             "sequence %u", seq);
2443                 }
2444 #endif
2445                 if (krdc->io_kstats) {
2446                         KSTAT_IO_PTR(krdc->io_kstats)->writes++;
2447                         KSTAT_IO_PTR(krdc->io_kstats)->nwritten +=
2448                             FBA_SIZE(kstat_len);
2449                 }
2450         }
2451         if (handle)
2452                 (void) nsc_free_buf(handle);
2453         if (reserved)
2454                 _rdc_rlse_devs(krdc, rtype);
2455         return (ret);
2456 }
2457 
2458 static int
2459 rdc_combywrite(rdc_k_info_t *krdc, nsc_buf_t *handle)
2460 {
2461         int rsync;
2462         int ret;
2463         int multiret;
2464 
2465         rsync = -1;
2466         ret = 0;
2467         /* Handle multihop I/O even on error */
2468         if (IS_MULTI(krdc)) {
2469                 rdc_k_info_t *ktmp;
2470                 rdc_u_info_t *utmp;
2471 
2472                 rdc_many_enter(krdc);
2473                 /*
2474                  * Find a target primary that is enabled,
2475                  * taking account of the fact that this
2476                  * could be a multihop secondary
2477                  * connected to a 1-to-many primary.
2478                  */
2479                 ktmp = krdc->multi_next;
2480                 if (ktmp == NULL) {
2481                         rdc_many_exit(krdc);
2482                         goto multi_done;
2483                 }
2484                 utmp = &rdc_u_info[ktmp->index];
2485                 do {
2486                         if ((rdc_get_vflags(utmp) & RDC_PRIMARY)
2487                             /* CSTYLED */
2488                             && IS_ENABLED(utmp))
2489                                 break;
2490 
2491                         ktmp = ktmp->many_next;
2492                         utmp = &rdc_u_info[ktmp->index];
2493                 } while (ktmp != krdc->multi_next);
2494 
2495                 if (!(rdc_get_vflags(utmp) & RDC_PRIMARY) ||
2496                     !IS_ENABLED(utmp)) {
2497                         rdc_many_exit(krdc);
2498                         goto multi_done;
2499                 }
2500 
2501                 rdc_many_exit(krdc);
2502                 rsync = (rdc_get_mflags(utmp) & RDC_SLAVE);
2503                 if (!rsync) {
2504                         /* normal case - local io first */
2505                         ret = nsc_write(handle, handle->sb_pos, handle->sb_len,
2506                             0);
2507                 }
2508                 multiret = _rdc_multi_write(handle, handle->sb_pos,
2509                     handle->sb_len, 0, ktmp);
2510                 if (!RDC_SUCCESS(multiret)) {
2511 #ifdef DEBUG
2512                         cmn_err(CE_NOTE, "!combywrite: "
2513                             "rdc_multi_write failed "
2514                             "status %d ret %d",
2515                             handle->sb_error, multiret);
2516 #endif
2517                         if (!(rdc_get_vflags(utmp) &
2518                             RDC_VOL_FAILED)) {
2519                                 rdc_many_enter(ktmp);
2520                                 if (rdc_get_vflags(utmp) &
2521                                     RDC_PRIMARY) {
2522                                         rdc_set_mflags(utmp,
2523                                             RDC_RSYNC_NEEDED);
2524                                 } else {
2525                                         rdc_set_flags(utmp,
2526                                             RDC_SYNC_NEEDED);
2527                                 }
2528                                 rdc_set_flags(utmp,
2529                                     RDC_VOL_FAILED);
2530                                 rdc_many_exit(ktmp);
2531                                 rdc_write_state(utmp);
2532                         }
2533                 }
2534         }
2535 
2536 multi_done:
2537         if (rsync != 0) {
2538                 /*
2539                  * Either:
2540                  * reverse sync in progress and so we
2541                  * need to do the local io after the
2542                  * (multihop) secondary io.
2543                  * Or:
2544                  * no multihop and this is the only io
2545                  * required.
2546                  */
2547                 ret = nsc_write(handle, handle->sb_pos, handle->sb_len, 0);
2548 
2549         }
2550         return (ret);
2551 }
2552 /*
2553  * set the pos and len values in the piggyback reply.
2554  */
2555 static void
2556 rdc_setbitind(int *pendcnt, net_pendvec_t *pvec, rdc_net_dataset_t *dset,
2557     uint_t seq, int pindex, int qpos)
2558 {
2559         int pc;
2560         ASSERT(*pendcnt < RDC_MAXPENDQ);
2561 
2562         pc = *pendcnt;
2563         pvec[pc].seq = seq;
2564         pvec[pc].apos = dset->pos;
2565         pvec[pc].qpos = qpos;
2566         pvec[pc].alen = dset->fbalen;
2567         pvec[pc].pindex = pindex;
2568         *pendcnt = pc + 1;
2569         DTRACE_PROBE1(pvec_reply, int, seq);
2570 }
2571 
2572 /*
2573  * Enters with group->ra_queue.net_qlock held.
2574  * Tries to construct the return status data for
2575  * all the pending requests in the sleepq that it can
2576  * satisfy.
2577  */
2578 static void
2579 rdc_dopending(rdc_group_t *group, netwriteres *netretp)
2580 {
2581         int pendcnt;
2582         net_pendvec_t *pendvec;
2583         rdc_sleepq_t *sq;
2584         int ret;
2585         int pendsz;
2586 
2587         ASSERT(MUTEX_HELD(&group->ra_queue.net_qlock));
2588 
2589         pendcnt = 0;
2590         pendsz = RDC_MAXPENDQ * sizeof (net_pendvec_t);
2591         pendvec = kmem_alloc(pendsz, KM_SLEEP);
2592 
2593         /*
2594          * now look at the Q of pending tasks, attempt
2595          * to write any that have been waiting for
2596          * me to complete my write, and piggyback
2597          * their results in my reply, by setiing pendcnt
2598          * to the number of extra requests sucessfully
2599          * processed.
2600          */
2601         while (group->sleepq && group->sleepq->seq == group->seq) {
2602                 rdc_k_info_t            *krdc;
2603                 rdc_u_info_t            *urdc;
2604                 struct rdc_net_dataset  *dset;
2605 
2606                 sq = group->sleepq;
2607                 group->sleepq = sq->next;
2608                 mutex_exit(&group->ra_queue.net_qlock);
2609 
2610                 krdc = &rdc_k_info[sq->sindex];
2611                 urdc = &rdc_u_info[sq->sindex];
2612                 if (krdc->io_kstats) {
2613                         mutex_enter(krdc->io_kstats->ks_lock);
2614                         kstat_waitq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2615                         mutex_exit(krdc->io_kstats->ks_lock);
2616                 }
2617 
2618                 dset = rdc_net_get_set(sq->sindex, sq->idx);
2619                 if (dset == NULL) {
2620 #ifdef  DEBUG
2621                         cmn_err(CE_NOTE, "!pending: %s:%s rdc_net_get_set "
2622                             "failed", urdc->secondary.intf,
2623                             urdc->secondary.file);
2624 #endif
2625                         /*
2626                          * as we failed to get the pointer, there
2627                          * is no point expecting the cleanup
2628                          * code in rdc_delsleepq() to get it
2629                          * either.
2630                          */
2631                         sq->idx = -1;
2632                         goto cleansq;
2633                 }
2634                 sq->idx = -1;        /* marked as cleaned up */
2635 
2636                 ret = rdc_writemaxfba(krdc, urdc, dset, sq->seq, sq->nocache);
2637                 if (RDC_SUCCESS(ret)) {
2638                         rdc_setbitind(&pendcnt, pendvec, dset,
2639                             sq->seq, sq->pindex, sq->qpos);
2640                 } else {
2641                         cmn_err(CE_WARN, "!dopending: Write of pending "
2642                             "asynchronous task failed, with "
2643                             "sequence number %u for SNDR set %s:%s",
2644                             sq->seq, urdc->secondary.intf,
2645                             urdc->secondary.file);
2646                 }
2647                 rdc_net_del_set(sq->sindex, dset);
2648 cleansq:
2649                 mutex_enter(&group->ra_queue.net_qlock);
2650                 group->seq = sq->seq + 1;
2651                 if (group->seq < sq->seq)
2652                         group->seq = RDC_NEWSEQ + 1;
2653                 rdc_delsleepq(sq);
2654         }
2655         mutex_exit(&group->ra_queue.net_qlock);
2656         if (pendcnt) {
2657                 int vecsz;
2658 #ifdef DEBUG
2659                 if (rdc_netwrite6) {
2660                         cmn_err(CE_NOTE, "!packing pend, count %d", pendcnt);
2661                 }
2662 #endif
2663                 vecsz = pendcnt * sizeof (net_pendvec_t);
2664                 netretp->vecdata.vecdata_val =
2665                     kmem_alloc(vecsz, KM_SLEEP);
2666                 netretp->vecdata.vecdata_len = pendcnt;
2667                 bcopy(pendvec, netretp->vecdata.vecdata_val, vecsz);
2668         }
2669         kmem_free(pendvec, pendsz);
2670         mutex_enter(&group->ra_queue.net_qlock);
2671 }
2672 
2673 /*
2674  * Take the dset and allocate and fill in the vector.
2675  */
2676 static nsc_vec_t *
2677 rdc_dset2vec(rdc_net_dataset_t *dset)
2678 {
2679         nsc_vec_t *vecret;
2680         int i;
2681         rdc_net_dataitem_t *ditem;
2682 
2683         ASSERT(dset->nitems > 0);
2684         ASSERT(dset->head);
2685         ASSERT(dset->tail);
2686 
2687         vecret = kmem_alloc((dset->nitems + 1) * sizeof (nsc_vec_t),
2688             KM_NOSLEEP);
2689         if (vecret == NULL) {
2690                 return (NULL);
2691         }
2692         RDC_DSMEMUSE((dset->nitems + 1) * sizeof (nsc_vec_t));
2693         ditem = dset->head;
2694         for (i = 0; i < dset->nitems; i++) {
2695                 ASSERT(ditem);
2696                 vecret[i].sv_addr = ditem->dptr;
2697                 vecret[i].sv_len = ditem->len;
2698                 ditem = ditem->next;
2699         }
2700         /*
2701          * Null terminate.
2702          */
2703         vecret[i].sv_addr = NULL;
2704         vecret[i].sv_len = 0;
2705         /*
2706          * Check the list and count matches.
2707          */
2708         ASSERT(ditem == NULL);
2709         return (vecret);
2710 }
2711 
2712 /*
2713  * Split the local read into maxfba sized chunks.
2714  * Returns 0 on an error, or a valid idx on success.
2715  */
2716 static int
2717 rdc_readmaxfba(int cd, nsc_off_t pos, nsc_size_t fbalen, int nocache)
2718 {
2719         int idx;
2720         rdc_k_info_t *krdc;
2721         rdc_u_info_t *urdc;
2722         rdc_net_dataset_t *dset;
2723         rdc_net_dataitem_t *ditem;
2724         int rtype;
2725         nsc_buf_t *handle;
2726         nsc_vec_t veclist[2];
2727         int ret;
2728         int reserved;
2729         nsc_size_t fbaleft;
2730         nsc_size_t mfba;
2731         nsc_off_t fba;
2732         nsc_off_t spos;
2733         int eintr_count;
2734 
2735         handle = NULL;
2736         idx = 0; /* error status */
2737         dset = NULL;
2738         ditem = NULL;
2739         reserved = 0;
2740         ret = 0;
2741         mfba = 0;
2742 
2743         rtype = RDC_RAW;
2744         krdc = &rdc_k_info[cd];
2745         urdc = &rdc_u_info[cd];
2746 
2747         eintr_count = 0;
2748         do {
2749                 ret = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL);
2750                 if (ret == EINTR) {
2751                         ++eintr_count;
2752                         delay(2);
2753                 }
2754         } while ((ret == EINTR) && (eintr_count < MAX_EINTR_COUNT));
2755         if (ret != 0) {
2756 #ifdef DEBUG
2757                 cmn_err(CE_NOTE, "!readmaxfba: reserve failed on set %s:%s %d",
2758                     urdc->secondary.intf, urdc->secondary.file,
2759                     ret);
2760 #endif
2761                 goto out;
2762         }
2763         reserved = 1;
2764         /*
2765          * create a dataset that we can hang all the buffers from.
2766          */
2767         dset = rdc_net_add_set(cd);
2768         if (dset == NULL) {
2769 #ifdef DEBUG
2770                 cmn_err(CE_NOTE, "!readmaxfba: Unable to allocate dset on set "
2771                     "%s:%s", urdc->secondary.intf, urdc->secondary.file);
2772 #endif
2773                 goto out;
2774         }
2775         dset->pos = pos;
2776         dset->fbalen = fbalen;
2777         ret = nsc_maxfbas(RDC_U_FD(krdc), 0, &mfba);
2778         if (ret != 0) {
2779 #ifdef DEBUG
2780                 cmn_err(CE_NOTE, "!readmaxfba: msc_maxfbas failed on set %s:%s "
2781                     "%d", urdc->secondary.intf,      urdc->secondary.file, ret);
2782 #endif
2783                 goto out;
2784         }
2785         spos = pos;
2786         fbaleft = fbalen;
2787         veclist[1].sv_addr = NULL;
2788         veclist[1].sv_len = 0;
2789 
2790         while (fbaleft > 0) {
2791                 fba = min(mfba, fbaleft);
2792                 if (handle) {
2793                         (void) nsc_free_buf(handle);
2794                         handle = NULL;
2795                 }
2796                 ret = nsc_alloc_buf(RDC_U_FD(krdc), spos, fba,
2797                     nocache|NSC_NODATA, &handle);
2798                 if (ret != 0) {
2799 #ifdef DEBUG
2800                         cmn_err(CE_NOTE, "!readmaxfba: alloc failed on set"
2801                             "%s:%s %d", urdc->secondary.intf,
2802                             urdc->secondary.file, ret);
2803 #endif
2804                         goto out;
2805                 }
2806                 ditem = kmem_alloc(sizeof (rdc_net_dataitem_t), KM_NOSLEEP);
2807                 if (ditem == NULL) {
2808                         goto out;
2809                 }
2810                 RDC_DSMEMUSE(sizeof (rdc_net_dataitem_t));
2811                 ditem->len = FBA_SIZE(fba);
2812                 ditem->mlen = ditem->len;
2813                 ditem->dptr = kmem_alloc(ditem->len, KM_SLEEP);
2814                 RDC_DSMEMUSE(ditem->len);
2815                 ditem->next = NULL;
2816                 /*
2817                  * construct a vector list
2818                  */
2819                 veclist[0].sv_addr = ditem->dptr;
2820                 veclist[0].sv_len = ditem->len;
2821                 handle->sb_vec = veclist;
2822                 ret = rdc_combyread(krdc, urdc, handle);
2823                 if (ret != 0) {
2824                         goto out;
2825                 }
2826                 /*
2827                  * place on linked list.
2828                  */
2829                 dset->nitems++;
2830                 if (dset->head == NULL) {
2831                         dset->head = ditem;
2832                         dset->tail = ditem;
2833                 } else {
2834                         dset->tail->next = ditem;
2835                         dset->tail = ditem;
2836                 }
2837                 /*
2838                  * now its linked, clear this so its not freed twice.
2839                  */
2840                 ditem = NULL;
2841                 fbaleft -= fba;
2842                 spos += fba;
2843         }
2844         /*
2845          * all the reads have worked, store the results.
2846          */
2847         idx = dset->id;
2848         rdc_net_put_set(cd, dset);
2849         dset = NULL;
2850 out:
2851         if (handle)
2852                 (void) nsc_free_buf(handle);
2853         if (reserved)
2854                 _rdc_rlse_devs(krdc, rtype);
2855         if (dset)
2856                 rdc_net_del_set(cd, dset);
2857         if (ditem) {
2858                 kmem_free(ditem->dptr, ditem->mlen);
2859                 RDC_DSMEMUSE(-ditem->mlen);
2860                 kmem_free(ditem, sizeof (*ditem));
2861                 RDC_DSMEMUSE(-sizeof (*ditem));
2862         }
2863         return (idx);
2864 }
2865 
2866 
2867 /*
2868  * perform both a local read, and if multihop, a remote read.
2869  * return 0 on success, or errno on failure.
2870  */
2871 static int
2872 rdc_combyread(rdc_k_info_t *krdc, rdc_u_info_t *urdc, nsc_buf_t *handle)
2873 {
2874         int ret;
2875         rdc_k_info_t *ktmp;
2876         rdc_u_info_t *utmp;
2877 
2878         /*
2879          * read it.
2880          */
2881         if (krdc->io_kstats) {
2882                 mutex_enter(krdc->io_kstats->ks_lock);
2883                 kstat_runq_enter(KSTAT_IO_PTR(krdc->io_kstats));
2884                 mutex_exit(krdc->io_kstats->ks_lock);
2885         }
2886 
2887         ret = nsc_read(handle, handle->sb_pos, handle->sb_len, NSC_READ);
2888 
2889         if (krdc->io_kstats) {
2890                 mutex_enter(krdc->io_kstats->ks_lock);
2891                 kstat_runq_exit(KSTAT_IO_PTR(krdc->io_kstats));
2892                 mutex_exit(krdc->io_kstats->ks_lock);
2893         }
2894 
2895         if (ret != 0) {
2896 #ifdef DEBUG
2897                 cmn_err(CE_NOTE, "!combyread: read failed on set %s:%s %d",
2898                     urdc->secondary.intf, urdc->secondary.file, ret);
2899 #endif
2900                 if (!(rdc_get_vflags(urdc) & RDC_VOL_FAILED)) {
2901                         rdc_many_enter(krdc);
2902                         rdc_set_mflags(urdc, RDC_RSYNC_NEEDED);
2903                         rdc_set_flags_log(urdc, RDC_VOL_FAILED,
2904                             "comby read failed");
2905                         rdc_many_exit(krdc);
2906                         rdc_write_state(urdc);
2907                 }
2908                 goto out;
2909         }
2910         if (IS_MULTI(krdc) && (ktmp = krdc->multi_next) &&
2911             (utmp = &rdc_u_info[ktmp->index]) &&
2912             IS_ENABLED(utmp) &&
2913             (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED)) {
2914                 ret = _rdc_remote_read(ktmp, handle, handle->sb_pos,
2915                     handle->sb_len, NSC_READ);
2916                 /*
2917                  * Set NSC_MIXED so
2918                  * that the cache will throw away this
2919                  * buffer when we free it since we have
2920                  * combined data from multiple sources
2921                  * into a single buffer.
2922                  * Currently we don't use the cache for
2923                  * data volumes, so comment this out.
2924                  * handle->sb_flag |= NSC_MIXED;
2925                  */
2926                 if (ret != 0) {
2927 #ifdef DEBUG
2928                         cmn_err(CE_NOTE, "!combyread: remote read failed on "
2929                             "set %s:%s %d", utmp->secondary.intf,
2930                             utmp->secondary.file, ret);
2931 #endif
2932                         goto out;
2933                 }
2934         }
2935         if (krdc->io_kstats) {
2936                 KSTAT_IO_PTR(krdc->io_kstats)->reads++;
2937                 KSTAT_IO_PTR(krdc->io_kstats)->nread +=
2938                     FBA_SIZE(handle->sb_len);
2939         }
2940 out:
2941         return (ret);
2942 }
2943 
2944 
2945 /*
2946  * remove and free all the collected dsets for this set.
2947  */
2948 void
2949 rdc_dump_dsets(int index)
2950 {
2951         rdc_k_info_t *krdc;
2952         rdc_net_dataset_t *dset;
2953 
2954         krdc = &rdc_k_info[index];
2955 tloop:
2956         mutex_enter(&krdc->dc_sleep);
2957         while ((dset = krdc->net_dataset) != NULL) {
2958                 if (dset->inuse) {
2959                         /*
2960                          * for the dset to be in use, the
2961                          * service routine r_net_write6() must
2962                          * be active with it. It will free
2963                          * it eventually.
2964                          */
2965                         mutex_exit(&krdc->dc_sleep);
2966                         delay(5);
2967                         goto tloop;
2968                 }
2969                 /*
2970                  * free it.
2971                  */
2972                 rdc_net_free_set(krdc, dset);
2973         }
2974         mutex_exit(&krdc->dc_sleep);
2975 }
2976 
2977 #ifdef  DEBUG
2978 void
2979 rdc_stallzero(int flag)
2980 {
2981         static int init = 0;
2982         static kcondvar_t cv;
2983         static kmutex_t mu;
2984 
2985         if (init == 0) {
2986                 cv_init(&cv, NULL, CV_DRIVER, NULL);
2987                 mutex_init(&mu, NULL, MUTEX_DRIVER, NULL);
2988                 init = 1;
2989         }
2990 
2991         mutex_enter(&mu);
2992         switch (flag) {
2993         case 0:
2994                 rdc_stall0 = 0;
2995                 cv_signal(&cv);
2996                 break;
2997         case 1:
2998                 rdc_stall0 = 1;
2999                 break;
3000         case 2:
3001                 while (rdc_stall0 == 1)
3002                         cv_wait(&cv, &mu);
3003                 break;
3004         default:
3005                 cmn_err(CE_PANIC, "Bad flag value passed to rdc_stallzero");
3006                 break;
3007         }
3008         mutex_exit(&mu);
3009 }
3010 #endif
3011 
3012 /*
3013  * RDC protocol version 5
3014  */
3015 static rdc_disptab_t rdc_disptab5[] =
3016 {
3017         /* PROC                 Idempotent */
3018         { r_net_null,           FALSE },
3019         { rdcsrv_noproc,        FALSE },
3020         { r_net_getsize,        FALSE },
3021         { rdcsrv_noproc,        FALSE },
3022         { r_net_write5,         TRUE },
3023         { r_net_read,           FALSE },
3024         { rdcsrv_noproc,        FALSE },
3025         { r_net_state4,         FALSE },
3026         { r_net_ping4,          FALSE },
3027         { r_net_bmap,           FALSE },
3028         { r_net_bdata,          FALSE },
3029         { rdcsrv_noproc,        FALSE },
3030         { r_net_getstate4,      FALSE }
3031 };
3032 
3033 /*
3034  * RDC protocol version 6
3035  */
3036 static rdc_disptab_t rdc_disptab6[] =
3037 {
3038         /* PROC                 Idempotent */
3039         { r_net_null,           FALSE },
3040         { rdcsrv_noproc,        FALSE },
3041         { r_net_getsize6,       FALSE },
3042         { rdcsrv_noproc,        FALSE },
3043         { r_net_write6,         TRUE },
3044         { r_net_read6,          FALSE },
3045         { rdcsrv_noproc,        FALSE },
3046         { r_net_state4,         FALSE },
3047         { r_net_ping4,          FALSE },
3048         { r_net_bmap6,          FALSE },
3049         { r_net_bdata6,         FALSE },
3050         { rdcsrv_noproc,        FALSE },
3051         { r_net_getstate4,      FALSE }
3052 };
3053 
3054 /*
3055  * RDC protocol version 7
3056  */
3057 static rdc_disptab_t rdc_disptab7[] =
3058 {
3059         /* PROC                 Idempotent */
3060         { r_net_null,           FALSE },
3061         { rdcsrv_noproc,        FALSE },
3062         { r_net_getsize6,       FALSE },
3063         { rdcsrv_noproc,        FALSE },
3064         { r_net_write6,         TRUE },
3065         { r_net_read6,          FALSE },
3066         { rdcsrv_noproc,        FALSE },
3067         { r_net_state,          FALSE },
3068         { r_net_ping7,          FALSE },
3069         { r_net_bmap6,          FALSE },
3070         { r_net_bdata6,         FALSE },
3071         { rdcsrv_noproc,        FALSE },
3072         { r_net_getstate7,      FALSE }
3073 };
3074 
3075 static rdcsrv_t rdc_srvtab[] = {
3076         { rdc_disptab5, sizeof (rdc_disptab5) / sizeof (*rdc_disptab5) },
3077         { rdc_disptab6, sizeof (rdc_disptab6) / sizeof (*rdc_disptab6) },
3078         { rdc_disptab7, sizeof (rdc_disptab7) / sizeof (*rdc_disptab7) }
3079 };