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 /* 22392e836bSGavin Maltby * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * Fault Management for Device Drivers 277c478bd9Sstevel@tonic-gate * 287c478bd9Sstevel@tonic-gate * Device drivers wishing to participate in fault management may do so by 297c478bd9Sstevel@tonic-gate * first initializing their fault management state and capabilties via 307c478bd9Sstevel@tonic-gate * ddi_fm_init(). If the system supports the requested FM capabilities, 317c478bd9Sstevel@tonic-gate * the IO framework will intialize FM state and return a bit mask of the 327c478bd9Sstevel@tonic-gate * requested capabilities. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * If the system does not support the requested FM capabilities, 357c478bd9Sstevel@tonic-gate * the device driver must behave in accordance with the programming semantics 367c478bd9Sstevel@tonic-gate * defined below for the capabilities returned from ddi_fm_init(). 377c478bd9Sstevel@tonic-gate * ddi_fm_init() must be called at attach(9E) time and ddi_fm_fini() must be 387c478bd9Sstevel@tonic-gate * called from detach(9E) to perform FM clean-up. 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * Driver Fault Management Capabilities 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * DDI_FM_NOT_CAPABLE 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * This is the default fault management capability for drivers. Drivers 457c478bd9Sstevel@tonic-gate * that implement no fault management capabilites or do not participate 467c478bd9Sstevel@tonic-gate * in fault management activities have their FM capability bitmask set 477c478bd9Sstevel@tonic-gate * to 0. 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * DDI_FM_EREPORT_CAPABLE 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * When this capability bit is set, drivers are expected to generate error 527c478bd9Sstevel@tonic-gate * report events via ddi_ereport_post() for the associated faults 537c478bd9Sstevel@tonic-gate * that are diagnosed by the IO fault manager DE. ddi_ereport_post() 547c478bd9Sstevel@tonic-gate * may be called in any context subject to the constraints specified 557c478bd9Sstevel@tonic-gate * by the interrupt iblock cookie returned during initialization. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * Error reports resulting from hardware component specific and common IO 587c478bd9Sstevel@tonic-gate * fault and driver defects must be accompanied by an Eversholt fault 597c478bd9Sstevel@tonic-gate * tree (.eft) by the Solaris fault manager (fmd(1M)) for 607c478bd9Sstevel@tonic-gate * diagnosis. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * DDI_FM_ERRCB_CAPABLE 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * Device drivers are expected to implement and register an error 657c478bd9Sstevel@tonic-gate * handler callback function. ddi_fm_handler_register() and 667c478bd9Sstevel@tonic-gate * ddi_fm_handler_unregister() must be 677c478bd9Sstevel@tonic-gate * called in passive kernel context, typically during an attach(9E) 687c478bd9Sstevel@tonic-gate * or detach(9E) operation. When called by the FM IO framework, 697c478bd9Sstevel@tonic-gate * the callback function should check for error conditions for the 707c478bd9Sstevel@tonic-gate * hardware and software under its control. All detected errors 717c478bd9Sstevel@tonic-gate * should have ereport events generated for them. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * Upon completion of the error handler callback, the driver should 747c478bd9Sstevel@tonic-gate * return one of the following values: 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * #define DDI_FM_OK - no error was detected 777c478bd9Sstevel@tonic-gate * #define DDI_FM_FATAL - a fatal error was detected 787c478bd9Sstevel@tonic-gate * #define DDI_FM_NONFATAL - a non-fatal error was detected 797c478bd9Sstevel@tonic-gate * #define DDI_FM_UNKNOWN - the error status is unknown 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * To insure single threaded access to error handling callbacks, 827c478bd9Sstevel@tonic-gate * the device driver may use i_ddi_fm_handler_enter() and 837c478bd9Sstevel@tonic-gate * i_ddi_fm_handler_exit() when entering and exiting the callback. 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * DDI_FM_ACCCHK_CAPABLE/DDI_FM_DMACHK_CAPABLE 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * Device drivers are expected to set-up access and DMA handles 887c478bd9Sstevel@tonic-gate * with FM-specific attributes designed to allow nexus parent 897c478bd9Sstevel@tonic-gate * drivers to flag any errors seen during subsequent IO transactions. 907c478bd9Sstevel@tonic-gate * Drivers must set the devacc_attr_acc_flag member of their 917c478bd9Sstevel@tonic-gate * ddi_device_acc_attr_t structures to DDI_FLAGERR_ACC or DDI_CAUTIOUS_ACC. 927c478bd9Sstevel@tonic-gate * For DMA transactions, driver must set the dma_attr_flags of 937c478bd9Sstevel@tonic-gate * their ddi_dma_attr_t structures to DDI_DMA_FLAGERR. 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * Upon completion of an IO transaction, device drivers are expected 967c478bd9Sstevel@tonic-gate * to check the status of host-side hardware access and device-side 977c478bd9Sstevel@tonic-gate * dma completions by calling ddi_acc_err_check() or ddi_dma_err_check() 987c478bd9Sstevel@tonic-gate * respectively. If the handle is associated with an error detected by 997c478bd9Sstevel@tonic-gate * the nexus parent or FM IO framework, ddi_fm_error_t data (status, ena 1007c478bd9Sstevel@tonic-gate * and error expectation) is returned. If status of DDI_FM_NONFATAL or 1017c478bd9Sstevel@tonic-gate * DDI_FM_FATAL is returned, the ena is valid and the expectation flag 1027c478bd9Sstevel@tonic-gate * will be set to 1 if the error was unexpected (i.e. not the result 1037c478bd9Sstevel@tonic-gate * of a peek or poke type operation). 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * ddi_acc_err_check() and ddi_dma_err_check() may be called in any 1067c478bd9Sstevel@tonic-gate * context subject to the constraints specified by the interrupt 1077c478bd9Sstevel@tonic-gate * iblock cookie returned during initialization. 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * Device drivers should generate an access (DDI_FM_IO_ACC) or dma 1107c478bd9Sstevel@tonic-gate * (DDI_FM_IO_DMA) data path error report if DDI_FM_NONFATAL or 1117c478bd9Sstevel@tonic-gate * DDI_FM_FATAL is returned. 1127c478bd9Sstevel@tonic-gate * 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #include <sys/types.h> 1167c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 1177c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 1187c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 1197c478bd9Sstevel@tonic-gate #include <sys/nvpair.h> 1207c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 1217c478bd9Sstevel@tonic-gate #include <sys/ndifm.h> 1227c478bd9Sstevel@tonic-gate #include <sys/ddifm.h> 1237c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 1247c478bd9Sstevel@tonic-gate #include <sys/ddi_isa.h> 1257c478bd9Sstevel@tonic-gate #include <sys/spl.h> 1267c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 1277c478bd9Sstevel@tonic-gate #include <sys/systm.h> 1287c478bd9Sstevel@tonic-gate #include <sys/disp.h> 1297c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 1307c478bd9Sstevel@tonic-gate #include <sys/errorq_impl.h> 1317c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 1327c478bd9Sstevel@tonic-gate #include <sys/fm/util.h> 1337c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h> 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate #define ERPT_CLASS_SZ sizeof (DDI_IO_CLASS) + sizeof (FM_EREPORT_CLASS) + \ 1367c478bd9Sstevel@tonic-gate DDI_MAX_ERPT_CLASS + 2 1377c478bd9Sstevel@tonic-gate /* Globals */ 1387c478bd9Sstevel@tonic-gate int default_dmacache_sz = DEFAULT_DMACACHE_SZ; 1397c478bd9Sstevel@tonic-gate int default_acccache_sz = DEFAULT_ACCCACHE_SZ; 1407c478bd9Sstevel@tonic-gate int ddi_system_fmcap = 0; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate static struct i_ddi_fmkstat ddifm_kstat_template = { 1437c478bd9Sstevel@tonic-gate {"erpt_dropped", KSTAT_DATA_UINT64 }, 144a5667d81SCheng Sean Ye {"fm_cache_miss", KSTAT_DATA_UINT64 }, 1457c478bd9Sstevel@tonic-gate {"fm_cache_full", KSTAT_DATA_UINT64 }, 1467c478bd9Sstevel@tonic-gate {"acc_err", KSTAT_DATA_UINT64 }, 1477c478bd9Sstevel@tonic-gate {"dma_err", KSTAT_DATA_UINT64 } 1487c478bd9Sstevel@tonic-gate }; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Update the service state following the detection of an 1527c478bd9Sstevel@tonic-gate * error. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate void 1557c478bd9Sstevel@tonic-gate ddi_fm_service_impact(dev_info_t *dip, int svc_impact) 1567c478bd9Sstevel@tonic-gate { 15700d0963fSdilpreet uint64_t ena; 15800d0963fSdilpreet char buf[FM_MAX_CLASS]; 15900d0963fSdilpreet 16000d0963fSdilpreet ena = fm_ena_generate(0, FM_ENA_FMT1); 1617c478bd9Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 1627c478bd9Sstevel@tonic-gate if (!DEVI_IS_DEVICE_OFFLINE(dip)) { 1637c478bd9Sstevel@tonic-gate switch (svc_impact) { 1647c478bd9Sstevel@tonic-gate case DDI_SERVICE_LOST: 1657c478bd9Sstevel@tonic-gate DEVI_SET_DEVICE_DOWN(dip); 16600d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 16700d0963fSdilpreet DDI_FM_SERVICE_IMPACT, DDI_FM_SERVICE_LOST); 16800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 16900d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, 17000d0963fSdilpreet NULL); 1717c478bd9Sstevel@tonic-gate break; 1727c478bd9Sstevel@tonic-gate case DDI_SERVICE_DEGRADED: 1737c478bd9Sstevel@tonic-gate DEVI_SET_DEVICE_DEGRADED(dip); 17400d0963fSdilpreet if (DEVI_IS_DEVICE_DEGRADED(dip)) { 17500d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 17600d0963fSdilpreet DDI_FM_SERVICE_IMPACT, 17700d0963fSdilpreet DDI_FM_SERVICE_DEGRADED); 17800d0963fSdilpreet ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 17900d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 18000d0963fSdilpreet FM_EREPORT_VERS0, NULL); 18100d0963fSdilpreet } else if (DEVI_IS_DEVICE_DOWN(dip)) { 18200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 18300d0963fSdilpreet DDI_FM_SERVICE_IMPACT, 18400d0963fSdilpreet DDI_FM_SERVICE_LOST); 18500d0963fSdilpreet ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 18600d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, 18700d0963fSdilpreet FM_EREPORT_VERS0, NULL); 18800d0963fSdilpreet } 1897c478bd9Sstevel@tonic-gate break; 1907c478bd9Sstevel@tonic-gate case DDI_SERVICE_RESTORED: 1917c478bd9Sstevel@tonic-gate DEVI_SET_DEVICE_UP(dip); 19200d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 19300d0963fSdilpreet DDI_FM_SERVICE_IMPACT, DDI_FM_SERVICE_RESTORED); 19400d0963fSdilpreet ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 19500d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, 19600d0963fSdilpreet NULL); 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate case DDI_SERVICE_UNAFFECTED: 19900d0963fSdilpreet (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 20000d0963fSdilpreet DDI_FM_SERVICE_IMPACT, DDI_FM_SERVICE_UNAFFECTED); 20100d0963fSdilpreet ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 20200d0963fSdilpreet FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, 20300d0963fSdilpreet NULL); 20400d0963fSdilpreet break; 2057c478bd9Sstevel@tonic-gate default: 2067c478bd9Sstevel@tonic-gate break; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate void 2137c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dev_info_t *dip, const char *error_class, 2147c478bd9Sstevel@tonic-gate nvlist_t *errp, int sflag) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate int i; 2177c478bd9Sstevel@tonic-gate int depth; 2187c478bd9Sstevel@tonic-gate char classp[DDI_DVR_MAX_CLASS]; 2197c478bd9Sstevel@tonic-gate caddr_t stkp; 2207c478bd9Sstevel@tonic-gate char *buf; 2217c478bd9Sstevel@tonic-gate char **stkpp; 2227c478bd9Sstevel@tonic-gate char *sym; 2237c478bd9Sstevel@tonic-gate pc_t stack[DDI_FM_STKDEPTH]; 2247c478bd9Sstevel@tonic-gate ulong_t off; 2257c478bd9Sstevel@tonic-gate dev_info_t *root_dip = ddi_root_node(); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(root_dip))) 2287c478bd9Sstevel@tonic-gate return; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate (void) snprintf(classp, DDI_DVR_MAX_CLASS, "%s%s", DVR_ERPT, 2317c478bd9Sstevel@tonic-gate error_class); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (sflag == DDI_SLEEP) { 2347c478bd9Sstevel@tonic-gate depth = getpcstack(stack, DDI_FM_STKDEPTH); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* Allocate array of char * for nvlist payload */ 2377c478bd9Sstevel@tonic-gate stkpp = (char **)kmem_alloc(depth * sizeof (char *), KM_SLEEP); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Allocate temporary 64-bit aligned buffer for stack 2417c478bd9Sstevel@tonic-gate * symbol strings 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate buf = kmem_alloc(depth * DDI_FM_SYM_SZ, KM_SLEEP); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate stkp = buf; 2467c478bd9Sstevel@tonic-gate for (i = 0; i < depth; ++i) { 2477c478bd9Sstevel@tonic-gate sym = kobj_getsymname(stack[i], &off); 2487c478bd9Sstevel@tonic-gate (void) snprintf(stkp, DDI_FM_SYM_SZ, 2497c478bd9Sstevel@tonic-gate "\t%s+%lx\n", sym ? sym : "?", off); 2507c478bd9Sstevel@tonic-gate stkpp[i] = stkp; 2517c478bd9Sstevel@tonic-gate stkp += DDI_FM_SYM_SZ; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (errp) 2557c478bd9Sstevel@tonic-gate ddi_fm_ereport_post(root_dip, 2567c478bd9Sstevel@tonic-gate classp, fm_ena_generate(0, FM_ENA_FMT1), sflag, 2577c478bd9Sstevel@tonic-gate FM_VERSION, DATA_TYPE_UINT8, 0, 2587c478bd9Sstevel@tonic-gate DVR_NAME, DATA_TYPE_STRING, ddi_driver_name(dip), 2597c478bd9Sstevel@tonic-gate DVR_STACK_DEPTH, DATA_TYPE_UINT32, depth, 2607c478bd9Sstevel@tonic-gate DVR_STACK, DATA_TYPE_STRING_ARRAY, depth, stkpp, 2617c478bd9Sstevel@tonic-gate DVR_ERR_SPECIFIC, DATA_TYPE_NVLIST, errp, NULL); 2627c478bd9Sstevel@tonic-gate else 2637c478bd9Sstevel@tonic-gate ddi_fm_ereport_post(root_dip, 2647c478bd9Sstevel@tonic-gate classp, fm_ena_generate(0, FM_ENA_FMT1), sflag, 2657c478bd9Sstevel@tonic-gate FM_VERSION, DATA_TYPE_UINT8, 0, 2667c478bd9Sstevel@tonic-gate DVR_NAME, DATA_TYPE_STRING, ddi_driver_name(dip), 2677c478bd9Sstevel@tonic-gate DVR_STACK_DEPTH, DATA_TYPE_UINT32, depth, 2687c478bd9Sstevel@tonic-gate DVR_STACK, DATA_TYPE_STRING_ARRAY, depth, stkpp, 2697c478bd9Sstevel@tonic-gate NULL); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate kmem_free(stkpp, depth * sizeof (char *)); 2727c478bd9Sstevel@tonic-gate kmem_free(buf, depth * DDI_FM_SYM_SZ); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate } else { 2757c478bd9Sstevel@tonic-gate if (errp) 2767c478bd9Sstevel@tonic-gate ddi_fm_ereport_post(root_dip, 2777c478bd9Sstevel@tonic-gate classp, fm_ena_generate(0, FM_ENA_FMT1), sflag, 2787c478bd9Sstevel@tonic-gate FM_VERSION, DATA_TYPE_UINT8, 0, 2797c478bd9Sstevel@tonic-gate DVR_NAME, DATA_TYPE_STRING, ddi_driver_name(dip), 2807c478bd9Sstevel@tonic-gate DVR_ERR_SPECIFIC, DATA_TYPE_NVLIST, errp, NULL); 2817c478bd9Sstevel@tonic-gate else 2827c478bd9Sstevel@tonic-gate ddi_fm_ereport_post(root_dip, 2837c478bd9Sstevel@tonic-gate classp, fm_ena_generate(0, FM_ENA_FMT1), sflag, 2847c478bd9Sstevel@tonic-gate FM_VERSION, DATA_TYPE_UINT8, 0, 2857c478bd9Sstevel@tonic-gate DVR_NAME, DATA_TYPE_STRING, ddi_driver_name(dip), 2867c478bd9Sstevel@tonic-gate NULL); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 291602ca9eaScth * fm_dev_ereport_postv: Common consolidation private interface to 292602ca9eaScth * post a device tree oriented dev_scheme ereport. The device tree is 293602ca9eaScth * composed of the following entities: devinfo nodes, minor nodes, and 294602ca9eaScth * pathinfo nodes. All entities are associated with some devinfo node, 295602ca9eaScth * either directly or indirectly. The intended devinfo node association 296602ca9eaScth * for the ereport is communicated by the 'dip' argument. A minor node, 297602ca9eaScth * an entity below 'dip', is represented by a non-null 'minor_name' 298602ca9eaScth * argument. An application specific caller, like scsi_fm_ereport_post, 299602ca9eaScth * can override the devinfo path with a pathinfo path via a non-null 300602ca9eaScth * 'devpath' argument - in this case 'dip' is the MPXIO client node and 301602ca9eaScth * devpath should be the path through the pHCI devinfo node to the 302602ca9eaScth * pathinfo node. 303602ca9eaScth * 304602ca9eaScth * This interface also allows the caller to decide if the error being 305602ca9eaScth * reported is know to be associated with a specific device identity 306602ca9eaScth * via the 'devid' argument. The caller needs to control wether the 307602ca9eaScth * devid appears as an authority in the FMRI because for some types of 308602ca9eaScth * errors, like transport errors, the identity of the device on the 309602ca9eaScth * other end of the transport is not guaranteed to be the current 310602ca9eaScth * identity of the dip. For transport errors the caller should specify 311602ca9eaScth * a NULL devid, even when there is a valid devid associated with the dip. 312602ca9eaScth * 313602ca9eaScth * The ddi_fm_ereport_post() implementation calls this interface with 314602ca9eaScth * just a dip: devpath, minor_name, and devid are all NULL. The 315602ca9eaScth * scsi_fm_ereport_post() implementation may call this interface with 316602ca9eaScth * non-null devpath, minor_name, and devid arguments depending on 317602ca9eaScth * wether MPXIO is enabled, and wether a transport or non-transport 318602ca9eaScth * error is being posted. 319392e836bSGavin Maltby * 320392e836bSGavin Maltby * Additional event payload is specified via the varargs plist and, if 321392e836bSGavin Maltby * not NULL, the nvlist passed in (such an nvlist will be merged into 322392e836bSGavin Maltby * the payload; the caller is responsible for freeing this nvlist). 323392e836bSGavin Maltby * Do not specify any high-level protocol event member names as part of the 324392e836bSGavin Maltby * payload - eg no payload to be named "class", "version", "detector" etc 325392e836bSGavin Maltby * or they will replace the members we construct here. 326392e836bSGavin Maltby * 327392e836bSGavin Maltby * The 'target-port-l0id' argument is SCSI specific. It is used 328392e836bSGavin Maltby * by SCSI enumeration code when a devid is unavailable. If non-NULL 329392e836bSGavin Maltby * the property-value becomes part of the ereport detector. The value 330392e836bSGavin Maltby * specified might match one of the target-port-l0ids values of a 331392e836bSGavin Maltby * libtopo disk chassis node. When libtopo finds a disk with a guaranteed 332392e836bSGavin Maltby * unique wWWN target-port of a single-lun 'real' disk, it can add 333392e836bSGavin Maltby * the target-port value to the libtopo disk chassis node target-port-l0ids 334392e836bSGavin Maltby * string array property. Kernel code has no idea if this type of 335392e836bSGavin Maltby * libtopo chassis node exists, or if matching will in fact occur. 336602ca9eaScth */ 337602ca9eaScth void 338602ca9eaScth fm_dev_ereport_postv(dev_info_t *dip, dev_info_t *eqdip, 339602ca9eaScth const char *devpath, const char *minor_name, const char *devid, 340392e836bSGavin Maltby const char *tpl0, const char *error_class, uint64_t ena, int sflag, 341392e836bSGavin Maltby nvlist_t *pl, va_list ap) 342602ca9eaScth { 3430b1ecf75Scth nv_alloc_t *nva = NULL; 3440b1ecf75Scth struct i_ddi_fmhdl *fmhdl = NULL; 345602ca9eaScth errorq_elem_t *eqep; 346602ca9eaScth nvlist_t *ereport = NULL; 347602ca9eaScth nvlist_t *detector = NULL; 348602ca9eaScth char *name; 349602ca9eaScth data_type_t type; 350602ca9eaScth uint8_t version; 351602ca9eaScth char class[ERPT_CLASS_SZ]; 352602ca9eaScth char path[MAXPATHLEN]; 353602ca9eaScth 354392e836bSGavin Maltby ASSERT(ap != NULL); /* must supply at least ereport version */ 355602ca9eaScth ASSERT(dip && eqdip && error_class); 356602ca9eaScth 357602ca9eaScth /* 358602ca9eaScth * This interface should be called with a fm_capable eqdip. The 359602ca9eaScth * ddi_fm_ereport_post* interfaces call with eqdip == dip, 360602ca9eaScth * ndi_fm_ereport_post* interfaces call with eqdip == ddi_parent(dip). 361602ca9eaScth */ 362602ca9eaScth if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(eqdip))) 363602ca9eaScth goto err; 364602ca9eaScth 365602ca9eaScth /* get ereport nvlist handle */ 366602ca9eaScth if ((sflag == DDI_SLEEP) && !panicstr) { 367602ca9eaScth /* 368602ca9eaScth * Driver defect - should not call with DDI_SLEEP while in 369602ca9eaScth * interrupt context. 370602ca9eaScth */ 371602ca9eaScth if (servicing_interrupt()) { 372602ca9eaScth i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, sflag); 373602ca9eaScth goto err; 374602ca9eaScth } 375602ca9eaScth 376602ca9eaScth /* Use normal interfaces to allocate memory. */ 377602ca9eaScth if ((ereport = fm_nvlist_create(NULL)) == NULL) 378602ca9eaScth goto err; 3790b1ecf75Scth ASSERT(nva == NULL); 380602ca9eaScth } else { 381602ca9eaScth /* Use errorq interfaces to avoid memory allocation. */ 382602ca9eaScth fmhdl = DEVI(eqdip)->devi_fmhdl; 383602ca9eaScth ASSERT(fmhdl); 384602ca9eaScth eqep = errorq_reserve(fmhdl->fh_errorq); 385602ca9eaScth if (eqep == NULL) 386602ca9eaScth goto err; 387602ca9eaScth 388602ca9eaScth ereport = errorq_elem_nvl(fmhdl->fh_errorq, eqep); 389602ca9eaScth nva = errorq_elem_nva(fmhdl->fh_errorq, eqep); 390602ca9eaScth ASSERT(nva); 391602ca9eaScth } 392602ca9eaScth ASSERT(ereport); 393602ca9eaScth 394602ca9eaScth /* 395602ca9eaScth * Form parts of an ereport: 396602ca9eaScth * A: version 397602ca9eaScth * B: error_class 398602ca9eaScth * C: ena 399602ca9eaScth * D: detector (path and optional devid authority) 400602ca9eaScth * E: payload 401602ca9eaScth * 402602ca9eaScth * A: ereport version: first payload tuple must be the version. 403602ca9eaScth */ 404602ca9eaScth name = va_arg(ap, char *); 405602ca9eaScth type = va_arg(ap, data_type_t); 406602ca9eaScth version = va_arg(ap, uint_t); 407602ca9eaScth if ((strcmp(name, FM_VERSION) != 0) || (type != DATA_TYPE_UINT8)) { 408602ca9eaScth i_ddi_drv_ereport_post(dip, DVR_EVER, NULL, sflag); 409602ca9eaScth goto err; 410602ca9eaScth } 411602ca9eaScth 412602ca9eaScth /* B: ereport error_class: add "io." prefix to class. */ 413602ca9eaScth (void) snprintf(class, ERPT_CLASS_SZ, "%s.%s", 414602ca9eaScth DDI_IO_CLASS, error_class); 415602ca9eaScth 416602ca9eaScth /* C: ereport ena: if not passed in, generate new ena. */ 417602ca9eaScth if (ena == 0) 418602ca9eaScth ena = fm_ena_generate(0, FM_ENA_FMT1); 419602ca9eaScth 420602ca9eaScth /* D: detector: form dev scheme fmri with path and devid. */ 421602ca9eaScth if (devpath) { 422602ca9eaScth (void) strlcpy(path, devpath, sizeof (path)); 423602ca9eaScth } else { 424602ca9eaScth /* derive devpath from dip */ 425602ca9eaScth if (dip == ddi_root_node()) 426602ca9eaScth (void) strcpy(path, "/"); 427602ca9eaScth else 428602ca9eaScth (void) ddi_pathname(dip, path); 429602ca9eaScth } 430602ca9eaScth if (minor_name) { 431602ca9eaScth (void) strlcat(path, ":", sizeof (path)); 432602ca9eaScth (void) strlcat(path, minor_name, sizeof (path)); 433602ca9eaScth } 434602ca9eaScth detector = fm_nvlist_create(nva); 435392e836bSGavin Maltby fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, path, 436392e836bSGavin Maltby devid, tpl0); 437602ca9eaScth 438602ca9eaScth /* Pull parts of ereport together into ereport. */ 439602ca9eaScth fm_ereport_set(ereport, version, class, ena, detector, NULL); 440602ca9eaScth 441392e836bSGavin Maltby /* Merge any preconstructed payload into the event. */ 442392e836bSGavin Maltby if (pl) 443392e836bSGavin Maltby (void) nvlist_merge(ereport, pl, 0); 444392e836bSGavin Maltby 445392e836bSGavin Maltby /* Add any remaining (after version) varargs payload to ereport. */ 446602ca9eaScth name = va_arg(ap, char *); 447602ca9eaScth (void) i_fm_payload_set(ereport, name, ap); 448602ca9eaScth 449602ca9eaScth /* Post the ereport. */ 450602ca9eaScth if (nva) 451602ca9eaScth errorq_commit(fmhdl->fh_errorq, eqep, ERRORQ_ASYNC); 452602ca9eaScth else 453602ca9eaScth fm_ereport_post(ereport, EVCH_SLEEP); 454602ca9eaScth goto out; 455602ca9eaScth 456602ca9eaScth /* Count errors as drops. */ 457602ca9eaScth err: if (fmhdl) 458*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fmhdl->fh_kstat.fek_erpt_dropped.value.ui64); 459602ca9eaScth 4600b1ecf75Scth /* Free up nvlists if normal interfaces were used to allocate memory */ 461602ca9eaScth out: if (ereport && (nva == NULL)) 462602ca9eaScth fm_nvlist_destroy(ereport, FM_NVA_FREE); 463602ca9eaScth if (detector && (nva == NULL)) 464602ca9eaScth fm_nvlist_destroy(detector, FM_NVA_FREE); 465602ca9eaScth } 466602ca9eaScth 467602ca9eaScth /* 4687c478bd9Sstevel@tonic-gate * Generate an error report for consumption by the Solaris Fault Manager, 469602ca9eaScth * fmd(1M). Valid ereport classes are defined in /usr/include/sys/fm/io. 470602ca9eaScth * 471602ca9eaScth * The ENA should be set if this error is a result of an error status 472602ca9eaScth * returned from ddi_dma_err_check() or ddi_acc_err_check(). Otherwise, 473602ca9eaScth * an ENA value of 0 is appropriate. 4747c478bd9Sstevel@tonic-gate * 4757c478bd9Sstevel@tonic-gate * If sflag == DDI_NOSLEEP, ddi_fm_ereport_post () may be called 4767c478bd9Sstevel@tonic-gate * from user, kernel, interrupt or high-interrupt context. Otherwise, 4777c478bd9Sstevel@tonic-gate * ddi_fm_ereport_post() must be called from user or kernel context. 478602ca9eaScth * 479602ca9eaScth * The ndi_interfaces are provided for use by nexus drivers to post 480602ca9eaScth * ereports about children who may not themselves be fm_capable. 481602ca9eaScth * 482602ca9eaScth * All interfaces end up in the common fm_dev_ereport_postv code above. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate void 485602ca9eaScth ddi_fm_ereport_post(dev_info_t *dip, 486602ca9eaScth const char *error_class, uint64_t ena, int sflag, ...) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate va_list ap; 4897c478bd9Sstevel@tonic-gate 490602ca9eaScth ASSERT(dip && error_class); 4917c478bd9Sstevel@tonic-gate va_start(ap, sflag); 492392e836bSGavin Maltby fm_dev_ereport_postv(dip, dip, NULL, NULL, NULL, NULL, 493392e836bSGavin Maltby error_class, ena, sflag, NULL, ap); 4947c478bd9Sstevel@tonic-gate va_end(ap); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 497602ca9eaScth void 498602ca9eaScth ndi_fm_ereport_post(dev_info_t *dip, 499602ca9eaScth const char *error_class, uint64_t ena, int sflag, ...) 500602ca9eaScth { 501602ca9eaScth va_list ap; 502602ca9eaScth 503602ca9eaScth ASSERT(dip && error_class && (sflag == DDI_SLEEP)); 504602ca9eaScth va_start(ap, sflag); 505392e836bSGavin Maltby fm_dev_ereport_postv(dip, ddi_get_parent(dip), NULL, NULL, NULL, NULL, 506392e836bSGavin Maltby error_class, ena, sflag, NULL, ap); 5077c478bd9Sstevel@tonic-gate va_end(ap); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Driver error handling entry. Prevents multiple simultaneous calls into 5127c478bd9Sstevel@tonic-gate * driver error handling callback. 5137c478bd9Sstevel@tonic-gate * 5147c478bd9Sstevel@tonic-gate * May be called from a context consistent with the iblock_cookie returned 5157c478bd9Sstevel@tonic-gate * in ddi_fm_init(). 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate void 5187c478bd9Sstevel@tonic-gate i_ddi_fm_handler_enter(dev_info_t *dip) 5197c478bd9Sstevel@tonic-gate { 5207c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate mutex_enter(&hdl->fh_lock); 523eae2e508Skrishnae hdl->fh_lock_owner = curthread; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * Driver error handling exit. 5287c478bd9Sstevel@tonic-gate * 5297c478bd9Sstevel@tonic-gate * May be called from a context consistent with the iblock_cookie returned 5307c478bd9Sstevel@tonic-gate * in ddi_fm_init(). 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate void 5337c478bd9Sstevel@tonic-gate i_ddi_fm_handler_exit(dev_info_t *dip) 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl; 5367c478bd9Sstevel@tonic-gate 537eae2e508Skrishnae hdl->fh_lock_owner = NULL; 5387c478bd9Sstevel@tonic-gate mutex_exit(&hdl->fh_lock); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 541eae2e508Skrishnae boolean_t 542eae2e508Skrishnae i_ddi_fm_handler_owned(dev_info_t *dip) 543eae2e508Skrishnae { 544eae2e508Skrishnae struct i_ddi_fmhdl *hdl = DEVI(dip)->devi_fmhdl; 545eae2e508Skrishnae 546eae2e508Skrishnae return (hdl->fh_lock_owner == curthread); 547eae2e508Skrishnae } 548eae2e508Skrishnae 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * Register a fault manager error handler for this device instance 5517c478bd9Sstevel@tonic-gate * 5527c478bd9Sstevel@tonic-gate * This function must be called from a driver's attach(9E) routine. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate void 5557c478bd9Sstevel@tonic-gate ddi_fm_handler_register(dev_info_t *dip, ddi_err_func_t handler, 5567c478bd9Sstevel@tonic-gate void *impl_data) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate dev_info_t *pdip; 5597c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *pfmhdl; 5607c478bd9Sstevel@tonic-gate struct i_ddi_errhdl *new_eh; 5617c478bd9Sstevel@tonic-gate struct i_ddi_fmtgt *tgt; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* 5647c478bd9Sstevel@tonic-gate * Check for proper calling context. 5657c478bd9Sstevel@tonic-gate * The DDI configuration framework does not support 5667c478bd9Sstevel@tonic-gate * DR states to allow checking for proper invocation 5677c478bd9Sstevel@tonic-gate * from a DDI_ATTACH or DDI_RESUME. This limits context checking 5687c478bd9Sstevel@tonic-gate * to interrupt only. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate if (servicing_interrupt()) { 5717c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, DDI_NOSLEEP); 5727c478bd9Sstevel@tonic-gate return; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757aec1d6eScindi if (dip == ddi_root_node()) 5767aec1d6eScindi pdip = dip; 5777aec1d6eScindi else 5787c478bd9Sstevel@tonic-gate pdip = (dev_info_t *)DEVI(dip)->devi_parent; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate ASSERT(pdip); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (!(DDI_FM_ERRCB_CAP(ddi_fm_capable(dip)) && 5837c478bd9Sstevel@tonic-gate DDI_FM_ERRCB_CAP(ddi_fm_capable(pdip)))) { 5847c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 5857c478bd9Sstevel@tonic-gate return; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate new_eh = kmem_zalloc(sizeof (struct i_ddi_errhdl), KM_SLEEP); 5897c478bd9Sstevel@tonic-gate new_eh->eh_func = handler; 5907c478bd9Sstevel@tonic-gate new_eh->eh_impl = impl_data; 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* Add dip to parent's target list of registered error handlers */ 5937c478bd9Sstevel@tonic-gate tgt = kmem_alloc(sizeof (struct i_ddi_fmtgt), KM_SLEEP); 5947c478bd9Sstevel@tonic-gate tgt->ft_dip = dip; 5957c478bd9Sstevel@tonic-gate tgt->ft_errhdl = new_eh; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate i_ddi_fm_handler_enter(pdip); 5987c478bd9Sstevel@tonic-gate pfmhdl = DEVI(pdip)->devi_fmhdl; 5997c478bd9Sstevel@tonic-gate ASSERT(pfmhdl); 6007c478bd9Sstevel@tonic-gate tgt->ft_next = pfmhdl->fh_tgts; 6017c478bd9Sstevel@tonic-gate pfmhdl->fh_tgts = tgt; 6027c478bd9Sstevel@tonic-gate i_ddi_fm_handler_exit(pdip); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * Unregister a fault manager error handler for this device instance 6077c478bd9Sstevel@tonic-gate * 6087c478bd9Sstevel@tonic-gate * This function must be called from a drivers attach(9E) or detach(9E) 6097c478bd9Sstevel@tonic-gate * routine. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate void 6127c478bd9Sstevel@tonic-gate ddi_fm_handler_unregister(dev_info_t *dip) 6137c478bd9Sstevel@tonic-gate { 6147c478bd9Sstevel@tonic-gate dev_info_t *pdip; 6157c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *pfmhdl; 6167c478bd9Sstevel@tonic-gate struct i_ddi_fmtgt *tgt, **ptgt; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* 6197c478bd9Sstevel@tonic-gate * Check for proper calling context. 6207c478bd9Sstevel@tonic-gate * The DDI configuration framework does not support 6217c478bd9Sstevel@tonic-gate * DR states to allow checking for proper invocation 6227c478bd9Sstevel@tonic-gate * from a DDI_DETACH or DDI_SUSPEND. This limits context checking 6237c478bd9Sstevel@tonic-gate * to interrupt only. 6247c478bd9Sstevel@tonic-gate */ 6257c478bd9Sstevel@tonic-gate if (servicing_interrupt()) { 6267c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, DDI_NOSLEEP); 6277c478bd9Sstevel@tonic-gate return; 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307aec1d6eScindi if (dip == ddi_root_node()) 6317aec1d6eScindi pdip = dip; 6327aec1d6eScindi else 6337c478bd9Sstevel@tonic-gate pdip = (dev_info_t *)DEVI(dip)->devi_parent; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate ASSERT(pdip); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate if (!(DDI_FM_ERRCB_CAP(ddi_fm_capable(dip)) && 6387c478bd9Sstevel@tonic-gate DDI_FM_ERRCB_CAP(ddi_fm_capable(pdip)))) { 6397c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 6407c478bd9Sstevel@tonic-gate return; 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate i_ddi_fm_handler_enter(pdip); 6447c478bd9Sstevel@tonic-gate pfmhdl = DEVI(pdip)->devi_fmhdl; 6457c478bd9Sstevel@tonic-gate ASSERT(pfmhdl); 6467c478bd9Sstevel@tonic-gate ptgt = &pfmhdl->fh_tgts; 6477c478bd9Sstevel@tonic-gate for (tgt = pfmhdl->fh_tgts; tgt != NULL; tgt = tgt->ft_next) { 6487c478bd9Sstevel@tonic-gate if (dip == tgt->ft_dip) { 6497c478bd9Sstevel@tonic-gate *ptgt = tgt->ft_next; 6507c478bd9Sstevel@tonic-gate kmem_free(tgt->ft_errhdl, sizeof (struct i_ddi_errhdl)); 6517c478bd9Sstevel@tonic-gate kmem_free(tgt, sizeof (struct i_ddi_fmtgt)); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate ptgt = &tgt->ft_next; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate i_ddi_fm_handler_exit(pdip); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * Initialize Fault Management capabilities for this device instance (dip). 6637c478bd9Sstevel@tonic-gate * When called with the following capabilities, data structures neccessary 6647c478bd9Sstevel@tonic-gate * for fault management activities are allocated and initialized. 6657c478bd9Sstevel@tonic-gate * 6667c478bd9Sstevel@tonic-gate * DDI_FM_EREPORT_CAPABLE - initialize ereport errorq and ereport 6677c478bd9Sstevel@tonic-gate * capable driver property. 6687c478bd9Sstevel@tonic-gate * 6697c478bd9Sstevel@tonic-gate * DDI_FM_ERRCB_CAPABLE - check with parent for ability to register 6707c478bd9Sstevel@tonic-gate * an error handler. 6717c478bd9Sstevel@tonic-gate * 6727c478bd9Sstevel@tonic-gate * DDI_FM_ACCCHK_CAPABLE - initialize access handle cache and acc-chk 6737c478bd9Sstevel@tonic-gate * driver property 6747c478bd9Sstevel@tonic-gate * 6757c478bd9Sstevel@tonic-gate * DDI_FM_DMACHK_CAPABLE - initialize dma handle cache and dma-chk 6767c478bd9Sstevel@tonic-gate * driver property 6777c478bd9Sstevel@tonic-gate * 6787c478bd9Sstevel@tonic-gate * A driver's FM capability level may not exceed that of its parent or 6797c478bd9Sstevel@tonic-gate * system-wide FM capability. The available capability level for this 6807c478bd9Sstevel@tonic-gate * device instance is returned in *fmcap. 6817c478bd9Sstevel@tonic-gate * 6827c478bd9Sstevel@tonic-gate * This function must be called from a driver's attach(9E) entry point. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate void 6857aec1d6eScindi ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibcp) 6867c478bd9Sstevel@tonic-gate { 6877c478bd9Sstevel@tonic-gate struct dev_info *devi = DEVI(dip); 6887c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl; 6897aec1d6eScindi ddi_iblock_cookie_t ibc; 6907c478bd9Sstevel@tonic-gate int pcap, newcap = DDI_FM_NOT_CAPABLE; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate if (!DEVI_IS_ATTACHING(dip)) { 6937c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, DDI_NOSLEEP); 6947c478bd9Sstevel@tonic-gate *fmcap = DDI_FM_NOT_CAPABLE; 6957c478bd9Sstevel@tonic-gate return; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate if (DDI_FM_DEFAULT_CAP(*fmcap)) 6997c478bd9Sstevel@tonic-gate return; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Check parent for supported FM level 7037c478bd9Sstevel@tonic-gate * and correct error handling PIL 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate if (dip != ddi_root_node()) { 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * Initialize the default ibc. The parent may change it 7097c478bd9Sstevel@tonic-gate * depending upon its capabilities. 7107c478bd9Sstevel@tonic-gate */ 7117aec1d6eScindi ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL); 7127c478bd9Sstevel@tonic-gate 7137aec1d6eScindi pcap = i_ndi_busop_fm_init(dip, *fmcap, &ibc); 7147c478bd9Sstevel@tonic-gate } else { 7157c478bd9Sstevel@tonic-gate pcap = *fmcap; 7167aec1d6eScindi ibc = *ibcp; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* Initialize the per-device instance FM handle */ 7207c478bd9Sstevel@tonic-gate fmhdl = kmem_zalloc(sizeof (struct i_ddi_fmhdl), KM_SLEEP); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if ((fmhdl->fh_ksp = kstat_create((char *)ddi_driver_name(dip), 7237c478bd9Sstevel@tonic-gate ddi_get_instance(dip), "fm", "misc", 7247c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (struct i_ddi_fmkstat) / 7257c478bd9Sstevel@tonic-gate sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL)) == NULL) { 7267c478bd9Sstevel@tonic-gate mutex_destroy(&fmhdl->fh_lock); 7277c478bd9Sstevel@tonic-gate kmem_free(fmhdl, sizeof (struct i_ddi_fmhdl)); 7287c478bd9Sstevel@tonic-gate *fmcap = DDI_FM_NOT_CAPABLE; 7297c478bd9Sstevel@tonic-gate return; 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate bcopy(&ddifm_kstat_template, &fmhdl->fh_kstat, 7337c478bd9Sstevel@tonic-gate sizeof (struct i_ddi_fmkstat)); 7347c478bd9Sstevel@tonic-gate fmhdl->fh_ksp->ks_data = &fmhdl->fh_kstat; 7357c478bd9Sstevel@tonic-gate fmhdl->fh_ksp->ks_private = fmhdl; 7367c478bd9Sstevel@tonic-gate kstat_install(fmhdl->fh_ksp); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate fmhdl->fh_dma_cache = NULL; 7397c478bd9Sstevel@tonic-gate fmhdl->fh_acc_cache = NULL; 7407c478bd9Sstevel@tonic-gate fmhdl->fh_tgts = NULL; 7417c478bd9Sstevel@tonic-gate fmhdl->fh_dip = dip; 7427aec1d6eScindi fmhdl->fh_ibc = ibc; 7437c478bd9Sstevel@tonic-gate mutex_init(&fmhdl->fh_lock, NULL, MUTEX_DRIVER, fmhdl->fh_ibc); 7447c478bd9Sstevel@tonic-gate devi->devi_fmhdl = fmhdl; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Initialize support for ereport generation 7487c478bd9Sstevel@tonic-gate */ 74900d0963fSdilpreet if (DDI_FM_EREPORT_CAP(*fmcap) && DDI_FM_EREPORT_CAP(pcap)) { 7507c478bd9Sstevel@tonic-gate fmhdl->fh_errorq = ereport_errorq; 75100d0963fSdilpreet if (ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 7527c478bd9Sstevel@tonic-gate "fm-ereport-capable", 0) == 0) 75300d0963fSdilpreet (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 7547c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "fm-ereport-capable", NULL, 0); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate newcap |= DDI_FM_EREPORT_CAPABLE; 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate * Need cooperation of the parent for error handling 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate if (DDI_FM_ERRCB_CAP(*fmcap) && DDI_FM_ERRCB_CAP(pcap)) { 76400d0963fSdilpreet if (ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 7657c478bd9Sstevel@tonic-gate "fm-errcb-capable", 0) == 0) 76600d0963fSdilpreet (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 7677c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "fm-errcb-capable", NULL, 0); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate newcap |= DDI_FM_ERRCB_CAPABLE; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Support for DMA and Access error handling 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate if (DDI_FM_DMA_ERR_CAP(*fmcap) && DDI_FM_DMA_ERR_CAP(pcap)) { 7777aec1d6eScindi i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, ibc); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* Set-up dma chk capability prop */ 78000d0963fSdilpreet if (ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 7817c478bd9Sstevel@tonic-gate "fm-dmachk-capable", 0) == 0) 78200d0963fSdilpreet (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 7837c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "fm-dmachk-capable", NULL, 0); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate newcap |= DDI_FM_DMACHK_CAPABLE; 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (DDI_FM_ACC_ERR_CAP(*fmcap) && DDI_FM_ACC_ERR_CAP(pcap)) { 7897aec1d6eScindi i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, ibc); 7907c478bd9Sstevel@tonic-gate /* Set-up dma chk capability prop */ 79100d0963fSdilpreet if (ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 7927c478bd9Sstevel@tonic-gate "fm-accchk-capable", 0) == 0) 79300d0963fSdilpreet (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 7947c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "fm-accchk-capable", NULL, 0); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate newcap |= DDI_FM_ACCCHK_CAPABLE; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * Return the capability support available 8017c478bd9Sstevel@tonic-gate * to this driver instance 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate fmhdl->fh_cap = newcap; 8047c478bd9Sstevel@tonic-gate *fmcap = newcap; 8057aec1d6eScindi 8067aec1d6eScindi if (ibcp != NULL) 8077aec1d6eScindi *ibcp = ibc; 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate /* 8117c478bd9Sstevel@tonic-gate * Finalize Fault Management activities for this device instance. 8127c478bd9Sstevel@tonic-gate * Outstanding IO transaction must be completed prior to calling 8137c478bd9Sstevel@tonic-gate * this routine. All previously allocated resources and error handler 8147c478bd9Sstevel@tonic-gate * registration are cleared and deallocated. 8157c478bd9Sstevel@tonic-gate * 8167c478bd9Sstevel@tonic-gate * This function must be called from a driver's detach(9E) entry point. 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate void 8197c478bd9Sstevel@tonic-gate ddi_fm_fini(dev_info_t *dip) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 8227c478bd9Sstevel@tonic-gate 82300d0963fSdilpreet ASSERT(fmhdl); 82400d0963fSdilpreet 8257c478bd9Sstevel@tonic-gate if (!(DEVI_IS_DETACHING(dip) || DEVI_IS_ATTACHING(dip))) { 8267c478bd9Sstevel@tonic-gate i_ddi_drv_ereport_post(dip, DVR_ECONTEXT, NULL, DDI_NOSLEEP); 8277c478bd9Sstevel@tonic-gate return; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate kstat_delete(fmhdl->fh_ksp); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate if (DDI_FM_EREPORT_CAP(fmhdl->fh_cap)) { 83300d0963fSdilpreet (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 8347c478bd9Sstevel@tonic-gate "fm-ereport-capable"); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate if (dip != ddi_root_node()) { 838cecfa358Sstephh if (DDI_FM_ERRCB_CAP(fmhdl->fh_cap)) { 8397c478bd9Sstevel@tonic-gate ddi_fm_handler_unregister(dip); 840cecfa358Sstephh (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 841cecfa358Sstephh "fm-errcb-capable"); 842cecfa358Sstephh } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (DDI_FM_DMA_ERR_CAP(fmhdl->fh_cap) || 8457c478bd9Sstevel@tonic-gate DDI_FM_ACC_ERR_CAP(fmhdl->fh_cap)) { 8467c478bd9Sstevel@tonic-gate if (fmhdl->fh_dma_cache != NULL) { 8477c478bd9Sstevel@tonic-gate i_ndi_fmc_destroy(fmhdl->fh_dma_cache); 84800d0963fSdilpreet (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 8497c478bd9Sstevel@tonic-gate "fm-dmachk-capable"); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate if (fmhdl->fh_acc_cache != NULL) { 8527c478bd9Sstevel@tonic-gate i_ndi_fmc_destroy(fmhdl->fh_acc_cache); 85300d0963fSdilpreet (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 8547c478bd9Sstevel@tonic-gate "fm-accachk-capable"); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate i_ndi_busop_fm_fini(dip); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate kmem_free(fmhdl, sizeof (struct i_ddi_fmhdl)); 8627c478bd9Sstevel@tonic-gate DEVI(dip)->devi_fmhdl = NULL; 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * Return the fault management capability level for this device instance. 8677c478bd9Sstevel@tonic-gate * 8687c478bd9Sstevel@tonic-gate * This function may be called from user, kernel, or interrupt context. 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate int 8717c478bd9Sstevel@tonic-gate ddi_fm_capable(dev_info_t *dip) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate if (fmhdl == NULL) 8767c478bd9Sstevel@tonic-gate return (DDI_FM_NOT_CAPABLE); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate return (fmhdl->fh_cap); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Routines to set and get error information for/from an access or dma handle 8837c478bd9Sstevel@tonic-gate * 8847c478bd9Sstevel@tonic-gate * These routines may be called from user, kernel, and interrupt contexts. 8857c478bd9Sstevel@tonic-gate */ 886837c1ac4SStephen Hanson 887837c1ac4SStephen Hanson static void 888837c1ac4SStephen Hanson ddi_fm_acc_err_get_fail(ddi_acc_handle_t handle) 889837c1ac4SStephen Hanson { 890837c1ac4SStephen Hanson ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 891837c1ac4SStephen Hanson 892837c1ac4SStephen Hanson i_ddi_drv_ereport_post(hp->ah_dip, DVR_EVER, NULL, DDI_NOSLEEP); 893837c1ac4SStephen Hanson cmn_err(CE_PANIC, "ddi_fm_acc_err_get: Invalid driver version\n"); 894837c1ac4SStephen Hanson } 895837c1ac4SStephen Hanson 8967c478bd9Sstevel@tonic-gate void 8977c478bd9Sstevel@tonic-gate ddi_fm_acc_err_get(ddi_acc_handle_t handle, ddi_fm_error_t *de, int version) 8987c478bd9Sstevel@tonic-gate { 89900d0963fSdilpreet ndi_err_t *errp; 90000d0963fSdilpreet 90100d0963fSdilpreet if (handle == NULL) 90200d0963fSdilpreet return; 9037c478bd9Sstevel@tonic-gate 9048aec9182Sstephh if (version != DDI_FME_VER0 && version != DDI_FME_VER1) { 905837c1ac4SStephen Hanson ddi_fm_acc_err_get_fail(handle); 906837c1ac4SStephen Hanson return; 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 90900d0963fSdilpreet errp = ((ddi_acc_impl_t *)handle)->ahi_err; 910837c1ac4SStephen Hanson if (errp->err_status == DDI_FM_OK) { 911837c1ac4SStephen Hanson if (de->fme_status != DDI_FM_OK) 912837c1ac4SStephen Hanson de->fme_status = DDI_FM_OK; 913837c1ac4SStephen Hanson return; 914837c1ac4SStephen Hanson } 9157c478bd9Sstevel@tonic-gate de->fme_status = errp->err_status; 9167c478bd9Sstevel@tonic-gate de->fme_ena = errp->err_ena; 9177c478bd9Sstevel@tonic-gate de->fme_flag = errp->err_expected; 9187c478bd9Sstevel@tonic-gate de->fme_acc_handle = handle; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate void 922837c1ac4SStephen Hanson ddi_fm_dma_err_get_fail(ddi_dma_handle_t handle) 923837c1ac4SStephen Hanson { 924837c1ac4SStephen Hanson i_ddi_drv_ereport_post(((ddi_dma_impl_t *)handle)->dmai_rdip, 925837c1ac4SStephen Hanson DVR_EVER, NULL, DDI_NOSLEEP); 926837c1ac4SStephen Hanson cmn_err(CE_PANIC, "ddi_fm_dma_err_get: Invalid driver version\n"); 927837c1ac4SStephen Hanson } 928837c1ac4SStephen Hanson 929837c1ac4SStephen Hanson void 9307c478bd9Sstevel@tonic-gate ddi_fm_dma_err_get(ddi_dma_handle_t handle, ddi_fm_error_t *de, int version) 9317c478bd9Sstevel@tonic-gate { 93200d0963fSdilpreet ndi_err_t *errp; 93300d0963fSdilpreet 93400d0963fSdilpreet if (handle == NULL) 93500d0963fSdilpreet return; 9367c478bd9Sstevel@tonic-gate 9378aec9182Sstephh if (version != DDI_FME_VER0 && version != DDI_FME_VER1) { 938837c1ac4SStephen Hanson ddi_fm_dma_err_get_fail(handle); 939837c1ac4SStephen Hanson return; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 94200d0963fSdilpreet errp = &((ddi_dma_impl_t *)handle)->dmai_error; 94300d0963fSdilpreet 944837c1ac4SStephen Hanson if (errp->err_status == DDI_FM_OK) { 945837c1ac4SStephen Hanson if (de->fme_status != DDI_FM_OK) 946837c1ac4SStephen Hanson de->fme_status = DDI_FM_OK; 947837c1ac4SStephen Hanson return; 948837c1ac4SStephen Hanson } 9497c478bd9Sstevel@tonic-gate de->fme_status = errp->err_status; 9507c478bd9Sstevel@tonic-gate de->fme_ena = errp->err_ena; 9517c478bd9Sstevel@tonic-gate de->fme_flag = errp->err_expected; 9527c478bd9Sstevel@tonic-gate de->fme_dma_handle = handle; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate void 956837c1ac4SStephen Hanson ddi_fm_acc_err_clear_fail(ddi_acc_handle_t handle) 957837c1ac4SStephen Hanson { 958837c1ac4SStephen Hanson ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle); 959837c1ac4SStephen Hanson 960837c1ac4SStephen Hanson i_ddi_drv_ereport_post(hp->ah_dip, DVR_EVER, NULL, DDI_NOSLEEP); 961837c1ac4SStephen Hanson cmn_err(CE_PANIC, "ddi_fm_acc_err_clear: Invalid driver version\n"); 962837c1ac4SStephen Hanson } 963837c1ac4SStephen Hanson 964837c1ac4SStephen Hanson void 96500d0963fSdilpreet ddi_fm_acc_err_clear(ddi_acc_handle_t handle, int version) 96600d0963fSdilpreet { 96700d0963fSdilpreet ndi_err_t *errp; 96800d0963fSdilpreet 96900d0963fSdilpreet if (handle == NULL) 97000d0963fSdilpreet return; 97100d0963fSdilpreet 9728aec9182Sstephh if (version != DDI_FME_VER0 && version != DDI_FME_VER1) { 973837c1ac4SStephen Hanson ddi_fm_acc_err_clear_fail(handle); 974837c1ac4SStephen Hanson return; 97500d0963fSdilpreet } 97600d0963fSdilpreet 97700d0963fSdilpreet errp = ((ddi_acc_impl_t *)handle)->ahi_err; 97800d0963fSdilpreet errp->err_status = DDI_FM_OK; 97900d0963fSdilpreet errp->err_ena = 0; 98000d0963fSdilpreet errp->err_expected = DDI_FM_ERR_UNEXPECTED; 98100d0963fSdilpreet } 98200d0963fSdilpreet 98300d0963fSdilpreet void 984837c1ac4SStephen Hanson ddi_fm_dma_err_clear_fail(ddi_dma_handle_t handle) 985837c1ac4SStephen Hanson { 986837c1ac4SStephen Hanson i_ddi_drv_ereport_post(((ddi_dma_impl_t *)handle)->dmai_rdip, 987837c1ac4SStephen Hanson DVR_EVER, NULL, DDI_NOSLEEP); 988837c1ac4SStephen Hanson cmn_err(CE_PANIC, "ddi_fm_dma_err_clear: Invalid driver version\n"); 989837c1ac4SStephen Hanson } 990837c1ac4SStephen Hanson 991837c1ac4SStephen Hanson void 99200d0963fSdilpreet ddi_fm_dma_err_clear(ddi_dma_handle_t handle, int version) 99300d0963fSdilpreet { 99400d0963fSdilpreet ndi_err_t *errp; 99500d0963fSdilpreet 99600d0963fSdilpreet if (handle == NULL) 99700d0963fSdilpreet return; 99800d0963fSdilpreet 9998aec9182Sstephh if (version != DDI_FME_VER0 && version != DDI_FME_VER1) { 1000837c1ac4SStephen Hanson ddi_fm_dma_err_clear_fail(handle); 1001837c1ac4SStephen Hanson return; 100200d0963fSdilpreet } 100300d0963fSdilpreet 100400d0963fSdilpreet errp = &((ddi_dma_impl_t *)handle)->dmai_error; 100500d0963fSdilpreet 100600d0963fSdilpreet errp->err_status = DDI_FM_OK; 100700d0963fSdilpreet errp->err_ena = 0; 100800d0963fSdilpreet errp->err_expected = DDI_FM_ERR_UNEXPECTED; 100900d0963fSdilpreet } 101000d0963fSdilpreet 101100d0963fSdilpreet void 10127c478bd9Sstevel@tonic-gate i_ddi_fm_acc_err_set(ddi_acc_handle_t handle, uint64_t ena, int status, 10137c478bd9Sstevel@tonic-gate int flag) 10147c478bd9Sstevel@tonic-gate { 10157c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hdlp = impl_acc_hdl_get(handle); 10167c478bd9Sstevel@tonic-gate ddi_acc_impl_t *i_hdlp = (ddi_acc_impl_t *)handle; 10177c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(hdlp->ah_dip)->devi_fmhdl; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate i_hdlp->ahi_err->err_ena = ena; 10207c478bd9Sstevel@tonic-gate i_hdlp->ahi_err->err_status = status; 10217c478bd9Sstevel@tonic-gate i_hdlp->ahi_err->err_expected = flag; 1022*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fmhdl->fh_kstat.fek_acc_err.value.ui64); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate void 10267c478bd9Sstevel@tonic-gate i_ddi_fm_dma_err_set(ddi_dma_handle_t handle, uint64_t ena, int status, 10277c478bd9Sstevel@tonic-gate int flag) 10287c478bd9Sstevel@tonic-gate { 10297c478bd9Sstevel@tonic-gate ddi_dma_impl_t *hdlp = (ddi_dma_impl_t *)handle; 10307c478bd9Sstevel@tonic-gate struct i_ddi_fmhdl *fmhdl = DEVI(hdlp->dmai_rdip)->devi_fmhdl; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate hdlp->dmai_error.err_ena = ena; 10337c478bd9Sstevel@tonic-gate hdlp->dmai_error.err_status = status; 10347c478bd9Sstevel@tonic-gate hdlp->dmai_error.err_expected = flag; 1035*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fmhdl->fh_kstat.fek_dma_err.value.ui64); 10367c478bd9Sstevel@tonic-gate } 103700d0963fSdilpreet 103800d0963fSdilpreet ddi_fmcompare_t 103900d0963fSdilpreet i_ddi_fm_acc_err_cf_get(ddi_acc_handle_t handle) 104000d0963fSdilpreet { 104100d0963fSdilpreet ddi_acc_impl_t *i_hdlp = (ddi_acc_impl_t *)handle; 104200d0963fSdilpreet 104300d0963fSdilpreet return (i_hdlp->ahi_err->err_cf); 104400d0963fSdilpreet } 104500d0963fSdilpreet 104600d0963fSdilpreet ddi_fmcompare_t 104700d0963fSdilpreet i_ddi_fm_dma_err_cf_get(ddi_dma_handle_t handle) 104800d0963fSdilpreet { 104900d0963fSdilpreet ddi_dma_impl_t *hdlp = (ddi_dma_impl_t *)handle; 105000d0963fSdilpreet 105100d0963fSdilpreet return (hdlp->dmai_error.err_cf); 105200d0963fSdilpreet } 1053