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