blob: 6554d29f764cf282f63ae7f10a9c5e67ea62d526 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
dilpreet00d09632006-04-23 15:26:28 -07005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
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/*
Stephen Hanson8cffa122009-03-18 05:54:25 -070022 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070023 * Use is subject to license terms.
24 */
Garrett D'Amorecd21e7c2012-03-11 22:00:47 -070025/*
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070028
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070029
30#include <sys/types.h>
31#include <sys/sysmacros.h>
32#include <sys/buf.h>
33#include <sys/errno.h>
34#include <sys/modctl.h>
35#include <sys/conf.h>
36#include <sys/stat.h>
37#include <sys/kmem.h>
38#include <sys/proc.h>
39#include <sys/cpuvar.h>
40#include <sys/ddi_impldefs.h>
41#include <sys/ddi.h>
dilpreet00d09632006-04-23 15:26:28 -070042#include <sys/fm/protocol.h>
43#include <sys/fm/util.h>
44#include <sys/fm/io/ddi.h>
45#include <sys/sysevent/eventdefs.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070046#include <sys/sunddi.h>
47#include <sys/sunndi.h>
48#include <sys/debug.h>
49#include <sys/bofi.h>
50#include <sys/dvma.h>
51#include <sys/bofi_impl.h>
52
53/*
54 * Testing the resilience of a hardened device driver requires a suitably wide
55 * range of different types of "typical" hardware faults to be injected,
56 * preferably in a controlled and repeatable fashion. This is not in general
57 * possible via hardware, so the "fault injection test harness" is provided.
58 * This works by intercepting calls from the driver to various DDI routines,
59 * and then corrupting the result of those DDI routine calls as if the
60 * hardware had caused the corruption.
61 *
62 * Conceptually, the bofi driver consists of two parts:
63 *
64 * A driver interface that supports a number of ioctls which allow error
65 * definitions ("errdefs") to be defined and subsequently managed. The
66 * driver is a clone driver, so each open will create a separate
67 * invocation. Any errdefs created by using ioctls to that invocation
68 * will automatically be deleted when that invocation is closed.
69 *
70 * Intercept routines: When the bofi driver is attached, it edits the
71 * bus_ops structure of the bus nexus specified by the "bofi-nexus"
72 * field in the "bofi.conf" file, thus allowing the
73 * bofi driver to intercept various ddi functions. These intercept
74 * routines primarily carry out fault injections based on the errdefs
75 * created for that device.
76 *
77 * Faults can be injected into:
78 *
79 * DMA (corrupting data for DMA to/from memory areas defined by
80 * ddi_dma_setup(), ddi_dma_bind_handle(), etc)
81 *
82 * Physical IO (corrupting data sent/received via ddi_get8(), ddi_put8(),
83 * etc),
84 *
85 * Interrupts (generating spurious interrupts, losing interrupts,
86 * delaying interrupts).
87 *
88 * By default, ddi routines called from all drivers will be intercepted
89 * and faults potentially injected. However, the "bofi-to-test" field in
90 * the "bofi.conf" file can be set to a space-separated list of drivers to
91 * test (or by preceding each driver name in the list with an "!", a list
92 * of drivers not to test).
93 *
94 * In addition to fault injection, the bofi driver does a number of static
95 * checks which are controlled by properties in the "bofi.conf" file.
96 *
97 * "bofi-ddi-check" - if set will validate that there are no PIO access
98 * other than those using the DDI routines (ddi_get8(), ddi_put8(), etc).
99 *
100 * "bofi-range-check" - if set to values 1 (warning) or 2 (panic), will
101 * validate that calls to ddi_get8(), ddi_put8(), etc are not made
102 * specifying addresses outside the range of the access_handle.
103 *
104 * "bofi-sync-check" - if set will validate that calls to ddi_dma_sync()
105 * are being made correctly.
106 */
107
108extern void *bp_mapin_common(struct buf *, int);
109
110static int bofi_ddi_check;
111static int bofi_sync_check;
112static int bofi_range_check;
113
114static struct bofi_link bofi_link_array[BOFI_NLINKS], *bofi_link_freelist;
115
116#define LLSZMASK (sizeof (uint64_t)-1)
117
118#define HDL_HASH_TBL_SIZE 64
119static struct bofi_shadow hhash_table[HDL_HASH_TBL_SIZE];
120static struct bofi_shadow dhash_table[HDL_HASH_TBL_SIZE];
121#define HDL_DHASH(x) \
122 (&dhash_table[((uintptr_t)(x) >> 3) & (HDL_HASH_TBL_SIZE-1)])
123#define HDL_HHASH(x) \
124 (&hhash_table[((uintptr_t)(x) >> 5) & (HDL_HASH_TBL_SIZE-1)])
125
126static struct bofi_shadow shadow_list;
127static struct bofi_errent *errent_listp;
128
129static char driver_list[NAMESIZE];
130static int driver_list_size;
131static int driver_list_neg;
132static char nexus_name[NAMESIZE];
133
134static int initialized = 0;
135
stephhe5ba14f2007-10-09 15:55:12 -0700136#define NCLONES 2560
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700137static int clone_tab[NCLONES];
138
139static dev_info_t *our_dip;
140
141static kmutex_t bofi_mutex;
142static kmutex_t clone_tab_mutex;
143static kmutex_t bofi_low_mutex;
144static ddi_iblock_cookie_t bofi_low_cookie;
145static uint_t bofi_signal(caddr_t arg);
146static int bofi_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
147static int bofi_attach(dev_info_t *, ddi_attach_cmd_t);
148static int bofi_detach(dev_info_t *, ddi_detach_cmd_t);
149static int bofi_open(dev_t *, int, int, cred_t *);
150static int bofi_close(dev_t, int, int, cred_t *);
151static int bofi_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
152static int bofi_errdef_alloc(struct bofi_errdef *, char *,
153 struct bofi_errent *);
154static int bofi_errdef_free(struct bofi_errent *);
155static void bofi_start(struct bofi_errctl *, char *);
156static void bofi_stop(struct bofi_errctl *, char *);
157static void bofi_broadcast(struct bofi_errctl *, char *);
158static void bofi_clear_acc_chk(struct bofi_errctl *, char *);
159static void bofi_clear_errors(struct bofi_errctl *, char *);
160static void bofi_clear_errdefs(struct bofi_errctl *, char *);
161static int bofi_errdef_check(struct bofi_errstate *,
162 struct acc_log_elem **);
163static int bofi_errdef_check_w(struct bofi_errstate *,
164 struct acc_log_elem **);
165static int bofi_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
166 off_t, off_t, caddr_t *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700167static int bofi_dma_allochdl(dev_info_t *, dev_info_t *,
168 ddi_dma_attr_t *, int (*)(caddr_t), caddr_t,
169 ddi_dma_handle_t *);
170static int bofi_dma_freehdl(dev_info_t *, dev_info_t *,
171 ddi_dma_handle_t);
172static int bofi_dma_bindhdl(dev_info_t *, dev_info_t *,
173 ddi_dma_handle_t, struct ddi_dma_req *, ddi_dma_cookie_t *,
174 uint_t *);
175static int bofi_dma_unbindhdl(dev_info_t *, dev_info_t *,
176 ddi_dma_handle_t);
177static int bofi_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
178 off_t, size_t, uint_t);
179static int bofi_dma_ctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
180 enum ddi_dma_ctlops, off_t *, size_t *, caddr_t *, uint_t);
181static int bofi_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
182 uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
183static int bofi_intr_ops(dev_info_t *dip, dev_info_t *rdip,
184 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp,
185 void *result);
dilpreet00d09632006-04-23 15:26:28 -0700186static int bofi_fm_ereport_callback(sysevent_t *ev, void *cookie);
187
188evchan_t *bofi_error_chan;
189
190#define FM_SIMULATED_DMA "simulated.dma"
191#define FM_SIMULATED_PIO "simulated.pio"
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700192
193#if defined(__sparc)
194static void bofi_dvma_kaddr_load(ddi_dma_handle_t, caddr_t, uint_t,
195 uint_t, ddi_dma_cookie_t *);
196static void bofi_dvma_unload(ddi_dma_handle_t, uint_t, uint_t);
197static void bofi_dvma_sync(ddi_dma_handle_t, uint_t, uint_t);
198static void bofi_dvma_reserve(dev_info_t *, ddi_dma_handle_t);
199#endif
200static int driver_under_test(dev_info_t *);
201static int bofi_check_acc_hdl(ddi_acc_impl_t *);
202static int bofi_check_dma_hdl(ddi_dma_impl_t *);
203static int bofi_post_event(dev_info_t *dip, dev_info_t *rdip,
204 ddi_eventcookie_t eventhdl, void *impl_data);
205
206static struct bus_ops bofi_bus_ops = {
207 BUSO_REV,
208 bofi_map,
209 NULL,
210 NULL,
211 NULL,
212 i_ddi_map_fault,
Garrett D'Amorecd21e7c2012-03-11 22:00:47 -0700213 NULL,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700214 bofi_dma_allochdl,
215 bofi_dma_freehdl,
216 bofi_dma_bindhdl,
217 bofi_dma_unbindhdl,
218 bofi_dma_flush,
219 bofi_dma_win,
220 bofi_dma_ctl,
221 NULL,
222 ddi_bus_prop_op,
223 ndi_busop_get_eventcookie,
224 ndi_busop_add_eventcall,
225 ndi_busop_remove_eventcall,
226 bofi_post_event,
227 NULL,
228 0,
229 0,
230 0,
231 0,
232 0,
233 0,
234 0,
235 bofi_intr_ops
236};
237
238static struct cb_ops bofi_cb_ops = {
ctha913d552005-07-29 08:45:16 -0700239 bofi_open, /* open */
240 bofi_close, /* close */
241 nodev, /* strategy */
242 nodev, /* print */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700243 nodev, /* dump */
ctha913d552005-07-29 08:45:16 -0700244 nodev, /* read */
245 nodev, /* write */
246 bofi_ioctl, /* ioctl */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700247 nodev, /* devmap */
ctha913d552005-07-29 08:45:16 -0700248 nodev, /* mmap */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700249 nodev, /* segmap */
ctha913d552005-07-29 08:45:16 -0700250 nochpoll, /* chpoll */
251 ddi_prop_op, /* prop_op */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700252 NULL, /* for STREAMS drivers */
ctha913d552005-07-29 08:45:16 -0700253 D_MP, /* driver compatibility flag */
254 CB_REV, /* cb_ops revision */
255 nodev, /* aread */
256 nodev /* awrite */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700257};
258
259static struct dev_ops bofi_ops = {
260 DEVO_REV, /* driver build version */
261 0, /* device reference count */
262 bofi_getinfo,
263 nulldev,
264 nulldev, /* probe */
265 bofi_attach,
266 bofi_detach,
267 nulldev, /* reset */
268 &bofi_cb_ops,
269 (struct bus_ops *)NULL,
Sherry Moore19397402008-09-22 16:30:26 -0700270 nulldev, /* power */
271 ddi_quiesce_not_needed, /* quiesce */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700272};
273
274/* module configuration stuff */
275static void *statep;
276
277static struct modldrv modldrv = {
278 &mod_driverops,
Sherry Moore19397402008-09-22 16:30:26 -0700279 "bofi driver",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700280 &bofi_ops
281};
282
283static struct modlinkage modlinkage = {
284 MODREV_1,
285 &modldrv,
286 0
287};
288
289static struct bus_ops save_bus_ops;
290
291#if defined(__sparc)
292static struct dvma_ops bofi_dvma_ops = {
293 DVMAO_REV,
294 bofi_dvma_kaddr_load,
295 bofi_dvma_unload,
296 bofi_dvma_sync
297};
298#endif
299
300/*
301 * support routine - map user page into kernel virtual
302 */
303static caddr_t
304dmareq_mapin(offset_t len, caddr_t addr, struct as *as, int flag)
305{
306 struct buf buf;
307 struct proc proc;
308
309 /*
310 * mock up a buf structure so we can call bp_mapin_common()
311 */
312 buf.b_flags = B_PHYS;
313 buf.b_un.b_addr = (caddr_t)addr;
314 buf.b_bcount = (size_t)len;
315 proc.p_as = as;
316 buf.b_proc = &proc;
317 return (bp_mapin_common(&buf, flag));
318}
319
320
321/*
322 * support routine - map page chain into kernel virtual
323 */
324static caddr_t
325dmareq_pp_mapin(offset_t len, uint_t offset, page_t *pp, int flag)
326{
327 struct buf buf;
328
329 /*
330 * mock up a buf structure so we can call bp_mapin_common()
331 */
332 buf.b_flags = B_PAGEIO;
333 buf.b_un.b_addr = (caddr_t)(uintptr_t)offset;
334 buf.b_bcount = (size_t)len;
335 buf.b_pages = pp;
336 return (bp_mapin_common(&buf, flag));
337}
338
339
340/*
341 * support routine - map page array into kernel virtual
342 */
343static caddr_t
344dmareq_pplist_mapin(uint_t len, caddr_t addr, page_t **pplist, struct as *as,
345 int flag)
346{
347 struct buf buf;
348 struct proc proc;
349
350 /*
351 * mock up a buf structure so we can call bp_mapin_common()
352 */
353 buf.b_flags = B_PHYS|B_SHADOW;
354 buf.b_un.b_addr = addr;
355 buf.b_bcount = len;
356 buf.b_shadow = pplist;
357 proc.p_as = as;
358 buf.b_proc = &proc;
359 return (bp_mapin_common(&buf, flag));
360}
361
362
363/*
364 * support routine - map dmareq into kernel virtual if not already
365 * fills in *lenp with length
366 * *mapaddr will be new kernel virtual address - or null if no mapping needed
367 */
368static caddr_t
369ddi_dmareq_mapin(struct ddi_dma_req *dmareqp, caddr_t *mapaddrp,
370 offset_t *lenp)
371{
372 int sleep = (dmareqp->dmar_fp == DDI_DMA_SLEEP) ? VM_SLEEP: VM_NOSLEEP;
373
374 *lenp = dmareqp->dmar_object.dmao_size;
375 if (dmareqp->dmar_object.dmao_type == DMA_OTYP_PAGES) {
376 *mapaddrp = dmareq_pp_mapin(dmareqp->dmar_object.dmao_size,
377 dmareqp->dmar_object.dmao_obj.pp_obj.pp_offset,
378 dmareqp->dmar_object.dmao_obj.pp_obj.pp_pp, sleep);
379 return (*mapaddrp);
380 } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_priv != NULL) {
381 *mapaddrp = dmareq_pplist_mapin(dmareqp->dmar_object.dmao_size,
382 dmareqp->dmar_object.dmao_obj.virt_obj.v_addr,
383 dmareqp->dmar_object.dmao_obj.virt_obj.v_priv,
384 dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep);
385 return (*mapaddrp);
386 } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == &kas) {
387 *mapaddrp = NULL;
388 return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr);
389 } else if (dmareqp->dmar_object.dmao_obj.virt_obj.v_as == NULL) {
390 *mapaddrp = NULL;
391 return (dmareqp->dmar_object.dmao_obj.virt_obj.v_addr);
392 } else {
393 *mapaddrp = dmareq_mapin(dmareqp->dmar_object.dmao_size,
394 dmareqp->dmar_object.dmao_obj.virt_obj.v_addr,
395 dmareqp->dmar_object.dmao_obj.virt_obj.v_as, sleep);
396 return (*mapaddrp);
397 }
398}
399
400
401/*
402 * support routine - free off kernel virtual mapping as allocated by
403 * ddi_dmareq_mapin()
404 */
405static void
stephhcecfa352007-04-05 03:14:36 -0700406ddi_dmareq_mapout(caddr_t addr, offset_t len, int map_flags, page_t *pp,
407 page_t **pplist)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700408{
409 struct buf buf;
410
411 if (addr == NULL)
412 return;
413 /*
414 * mock up a buf structure
415 */
stephhcecfa352007-04-05 03:14:36 -0700416 buf.b_flags = B_REMAPPED | map_flags;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700417 buf.b_un.b_addr = addr;
418 buf.b_bcount = (size_t)len;
stephhcecfa352007-04-05 03:14:36 -0700419 buf.b_pages = pp;
420 buf.b_shadow = pplist;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700421 bp_mapout(&buf);
422}
423
424static time_t
425bofi_gettime()
426{
427 timestruc_t ts;
428
429 gethrestime(&ts);
430 return (ts.tv_sec);
431}
432
433/*
434 * reset the bus_ops structure of the specified nexus to point to
435 * the original values in the save_bus_ops structure.
436 *
437 * Note that both this routine and modify_bus_ops() rely on the current
438 * behavior of the framework in that nexus drivers are not unloadable
439 *
440 */
441
442static int
443reset_bus_ops(char *name, struct bus_ops *bop)
444{
445 struct modctl *modp;
446 struct modldrv *mp;
447 struct bus_ops *bp;
448 struct dev_ops *ops;
449
450 mutex_enter(&mod_lock);
451 /*
452 * find specified module
453 */
454 modp = &modules;
455 do {
456 if (strcmp(name, modp->mod_modname) == 0) {
457 if (!modp->mod_linkage) {
458 mutex_exit(&mod_lock);
459 return (0);
460 }
461 mp = modp->mod_linkage->ml_linkage[0];
462 if (!mp || !mp->drv_dev_ops) {
463 mutex_exit(&mod_lock);
464 return (0);
465 }
466 ops = mp->drv_dev_ops;
467 bp = ops->devo_bus_ops;
468 if (!bp) {
469 mutex_exit(&mod_lock);
470 return (0);
471 }
472 if (ops->devo_refcnt > 0) {
473 /*
474 * As long as devices are active with modified
475 * bus ops bofi must not go away. There may be
476 * drivers with modified access or dma handles.
477 */
478 mutex_exit(&mod_lock);
479 return (0);
480 }
481 cmn_err(CE_NOTE, "bofi reset bus_ops for %s",
482 mp->drv_linkinfo);
483 bp->bus_intr_op = bop->bus_intr_op;
484 bp->bus_post_event = bop->bus_post_event;
485 bp->bus_map = bop->bus_map;
486 bp->bus_dma_map = bop->bus_dma_map;
487 bp->bus_dma_allochdl = bop->bus_dma_allochdl;
488 bp->bus_dma_freehdl = bop->bus_dma_freehdl;
489 bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
490 bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
491 bp->bus_dma_flush = bop->bus_dma_flush;
492 bp->bus_dma_win = bop->bus_dma_win;
493 bp->bus_dma_ctl = bop->bus_dma_ctl;
494 mutex_exit(&mod_lock);
495 return (1);
496 }
497 } while ((modp = modp->mod_next) != &modules);
498 mutex_exit(&mod_lock);
499 return (0);
500}
501
502/*
503 * modify the bus_ops structure of the specified nexus to point to bofi
504 * routines, saving the original values in the save_bus_ops structure
505 */
506
507static int
508modify_bus_ops(char *name, struct bus_ops *bop)
509{
510 struct modctl *modp;
511 struct modldrv *mp;
512 struct bus_ops *bp;
513 struct dev_ops *ops;
514
515 if (ddi_name_to_major(name) == -1)
516 return (0);
517
518 mutex_enter(&mod_lock);
519 /*
520 * find specified module
521 */
522 modp = &modules;
523 do {
524 if (strcmp(name, modp->mod_modname) == 0) {
525 if (!modp->mod_linkage) {
526 mutex_exit(&mod_lock);
527 return (0);
528 }
529 mp = modp->mod_linkage->ml_linkage[0];
530 if (!mp || !mp->drv_dev_ops) {
531 mutex_exit(&mod_lock);
532 return (0);
533 }
534 ops = mp->drv_dev_ops;
535 bp = ops->devo_bus_ops;
536 if (!bp) {
537 mutex_exit(&mod_lock);
538 return (0);
539 }
540 if (ops->devo_refcnt == 0) {
541 /*
542 * If there is no device active for this
543 * module then there is nothing to do for bofi.
544 */
545 mutex_exit(&mod_lock);
546 return (0);
547 }
548 cmn_err(CE_NOTE, "bofi modify bus_ops for %s",
549 mp->drv_linkinfo);
550 save_bus_ops = *bp;
551 bp->bus_intr_op = bop->bus_intr_op;
552 bp->bus_post_event = bop->bus_post_event;
553 bp->bus_map = bop->bus_map;
554 bp->bus_dma_map = bop->bus_dma_map;
555 bp->bus_dma_allochdl = bop->bus_dma_allochdl;
556 bp->bus_dma_freehdl = bop->bus_dma_freehdl;
557 bp->bus_dma_bindhdl = bop->bus_dma_bindhdl;
558 bp->bus_dma_unbindhdl = bop->bus_dma_unbindhdl;
559 bp->bus_dma_flush = bop->bus_dma_flush;
560 bp->bus_dma_win = bop->bus_dma_win;
561 bp->bus_dma_ctl = bop->bus_dma_ctl;
562 mutex_exit(&mod_lock);
563 return (1);
564 }
565 } while ((modp = modp->mod_next) != &modules);
566 mutex_exit(&mod_lock);
567 return (0);
568}
569
570
571int
572_init(void)
573{
574 int e;
575
576 e = ddi_soft_state_init(&statep, sizeof (struct bofi_errent), 1);
577 if (e != 0)
578 return (e);
579 if ((e = mod_install(&modlinkage)) != 0)
580 ddi_soft_state_fini(&statep);
581 return (e);
582}
583
584
585int
586_fini(void)
587{
588 int e;
589
590 if ((e = mod_remove(&modlinkage)) != 0)
591 return (e);
592 ddi_soft_state_fini(&statep);
593 return (e);
594}
595
596
597int
598_info(struct modinfo *modinfop)
599{
600 return (mod_info(&modlinkage, modinfop));
601}
602
603
604static int
605bofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
606{
607 char *name;
608 char buf[80];
609 int i;
610 int s, ss;
611 int size = NAMESIZE;
612 int new_string;
613 char *ptr;
614
615 if (cmd != DDI_ATTACH)
616 return (DDI_FAILURE);
617 /*
618 * only one instance - but we clone using the open routine
619 */
620 if (ddi_get_instance(dip) > 0)
621 return (DDI_FAILURE);
622
623 if (!initialized) {
624 if ((name = ddi_get_name(dip)) == NULL)
625 return (DDI_FAILURE);
626 (void) snprintf(buf, sizeof (buf), "%s,ctl", name);
627 if (ddi_create_minor_node(dip, buf, S_IFCHR, 0,
628 DDI_PSEUDO, NULL) == DDI_FAILURE)
629 return (DDI_FAILURE);
630
631 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_MED,
632 &bofi_low_cookie) != DDI_SUCCESS) {
633 ddi_remove_minor_node(dip, buf);
634 return (DDI_FAILURE); /* fail attach */
635 }
636 /*
637 * get nexus name (from conf file)
638 */
639 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
640 "bofi-nexus", nexus_name, &size) != DDI_PROP_SUCCESS) {
641 ddi_remove_minor_node(dip, buf);
642 return (DDI_FAILURE);
643 }
644 /*
645 * get whether to do dma map kmem private checking
646 */
647 if ((bofi_range_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
648 dip, 0, "bofi-range-check", &ptr)) != DDI_PROP_SUCCESS)
649 bofi_range_check = 0;
650 else if (strcmp(ptr, "panic") == 0)
651 bofi_range_check = 2;
652 else if (strcmp(ptr, "warn") == 0)
653 bofi_range_check = 1;
654 else
655 bofi_range_check = 0;
656 ddi_prop_free(ptr);
657
658 /*
659 * get whether to prevent direct access to register
660 */
661 if ((bofi_ddi_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
662 dip, 0, "bofi-ddi-check", &ptr)) != DDI_PROP_SUCCESS)
663 bofi_ddi_check = 0;
664 else if (strcmp(ptr, "on") == 0)
665 bofi_ddi_check = 1;
666 else
667 bofi_ddi_check = 0;
668 ddi_prop_free(ptr);
669
670 /*
671 * get whether to do copy on ddi_dma_sync
672 */
673 if ((bofi_sync_check = ddi_prop_lookup_string(DDI_DEV_T_ANY,
674 dip, 0, "bofi-sync-check", &ptr)) != DDI_PROP_SUCCESS)
675 bofi_sync_check = 0;
676 else if (strcmp(ptr, "on") == 0)
677 bofi_sync_check = 1;
678 else
679 bofi_sync_check = 0;
680 ddi_prop_free(ptr);
681
682 /*
683 * get driver-under-test names (from conf file)
684 */
685 size = NAMESIZE;
686 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, 0,
687 "bofi-to-test", driver_list, &size) != DDI_PROP_SUCCESS)
688 driver_list[0] = 0;
689 /*
690 * and convert into a sequence of strings
691 */
692 driver_list_neg = 1;
693 new_string = 1;
694 driver_list_size = strlen(driver_list);
695 for (i = 0; i < driver_list_size; i++) {
696 if (driver_list[i] == ' ') {
697 driver_list[i] = '\0';
698 new_string = 1;
699 } else if (new_string) {
700 if (driver_list[i] != '!')
701 driver_list_neg = 0;
702 new_string = 0;
703 }
704 }
705 /*
706 * initialize mutex, lists
707 */
708 mutex_init(&clone_tab_mutex, NULL, MUTEX_DRIVER,
709 NULL);
710 /*
711 * fake up iblock cookie - need to protect outselves
712 * against drivers that use hilevel interrupts
713 */
714 ss = spl8();
715 s = spl8();
716 splx(ss);
717 mutex_init(&bofi_mutex, NULL, MUTEX_SPIN, (void *)(uintptr_t)s);
718 mutex_init(&bofi_low_mutex, NULL, MUTEX_DRIVER,
719 (void *)bofi_low_cookie);
720 shadow_list.next = &shadow_list;
721 shadow_list.prev = &shadow_list;
722 for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
723 hhash_table[i].hnext = &hhash_table[i];
724 hhash_table[i].hprev = &hhash_table[i];
725 dhash_table[i].dnext = &dhash_table[i];
726 dhash_table[i].dprev = &dhash_table[i];
727 }
728 for (i = 1; i < BOFI_NLINKS; i++)
729 bofi_link_array[i].link = &bofi_link_array[i-1];
730 bofi_link_freelist = &bofi_link_array[BOFI_NLINKS - 1];
731 /*
732 * overlay bus_ops structure
733 */
734 if (modify_bus_ops(nexus_name, &bofi_bus_ops) == 0) {
735 ddi_remove_minor_node(dip, buf);
736 mutex_destroy(&clone_tab_mutex);
737 mutex_destroy(&bofi_mutex);
738 mutex_destroy(&bofi_low_mutex);
739 return (DDI_FAILURE);
740 }
dilpreet00d09632006-04-23 15:26:28 -0700741 if (sysevent_evc_bind(FM_ERROR_CHAN, &bofi_error_chan, 0) == 0)
742 (void) sysevent_evc_subscribe(bofi_error_chan, "bofi",
743 EC_FM, bofi_fm_ereport_callback, NULL, 0);
744
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700745 /*
746 * save dip for getinfo
747 */
748 our_dip = dip;
749 ddi_report_dev(dip);
750 initialized = 1;
751 }
752 return (DDI_SUCCESS);
753}
754
755
756static int
757bofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
758{
759 char *name;
760 char buf[80];
761
762 if (cmd != DDI_DETACH)
763 return (DDI_FAILURE);
764 if (ddi_get_instance(dip) > 0)
765 return (DDI_FAILURE);
766 if ((name = ddi_get_name(dip)) == NULL)
767 return (DDI_FAILURE);
768 (void) snprintf(buf, sizeof (buf), "%s,ctl", name);
769 mutex_enter(&bofi_low_mutex);
770 mutex_enter(&bofi_mutex);
771 /*
772 * make sure test bofi is no longer in use
773 */
774 if (shadow_list.next != &shadow_list || errent_listp != NULL) {
775 mutex_exit(&bofi_mutex);
776 mutex_exit(&bofi_low_mutex);
777 return (DDI_FAILURE);
778 }
779 mutex_exit(&bofi_mutex);
780 mutex_exit(&bofi_low_mutex);
781
782 /*
783 * restore bus_ops structure
784 */
785 if (reset_bus_ops(nexus_name, &save_bus_ops) == 0)
786 return (DDI_FAILURE);
787
Gavin Maltby49b225e2009-11-19 15:28:11 +1100788 (void) sysevent_evc_unbind(bofi_error_chan);
dilpreet00d09632006-04-23 15:26:28 -0700789
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700790 mutex_destroy(&clone_tab_mutex);
791 mutex_destroy(&bofi_mutex);
792 mutex_destroy(&bofi_low_mutex);
793 ddi_remove_minor_node(dip, buf);
794 our_dip = NULL;
795 initialized = 0;
796 return (DDI_SUCCESS);
797}
798
799
800/* ARGSUSED */
801static int
802bofi_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
803{
804 dev_t dev = (dev_t)arg;
805 int minor = (int)getminor(dev);
806 int retval;
807
808 switch (cmd) {
809 case DDI_INFO_DEVT2DEVINFO:
810 if (minor != 0 || our_dip == NULL) {
811 *result = (void *)NULL;
812 retval = DDI_FAILURE;
813 } else {
814 *result = (void *)our_dip;
815 retval = DDI_SUCCESS;
816 }
817 break;
818 case DDI_INFO_DEVT2INSTANCE:
819 *result = (void *)0;
820 retval = DDI_SUCCESS;
821 break;
822 default:
823 retval = DDI_FAILURE;
824 }
825 return (retval);
826}
827
828
829/* ARGSUSED */
830static int
831bofi_open(dev_t *devp, int flag, int otyp, cred_t *credp)
832{
833 int minor = (int)getminor(*devp);
834 struct bofi_errent *softc;
835
836 /*
837 * only allow open on minor=0 - the clone device
838 */
839 if (minor != 0)
840 return (ENXIO);
841 /*
842 * fail if not attached
843 */
844 if (!initialized)
845 return (ENXIO);
846 /*
847 * find a free slot and grab it
848 */
849 mutex_enter(&clone_tab_mutex);
850 for (minor = 1; minor < NCLONES; minor++) {
851 if (clone_tab[minor] == 0) {
852 clone_tab[minor] = 1;
853 break;
854 }
855 }
856 mutex_exit(&clone_tab_mutex);
857 if (minor == NCLONES)
858 return (EAGAIN);
859 /*
860 * soft state structure for this clone is used to maintain a list
861 * of allocated errdefs so they can be freed on close
862 */
863 if (ddi_soft_state_zalloc(statep, minor) != DDI_SUCCESS) {
864 mutex_enter(&clone_tab_mutex);
865 clone_tab[minor] = 0;
866 mutex_exit(&clone_tab_mutex);
867 return (EAGAIN);
868 }
869 softc = ddi_get_soft_state(statep, minor);
870 softc->cnext = softc;
871 softc->cprev = softc;
872
873 *devp = makedevice(getmajor(*devp), minor);
874 return (0);
875}
876
877
878/* ARGSUSED */
879static int
880bofi_close(dev_t dev, int flag, int otyp, cred_t *credp)
881{
882 int minor = (int)getminor(dev);
883 struct bofi_errent *softc;
884 struct bofi_errent *ep, *next_ep;
885
886 softc = ddi_get_soft_state(statep, minor);
887 if (softc == NULL)
888 return (ENXIO);
889 /*
890 * find list of errdefs and free them off
891 */
892 for (ep = softc->cnext; ep != softc; ) {
893 next_ep = ep->cnext;
894 (void) bofi_errdef_free(ep);
895 ep = next_ep;
896 }
897 /*
898 * free clone tab slot
899 */
900 mutex_enter(&clone_tab_mutex);
901 clone_tab[minor] = 0;
902 mutex_exit(&clone_tab_mutex);
903
904 ddi_soft_state_free(statep, minor);
905 return (0);
906}
907
908
909/* ARGSUSED */
910static int
911bofi_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
912 int *rvalp)
913{
914 struct bofi_errent *softc;
915 int minor = (int)getminor(dev);
916 struct bofi_errdef errdef;
917 struct bofi_errctl errctl;
918 struct bofi_errstate errstate;
919 void *ed_handle;
920 struct bofi_get_handles get_handles;
921 struct bofi_get_hdl_info hdl_info;
922 struct handle_info *hdlip;
923 struct handle_info *hib;
924
925 char *buffer;
926 char *bufptr;
927 char *endbuf;
928 int req_count, count, err;
929 char *namep;
930 struct bofi_shadow *hp;
931 int retval;
932 struct bofi_shadow *hhashp;
933 int i;
934
935 switch (cmd) {
936 case BOFI_ADD_DEF:
937 /*
938 * add a new error definition
939 */
940#ifdef _MULTI_DATAMODEL
941 switch (ddi_model_convert_from(mode & FMODELS)) {
942 case DDI_MODEL_ILP32:
943 {
944 /*
945 * For use when a 32 bit app makes a call into a
946 * 64 bit ioctl
947 */
948 struct bofi_errdef32 errdef_32;
949
950 if (ddi_copyin((void *)arg, &errdef_32,
951 sizeof (struct bofi_errdef32), mode)) {
952 return (EFAULT);
953 }
954 errdef.namesize = errdef_32.namesize;
955 (void) strncpy(errdef.name, errdef_32.name, NAMESIZE);
956 errdef.instance = errdef_32.instance;
957 errdef.rnumber = errdef_32.rnumber;
958 errdef.offset = errdef_32.offset;
959 errdef.len = errdef_32.len;
960 errdef.access_type = errdef_32.access_type;
961 errdef.access_count = errdef_32.access_count;
962 errdef.fail_count = errdef_32.fail_count;
963 errdef.acc_chk = errdef_32.acc_chk;
964 errdef.optype = errdef_32.optype;
965 errdef.operand = errdef_32.operand;
966 errdef.log.logsize = errdef_32.log.logsize;
967 errdef.log.entries = errdef_32.log.entries;
968 errdef.log.flags = errdef_32.log.flags;
969 errdef.log.wrapcnt = errdef_32.log.wrapcnt;
970 errdef.log.start_time = errdef_32.log.start_time;
971 errdef.log.stop_time = errdef_32.log.stop_time;
972 errdef.log.logbase =
973 (caddr_t)(uintptr_t)errdef_32.log.logbase;
974 errdef.errdef_handle = errdef_32.errdef_handle;
975 break;
976 }
977 case DDI_MODEL_NONE:
978 if (ddi_copyin((void *)arg, &errdef,
979 sizeof (struct bofi_errdef), mode))
980 return (EFAULT);
981 break;
982 }
983#else /* ! _MULTI_DATAMODEL */
984 if (ddi_copyin((void *)arg, &errdef,
985 sizeof (struct bofi_errdef), mode) != 0)
986 return (EFAULT);
987#endif /* _MULTI_DATAMODEL */
988 /*
989 * do some validation
990 */
991 if (errdef.fail_count == 0)
992 errdef.optype = 0;
993 if (errdef.optype != 0) {
994 if (errdef.access_type & BOFI_INTR &&
995 errdef.optype != BOFI_DELAY_INTR &&
996 errdef.optype != BOFI_LOSE_INTR &&
997 errdef.optype != BOFI_EXTRA_INTR)
998 return (EINVAL);
999 if ((errdef.access_type & (BOFI_DMA_RW|BOFI_PIO_R)) &&
1000 errdef.optype == BOFI_NO_TRANSFER)
1001 return (EINVAL);
1002 if ((errdef.access_type & (BOFI_PIO_RW)) &&
1003 errdef.optype != BOFI_EQUAL &&
1004 errdef.optype != BOFI_OR &&
1005 errdef.optype != BOFI_XOR &&
1006 errdef.optype != BOFI_AND &&
1007 errdef.optype != BOFI_NO_TRANSFER)
1008 return (EINVAL);
1009 }
1010 /*
1011 * find softstate for this clone, so we can tag
1012 * new errdef on to it
1013 */
1014 softc = ddi_get_soft_state(statep, minor);
1015 if (softc == NULL)
1016 return (ENXIO);
1017 /*
1018 * read in name
1019 */
1020 if (errdef.namesize > NAMESIZE)
1021 return (EINVAL);
1022 namep = kmem_zalloc(errdef.namesize+1, KM_SLEEP);
1023 (void) strncpy(namep, errdef.name, errdef.namesize);
1024
1025 if (bofi_errdef_alloc(&errdef, namep, softc) != DDI_SUCCESS) {
1026 (void) bofi_errdef_free((struct bofi_errent *)
1027 (uintptr_t)errdef.errdef_handle);
1028 kmem_free(namep, errdef.namesize+1);
1029 return (EINVAL);
1030 }
1031 /*
1032 * copy out errdef again, including filled in errdef_handle
1033 */
1034#ifdef _MULTI_DATAMODEL
1035 switch (ddi_model_convert_from(mode & FMODELS)) {
1036 case DDI_MODEL_ILP32:
1037 {
1038 /*
1039 * For use when a 32 bit app makes a call into a
1040 * 64 bit ioctl
1041 */
1042 struct bofi_errdef32 errdef_32;
1043
1044 errdef_32.namesize = errdef.namesize;
1045 (void) strncpy(errdef_32.name, errdef.name, NAMESIZE);
1046 errdef_32.instance = errdef.instance;
1047 errdef_32.rnumber = errdef.rnumber;
1048 errdef_32.offset = errdef.offset;
1049 errdef_32.len = errdef.len;
1050 errdef_32.access_type = errdef.access_type;
1051 errdef_32.access_count = errdef.access_count;
1052 errdef_32.fail_count = errdef.fail_count;
1053 errdef_32.acc_chk = errdef.acc_chk;
1054 errdef_32.optype = errdef.optype;
1055 errdef_32.operand = errdef.operand;
1056 errdef_32.log.logsize = errdef.log.logsize;
1057 errdef_32.log.entries = errdef.log.entries;
1058 errdef_32.log.flags = errdef.log.flags;
1059 errdef_32.log.wrapcnt = errdef.log.wrapcnt;
1060 errdef_32.log.start_time = errdef.log.start_time;
1061 errdef_32.log.stop_time = errdef.log.stop_time;
1062 errdef_32.log.logbase =
1063 (caddr32_t)(uintptr_t)errdef.log.logbase;
1064 errdef_32.errdef_handle = errdef.errdef_handle;
1065 if (ddi_copyout(&errdef_32, (void *)arg,
1066 sizeof (struct bofi_errdef32), mode) != 0) {
1067 (void) bofi_errdef_free((struct bofi_errent *)
1068 errdef.errdef_handle);
1069 kmem_free(namep, errdef.namesize+1);
1070 return (EFAULT);
1071 }
1072 break;
1073 }
1074 case DDI_MODEL_NONE:
1075 if (ddi_copyout(&errdef, (void *)arg,
1076 sizeof (struct bofi_errdef), mode) != 0) {
1077 (void) bofi_errdef_free((struct bofi_errent *)
1078 errdef.errdef_handle);
1079 kmem_free(namep, errdef.namesize+1);
1080 return (EFAULT);
1081 }
1082 break;
1083 }
1084#else /* ! _MULTI_DATAMODEL */
1085 if (ddi_copyout(&errdef, (void *)arg,
1086 sizeof (struct bofi_errdef), mode) != 0) {
1087 (void) bofi_errdef_free((struct bofi_errent *)
1088 (uintptr_t)errdef.errdef_handle);
1089 kmem_free(namep, errdef.namesize+1);
1090 return (EFAULT);
1091 }
1092#endif /* _MULTI_DATAMODEL */
1093 return (0);
1094 case BOFI_DEL_DEF:
1095 /*
1096 * delete existing errdef
1097 */
1098 if (ddi_copyin((void *)arg, &ed_handle,
1099 sizeof (void *), mode) != 0)
1100 return (EFAULT);
1101 return (bofi_errdef_free((struct bofi_errent *)ed_handle));
1102 case BOFI_START:
1103 /*
1104 * start all errdefs corresponding to
1105 * this name and instance
1106 */
1107 if (ddi_copyin((void *)arg, &errctl,
1108 sizeof (struct bofi_errctl), mode) != 0)
1109 return (EFAULT);
1110 /*
1111 * copy in name
1112 */
1113 if (errctl.namesize > NAMESIZE)
1114 return (EINVAL);
1115 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1116 (void) strncpy(namep, errctl.name, errctl.namesize);
1117 bofi_start(&errctl, namep);
1118 kmem_free(namep, errctl.namesize+1);
1119 return (0);
1120 case BOFI_STOP:
1121 /*
1122 * stop all errdefs corresponding to
1123 * this name and instance
1124 */
1125 if (ddi_copyin((void *)arg, &errctl,
1126 sizeof (struct bofi_errctl), mode) != 0)
1127 return (EFAULT);
1128 /*
1129 * copy in name
1130 */
1131 if (errctl.namesize > NAMESIZE)
1132 return (EINVAL);
1133 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1134 (void) strncpy(namep, errctl.name, errctl.namesize);
1135 bofi_stop(&errctl, namep);
1136 kmem_free(namep, errctl.namesize+1);
1137 return (0);
1138 case BOFI_BROADCAST:
1139 /*
1140 * wakeup all errdefs corresponding to
1141 * this name and instance
1142 */
1143 if (ddi_copyin((void *)arg, &errctl,
1144 sizeof (struct bofi_errctl), mode) != 0)
1145 return (EFAULT);
1146 /*
1147 * copy in name
1148 */
1149 if (errctl.namesize > NAMESIZE)
1150 return (EINVAL);
1151 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1152 (void) strncpy(namep, errctl.name, errctl.namesize);
1153 bofi_broadcast(&errctl, namep);
1154 kmem_free(namep, errctl.namesize+1);
1155 return (0);
1156 case BOFI_CLEAR_ACC_CHK:
1157 /*
1158 * clear "acc_chk" for all errdefs corresponding to
1159 * this name and instance
1160 */
1161 if (ddi_copyin((void *)arg, &errctl,
1162 sizeof (struct bofi_errctl), mode) != 0)
1163 return (EFAULT);
1164 /*
1165 * copy in name
1166 */
1167 if (errctl.namesize > NAMESIZE)
1168 return (EINVAL);
1169 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1170 (void) strncpy(namep, errctl.name, errctl.namesize);
1171 bofi_clear_acc_chk(&errctl, namep);
1172 kmem_free(namep, errctl.namesize+1);
1173 return (0);
1174 case BOFI_CLEAR_ERRORS:
1175 /*
1176 * set "fail_count" to 0 for all errdefs corresponding to
1177 * this name and instance whose "access_count"
1178 * has expired.
1179 */
1180 if (ddi_copyin((void *)arg, &errctl,
1181 sizeof (struct bofi_errctl), mode) != 0)
1182 return (EFAULT);
1183 /*
1184 * copy in name
1185 */
1186 if (errctl.namesize > NAMESIZE)
1187 return (EINVAL);
1188 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1189 (void) strncpy(namep, errctl.name, errctl.namesize);
1190 bofi_clear_errors(&errctl, namep);
1191 kmem_free(namep, errctl.namesize+1);
1192 return (0);
1193 case BOFI_CLEAR_ERRDEFS:
1194 /*
1195 * set "access_count" and "fail_count" to 0 for all errdefs
1196 * corresponding to this name and instance
1197 */
1198 if (ddi_copyin((void *)arg, &errctl,
1199 sizeof (struct bofi_errctl), mode) != 0)
1200 return (EFAULT);
1201 /*
1202 * copy in name
1203 */
1204 if (errctl.namesize > NAMESIZE)
1205 return (EINVAL);
1206 namep = kmem_zalloc(errctl.namesize+1, KM_SLEEP);
1207 (void) strncpy(namep, errctl.name, errctl.namesize);
1208 bofi_clear_errdefs(&errctl, namep);
1209 kmem_free(namep, errctl.namesize+1);
1210 return (0);
1211 case BOFI_CHK_STATE:
1212 {
1213 struct acc_log_elem *klg;
1214 size_t uls;
1215 /*
1216 * get state for this errdef - read in dummy errstate
1217 * with just the errdef_handle filled in
1218 */
1219#ifdef _MULTI_DATAMODEL
1220 switch (ddi_model_convert_from(mode & FMODELS)) {
1221 case DDI_MODEL_ILP32:
1222 {
1223 /*
1224 * For use when a 32 bit app makes a call into a
1225 * 64 bit ioctl
1226 */
1227 struct bofi_errstate32 errstate_32;
1228
1229 if (ddi_copyin((void *)arg, &errstate_32,
1230 sizeof (struct bofi_errstate32), mode) != 0) {
1231 return (EFAULT);
1232 }
1233 errstate.fail_time = errstate_32.fail_time;
1234 errstate.msg_time = errstate_32.msg_time;
1235 errstate.access_count = errstate_32.access_count;
1236 errstate.fail_count = errstate_32.fail_count;
1237 errstate.acc_chk = errstate_32.acc_chk;
1238 errstate.errmsg_count = errstate_32.errmsg_count;
1239 (void) strncpy(errstate.buffer, errstate_32.buffer,
1240 ERRMSGSIZE);
1241 errstate.severity = errstate_32.severity;
1242 errstate.log.logsize = errstate_32.log.logsize;
1243 errstate.log.entries = errstate_32.log.entries;
1244 errstate.log.flags = errstate_32.log.flags;
1245 errstate.log.wrapcnt = errstate_32.log.wrapcnt;
1246 errstate.log.start_time = errstate_32.log.start_time;
1247 errstate.log.stop_time = errstate_32.log.stop_time;
1248 errstate.log.logbase =
1249 (caddr_t)(uintptr_t)errstate_32.log.logbase;
1250 errstate.errdef_handle = errstate_32.errdef_handle;
1251 break;
1252 }
1253 case DDI_MODEL_NONE:
1254 if (ddi_copyin((void *)arg, &errstate,
1255 sizeof (struct bofi_errstate), mode) != 0)
1256 return (EFAULT);
1257 break;
1258 }
1259#else /* ! _MULTI_DATAMODEL */
1260 if (ddi_copyin((void *)arg, &errstate,
1261 sizeof (struct bofi_errstate), mode) != 0)
1262 return (EFAULT);
1263#endif /* _MULTI_DATAMODEL */
1264 if ((retval = bofi_errdef_check(&errstate, &klg)) == EINVAL)
1265 return (EINVAL);
1266 /*
1267 * copy out real errstate structure
1268 */
1269 uls = errstate.log.logsize;
1270 if (errstate.log.entries > uls && uls)
1271 /* insufficient user memory */
1272 errstate.log.entries = uls;
1273 /* always pass back a time */
1274 if (errstate.log.stop_time == 0ul)
1275 (void) drv_getparm(TIME, &(errstate.log.stop_time));
1276
1277#ifdef _MULTI_DATAMODEL
1278 switch (ddi_model_convert_from(mode & FMODELS)) {
1279 case DDI_MODEL_ILP32:
1280 {
1281 /*
1282 * For use when a 32 bit app makes a call into a
1283 * 64 bit ioctl
1284 */
1285 struct bofi_errstate32 errstate_32;
1286
1287 errstate_32.fail_time = errstate.fail_time;
1288 errstate_32.msg_time = errstate.msg_time;
1289 errstate_32.access_count = errstate.access_count;
1290 errstate_32.fail_count = errstate.fail_count;
1291 errstate_32.acc_chk = errstate.acc_chk;
1292 errstate_32.errmsg_count = errstate.errmsg_count;
1293 (void) strncpy(errstate_32.buffer, errstate.buffer,
1294 ERRMSGSIZE);
1295 errstate_32.severity = errstate.severity;
1296 errstate_32.log.logsize = errstate.log.logsize;
1297 errstate_32.log.entries = errstate.log.entries;
1298 errstate_32.log.flags = errstate.log.flags;
1299 errstate_32.log.wrapcnt = errstate.log.wrapcnt;
1300 errstate_32.log.start_time = errstate.log.start_time;
1301 errstate_32.log.stop_time = errstate.log.stop_time;
1302 errstate_32.log.logbase =
1303 (caddr32_t)(uintptr_t)errstate.log.logbase;
1304 errstate_32.errdef_handle = errstate.errdef_handle;
1305 if (ddi_copyout(&errstate_32, (void *)arg,
1306 sizeof (struct bofi_errstate32), mode) != 0)
1307 return (EFAULT);
1308 break;
1309 }
1310 case DDI_MODEL_NONE:
1311 if (ddi_copyout(&errstate, (void *)arg,
1312 sizeof (struct bofi_errstate), mode) != 0)
1313 return (EFAULT);
1314 break;
1315 }
1316#else /* ! _MULTI_DATAMODEL */
1317 if (ddi_copyout(&errstate, (void *)arg,
1318 sizeof (struct bofi_errstate), mode) != 0)
1319 return (EFAULT);
1320#endif /* _MULTI_DATAMODEL */
1321 if (uls && errstate.log.entries &&
1322 ddi_copyout(klg, errstate.log.logbase,
1323 errstate.log.entries * sizeof (struct acc_log_elem),
1324 mode) != 0) {
1325 return (EFAULT);
1326 }
1327 return (retval);
1328 }
1329 case BOFI_CHK_STATE_W:
1330 {
1331 struct acc_log_elem *klg;
1332 size_t uls;
1333 /*
1334 * get state for this errdef - read in dummy errstate
1335 * with just the errdef_handle filled in. Then wait for
1336 * a ddi_report_fault message to come back
1337 */
1338#ifdef _MULTI_DATAMODEL
1339 switch (ddi_model_convert_from(mode & FMODELS)) {
1340 case DDI_MODEL_ILP32:
1341 {
1342 /*
1343 * For use when a 32 bit app makes a call into a
1344 * 64 bit ioctl
1345 */
1346 struct bofi_errstate32 errstate_32;
1347
1348 if (ddi_copyin((void *)arg, &errstate_32,
1349 sizeof (struct bofi_errstate32), mode) != 0) {
1350 return (EFAULT);
1351 }
1352 errstate.fail_time = errstate_32.fail_time;
1353 errstate.msg_time = errstate_32.msg_time;
1354 errstate.access_count = errstate_32.access_count;
1355 errstate.fail_count = errstate_32.fail_count;
1356 errstate.acc_chk = errstate_32.acc_chk;
1357 errstate.errmsg_count = errstate_32.errmsg_count;
1358 (void) strncpy(errstate.buffer, errstate_32.buffer,
1359 ERRMSGSIZE);
1360 errstate.severity = errstate_32.severity;
1361 errstate.log.logsize = errstate_32.log.logsize;
1362 errstate.log.entries = errstate_32.log.entries;
1363 errstate.log.flags = errstate_32.log.flags;
1364 errstate.log.wrapcnt = errstate_32.log.wrapcnt;
1365 errstate.log.start_time = errstate_32.log.start_time;
1366 errstate.log.stop_time = errstate_32.log.stop_time;
1367 errstate.log.logbase =
1368 (caddr_t)(uintptr_t)errstate_32.log.logbase;
1369 errstate.errdef_handle = errstate_32.errdef_handle;
1370 break;
1371 }
1372 case DDI_MODEL_NONE:
1373 if (ddi_copyin((void *)arg, &errstate,
1374 sizeof (struct bofi_errstate), mode) != 0)
1375 return (EFAULT);
1376 break;
1377 }
1378#else /* ! _MULTI_DATAMODEL */
1379 if (ddi_copyin((void *)arg, &errstate,
1380 sizeof (struct bofi_errstate), mode) != 0)
1381 return (EFAULT);
1382#endif /* _MULTI_DATAMODEL */
1383 if ((retval = bofi_errdef_check_w(&errstate, &klg)) == EINVAL)
1384 return (EINVAL);
1385 /*
1386 * copy out real errstate structure
1387 */
1388 uls = errstate.log.logsize;
1389 uls = errstate.log.logsize;
1390 if (errstate.log.entries > uls && uls)
1391 /* insufficient user memory */
1392 errstate.log.entries = uls;
1393 /* always pass back a time */
1394 if (errstate.log.stop_time == 0ul)
1395 (void) drv_getparm(TIME, &(errstate.log.stop_time));
1396
1397#ifdef _MULTI_DATAMODEL
1398 switch (ddi_model_convert_from(mode & FMODELS)) {
1399 case DDI_MODEL_ILP32:
1400 {
1401 /*
1402 * For use when a 32 bit app makes a call into a
1403 * 64 bit ioctl
1404 */
1405 struct bofi_errstate32 errstate_32;
1406
1407 errstate_32.fail_time = errstate.fail_time;
1408 errstate_32.msg_time = errstate.msg_time;
1409 errstate_32.access_count = errstate.access_count;
1410 errstate_32.fail_count = errstate.fail_count;
1411 errstate_32.acc_chk = errstate.acc_chk;
1412 errstate_32.errmsg_count = errstate.errmsg_count;
1413 (void) strncpy(errstate_32.buffer, errstate.buffer,
1414 ERRMSGSIZE);
1415 errstate_32.severity = errstate.severity;
1416 errstate_32.log.logsize = errstate.log.logsize;
1417 errstate_32.log.entries = errstate.log.entries;
1418 errstate_32.log.flags = errstate.log.flags;
1419 errstate_32.log.wrapcnt = errstate.log.wrapcnt;
1420 errstate_32.log.start_time = errstate.log.start_time;
1421 errstate_32.log.stop_time = errstate.log.stop_time;
1422 errstate_32.log.logbase =
1423 (caddr32_t)(uintptr_t)errstate.log.logbase;
1424 errstate_32.errdef_handle = errstate.errdef_handle;
1425 if (ddi_copyout(&errstate_32, (void *)arg,
1426 sizeof (struct bofi_errstate32), mode) != 0)
1427 return (EFAULT);
1428 break;
1429 }
1430 case DDI_MODEL_NONE:
1431 if (ddi_copyout(&errstate, (void *)arg,
1432 sizeof (struct bofi_errstate), mode) != 0)
1433 return (EFAULT);
1434 break;
1435 }
1436#else /* ! _MULTI_DATAMODEL */
1437 if (ddi_copyout(&errstate, (void *)arg,
1438 sizeof (struct bofi_errstate), mode) != 0)
1439 return (EFAULT);
1440#endif /* _MULTI_DATAMODEL */
1441
1442 if (uls && errstate.log.entries &&
1443 ddi_copyout(klg, errstate.log.logbase,
1444 errstate.log.entries * sizeof (struct acc_log_elem),
1445 mode) != 0) {
1446 return (EFAULT);
1447 }
1448 return (retval);
1449 }
1450 case BOFI_GET_HANDLES:
1451 /*
1452 * display existing handles
1453 */
1454#ifdef _MULTI_DATAMODEL
1455 switch (ddi_model_convert_from(mode & FMODELS)) {
1456 case DDI_MODEL_ILP32:
1457 {
1458 /*
1459 * For use when a 32 bit app makes a call into a
1460 * 64 bit ioctl
1461 */
1462 struct bofi_get_handles32 get_handles_32;
1463
1464 if (ddi_copyin((void *)arg, &get_handles_32,
1465 sizeof (get_handles_32), mode) != 0) {
1466 return (EFAULT);
1467 }
1468 get_handles.namesize = get_handles_32.namesize;
1469 (void) strncpy(get_handles.name, get_handles_32.name,
1470 NAMESIZE);
1471 get_handles.instance = get_handles_32.instance;
1472 get_handles.count = get_handles_32.count;
1473 get_handles.buffer =
1474 (caddr_t)(uintptr_t)get_handles_32.buffer;
1475 break;
1476 }
1477 case DDI_MODEL_NONE:
1478 if (ddi_copyin((void *)arg, &get_handles,
1479 sizeof (get_handles), mode) != 0)
1480 return (EFAULT);
1481 break;
1482 }
1483#else /* ! _MULTI_DATAMODEL */
1484 if (ddi_copyin((void *)arg, &get_handles,
1485 sizeof (get_handles), mode) != 0)
1486 return (EFAULT);
1487#endif /* _MULTI_DATAMODEL */
1488 /*
1489 * read in name
1490 */
1491 if (get_handles.namesize > NAMESIZE)
1492 return (EINVAL);
1493 namep = kmem_zalloc(get_handles.namesize+1, KM_SLEEP);
1494 (void) strncpy(namep, get_handles.name, get_handles.namesize);
1495 req_count = get_handles.count;
1496 bufptr = buffer = kmem_zalloc(req_count, KM_SLEEP);
1497 endbuf = bufptr + req_count;
1498 /*
1499 * display existing handles
1500 */
1501 mutex_enter(&bofi_low_mutex);
1502 mutex_enter(&bofi_mutex);
1503 for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
1504 hhashp = &hhash_table[i];
1505 for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) {
1506 if (!driver_under_test(hp->dip))
1507 continue;
1508 if (ddi_name_to_major(ddi_get_name(hp->dip)) !=
1509 ddi_name_to_major(namep))
1510 continue;
1511 if (hp->instance != get_handles.instance)
1512 continue;
1513 /*
1514 * print information per handle - note that
1515 * DMA* means an unbound DMA handle
1516 */
1517 (void) snprintf(bufptr, (size_t)(endbuf-bufptr),
1518 " %s %d %s ", hp->name, hp->instance,
1519 (hp->type == BOFI_INT_HDL) ? "INTR" :
1520 (hp->type == BOFI_ACC_HDL) ? "PIO" :
1521 (hp->type == BOFI_DMA_HDL) ? "DMA" :
1522 (hp->hparrayp != NULL) ? "DVMA" : "DMA*");
1523 bufptr += strlen(bufptr);
1524 if (hp->type == BOFI_ACC_HDL) {
1525 if (hp->len == INT_MAX - hp->offset)
1526 (void) snprintf(bufptr,
1527 (size_t)(endbuf-bufptr),
1528 "reg set %d off 0x%llx\n",
1529 hp->rnumber, hp->offset);
1530 else
1531 (void) snprintf(bufptr,
1532 (size_t)(endbuf-bufptr),
1533 "reg set %d off 0x%llx"
1534 " len 0x%llx\n",
1535 hp->rnumber, hp->offset,
1536 hp->len);
1537 } else if (hp->type == BOFI_DMA_HDL)
1538 (void) snprintf(bufptr,
1539 (size_t)(endbuf-bufptr),
1540 "handle no %d len 0x%llx"
1541 " addr 0x%p\n", hp->rnumber,
1542 hp->len, (void *)hp->addr);
1543 else if (hp->type == BOFI_NULL &&
1544 hp->hparrayp == NULL)
1545 (void) snprintf(bufptr,
1546 (size_t)(endbuf-bufptr),
1547 "handle no %d\n", hp->rnumber);
1548 else
1549 (void) snprintf(bufptr,
1550 (size_t)(endbuf-bufptr), "\n");
1551 bufptr += strlen(bufptr);
1552 }
1553 }
1554 mutex_exit(&bofi_mutex);
1555 mutex_exit(&bofi_low_mutex);
1556 err = ddi_copyout(buffer, get_handles.buffer, req_count, mode);
1557 kmem_free(namep, get_handles.namesize+1);
1558 kmem_free(buffer, req_count);
1559 if (err != 0)
1560 return (EFAULT);
1561 else
1562 return (0);
1563 case BOFI_GET_HANDLE_INFO:
1564 /*
1565 * display existing handles
1566 */
1567#ifdef _MULTI_DATAMODEL
1568 switch (ddi_model_convert_from(mode & FMODELS)) {
1569 case DDI_MODEL_ILP32:
1570 {
1571 /*
1572 * For use when a 32 bit app makes a call into a
1573 * 64 bit ioctl
1574 */
1575 struct bofi_get_hdl_info32 hdl_info_32;
1576
1577 if (ddi_copyin((void *)arg, &hdl_info_32,
1578 sizeof (hdl_info_32), mode)) {
1579 return (EFAULT);
1580 }
1581 hdl_info.namesize = hdl_info_32.namesize;
1582 (void) strncpy(hdl_info.name, hdl_info_32.name,
1583 NAMESIZE);
1584 hdl_info.count = hdl_info_32.count;
1585 hdl_info.hdli = (caddr_t)(uintptr_t)hdl_info_32.hdli;
1586 break;
1587 }
1588 case DDI_MODEL_NONE:
1589 if (ddi_copyin((void *)arg, &hdl_info,
1590 sizeof (hdl_info), mode))
1591 return (EFAULT);
1592 break;
1593 }
1594#else /* ! _MULTI_DATAMODEL */
1595 if (ddi_copyin((void *)arg, &hdl_info,
1596 sizeof (hdl_info), mode))
1597 return (EFAULT);
1598#endif /* _MULTI_DATAMODEL */
1599 if (hdl_info.namesize > NAMESIZE)
1600 return (EINVAL);
1601 namep = kmem_zalloc(hdl_info.namesize + 1, KM_SLEEP);
1602 (void) strncpy(namep, hdl_info.name, hdl_info.namesize);
1603 req_count = hdl_info.count;
1604 count = hdl_info.count = 0; /* the actual no of handles */
1605 if (req_count > 0) {
1606 hib = hdlip =
1607 kmem_zalloc(req_count * sizeof (struct handle_info),
1608 KM_SLEEP);
1609 } else {
1610 hib = hdlip = 0;
1611 req_count = hdl_info.count = 0;
1612 }
1613
1614 /*
1615 * display existing handles
1616 */
1617 mutex_enter(&bofi_low_mutex);
1618 mutex_enter(&bofi_mutex);
1619 for (i = 0; i < HDL_HASH_TBL_SIZE; i++) {
1620 hhashp = &hhash_table[i];
1621 for (hp = hhashp->hnext; hp != hhashp; hp = hp->hnext) {
1622 if (!driver_under_test(hp->dip) ||
1623 ddi_name_to_major(ddi_get_name(hp->dip)) !=
1624 ddi_name_to_major(namep) ||
1625 ++(hdl_info.count) > req_count ||
1626 count == req_count)
1627 continue;
1628
1629 hdlip->instance = hp->instance;
1630 hdlip->rnumber = hp->rnumber;
1631 switch (hp->type) {
1632 case BOFI_ACC_HDL:
1633 hdlip->access_type = BOFI_PIO_RW;
1634 hdlip->offset = hp->offset;
1635 hdlip->len = hp->len;
1636 break;
1637 case BOFI_DMA_HDL:
1638 hdlip->access_type = 0;
1639 if (hp->flags & DDI_DMA_WRITE)
1640 hdlip->access_type |=
1641 BOFI_DMA_W;
1642 if (hp->flags & DDI_DMA_READ)
1643 hdlip->access_type |=
1644 BOFI_DMA_R;
1645 hdlip->len = hp->len;
1646 hdlip->addr_cookie =
1647 (uint64_t)(uintptr_t)hp->addr;
1648 break;
1649 case BOFI_INT_HDL:
1650 hdlip->access_type = BOFI_INTR;
1651 break;
1652 default:
1653 hdlip->access_type = 0;
1654 break;
1655 }
1656 hdlip++;
1657 count++;
1658 }
1659 }
1660 mutex_exit(&bofi_mutex);
1661 mutex_exit(&bofi_low_mutex);
1662 err = 0;
1663#ifdef _MULTI_DATAMODEL
1664 switch (ddi_model_convert_from(mode & FMODELS)) {
1665 case DDI_MODEL_ILP32:
1666 {
1667 /*
1668 * For use when a 32 bit app makes a call into a
1669 * 64 bit ioctl
1670 */
1671 struct bofi_get_hdl_info32 hdl_info_32;
1672
1673 hdl_info_32.namesize = hdl_info.namesize;
1674 (void) strncpy(hdl_info_32.name, hdl_info.name,
1675 NAMESIZE);
1676 hdl_info_32.count = hdl_info.count;
1677 hdl_info_32.hdli = (caddr32_t)(uintptr_t)hdl_info.hdli;
1678 if (ddi_copyout(&hdl_info_32, (void *)arg,
1679 sizeof (hdl_info_32), mode) != 0) {
1680 kmem_free(namep, hdl_info.namesize+1);
1681 if (req_count > 0)
1682 kmem_free(hib,
1683 req_count * sizeof (*hib));
1684 return (EFAULT);
1685 }
1686 break;
1687 }
1688 case DDI_MODEL_NONE:
1689 if (ddi_copyout(&hdl_info, (void *)arg,
1690 sizeof (hdl_info), mode) != 0) {
1691 kmem_free(namep, hdl_info.namesize+1);
1692 if (req_count > 0)
1693 kmem_free(hib,
1694 req_count * sizeof (*hib));
1695 return (EFAULT);
1696 }
1697 break;
1698 }
1699#else /* ! _MULTI_DATAMODEL */
1700 if (ddi_copyout(&hdl_info, (void *)arg,
1701 sizeof (hdl_info), mode) != 0) {
1702 kmem_free(namep, hdl_info.namesize+1);
1703 if (req_count > 0)
1704 kmem_free(hib, req_count * sizeof (*hib));
1705 return (EFAULT);
1706 }
1707#endif /* ! _MULTI_DATAMODEL */
1708 if (count > 0) {
1709 if (ddi_copyout(hib, hdl_info.hdli,
1710 count * sizeof (*hib), mode) != 0) {
1711 kmem_free(namep, hdl_info.namesize+1);
1712 if (req_count > 0)
1713 kmem_free(hib,
1714 req_count * sizeof (*hib));
1715 return (EFAULT);
1716 }
1717 }
1718 kmem_free(namep, hdl_info.namesize+1);
1719 if (req_count > 0)
1720 kmem_free(hib, req_count * sizeof (*hib));
1721 return (err);
1722 default:
1723 return (ENOTTY);
1724 }
1725}
1726
1727
1728/*
1729 * add a new error definition
1730 */
1731static int
1732bofi_errdef_alloc(struct bofi_errdef *errdefp, char *namep,
1733 struct bofi_errent *softc)
1734{
1735 struct bofi_errent *ep;
1736 struct bofi_shadow *hp;
1737 struct bofi_link *lp;
1738
1739 /*
1740 * allocate errdef structure and put on in-use list
1741 */
1742 ep = kmem_zalloc(sizeof (struct bofi_errent), KM_SLEEP);
1743 ep->errdef = *errdefp;
1744 ep->name = namep;
1745 ep->errdef.errdef_handle = (uint64_t)(uintptr_t)ep;
dilpreet00d09632006-04-23 15:26:28 -07001746 ep->errstate.severity = DDI_SERVICE_RESTORED;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001747 ep->errstate.errdef_handle = (uint64_t)(uintptr_t)ep;
1748 cv_init(&ep->cv, NULL, CV_DRIVER, NULL);
1749 /*
1750 * allocate space for logging
1751 */
1752 ep->errdef.log.entries = 0;
1753 ep->errdef.log.wrapcnt = 0;
1754 if (ep->errdef.access_type & BOFI_LOG)
1755 ep->logbase = kmem_alloc(sizeof (struct acc_log_elem) *
1756 ep->errdef.log.logsize, KM_SLEEP);
1757 else
1758 ep->logbase = NULL;
1759 /*
1760 * put on in-use list
1761 */
1762 mutex_enter(&bofi_low_mutex);
1763 mutex_enter(&bofi_mutex);
1764 ep->next = errent_listp;
1765 errent_listp = ep;
1766 /*
1767 * and add it to the per-clone list
1768 */
1769 ep->cnext = softc->cnext;
1770 softc->cnext->cprev = ep;
1771 ep->cprev = softc;
1772 softc->cnext = ep;
1773
1774 /*
1775 * look for corresponding shadow handle structures and if we find any
1776 * tag this errdef structure on to their link lists.
1777 */
1778 for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) {
1779 if (ddi_name_to_major(hp->name) == ddi_name_to_major(namep) &&
1780 hp->instance == errdefp->instance &&
1781 (((errdefp->access_type & BOFI_DMA_RW) &&
1782 (ep->errdef.rnumber == -1 ||
1783 hp->rnumber == ep->errdef.rnumber) &&
1784 hp->type == BOFI_DMA_HDL &&
1785 (((uintptr_t)(hp->addr + ep->errdef.offset +
1786 ep->errdef.len) & ~LLSZMASK) >
1787 ((uintptr_t)((hp->addr + ep->errdef.offset) +
1788 LLSZMASK) & ~LLSZMASK))) ||
1789 ((errdefp->access_type & BOFI_INTR) &&
1790 hp->type == BOFI_INT_HDL) ||
1791 ((errdefp->access_type & BOFI_PIO_RW) &&
1792 hp->type == BOFI_ACC_HDL &&
1793 (errdefp->rnumber == -1 ||
1794 hp->rnumber == errdefp->rnumber) &&
1795 (errdefp->len == 0 ||
1796 hp->offset < errdefp->offset + errdefp->len) &&
1797 hp->offset + hp->len > errdefp->offset))) {
1798 lp = bofi_link_freelist;
1799 if (lp != NULL) {
1800 bofi_link_freelist = lp->link;
1801 lp->errentp = ep;
1802 lp->link = hp->link;
1803 hp->link = lp;
1804 }
1805 }
1806 }
1807 errdefp->errdef_handle = (uint64_t)(uintptr_t)ep;
1808 mutex_exit(&bofi_mutex);
1809 mutex_exit(&bofi_low_mutex);
1810 ep->softintr_id = NULL;
1811 return (ddi_add_softintr(our_dip, DDI_SOFTINT_MED, &ep->softintr_id,
1812 NULL, NULL, bofi_signal, (caddr_t)&ep->errdef));
1813}
1814
1815
1816/*
1817 * delete existing errdef
1818 */
1819static int
1820bofi_errdef_free(struct bofi_errent *ep)
1821{
1822 struct bofi_errent *hep, *prev_hep;
1823 struct bofi_link *lp, *prev_lp, *next_lp;
1824 struct bofi_shadow *hp;
1825
1826 mutex_enter(&bofi_low_mutex);
1827 mutex_enter(&bofi_mutex);
1828 /*
1829 * don't just assume its a valid ep - check that its on the
1830 * in-use list
1831 */
1832 prev_hep = NULL;
1833 for (hep = errent_listp; hep != NULL; ) {
1834 if (hep == ep)
1835 break;
1836 prev_hep = hep;
1837 hep = hep->next;
1838 }
1839 if (hep == NULL) {
1840 mutex_exit(&bofi_mutex);
1841 mutex_exit(&bofi_low_mutex);
1842 return (EINVAL);
1843 }
1844 /*
1845 * found it - delete from in-use list
1846 */
1847
1848 if (prev_hep)
1849 prev_hep->next = hep->next;
1850 else
1851 errent_listp = hep->next;
1852 /*
1853 * and take it off the per-clone list
1854 */
1855 hep->cnext->cprev = hep->cprev;
1856 hep->cprev->cnext = hep->cnext;
1857 /*
1858 * see if we are on any shadow handle link lists - and if we
1859 * are then take us off
1860 */
1861 for (hp = shadow_list.next; hp != &shadow_list; hp = hp->next) {
1862 prev_lp = NULL;
1863 for (lp = hp->link; lp != NULL; ) {
1864 if (lp->errentp == ep) {
1865 if (prev_lp)
1866 prev_lp->link = lp->link;
1867 else
1868 hp->link = lp->link;
1869 next_lp = lp->link;
1870 lp->link = bofi_link_freelist;
1871 bofi_link_freelist = lp;
1872 lp = next_lp;
1873 } else {
1874 prev_lp = lp;
1875 lp = lp->link;
1876 }
1877 }
1878 }
1879 mutex_exit(&bofi_mutex);
1880 mutex_exit(&bofi_low_mutex);
1881
1882 cv_destroy(&ep->cv);
1883 kmem_free(ep->name, ep->errdef.namesize+1);
1884 if ((ep->errdef.access_type & BOFI_LOG) &&
stephhe5ba14f2007-10-09 15:55:12 -07001885 ep->errdef.log.logsize && ep->logbase) /* double check */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001886 kmem_free(ep->logbase,
1887 sizeof (struct acc_log_elem) * ep->errdef.log.logsize);
1888
1889 if (ep->softintr_id)
1890 ddi_remove_softintr(ep->softintr_id);
1891 kmem_free(ep, sizeof (struct bofi_errent));
1892 return (0);
1893}
1894
1895
1896/*
1897 * start all errdefs corresponding to this name and instance
1898 */
1899static void
1900bofi_start(struct bofi_errctl *errctlp, char *namep)
1901{
1902 struct bofi_errent *ep;
1903
1904 /*
1905 * look for any errdefs with matching name and instance
1906 */
1907 mutex_enter(&bofi_low_mutex);
1908 for (ep = errent_listp; ep != NULL; ep = ep->next)
1909 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1910 errctlp->instance == ep->errdef.instance) {
1911 ep->state |= BOFI_DEV_ACTIVE;
1912 (void) drv_getparm(TIME, &(ep->errdef.log.start_time));
1913 ep->errdef.log.stop_time = 0ul;
1914 }
1915 mutex_exit(&bofi_low_mutex);
1916}
1917
1918
1919/*
1920 * stop all errdefs corresponding to this name and instance
1921 */
1922static void
1923bofi_stop(struct bofi_errctl *errctlp, char *namep)
1924{
1925 struct bofi_errent *ep;
1926
1927 /*
1928 * look for any errdefs with matching name and instance
1929 */
1930 mutex_enter(&bofi_low_mutex);
1931 for (ep = errent_listp; ep != NULL; ep = ep->next)
1932 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1933 errctlp->instance == ep->errdef.instance) {
1934 ep->state &= ~BOFI_DEV_ACTIVE;
1935 if (ep->errdef.log.stop_time == 0ul)
1936 (void) drv_getparm(TIME,
1937 &(ep->errdef.log.stop_time));
1938 }
1939 mutex_exit(&bofi_low_mutex);
1940}
1941
1942
1943/*
1944 * wake up any thread waiting on this errdefs
1945 */
1946static uint_t
1947bofi_signal(caddr_t arg)
1948{
1949 struct bofi_errdef *edp = (struct bofi_errdef *)arg;
1950 struct bofi_errent *hep;
1951 struct bofi_errent *ep =
1952 (struct bofi_errent *)(uintptr_t)edp->errdef_handle;
1953
1954 mutex_enter(&bofi_low_mutex);
1955 for (hep = errent_listp; hep != NULL; ) {
1956 if (hep == ep)
1957 break;
1958 hep = hep->next;
1959 }
1960 if (hep == NULL) {
1961 mutex_exit(&bofi_low_mutex);
1962 return (DDI_INTR_UNCLAIMED);
1963 }
1964 if ((ep->errdef.access_type & BOFI_LOG) &&
1965 (edp->log.flags & BOFI_LOG_FULL)) {
1966 edp->log.stop_time = bofi_gettime();
1967 ep->state |= BOFI_NEW_MESSAGE;
1968 if (ep->state & BOFI_MESSAGE_WAIT)
1969 cv_broadcast(&ep->cv);
1970 ep->state &= ~BOFI_MESSAGE_WAIT;
1971 }
1972 if (ep->errstate.msg_time != 0) {
1973 ep->state |= BOFI_NEW_MESSAGE;
1974 if (ep->state & BOFI_MESSAGE_WAIT)
1975 cv_broadcast(&ep->cv);
1976 ep->state &= ~BOFI_MESSAGE_WAIT;
1977 }
1978 mutex_exit(&bofi_low_mutex);
1979 return (DDI_INTR_CLAIMED);
1980}
1981
1982
1983/*
1984 * wake up all errdefs corresponding to this name and instance
1985 */
1986static void
1987bofi_broadcast(struct bofi_errctl *errctlp, char *namep)
1988{
1989 struct bofi_errent *ep;
1990
1991 /*
1992 * look for any errdefs with matching name and instance
1993 */
1994 mutex_enter(&bofi_low_mutex);
1995 for (ep = errent_listp; ep != NULL; ep = ep->next)
1996 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
1997 errctlp->instance == ep->errdef.instance) {
1998 /*
1999 * wake up sleepers
2000 */
2001 ep->state |= BOFI_NEW_MESSAGE;
2002 if (ep->state & BOFI_MESSAGE_WAIT)
2003 cv_broadcast(&ep->cv);
2004 ep->state &= ~BOFI_MESSAGE_WAIT;
2005 }
2006 mutex_exit(&bofi_low_mutex);
2007}
2008
2009
2010/*
2011 * clear "acc_chk" for all errdefs corresponding to this name and instance
2012 * and wake them up.
2013 */
2014static void
2015bofi_clear_acc_chk(struct bofi_errctl *errctlp, char *namep)
2016{
2017 struct bofi_errent *ep;
2018
2019 /*
2020 * look for any errdefs with matching name and instance
2021 */
2022 mutex_enter(&bofi_low_mutex);
2023 for (ep = errent_listp; ep != NULL; ep = ep->next)
2024 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2025 errctlp->instance == ep->errdef.instance) {
2026 mutex_enter(&bofi_mutex);
2027 if (ep->errdef.access_count == 0 &&
2028 ep->errdef.fail_count == 0)
2029 ep->errdef.acc_chk = 0;
2030 mutex_exit(&bofi_mutex);
2031 /*
2032 * wake up sleepers
2033 */
2034 ep->state |= BOFI_NEW_MESSAGE;
2035 if (ep->state & BOFI_MESSAGE_WAIT)
2036 cv_broadcast(&ep->cv);
2037 ep->state &= ~BOFI_MESSAGE_WAIT;
2038 }
2039 mutex_exit(&bofi_low_mutex);
2040}
2041
2042
2043/*
2044 * set "fail_count" to 0 for all errdefs corresponding to this name and instance
2045 * whose "access_count" has expired, set "acc_chk" to 0 and wake them up.
2046 */
2047static void
2048bofi_clear_errors(struct bofi_errctl *errctlp, char *namep)
2049{
2050 struct bofi_errent *ep;
2051
2052 /*
2053 * look for any errdefs with matching name and instance
2054 */
2055 mutex_enter(&bofi_low_mutex);
2056 for (ep = errent_listp; ep != NULL; ep = ep->next)
2057 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2058 errctlp->instance == ep->errdef.instance) {
2059 mutex_enter(&bofi_mutex);
2060 if (ep->errdef.access_count == 0) {
2061 ep->errdef.acc_chk = 0;
2062 ep->errdef.fail_count = 0;
2063 mutex_exit(&bofi_mutex);
2064 if (ep->errdef.log.stop_time == 0ul)
2065 (void) drv_getparm(TIME,
2066 &(ep->errdef.log.stop_time));
2067 } else
2068 mutex_exit(&bofi_mutex);
2069 /*
2070 * wake up sleepers
2071 */
2072 ep->state |= BOFI_NEW_MESSAGE;
2073 if (ep->state & BOFI_MESSAGE_WAIT)
2074 cv_broadcast(&ep->cv);
2075 ep->state &= ~BOFI_MESSAGE_WAIT;
2076 }
2077 mutex_exit(&bofi_low_mutex);
2078}
2079
2080
2081/*
2082 * set "access_count" and "fail_count" to 0 for all errdefs corresponding to
2083 * this name and instance, set "acc_chk" to 0, and wake them up.
2084 */
2085static void
2086bofi_clear_errdefs(struct bofi_errctl *errctlp, char *namep)
2087{
2088 struct bofi_errent *ep;
2089
2090 /*
2091 * look for any errdefs with matching name and instance
2092 */
2093 mutex_enter(&bofi_low_mutex);
2094 for (ep = errent_listp; ep != NULL; ep = ep->next)
2095 if (strncmp(namep, ep->name, NAMESIZE) == 0 &&
2096 errctlp->instance == ep->errdef.instance) {
2097 mutex_enter(&bofi_mutex);
2098 ep->errdef.acc_chk = 0;
2099 ep->errdef.access_count = 0;
2100 ep->errdef.fail_count = 0;
2101 mutex_exit(&bofi_mutex);
2102 if (ep->errdef.log.stop_time == 0ul)
2103 (void) drv_getparm(TIME,
2104 &(ep->errdef.log.stop_time));
2105 /*
2106 * wake up sleepers
2107 */
2108 ep->state |= BOFI_NEW_MESSAGE;
2109 if (ep->state & BOFI_MESSAGE_WAIT)
2110 cv_broadcast(&ep->cv);
2111 ep->state &= ~BOFI_MESSAGE_WAIT;
2112 }
2113 mutex_exit(&bofi_low_mutex);
2114}
2115
2116
2117/*
2118 * get state for this errdef
2119 */
2120static int
2121bofi_errdef_check(struct bofi_errstate *errstatep, struct acc_log_elem **logpp)
2122{
2123 struct bofi_errent *hep;
2124 struct bofi_errent *ep;
2125
2126 ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle;
2127 mutex_enter(&bofi_low_mutex);
2128 /*
2129 * don't just assume its a valid ep - check that its on the
2130 * in-use list
2131 */
2132 for (hep = errent_listp; hep != NULL; hep = hep->next)
2133 if (hep == ep)
2134 break;
2135 if (hep == NULL) {
2136 mutex_exit(&bofi_low_mutex);
2137 return (EINVAL);
2138 }
2139 mutex_enter(&bofi_mutex);
2140 ep->errstate.access_count = ep->errdef.access_count;
2141 ep->errstate.fail_count = ep->errdef.fail_count;
2142 ep->errstate.acc_chk = ep->errdef.acc_chk;
2143 ep->errstate.log = ep->errdef.log;
2144 *logpp = ep->logbase;
2145 *errstatep = ep->errstate;
2146 mutex_exit(&bofi_mutex);
2147 mutex_exit(&bofi_low_mutex);
2148 return (0);
2149}
2150
2151
2152/*
2153 * Wait for a ddi_report_fault message to come back for this errdef
2154 * Then return state for this errdef.
2155 * fault report is intercepted by bofi_post_event, which triggers
2156 * bofi_signal via a softint, which will wake up this routine if
2157 * we are waiting
2158 */
2159static int
2160bofi_errdef_check_w(struct bofi_errstate *errstatep,
2161 struct acc_log_elem **logpp)
2162{
2163 struct bofi_errent *hep;
2164 struct bofi_errent *ep;
2165 int rval = 0;
2166
2167 ep = (struct bofi_errent *)(uintptr_t)errstatep->errdef_handle;
2168 mutex_enter(&bofi_low_mutex);
2169retry:
2170 /*
2171 * don't just assume its a valid ep - check that its on the
2172 * in-use list
2173 */
2174 for (hep = errent_listp; hep != NULL; hep = hep->next)
2175 if (hep == ep)
2176 break;
2177 if (hep == NULL) {
2178 mutex_exit(&bofi_low_mutex);
2179 return (EINVAL);
2180 }
2181 /*
2182 * wait for ddi_report_fault for the devinfo corresponding
2183 * to this errdef
2184 */
2185 if (rval == 0 && !(ep->state & BOFI_NEW_MESSAGE)) {
2186 ep->state |= BOFI_MESSAGE_WAIT;
dilpreet00d09632006-04-23 15:26:28 -07002187 if (cv_wait_sig(&ep->cv, &bofi_low_mutex) == 0) {
2188 if (!(ep->state & BOFI_NEW_MESSAGE))
2189 rval = EINTR;
2190 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002191 goto retry;
2192 }
2193 ep->state &= ~BOFI_NEW_MESSAGE;
2194 /*
2195 * we either didn't need to sleep, we've been woken up or we've been
2196 * signaled - either way return state now
2197 */
2198 mutex_enter(&bofi_mutex);
2199 ep->errstate.access_count = ep->errdef.access_count;
2200 ep->errstate.fail_count = ep->errdef.fail_count;
2201 ep->errstate.acc_chk = ep->errdef.acc_chk;
2202 ep->errstate.log = ep->errdef.log;
2203 *logpp = ep->logbase;
2204 *errstatep = ep->errstate;
2205 mutex_exit(&bofi_mutex);
2206 mutex_exit(&bofi_low_mutex);
2207 return (rval);
2208}
2209
2210
2211/*
2212 * support routine - check if requested driver is defined as under test in the
2213 * conf file.
2214 */
2215static int
2216driver_under_test(dev_info_t *rdip)
2217{
2218 int i;
2219 char *rname;
2220 major_t rmaj;
2221
2222 rname = ddi_get_name(rdip);
2223 rmaj = ddi_name_to_major(rname);
2224
2225 /*
2226 * Enforce the user to specifically request the following drivers.
2227 */
2228 for (i = 0; i < driver_list_size; i += (1 + strlen(&driver_list[i]))) {
2229 if (driver_list_neg == 0) {
2230 if (rmaj == ddi_name_to_major(&driver_list[i]))
2231 return (1);
2232 } else {
2233 if (rmaj == ddi_name_to_major(&driver_list[i+1]))
2234 return (0);
2235 }
2236 }
2237 if (driver_list_neg == 0)
2238 return (0);
2239 else
2240 return (1);
2241
2242}
2243
2244
2245static void
2246log_acc_event(struct bofi_errent *ep, uint_t at, offset_t offset, off_t len,
2247 size_t repcount, uint64_t *valuep)
2248{
2249 struct bofi_errdef *edp = &(ep->errdef);
2250 struct acc_log *log = &edp->log;
2251
2252 ASSERT(log != NULL);
2253 ASSERT(MUTEX_HELD(&bofi_mutex));
2254
2255 if (log->flags & BOFI_LOG_REPIO)
2256 repcount = 1;
2257 else if (repcount == 0 && edp->access_count > 0 &&
stephhe5ba14f2007-10-09 15:55:12 -07002258 (log->flags & BOFI_LOG_FULL) == 0)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002259 edp->access_count += 1;
2260
2261 if (repcount && log->entries < log->logsize) {
2262 struct acc_log_elem *elem = ep->logbase + log->entries;
2263
2264 if (log->flags & BOFI_LOG_TIMESTAMP)
2265 elem->access_time = bofi_gettime();
2266 elem->access_type = at;
2267 elem->offset = offset;
2268 elem->value = valuep ? *valuep : 0ll;
2269 elem->size = len;
2270 elem->repcount = repcount;
2271 ++log->entries;
2272 if (log->entries == log->logsize) {
2273 log->flags |= BOFI_LOG_FULL;
2274 ddi_trigger_softintr(((struct bofi_errent *)
2275 (uintptr_t)edp->errdef_handle)->softintr_id);
2276 }
2277 }
2278 if ((log->flags & BOFI_LOG_WRAP) && edp->access_count <= 1) {
2279 log->wrapcnt++;
2280 edp->access_count = log->logsize;
2281 log->entries = 0; /* wrap back to the start */
2282 }
2283}
2284
2285
2286/*
2287 * got a condition match on dma read/write - check counts and corrupt
2288 * data if necessary
2289 *
2290 * bofi_mutex always held when this is called.
2291 */
2292static void
2293do_dma_corrupt(struct bofi_shadow *hp, struct bofi_errent *ep,
2294 uint_t synctype, off_t off, off_t length)
2295{
2296 uint64_t operand;
2297 int i;
2298 off_t len;
2299 caddr_t logaddr;
2300 uint64_t *addr;
2301 uint64_t *endaddr;
dilpreet00d09632006-04-23 15:26:28 -07002302 ddi_dma_impl_t *hdlp;
2303 ndi_err_t *errp;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002304
2305 ASSERT(MUTEX_HELD(&bofi_mutex));
2306 if ((ep->errdef.access_count ||
stephhe5ba14f2007-10-09 15:55:12 -07002307 ep->errdef.fail_count) &&
2308 (ep->errdef.access_type & BOFI_LOG)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002309 uint_t atype;
2310
2311 if (synctype == DDI_DMA_SYNC_FORDEV)
2312 atype = BOFI_DMA_W;
2313 else if (synctype == DDI_DMA_SYNC_FORCPU ||
stephhe5ba14f2007-10-09 15:55:12 -07002314 synctype == DDI_DMA_SYNC_FORKERNEL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002315 atype = BOFI_DMA_R;
2316 else
2317 atype = 0;
2318 if ((off <= ep->errdef.offset &&
stephhe5ba14f2007-10-09 15:55:12 -07002319 off + length > ep->errdef.offset) ||
2320 (off > ep->errdef.offset &&
2321 off < ep->errdef.offset + ep->errdef.len)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002322 logaddr = (caddr_t)((uintptr_t)(hp->addr +
2323 off + LLSZMASK) & ~LLSZMASK);
2324
2325 log_acc_event(ep, atype, logaddr - hp->addr,
2326 length, 1, 0);
2327 }
2328 }
2329 if (ep->errdef.access_count > 1) {
2330 ep->errdef.access_count--;
2331 } else if (ep->errdef.fail_count > 0) {
2332 ep->errdef.fail_count--;
2333 ep->errdef.access_count = 0;
2334 /*
2335 * OK do the corruption
2336 */
2337 if (ep->errstate.fail_time == 0)
2338 ep->errstate.fail_time = bofi_gettime();
2339 /*
2340 * work out how much to corrupt
2341 *
2342 * Make sure endaddr isn't greater than hp->addr + hp->len.
2343 * If endaddr becomes less than addr len becomes negative
2344 * and the following loop isn't entered.
2345 */
2346 addr = (uint64_t *)((uintptr_t)((hp->addr +
2347 ep->errdef.offset) + LLSZMASK) & ~LLSZMASK);
2348 endaddr = (uint64_t *)((uintptr_t)(hp->addr + min(hp->len,
2349 ep->errdef.offset + ep->errdef.len)) & ~LLSZMASK);
2350 len = endaddr - addr;
2351 operand = ep->errdef.operand;
dilpreet00d09632006-04-23 15:26:28 -07002352 hdlp = (ddi_dma_impl_t *)(hp->hdl.dma_handle);
2353 errp = &hdlp->dmai_error;
2354 if (ep->errdef.acc_chk & 2) {
2355 uint64_t ena;
2356 char buf[FM_MAX_CLASS];
2357
2358 errp->err_status = DDI_FM_NONFATAL;
2359 (void) snprintf(buf, FM_MAX_CLASS, FM_SIMULATED_DMA);
2360 ena = fm_ena_generate(0, FM_ENA_FMT1);
2361 ddi_fm_ereport_post(hp->dip, buf, ena,
2362 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
2363 FM_EREPORT_VERS0, NULL);
2364 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002365 switch (ep->errdef.optype) {
2366 case BOFI_EQUAL :
2367 for (i = 0; i < len; i++)
2368 *(addr + i) = operand;
2369 break;
2370 case BOFI_AND :
2371 for (i = 0; i < len; i++)
2372 *(addr + i) &= operand;
2373 break;
2374 case BOFI_OR :
2375 for (i = 0; i < len; i++)
2376 *(addr + i) |= operand;
2377 break;
2378 case BOFI_XOR :
2379 for (i = 0; i < len; i++)
2380 *(addr + i) ^= operand;
2381 break;
2382 default:
2383 /* do nothing */
2384 break;
2385 }
2386 }
2387}
2388
2389
2390static uint64_t do_bofi_rd8(struct bofi_shadow *, caddr_t);
2391static uint64_t do_bofi_rd16(struct bofi_shadow *, caddr_t);
2392static uint64_t do_bofi_rd32(struct bofi_shadow *, caddr_t);
2393static uint64_t do_bofi_rd64(struct bofi_shadow *, caddr_t);
2394
2395
2396/*
2397 * check all errdefs linked to this shadow handle. If we've got a condition
2398 * match check counts and corrupt data if necessary
2399 *
2400 * bofi_mutex always held when this is called.
2401 *
2402 * because of possibility of BOFI_NO_TRANSFER, we couldn't get data
2403 * from io-space before calling this, so we pass in the func to do the
2404 * transfer as a parameter.
2405 */
2406static uint64_t
2407do_pior_corrupt(struct bofi_shadow *hp, caddr_t addr,
2408 uint64_t (*func)(), size_t repcount, size_t accsize)
2409{
2410 struct bofi_errent *ep;
2411 struct bofi_link *lp;
2412 uint64_t operand;
2413 uintptr_t minlen;
2414 intptr_t base;
2415 int done_get = 0;
2416 uint64_t get_val, gv;
dilpreet00d09632006-04-23 15:26:28 -07002417 ddi_acc_impl_t *hdlp;
2418 ndi_err_t *errp;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002419
2420 ASSERT(MUTEX_HELD(&bofi_mutex));
2421 /*
2422 * check through all errdefs associated with this shadow handle
2423 */
2424 for (lp = hp->link; lp != NULL; lp = lp->link) {
2425 ep = lp->errentp;
2426 if (ep->errdef.len == 0)
2427 minlen = hp->len;
2428 else
2429 minlen = min(hp->len, ep->errdef.len);
2430 base = addr - hp->addr - ep->errdef.offset + hp->offset;
2431 if ((ep->errdef.access_type & BOFI_PIO_R) &&
2432 (ep->state & BOFI_DEV_ACTIVE) &&
2433 base >= 0 && base < minlen) {
2434 /*
2435 * condition match for pio read
2436 */
2437 if (ep->errdef.access_count > 1) {
2438 ep->errdef.access_count--;
2439 if (done_get == 0) {
2440 done_get = 1;
2441 gv = get_val = func(hp, addr);
2442 }
2443 if (ep->errdef.access_type & BOFI_LOG) {
2444 log_acc_event(ep, BOFI_PIO_R,
2445 addr - hp->addr,
2446 accsize, repcount, &gv);
2447 }
2448 } else if (ep->errdef.fail_count > 0) {
2449 ep->errdef.fail_count--;
2450 ep->errdef.access_count = 0;
2451 /*
2452 * OK do corruption
2453 */
2454 if (ep->errstate.fail_time == 0)
2455 ep->errstate.fail_time = bofi_gettime();
2456 operand = ep->errdef.operand;
2457 if (done_get == 0) {
2458 if (ep->errdef.optype ==
2459 BOFI_NO_TRANSFER)
2460 /*
2461 * no transfer - bomb out
2462 */
2463 return (operand);
2464 done_get = 1;
2465 gv = get_val = func(hp, addr);
2466
2467 }
2468 if (ep->errdef.access_type & BOFI_LOG) {
2469 log_acc_event(ep, BOFI_PIO_R,
2470 addr - hp->addr,
2471 accsize, repcount, &gv);
2472 }
dilpreet00d09632006-04-23 15:26:28 -07002473 hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle);
2474 errp = hdlp->ahi_err;
2475 if (ep->errdef.acc_chk & 1) {
2476 uint64_t ena;
2477 char buf[FM_MAX_CLASS];
2478
2479 errp->err_status = DDI_FM_NONFATAL;
2480 (void) snprintf(buf, FM_MAX_CLASS,
2481 FM_SIMULATED_PIO);
2482 ena = fm_ena_generate(0, FM_ENA_FMT1);
2483 ddi_fm_ereport_post(hp->dip, buf, ena,
2484 DDI_NOSLEEP, FM_VERSION,
2485 DATA_TYPE_UINT8, FM_EREPORT_VERS0,
2486 NULL);
2487 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002488 switch (ep->errdef.optype) {
2489 case BOFI_EQUAL :
2490 get_val = operand;
2491 break;
2492 case BOFI_AND :
2493 get_val &= operand;
2494 break;
2495 case BOFI_OR :
2496 get_val |= operand;
2497 break;
2498 case BOFI_XOR :
2499 get_val ^= operand;
2500 break;
2501 default:
2502 /* do nothing */
2503 break;
2504 }
2505 }
2506 }
2507 }
2508 if (done_get == 0)
2509 return (func(hp, addr));
2510 else
2511 return (get_val);
2512}
2513
2514
2515/*
2516 * check all errdefs linked to this shadow handle. If we've got a condition
2517 * match check counts and corrupt data if necessary
2518 *
2519 * bofi_mutex always held when this is called.
2520 *
2521 * because of possibility of BOFI_NO_TRANSFER, we return 0 if no data
2522 * is to be written out to io-space, 1 otherwise
2523 */
2524static int
2525do_piow_corrupt(struct bofi_shadow *hp, caddr_t addr, uint64_t *valuep,
2526 size_t size, size_t repcount)
2527{
2528 struct bofi_errent *ep;
2529 struct bofi_link *lp;
2530 uintptr_t minlen;
2531 intptr_t base;
2532 uint64_t v = *valuep;
dilpreet00d09632006-04-23 15:26:28 -07002533 ddi_acc_impl_t *hdlp;
2534 ndi_err_t *errp;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002535
2536 ASSERT(MUTEX_HELD(&bofi_mutex));
2537 /*
2538 * check through all errdefs associated with this shadow handle
2539 */
2540 for (lp = hp->link; lp != NULL; lp = lp->link) {
2541 ep = lp->errentp;
2542 if (ep->errdef.len == 0)
2543 minlen = hp->len;
2544 else
2545 minlen = min(hp->len, ep->errdef.len);
2546 base = (caddr_t)addr - hp->addr - ep->errdef.offset +hp->offset;
2547 if ((ep->errdef.access_type & BOFI_PIO_W) &&
2548 (ep->state & BOFI_DEV_ACTIVE) &&
2549 base >= 0 && base < minlen) {
2550 /*
2551 * condition match for pio write
2552 */
2553
2554 if (ep->errdef.access_count > 1) {
2555 ep->errdef.access_count--;
2556 if (ep->errdef.access_type & BOFI_LOG)
2557 log_acc_event(ep, BOFI_PIO_W,
2558 addr - hp->addr, size,
2559 repcount, &v);
2560 } else if (ep->errdef.fail_count > 0) {
2561 ep->errdef.fail_count--;
2562 ep->errdef.access_count = 0;
2563 if (ep->errdef.access_type & BOFI_LOG)
2564 log_acc_event(ep, BOFI_PIO_W,
2565 addr - hp->addr, size,
2566 repcount, &v);
2567 /*
2568 * OK do corruption
2569 */
2570 if (ep->errstate.fail_time == 0)
2571 ep->errstate.fail_time = bofi_gettime();
dilpreet00d09632006-04-23 15:26:28 -07002572 hdlp = (ddi_acc_impl_t *)(hp->hdl.acc_handle);
2573 errp = hdlp->ahi_err;
2574 if (ep->errdef.acc_chk & 1) {
2575 uint64_t ena;
2576 char buf[FM_MAX_CLASS];
2577
2578 errp->err_status = DDI_FM_NONFATAL;
2579 (void) snprintf(buf, FM_MAX_CLASS,
2580 FM_SIMULATED_PIO);
2581 ena = fm_ena_generate(0, FM_ENA_FMT1);
2582 ddi_fm_ereport_post(hp->dip, buf, ena,
2583 DDI_NOSLEEP, FM_VERSION,
2584 DATA_TYPE_UINT8, FM_EREPORT_VERS0,
2585 NULL);
2586 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002587 switch (ep->errdef.optype) {
2588 case BOFI_EQUAL :
2589 *valuep = ep->errdef.operand;
2590 break;
2591 case BOFI_AND :
2592 *valuep &= ep->errdef.operand;
2593 break;
2594 case BOFI_OR :
2595 *valuep |= ep->errdef.operand;
2596 break;
2597 case BOFI_XOR :
2598 *valuep ^= ep->errdef.operand;
2599 break;
2600 case BOFI_NO_TRANSFER :