1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Source file containing the implementation of fma support in driver 29 * 30 */ 31 32 #include <oce_impl.h> 33 34 static int oce_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 35 const void *impl_data); 36 37 /* 38 * function to initialize driver fma support 39 * 40 * dev - software handle to the device 41 * 42 * return none 43 */ 44 45 void 46 oce_fm_init(struct oce_dev *dev) 47 { 48 ddi_iblock_cookie_t ibc; 49 50 if (dev->fm_caps == DDI_FM_NOT_CAPABLE) { 51 return; 52 } 53 54 oce_set_dma_fma_flags(dev->fm_caps); 55 oce_set_reg_fma_flags(dev->fm_caps); 56 oce_set_tx_map_dma_fma_flags(dev->fm_caps); 57 58 (void) ddi_fm_init(dev->dip, &dev->fm_caps, &ibc); 59 if (DDI_FM_EREPORT_CAP(dev->fm_caps) || 60 DDI_FM_ERRCB_CAP(dev->fm_caps)) { 61 pci_ereport_setup(dev->dip); 62 } 63 if (DDI_FM_ERRCB_CAP(dev->fm_caps)) { 64 ddi_fm_handler_register(dev->dip, oce_fm_error_cb, 65 (void *)dev); 66 } 67 } /* oce_fm_init */ 68 69 /* 70 * function to deinitialize driver fma support 71 * 72 * dev - software handle to the device 73 * 74 * return none 75 */ 76 void 77 oce_fm_fini(struct oce_dev *dev) 78 { 79 if (dev->fm_caps == DDI_FM_NOT_CAPABLE) { 80 return; 81 } 82 if (DDI_FM_ERRCB_CAP(dev->fm_caps)) { 83 ddi_fm_handler_unregister(dev->dip); 84 } 85 if (DDI_FM_EREPORT_CAP(dev->fm_caps) || 86 DDI_FM_ERRCB_CAP(dev->fm_caps)) { 87 pci_ereport_teardown(dev->dip); 88 } 89 (void) ddi_fm_fini(dev->dip); 90 } /* oce_fm_fini */ 91 92 /* 93 * function to check the access handle 94 * 95 * dev - software handle to the device 96 * acc_handle - access handle 97 * 98 * return fm error status 99 */ 100 int 101 oce_fm_check_acc_handle(struct oce_dev *dev, ddi_acc_handle_t acc_handle) 102 { 103 ddi_fm_error_t fme; 104 105 if (!DDI_FM_ACC_ERR_CAP(dev->fm_caps)) { 106 return (DDI_FM_OK); 107 } 108 (void) ddi_fm_acc_err_get(acc_handle, &fme, DDI_FME_VERSION); 109 (void) ddi_fm_acc_err_clear(acc_handle, DDI_FME_VERSION); 110 111 return (fme.fme_status); 112 } /* oce_fm_chk_ach */ 113 114 /* 115 * function to check error updates associated with a dma handle 116 * 117 * dev - software handle to the device 118 * dma_handle - dma handle to the resources on which to check for errors 119 * 120 * return error code. DDI_FM_OK => no error 121 */ 122 int 123 oce_fm_check_dma_handle(struct oce_dev *dev, ddi_dma_handle_t dma_handle) 124 { 125 ddi_fm_error_t fme; 126 127 if (!DDI_FM_DMA_ERR_CAP(dev->fm_caps)) { 128 return (DDI_FM_OK); 129 } 130 131 (void) ddi_fm_dma_err_get(dma_handle, &fme, DDI_FME_VERSION); 132 return (fme.fme_status); 133 } /* oce_fm_chk_dh */ 134 135 /* 136 * function to report an error to the FMA framework 137 * 138 * dev - software handle to the device 139 * detail - OS defined string that provides the kind of error to report 140 */ 141 void 142 oce_fm_ereport(struct oce_dev *dev, char *detail) 143 { 144 uint64_t ena; 145 char buf[FM_MAX_CLASS]; 146 147 if (!DDI_FM_EREPORT_CAP(dev->fm_caps) || detail == NULL) { 148 return; 149 } 150 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 151 ena = fm_ena_generate(0, FM_ENA_FMT1); 152 if (DDI_FM_EREPORT_CAP(dev->fm_caps)) { 153 ddi_fm_ereport_post(dev->dip, buf, ena, DDI_NOSLEEP, 154 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 155 } 156 } /* oce_fm_ereport */ 157 158 /* 159 * callback function registered with the FMA infrastructure. This callback is 160 * called by the nexux driver if there is an error with the device 161 * 162 * dip - dev_info_t structure for this device 163 * err - error information provided by the nexus 164 * impl_data - callback data 165 * 166 * return error code. DDI_FM_OK => no error 167 */ 168 static int 169 oce_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 170 { 171 _NOTE(ARGUNUSED(impl_data)); 172 /* Driver must handle the dma/access error */ 173 pci_ereport_post(dip, err, NULL); 174 return (err->fme_status); 175 } 176