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