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