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 #define offsetof(s, m)  ((size_t)(&((s *)0)->m))
 530 #endif
 531 
 532 /*
 533  * Build a 32bit rdc_set structure and copyout to the user level.
 534  */
 535 int
 536 rdc_status_copy32(const void *arg, void *usetp, size_t size, int mode)
 537 {
 538         rdc_u_info_t *urdc = (rdc_u_info_t *)arg;
 539         struct rdc_set32 set32;
 540         size_t tailsize;
 541 #ifdef DEBUG
 542         size_t tailsize32;
 543 #endif
 544 
 545         bzero(&set32, sizeof (set32));
 546 
 547         tailsize = sizeof (struct rdc_addr32) -
 548             offsetof(struct rdc_addr32, intf);
 549 
 550         /* primary address structure, avoiding netbuf */
 551         bcopy(&urdc->primary.intf[0], &set32.primary.intf[0], tailsize);
 552 
 553         /* secondary address structure, avoiding netbuf */
 554         bcopy(&urdc->secondary.intf[0], &set32.secondary.intf[0], tailsize);
 555 
 556         /*
 557          * the rest, avoiding netconfig
 558          * note: the tail must be the same size in both structures
 559          */
 560         tailsize = sizeof (struct rdc_set) - offsetof(struct rdc_set, flags);
 561 #ifdef DEBUG
 562         /*
 563          * ASSERT is calling for debug reason, and tailsize32 is only declared
 564          * for ASSERT, put them under debug to avoid lint warning.
 565          */
 566         tailsize32 = sizeof (struct rdc_set32) -
 567             offsetof(struct rdc_set32, flags);
 568         ASSERT(tailsize == tailsize32);
 569 #endif
 570 
 571         bcopy(&urdc->flags, &set32.flags, tailsize);
 572 
 573         /* copyout to user level */
 574         return (ddi_copyout(&set32, usetp, size, mode));
 575 }
 576 
 577 
 578 /*
 579  * Status ioctl.
 580  */
 581 static int
 582 rdcstatus(_rdc_ioctl_t *args, int mode)
 583 {
 584         int (*copyout)(const void *, void *, size_t, int);
 585         rdc_u_info_t *urdc;
 586         rdc_k_info_t *krdc;
 587         disk_queue *dqp;
 588         char *usetp;                    /* pointer to user rdc_set structure */
 589         size_t size;                    /* sizeof user rdc_set structure */
 590         int32_t *maxsetsp;              /* address of status->maxsets; */
 591         int nset, max, i, j;
 592 
 593         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 594                 struct rdc_status32 status32;
 595 
 596                 if (ddi_copyin((void *)args->arg0, &status32,
 597                     sizeof (status32), mode)) {
 598                         return (EFAULT);
 599                 }
 600 
 601                 usetp = ((char *)args->arg0) +
 602                     offsetof(struct rdc_status32, rdc_set);
 603                 maxsetsp = (int32_t *)((char *)args->arg0 +
 604                     offsetof(struct rdc_status32, maxsets));
 605                 nset = status32.nset;
 606 
 607                 size = sizeof (struct rdc_set32);
 608                 copyout = rdc_status_copy32;
 609         } else {
 610                 struct rdc_status status;
 611 
 612                 if (ddi_copyin((void *)args->arg0, &status,
 613                     sizeof (status), mode)) {
 614                         return (EFAULT);
 615                 }
 616 
 617                 usetp = ((char *)args->arg0) +
 618                     offsetof(struct rdc_status, rdc_set);
 619                 maxsetsp = (int32_t *)((char *)args->arg0 +
 620                     offsetof(struct rdc_status, maxsets));
 621                 nset = status.nset;
 622 
 623                 size = sizeof (struct rdc_set);
 624                 copyout = ddi_copyout;
 625         }
 626 
 627         max = min(nset, rdc_max_sets);
 628 
 629         for (i = 0, j = 0; i < max; i++) {
 630                 urdc = &rdc_u_info[i];
 631                 krdc = &rdc_k_info[i];
 632 
 633                 if (!IS_ENABLED(urdc))
 634                         continue;
 635 
 636                 /*
 637                  * sneak out qstate in urdc->flags
 638                  * this is harmless because it's value is not used
 639                  * in urdc->flags. the real qstate is kept in
 640                  * group->diskq->disk_hdr.h.state
 641                  */
 642                 if (RDC_IS_DISKQ(krdc->group)) {
 643                         dqp = &krdc->group->diskq;
 644                         if (IS_QSTATE(dqp, RDC_QNOBLOCK))
 645                                 urdc->flags |= RDC_QNOBLOCK;
 646                 }
 647 
 648                 j++;
 649                 if ((*copyout)(urdc, usetp, size, mode) != 0)
 650                         return (EFAULT);
 651 
 652                 urdc->flags &= ~RDC_QNOBLOCK; /* clear qstate */
 653                 usetp += size;
 654         }
 655 
 656         /* copyout rdc_max_sets value */
 657 
 658         if (ddi_copyout(&rdc_max_sets, maxsetsp, sizeof (*maxsetsp), mode) != 0)
 659                 return (EFAULT);
 660 
 661         /* copyout number of sets manipulated */
 662 
 663         /*CONSTCOND*/
 664         ASSERT(offsetof(struct rdc_status32, nset) == 0);
 665         /*CONSTCOND*/
 666         ASSERT(offsetof(struct rdc_status, nset) == 0);
 667 
 668         return (ddi_copyout(&j, (void *)args->arg0, sizeof (int), mode));
 669 }
 670 
 671 
 672 /* ARGSUSED */
 673 
 674 static int
 675 rdcioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
 676 {
 677         spcs_s_info_t kstatus = NULL;
 678         _rdc_ioctl_t args;
 679         int error;
 680         int rc = 0;
 681 
 682         if (cmd != RDC_STATUS) {
 683                 if ((error = drv_priv(crp)) != 0)
 684                         return (error);
 685         }
 686 #ifdef  DEBUG
 687         if (cmd == RDC_ASYNC6) {
 688                 rc = rdc_async6((void *)arg, mode, rvp);
 689                 return (rc);
 690         }
 691 
 692         if (cmd == RDC_CLRKSTAT) {
 693                 rc = rdc_clrkstat((void *)arg);
 694                 return (rc);
 695         }
 696 
 697         if (cmd == RDC_STALL0) {
 698                 if (((int)arg > 1) || ((int)arg < 0))
 699                         return (EINVAL);
 700                 rdc_stallzero((int)arg);
 701                 return (0);
 702         }
 703         if (cmd == RDC_READGEN) {
 704                 rc = rdc_readgen((void *)arg, mode, rvp);
 705                 return (rc);
 706         }
 707 #endif
 708         if (cmd == RDC_BITMAPOP) {
 709                 rdc_bitmap_op_t bmop;
 710                 rdc_bitmap_op32_t bmop32;
 711 
 712                 if (ddi_model_convert_from(mode & FMODELS)
 713                     == DDI_MODEL_ILP32) {
 714                         if (ddi_copyin((void *)arg, &bmop32, sizeof (bmop32),
 715                             mode))
 716                                 return (EFAULT);
 717                         bmop.offset = bmop32.offset;
 718                         bmop.op = bmop32.op;
 719                         (void) strncpy(bmop.sechost, bmop32.sechost,
 720                             MAX_RDC_HOST_SIZE);
 721                         (void) strncpy(bmop.secfile, bmop32.secfile,
 722                             NSC_MAXPATH);
 723                         bmop.len = bmop32.len;
 724                         bmop.addr = (unsigned long)bmop32.addr;
 725                 } else {
 726                         if (ddi_copyin((void *)arg, &bmop, sizeof (bmop),
 727                             mode))
 728                                 return (EFAULT);
 729                 }
 730                 rc = rdc_bitmapset(bmop.op, bmop.sechost, bmop.secfile,
 731                     (void *)bmop.addr, bmop.len, bmop.offset, mode);
 732                 return (rc);
 733         }
 734 
 735         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 736                 if ((rc = convert_ioctl_args(cmd, arg, mode, &args)) != 0)
 737                         return (rc);
 738         } else {
 739                 if (ddi_copyin((void *)arg, &args,
 740                     sizeof (_rdc_ioctl_t), mode)) {
 741                         return (EFAULT);
 742                 }
 743         }
 744 
 745         kstatus = spcs_s_kcreate();
 746         if (!kstatus) {
 747                 return (ENOMEM);
 748         }
 749 
 750 
 751         switch (cmd) {
 752 
 753         case RDC_POOL_CREATE: {
 754                 struct svcpool_args p;
 755 
 756                 if (ddi_copyin((void *)arg, &p, sizeof (p), mode)) {
 757                         spcs_s_kfree(kstatus);
 758                         return (EFAULT);
 759                 }
 760                 error = svc_pool_create(&p);
 761 
 762                 break;
 763         }
 764         case RDC_POOL_WAIT: {
 765                 int id;
 766 
 767                 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
 768                         spcs_s_kfree(kstatus);
 769                         return (EFAULT);
 770                 }
 771 
 772                 error = svc_wait(id);
 773                 break;
 774         }
 775         case RDC_POOL_RUN: {
 776                 int id;
 777 
 778                 if (ddi_copyin((void *)arg, &id, sizeof (id), mode)) {
 779                         spcs_s_kfree(kstatus);
 780                         return (EFAULT);
 781                 }
 782                 error = svc_do_run(id);
 783                 break;
 784         }
 785         case RDC_ENABLE_SVR:
 786                 {
 787                         STRUCT_DECL(rdc_svc_args, parms);
 788 
 789                         STRUCT_INIT(parms, mode);
 790                         /* Only used by sndrd which does not use unistat */
 791 
 792                         if (ddi_copyin((void *)args.arg0, STRUCT_BUF(parms),
 793                             STRUCT_SIZE(parms), mode)) {
 794                                 spcs_s_kfree(kstatus);
 795                                 return (EFAULT);
 796                         }
 797                         rc = rdc_start_server(STRUCT_BUF(parms), mode);
 798                 }
 799                 break;
 800 
 801         case RDC_STATUS:
 802                 rc = rdcstatus(&args, mode);
 803                 break;
 804 
 805         case RDC_CONFIG:
 806                 rc = _rdc_config((void *)args.arg0, mode, kstatus, rvp);
 807                 spcs_s_copyoutf(&kstatus, args.ustatus);
 808                 return (rc);
 809 
 810         case RDC_VERSION:
 811                 {
 812                         STRUCT_DECL(rdc_version, parms);
 813 
 814                         STRUCT_INIT(parms, mode);
 815 
 816                         STRUCT_FSET(parms, major, sndr_major_rev);
 817                         STRUCT_FSET(parms, minor, sndr_minor_rev);
 818                         STRUCT_FSET(parms, micro, sndr_micro_rev);
 819                         STRUCT_FSET(parms, baseline, sndr_baseline_rev);
 820 
 821                         if (ddi_copyout(STRUCT_BUF(parms), (void *)args.arg0,
 822                             STRUCT_SIZE(parms), mode)) {
 823                                 spcs_s_kfree(kstatus);
 824                                 return (EFAULT);
 825                         }
 826                         break;
 827                 }
 828 
 829         case RDC_LINK_DOWN:
 830                 /* char *host from user */
 831                 rc = _rdc_link_down((void *)args.arg0, mode, kstatus, rvp);
 832                 spcs_s_copyoutf(&kstatus, args.ustatus);
 833 
 834                 return (rc);
 835 
 836         case RDC_SYNC_EVENT:
 837                 rc = _rdc_sync_event_wait((void *)args.arg0, (void *)args.arg1,
 838                     mode, kstatus, rvp);
 839                 spcs_s_copyoutf(&kstatus, args.ustatus);
 840 
 841                 return (rc);
 842 
 843 
 844         default:
 845                 rc = EINVAL;
 846                 break;
 847         }
 848 
 849         spcs_s_kfree(kstatus);
 850         return (rc);
 851 }
 852 
 853 int
 854 sndr_info_stats_update(kstat_t *ksp, int rw)
 855 {
 856         extern int rdc_rpc_tmout;
 857         extern int rdc_health_thres;
 858         extern int rdc_bitmap_delay;
 859         extern long rdc_clnt_count;
 860         extern long rdc_svc_count;
 861         sndr_m_stats_t  *info_stats;
 862         rdc_k_info_t    *krdc;
 863 
 864         info_stats = (sndr_m_stats_t *)(ksp->ks_data);
 865         krdc = (rdc_k_info_t *)(ksp->ks_private);
 866 
 867         /* no writes currently allowed */
 868 
 869         if (rw == KSTAT_WRITE) {
 870                 return (EACCES);
 871         }
 872 
 873         /* default to READ */
 874         info_stats->m_maxsets.value.ul = rdc_max_sets;
 875         info_stats->m_maxfbas.value.ul = krdc->maxfbas;
 876         info_stats->m_rpc_timeout.value.ul = rdc_rpc_tmout;
 877         info_stats->m_health_thres.value.ul = rdc_health_thres;
 878         info_stats->m_bitmap_writes.value.ul = krdc->bitmap_write;
 879         info_stats->m_bitmap_ref_delay.value.ul = rdc_bitmap_delay;
 880 
 881         /* clts counters not implemented yet */
 882         info_stats->m_clnt_cots_calls.value.ul = rdc_clnt_count;
 883         info_stats->m_clnt_clts_calls.value.ul = 0;
 884         info_stats->m_svc_cots_calls.value.ul = rdc_svc_count;
 885         info_stats->m_svc_clts_calls.value.ul = 0;
 886 
 887         return (0);
 888 }
 889 
 890 /*
 891  * copy tailsize-1 bytes of tail of s to s1.
 892  */
 893 void
 894 rdc_str_tail_cpy(char *s1, char *s, size_t tailsize)
 895 {
 896         /* To avoid un-terminated string, max size is 16 - 1 */
 897         ssize_t offset = strlen(s) - (tailsize - 1);
 898 
 899         offset = (offset > 0) ? offset : 0;
 900 
 901         /* ensure it's null terminated */
 902         (void) strlcpy(s1, (const char *)(s + offset), tailsize);
 903 }
 904 
 905 int
 906 rdc_info_stats_update(kstat_t *ksp, int rw)
 907 {
 908         rdc_info_stats_t        *rdc_info_stats;
 909         rdc_k_info_t            *krdc;
 910         rdc_u_info_t            *urdc;
 911 
 912         rdc_info_stats = (rdc_info_stats_t *)(ksp->ks_data);
 913         krdc = (rdc_k_info_t *)(ksp->ks_private);
 914         urdc = &rdc_u_info[krdc->index];
 915 
 916         /* no writes currently allowed */
 917 
 918         if (rw == KSTAT_WRITE) {
 919                 return (EACCES);
 920         }
 921 
 922         /* default to READ */
 923         rdc_info_stats->s_flags.value.ul = urdc->flags;
 924         rdc_info_stats->s_syncflags.value.ul =
 925             urdc->sync_flags;
 926         rdc_info_stats->s_bmpflags.value.ul =
 927             urdc->bmap_flags;
 928         rdc_info_stats->s_syncpos.value.ul =
 929             urdc->sync_pos;
 930         rdc_info_stats->s_volsize.value.ul =
 931             urdc->volume_size;
 932         rdc_info_stats->s_bits_set.value.ul =
 933             urdc->bits_set;
 934         rdc_info_stats->s_autosync.value.ul =
 935             urdc->autosync;
 936         rdc_info_stats->s_maxqfbas.value.ul =
 937             urdc->maxqfbas;
 938         rdc_info_stats->s_maxqitems.value.ul =
 939             urdc->maxqitems;
 940 
 941         kstat_named_setstr(&rdc_info_stats->s_primary_vol,
 942             urdc->primary.file);
 943 
 944         kstat_named_setstr(&rdc_info_stats->s_secondary_vol,
 945             urdc->secondary.file);
 946 
 947         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
 948                 kstat_named_setstr(&rdc_info_stats->s_bitmap,
 949                     urdc->primary.bitmap);
 950         } else {
 951                 kstat_named_setstr(&rdc_info_stats->s_bitmap,
 952                     urdc->secondary.bitmap);
 953         }
 954 
 955         kstat_named_setstr(&rdc_info_stats->s_primary_intf,
 956             urdc->primary.intf);
 957 
 958         kstat_named_setstr(&rdc_info_stats->s_secondary_intf,
 959             urdc->secondary.intf);
 960 
 961         rdc_info_stats->s_type_flag.value.ul = krdc->type_flag;
 962         rdc_info_stats->s_bitmap_size.value.ul = krdc->bitmap_size;
 963         rdc_info_stats->s_disk_status.value.ul = krdc->disk_status;
 964 
 965         if (krdc->intf) {
 966                 rdc_info_stats->s_if_if_down.value.ul = krdc->intf->if_down;
 967                 rdc_info_stats->s_if_rpc_version.value.ul =
 968                     krdc->intf->rpc_version;
 969         }
 970 
 971         /* the type can change without disable/re-enable so... */
 972         bzero(rdc_info_stats->s_aqueue_type.value.c, KSTAT_DATA_CHAR_LEN);
 973         if (RDC_IS_MEMQ(krdc->group)) {
 974                 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "memory");
 975                 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
 976                     krdc->group->ra_queue.blocks_hwm;
 977                 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
 978                     krdc->group->ra_queue.nitems_hwm;
 979                 rdc_info_stats->s_aqueue_throttle.value.ul =
 980                     krdc->group->ra_queue.throttle_delay;
 981                 rdc_info_stats->s_aqueue_items.value.ul =
 982                     krdc->group->ra_queue.nitems;
 983                 rdc_info_stats->s_aqueue_blocks.value.ul =
 984                     krdc->group->ra_queue.blocks;
 985 
 986         } else if (RDC_IS_DISKQ(krdc->group)) {
 987                 disk_queue *q = &krdc->group->diskq;
 988                 rdc_info_stats->s_aqueue_blk_hwm.value.ul =
 989                     krdc->group->diskq.blocks_hwm;
 990                 rdc_info_stats->s_aqueue_itm_hwm.value.ul =
 991                     krdc->group->diskq.nitems_hwm;
 992                 rdc_info_stats->s_aqueue_throttle.value.ul =
 993                     krdc->group->diskq.throttle_delay;
 994                 rdc_info_stats->s_aqueue_items.value.ul = QNITEMS(q);
 995                 rdc_info_stats->s_aqueue_blocks.value.ul = QBLOCKS(q);
 996                 (void) strcpy(rdc_info_stats->s_aqueue_type.value.c, "disk");
 997         }
 998 
 999         return (0);
1000 }
1001 
1002 void
1003 rdc_kstat_create(int index)
1004 {
1005         int j = index;
1006         rdc_k_info_t *krdc = &rdc_k_info[index];
1007         rdc_u_info_t *urdc = &rdc_u_info[krdc->index];
1008         size_t varsize;
1009 
1010         if (!krdc->set_kstats) {
1011                 krdc->set_kstats = kstat_create(RDC_KSTAT_MODULE, j,
1012                     RDC_KSTAT_INFO, RDC_KSTAT_CLASS, KSTAT_TYPE_NAMED,
1013                     sizeof (rdc_info_stats_t) / sizeof (kstat_named_t),
1014                     KSTAT_FLAG_VIRTUAL);
1015 #ifdef DEBUG
1016                 if (!krdc->set_kstats)
1017                         cmn_err(CE_NOTE, "!krdc:u_kstat null");
1018 #endif
1019 
1020                 if (krdc->set_kstats) {
1021                         /* calculate exact size of KSTAT_DATA_STRINGs */
1022                         varsize = strlen(urdc->primary.file) + 1
1023                             + strlen(urdc->secondary.file) + 1
1024                             + strlen(urdc->primary.intf) + 1
1025                             + strlen(urdc->secondary.intf) + 1;
1026                         if (rdc_get_vflags(urdc) & RDC_PRIMARY) {
1027                                 varsize += strlen(urdc->primary.bitmap) + 1;
1028                         } else {
1029                                 varsize += strlen(urdc->secondary.bitmap) + 1;
1030                         }
1031 
1032                         krdc->set_kstats->ks_data_size += varsize;
1033                         krdc->set_kstats->ks_data = &rdc_info_stats;
1034                         krdc->set_kstats->ks_update = rdc_info_stats_update;
1035                         krdc->set_kstats->ks_private = &rdc_k_info[j];
1036                         kstat_install(krdc->set_kstats);
1037                 } else
1038                         cmn_err(CE_WARN, "!SNDR: k-kstats failed");
1039         }
1040 
1041         krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, j, NULL,
1042             "disk", KSTAT_TYPE_IO, 1, 0);
1043         if (krdc->io_kstats) {
1044                 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1045                 kstat_install(krdc->io_kstats);
1046         }
1047         krdc->bmp_kstats = kstat_create("sndrbmp", j, NULL,
1048             "disk", KSTAT_TYPE_IO, 1, 0);
1049         if (krdc->bmp_kstats) {
1050                 krdc->bmp_kstats->ks_lock = &krdc->bmp_kstat_mutex;
1051                 kstat_install(krdc->bmp_kstats);
1052         }
1053 }
1054 
1055 void
1056 rdc_kstat_delete(int index)
1057 {
1058         rdc_k_info_t *krdc = &rdc_k_info[index];
1059 
1060         if (krdc->set_kstats) {
1061                 kstat_delete(krdc->set_kstats);
1062                 krdc->set_kstats = NULL;
1063         }
1064 
1065         if (krdc->io_kstats) {
1066                 kstat_delete(krdc->io_kstats);
1067                 krdc->io_kstats = NULL;
1068         }
1069         if (krdc->bmp_kstats) {
1070                 kstat_delete(krdc->bmp_kstats);
1071                 krdc->bmp_kstats = NULL;
1072         }
1073 }
1074 
1075 #ifdef  DEBUG
1076 /*
1077  * Reset the io_kstat structure of the krdc specified
1078  * by the arg index.
1079  */
1080 static int
1081 rdc_clrkstat(void *arg)
1082 {
1083         int index;
1084         rdc_k_info_t *krdc;
1085 
1086         index = (int)(unsigned long)arg;
1087         if ((index < 0) || (index >= rdc_max_sets)) {
1088                 return (EINVAL);
1089         }
1090         krdc = &rdc_k_info[index];
1091         if (krdc->io_kstats) {
1092                 kstat_delete(krdc->io_kstats);
1093                 krdc->io_kstats = NULL;
1094         } else {
1095                 return (EINVAL);
1096         }
1097         krdc->io_kstats = kstat_create(RDC_KSTAT_MODULE, index, NULL,
1098             "disk", KSTAT_TYPE_IO, 1, 0);
1099         if (krdc->io_kstats) {
1100                 krdc->io_kstats->ks_lock = &krdc->kstat_mutex;
1101                 kstat_install(krdc->io_kstats);
1102         } else {
1103                 return (EINVAL);
1104         }
1105         /*
1106          * clear the high water marks and throttle.
1107          */
1108         if (krdc->group) {
1109                 krdc->group->ra_queue.nitems_hwm = 0;
1110                 krdc->group->ra_queue.blocks_hwm = 0;
1111                 krdc->group->ra_queue.throttle_delay = 0;
1112         }
1113         return (0);
1114 }
1115 #endif