17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
500d0963fSdilpreet * Common Development and Distribution License (the "License").
600d0963fSdilpreet * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*567c0b92SStephen Hanson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Fault Management for Nexus Device Drivers
287c478bd9Sstevel@tonic-gate *
297c478bd9Sstevel@tonic-gate * In addition to implementing and supporting Fault Management for Device
307c478bd9Sstevel@tonic-gate * Drivers (ddifm.c), nexus drivers must support their children by
317c478bd9Sstevel@tonic-gate * reporting FM capabilities, intializing interrupt block cookies
327c478bd9Sstevel@tonic-gate * for error handling callbacks and caching mapped resources for lookup
337c478bd9Sstevel@tonic-gate * during the detection of an IO transaction error.
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * It is typically the nexus driver that receives an error indication
367c478bd9Sstevel@tonic-gate * for a fault that may have occurred in the data path of an IO transaction.
377c478bd9Sstevel@tonic-gate * Errors may be detected or received via an interrupt, a callback from
387c478bd9Sstevel@tonic-gate * another subsystem (e.g. a cpu trap) or examination of control data.
397c478bd9Sstevel@tonic-gate *
407c478bd9Sstevel@tonic-gate * Upon detection of an error, the nexus has a responsibility to alert
417c478bd9Sstevel@tonic-gate * its children of the error and the transaction associated with that
427c478bd9Sstevel@tonic-gate * error. The actual implementation may vary depending upon the capabilities
437c478bd9Sstevel@tonic-gate * of the nexus, its underlying hardware and its children. In this file,
447c478bd9Sstevel@tonic-gate * we provide support for typical nexus driver fault management tasks.
457c478bd9Sstevel@tonic-gate *
467c478bd9Sstevel@tonic-gate * Fault Management Initialization
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate * Nexus drivers must implement two new busops, bus_fm_init() and
497c478bd9Sstevel@tonic-gate * bus_fm_fini(). bus_fm_init() is called from a child nexus or device
507c478bd9Sstevel@tonic-gate * driver and is expected to initialize any per-child state and return
517c478bd9Sstevel@tonic-gate * the FM and error interrupt priority levels of the nexus driver.
527c478bd9Sstevel@tonic-gate * Similarly, bus_fm_fini() is called by child drivers and should
537c478bd9Sstevel@tonic-gate * clean-up any resources allocated during bus_fm_init().
547c478bd9Sstevel@tonic-gate * These functions are called from passive kernel context, typically from
557c478bd9Sstevel@tonic-gate * driver attach(9F) and detach(9F) entry points.
567c478bd9Sstevel@tonic-gate *
577c478bd9Sstevel@tonic-gate * Error Handler Dispatching
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate * Nexus drivers implemented to support error handler capabilities
607c478bd9Sstevel@tonic-gate * should invoke registered error handler callbacks for child drivers
617c478bd9Sstevel@tonic-gate * thought to be involved in the error.
627c478bd9Sstevel@tonic-gate * ndi_fm_handler_dispatch() is used to invoke
637c478bd9Sstevel@tonic-gate * all error handlers and returns one of the following status
647c478bd9Sstevel@tonic-gate * indications:
657c478bd9Sstevel@tonic-gate *
667c478bd9Sstevel@tonic-gate * DDI_FM_OK - No errors found by any child
677c478bd9Sstevel@tonic-gate * DDI_FM_FATAL - one or more children have detected a fatal error
687c478bd9Sstevel@tonic-gate * DDI_FM_NONFATAL - no fatal errors, but one or more children have
697c478bd9Sstevel@tonic-gate * detected a non-fatal error
707c478bd9Sstevel@tonic-gate *
717c478bd9Sstevel@tonic-gate * ndi_fm_handler_dispatch() may be called in any context
727c478bd9Sstevel@tonic-gate * subject to the constraints specified by the interrupt iblock cookie
737c478bd9Sstevel@tonic-gate * returned during initialization.
747c478bd9Sstevel@tonic-gate *
757c478bd9Sstevel@tonic-gate * Protected Accesses
767c478bd9Sstevel@tonic-gate *
777c478bd9Sstevel@tonic-gate * When an access handle is mapped or a DMA handle is bound via the
787c478bd9Sstevel@tonic-gate * standard busops, bus_map() or bus_dma_bindhdl(), a child driver
797c478bd9Sstevel@tonic-gate * implemented to support DDI_FM_ACCCHK_CAPABLE or
807c478bd9Sstevel@tonic-gate * DDI_FM_DMACHK_CAPABLE capabilites
817c478bd9Sstevel@tonic-gate * expects the nexus to flag any errors detected for transactions
827c478bd9Sstevel@tonic-gate * associated with the mapped or bound handles.
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate * Children nexus or device drivers will set the following flags
857c478bd9Sstevel@tonic-gate * in their ddi_device_access or dma_attr_flags when requesting
867c478bd9Sstevel@tonic-gate * the an access or DMA handle mapping:
877c478bd9Sstevel@tonic-gate *
887c478bd9Sstevel@tonic-gate * DDI_DMA_FLAGERR - nexus should set error status for any errors
897c478bd9Sstevel@tonic-gate * detected for a failed DMA transaction.
907c478bd9Sstevel@tonic-gate * DDI_ACC_FLAGERR - nexus should set error status for any errors
917c478bd9Sstevel@tonic-gate * detected for a failed PIO transaction.
927c478bd9Sstevel@tonic-gate *
937c478bd9Sstevel@tonic-gate * A nexus is expected to provide additional error detection and
947c478bd9Sstevel@tonic-gate * handling for handles with these flags set.
957c478bd9Sstevel@tonic-gate *
967c478bd9Sstevel@tonic-gate * Exclusive Bus Access
977c478bd9Sstevel@tonic-gate *
987c478bd9Sstevel@tonic-gate * In cases where a driver requires a high level of fault tolerance
997c478bd9Sstevel@tonic-gate * for a programmed IO transaction, it is neccessary to grant exclusive
1007c478bd9Sstevel@tonic-gate * access to the bus resource. Exclusivity guarantees that a fault
1017c478bd9Sstevel@tonic-gate * resulting from a transaction on the bus can be easily traced and
1027c478bd9Sstevel@tonic-gate * reported to the driver requesting the transaction.
1037c478bd9Sstevel@tonic-gate *
1047c478bd9Sstevel@tonic-gate * Nexus drivers must implement two new busops to support exclusive
1057c478bd9Sstevel@tonic-gate * access, bus_fm_access_enter() and bus_fm_access_exit(). The IO
1067c478bd9Sstevel@tonic-gate * framework will use these functions when it must set-up access
1077c478bd9Sstevel@tonic-gate * handles that set devacc_attr_access to DDI_ACC_CAUTIOUS in
1087c478bd9Sstevel@tonic-gate * their ddi_device_acc_attr_t request.
1097c478bd9Sstevel@tonic-gate *
1107c478bd9Sstevel@tonic-gate * Upon receipt of a bus_fm_access_enter() request, the nexus must prevent
1117c478bd9Sstevel@tonic-gate * all other access requests until it receives bus_fm_access_exit()
1127c478bd9Sstevel@tonic-gate * for the requested bus instance. bus_fm_access_enter() and
1137c478bd9Sstevel@tonic-gate * bus_fm_access_exit() may be called from user, kernel or kernel
1147c478bd9Sstevel@tonic-gate * interrupt context.
1157c478bd9Sstevel@tonic-gate *
1167c478bd9Sstevel@tonic-gate * Access and DMA Handle Caching
1177c478bd9Sstevel@tonic-gate *
1187c478bd9Sstevel@tonic-gate * To aid a nexus driver in associating access or DMA handles with
1197c478bd9Sstevel@tonic-gate * a detected error, the nexus should cache all handles that are
1207c478bd9Sstevel@tonic-gate * associated with DDI_ACC_FLAGERR, DDI_ACC_CAUTIOUS_ACC or
1217c478bd9Sstevel@tonic-gate * DDI_DMA_FLAGERR requests from its children. ndi_fmc_insert() is
1227c478bd9Sstevel@tonic-gate * called by a nexus to cache handles with the above protection flags
1237c478bd9Sstevel@tonic-gate * and ndi_fmc_remove() is called when that handle is unmapped or
1247c478bd9Sstevel@tonic-gate * unbound by the requesting child. ndi_fmc_insert() and
1257c478bd9Sstevel@tonic-gate * ndi_fmc_remove() may be called from any user or kernel context.
1267c478bd9Sstevel@tonic-gate *
127a5667d81SCheng Sean Ye * FM cache element is implemented by kmem_cache. The elements are
128a5667d81SCheng Sean Ye * stored in a doubly-linked searchable list. When a handle is created,
129a5667d81SCheng Sean Ye * ndi_fm_insert() allocates an entry from the kmem_cache and inserts
130a5667d81SCheng Sean Ye * the entry to the head of the list. When a handle is unmapped
131a5667d81SCheng Sean Ye * or unbound, ndi_fm_remove() removes its associated cache entry from
132a5667d81SCheng Sean Ye * the list.
1337c478bd9Sstevel@tonic-gate *
1347c478bd9Sstevel@tonic-gate * Upon detection of an error, the nexus may invoke ndi_fmc_error() to
1357c478bd9Sstevel@tonic-gate * iterate over the handle cache of one or more of its FM compliant
1367c478bd9Sstevel@tonic-gate * children. A comparison callback function is provided upon each
1377c478bd9Sstevel@tonic-gate * invocation of ndi_fmc_error() to tell the IO framework if a
1387c478bd9Sstevel@tonic-gate * handle is associated with an error. If so, the framework will
1397c478bd9Sstevel@tonic-gate * set the error status for that handle before returning from
1407c478bd9Sstevel@tonic-gate * ndi_fmc_error().
1417c478bd9Sstevel@tonic-gate *
1427c478bd9Sstevel@tonic-gate * ndi_fmc_error() may be called in any context
1437c478bd9Sstevel@tonic-gate * subject to the constraints specified by the interrupt iblock cookie
1447c478bd9Sstevel@tonic-gate * returned during initialization of the nexus and its children.
1457c478bd9Sstevel@tonic-gate *
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate #include <sys/types.h>
1497c478bd9Sstevel@tonic-gate #include <sys/param.h>
1507c478bd9Sstevel@tonic-gate #include <sys/debug.h>
1517c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
1527c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
1537c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
1547c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
1557c478bd9Sstevel@tonic-gate #include <sys/devctl.h>
1567c478bd9Sstevel@tonic-gate #include <sys/nvpair.h>
1577c478bd9Sstevel@tonic-gate #include <sys/ddifm.h>
1587c478bd9Sstevel@tonic-gate #include <sys/ndifm.h>
1597c478bd9Sstevel@tonic-gate #include <sys/spl.h>
1607c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
1617c478bd9Sstevel@tonic-gate #include <sys/devops.h>
1627c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
163a5667d81SCheng Sean Ye #include <sys/kmem.h>
1647c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
1657c478bd9Sstevel@tonic-gate
166a5667d81SCheng Sean Ye kmem_cache_t *ndi_fm_entry_cache;
167a5667d81SCheng Sean Ye
168a5667d81SCheng Sean Ye void
ndi_fm_init(void)169a5667d81SCheng Sean Ye ndi_fm_init(void)
170a5667d81SCheng Sean Ye {
171a5667d81SCheng Sean Ye ndi_fm_entry_cache = kmem_cache_create("ndi_fm_entry_cache",
172a5667d81SCheng Sean Ye sizeof (ndi_fmcentry_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
173a5667d81SCheng Sean Ye }
174a5667d81SCheng Sean Ye
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate * Allocate and initialize a fault management resource cache
1777c478bd9Sstevel@tonic-gate * A fault management cache consists of a set of cache elements that
178a5667d81SCheng Sean Ye * are allocated from "ndi_fm_entry_cache".
1797c478bd9Sstevel@tonic-gate */
180a5667d81SCheng Sean Ye /* ARGSUSED */
1817c478bd9Sstevel@tonic-gate void
i_ndi_fmc_create(ndi_fmc_t ** fcpp,int qlen,ddi_iblock_cookie_t ibc)1827c478bd9Sstevel@tonic-gate i_ndi_fmc_create(ndi_fmc_t **fcpp, int qlen, ddi_iblock_cookie_t ibc)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate ndi_fmc_t *fcp;
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate fcp = kmem_zalloc(sizeof (ndi_fmc_t), KM_SLEEP);
1877c478bd9Sstevel@tonic-gate mutex_init(&fcp->fc_lock, NULL, MUTEX_DRIVER, ibc);
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate *fcpp = fcp;
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate * Destroy and resources associated with the given fault management cache.
1947c478bd9Sstevel@tonic-gate */
1957c478bd9Sstevel@tonic-gate void
i_ndi_fmc_destroy(ndi_fmc_t * fcp)1967c478bd9Sstevel@tonic-gate i_ndi_fmc_destroy(ndi_fmc_t *fcp)
1977c478bd9Sstevel@tonic-gate {
198a5667d81SCheng Sean Ye ndi_fmcentry_t *fep, *pp;
199a5667d81SCheng Sean Ye
2007c478bd9Sstevel@tonic-gate if (fcp == NULL)
2017c478bd9Sstevel@tonic-gate return;
2027c478bd9Sstevel@tonic-gate
203a5667d81SCheng Sean Ye /* Free all the cached entries, this should not happen though */
2043c9b99a0Scindi mutex_enter(&fcp->fc_lock);
205a5667d81SCheng Sean Ye for (fep = fcp->fc_head; fep != NULL; fep = pp) {
206a5667d81SCheng Sean Ye pp = fep->fce_next;
207a5667d81SCheng Sean Ye kmem_cache_free(ndi_fm_entry_cache, fep);
208a5667d81SCheng Sean Ye }
2093c9b99a0Scindi mutex_exit(&fcp->fc_lock);
210a5667d81SCheng Sean Ye mutex_destroy(&fcp->fc_lock);
211a5667d81SCheng Sean Ye kmem_free(fcp, sizeof (ndi_fmc_t));
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate * ndi_fmc_insert -
2167c478bd9Sstevel@tonic-gate * Add a new entry to the specified cache.
2177c478bd9Sstevel@tonic-gate *
2187c478bd9Sstevel@tonic-gate * This function must be called at or below LOCK_LEVEL
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate void
ndi_fmc_insert(dev_info_t * dip,int flag,void * resource,void * bus_specific)2217c478bd9Sstevel@tonic-gate ndi_fmc_insert(dev_info_t *dip, int flag, void *resource, void *bus_specific)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate struct dev_info *devi = DEVI(dip);
2247c478bd9Sstevel@tonic-gate ndi_fmc_t *fcp;
2257c478bd9Sstevel@tonic-gate ndi_fmcentry_t *fep, **fpp;
2267c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl;
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate ASSERT(devi);
2297c478bd9Sstevel@tonic-gate ASSERT(flag == DMA_HANDLE || flag == ACC_HANDLE);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate fmhdl = devi->devi_fmhdl;
2327c478bd9Sstevel@tonic-gate if (fmhdl == NULL) {
2337c478bd9Sstevel@tonic-gate return;
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate if (flag == DMA_HANDLE) {
2377c478bd9Sstevel@tonic-gate if (!DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap)) {
2387c478bd9Sstevel@tonic-gate return;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate fcp = fmhdl->fh_dma_cache;
2417c478bd9Sstevel@tonic-gate fpp = &((ddi_dma_impl_t *)resource)->dmai_error.err_fep;
2427c478bd9Sstevel@tonic-gate } else if (flag == ACC_HANDLE) {
2437c478bd9Sstevel@tonic-gate if (!DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) {
2447c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL,
2457c478bd9Sstevel@tonic-gate DDI_NOSLEEP);
2467c478bd9Sstevel@tonic-gate return;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate fcp = fmhdl->fh_acc_cache;
2497c478bd9Sstevel@tonic-gate fpp = &((ddi_acc_impl_t *)resource)->ahi_err->err_fep;
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
252a5667d81SCheng Sean Ye fep = kmem_cache_alloc(ndi_fm_entry_cache, KM_NOSLEEP);
2537c478bd9Sstevel@tonic-gate if (fep == NULL) {
254a5667d81SCheng Sean Ye atomic_inc_64(&fmhdl->fh_kstat.fek_fmc_full.value.ui64);
2557c478bd9Sstevel@tonic-gate return;
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate * Set-up the handle resource and bus_specific information.
2607c478bd9Sstevel@tonic-gate * Also remember the pointer back to the cache for quick removal.
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate fep->fce_bus_specific = bus_specific;
2637c478bd9Sstevel@tonic-gate fep->fce_resource = resource;
2647c478bd9Sstevel@tonic-gate fep->fce_next = NULL;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /* Add entry to the end of the active list */
267fa52d01bScindi mutex_enter(&fcp->fc_lock);
268a5667d81SCheng Sean Ye ASSERT(*fpp == NULL);
269a5667d81SCheng Sean Ye *fpp = fep;
2707c478bd9Sstevel@tonic-gate fep->fce_prev = fcp->fc_tail;
271a5667d81SCheng Sean Ye if (fcp->fc_tail != NULL)
2727c478bd9Sstevel@tonic-gate fcp->fc_tail->fce_next = fep;
273a5667d81SCheng Sean Ye else
274a5667d81SCheng Sean Ye fcp->fc_head = fep;
2757c478bd9Sstevel@tonic-gate fcp->fc_tail = fep;
2767c478bd9Sstevel@tonic-gate mutex_exit(&fcp->fc_lock);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate * Remove an entry from the specified cache of access or dma mappings
2817c478bd9Sstevel@tonic-gate *
2827c478bd9Sstevel@tonic-gate * This function must be called at or below LOCK_LEVEL.
2837c478bd9Sstevel@tonic-gate */
2847c478bd9Sstevel@tonic-gate void
ndi_fmc_remove(dev_info_t * dip,int flag,const void * resource)2857c478bd9Sstevel@tonic-gate ndi_fmc_remove(dev_info_t *dip, int flag, const void *resource)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate ndi_fmc_t *fcp;
2887c478bd9Sstevel@tonic-gate ndi_fmcentry_t *fep;
2897c478bd9Sstevel@tonic-gate struct dev_info *devi = DEVI(dip);
2907c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl;
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate ASSERT(devi);
2937c478bd9Sstevel@tonic-gate ASSERT(flag == DMA_HANDLE || flag == ACC_HANDLE);
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate fmhdl = devi->devi_fmhdl;
2967c478bd9Sstevel@tonic-gate if (fmhdl == NULL) {
2977c478bd9Sstevel@tonic-gate return;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /* Find cache entry pointer for this resource */
3017c478bd9Sstevel@tonic-gate if (flag == DMA_HANDLE) {
3027c478bd9Sstevel@tonic-gate if (!DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap)) {
3037c478bd9Sstevel@tonic-gate return;
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate fcp = fmhdl->fh_dma_cache;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate ASSERT(fcp);
3087c478bd9Sstevel@tonic-gate
309a5667d81SCheng Sean Ye mutex_enter(&fcp->fc_lock);
3107c478bd9Sstevel@tonic-gate fep = ((ddi_dma_impl_t *)resource)->dmai_error.err_fep;
3117c478bd9Sstevel@tonic-gate ((ddi_dma_impl_t *)resource)->dmai_error.err_fep = NULL;
3127c478bd9Sstevel@tonic-gate } else if (flag == ACC_HANDLE) {
3137c478bd9Sstevel@tonic-gate if (!DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) {
3147c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL,
3157c478bd9Sstevel@tonic-gate DDI_NOSLEEP);
3167c478bd9Sstevel@tonic-gate return;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate fcp = fmhdl->fh_acc_cache;
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate ASSERT(fcp);
3217c478bd9Sstevel@tonic-gate
322a5667d81SCheng Sean Ye mutex_enter(&fcp->fc_lock);
3237c478bd9Sstevel@tonic-gate fep = ((ddi_acc_impl_t *)resource)->ahi_err->err_fep;
3247c478bd9Sstevel@tonic-gate ((ddi_acc_impl_t *)resource)->ahi_err->err_fep = NULL;
3253c9b99a0Scindi } else {
3263c9b99a0Scindi return;
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * Resource not in cache, return
3317c478bd9Sstevel@tonic-gate */
3323c9b99a0Scindi if (fep == NULL) {
333a5667d81SCheng Sean Ye mutex_exit(&fcp->fc_lock);
334a5667d81SCheng Sean Ye atomic_inc_64(&fmhdl->fh_kstat.fek_fmc_miss.value.ui64);
3357c478bd9Sstevel@tonic-gate return;
3363c9b99a0Scindi }
3377c478bd9Sstevel@tonic-gate
3383c9b99a0Scindi /*
3393c9b99a0Scindi * Updates to FM cache pointers require us to grab fmc_lock
3403c9b99a0Scindi * to synchronize access to the cache for ndi_fmc_insert()
3413c9b99a0Scindi * and ndi_fmc_error()
3423c9b99a0Scindi */
343a5667d81SCheng Sean Ye if (fep == fcp->fc_head)
344a5667d81SCheng Sean Ye fcp->fc_head = fep->fce_next;
345a5667d81SCheng Sean Ye else
3467c478bd9Sstevel@tonic-gate fep->fce_prev->fce_next = fep->fce_next;
3477c478bd9Sstevel@tonic-gate if (fep == fcp->fc_tail)
3487c478bd9Sstevel@tonic-gate fcp->fc_tail = fep->fce_prev;
3497c478bd9Sstevel@tonic-gate else
3507c478bd9Sstevel@tonic-gate fep->fce_next->fce_prev = fep->fce_prev;
351fa52d01bScindi mutex_exit(&fcp->fc_lock);
3527c478bd9Sstevel@tonic-gate
353a5667d81SCheng Sean Ye kmem_cache_free(ndi_fm_entry_cache, fep);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
35600d0963fSdilpreet int
ndi_fmc_entry_error(dev_info_t * dip,int flag,ddi_fm_error_t * derr,const void * bus_err_state)35700d0963fSdilpreet ndi_fmc_entry_error(dev_info_t *dip, int flag, ddi_fm_error_t *derr,
35800d0963fSdilpreet const void *bus_err_state)
35900d0963fSdilpreet {
36000d0963fSdilpreet int status, fatal = 0, nonfatal = 0;
36100d0963fSdilpreet ndi_fmc_t *fcp = NULL;
36200d0963fSdilpreet ndi_fmcentry_t *fep;
36300d0963fSdilpreet struct i_ddi_fmhdl *fmhdl;
36400d0963fSdilpreet
36500d0963fSdilpreet ASSERT(flag == DMA_HANDLE || flag == ACC_HANDLE);
36600d0963fSdilpreet
36700d0963fSdilpreet fmhdl = DEVI(dip)->devi_fmhdl;
36800d0963fSdilpreet ASSERT(fmhdl);
36900d0963fSdilpreet status = DDI_FM_UNKNOWN;
37000d0963fSdilpreet
37100d0963fSdilpreet if (flag == DMA_HANDLE && DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap)) {
37200d0963fSdilpreet fcp = fmhdl->fh_dma_cache;
37300d0963fSdilpreet ASSERT(fcp);
37400d0963fSdilpreet } else if (flag == ACC_HANDLE && DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) {
37500d0963fSdilpreet fcp = fmhdl->fh_acc_cache;
37600d0963fSdilpreet ASSERT(fcp);
37700d0963fSdilpreet }
37800d0963fSdilpreet
37900d0963fSdilpreet if (fcp != NULL) {
38000d0963fSdilpreet
38100d0963fSdilpreet /*
38200d0963fSdilpreet * Check active resource entries
38300d0963fSdilpreet */
38400d0963fSdilpreet mutex_enter(&fcp->fc_lock);
385a5667d81SCheng Sean Ye for (fep = fcp->fc_head; fep != NULL; fep = fep->fce_next) {
38600d0963fSdilpreet ddi_fmcompare_t compare_func;
38700d0963fSdilpreet
38800d0963fSdilpreet /*
38900d0963fSdilpreet * Compare captured error state with handle
39000d0963fSdilpreet * resources. During the comparison and
39100d0963fSdilpreet * subsequent error handling, we block
39200d0963fSdilpreet * attempts to free the cache entry.
39300d0963fSdilpreet */
39400d0963fSdilpreet compare_func = (flag == ACC_HANDLE) ?
39500d0963fSdilpreet i_ddi_fm_acc_err_cf_get((ddi_acc_handle_t)
39600d0963fSdilpreet fep->fce_resource) :
39700d0963fSdilpreet i_ddi_fm_dma_err_cf_get((ddi_dma_handle_t)
39800d0963fSdilpreet fep->fce_resource);
39900d0963fSdilpreet
400*567c0b92SStephen Hanson if (compare_func == NULL) /* unbound or not FLAGERR */
401*567c0b92SStephen Hanson continue;
402*567c0b92SStephen Hanson
40300d0963fSdilpreet status = compare_func(dip, fep->fce_resource,
40400d0963fSdilpreet bus_err_state, fep->fce_bus_specific);
40500d0963fSdilpreet if (status == DDI_FM_UNKNOWN || status == DDI_FM_OK)
40600d0963fSdilpreet continue;
40700d0963fSdilpreet
40800d0963fSdilpreet if (status == DDI_FM_FATAL)
40900d0963fSdilpreet ++fatal;
41000d0963fSdilpreet else if (status == DDI_FM_NONFATAL)
41100d0963fSdilpreet ++nonfatal;
41200d0963fSdilpreet
41300d0963fSdilpreet /* Set the error for this resource handle */
41400d0963fSdilpreet if (flag == ACC_HANDLE) {
41500d0963fSdilpreet ddi_acc_handle_t ap = fep->fce_resource;
41600d0963fSdilpreet
41700d0963fSdilpreet i_ddi_fm_acc_err_set(ap, derr->fme_ena, status,
41800d0963fSdilpreet DDI_FM_ERR_UNEXPECTED);
41900d0963fSdilpreet ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
42000d0963fSdilpreet derr->fme_acc_handle = ap;
42100d0963fSdilpreet } else {
42200d0963fSdilpreet ddi_dma_handle_t dp = fep->fce_resource;
42300d0963fSdilpreet
42400d0963fSdilpreet i_ddi_fm_dma_err_set(dp, derr->fme_ena, status,
42500d0963fSdilpreet DDI_FM_ERR_UNEXPECTED);
42600d0963fSdilpreet ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION);
42700d0963fSdilpreet derr->fme_dma_handle = dp;
42800d0963fSdilpreet }
42900d0963fSdilpreet }
43000d0963fSdilpreet mutex_exit(&fcp->fc_lock);
43100d0963fSdilpreet }
43200d0963fSdilpreet return (fatal ? DDI_FM_FATAL : nonfatal ? DDI_FM_NONFATAL :
43300d0963fSdilpreet DDI_FM_UNKNOWN);
43400d0963fSdilpreet }
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate * Check error state against the handle resource stored in the specified
4387c478bd9Sstevel@tonic-gate * FM cache. If tdip != NULL, we check only the cache entries for tdip.
4397c478bd9Sstevel@tonic-gate * The caller must ensure that tdip is valid throughout the call and
4407c478bd9Sstevel@tonic-gate * all FM data structures can be safely accesses.
4417c478bd9Sstevel@tonic-gate *
4427c478bd9Sstevel@tonic-gate * If tdip == NULL, we check all children that have registered their
4437c478bd9Sstevel@tonic-gate * FM_DMA_CHK or FM_ACC_CHK capabilities.
4447c478bd9Sstevel@tonic-gate *
4457c478bd9Sstevel@tonic-gate * The following status values may be returned:
4467c478bd9Sstevel@tonic-gate *
4477c478bd9Sstevel@tonic-gate * DDI_FM_FATAL - if at least one cache entry comparison yields a
4487c478bd9Sstevel@tonic-gate * fatal error.
4497c478bd9Sstevel@tonic-gate *
4507c478bd9Sstevel@tonic-gate * DDI_FM_NONFATAL - if at least one cache entry comparison yields a
4517c478bd9Sstevel@tonic-gate * non-fatal error and no comparison yields a fatal error.
4527c478bd9Sstevel@tonic-gate *
4537c478bd9Sstevel@tonic-gate * DDI_FM_UNKNOWN - cache entry comparisons did not yield fatal or
4547c478bd9Sstevel@tonic-gate * non-fatal errors.
4557c478bd9Sstevel@tonic-gate *
4567c478bd9Sstevel@tonic-gate */
4577c478bd9Sstevel@tonic-gate int
ndi_fmc_error(dev_info_t * dip,dev_info_t * tdip,int flag,uint64_t ena,const void * bus_err_state)45800d0963fSdilpreet ndi_fmc_error(dev_info_t *dip, dev_info_t *tdip, int flag, uint64_t ena,
45900d0963fSdilpreet const void *bus_err_state)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate int status, fatal = 0, nonfatal = 0;
4627c478bd9Sstevel@tonic-gate ddi_fm_error_t derr;
4637c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl;
4647c478bd9Sstevel@tonic-gate struct i_ddi_fmtgt *tgt;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate ASSERT(flag == DMA_HANDLE || flag == ACC_HANDLE);
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate i_ddi_fm_handler_enter(dip);
4697c478bd9Sstevel@tonic-gate fmhdl = DEVI(dip)->devi_fmhdl;
4707c478bd9Sstevel@tonic-gate ASSERT(fmhdl);
47100d0963fSdilpreet
47200d0963fSdilpreet bzero(&derr, sizeof (ddi_fm_error_t));
47300d0963fSdilpreet derr.fme_version = DDI_FME_VERSION;
47400d0963fSdilpreet derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
47500d0963fSdilpreet derr.fme_ena = ena;
47600d0963fSdilpreet
4777c478bd9Sstevel@tonic-gate for (tgt = fmhdl->fh_tgts; tgt != NULL; tgt = tgt->ft_next) {
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate if (tdip != NULL && tdip != tgt->ft_dip)
4807c478bd9Sstevel@tonic-gate continue;
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
48300d0963fSdilpreet * Attempt to find the entry in this childs handle cache
4847c478bd9Sstevel@tonic-gate */
48500d0963fSdilpreet status = ndi_fmc_entry_error(tgt->ft_dip, flag, &derr,
48600d0963fSdilpreet bus_err_state);
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate if (status == DDI_FM_FATAL)
4897c478bd9Sstevel@tonic-gate ++fatal;
4907c478bd9Sstevel@tonic-gate else if (status == DDI_FM_NONFATAL)
4917c478bd9Sstevel@tonic-gate ++nonfatal;
49200d0963fSdilpreet else
49300d0963fSdilpreet continue;
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate * Call our child to process this error.
4977c478bd9Sstevel@tonic-gate */
49800d0963fSdilpreet status = tgt->ft_errhdl->eh_func(tgt->ft_dip, &derr,
49900d0963fSdilpreet tgt->ft_errhdl->eh_impl);
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate if (status == DDI_FM_FATAL)
5027c478bd9Sstevel@tonic-gate ++fatal;
5037c478bd9Sstevel@tonic-gate else if (status == DDI_FM_NONFATAL)
5047c478bd9Sstevel@tonic-gate ++nonfatal;
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate i_ddi_fm_handler_exit(dip);
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate if (fatal)
5107c478bd9Sstevel@tonic-gate return (DDI_FM_FATAL);
5117c478bd9Sstevel@tonic-gate else if (nonfatal)
5127c478bd9Sstevel@tonic-gate return (DDI_FM_NONFATAL);
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate return (DDI_FM_UNKNOWN);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
5178aec9182Sstephh int
ndi_fmc_entry_error_all(dev_info_t * dip,int flag,ddi_fm_error_t * derr)5188aec9182Sstephh ndi_fmc_entry_error_all(dev_info_t *dip, int flag, ddi_fm_error_t *derr)
5198aec9182Sstephh {
5208aec9182Sstephh ndi_fmc_t *fcp = NULL;
5218aec9182Sstephh ndi_fmcentry_t *fep;
5228aec9182Sstephh struct i_ddi_fmhdl *fmhdl;
5238aec9182Sstephh int nonfatal = 0;
5248aec9182Sstephh
5258aec9182Sstephh ASSERT(flag == DMA_HANDLE || flag == ACC_HANDLE);
5268aec9182Sstephh
5278aec9182Sstephh fmhdl = DEVI(dip)->devi_fmhdl;
5288aec9182Sstephh ASSERT(fmhdl);
5298aec9182Sstephh
5308aec9182Sstephh if (flag == DMA_HANDLE && DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap)) {
5318aec9182Sstephh fcp = fmhdl->fh_dma_cache;
5328aec9182Sstephh ASSERT(fcp);
5338aec9182Sstephh } else if (flag == ACC_HANDLE && DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) {
5348aec9182Sstephh fcp = fmhdl->fh_acc_cache;
5358aec9182Sstephh ASSERT(fcp);
5368aec9182Sstephh }
5378aec9182Sstephh
5388aec9182Sstephh if (fcp != NULL) {
5398aec9182Sstephh /*
5408aec9182Sstephh * Check active resource entries
5418aec9182Sstephh */
5428aec9182Sstephh mutex_enter(&fcp->fc_lock);
543a5667d81SCheng Sean Ye for (fep = fcp->fc_head; fep != NULL; fep = fep->fce_next) {
544*567c0b92SStephen Hanson ddi_fmcompare_t compare_func;
545*567c0b92SStephen Hanson
546*567c0b92SStephen Hanson compare_func = (flag == ACC_HANDLE) ?
547*567c0b92SStephen Hanson i_ddi_fm_acc_err_cf_get((ddi_acc_handle_t)
548*567c0b92SStephen Hanson fep->fce_resource) :
549*567c0b92SStephen Hanson i_ddi_fm_dma_err_cf_get((ddi_dma_handle_t)
550*567c0b92SStephen Hanson fep->fce_resource);
551*567c0b92SStephen Hanson
552*567c0b92SStephen Hanson if (compare_func == NULL) /* unbound or not FLAGERR */
553*567c0b92SStephen Hanson continue;
554*567c0b92SStephen Hanson
5558aec9182Sstephh /* Set the error for this resource handle */
5568aec9182Sstephh nonfatal++;
557*567c0b92SStephen Hanson
5588aec9182Sstephh if (flag == ACC_HANDLE) {
5598aec9182Sstephh ddi_acc_handle_t ap = fep->fce_resource;
5608aec9182Sstephh
5618aec9182Sstephh i_ddi_fm_acc_err_set(ap, derr->fme_ena,
5628aec9182Sstephh DDI_FM_NONFATAL, DDI_FM_ERR_UNEXPECTED);
5638aec9182Sstephh ddi_fm_acc_err_get(ap, derr, DDI_FME_VERSION);
5648aec9182Sstephh derr->fme_acc_handle = ap;
5658aec9182Sstephh } else {
5668aec9182Sstephh ddi_dma_handle_t dp = fep->fce_resource;
5678aec9182Sstephh
5688aec9182Sstephh i_ddi_fm_dma_err_set(dp, derr->fme_ena,
5698aec9182Sstephh DDI_FM_NONFATAL, DDI_FM_ERR_UNEXPECTED);
5708aec9182Sstephh ddi_fm_dma_err_get(dp, derr, DDI_FME_VERSION);
5718aec9182Sstephh derr->fme_dma_handle = dp;
5728aec9182Sstephh }
5738aec9182Sstephh }
5748aec9182Sstephh mutex_exit(&fcp->fc_lock);
5758aec9182Sstephh }
5768aec9182Sstephh return (nonfatal ? DDI_FM_NONFATAL : DDI_FM_UNKNOWN);
5778aec9182Sstephh }
5788aec9182Sstephh
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate * Dispatch registered error handlers for dip. If tdip != NULL, only
5817c478bd9Sstevel@tonic-gate * the error handler (if available) for tdip is invoked. Otherwise,
5827c478bd9Sstevel@tonic-gate * all registered error handlers are invoked.
5837c478bd9Sstevel@tonic-gate *
5847c478bd9Sstevel@tonic-gate * The following status values may be returned:
5857c478bd9Sstevel@tonic-gate *
5867c478bd9Sstevel@tonic-gate * DDI_FM_FATAL - if at least one error handler returns a
5877c478bd9Sstevel@tonic-gate * fatal error.
5887c478bd9Sstevel@tonic-gate *
5897c478bd9Sstevel@tonic-gate * DDI_FM_NONFATAL - if at least one error handler returns a
5907c478bd9Sstevel@tonic-gate * non-fatal error and none returned a fatal error.
5917c478bd9Sstevel@tonic-gate *
5927c478bd9Sstevel@tonic-gate * DDI_FM_UNKNOWN - if at least one error handler returns
5937c478bd9Sstevel@tonic-gate * unknown status and none return fatal or non-fatal.
5947c478bd9Sstevel@tonic-gate *
5957c478bd9Sstevel@tonic-gate * DDI_FM_OK - if all error handlers return DDI_FM_OK
5967c478bd9Sstevel@tonic-gate */
5977c478bd9Sstevel@tonic-gate int
ndi_fm_handler_dispatch(dev_info_t * dip,dev_info_t * tdip,const ddi_fm_error_t * nerr)5987c478bd9Sstevel@tonic-gate ndi_fm_handler_dispatch(dev_info_t *dip, dev_info_t *tdip,
5997c478bd9Sstevel@tonic-gate const ddi_fm_error_t *nerr)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate int status;
6027c478bd9Sstevel@tonic-gate int unknown = 0, fatal = 0, nonfatal = 0;
6037c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *hdl;
6047c478bd9Sstevel@tonic-gate struct i_ddi_fmtgt *tgt;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate status = DDI_FM_UNKNOWN;
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate i_ddi_fm_handler_enter(dip);
6097c478bd9Sstevel@tonic-gate hdl = DEVI(dip)->devi_fmhdl;
6107c478bd9Sstevel@tonic-gate tgt = hdl->fh_tgts;
6117c478bd9Sstevel@tonic-gate while (tgt != NULL) {
6127c478bd9Sstevel@tonic-gate if (tdip == NULL || tdip == tgt->ft_dip) {
6137c478bd9Sstevel@tonic-gate struct i_ddi_errhdl *errhdl;
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate errhdl = tgt->ft_errhdl;
6167c478bd9Sstevel@tonic-gate status = errhdl->eh_func(tgt->ft_dip, nerr,
6177c478bd9Sstevel@tonic-gate errhdl->eh_impl);
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate if (status == DDI_FM_FATAL)
6207c478bd9Sstevel@tonic-gate ++fatal;
6217c478bd9Sstevel@tonic-gate else if (status == DDI_FM_NONFATAL)
6227c478bd9Sstevel@tonic-gate ++nonfatal;
6237c478bd9Sstevel@tonic-gate else if (status == DDI_FM_UNKNOWN)
6247c478bd9Sstevel@tonic-gate ++unknown;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate /* Only interested in one target */
6277c478bd9Sstevel@tonic-gate if (tdip != NULL)
6287c478bd9Sstevel@tonic-gate break;
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate tgt = tgt->ft_next;
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate i_ddi_fm_handler_exit(dip);
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate if (fatal)
6357c478bd9Sstevel@tonic-gate return (DDI_FM_FATAL);
6367c478bd9Sstevel@tonic-gate else if (nonfatal)
6377c478bd9Sstevel@tonic-gate return (DDI_FM_NONFATAL);
6387c478bd9Sstevel@tonic-gate else if (unknown)
6397c478bd9Sstevel@tonic-gate return (DDI_FM_UNKNOWN);
6407c478bd9Sstevel@tonic-gate else
6417c478bd9Sstevel@tonic-gate return (DDI_FM_OK);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate * Set error status for specified access or DMA handle
6467c478bd9Sstevel@tonic-gate *
6477c478bd9Sstevel@tonic-gate * May be called in any context but caller must insure validity of
6487c478bd9Sstevel@tonic-gate * handle.
6497c478bd9Sstevel@tonic-gate */
6507c478bd9Sstevel@tonic-gate void
ndi_fm_acc_err_set(ddi_acc_handle_t handle,ddi_fm_error_t * dfe)6517c478bd9Sstevel@tonic-gate ndi_fm_acc_err_set(ddi_acc_handle_t handle, ddi_fm_error_t *dfe)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate i_ddi_fm_acc_err_set(handle, dfe->fme_ena, dfe->fme_status,
6547c478bd9Sstevel@tonic-gate dfe->fme_flag);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate void
ndi_fm_dma_err_set(ddi_dma_handle_t handle,ddi_fm_error_t * dfe)6587c478bd9Sstevel@tonic-gate ndi_fm_dma_err_set(ddi_dma_handle_t handle, ddi_fm_error_t *dfe)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate i_ddi_fm_dma_err_set(handle, dfe->fme_ena, dfe->fme_status,
6617c478bd9Sstevel@tonic-gate dfe->fme_flag);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate * Call parent busop fm initialization routine.
6667c478bd9Sstevel@tonic-gate *
6677c478bd9Sstevel@tonic-gate * Called during driver attach(1M)
6687c478bd9Sstevel@tonic-gate */
6697c478bd9Sstevel@tonic-gate int
i_ndi_busop_fm_init(dev_info_t * dip,int tcap,ddi_iblock_cookie_t * ibc)6707c478bd9Sstevel@tonic-gate i_ndi_busop_fm_init(dev_info_t *dip, int tcap, ddi_iblock_cookie_t *ibc)
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate int pcap;
6737c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate if (dip == ddi_root_node())
6767c478bd9Sstevel@tonic-gate return (ddi_system_fmcap | DDI_FM_EREPORT_CAPABLE);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /* Valid operation for BUSO_REV_6 and above */
6797c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_6)
6807c478bd9Sstevel@tonic-gate return (DDI_FM_NOT_CAPABLE);
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_init == NULL)
6837c478bd9Sstevel@tonic-gate return (DDI_FM_NOT_CAPABLE);
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate pcap = (*DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_init)
6867c478bd9Sstevel@tonic-gate (pdip, dip, tcap, ibc);
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate return (pcap);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate * Call parent busop fm clean-up routine.
6937c478bd9Sstevel@tonic-gate *
6947c478bd9Sstevel@tonic-gate * Called during driver detach(1M)
6957c478bd9Sstevel@tonic-gate */
6967c478bd9Sstevel@tonic-gate void
i_ndi_busop_fm_fini(dev_info_t * dip)6977c478bd9Sstevel@tonic-gate i_ndi_busop_fm_fini(dev_info_t *dip)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate if (dip == ddi_root_node())
7027c478bd9Sstevel@tonic-gate return;
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate /* Valid operation for BUSO_REV_6 and above */
7057c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_6)
7067c478bd9Sstevel@tonic-gate return;
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_fini == NULL)
7097c478bd9Sstevel@tonic-gate return;
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate (*DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_fini)(pdip, dip);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate * The following routines provide exclusive access to a nexus resource
7167c478bd9Sstevel@tonic-gate *
7177c478bd9Sstevel@tonic-gate * These busops may be called in user or kernel driver context.
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate void
i_ndi_busop_access_enter(dev_info_t * dip,ddi_acc_handle_t handle)7207c478bd9Sstevel@tonic-gate i_ndi_busop_access_enter(dev_info_t *dip, ddi_acc_handle_t handle)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate /* Valid operation for BUSO_REV_6 and above */
7257c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_6)
7267c478bd9Sstevel@tonic-gate return;
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_access_enter == NULL)
7297c478bd9Sstevel@tonic-gate return;
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate (*DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_access_enter)
7327c478bd9Sstevel@tonic-gate (pdip, handle);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate void
i_ndi_busop_access_exit(dev_info_t * dip,ddi_acc_handle_t handle)7367c478bd9Sstevel@tonic-gate i_ndi_busop_access_exit(dev_info_t *dip, ddi_acc_handle_t handle)
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate /* Valid operation for BUSO_REV_6 and above */
7417c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->busops_rev < BUSO_REV_6)
7427c478bd9Sstevel@tonic-gate return;
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate if (DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_access_exit == NULL)
7457c478bd9Sstevel@tonic-gate return;
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate (*DEVI(pdip)->devi_ops->devo_bus_ops->bus_fm_access_exit)(pdip, handle);
7487c478bd9Sstevel@tonic-gate }
749