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