1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2020 Joyent, Inc.
  14  */
  15 
  16 #ifndef _SYS_DDI_UFM_H
  17 #define _SYS_DDI_UFM_H
  18 
  19 #ifdef __cplusplus
  20 extern "C" {
  21 #endif
  22 
  23 #ifdef _KERNEL
  24 #include <sys/cred.h>
  25 #include <sys/dditypes.h>
  26 #include <sys/nvpair.h>
  27 #include <sys/param.h>
  28 #else
  29 #include <sys/nvpair.h>
  30 #include <sys/param.h>
  31 #include <sys/types.h>
  32 #endif /* _KERNEL */
  33 
  34 #define DDI_UFM_DEV             "/dev/ufm"
  35 #define DDI_UFM_CURRENT_VERSION 1
  36 #define DDI_UFM_VERSION_ONE     1
  37 
  38 #define UFM_IOC                 ('u' << 24) | ('f' << 16) | ('m' << 8)
  39 #define UFM_IOC_GETCAPS         (UFM_IOC | 1)
  40 #define UFM_IOC_REPORTSZ        (UFM_IOC | 2)
  41 #define UFM_IOC_REPORT          (UFM_IOC | 3)
  42 #define UFM_IOC_MAX             UFM_IOC_REPORT
  43 
  44 /*
  45  * Bitfield enumerating the DDI UFM capabilities supported by this device
  46  * instance.  Currently there is only a single capability of being able to
  47  * report UFM information.  Future UFM versions may add additional capabilities
  48  * such as the ability to obtain a raw dump the firmware image or ability to
  49  * upgrade the firmware.  When support for new capabilties are added to the DDI
  50  * UFM subsystem, it should be reflected in this enum and the implementation of
  51  * the UFM_IOC_GETCAPS should be extended appropriately.
  52  */
  53 typedef enum {
  54         DDI_UFM_CAP_REPORT      = 1 << 0
  55 } ddi_ufm_cap_t;
  56 
  57 /*
  58  * This struct defines the input/output data for the UFM_IOC_GETCAPS ioctl.
  59  * Callers should specify the ufmg_version and ufmg_devpath fields.  On success
  60  * the ufmg_caps field will be filled in with a value indicating the supported
  61  * UFM capabilities of the device specified in ufmg_devpath.
  62  */
  63 typedef struct ufm_ioc_getcaps {
  64         uint_t          ufmg_version;   /* DDI_UFM_VERSION */
  65         uint_t          ufmg_caps;      /* UFM Caps */
  66         char            ufmg_devpath[MAXPATHLEN];
  67 } ufm_ioc_getcaps_t;
  68 
  69 /*
  70  * This struct defines the input/output data for the UFM_IOC_REPORTSZ ioctl.
  71  * Callers should specify the ufbz_version and ufbz_devpath fields.  On success
  72  * the ufmg_size field will be filled in with the amount of space (in bytes)
  73  * required to hold the UFM data for this device instance.  This should be used
  74  * to allocate a sufficiently size buffer for the UFM_IOC_REPORT ioctl.
  75  */
  76 typedef struct ufm_ioc_bufsz {
  77         uint_t          ufbz_version;   /* DDI_UFM_VERSION */
  78         size_t          ufbz_size;      /* sz of buf to be returned by ioctl */
  79         char            ufbz_devpath[MAXPATHLEN];
  80 } ufm_ioc_bufsz_t;
  81 
  82 #ifdef _KERNEL
  83 typedef struct ufm_ioc_bufsz32 {
  84         uint_t          ufbz_version;
  85         size32_t        ufbz_size;
  86         char            ufbz_devpath[MAXPATHLEN];
  87 } ufm_ioc_bufsz32_t;
  88 #endif  /* _KERNEL */
  89 
  90 /*
  91  * This struct defines the input/output data for the UFM_IOC_REPORT ioctl.
  92  * Callers should specify the ufmr_version, ufmr_bufsz and ufmr_devpath fields.
  93  * On success, the ufmr_buf field will point to a packed nvlist containing the
  94  * UFM data for the specified device instance.  The value of ufmr_bufsz will be
  95  * updated to reflect the actual size of data copied out.
  96  */
  97 typedef struct ufm_ioc_report {
  98         uint_t          ufmr_version;   /* DDI_UFM_VERSION */
  99         size_t          ufmr_bufsz;     /* size of caller-supplied buffer */
 100         caddr_t         ufmr_buf;       /* buf to hold packed output nvl */
 101         char            ufmr_devpath[MAXPATHLEN];
 102 } ufm_ioc_report_t;
 103 
 104 #ifdef _KERNEL
 105 typedef struct ufm_ioc_report32 {
 106         uint_t          ufmr_version;
 107         size32_t        ufmr_bufsz;
 108         caddr32_t       ufmr_buf;
 109         char            ufmr_devpath[MAXPATHLEN];
 110 } ufm_ioc_report32_t;
 111 #endif  /* _KERNEL */
 112 
 113 /*
 114  * The UFM_IOC_REPORT ioctl return UFM image and slot data in the form of a
 115  * packed nvlist.  The nvlist contains and array of nvlists (one-per-image).
 116  * Each image nvlist contains will contain a string nvpair containing a
 117  * description of the image and an optional nvlist nvpair containing
 118  * miscellaneous image information.
 119  */
 120 #define DDI_UFM_NV_IMAGES               "ufm-images"
 121 #define DDI_UFM_NV_IMAGE_DESC           "ufm-image-description"
 122 #define DDI_UFM_NV_IMAGE_MISC           "ufm-image-misc"
 123 
 124 /*
 125  * Each image nvlist also contains an array of nvlists representing the slots.
 126  */
 127 #define DDI_UFM_NV_IMAGE_SLOTS          "ufm-image-slots"
 128 
 129 /*
 130  * Each slot nvlist as a string nvpair describing the firmware image version
 131  * and an uint32 nvpair describing the slot attributes (see ddi_ufm_attr_t
 132  * above).  An option nvlist nvpar may be present containing additional
 133  * miscellaneous slot data.
 134  */
 135 #define DDI_UFM_NV_SLOT_VERSION         "ufm-slot-version"
 136 
 137 typedef enum {
 138         DDI_UFM_ATTR_READABLE   = 1 << 0,
 139         DDI_UFM_ATTR_WRITEABLE  = 1 << 1,
 140         DDI_UFM_ATTR_ACTIVE     = 1 << 2,
 141         DDI_UFM_ATTR_EMPTY      = 1 << 3
 142 } ddi_ufm_attr_t;
 143 
 144 #define DDI_UFM_ATTR_MAX        DDI_UFM_ATTR_READABLE | \
 145                                 DDI_UFM_ATTR_WRITEABLE | \
 146                                 DDI_UFM_ATTR_ACTIVE | \
 147                                 DDI_UFM_ATTR_EMPTY
 148 
 149 #define DDI_UFM_NV_SLOT_ATTR            "ufm-slot-attributes"
 150 
 151 #define DDI_UFM_NV_SLOT_MISC            "ufm-slot-misc"
 152 
 153 #ifdef _KERNEL
 154 /* opaque structures */
 155 typedef struct ddi_ufm_handle ddi_ufm_handle_t;
 156 typedef struct ddi_ufm_image ddi_ufm_image_t;
 157 typedef struct ddi_ufm_slot ddi_ufm_slot_t;
 158 
 159 /*
 160  * DDI UFM Operations vector
 161  */
 162 typedef struct ddi_ufm_ops {
 163         int (*ddi_ufm_op_nimages)(ddi_ufm_handle_t *, void *, uint_t *);
 164         int (*ddi_ufm_op_fill_image)(ddi_ufm_handle_t *, void *, uint_t,
 165             ddi_ufm_image_t *);
 166         int (*ddi_ufm_op_fill_slot)(ddi_ufm_handle_t *, void *, uint_t, uint_t,
 167             ddi_ufm_slot_t *);
 168         int (*ddi_ufm_op_getcaps)(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *);
 169 } ddi_ufm_ops_t;
 170 
 171 /*
 172  * During a device driver's attach(9E) entry point, a device driver should
 173  * register with the UFM subsystem by filling out a UFM operations vector
 174  * (see above) and then calling ddi_ufm_init(9F).  The driver may pass in a
 175  * value, usually a pointer to its soft state pointer, which it will then
 176  * receive when its subsequent entry points are called.
 177  */
 178 int ddi_ufm_init(dev_info_t *, uint_t version, ddi_ufm_ops_t *,
 179     ddi_ufm_handle_t **, void *);
 180 
 181 /*
 182  * Device drivers should call ddi_ufm_update(9F) after driver initialization is
 183  * complete and after calling ddi_ufm_init(9F), in order to indicate to the
 184  * UFM subsystem that the driver is in a state where it is ready to receive
 185  * calls to its UFM entry points.
 186  *
 187  * Additionally, whenever the driver detects a change in the state of a UFM, it
 188  * should call ddi_ufm_update(9F).  This will cause the UFM subsystem to
 189  * invalidate any cached state regarding this driver's UFM(s)
 190  */
 191 void ddi_ufm_update(ddi_ufm_handle_t *);
 192 
 193 /*
 194  * A device driver should call ddi_ufm_fini(9F) during its detach(9E) entry
 195  * point.  Upon return, the driver is gaurunteed that no further DDI UFM entry
 196  * points will be called and thus any related state can be safely torn down.
 197  *
 198  * After return, the UFM handle is no longer valid and should not be used in
 199  * any future ddi_ufm_* calls.
 200  */
 201 void ddi_ufm_fini(ddi_ufm_handle_t *);
 202 
 203 /*
 204  * These interfaces should only be called within the context of a
 205  * ddi_ufm_op_fill_image callback.
 206  */
 207 void ddi_ufm_image_set_desc(ddi_ufm_image_t *, const char *);
 208 void ddi_ufm_image_set_nslots(ddi_ufm_image_t *, uint_t);
 209 void ddi_ufm_image_set_misc(ddi_ufm_image_t *, nvlist_t *);
 210 
 211 /*
 212  * These interfaces should only be called within the context of a
 213  * ddi_ufm_op_fill_slot callback.
 214  */
 215 void ddi_ufm_slot_set_version(ddi_ufm_slot_t *, const char *);
 216 void ddi_ufm_slot_set_attrs(ddi_ufm_slot_t *, ddi_ufm_attr_t);
 217 void ddi_ufm_slot_set_misc(ddi_ufm_slot_t *, nvlist_t *);
 218 #endif /* _KERNEL */
 219 
 220 #ifdef __cplusplus
 221 }
 222 #endif
 223 
 224 #endif  /* _SYS_DDI_UFM_H */