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 }