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 #define _RDC_
  27 #include <sys/types.h>
  28 #include <sys/ksynch.h>
  29 #include <sys/kmem.h>
  30 #include <sys/errno.h>
  31 #include <sys/conf.h>
  32 #include <sys/cmn_err.h>
  33 #include <sys/modctl.h>
  34 #include <sys/cred.h>
  35 #include <sys/ddi.h>
  36 #include <sys/unistat/spcs_s.h>
  37 #include <sys/unistat/spcs_s_k.h>
  38 #include <sys/unistat/spcs_errors.h>
  39 
  40 #include <sys/nsc_thread.h>
  41 #ifdef DS_DDICT
  42 #include "../contract.h"
  43 #endif
  44 #include <sys/nsctl/nsctl.h>
  45 #include <sys/nsctl/nsvers.h>
  46 
  47 #include <sys/sdt.h>              /* dtrace is S10 or later */
  48 
  49 #include "rdc.h"
  50 #include "rdc_io.h"
  51 #include "rdc_bitmap.h"
  52 #include "rdc_ioctl.h"
  53 #include "rdcsrv.h"
  54 #include "rdc_diskq.h"
  55 
  56 #define DIDINIT         0x01
  57 #define DIDNODES        0x02
  58 #define DIDCONFIG       0x04
  59 
  60 static int rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp);
  61 static int rdcclose(dev_t dev, int flag, int otyp, cred_t *crp);
  62 static int rdcprint(dev_t dev, char *str);
  63 static int rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp,
  64         int *rvp);
  65 static int rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
  66 static int rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  67 static int rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
  68         void **result);
  69 #ifdef  DEBUG
  70 static int rdc_clrkstat(void *);
  71 #endif
  72 
  73 /*
  74  * kstat interface
  75  */
  76 static kstat_t *sndr_kstats;
  77 
  78 int sndr_info_stats_update(kstat_t *ksp, int rw);
  79 
  80 static sndr_m_stats_t sndr_info_stats = {
  81         {RDC_MKSTAT_MAXSETS,                    KSTAT_DATA_ULONG},
  82         {RDC_MKSTAT_MAXFBAS,                    KSTAT_DATA_ULONG},
  83         {RDC_MKSTAT_RPC_TIMEOUT,                KSTAT_DATA_ULONG},
  84         {RDC_MKSTAT_HEALTH_THRES,               KSTAT_DATA_ULONG},
  85         {RDC_MKSTAT_BITMAP_WRITES,              KSTAT_DATA_ULONG},
  86         {RDC_MKSTAT_CLNT_COTS_CALLS,            KSTAT_DATA_ULONG},
  87         {RDC_MKSTAT_CLNT_CLTS_CALLS,            KSTAT_DATA_ULONG},
  88         {RDC_MKSTAT_SVC_COTS_CALLS,             KSTAT_DATA_ULONG},
  89         {RDC_MKSTAT_SVC_CLTS_CALLS,             KSTAT_DATA_ULONG},
  90         {RDC_MKSTAT_BITMAP_REF_DELAY,           KSTAT_DATA_ULONG}
  91 };
  92 
  93 int rdc_info_stats_update(kstat_t *ksp, int rw);
  94 
  95 static rdc_info_stats_t rdc_info_stats = {
  96         {RDC_IKSTAT_FLAGS,              KSTAT_DATA_ULONG},
  97         {RDC_IKSTAT_SYNCFLAGS,          KSTAT_DATA_ULONG},
  98         {RDC_IKSTAT_BMPFLAGS,           KSTAT_DATA_ULONG},
  99         {RDC_IKSTAT_SYNCPOS,            KSTAT_DATA_ULONG},
 100         {RDC_IKSTAT_VOLSIZE,            KSTAT_DATA_ULONG},
 101         {RDC_IKSTAT_BITSSET,            KSTAT_DATA_ULONG},
 102         {RDC_IKSTAT_AUTOSYNC,           KSTAT_DATA_ULONG},
 103         {RDC_IKSTAT_MAXQFBAS,           KSTAT_DATA_ULONG},
 104         {RDC_IKSTAT_MAXQITEMS,          KSTAT_DATA_ULONG},
 105         {RDC_IKSTAT_FILE,               KSTAT_DATA_STRING},
 106         {RDC_IKSTAT_SECFILE,            KSTAT_DATA_STRING},
 107         {RDC_IKSTAT_BITMAP,             KSTAT_DATA_STRING},
 108         {RDC_IKSTAT_PRIMARY_HOST,       KSTAT_DATA_STRING},
 109         {RDC_IKSTAT_SECONDARY_HOST,     KSTAT_DATA_STRING},
 110         {RDC_IKSTAT_TYPE_FLAG,          KSTAT_DATA_ULONG},
 111         {RDC_IKSTAT_BMP_SIZE,           KSTAT_DATA_ULONG},
 112         {RDC_IKSTAT_DISK_STATUS,        KSTAT_DATA_ULONG},
 113         {RDC_IKSTAT_IF_DOWN,            KSTAT_DATA_ULONG},
 114         {RDC_IKSTAT_IF_RPC_VERSION,     KSTAT_DATA_ULONG},
 115         {RDC_IKSTAT_ASYNC_BLOCK_HWM,    KSTAT_DATA_ULONG},
 116         {RDC_IKSTAT_ASYNC_ITEM_HWM,     KSTAT_DATA_ULONG},
 117         {RDC_IKSTAT_ASYNC_THROTTLE_DELAY,       KSTAT_DATA_ULONG},
 118         {RDC_IKSTAT_ASYNC_ITEMS,        KSTAT_DATA_ULONG},
 119         {RDC_IKSTAT_ASYNC_BLOCKS,       KSTAT_DATA_ULONG},
 120         {RDC_IKSTAT_QUEUE_TYPE,         KSTAT_DATA_CHAR}
 121 };
 122 
 123 static struct cb_ops rdc_cb_ops = {
 124         rdcopen,
 125         rdcclose,
 126         nulldev,                /* no strategy */
 127         rdcprint,
 128         nodev,                  /* no dump */
 129         nodev,                  /* no read */
 130         nodev,                  /* no write */
 131         rdcioctl,
 132         nodev,                  /* no devmap */
 133         nodev,                  /* no mmap */
 134         nodev,                  /* no segmap */
 135         nochpoll,
 136         ddi_prop_op,
 137         NULL,                   /* not STREAMS */
 138         D_NEW | D_MP | D_64BIT,
 139         CB_REV,
 140         nodev,                  /* no aread */
 141         nodev,                  /* no awrite */
 142 };
 143 
 144 static struct dev_ops rdc_ops = {
 145         DEVO_REV,
 146         0,
 147         rdcgetinfo,
 148         nulldev,                /* identify */
 149         nulldev,                /* probe */
 150         rdcattach,
 151         rdcdetach,
 152         nodev,                  /* no reset */
 153         &rdc_cb_ops,
 154         (struct bus_ops *)NULL
 155 };
 156 
 157 static struct modldrv rdc_ldrv = {
 158         &mod_driverops,
 159         "nws:Remote Mirror:" ISS_VERSION_STR,
 160         &rdc_ops
 161 };
 162 
 163 static struct modlinkage rdc_modlinkage = {
 164         MODREV_1,
 165         &rdc_ldrv,
 166         NULL
 167 };
 168 
 169 const   int sndr_major_rev = ISS_VERSION_MAJ;
 170 const   int sndr_minor_rev = ISS_VERSION_MIN;
 171 const   int sndr_micro_rev = ISS_VERSION_MIC;
 172 const   int sndr_baseline_rev = ISS_VERSION_NUM;
 173 static  char sndr_version[16];
 174 
 175 static void *rdc_dip;
 176 
 177 extern int _rdc_init_dev();
 178 extern void _rdc_deinit_dev();
 179 extern void rdc_link_down_free();
 180 
 181 int rdc_bitmap_mode;
 182 int rdc_auto_sync;
 183 int rdc_max_sets;
 184 extern int rdc_health_thres;
 185 
 186 kmutex_t rdc_sync_mutex;
 187 rdc_sync_event_t rdc_sync_event;
 188 clock_t rdc_sync_event_timeout;
 189 
 190 static void
 191 rdc_sync_event_init()
 192 {
 193         mutex_init(&rdc_sync_mutex, NULL, MUTEX_DRIVER, NULL);
 194         mutex_init(&rdc_sync_event.mutex, NULL, MUTEX_DRIVER, NULL);
 195         cv_init(&rdc_sync_event.cv, NULL, CV_DRIVER, NULL);
 196         cv_init(&rdc_sync_event.done_cv, NULL, CV_DRIVER, NULL);
 197         rdc_sync_event.master[0] = 0;
 198         rdc_sync_event.lbolt = (clock_t)0;
 199         rdc_sync_event_timeout = RDC_SYNC_EVENT_TIMEOUT;
 200 }
 201 
 202 
 203 static void
 204 rdc_sync_event_destroy()
 205 {
 206         mutex_destroy(&rdc_sync_mutex);
 207         mutex_destroy(&rdc_sync_event.mutex);
 208         cv_destroy(&rdc_sync_event.cv);
 209         cv_destroy(&rdc_sync_event.done_cv);
 210 }
 211 
 212 
 213 
 214 int
 215 _init(void)
 216 {
 217         return (mod_install(&rdc_modlinkage));
 218 }
 219 
 220 int
 221 _fini(void)
 222 {
 223         return (mod_remove(&rdc_modlinkage));
 224 }
 225 
 226 int
 227 _info(struct modinfo *modinfop)
 228 {
 229         return (mod_info(&rdc_modlinkage, modinfop));
 230 }
 231 
 232 static int
 233 rdcattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 234 {
 235         intptr_t flags;
 236         int instance;
 237         int i;
 238 
 239         /*CONSTCOND*/
 240         ASSERT(sizeof (u_longlong_t) == 8);
 241 
 242         if (cmd != DDI_ATTACH)
 243                 return (DDI_FAILURE);
 244 
 245         (void) strncpy(sndr_version, _VERSION_, sizeof (sndr_version));
 246 
 247         instance = ddi_get_instance(dip);
 248         rdc_dip = dip;
 249 
 250         flags = 0;
 251 
 252         rdc_sync_event_init();
 253 
 254         /*
 255          * rdc_max_sets must be set before calling _rdc_load().
 256          */
 257 
 258         rdc_max_sets = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 259             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "rdc_max_sets", 64);
 260 
 261         if (_rdc_init_dev()) {
 262                 cmn_err(CE_WARN, "!rdc: _rdc_init_dev failed");
 263                 goto out;
 264         }
 265         flags |= DIDINIT;
 266 
 267         if (_rdc_load() != 0) {
 268                 cmn_err(CE_WARN, "!rdc: _rdc_load failed");
 269                 goto out;
 270         }
 271 
 272         if (_rdc_configure()) {
 273                 cmn_err(CE_WARN, "!rdc: _rdc_configure failed");
 274                 goto out;
 275         }
 276         flags |= DIDCONFIG;
 277 
 278         if (ddi_create_minor_node(dip, "rdc", S_IFCHR, instance, DDI_PSEUDO, 0)
 279             != DDI_SUCCESS) {
 280                 cmn_err(CE_WARN, "!rdc: could not create node.");
 281                 goto out;
 282         }
 283         flags |= DIDNODES;
 284 
 285         rdc_bitmap_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 286             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
 287             "rdc_bitmap_mode", 0);
 288 
 289         switch (rdc_bitmap_mode) {
 290         case RDC_BMP_AUTO:              /* 0 */
 291                 break;
 292         case RDC_BMP_ALWAYS:            /* 1 */
 293                 break;
 294         case RDC_BMP_NEVER:             /* 2 */
 295                 cmn_err(CE_NOTE, "!SNDR bitmap mode override");
 296                 cmn_err(CE_CONT,
 297                     "!SNDR: bitmaps will only be written on shutdown\n");
 298                 break;
 299         default:                        /* unknown */
 300                 cmn_err(CE_NOTE,
 301                     "!SNDR: unknown bitmap mode %d - autodetecting mode",
 302                     rdc_bitmap_mode);
 303                 rdc_bitmap_mode = RDC_BMP_AUTO;
 304                 break;
 305         }
 306 
 307         rdc_bitmap_init();
 308 
 309         rdc_auto_sync = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 310             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
 311             "rdc_auto_sync", 0);
 312 
 313         i = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 314             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
 315             "rdc_health_thres", RDC_HEALTH_THRESHOLD);
 316         if (i >= RDC_MIN_HEALTH_THRES)
 317                 rdc_health_thres = i;
 318         else
 319                 cmn_err(CE_WARN, "!value rdc_heath_thres from rdc.conf ignored "
 320                     "as it is smaller than the min value of %d",
 321                     RDC_MIN_HEALTH_THRES);
 322 
 323         ddi_set_driver_private(dip, (caddr_t)flags);
 324         ddi_report_dev(dip);
 325 
 326         sndr_kstats = kstat_create(RDC_KSTAT_MODULE, 0,
 327             RDC_KSTAT_MINFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
 328             sizeof (sndr_m_stats_t) / sizeof (kstat_named_t),
 329             KSTAT_FLAG_VIRTUAL);
 330 
 331         if (sndr_kstats) {
 332                 sndr_kstats->ks_data = &sndr_info_stats;
 333                 sndr_kstats->ks_update = sndr_info_stats_update;
 334                 sndr_kstats->ks_private = &rdc_k_info[0];
 335                 kstat_install(sndr_kstats);
 336         } else
 337                         cmn_err(CE_WARN, "!SNDR: module kstats failed");
 338 
 339         return (DDI_SUCCESS);
 340 
 341 out:
 342         DTRACE_PROBE(rdc_attach_failed);
 343         ddi_set_driver_private(dip, (caddr_t)flags);
 344         (void) rdcdetach(dip, DDI_DETACH);
 345         return (DDI_FAILURE);
 346 }
 347 
 348 static int
 349 rdcdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 350 {
 351         rdc_k_info_t *krdc;
 352         rdc_u_info_t *urdc;
 353         int rdcd;
 354         intptr_t flags;
 355 
 356 
 357         if (cmd != DDI_DETACH) {
 358                 DTRACE_PROBE(rdc_detach_unknown_cmd);
 359                 return (DDI_FAILURE);
 360         }
 361 
 362         if (rdc_k_info == NULL || rdc_u_info == NULL)
 363                 goto cleanup;
 364 
 365         mutex_enter(&rdc_conf_lock);
 366 
 367         for (rdcd = 0; rdcd < rdc_max_sets; rdcd++) {
 368                 krdc = &rdc_k_info[rdcd];
 369                 urdc = &rdc_u_info[rdcd];
 370 
 371                 if (IS_ENABLED(urdc) || krdc->devices) {
 372 #ifdef DEBUG
 373                         cmn_err(CE_WARN,
 374                             "!rdc: cannot detach, rdcd %d still in use", rdcd);
 375 #endif
 376                         mutex_exit(&rdc_conf_lock);
 377                         DTRACE_PROBE(rdc_detach_err_busy);
 378                         return (DDI_FAILURE);
 379                 }
 380         }
 381 
 382         mutex_exit(&rdc_conf_lock);
 383 
 384 cleanup:
 385         flags = (intptr_t)ddi_get_driver_private(dip);
 386 
 387         if (flags & DIDNODES)
 388                 ddi_remove_minor_node(dip, NULL);
 389 
 390         if (sndr_kstats) {
 391                 kstat_delete(sndr_kstats);
 392         }
 393         if (flags & DIDINIT)
 394                 _rdc_deinit_dev();
 395 
 396         if (flags & DIDCONFIG) {
 397                 (void) _rdc_deconfigure();
 398                 (void) _rdc_unload();
 399                 rdcsrv_unload();
 400         }
 401 
 402         rdc_sync_event_destroy();
 403         rdc_link_down_free();
 404 
 405         rdc_dip = NULL;
 406         return (DDI_SUCCESS);
 407 }
 408 
 409 /* ARGSUSED */
 410 static int
 411 rdcgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 412 {
 413         int rc = DDI_FAILURE;
 414 
 415         switch (infocmd) {
 416 
 417         case DDI_INFO_DEVT2DEVINFO:
 418                 *result = rdc_dip;
 419                 rc = DDI_SUCCESS;
 420                 break;
 421 
 422         case DDI_INFO_DEVT2INSTANCE:
 423                 /* We only have a single instance */
 424                 *result = 0;
 425                 rc = DDI_SUCCESS;
 426                 break;
 427 
 428         default:
 429                 break;
 430         }
 431 
 432         return (rc);
 433 }
 434 
 435 
 436 /* ARGSUSED */
 437 
 438 static int
 439 rdcopen(dev_t *devp, int flag, int otyp, cred_t *crp)
 440 {
 441         return (0);
 442 }
 443 
 444 
 445 /* ARGSUSED */
 446 
 447 static int
 448 rdcclose(dev_t dev, int flag, int otyp, cred_t *crp)
 449 {
 450         return (0);
 451 }
 452 
 453 /* ARGSUSED */
 454 
 455 static int
 456 rdcprint(dev_t dev, char *str)
 457 {
 458         int instance = 0;
 459 
 460         cmn_err(CE_WARN, "!rdc%d: %s", instance, str);
 461         return (0);
 462 }
 463 
 464 
 465 static int
 466 convert_ioctl_args(int cmd, intptr_t arg, int mode, _rdc_ioctl_t *args)
 467 {
 468         _rdc_ioctl32_t args32;
 469 
 470         if (ddi_copyin((void *)arg, &args32, sizeof (_rdc_ioctl32_t), mode))
 471                 return (EFAULT);
 472 
 473         bzero((void *)args, sizeof (_rdc_ioctl_t));
 474 
 475         switch (cmd) {
 476         case RDC_CONFIG:
 477                 args->arg0 = (uint32_t)args32.arg0; /* _rdc_config_t * */
 478                 args->arg1 = (uint32_t)args32.arg1; /* pointer */
 479                 args->arg2 = (uint32_t)args32.arg2; /* size */
 480                 args->ustatus = (spcs_s_info_t)args32.ustatus;
 481                 break;
 482 
 483         case RDC_STATUS:
 484                 args->arg0 = (uint32_t)args32.arg0; /* pointer */
 485                 args->ustatus = (spcs_s_info_t)args32.ustatus;
 486                 break;
 487 
 488         case RDC_ENABLE_SVR:
 489                 args->arg0 = (uint32_t)args32.arg0; /* _rdc_svc_args *  */
 490                 break;
 491 
 492         case RDC_VERSION:
 493                 args->arg0 = (uint32_t)args32.arg0; /* _rdc_version_t *  */
 494                 args->ustatus = (spcs_s_info_t)args32.ustatus;
 495                 break;
 496 
 497         case RDC_SYNC_EVENT:
 498                 args->arg0 = (uint32_t)args32.arg0; /* char *  */
 499                 args->arg1 = (uint32_t)args32.arg1; /* char *  */
 500                 args->ustatus = (spcs_s_info_t)args32.ustatus;
 501                 break;
 502 
 503         case RDC_LINK_DOWN:
 504                 args->arg0 = (uint32_t)args32.arg0; /* char *  */
 505                 args->ustatus = (spcs_s_info_t)args32.ustatus;
 506                 break;
 507         case RDC_POOL_CREATE:
 508                 args->arg0 = (uint32_t)args32.arg0; /* svcpool_args *  */
 509                 break;
 510         case RDC_POOL_WAIT:
 511                 args->arg0 = (uint32_t)args32.arg0; /* int */
 512                 break;
 513         case RDC_POOL_RUN:
 514                 args->arg0 = (uint32_t)args32.arg0; /* int */
 515                 break;
 516 
 517         default:
 518                 return (EINVAL);
 519         }
 520 
 521         return (0);
 522 }
 523 
 524 
 525 /*
 526  * Yet another standard thing that is not standard ...
 527  */
 528 #ifndef offsetof
 529 #if defined(__GNUC__)
 530 #define offsetof(s, m)  __builtin_offsetof(s, m)
 531 #else
 532 #define offsetof(s, m)  ((size_t)(&(((s *)0)->m)))
 533 #endif
 534 #endif
 535 
 536 /*
 537  * Build a 32bit rdc_set structure and copyout to the user level.
 538  */
 539 int
 540 rdc_status_copy32(const void *arg, void *usetp, size_t size, int mode)
 541 {
 542         rdc_u_info_t *urdc = (rdc_u_info_t *)arg;
 543         struct rdc_set32 set32;
 544         size_t tailsize;
 545 #ifdef DEBUG
 546         size_t tailsize32;
 547 #endif
 548 
 549         bzero(&set32, sizeof (set32));
 550 
 551         tailsize = sizeof (struct rdc_addr32) -
 552             offsetof(struct rdc_addr32, intf);
 553 
 554         /* primary address structure, avoiding netbuf */
 555         bcopy(&urdc->primary.intf[0], &set32.primary.intf[0], tailsize);
 556 
 557         /* secondary address structure, avoiding netbuf */
 558         bcopy(&urdc->secondary.intf[0], &set32.secondary.intf[0], tailsize);
 559 
 560         /*
 561          * the rest, avoiding netconfig
 562          * note: the tail must be the same size in both structures
 563          */
 564         tailsize = sizeof (struct rdc_set) - offsetof(struct rdc_set, flags);
 565 #ifdef DEBUG
 566         /*
 567          * ASSERT is calling for debug reason, and tailsize32 is only declared
 568          * for ASSERT, put them under debug to avoid lint warning.
 569          */
 570         tailsize32 = sizeof (struct rdc_set32) -
 571             offsetof(struct rdc_set32, flags);
 572         ASSERT(tailsize == tailsize32);
 573 #endif
 574 
 575         bcopy(&urdc->flags, &set32.flags, tailsize);
 576 
 577         /* copyout to user level */
 578         return (ddi_copyout(&set32, usetp, size, mode));
 579 }
 580 
 581 
 582 /*
 583  * Status ioctl.
 584  */
 585 static int
 586 rdcstatus(_rdc_ioctl_t *args, int mode)
 587 {
 588         int (*copyout)(const void *, void *, size_t, int);
 589         rdc_u_info_t *urdc;
 590         rdc_k_info_t *krdc;
 591         disk_queue *dqp;
 592         char *usetp;                    /* pointer to user rdc_set structure */
 593         size_t size;                    /* sizeof user rdc_set structure */
 594         int32_t *maxsetsp;              /* address of status->maxsets; */
 595         int nset, max, i, j;
 596 
 597         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 598                 struct rdc_status32 status32;
 599 
 600                 if (ddi_copyin((void *)args->arg0, &status32,
 601                     sizeof (status32), mode)) {
 602                         return (EFAULT);
 603                 }
 604 
 605                 usetp = ((char *)args->arg0) +
 606                     offsetof(struct rdc_status32, rdc_set);
 607                 maxsetsp = (int32_t *)((char *)args->arg0 +
 608                     offsetof(struct rdc_status32, maxsets));
 609                 nset = status32.nset;
 610 
 611                 size = sizeof (struct rdc_set32);
 612                 copyout = rdc_status_copy32;
 613         } else {
 614                 struct rdc_status status;
 615 
 616                 if (ddi_copyin((void *)args->arg0, &status,
 617                     sizeof (status), mode)) {
 618                         return (EFAULT);
 619                 }
 620 
 621                 usetp = ((char *)args->arg0) +
 622                     offsetof(struct rdc_status, rdc_set);
 623                 maxsetsp = (int32_t *)((char *)args->arg0 +
 624                     offsetof(struct rdc_status, maxsets));
 625                 nset = status.nset;
 626 
 627                 size = sizeof (struct rdc_set);
 628                 copyout = ddi_copyout;
 629         }
 630 
 631         max = min(nset, rdc_max_sets);
 632 
 633         for (i = 0, j = 0; i < max; i++) {
 634                 urdc = &rdc_u_info[i];
 635                 krdc = &rdc_k_info[i];
 636 
 637                 if (!IS_ENABLED(urdc))
 638                         continue;
 639 
 640                 /*
 641                  * sneak out qstate in urdc->flags
 642                  * this is harmless because it's value is not used
 643                  * in urdc->flags. the real qstate is kept in
 644                  * group->diskq->disk_hdr.h.state
 645                  */
 646                 if (RDC_IS_DISKQ(krdc->group)) {
 647                         dqp = &krdc->group->diskq;
 648                         if (IS_QSTATE(dqp, RDC_QNOBLOCK))
 649                                 urdc->flags |= RDC_QNOBLOCK;
 650                 }
 651 
 652                 j++;
 653                 if ((*copyout)(urdc, usetp, size, mode) != 0)
 654                         return (EFAULT);
 655 
 656                 urdc->flags &= ~RDC_QNOBLOCK; /* clear qstate */
 657                 usetp += size;
 658         }
 659 
 660         /* copyout rdc_max_sets value */
 661 
 662         if (ddi_copyout(&rdc_max_sets, maxsetsp, sizeof (*maxsetsp), mode) != 0)
 663                 return (EFAULT);
 664 
 665         /* copyout number of sets manipulated */
 666 
 667         /*CONSTCOND*/
 668         ASSERT(offsetof(struct rdc_status32, nset) == 0);
 669         /*CONSTCOND*/
 670         ASSERT(offsetof(struct rdc_status, nset) == 0);
 671 
 672         return (ddi_copyout(&j, (void *)args->arg0, sizeof (int), mode));
 673 }
 674 
 675 
 676 /* ARGSUSED */
 677 
 678 static int
 679 rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
 680 {
 681         spcs_s_info_t kstatus = NULL;
 682         _rdc_ioctl_t args;
 683         int error;
 684         int rc = 0;
 685 
 686         if (cmd != RDC_STATUS) {
 687                 if ((error = drv_priv(crp)) != 0)
 688                         return (error);
 689         }
 690 #ifdef  DEBUG
 691         if (cmd == RDC_ASYNC6) {
 692                 rc = rdc_async6((void *)arg, mode, rvp);
 693                 return (rc);
 694         }
 695 
 696         if (cmd == RDC_CLRKSTAT) {
 697                 rc = rdc_clrkstat((void *)arg);
 698                 return (rc);
 699         }
 700 
 701         if (cmd == RDC_STALL0) {
 702                 if (((int)arg > 1) || ((int)arg < 0))
 703                         return (EINVAL);
 704                 rdc_stallzero((int)arg);
 705                 return (0);
 706         }
 707         if (cmd == RDC_READGEN) {
 708                 rc = rdc_readgen((void *)arg, mode, rvp);
 709                 return (rc);
 710         }
 711 #endif
 712         if (cmd == RDC_BITMAPOP) {
 713                 rdc_bitmap_op_t bmop;
 714                 rdc_bitmap_op32_t bmop32;
 715 
 716                 if (ddi_model_convert_from(mode & FMODELS)
 717                     == DDI_MODEL_ILP32) {
 718                         if (ddi_copyin((void *)arg, &bmop32, sizeof (bmop32),
 719                             mode))
 720                                 return (EFAULT);
 721                         bmop.offset = bmop32.offset;
 722                         bmop.op = bmop32.op;
 723                         (void) strncpy(bmop.sechost, bmop32.sechost,
 724                             MAX_RDC_HOST_SIZE);
 725                         (void) strncpy(bmop.secfile, bmop32.secfile,
 726                             NSC_MAXPATH);
 727                         bmop.len = bmop32.len;
 728                         bmop.addr = (unsigned long)bmop32.addr;
 729                 } else {
 730                         if (ddi_copyin((void *)arg, &bmop, sizeof (bmop),
 731                             mode))
 732                                 return (EFAULT);
 733                 }
 734                 rc = rdc_bitmapset(bmop.op, bmop.sechost, bmop.secfile,
 735                     (void *)bmop.addr, bmop.len, bmop.offset, mode);
 736                 return (rc);
 737         }
 738 
 739         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 740                 if ((rc = convert_ioctl_args(cmd, arg, mode, &args)) != 0)
 741                         return (rc);
 742         } else {
 743                 if (ddi_copyin((void *)arg, &args,
 744                     sizeof (_rdc_ioctl_t), mode)) {
 745                         return (EFAULT);
 746                 }
 747         }
 748 
 749         kstatus = spcs_s_kcreate();
 750         if (!kstatus) {
 751                 return (ENOMEM);
 752         }
 753 
 754 
 755         switch (cmd) {
 756 
 757         case RDC_POOL_CREATE: {
 758                 struct svcpool_args p;
 759 
 760                 if (ddi_copyin((void *)arg, &p, sizeof (p), mode)) {
 761                         spcs_s_kfree(kstatus);
 762                         return (EFAULT);
 763                 }
 764                 error = svc_pool_create(&p);
 765 
 766                 break;
 767         }
 768         case RDC_POOL_WAIT: {
 769                 int id;
 770 
 771                 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
 772                         spcs_s_kfree(kstatus);
 773                         return (EFAULT);
 774                 }
 775 
 776                 error = svc_wait(id);
 777                 break;
 778         }
 779         case RDC_POOL_RUN: {
 780                 int id;
 781 
 782                 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
 783                         spcs_s_kfree(kstatus);
 784                         return (EFAULT);
 785                 }
 786                 error = svc_do_run(id);
 787                 break;
 788         }
 789         case RDC_ENABLE_SVR:
 790                 {
 791                         STRUCT_DECL(rdc_svc_args, parms);
 792 
 793                         STRUCT_INIT(parms, mode);
 794                         /* Only used by sndrd which does not use unistat */
 795 
 796                         if (ddi_copyin((void *)args.arg0, STRUCT_BUF(parms),
 797                             STRUCT_SIZE(parms), mode)) {
 798                                 spcs_s_kfree(kstatus);
 799                                 return (EFAULT);
 800                         }
 801                         rc = rdc_start_server(STRUCT_BUF(parms), mode);
 802                 }
 803                 break;
 804 
 805         case RDC_STATUS:
 806                 rc = rdcstatus(&args, mode);
 807                 break;
 808 
 809         case RDC_CONFIG:
 810                 rc = _rdc_config((void *)args.arg0, mode, kstatus, rvp);
 811                 spcs_s_copyoutf(&kstatus, args.ustatus);
 812                 return (rc);
 813 
 814         case RDC_VERSION:
 815                 {
 816                         STRUCT_DECL(rdc_version, parms);
 817 
 818                         STRUCT_INIT(parms, mode);
 819 
 820                         STRUCT_FSET(parms, major, sndr_major_rev);
 821                         STRUCT_FSET(parms, minor, sndr_minor_rev);
 822                         STRUCT_FSET(parms, micro, sndr_micro_rev);
 823                         STRUCT_FSET(parms, baseline, sndr_baseline_rev);
 824 
 825                         if (ddi_copyout(STRUCT_BUF(parms), (void *)args.arg0,
 826                             STRUCT_SIZE(parms), mode)) {
 827                                 spcs_s_kfree(kstatus);
 828                                 return (EFAULT);
 829                         }
 830                         break;
 831                 }
 832 
 833         case RDC_LINK_DOWN:
 834                 /* char *host from user */
 835                 rc = _rdc_link_down((void *)args.arg0, mode, kstatus, rvp);
 836                 spcs_s_copyoutf(&kstatus, args.ustatus);
 837 
 838                 return (rc);
 839 
 840         case RDC_SYNC_EVENT:
 841                 rc = _rdc_sync_event_wait((void *)args.arg0, (void *)args.arg1,
 842                     mode, kstatus, rvp);
 843                 spcs_s_copyoutf(&kstatus, args.ustatus);
 844 
 845                 return (rc);
 846 
 847 
 848         default:
 849                 rc = EINVAL;
 850                 break;
 851         }
 852 
 853         spcs_s_kfree(kstatus);
 854         return (rc);
 855 }
 856 
 857 int
 858 sndr_info_stats_update(kstat_t *ksp, int rw)
 859 {
 860         extern int rdc_rpc_tmout;
 861         extern int rdc_health_thres;
 862         extern int rdc_bitmap_delay;
 863         extern long rdc_clnt_count;
 864         extern long rdc_svc_count;
 865         sndr_m_stats_t  *info_stats;
 866         rdc_k_info_t    *krdc;
 867 
 868         info_stats = (sndr_m_stats_t *)(ksp->ks_data);
 869         krdc = (rdc_k_info_t *)(ksp->ks_private);
 870 
 871         /* no writes currently allowed */
 872 
 873         if (rw == KSTAT_WRITE) {
 874                 return (EACCES);
 875         }
 876 
 877         /* default to READ */
 878         info_stats->m_maxsets.value.ul = rdc_max_sets;
 879         info_stats->m_maxfbas.value.ul = krdc->maxfbas;
 880         info_stats->m_rpc_timeout.value.ul = rdc_rpc_tmout;
 881         info_stats->m_health_thres.value.ul = rdc_health_thres;
 882         info_stats->m_bitmap_writes.value.ul = krdc->bitmap_write;
 883         info_stats->m_bitmap_ref_delay.value.ul = rdc_bitmap_delay;
 884 
 885         /* clts counters not implemented yet */
 886         info_stats->m_clnt_cots_calls.value.ul = rdc_clnt_count;
 887         info_stats->m_clnt_clts_calls.value.ul = 0;
 888         info_stats->m_svc_cots_calls.value.ul = rdc_svc_count;
 889         info_stats->m_svc_clts_calls.value.ul = 0;
 890 
 891         return (0);
 892 }
 893 
 894 /*
 895  * copy tailsize-1 bytes of tail of s to s1.
 896  */
 897 void
 898 rdc_str_tail_cpy(char *s1, char *s, size_t tailsize)
 899 {
 900         /* To avoid un-terminated string, max size is 16 - 1 */
 901         ssize_t offset = strlen(s) - (tailsize - 1);
 902 
 903         offset = (offset > 0) ? offset : 0;
 904 
 905         /* ensure it's null terminated */
 906         (void) strlcpy(s1, (const char *)(s + offset), tailsize);
 907 }
 908 
 909 int
 910 rdc_info_stats_update(kstat_t *ksp, int rw)
 911 {
 912         rdc_info_stats_t        *rdc_info_stats;
 913         rdc_k_info_t            *krdc;
 914         rdc_u_info_t            *urdc;
 915 
 916         rdc_info_stats = (rdc_info_stats_t *)(ksp->ks_data);
 917         krdc = (rdc_k_info_t *)(ksp->ks_private);
 918         urdc = &rdc_u_info[krdc->index];
 919 
 920         /* no writes currently allowed */
 921 
 922         if (rw == KSTAT_WRITE) {
 923                 return (EACCES);
 924         }
 925 
 926         /* default to READ */
 927         rdc_info_stats->s_flags.value.ul = urdc->flags;
 928         rdc_info_stats->s_syncflags.value.ul =
 929             urdc->sync_flags;
 930         rdc_info_stats->s_bmpflags.value.ul =
 931             urdc->bmap_flags;
 932         rdc_info_stats->s_syncpos.value.ul =
 933             urdc->sync_pos;
 934         rdc_info_stats->s_volsize.value.ul =
 935             urdc->volume_size;
 936         rdc_info_stats->s_bits_set.value.ul =
 937             urdc->bits_set;
 938         rdc_info_stats->s_autosync.value.ul =
 939             urdc->autosync;
 940         rdc_info_stats->s_maxqfbas.value.ul =
 941             urdc->maxqfbas;
 942         rdc_info_stats->s_maxqitems.value.ul =
 943             urdc->maxqitems;
 944 
 945         kstat_named_setstr(&rdc_info_stats->s_primary_vol,
 946             urdc->primary.file);
 947 
 948         kstat_named_setstr(&rdc_info_stats->s_secondary_vol,
 949             urdc->secondary.file);
 950 
 951         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
 952                 kstat_named_setstr(&rdc_info_stats->s_bitmap,
 953                     urdc->primary.bitmap);
 954         } else {
 955                 kstat_named_setstr(&rdc_info_stats->s_bitmap,
 956                     urdc->secondary.bitmap);
 957         }
 958 
 959         kstat_named_setstr(&rdc_info_stats->s_primary_intf,
 960             urdc->primary.intf);
 961 
 962         kstat_named_setstr(&rdc_info_stats->s_secondary_intf,
 963             urdc->secondary.intf);
 964 
 965         rdc_info_stats->s_type_flag.value.ul = krdc->type_flag;
 966         rdc_info_stats->s_bitmap_size.value.ul = krdc->bitmap_size;
 967         rdc_info_stats->s_disk_status.value.ul = krdc->disk_status;
 968 
 969         if (krdc->intf) {
 970                 rdc_info_stats->s_if_if_down.value.ul = krdc->intf->if_down;
 971                 rdc_info_stats->s_if_rpc_version.value.ul =
 972                     krdc->intf->rpc_version;
 973         }
 974 
 975         /* the type can change without disable/re-enable so... */
 976         bzero(rdc_info_stats->s_aqueue_type.value.c, KSTAT_DATA_CHAR_LEN);
 977         if (RDC_IS_MEMQ(krdc->group)) {
 978                 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "memory");
 979                 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
 980                     krdc->group->ra_queue.blocks_hwm;
 981                 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
 982                     krdc->group->ra_queue.nitems_hwm;
 983                 rdc_info_stats->s_aqueue_throttle.value.ul =
 984                     krdc->group->ra_queue.throttle_delay;
 985                 rdc_info_stats->s_aqueue_items.value.ul =
 986                     krdc->group->ra_queue.nitems;
 987                 rdc_info_stats->s_aqueue_blocks.value.ul =
 988                     krdc->group->ra_queue.blocks;
 989 
 990         } else if (RDC_IS_DISKQ(krdc->group)) {
 991                 disk_queue *q = &krdc->group->diskq;
 992                 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
 993                     krdc->group->diskq.blocks_hwm;
 994                 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
 995                     krdc->group->diskq.nitems_hwm;
 996                 rdc_info_stats->s_aqueue_throttle.value.ul =
 997                     krdc->group->diskq.throttle_delay;
 998                 rdc_info_stats->s_aqueue_items.value.ul = QNITEMS(q);
 999                 rdc_info_stats->s_aqueue_blocks.value.ul = QBLOCKS(q);
1000                 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "disk");
1001         }
1002 
1003         return (0);
1004 }
1005 
1006 void
1007 rdc_kstat_create(int index)
1008 {
1009         int j = index;
1010         rdc_k_info_t *krdc = &rdc_k_info[index];
1011         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1012         size_t varsize;
1013 
1014         if (!krdc->set_kstats) {
1015                 krdc->set_kstats = kstat_create(RDC_KSTAT_MODULE, j,
1016                     RDC_KSTAT_INFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1017                     sizeof (rdc_info_stats_t) / sizeof (kstat_named_t),
1018                     KSTAT_FLAG_VIRTUAL);
1019 #ifdef DEBUG
1020                 if (!krdc->set_kstats)
1021                         cmn_err(CE_NOTE, "!krdc:u_kstat null");
1022 #endif
1023 
1024                 if (krdc->set_kstats) {
1025                         /* calculate exact size of KSTAT_DATA_STRINGs */
1026                         varsize = strlen(urdc->primary.file) + 1
1027                             + strlen(urdc->secondary.file) + 1
1028                             + strlen(urdc->primary.intf) + 1
1029                             + strlen(urdc->secondary.intf) + 1;
1030                         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1031                                 varsize += strlen(urdc->primary.bitmap) + 1;
1032                         } else {
1033                                 varsize += strlen(urdc->secondary.bitmap) + 1;
1034                         }
1035 
1036                         krdc->set_kstats->ks_data_size += varsize;
1037                         krdc->set_kstats->ks_data = &rdc_info_stats;
1038                         krdc->set_kstats->ks_update = rdc_info_stats_update;
1039                         krdc->set_kstats->ks_private = &rdc_k_info[j];
1040                         kstat_install(krdc->set_kstats);
1041                 } else
1042                         cmn_err(CE_WARN, "!SNDR: k-kstats failed");
1043         }
1044 
1045         krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, j, NULL,
1046             "disk", KSTAT_TYPE_IO, 1, 0);
1047         if (krdc->io_kstats) {
1048                 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1049                 kstat_install(krdc->io_kstats);
1050         }
1051         krdc->bmp_kstats = kstat_create("sndrbmp", j, NULL,
1052             "disk", KSTAT_TYPE_IO, 1, 0);
1053         if (krdc->bmp_kstats) {
1054                 krdc->bmp_kstats->ks_lock = &krdc->bmp_kstat_mutex;
1055                 kstat_install(krdc->bmp_kstats);
1056         }
1057 }
1058 
1059 void
1060 rdc_kstat_delete(int index)
1061 {
1062         rdc_k_info_t *krdc = &rdc_k_info[index];
1063 
1064         if (krdc->set_kstats) {
1065                 kstat_delete(krdc->set_kstats);
1066                 krdc->set_kstats = NULL;
1067         }
1068 
1069         if (krdc->io_kstats) {
1070                 kstat_delete(krdc->io_kstats);
1071                 krdc->io_kstats = NULL;
1072         }
1073         if (krdc->bmp_kstats) {
1074                 kstat_delete(krdc->bmp_kstats);
1075                 krdc->bmp_kstats = NULL;
1076         }
1077 }
1078 
1079 #ifdef  DEBUG
1080 /*
1081  * Reset the io_kstat structure of the krdc specified
1082  * by the arg index.
1083  */
1084 static int
1085 rdc_clrkstat(void *arg)
1086 {
1087         int index;
1088         rdc_k_info_t *krdc;
1089 
1090         index = (int)(unsigned long)arg;
1091         if ((index < 0) || (index >= rdc_max_sets)) {
1092                 return (EINVAL);
1093         }
1094         krdc = &rdc_k_info[index];
1095         if (krdc->io_kstats) {
1096                 kstat_delete(krdc->io_kstats);
1097                 krdc->io_kstats = NULL;
1098         } else {
1099                 return (EINVAL);
1100         }
1101         krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, index, NULL,
1102             "disk", KSTAT_TYPE_IO, 1, 0);
1103         if (krdc->io_kstats) {
1104                 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1105                 kstat_install(krdc->io_kstats);
1106         } else {
1107                 return (EINVAL);
1108         }
1109         /*
1110          * clear the high water marks and throttle.
1111          */
1112         if (krdc->group) {
1113                 krdc->group->ra_queue.nitems_hwm = 0;
1114                 krdc->group->ra_queue.blocks_hwm = 0;
1115                 krdc->group->ra_queue.throttle_delay = 0;
1116         }
1117         return (0);
1118 }
1119 #endif