xref: /illumos-gate/usr/src/uts/common/sys/ddi_ufm.h (revision 8d55b806)
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