/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2020 Joyent, Inc. * Copyright 2020 Oxide Computer Company */ #ifndef _SYS_DDI_UFM_H #define _SYS_DDI_UFM_H #ifdef __cplusplus extern "C" { #endif #ifdef _KERNEL #include <sys/cred.h> #include <sys/dditypes.h> #include <sys/nvpair.h> #include <sys/param.h> #else #include <sys/nvpair.h> #include <sys/param.h> #include <sys/types.h> #endif /* _KERNEL */ #define DDI_UFM_DEV "/dev/ufm" #define DDI_UFM_CURRENT_VERSION 1 #define DDI_UFM_VERSION_ONE 1 #define UFM_IOC ('u' << 24) | ('f' << 16) | ('m' << 8) #define UFM_IOC_GETCAPS (UFM_IOC | 1) #define UFM_IOC_REPORTSZ (UFM_IOC | 2) #define UFM_IOC_REPORT (UFM_IOC | 3) #define UFM_IOC_READIMG (UFM_IOC | 4) #define UFM_IOC_MAX UFM_IOC_REPORT /* * Bitfield enumerating the DDI UFM capabilities supported by this device * instance. Currently there is only a single capability of being able to * report UFM information. When support for new capabilties are added to the * DDI UFM subsystem, it should be reflected in this enum and the implementation * of the UFM_IOC_GETCAPS should be extended appropriately. */ typedef enum { DDI_UFM_CAP_REPORT = 1 << 0, DDI_UFM_CAP_READIMG = 1 << 1 } ddi_ufm_cap_t; /* * This struct defines the input/output data for the UFM_IOC_GETCAPS ioctl. * Callers should specify the ufmg_version and ufmg_devpath fields. On success * the ufmg_caps field will be filled in with a value indicating the supported * UFM capabilities of the device specified in ufmg_devpath. */ typedef struct ufm_ioc_getcaps { uint_t ufmg_version; /* DDI_UFM_VERSION */ uint_t ufmg_caps; /* UFM Caps */ char ufmg_devpath[MAXPATHLEN]; } ufm_ioc_getcaps_t; /* * This struct defines the input/output data for the UFM_IOC_REPORTSZ ioctl. * Callers should specify the ufbz_version and ufbz_devpath fields. On success * the ufmg_size field will be filled in with the amount of space (in bytes) * required to hold the UFM data for this device instance. This should be used * to allocate a sufficiently size buffer for the UFM_IOC_REPORT ioctl. */ typedef struct ufm_ioc_bufsz { uint_t ufbz_version; /* DDI_UFM_VERSION */ size_t ufbz_size; /* sz of buf to be returned by ioctl */ char ufbz_devpath[MAXPATHLEN]; } ufm_ioc_bufsz_t; #ifdef _KERNEL typedef struct ufm_ioc_bufsz32 { uint_t ufbz_version; size32_t ufbz_size; char ufbz_devpath[MAXPATHLEN]; } ufm_ioc_bufsz32_t; #endif /* _KERNEL */ /* * This struct defines the input/output data for the UFM_IOC_REPORT ioctl. * Callers should specify the ufmr_version, ufmr_bufsz and ufmr_devpath fields. * On success, the ufmr_buf field will point to a packed nvlist containing the * UFM data for the specified device instance. The value of ufmr_bufsz will be * updated to reflect the actual size of data copied out. */ typedef struct ufm_ioc_report { uint_t ufmr_version; /* DDI_UFM_VERSION */ size_t ufmr_bufsz; /* size of caller-supplied buffer */ caddr_t ufmr_buf; /* buf to hold packed output nvl */ char ufmr_devpath[MAXPATHLEN]; } ufm_ioc_report_t; #ifdef _KERNEL typedef struct ufm_ioc_report32 { uint_t ufmr_version; size32_t ufmr_bufsz; caddr32_t ufmr_buf; char ufmr_devpath[MAXPATHLEN]; } ufm_ioc_report32_t; #endif /* _KERNEL */ /* * This struct defines the input/output data for the UFM_IOC_READ ioctl, which * reads the firmware image from a given slot. */ typedef struct ufm_ioc_readimg { uint_t ufri_version; uint_t ufri_imageno; uint_t ufri_slotno; uint64_t ufri_offset; uint64_t ufri_len; uint64_t ufri_nread; void *ufri_buf; char ufri_devpath[MAXPATHLEN]; } ufm_ioc_readimg_t; #ifdef _KERNEL #pragma pack(4) typedef struct ufm_ioc_readimg32 { uint_t ufri_version; uint_t ufri_imageno; uint_t ufri_slotno; uint64_t ufri_offset; uint64_t ufri_len; uint64_t ufri_nread; caddr32_t ufri_buf; char ufri_devpath[MAXPATHLEN]; } ufm_ioc_readimg32_t; #pragma pack() #endif /* _KERNEL */ /* * The UFM_IOC_REPORT ioctl return UFM image and slot data in the form of a * packed nvlist. The nvlist contains and array of nvlists (one-per-image). * Each image nvlist contains will contain a string nvpair containing a * description of the image and an optional nvlist nvpair containing * miscellaneous image information. */ #define DDI_UFM_NV_IMAGES "ufm-images" #define DDI_UFM_NV_IMAGE_DESC "ufm-image-description" #define DDI_UFM_NV_IMAGE_MISC "ufm-image-misc" /* * Each image nvlist also contains an array of nvlists representing the slots. */ #define DDI_UFM_NV_IMAGE_SLOTS "ufm-image-slots" /* * Each slot nvlist has the following: * * o A string nvpair describing the firmware image version * o A uint32 nvpair describing the slot attributes (see ddi_ufm_attr_t * below). * o An optional nvlist nvpar may be present containing additional * miscellaneous slot data. * o An optional uint64 slot length that indicates the size of the image in * that slot. Note htis is the size of the image, not the size of the slot. */ #define DDI_UFM_NV_SLOT_VERSION "ufm-slot-version" #define DDI_UFM_NV_SLOT_IMGSIZE "ufm-slot-imgsize" typedef enum { DDI_UFM_ATTR_READABLE = 1 << 0, DDI_UFM_ATTR_WRITEABLE = 1 << 1, DDI_UFM_ATTR_ACTIVE = 1 << 2, DDI_UFM_ATTR_EMPTY = 1 << 3 } ddi_ufm_attr_t; #define DDI_UFM_ATTR_MAX DDI_UFM_ATTR_READABLE | \ DDI_UFM_ATTR_WRITEABLE | \ DDI_UFM_ATTR_ACTIVE | \ DDI_UFM_ATTR_EMPTY #define DDI_UFM_NV_SLOT_ATTR "ufm-slot-attributes" #define DDI_UFM_NV_SLOT_MISC "ufm-slot-misc" #ifdef _KERNEL /* opaque structures */ typedef struct ddi_ufm_handle ddi_ufm_handle_t; typedef struct ddi_ufm_image ddi_ufm_image_t; typedef struct ddi_ufm_slot ddi_ufm_slot_t; /* * DDI UFM Operations vector */ typedef struct ddi_ufm_ops { int (*ddi_ufm_op_nimages)(ddi_ufm_handle_t *, void *, uint_t *); int (*ddi_ufm_op_fill_image)(ddi_ufm_handle_t *, void *, uint_t, ddi_ufm_image_t *); int (*ddi_ufm_op_fill_slot)(ddi_ufm_handle_t *, void *, uint_t, uint_t, ddi_ufm_slot_t *); int (*ddi_ufm_op_getcaps)(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *); int (*ddi_ufm_op_readimg)(ddi_ufm_handle_t *, void *, uint_t, uint_t, uint64_t, uint64_t, void *, uint64_t *); } ddi_ufm_ops_t; /* * During a device driver's attach(9E) entry point, a device driver should * register with the UFM subsystem by filling out a UFM operations vector * (see above) and then calling ddi_ufm_init(9F). The driver may pass in a * value, usually a pointer to its soft state pointer, which it will then * receive when its subsequent entry points are called. */ int ddi_ufm_init(dev_info_t *, uint_t version, ddi_ufm_ops_t *, ddi_ufm_handle_t **, void *); /* * Device drivers should call ddi_ufm_update(9F) after driver initialization is * complete and after calling ddi_ufm_init(9F), in order to indicate to the * UFM subsystem that the driver is in a state where it is ready to receive * calls to its UFM entry points. * * Additionally, whenever the driver detects a change in the state of a UFM, it * should call ddi_ufm_update(9F). This will cause the UFM subsystem to * invalidate any cached state regarding this driver's UFM(s) */ void ddi_ufm_update(ddi_ufm_handle_t *); /* * A device driver should call ddi_ufm_fini(9F) during its detach(9E) entry * point. Upon return, the driver is gaurunteed that no further DDI UFM entry * points will be called and thus any related state can be safely torn down. * * After return, the UFM handle is no longer valid and should not be used in * any future ddi_ufm_* calls. */ void ddi_ufm_fini(ddi_ufm_handle_t *); /* * These interfaces should only be called within the context of a * ddi_ufm_op_fill_image callback. */ void ddi_ufm_image_set_desc(ddi_ufm_image_t *, const char *); void ddi_ufm_image_set_nslots(ddi_ufm_image_t *, uint_t); void ddi_ufm_image_set_misc(ddi_ufm_image_t *, nvlist_t *); /* * These interfaces should only be called within the context of a * ddi_ufm_op_fill_slot callback. */ void ddi_ufm_slot_set_version(ddi_ufm_slot_t *, const char *); void ddi_ufm_slot_set_attrs(ddi_ufm_slot_t *, ddi_ufm_attr_t); void ddi_ufm_slot_set_misc(ddi_ufm_slot_t *, nvlist_t *); void ddi_ufm_slot_set_imgsize(ddi_ufm_slot_t *, uint64_t); #endif /* _KERNEL */ #ifdef __cplusplus } #endif #endif /* _SYS_DDI_UFM_H */