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 1109