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 _SCM_ 27 28 #include <sys/types.h> 29 #include <sys/ksynch.h> 30 #include <sys/cmn_err.h> 31 #include <sys/modctl.h> 32 #include <sys/conf.h> 33 #include <sys/errno.h> 34 #include <sys/file.h> 35 #include <sys/kmem.h> 36 #include <sys/cred.h> 37 #include <sys/ddi.h> 38 #include <sys/nsc_thread.h> 39 40 #include "sd_bcache.h" 41 #include "sd_misc.h" 42 #include "sd_trace.h" 43 #include "sd_ft.h" 44 #include "sd_io.h" 45 #include "sd_bio.h" 46 #include "sd_pcu.h" 47 #include "sd_tdaemon.h" 48 #include "sdbc_ioctl.h" 49 #include <sys/ncall/ncall.h> 50 #include <sys/nsctl/nsctl.h> 51 #include <sys/nsctl/nsvers.h> 52 53 #include <sys/sdt.h> /* dtrace is S10 or later */ 54 55 #include <sys/unistat/spcs_s.h> 56 #include <sys/unistat/spcs_s_k.h> 57 #include <sys/unistat/spcs_errors.h> 58 static dev_info_t *dev_dip; 59 dev_info_t *sdbc_get_dip(); 60 61 62 /* 63 * A global variable to set the threshold for large writes to 64 * be in write through mode when NVRAM is present. This should 65 * solve the NVRAM bandwidth problem. 66 */ 67 68 int sdbc_wrthru_len; 69 nsc_size_t sdbc_max_fbas = _SD_MAX_FBAS; 70 int sdbc_max_devs = 0; 71 72 krwlock_t sdbc_queue_lock; 73 74 static int _sd_debug_level = 0; 75 76 static kmutex_t _sd_block_lk; 77 78 #define REGISTER_SVC(X, Y) (ncall_register_svc(X, Y)) 79 #define UNREGISTER_SVC(X) (ncall_unregister_svc(X)) 80 81 const int sdbc_major_rev = ISS_VERSION_MAJ; 82 const int sdbc_minor_rev = ISS_VERSION_MIN; 83 const int sdbc_micro_rev = ISS_VERSION_MIC; 84 const int sdbc_baseline_rev = ISS_VERSION_NUM; 85 static char sdbc_version[16]; 86 87 static int _sdbc_attached = 0; 88 89 static int _sdbc_print(dev_t dev, char *s); 90 static int sdbcunload(void); 91 static int sdbcload(void); 92 static int sdbcopen(dev_t *devp, int flag, int otyp, cred_t *crp); 93 static int sdbcclose(dev_t dev, int flag, int otyp, cred_t *crp); 94 static int sdbcioctl(dev_t dev, int cmd, void *arg, int mode, cred_t *crp, 95 int *rvp); 96 static int _sdbc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 97 static int _sdbc_probe(dev_info_t *dip); 98 static int _sdbc_attach(dev_info_t *, ddi_attach_cmd_t); 99 static int _sdbc_detach(dev_info_t *, ddi_detach_cmd_t); 100 static int _sdbc_reset(dev_info_t *, ddi_reset_cmd_t); 101 102 #ifdef sun 103 /* 104 * Solaris specific driver module interface code. 105 */ 106 107 #ifdef USES_SOFT_STATE 108 struct sdbc_state { 109 dev_info_t *dip; /* everyone would need a devinfo */ 110 }; 111 112 static void *sdbc_statep; /* for soft state routines */ 113 #endif /* USES_SOFT_STATE */ 114 115 static struct cb_ops sdbc_cb_ops = { 116 sdbcopen, /* open */ 117 sdbcclose, /* close */ 118 nodev, /* not a block driver, strategy not an entry point */ 119 _sdbc_print, /* no print routine */ 120 nodev, /* no dump routine */ 121 nodev, /* read */ 122 nodev, /* write */ 123 (int (*) ()) sdbcioctl, /* ioctl */ 124 nodev, /* no devmap routine */ 125 nodev, /* no mmap routine */ 126 nodev, /* no segmap routine */ 127 nochpoll, /* no chpoll routine */ 128 ddi_prop_op, 129 0, /* not a STREAMS driver, no cb_str routine */ 130 D_NEW | D_MP, /* safe for multi-thread/multi-processor */ 131 }; 132 133 134 static struct dev_ops sdbc_ops = { 135 DEVO_REV, /* Driver build version */ 136 0, /* device reference count */ 137 _sdbc_getinfo, 138 nulldev, 139 _sdbc_probe, 140 _sdbc_attach, 141 _sdbc_detach, 142 _sdbc_reset, 143 &sdbc_cb_ops, 144 (struct bus_ops *)NULL 145 }; 146 147 static struct modldrv sdbc_ldrv = { 148 &mod_driverops, 149 "nws:Storage Cache:" ISS_VERSION_STR, 150 &sdbc_ops 151 }; 152 153 static struct modlinkage sdbc_modlinkage = { 154 MODREV_1, 155 { &sdbc_ldrv, NULL } 156 }; 157 158 /* 159 * dynmem interface 160 */ 161 static int mutex_and_condvar_flag; 162 163 /* 164 * Solaris module load time code 165 */ 166 int 167 _init(void) 168 { 169 170 int err; 171 172 mutex_and_condvar_flag = 0; 173 174 #ifdef USES_SOFT_STATE 175 ddi_soft_state_init(&sdbc_statep, sizeof (struct sdbc_state), 176 MAX_INSTANCES); 177 #endif /* USES_SOFT_STATE */ 178 179 /* 180 * It is "load" time, call the unixware equivalent. 181 */ 182 err = sdbcload(); 183 if (!err) 184 err = mod_install(&sdbc_modlinkage); 185 186 if (err) { 187 (void) sdbcunload(); 188 #ifdef USES_SOFT_STATE 189 ddi_soft_state_fini(&sdbc_statep); 190 #endif /* USES_SOFT_STATE */ 191 } 192 193 if (!err) { 194 mutex_and_condvar_flag = 1; 195 mutex_init(&dynmem_processing_dm.thread_dm_lock, "dynmem", 196 MUTEX_DRIVER, NULL); 197 cv_init(&dynmem_processing_dm.thread_dm_cv, "dynmem", 198 CV_DRIVER, NULL); 199 } 200 201 return (err); 202 203 } 204 /* 205 * Solaris module unload time code 206 */ 207 208 int 209 _fini(void) 210 { 211 int err; 212 213 if (_sd_cache_initialized) { 214 return (EBUSY); 215 } else if (_sd_ioset && 216 (_sd_ioset->set_nlive || _sd_ioset->set_nthread)) { 217 cmn_err(CE_WARN, "!sdbc:_fini() %d threads still " 218 "active; %d threads in set\n", _sd_ioset->set_nlive, 219 _sd_ioset->set_nthread); 220 return (EBUSY); 221 } 222 if ((err = mod_remove(&sdbc_modlinkage)) == 0) { 223 DTRACE_PROBE2(_sdbc_fini_mod_remove_succeeded, 224 int, err, 225 struct modlinkage *, &sdbc_modlinkage); 226 err = sdbcunload(); 227 #ifdef USES_SOFT_STATE 228 ddi_soft_state_fini(&sdbc_statep); 229 #endif /* USES_SOFT_STATE */ 230 231 if (mutex_and_condvar_flag) { 232 cv_destroy(&dynmem_processing_dm.thread_dm_cv); 233 mutex_destroy(&dynmem_processing_dm.thread_dm_lock); 234 mutex_and_condvar_flag = 0; 235 } 236 } 237 238 return (err); 239 } 240 241 /* 242 * Solaris module info code 243 */ 244 int 245 _info(struct modinfo *modinfop) 246 { 247 return (mod_info(&sdbc_modlinkage, modinfop)); 248 } 249 250 /*ARGSUSED*/ 251 static int 252 _sdbc_probe(dev_info_t *dip) 253 { 254 return (DDI_PROBE_SUCCESS); 255 } 256 257 /* 258 * Attach an instance of the device. This happens before an open 259 * can succeed. 260 */ 261 static int 262 _sdbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 263 { 264 _dm_process_vars_t local_dm_process_vars; 265 struct buf bp; 266 267 if (cmd != DDI_ATTACH) 268 return (DDI_FAILURE); 269 270 /* 271 * Get the threshold value for setting large writes in 272 * write through mode(when NVRAM is present) 273 */ 274 275 sdbc_wrthru_len = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 276 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_wrthru_thresh", 64); 277 278 /* Get sdbc_max_fbas from sdbc.conf */ 279 sdbc_max_fbas = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 280 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_max_fbas", 281 _SD_MAX_FBAS); 282 283 bp.b_bcount = (size_t)FBA_SIZE(sdbc_max_fbas); 284 minphys(&bp); /* clamps value to maxphys */ 285 286 sdbc_max_fbas = FBA_NUM(bp.b_bcount); 287 288 if (sdbc_max_fbas > _SD_MAX_FBAS) { 289 cmn_err(CE_WARN, 290 "!_sdbc_attach: sdbc_max_fbas set to %d", _SD_MAX_FBAS); 291 sdbc_max_fbas = _SD_MAX_FBAS; 292 } 293 294 /* 295 * -get the maximum list length for multipage dynmem 296 * -time between aging 297 * -number of agings before dealloc 298 * -what to report D0=shutdown, D1=thread variables 299 */ 300 dynmem_processing_dm.max_dyn_list = MAX_DYN_LIST_DEFAULT; 301 dynmem_processing_dm.monitor_dynmem_process = 302 MONITOR_DYNMEM_PROCESS_DEFAULT; 303 dynmem_processing_dm.cache_aging_ct1 = CACHE_AGING_CT_DEFAULT; 304 dynmem_processing_dm.cache_aging_ct2 = CACHE_AGING_CT_DEFAULT; 305 dynmem_processing_dm.cache_aging_ct3 = CACHE_AGING_CT_DEFAULT; 306 dynmem_processing_dm.cache_aging_sec1 = CACHE_AGING_SEC1_DEFAULT; 307 dynmem_processing_dm.cache_aging_sec2 = CACHE_AGING_SEC2_DEFAULT; 308 dynmem_processing_dm.cache_aging_sec3 = CACHE_AGING_SEC3_DEFAULT; 309 dynmem_processing_dm.cache_aging_pcnt1 = CACHE_AGING_PCNT1_DEFAULT; 310 dynmem_processing_dm.cache_aging_pcnt2 = CACHE_AGING_PCNT2_DEFAULT; 311 dynmem_processing_dm.max_holds_pcnt = MAX_HOLDS_PCNT_DEFAULT; 312 dynmem_processing_dm.process_directive = PROCESS_DIRECTIVE_DEFAULT; 313 314 local_dm_process_vars.max_dyn_list = ddi_prop_get_int(DDI_DEV_T_ANY, 315 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_max_dyn_list", 316 MAX_DYN_LIST_DEFAULT); 317 318 local_dm_process_vars.monitor_dynmem_process = 319 ddi_prop_get_int(DDI_DEV_T_ANY, dip, 320 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_monitor_dynmem", 321 MONITOR_DYNMEM_PROCESS_DEFAULT); 322 323 local_dm_process_vars.cache_aging_ct1 = ddi_prop_get_int(DDI_DEV_T_ANY, 324 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_ct1", 325 CACHE_AGING_CT_DEFAULT); 326 327 local_dm_process_vars.cache_aging_ct2 = ddi_prop_get_int(DDI_DEV_T_ANY, 328 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_ct2", 329 CACHE_AGING_CT_DEFAULT); 330 331 local_dm_process_vars.cache_aging_ct3 = ddi_prop_get_int(DDI_DEV_T_ANY, 332 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_ct3", 333 CACHE_AGING_CT_DEFAULT); 334 335 local_dm_process_vars.cache_aging_sec1 = ddi_prop_get_int(DDI_DEV_T_ANY, 336 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_sec1", 337 CACHE_AGING_SEC1_DEFAULT); 338 339 local_dm_process_vars.cache_aging_sec2 = ddi_prop_get_int(DDI_DEV_T_ANY, 340 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_sec2", 341 CACHE_AGING_SEC2_DEFAULT); 342 343 local_dm_process_vars.cache_aging_sec3 = ddi_prop_get_int(DDI_DEV_T_ANY, 344 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_sec3", 345 CACHE_AGING_SEC3_DEFAULT); 346 347 local_dm_process_vars.cache_aging_pcnt1 = 348 ddi_prop_get_int(DDI_DEV_T_ANY, dip, 349 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_pcnt1", 350 CACHE_AGING_PCNT1_DEFAULT); 351 352 local_dm_process_vars.cache_aging_pcnt2 = 353 ddi_prop_get_int(DDI_DEV_T_ANY, dip, 354 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_cache_aging_pcnt2", 355 CACHE_AGING_PCNT2_DEFAULT); 356 357 local_dm_process_vars.process_directive = 358 ddi_prop_get_int(DDI_DEV_T_ANY, dip, 359 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_process_directive", 360 PROCESS_DIRECTIVE_DEFAULT); 361 362 local_dm_process_vars.max_holds_pcnt = ddi_prop_get_int(DDI_DEV_T_ANY, 363 dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "sdbc_max_holds_pcnt", 364 MAX_HOLDS_PCNT_DEFAULT); 365 366 (void) sdbc_edit_xfer_process_vars_dm(&local_dm_process_vars); 367 368 #define MINOR_NAME "c,sdbc" /* character device */ 369 #define MINOR_NUMBER 0 370 #ifdef MINOR_NAME 371 if (ddi_create_minor_node(dip, MINOR_NAME, S_IFCHR, 372 MINOR_NUMBER, DDI_PSEUDO, 0) != DDI_SUCCESS) { 373 /* free anything we allocated here */ 374 return (DDI_FAILURE); 375 } 376 #endif /* MINOR_NAME */ 377 378 /* Announce presence of the device */ 379 ddi_report_dev(dip); 380 dev_dip = dip; 381 /* mark the device as attached, opens may proceed */ 382 _sdbc_attached = 1; 383 384 rw_init(&sdbc_queue_lock, NULL, RW_DRIVER, NULL); 385 386 return (DDI_SUCCESS); 387 } 388 389 /*ARGSUSED*/ 390 static int 391 _sdbc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 392 { 393 if (cmd == DDI_DETACH) { 394 /* 395 * Check first if the cache is still in use 396 * and if it is, prevent the detach. 397 */ 398 if (_sd_cache_initialized) 399 return (EBUSY); 400 401 _sdbc_attached = 0; 402 403 rw_destroy(&sdbc_queue_lock); 404 dev_dip = NULL; 405 406 return (DDI_SUCCESS); 407 } else 408 return (DDI_FAILURE); 409 } 410 411 /*ARGSUSED*/ 412 static int 413 _sdbc_reset(dev_info_t *dip, ddi_reset_cmd_t cmd) 414 { 415 return (DDI_SUCCESS); 416 } 417 418 /*ARGSUSED*/ 419 static int 420 _sdbc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 421 { 422 dev_t dev; 423 #ifdef USES_SOFT_STATE 424 struct sdbc_state *xsp; 425 int instance; 426 #endif /* USES_SOFT_STATE */ 427 int rc; 428 429 switch (cmd) { 430 case DDI_INFO_DEVT2INSTANCE: 431 dev = (dev_t)arg; 432 /* The "instance" number is the minor number */ 433 *result = (void *)(unsigned long)getminor(dev); 434 rc = DDI_SUCCESS; 435 break; 436 437 case DDI_INFO_DEVT2DEVINFO: 438 dev = (dev_t)arg; 439 #ifdef USES_SOFT_STATE 440 /* the instance number is the minor number */ 441 instance = getminor(dev); 442 xsp = ddi_get_soft_state(sdbc_statep, instance); 443 if (xsp == NULL) 444 return (DDI_FAILURE); 445 *result = (void *) xsp->dip; 446 #else 447 *result = (void *) NULL; 448 #endif /* USES_SOFT_STATE */ 449 rc = DDI_SUCCESS; 450 break; 451 452 default: 453 rc = DDI_FAILURE; 454 break; 455 } 456 return (rc); 457 } 458 459 /*ARGSUSED*/ 460 int 461 _sdbc_print(dev_t dev, char *s) 462 { 463 cmn_err(CE_WARN, "!sdbc(_sdbc_print) %s", s); 464 return (0); 465 } 466 #else 467 MOD_DRV_WRAPPER(sdbc, sdbcload, sdbcunload, NULL, "Storage Device Block Cache"); 468 #endif /* sun */ 469 470 static int sdbc_inited; 471 472 static int 473 sdbcinit(void) 474 { 475 int rc; 476 477 sdbc_inited = 0; 478 479 (void) strncpy(sdbc_version, _VERSION_, sizeof (sdbc_version)); 480 481 mutex_init(&_sd_cache_lock, NULL, MUTEX_DRIVER, NULL); 482 mutex_init(&_sdbc_config_lock, NULL, MUTEX_DRIVER, NULL); 483 484 #ifdef m88k 485 REGISTER_SVC(SD_DUAL_WRITE, r_sd_ifs_write); 486 REGISTER_SVC(SD_DUAL_READ, r_sd_ifs_read); 487 REGISTER_SVC(SD_SET_CD, r_sd_set_cd); 488 REGISTER_SVC(SD_GETSIZE, r_sd_getsize); 489 REGISTER_SVC(SD_DUAL_OPEN, r_sd_ifs_open); 490 REGISTER_SVC(SD_REMOTE_FLUSH, r_sd_remote_flush); 491 REGISTER_SVC(SD_SGREMOTE_FLUSH, r_sd_sgremote_flush); 492 REGISTER_SVC(SD_DISK_IO, r_sd_disk_io); 493 REGISTER_SVC(SD_GET_BMAP, r_rem_get_bmap); 494 495 if ((rc = hpf_register_module("SDBC", _sd_hpf_stats)) != 0) 496 return (rc); 497 #endif 498 REGISTER_SVC(SD_ENABLE, r_sd_ifs_cache_enable); 499 REGISTER_SVC(SD_DISABLE, r_sd_ifs_cache_disable); 500 REGISTER_SVC(SD_CD_DISCARD, r_cd_discard); 501 502 cv_init(&_sd_flush_cv, NULL, CV_DRIVER, NULL); 503 504 mutex_init(&_sd_block_lk, NULL, MUTEX_DRIVER, NULL); 505 506 sdbc_max_devs = nsc_max_devices(); 507 508 /* 509 * Initialize the bitmap array that would be useful in determining 510 * if the mask is not fragmented, instead of determinig this 511 * at run time. Also initialize a lookup array for each mask, with 512 * the starting position, the length, and the mask subset 513 */ 514 _sd_init_contig_bmap(); 515 _sd_init_lookup_map(); 516 517 if ((rc = _sdbc_iobuf_load()) != 0) 518 return (rc); 519 if ((rc = _sdbc_handles_load()) != 0) 520 return (rc); 521 if ((rc = _sdbc_tr_load()) != 0) 522 return (rc); 523 if ((rc = _sdbc_ft_load()) != 0) 524 return (rc); 525 if ((rc = _sdbc_tdaemon_load()) != 0) 526 return (rc); 527 if ((rc = _sdbc_hash_load()) != 0) 528 return (rc); 529 #ifdef DEBUG 530 _sdbc_ioj_load(); 531 #endif 532 sdbc_inited = 1; 533 534 return (0); 535 } 536 537 static int 538 sdbcunload(void) 539 { 540 if (_sd_cache_initialized) { 541 cmn_err(CE_WARN, 542 "!sdbc(sdbcunload) cannot unload module - cache in use!"); 543 return (EEXIST); 544 } 545 #ifdef m88k 546 UNREGISTER_SVC(SD_DUAL_WRITE); 547 UNREGISTER_SVC(SD_DUAL_READ); 548 UNREGISTER_SVC(SD_SET_CD); 549 UNREGISTER_SVC(SD_GETSIZE); 550 UNREGISTER_SVC(SD_DUAL_OPEN); 551 UNREGISTER_SVC(SD_REMOTE_FLUSH); 552 UNREGISTER_SVC(SD_SGREMOTE_FLUSH); 553 UNREGISTER_SVC(SD_DISK_IO); 554 UNREGISTER_SVC(SD_GET_BMAP); 555 556 (void) hpf_unregister_module("SDBC"); 557 #endif 558 UNREGISTER_SVC(SD_ENABLE); 559 UNREGISTER_SVC(SD_DISABLE); 560 UNREGISTER_SVC(SD_CD_DISCARD); 561 562 cv_destroy(&_sd_flush_cv); 563 mutex_destroy(&_sd_block_lk); 564 565 _sdbc_hash_unload(); 566 _sdbc_ft_unload(); 567 _sdbc_tr_unload(); 568 _sdbc_tdaemon_unload(); 569 _sdbc_handles_unload(); 570 _sdbc_iobuf_unload(); 571 #ifdef DEBUG 572 _sdbc_ioj_unload(); 573 #endif 574 575 mutex_destroy(&_sd_cache_lock); 576 mutex_destroy(&_sdbc_config_lock); 577 578 /* 579 * Normally we would unregister memory at deconfig time. 580 * However when chasing things like memory leaks it is 581 * useful to defer until unload time. 582 */ 583 if (_sdbc_memtype_deconfigure_delayed) 584 _sdbc_memtype_deconfigure(); 585 586 return (0); 587 } 588 589 590 static int 591 sdbcload(void) 592 { 593 int err; 594 595 if ((err = sdbcinit()) != 0) { 596 (void) sdbcunload(); 597 return (err); 598 } 599 return (0); 600 } 601 602 603 /* ARGSUSED */ 604 605 static int 606 sdbcopen(dev_t *devp, int flag, int otyp, cred_t *crp) 607 { 608 int nd = nsc_node_id(); 609 610 /* 611 * If we were statically linked in then returning an error out 612 * of sdbcinit won't prevent someone from coming thru here. 613 * We must prevent them from getting any further. 614 */ 615 if (!sdbc_inited) 616 return (EINVAL); 617 618 if (nd < nsc_min_nodeid) { 619 cmn_err(CE_WARN, 620 "!sdbc(sdbcopen) open failed, systemid (%d) must be >= %d", 621 nd, nsc_min_nodeid); 622 return (EINVAL); 623 } 624 if (!_sdbc_attached) 625 return (ENXIO); 626 627 return (0); 628 } 629 630 631 /* ARGSUSED */ 632 633 static int 634 sdbcclose(dev_t dev, int flag, int otyp, cred_t *crp) 635 { 636 return (0); 637 } 638 639 #ifdef _MULTI_DATAMODEL 640 static int 641 convert_ioctl_args(int cmd, void *arg, int mode, _sdbc_ioctl_t *args) 642 /* 643 * convert_ioctl-args - Do a case by case conversion of a ILP32 ioctl 644 * structure to an LP64 structure. 645 * The main concern here is whether to sign-extend or not. The rule 646 * is that pointers are not sign extended, the rest are obvious. 647 * Since most everything is sign-extended the definition of 648 * _sdbc_ioctl32_t uses signed fields. 649 * 650 */ 651 { 652 _sdbc_ioctl32_t args32; 653 654 if (ddi_copyin(arg, &args32, sizeof (_sdbc_ioctl32_t), mode)) 655 return (EFAULT); 656 657 bzero((void *) args, sizeof (_sdbc_ioctl_t)); 658 659 switch (cmd) { 660 661 case SDBC_UNUSED_1: 662 case SDBC_UNUSED_2: 663 case SDBC_UNUSED_3: 664 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 665 cmn_err(CE_WARN, 666 "!sdbc(convert_ioctl_args) obsolete sdbc ioctl used"); 667 return (EINVAL); 668 669 case SDBC_ADUMP: 670 args->arg0 = args32.arg0; /* cd */ 671 args->arg1 = (uint32_t)args32.arg1; /* &tt */ 672 args->arg2 = (uint32_t)args32.arg2; /* NULL (buf) */ 673 args->arg3 = args32.arg3; /* size of buf */ 674 args->arg4 = args32.arg4; /* flag */ 675 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 676 break; 677 678 case SDBC_TEST_INIT: 679 args->arg0 = (uint32_t)args32.arg0; /* fname (char *) */ 680 args->arg1 = args32.arg1; /* index */ 681 args->arg2 = args32.arg2; /* len */ 682 args->arg3 = args32.arg3; /* track size */ 683 args->arg4 = args32.arg4; /* flag */ 684 break; 685 686 case SDBC_TEST_START: 687 args->arg0 = args32.arg0; /* num */ 688 args->arg1 = args32.arg1; /* type */ 689 args->arg2 = args32.arg2; /* loops */ 690 args->arg3 = args32.arg3; /* from */ 691 args->arg4 = args32.arg4; /* seed */ 692 break; 693 694 case SDBC_TEST_END: 695 break; 696 697 case SDBC_ENABLE: 698 case SDBC_VERSION: 699 args->arg0 = (uint32_t)args32.arg0; /* pointer */ 700 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 701 break; 702 703 case SDBC_DISABLE: 704 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 705 break; 706 707 case SDBC_GET_CLUSTER_SIZE: 708 args->arg0 = (uint32_t)args32.arg0; /* (int * ) */ 709 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 710 break; 711 712 /* get the gl_file data */ 713 case SDBC_GET_CLUSTER_DATA: 714 /* pointer to array[2*cluster_size] */ 715 args->arg0 = (uint32_t)args32.arg0; 716 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 717 break; 718 719 /* get the size of the global info pages for each board */ 720 case SDBC_GET_GLMUL_SIZES: 721 args->arg0 = (uint32_t)args32.arg0; /* int[CACHE_MEM_PAD] * */ 722 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 723 break; 724 725 /* get the global info about write blocks */ 726 case SDBC_GET_GLMUL_INFO: 727 /* pointer to array[2*(sum of GLMUL_SIZES)] */ 728 args->arg0 = (uint32_t)args32.arg0; 729 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 730 break; 731 732 case SDBC_SET_CD_HINT: 733 args->arg0 = args32.arg0; /* cd */ 734 args->arg1 = args32.arg1; /* hint */ 735 args->arg2 = args32.arg2; /* flag */ 736 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 737 break; 738 739 case SDBC_GET_CD_HINT: 740 args->arg0 = args32.arg0; 741 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 742 break; 743 744 case SDBC_SET_NODE_HINT: 745 args->arg0 = args32.arg0; /* hint */ 746 args->arg1 = args32.arg1; /* flag */ 747 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 748 break; 749 750 case SDBC_GET_NODE_HINT: 751 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 752 break; 753 754 case SDBC_STATS: 755 args->arg0 = (uint32_t)args32.arg0; /* (_sd_stats_t *) */ 756 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 757 break; 758 759 case SDBC_ZAP_STATS: 760 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 761 break; 762 763 case SDBC_GET_CD_BLK: 764 args->arg0 = args32.arg0; /* cd */ 765 args->arg1 = (uint32_t)args32.arg1; /* blk */ 766 args->arg2 = (uint32_t)args32.arg2; /* (addr[5] *) */ 767 break; 768 769 case SDBC_GET_CONFIG: 770 args->arg0 = (uint32_t)args32.arg0; /* (_sdbc_config_t *) */ 771 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 772 break; 773 774 case SDBC_SET_CONFIG: 775 args->arg0 = (uint32_t)args32.arg0; /* (_sdbc_config_t *) */ 776 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 777 break; 778 779 case SDBC_MAXFILES: 780 args->arg0 = (uint32_t)args32.arg0; /* (int * ) */ 781 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 782 break; 783 784 #ifdef DEBUG 785 /* toggle flusher flag for testing */ 786 case SDBC_TOGGLE_FLUSH: 787 args->sdbc_ustatus = (spcs_s_info_t)args32.sdbc_ustatus; 788 break; 789 790 case SDBC_INJ_IOERR: /* cd, errnum */ 791 args->arg0 = args32.arg0; /* cd */ 792 args->arg1 = args32.arg1; /* i/o error number */ 793 args->arg2 = args32.arg2; /* countdown to issuing error */ 794 break; 795 796 /* clear injected i/o errors */ 797 case SDBC_CLR_IOERR: /* cd */ 798 args->arg0 = args32.arg0; /* cd */ 799 break; 800 #endif /* DEBUG */ 801 default: 802 return (EINVAL); 803 } 804 805 return (0); 806 } 807 #endif /* _MULTI_DATAMODEL */ 808 809 static int 810 sdbc_get_cd_blk(_sdbc_ioctl_t *args, int mode) 811 { 812 813 _sd_cctl_t *cc_ent; 814 caddr_t data; 815 char *taddr; 816 intptr_t addr[5]; 817 #ifdef _MULTI_DATAMODEL 818 uint32_t addr_32[5]; 819 #endif /* _MULTI_DATAMODEL */ 820 char *lookup_file = NULL; 821 int rc; 822 sdbc_info_t info; 823 nsc_off_t fba_pos; /* disk block number */ 824 825 if (_sd_cache_initialized == 0) { 826 return (EINVAL); 827 } 828 829 /* copyin the block number */ 830 if (ddi_copyin((void *)args->arg1, &fba_pos, sizeof (nsc_off_t), 831 mode)) { 832 return (EFAULT); 833 } 834 835 #ifdef _MULTI_DATAMODEL 836 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 837 if (ddi_copyin((void *)args->arg2, addr_32, sizeof (addr_32), 838 mode)) { 839 return (EFAULT); 840 } 841 addr[0] = addr_32[0]; /* (sdbc_info_t *) */ 842 addr[1] = addr_32[1]; /* (char *) cdata */ 843 addr[2] = addr_32[2]; /* ( int * ) cblk_size */ 844 addr[3] = addr_32[3]; /* ( char * ) filename */ 845 addr[4] = addr_32[4]; /* ( char *) wdata */ 846 } else { 847 if (ddi_copyin((void *)args->arg2, addr, sizeof (addr), mode)) { 848 return (EFAULT); 849 } 850 } 851 #else /* _MULTI_DATAMODEL */ 852 if (ddi_copyin((void *)args->arg2, addr, sizeof (addr), mode)) { 853 return (EFAULT); 854 } 855 #endif /* _MULTI_DATAMODEL */ 856 857 (void) copyout(&CACHE_BLOCK_SIZE, (void *)addr[2], sizeof (int)); 858 859 if (_sd_get_cd_blk((int)args->arg0, FBA_TO_BLK_NUM(fba_pos), 860 &cc_ent, &data, &lookup_file)) { 861 if (lookup_file != NULL) 862 (void) copyout(lookup_file, (void *)addr[3], 863 NSC_MAXPATH); 864 return (ENOENT); 865 } 866 rc = 0; 867 taddr = NULL; 868 869 info.ci_write = cc_ent->cc_write ? 1 : 0; 870 info.ci_dirty = cc_ent->cc_dirty; 871 info.ci_valid = cc_ent->cc_valid; 872 info.ci_cd = CENTRY_CD(cc_ent); 873 info.ci_dblk = BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)); 874 (void) copyout(lookup_file, (void *)addr[3], NSC_MAXPATH); 875 (void) copyout(&info, (void *)addr[0], sizeof (sdbc_info_t)); 876 877 (void) copyout(data, (void *)addr[1], CACHE_BLOCK_SIZE); 878 879 /* get the write data if any */ 880 if (cc_ent->cc_write) { 881 882 if (sdbc_safestore) { 883 cmn_err(CE_WARN, 884 "!sdbc(sdbc_get_cd_blk) cc_write 0x%p sc-res 0x%p", 885 (void *)cc_ent->cc_write, 886 (void *)cc_ent->cc_write->sc_res); 887 888 if ((taddr = kmem_alloc(CACHE_BLOCK_SIZE, 889 KM_NOSLEEP)) == NULL) { 890 cmn_err(CE_WARN, 891 "!sdbc(sdbc_get_cd_blk) kmem_alloc failed." 892 " cannot get write data"); 893 info.ci_write = NULL; 894 rc = EFAULT; 895 } else if (SSOP_READ_CBLOCK(sdbc_safestore, 896 cc_ent->cc_write->sc_res, taddr, 897 CACHE_BLOCK_SIZE, 0) == SS_ERR) { 898 899 cmn_err(CE_WARN, "sdbc(sdbc_get_cd_blk) " 900 "!safestore read failed"); 901 rc = EFAULT; 902 903 } else if (copyout(taddr, (void *)addr[4], 904 CACHE_BLOCK_SIZE)) { 905 cmn_err(CE_WARN, 906 "!sdbc(sdbc_get_cd_blk) copyout failed." 907 " cannot get write data"); 908 rc = EFAULT; 909 } 910 } 911 912 } 913 914 if (taddr) 915 kmem_free(taddr, CACHE_BLOCK_SIZE); 916 917 return (rc); 918 } 919 920 /* ARGSUSED */ 921 static int 922 sdbcioctl(dev_t dev, int cmd, void *arg, int mode, cred_t *crp, int *rvp) 923 { 924 int rc = 0; 925 _sdbc_ioctl_t args; 926 int convert_32 = 0; 927 spcs_s_info_t kstatus; 928 929 *rvp = 0; 930 931 #ifdef _MULTI_DATAMODEL 932 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 933 int rc; 934 convert_32 = 1; 935 if ((rc = convert_ioctl_args(cmd, arg, mode, &args)) != 0) 936 return (rc); 937 } else { 938 if (ddi_copyin(arg, &args, sizeof (_sdbc_ioctl_t), mode)) { 939 return (EFAULT); 940 } 941 } 942 #else /* _MULTI_DATAMODEL */ 943 if (ddi_copyin(arg, &args, sizeof (_sdbc_ioctl_t), mode)) { 944 return (EFAULT); 945 } 946 #endif /* _MULTI_DATAMODEL */ 947 948 kstatus = spcs_s_kcreate(); 949 if (!kstatus) 950 return (ENOMEM); 951 952 switch (cmd) { 953 954 case SDBC_UNUSED_1: 955 case SDBC_UNUSED_2: 956 case SDBC_UNUSED_3: 957 958 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 959 SDBC_EOBSOLETE)); 960 961 case SDBC_ADUMP: 962 rc = _sd_adump(&args, rvp); 963 break; 964 965 case SDBC_TEST_INIT: 966 rc = _sd_test_init(&args); 967 break; 968 969 case SDBC_TEST_START: 970 rc = _sd_test_start(&args, rvp); 971 break; 972 973 case SDBC_TEST_END: 974 rc = _sd_test_end(); 975 break; 976 977 case SDBC_ENABLE: 978 mutex_enter(&_sdbc_config_lock); 979 rc = _sdbc_configure((_sd_cache_param_t *)args.arg0, 980 NULL, kstatus); 981 if (rc && rc != EALREADY && rc != SDBC_ENONETMEM) { 982 (void) _sdbc_deconfigure(kstatus); 983 mutex_exit(&_sdbc_config_lock); 984 return (spcs_s_ocopyoutf 985 (&kstatus, args.sdbc_ustatus, rc)); 986 } 987 mutex_exit(&_sdbc_config_lock); 988 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 989 990 case SDBC_DISABLE: 991 mutex_enter(&_sdbc_config_lock); 992 if (_sd_cache_initialized == 0) { 993 994 mutex_exit(&_sdbc_config_lock); 995 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 996 SDBC_EDISABLE)); 997 } 998 rc = _sdbc_deconfigure(kstatus); 999 mutex_exit(&_sdbc_config_lock); 1000 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 1001 1002 case SDBC_GET_CLUSTER_SIZE: 1003 if (_sd_cache_initialized == 0) { 1004 1005 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1006 SDBC_ECLUSTER_SIZE)); 1007 } 1008 1009 rc = sd_get_file_info_size((void *)args.arg0); 1010 break; 1011 1012 /* get the gl_file data */ 1013 case SDBC_GET_CLUSTER_DATA: 1014 if (_sd_cache_initialized == 0) { 1015 1016 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1017 SDBC_ECLUSTER_DATA)); 1018 } 1019 rc = sd_get_file_info_data((void *)args.arg0); 1020 break; 1021 1022 /* get the size of the global info pages for each board */ 1023 case SDBC_GET_GLMUL_SIZES: 1024 if (_sd_cache_initialized == 0) { 1025 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1026 SDBC_EGLMUL_SIZE)); 1027 } 1028 rc = sd_get_glmul_sizes((void *)args.arg0); 1029 break; 1030 1031 /* get the global info about write blocks */ 1032 case SDBC_GET_GLMUL_INFO: 1033 if (_sd_cache_initialized == 0) { 1034 1035 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1036 SDBC_EGLMUL_INFO)); 1037 1038 } 1039 rc = sd_get_glmul_info((void *)args.arg0); 1040 break; 1041 1042 case SDBC_SET_CD_HINT: 1043 if (_sd_cache_initialized == 0) 1044 return (spcs_s_ocopyoutf(&kstatus, 1045 args.sdbc_ustatus, EINVAL)); 1046 rc = ((args.arg2) ? 1047 _sd_set_hint((int)args.arg0, (uint_t)args.arg1) : 1048 _sd_clear_hint((int)args.arg0, (uint_t)args.arg1)); 1049 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 1050 1051 case SDBC_GET_CD_HINT: 1052 { 1053 uint_t hint; 1054 1055 if (_sd_cache_initialized == 0) 1056 return (spcs_s_ocopyoutf(&kstatus, 1057 args.sdbc_ustatus, EINVAL)); 1058 if ((rc = _sd_get_cd_hint((int)args.arg0, &hint)) == 0) 1059 *rvp = hint; 1060 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1061 rc)); 1062 } 1063 1064 case SDBC_SET_NODE_HINT: 1065 rc = ((args.arg1) ? _sd_set_node_hint((uint_t)args.arg0) : 1066 _sd_clear_node_hint((uint_t)args.arg0)); 1067 if (rc) 1068 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1069 rc)); 1070 /* FALLTHRU */ 1071 case SDBC_GET_NODE_HINT: 1072 { 1073 uint_t hint; 1074 if ((rc = _sd_get_node_hint(&hint)) == 0) 1075 *rvp = hint; 1076 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1077 rc)); 1078 } 1079 1080 case SDBC_STATS: 1081 rc = _sd_get_stats((void *)args.arg0, convert_32); 1082 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 1083 1084 case SDBC_ZAP_STATS: 1085 _sd_zap_stats(); 1086 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 0)); 1087 1088 case SDBC_GET_CD_BLK: 1089 if (_sd_cache_initialized == 0) 1090 return (spcs_s_ocopyoutf(&kstatus, 1091 args.sdbc_ustatus, EINVAL)); 1092 rc = sdbc_get_cd_blk(&args, mode); 1093 break; 1094 1095 case SDBC_GET_CONFIG: 1096 { 1097 _sdbc_config_t sdbc_config_info; 1098 1099 if (ddi_copyin((void *)args.arg0, 1100 &sdbc_config_info, 1101 sizeof (_sdbc_config_t), 1102 mode)) { 1103 spcs_s_kfree(kstatus); 1104 return (EFAULT); 1105 } 1106 rc = _sdbc_get_config(&sdbc_config_info); 1107 (void) ddi_copyout(&sdbc_config_info, 1108 (void *)args.arg0, 1109 sizeof (_sdbc_config_t), 1110 mode); 1111 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 1112 } 1113 1114 case SDBC_SET_CONFIG: 1115 { 1116 _sdbc_config_t mgmt_config_info; 1117 1118 if (ddi_copyin((void *)args.arg0, 1119 &mgmt_config_info, 1120 sizeof (_sdbc_config_t), 1121 mode)) { 1122 spcs_s_kfree(kstatus); 1123 return (EFAULT); 1124 } 1125 1126 rc = _sdbc_configure(NULL, &mgmt_config_info, kstatus); 1127 if (rc && rc != EALREADY) { 1128 (void) _sdbc_deconfigure(kstatus); 1129 return (spcs_s_ocopyoutf 1130 (&kstatus, args.sdbc_ustatus, rc)); 1131 } 1132 1133 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, rc)); 1134 } 1135 1136 case SDBC_MAXFILES: 1137 if (copyout(&sdbc_max_devs, (void *)args.arg0, 1138 sizeof (sdbc_max_devs))) 1139 rc = EFAULT; 1140 else 1141 rc = 0; 1142 1143 break; 1144 1145 case SDBC_VERSION: 1146 { 1147 cache_version_t cache_version; 1148 1149 cache_version.major = sdbc_major_rev; 1150 cache_version.minor = sdbc_minor_rev; 1151 cache_version.micro = sdbc_micro_rev; 1152 cache_version.baseline = sdbc_baseline_rev; 1153 1154 if (ddi_copyout(&cache_version, (void *)args.arg0, 1155 sizeof (cache_version_t), mode)) { 1156 rc = EFAULT; 1157 break; 1158 } 1159 1160 break; 1161 } 1162 1163 1164 #ifdef DEBUG 1165 /* toggle flusher flag for testing */ 1166 case SDBC_TOGGLE_FLUSH: 1167 _sdbc_flush_flag ^= 1; 1168 *rvp = _sdbc_flush_flag; 1169 rc = 0; 1170 1171 return (spcs_s_ocopyoutf(&kstatus, args.sdbc_ustatus, 1172 SDBC_ETOGGLE_FLUSH, _sdbc_flush_flag ? "on" : "off")); 1173 1174 1175 /* inject i/o errors */ 1176 case SDBC_INJ_IOERR: /* cd, errnum */ 1177 if (_sd_cache_initialized == 0) 1178 return (spcs_s_ocopyoutf(&kstatus, 1179 args.sdbc_ustatus, EINVAL)); 1180 rc = _sdbc_inject_ioerr(args.arg0, args.arg1, args.arg2); 1181 break; 1182 1183 /* clear injected i/o errors */ 1184 case SDBC_CLR_IOERR: /* cd */ 1185 if (_sd_cache_initialized == 0) 1186 return (spcs_s_ocopyoutf(&kstatus, 1187 args.sdbc_ustatus, EINVAL)); 1188 rc = _sdbc_clear_ioerr(args.arg0); 1189 break; 1190 1191 #endif /* DEBUG */ 1192 default: 1193 _sd_print(3, "!SDBC unknown ioctl: 0x%x unsupported", cmd); 1194 rc = EINVAL; 1195 break; 1196 } 1197 1198 spcs_s_kfree(kstatus); 1199 return (rc); 1200 } 1201 1202 1203 /* 1204 * _sd_timed_block - sleep waiting for ticks time delay. 1205 * ticks - # of ticks to sleep 1206 * cvp - pointer to the cv we wait on while we delay. 1207 * 1208 * NO spin locks can be held at entry! 1209 * 1210 */ 1211 void 1212 _sd_timed_block(clock_t ticks, kcondvar_t *cvp) 1213 { 1214 mutex_enter(&_sd_block_lk); 1215 (void) cv_reltimedwait(cvp, &_sd_block_lk, ticks, TR_CLOCK_TICK); 1216 mutex_exit(&_sd_block_lk); 1217 } 1218 1219 1220 /* 1221 * _sd_unblock - awake a sleeper waiting on cv pointed to by cvp. 1222 * 1223 * NO spin locks can be held at entry as we may sleep. 1224 * 1225 */ 1226 void 1227 _sd_unblock(kcondvar_t *cvp) 1228 { 1229 1230 mutex_enter(&_sd_block_lk); 1231 cv_broadcast(cvp); 1232 mutex_exit(&_sd_block_lk); 1233 } 1234 1235 /* ARGSUSED */ 1236 void 1237 _sd_data_log(int num, _sd_cctl_t *centry, nsc_off_t st, nsc_size_t len) 1238 { 1239 #if defined(_SD_FBA_DATA_LOG) 1240 nsc_size_t i; 1241 nsc_off_t blk; 1242 1243 blk = BLK_TO_FBA_NUM(CENTRY_BLK(centry)); 1244 for (i = st; i < (st + len); i++) 1245 SDTRACE(num, CENTRY_CD(centry), 1, blk + i, 1246 *(int *)(centry->cc_data + FBA_SIZE(i)), 1247 *(int *)(centry->cc_data + FBA_SIZE(i) + 4)); 1248 #endif /* _SD_FBA_DATA_LOG */ 1249 } 1250 1251 /* ARGSUSED */ 1252 void 1253 _sd_data_log_chain(int num, _sd_cctl_t *centry, nsc_off_t fba_pos, 1254 nsc_size_t fba_len) 1255 { 1256 #if defined(_SD_FBA_DATA_LOG) 1257 sdbc_cblk_fba_t st_cblk_len; /* FBA len of starting cache block */ 1258 sdbc_cblk_fba_t end_cblk_len; /* FBA len of ending cache block */ 1259 sdbc_cblk_fba_t st_cblk_off; /* FBA offset into starting cblock */ 1260 1261 while (CENTRY_BLK(centry) != FBA_TO_BLK_NUM(fba_pos)) 1262 centry = centry->cc_chain; 1263 1264 st_cblk_off = BLK_FBA_OFF(fba_pos); 1265 st_cblk_len = BLK_FBAS - st_cblk_off; 1266 if (st_cblk_len >= fba_len) { 1267 end_cblk_len = 0; 1268 st_cblk_len = fba_len; 1269 } else { 1270 end_cblk_len = BLK_FBA_OFF(fba_pos + fba_len); 1271 } 1272 1273 DATA_LOG(num, centry, st_cblk_off, st_cblk_len); 1274 1275 fba_len -= st_cblk_len; 1276 centry = centry->cc_chain; 1277 1278 while (fba_len > end_cblk_len) { 1279 DATA_LOG(num, centry, 0, BLK_FBAS); 1280 fba_len -= BLK_FBAS; 1281 centry = centry->cc_chain; 1282 } 1283 if (end_cblk_len) DATA_LOG(num, centry, 0, end_cblk_len); 1284 #endif /* _SD_FBA_DATA_LOG */ 1285 } 1286 1287 1288 void 1289 _sd_zap_stats(void) 1290 { 1291 int i; 1292 1293 if (_sd_cache_stats == NULL) 1294 return; 1295 1296 _sd_cache_stats->st_rdhits = 0; 1297 _sd_cache_stats->st_rdmiss = 0; 1298 _sd_cache_stats->st_wrhits = 0; 1299 _sd_cache_stats->st_wrmiss = 0; 1300 _sd_lru_q.sq_noreq_stat = 0; 1301 _sd_lru_q.sq_req_stat = 0; 1302 1303 for (i = 0; i < sdbc_max_devs; i++) { 1304 _sd_cache_stats->st_shared[i].sh_cache_read = 0; 1305 _sd_cache_stats->st_shared[i].sh_cache_write = 0; 1306 _sd_cache_stats->st_shared[i].sh_disk_read = 0; 1307 _sd_cache_stats->st_shared[i].sh_disk_write = 0; 1308 } 1309 } 1310 1311 1312 /* 1313 * Return the cache sizes used by the Sense Subsystem Status CCW 1314 */ 1315 int 1316 _sd_cache_sizes(int *asize, int *wsize) 1317 { 1318 int psize; 1319 1320 *asize = 0; 1321 *wsize = 0; 1322 1323 /* 1324 * add in the total cache size and the 1325 * non-volatile (battery-backed) cache size. 1326 */ 1327 if (_sd_net_config.sn_configured) { 1328 psize = _sd_net_config.sn_psize; 1329 *asize += (_sd_net_config.sn_cpages * psize); 1330 *wsize += (safestore_config.ssc_wsize); 1331 } 1332 1333 return (0); 1334 } 1335 1336 1337 /*PRINTFLIKE2*/ 1338 void 1339 _sd_print(int level, char *fmt, ...) 1340 { 1341 va_list adx; 1342 if (level <= _sd_debug_level) { 1343 va_start(adx, fmt); 1344 vcmn_err(CE_NOTE, fmt, adx); 1345 va_end(adx); 1346 1347 } 1348 } 1349 1350 1351 int 1352 _sd_get_cd_blk(int cd, nsc_off_t cblk, _sd_cctl_t **cc, caddr_t *data, 1353 char **filename) 1354 { 1355 _sd_cctl_t *cc_ent; 1356 1357 if (FILE_OPENED(cd) != 0) { 1358 *filename = _sd_cache_files[cd].cd_info->sh_filename; 1359 if (cc_ent = (_sd_cctl_t *) 1360 _sd_hash_search(cd, cblk, _sd_htable)) { 1361 *cc = cc_ent; 1362 *data = (caddr_t)cc_ent->cc_data; 1363 return (0); 1364 } 1365 } 1366 return (-1); 1367 } 1368 1369 /* 1370 * central dyn mem processing vars edit rtn. 1371 * input a local copy and xfer to global 1372 * 1373 * sec0,sec1,sec2 1374 * range check 1 to 255 (arbitrary but in any case must be <= 2000 due to 1375 * 32bit signed int limits in later calc) 1376 * aging_ct 1377 * range check 1 to 255 (only 8 bits reserved for aging ctr) 1378 * 1379 */ 1380 int 1381 sdbc_edit_xfer_process_vars_dm(_dm_process_vars_t *process_vars) 1382 { 1383 if (process_vars->max_dyn_list > 0) 1384 dynmem_processing_dm.max_dyn_list = process_vars->max_dyn_list; 1385 1386 /* no edit on monitor_dynmem_process */ 1387 dynmem_processing_dm.monitor_dynmem_process = 1388 process_vars->monitor_dynmem_process; 1389 /* no edit on process_directive */ 1390 dynmem_processing_dm.process_directive = 1391 process_vars->process_directive; 1392 1393 if (process_vars->cache_aging_ct1 > 0 && 1394 process_vars->cache_aging_ct1 <= CACHE_AGING_CT_MAX) 1395 dynmem_processing_dm.cache_aging_ct1 = 1396 process_vars->cache_aging_ct1; 1397 if (process_vars->cache_aging_ct2 > 0 && 1398 process_vars->cache_aging_ct2 <= CACHE_AGING_CT_MAX) 1399 dynmem_processing_dm.cache_aging_ct2 = 1400 process_vars->cache_aging_ct2; 1401 if (process_vars->cache_aging_ct3 > 0 && 1402 process_vars->cache_aging_ct3 <= CACHE_AGING_CT_MAX) 1403 dynmem_processing_dm.cache_aging_ct3 = 1404 process_vars->cache_aging_ct3; 1405 if (process_vars->cache_aging_sec1 > 0 && 1406 process_vars->cache_aging_sec1 <= CACHE_AGING_SEC1_MAX) 1407 dynmem_processing_dm.cache_aging_sec1 = 1408 process_vars->cache_aging_sec1; 1409 if (process_vars->cache_aging_sec2 > 0 && 1410 process_vars->cache_aging_sec2 <= CACHE_AGING_SEC2_MAX) 1411 dynmem_processing_dm.cache_aging_sec2 = 1412 process_vars->cache_aging_sec2; 1413 if (process_vars->cache_aging_sec3 > 0 && 1414 process_vars->cache_aging_sec3 <= CACHE_AGING_SEC3_MAX) 1415 dynmem_processing_dm.cache_aging_sec3 = 1416 process_vars->cache_aging_sec3; 1417 if (process_vars->cache_aging_pcnt1 >= 0 && 1418 process_vars->cache_aging_pcnt1 <= CACHE_AGING_PCNT1_MAX) 1419 dynmem_processing_dm.cache_aging_pcnt1 = 1420 process_vars->cache_aging_pcnt1; 1421 if (process_vars->cache_aging_pcnt2 >= 0 && 1422 process_vars->cache_aging_pcnt2 <= CACHE_AGING_PCNT2_MAX) 1423 dynmem_processing_dm.cache_aging_pcnt2 = 1424 process_vars->cache_aging_pcnt2; 1425 if (process_vars->max_holds_pcnt >= 0 && 1426 process_vars->max_holds_pcnt <= MAX_HOLDS_PCNT_MAX) 1427 dynmem_processing_dm.max_holds_pcnt = 1428 process_vars->max_holds_pcnt; 1429 return (0); 1430 } 1431 1432 dev_info_t * 1433 sdbc_get_dip() 1434 { 1435 return (dev_dip); 1436 }