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