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 (c) 2009-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 
  29 /*
  30  * Source file containing the implementation of fma support in driver
  31  *
  32  */
  33 
  34 #include <oce_impl.h>
  35 
  36 static int oce_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
  37     const void *impl_data);
  38 
  39 /*
  40  * function to initialize driver fma support
  41  *
  42  * dev - software handle to the device
  43  *
  44  * return none
  45  */
  46 
  47 void
  48 oce_fm_init(struct oce_dev *dev)
  49 {
  50         ddi_iblock_cookie_t ibc;
  51 
  52         if (dev->fm_caps == DDI_FM_NOT_CAPABLE) {
  53         return;
  54         }
  55 
  56         oce_set_dma_fma_flags(dev->fm_caps);
  57         oce_set_reg_fma_flags(dev->fm_caps);
  58 
  59         (void) ddi_fm_init(dev->dip, &dev->fm_caps, &ibc);
  60         if (DDI_FM_EREPORT_CAP(dev->fm_caps) ||
  61             DDI_FM_ERRCB_CAP(dev->fm_caps)) {
  62                 pci_ereport_setup(dev->dip);
  63         }
  64         if (DDI_FM_ERRCB_CAP(dev->fm_caps)) {
  65                 ddi_fm_handler_register(dev->dip, oce_fm_error_cb,
  66                     (void *)dev);
  67         }
  68 } /* oce_fm_init */
  69 
  70 /*
  71  * function to deinitialize driver fma support
  72  *
  73  * dev - software handle to the device
  74  *
  75  * return none
  76  */
  77 void
  78 oce_fm_fini(struct oce_dev *dev)
  79 {
  80         if (dev->fm_caps == DDI_FM_NOT_CAPABLE) {
  81                 return;
  82         }
  83         if (DDI_FM_ERRCB_CAP(dev->fm_caps)) {
  84                 ddi_fm_handler_unregister(dev->dip);
  85         }
  86         if (DDI_FM_EREPORT_CAP(dev->fm_caps) ||
  87             DDI_FM_ERRCB_CAP(dev->fm_caps)) {
  88                 pci_ereport_teardown(dev->dip);
  89         }
  90         (void) ddi_fm_fini(dev->dip);
  91 } /* oce_fm_fini */
  92 
  93 /*
  94  * function to check the access handle
  95  *
  96  * dev - software handle to the device
  97  * acc_handle - access handle
  98  *
  99  * return fm error status
 100  */
 101 int
 102 oce_fm_check_acc_handle(struct oce_dev *dev, ddi_acc_handle_t acc_handle)
 103 {
 104         ddi_fm_error_t fme;
 105 
 106 
 107         if (!DDI_FM_ACC_ERR_CAP(dev->fm_caps)) {
 108                 return (DDI_FM_OK);
 109         }
 110         (void) ddi_fm_acc_err_get(acc_handle, &fme, DDI_FME_VERSION);
 111         (void) ddi_fm_acc_err_clear(acc_handle, DDI_FME_VERSION);
 112 
 113         return (fme.fme_status);
 114 } /* oce_fm_chk_ach */
 115 
 116 /*
 117  * function to check error updates associated with a dma handle
 118  *
 119  * dev - software handle to the device
 120  * dma_handle - dma handle to the resources on which to check for errors
 121  *
 122  * return error code. DDI_FM_OK => no error
 123  */
 124 int
 125 oce_fm_check_dma_handle(struct oce_dev *dev, ddi_dma_handle_t dma_handle)
 126 {
 127         ddi_fm_error_t fme;
 128 
 129         if (!DDI_FM_DMA_ERR_CAP(dev->fm_caps)) {
 130                 return (DDI_FM_OK);
 131         }
 132 
 133         (void) ddi_fm_dma_err_get(dma_handle, &fme, DDI_FME_VERSION);
 134         return (fme.fme_status);
 135 } /* oce_fm_chk_dh */
 136 
 137 /*
 138  * function to report an error to the FMA framework
 139  *
 140  * dev - software handle to the device
 141  * detail - OS defined string that provides the kind of error to report
 142  */
 143 void
 144 oce_fm_ereport(struct oce_dev *dev, char *detail)
 145 {
 146         uint64_t ena;
 147         char buf[FM_MAX_CLASS];
 148 
 149         if (!DDI_FM_EREPORT_CAP(dev->fm_caps) || detail == NULL) {
 150                 return;
 151         }
 152         (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
 153         ena = fm_ena_generate(0, FM_ENA_FMT1);
 154         if (DDI_FM_EREPORT_CAP(dev->fm_caps)) {
 155                 ddi_fm_ereport_post(dev->dip, buf, ena, DDI_NOSLEEP,
 156                     FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
 157         }
 158 } /* oce_fm_ereport */
 159 
 160 /*
 161  * callback function registered with the FMA infrastructure. This callback is
 162  * called by the nexux driver if there is an error with the device
 163  *
 164  * dip - dev_info_t structure for this device
 165  * err - error information provided by the nexus
 166  * impl_data - callback data
 167  *
 168  * return error code. DDI_FM_OK => no error
 169  */
 170 static int
 171 oce_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
 172 {
 173         _NOTE(ARGUNUSED(impl_data));
 174         /* Driver must  handle the  dma/access error  */
 175         pci_ereport_post(dip, err, NULL);
 176         return (err->fme_status);
 177 }