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