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 }