xref: /illumos-gate/usr/src/lib/libxpio/common/libxpio_dpio.c (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
1*fd71220bSRobert Mustacchi /*
2*fd71220bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*fd71220bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*fd71220bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*fd71220bSRobert Mustacchi  * 1.0 of the CDDL.
6*fd71220bSRobert Mustacchi  *
7*fd71220bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*fd71220bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*fd71220bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*fd71220bSRobert Mustacchi  */
11*fd71220bSRobert Mustacchi 
12*fd71220bSRobert Mustacchi /*
13*fd71220bSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
14*fd71220bSRobert Mustacchi  */
15*fd71220bSRobert Mustacchi 
16*fd71220bSRobert Mustacchi /*
17*fd71220bSRobert Mustacchi  * Dedicated Purpose I/O related routines
18*fd71220bSRobert Mustacchi  */
19*fd71220bSRobert Mustacchi 
20*fd71220bSRobert Mustacchi #include <unistd.h>
21*fd71220bSRobert Mustacchi #include <strings.h>
22*fd71220bSRobert Mustacchi #include <errno.h>
23*fd71220bSRobert Mustacchi #include <sys/types.h>
24*fd71220bSRobert Mustacchi #include <sys/stat.h>
25*fd71220bSRobert Mustacchi #include <fcntl.h>
26*fd71220bSRobert Mustacchi #include <sys/debug.h>
27*fd71220bSRobert Mustacchi 
28*fd71220bSRobert Mustacchi #include "libxpio_impl.h"
29*fd71220bSRobert Mustacchi 
30*fd71220bSRobert Mustacchi /*
31*fd71220bSRobert Mustacchi  * To avoid translation of flags we assume the kernel flags and our library
32*fd71220bSRobert Mustacchi  * flags are the same. The casts are required as that gets us the underlying
33*fd71220bSRobert Mustacchi  * enum's value in a way that a static assertion can handle.
34*fd71220bSRobert Mustacchi  */
35*fd71220bSRobert Mustacchi CTASSERT((uint32_t)XPIO_DPIO_F_READ == (uint32_t)KGPIO_DPIO_F_READ);
36*fd71220bSRobert Mustacchi CTASSERT((uint32_t)XPIO_DPIO_F_WRITE == (uint32_t)KGPIO_DPIO_F_WRITE);
37*fd71220bSRobert Mustacchi CTASSERT((uint32_t)XPIO_DPIO_F_KERNEL == (uint32_t)KGPIO_DPIO_F_KERNEL);
38*fd71220bSRobert Mustacchi 
39*fd71220bSRobert Mustacchi /*
40*fd71220bSRobert Mustacchi  * We do not have a /dev entry point for the dpinfo minor that we need to use to
41*fd71220bSRobert Mustacchi  * get information about DPIOs as this is private to the implementation. We
42*fd71220bSRobert Mustacchi  * therefore record it here.
43*fd71220bSRobert Mustacchi  */
44*fd71220bSRobert Mustacchi static const char *xpio_dpinfo_path = "/devices/pseudo/kgpio@0:dpinfo";
45*fd71220bSRobert Mustacchi 
46*fd71220bSRobert Mustacchi typedef struct {
47*fd71220bSRobert Mustacchi 	xpio_t *xdc_xpio;
48*fd71220bSRobert Mustacchi 	xpio_dpio_disc_f xdc_func;
49*fd71220bSRobert Mustacchi 	void *xdc_arg;
50*fd71220bSRobert Mustacchi } xpio_dpio_cb_t;
51*fd71220bSRobert Mustacchi 
52*fd71220bSRobert Mustacchi static int
xpio_dpio_discover_cb(di_node_t di,di_minor_t minor,void * arg)53*fd71220bSRobert Mustacchi xpio_dpio_discover_cb(di_node_t di, di_minor_t minor, void *arg)
54*fd71220bSRobert Mustacchi {
55*fd71220bSRobert Mustacchi 	bool ret;
56*fd71220bSRobert Mustacchi 	xpio_dpio_cb_t *cb = arg;
57*fd71220bSRobert Mustacchi 	xpio_dpio_disc_t disc;
58*fd71220bSRobert Mustacchi 
59*fd71220bSRobert Mustacchi 	disc.xdd_minor = minor;
60*fd71220bSRobert Mustacchi 
61*fd71220bSRobert Mustacchi 	ret = cb->xdc_func(cb->xdc_xpio, &disc, cb->xdc_arg);
62*fd71220bSRobert Mustacchi 	if (ret) {
63*fd71220bSRobert Mustacchi 		return (DI_WALK_CONTINUE);
64*fd71220bSRobert Mustacchi 	} else {
65*fd71220bSRobert Mustacchi 		return (DI_WALK_TERMINATE);
66*fd71220bSRobert Mustacchi 	}
67*fd71220bSRobert Mustacchi }
68*fd71220bSRobert Mustacchi 
69*fd71220bSRobert Mustacchi void
xpio_dpio_discover(xpio_t * xpio,xpio_dpio_disc_f func,void * arg)70*fd71220bSRobert Mustacchi xpio_dpio_discover(xpio_t *xpio, xpio_dpio_disc_f func, void *arg)
71*fd71220bSRobert Mustacchi {
72*fd71220bSRobert Mustacchi 	xpio_dpio_cb_t cb;
73*fd71220bSRobert Mustacchi 
74*fd71220bSRobert Mustacchi 	cb.xdc_xpio = xpio;
75*fd71220bSRobert Mustacchi 	cb.xdc_func = func;
76*fd71220bSRobert Mustacchi 	cb.xdc_arg = arg;
77*fd71220bSRobert Mustacchi 	(void) di_walk_minor(xpio->xp_devinfo, DDI_NT_GPIO_DPIO, 0, &cb,
78*fd71220bSRobert Mustacchi 	    xpio_dpio_discover_cb);
79*fd71220bSRobert Mustacchi }
80*fd71220bSRobert Mustacchi 
81*fd71220bSRobert Mustacchi void
xpio_dpio_info_free(xpio_dpio_info_t * info)82*fd71220bSRobert Mustacchi xpio_dpio_info_free(xpio_dpio_info_t *info)
83*fd71220bSRobert Mustacchi {
84*fd71220bSRobert Mustacchi 	free(info);
85*fd71220bSRobert Mustacchi }
86*fd71220bSRobert Mustacchi 
87*fd71220bSRobert Mustacchi const char *
xpio_dpio_info_ctrl(xpio_dpio_info_t * info)88*fd71220bSRobert Mustacchi xpio_dpio_info_ctrl(xpio_dpio_info_t *info)
89*fd71220bSRobert Mustacchi {
90*fd71220bSRobert Mustacchi 	return (info->xdi_ctrl);
91*fd71220bSRobert Mustacchi }
92*fd71220bSRobert Mustacchi 
93*fd71220bSRobert Mustacchi const char *
xpio_dpio_info_name(xpio_dpio_info_t * info)94*fd71220bSRobert Mustacchi xpio_dpio_info_name(xpio_dpio_info_t *info)
95*fd71220bSRobert Mustacchi {
96*fd71220bSRobert Mustacchi 	/*
97*fd71220bSRobert Mustacchi 	 * The raw minor name which is what we use to go to the kernel with
98*fd71220bSRobert Mustacchi 	 * includes a 'dpio:' prefix. However, that is not what users actually
99*fd71220bSRobert Mustacchi 	 * create and use, so strip that out of the returned name.
100*fd71220bSRobert Mustacchi 	 */
101*fd71220bSRobert Mustacchi 	return (info->xdi_dpio + 5);
102*fd71220bSRobert Mustacchi }
103*fd71220bSRobert Mustacchi 
104*fd71220bSRobert Mustacchi uint32_t
xpio_dpio_info_gpionum(xpio_dpio_info_t * info)105*fd71220bSRobert Mustacchi xpio_dpio_info_gpionum(xpio_dpio_info_t *info)
106*fd71220bSRobert Mustacchi {
107*fd71220bSRobert Mustacchi 	return (info->xdi_gpio);
108*fd71220bSRobert Mustacchi }
109*fd71220bSRobert Mustacchi 
110*fd71220bSRobert Mustacchi dpio_caps_t
xpio_dpio_info_caps(xpio_dpio_info_t * info)111*fd71220bSRobert Mustacchi xpio_dpio_info_caps(xpio_dpio_info_t *info)
112*fd71220bSRobert Mustacchi {
113*fd71220bSRobert Mustacchi 	return (info->xdi_caps);
114*fd71220bSRobert Mustacchi }
115*fd71220bSRobert Mustacchi 
116*fd71220bSRobert Mustacchi dpio_flags_t
xpio_dpio_info_flags(xpio_dpio_info_t * info)117*fd71220bSRobert Mustacchi xpio_dpio_info_flags(xpio_dpio_info_t *info)
118*fd71220bSRobert Mustacchi {
119*fd71220bSRobert Mustacchi 	return (info->xdi_flags);
120*fd71220bSRobert Mustacchi }
121*fd71220bSRobert Mustacchi 
122*fd71220bSRobert Mustacchi bool
xpio_dpio_info(xpio_t * xpio,di_minor_t minor,xpio_dpio_info_t ** outp)123*fd71220bSRobert Mustacchi xpio_dpio_info(xpio_t *xpio, di_minor_t minor, xpio_dpio_info_t **outp)
124*fd71220bSRobert Mustacchi {
125*fd71220bSRobert Mustacchi 	int fd = -1;
126*fd71220bSRobert Mustacchi 	xpio_dpio_info_t *info = NULL;
127*fd71220bSRobert Mustacchi 	dpio_info_t dpi;
128*fd71220bSRobert Mustacchi 
129*fd71220bSRobert Mustacchi 	if (minor == DI_NODE_NIL) {
130*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
131*fd71220bSRobert Mustacchi 		    "invalid di_minor_t: %p", minor));
132*fd71220bSRobert Mustacchi 	}
133*fd71220bSRobert Mustacchi 
134*fd71220bSRobert Mustacchi 	if (outp == NULL) {
135*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
136*fd71220bSRobert Mustacchi 		    "invalid xpio_ctrl_t output pointer: %p", outp));
137*fd71220bSRobert Mustacchi 	}
138*fd71220bSRobert Mustacchi 	*outp = NULL;
139*fd71220bSRobert Mustacchi 
140*fd71220bSRobert Mustacchi 	if (strcmp(di_minor_nodetype(minor), DDI_NT_GPIO_DPIO) != 0) {
141*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_WRONG_MINOR_TYPE, 0,
142*fd71220bSRobert Mustacchi 		    "minor %s has incorrect node type: %s, expected %s",
143*fd71220bSRobert Mustacchi 		    di_minor_name(minor), di_minor_nodetype(minor),
144*fd71220bSRobert Mustacchi 		    DDI_NT_GPIO_DPIO));
145*fd71220bSRobert Mustacchi 	}
146*fd71220bSRobert Mustacchi 
147*fd71220bSRobert Mustacchi 	if ((fd = open(xpio_dpinfo_path, O_RDONLY)) < 0) {
148*fd71220bSRobert Mustacchi 		int e = errno;
149*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_OPEN_DEV, e, "failed to open "
150*fd71220bSRobert Mustacchi 		    "DPIO information minor: %s", strerror(e)));
151*fd71220bSRobert Mustacchi 	}
152*fd71220bSRobert Mustacchi 
153*fd71220bSRobert Mustacchi 	info = calloc(1, sizeof (xpio_dpio_info_t));
154*fd71220bSRobert Mustacchi 	if (info == NULL) {
155*fd71220bSRobert Mustacchi 		int e = errno;
156*fd71220bSRobert Mustacchi 		(void) xpio_error(xpio, XPIO_ERR_NO_MEM, e, "failed to "
157*fd71220bSRobert Mustacchi 		    "allocate memory for a xpio_dpio_info_t: %s", strerror(e));
158*fd71220bSRobert Mustacchi 		goto err;
159*fd71220bSRobert Mustacchi 	}
160*fd71220bSRobert Mustacchi 
161*fd71220bSRobert Mustacchi 	(void) memset(&dpi, 0, sizeof (dpi));
162*fd71220bSRobert Mustacchi 	if (strlcpy(dpi.dpi_dpio, di_minor_name(minor),
163*fd71220bSRobert Mustacchi 	    sizeof (dpi.dpi_dpio)) >= sizeof (dpi.dpi_dpio)) {
164*fd71220bSRobert Mustacchi 		(void) xpio_error(xpio, XPIO_ERR_INTERNAL, 0, "DPIO name "
165*fd71220bSRobert Mustacchi 		    "somehow exceeded expected system length");
166*fd71220bSRobert Mustacchi 		goto err;
167*fd71220bSRobert Mustacchi 	}
168*fd71220bSRobert Mustacchi 
169*fd71220bSRobert Mustacchi 	if (ioctl(fd, DPIO_IOC_INFO, &dpi) != 0) {
170*fd71220bSRobert Mustacchi 		int e = errno;
171*fd71220bSRobert Mustacchi 		switch (e) {
172*fd71220bSRobert Mustacchi 		case ENOENT:
173*fd71220bSRobert Mustacchi 			(void) xpio_error(xpio, XPIO_ERR_BAD_DPIO_NAME, 0,
174*fd71220bSRobert Mustacchi 			    "DPIO %s does not exist", di_minor_name(minor));
175*fd71220bSRobert Mustacchi 			goto err;
176*fd71220bSRobert Mustacchi 		case EFAULT:
177*fd71220bSRobert Mustacchi 			abort();
178*fd71220bSRobert Mustacchi 		default:
179*fd71220bSRobert Mustacchi 			(void) xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to "
180*fd71220bSRobert Mustacchi 			    "issue dpio information ioctl for dpio %s: %s",
181*fd71220bSRobert Mustacchi 			    di_minor_name(minor), strerror(e));
182*fd71220bSRobert Mustacchi 
183*fd71220bSRobert Mustacchi 			goto err;
184*fd71220bSRobert Mustacchi 		}
185*fd71220bSRobert Mustacchi 	}
186*fd71220bSRobert Mustacchi 
187*fd71220bSRobert Mustacchi 	(void) memcpy(info->xdi_dpio, dpi.dpi_dpio, sizeof (dpi.dpi_dpio));
188*fd71220bSRobert Mustacchi 	(void) memcpy(info->xdi_ctrl, dpi.dpi_ctrl, sizeof (dpi.dpi_ctrl));
189*fd71220bSRobert Mustacchi 	info->xdi_gpio = dpi.dpi_gpio;
190*fd71220bSRobert Mustacchi 	info->xdi_caps = dpi.dpi_caps;
191*fd71220bSRobert Mustacchi 	info->xdi_flags = dpi.dpi_flags;
192*fd71220bSRobert Mustacchi 
193*fd71220bSRobert Mustacchi 	(void) close(fd);
194*fd71220bSRobert Mustacchi 	*outp = info;
195*fd71220bSRobert Mustacchi 	return (xpio_success(xpio));
196*fd71220bSRobert Mustacchi 
197*fd71220bSRobert Mustacchi err:
198*fd71220bSRobert Mustacchi 	if (fd >= 0) {
199*fd71220bSRobert Mustacchi 		(void) close(fd);
200*fd71220bSRobert Mustacchi 	}
201*fd71220bSRobert Mustacchi 	free(info);
202*fd71220bSRobert Mustacchi 	return (false);
203*fd71220bSRobert Mustacchi }
204*fd71220bSRobert Mustacchi 
205*fd71220bSRobert Mustacchi bool
xpio_dpio_create(xpio_ctrl_t * ctrl,xpio_gpio_info_t * gi,const char * name,xpio_dpio_features_t feat)206*fd71220bSRobert Mustacchi xpio_dpio_create(xpio_ctrl_t *ctrl, xpio_gpio_info_t *gi, const char *name,
207*fd71220bSRobert Mustacchi     xpio_dpio_features_t feat)
208*fd71220bSRobert Mustacchi {
209*fd71220bSRobert Mustacchi 	kgpio_dpio_create_t create;
210*fd71220bSRobert Mustacchi 	xpio_t *xpio = ctrl->xc_xpio;
211*fd71220bSRobert Mustacchi 	const uint32_t all_feats = XPIO_DPIO_F_READ | XPIO_DPIO_F_WRITE |
212*fd71220bSRobert Mustacchi 	    XPIO_DPIO_F_KERNEL;
213*fd71220bSRobert Mustacchi 
214*fd71220bSRobert Mustacchi 	if (gi == NULL) {
215*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
216*fd71220bSRobert Mustacchi 		    "invalid xpio_gpio_info_t pointer: %p", gi));
217*fd71220bSRobert Mustacchi 	}
218*fd71220bSRobert Mustacchi 
219*fd71220bSRobert Mustacchi 	if (name == NULL) {
220*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
221*fd71220bSRobert Mustacchi 		    "invalid pointer for DPIO name: %p", name));
222*fd71220bSRobert Mustacchi 	}
223*fd71220bSRobert Mustacchi 
224*fd71220bSRobert Mustacchi 	if ((feat & ~all_feats) != 0) {
225*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_DPIO_FEAT, 0, "found "
226*fd71220bSRobert Mustacchi 		    "unknown dpio features specified: 0x%x",
227*fd71220bSRobert Mustacchi 		    feat & ~all_feats));
228*fd71220bSRobert Mustacchi 	}
229*fd71220bSRobert Mustacchi 
230*fd71220bSRobert Mustacchi 	(void) memset(&create, 0, sizeof (create));
231*fd71220bSRobert Mustacchi 	if (strlcpy(create.kdc_name, name, sizeof (create.kdc_name)) >=
232*fd71220bSRobert Mustacchi 	    sizeof (create.kdc_name)) {
233*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_DPIO_NAME, 0,
234*fd71220bSRobert Mustacchi 		    "requested DPIO name is longer than the maximum supported "
235*fd71220bSRobert Mustacchi 		    "(%zu characters including '\\0')",
236*fd71220bSRobert Mustacchi 		    sizeof (create.kdc_name)));
237*fd71220bSRobert Mustacchi 	}
238*fd71220bSRobert Mustacchi 
239*fd71220bSRobert Mustacchi 	/*
240*fd71220bSRobert Mustacchi 	 * Right now there is a 1:1 mapping between library and kgpio features.
241*fd71220bSRobert Mustacchi 	 */
242*fd71220bSRobert Mustacchi 	create.kdc_flags = (kgpio_dpio_flags_t)feat;
243*fd71220bSRobert Mustacchi 	create.kdc_id = gi->xgi_id;
244*fd71220bSRobert Mustacchi 
245*fd71220bSRobert Mustacchi 	/*
246*fd71220bSRobert Mustacchi 	 * At some point it'd be good for us to take this apart and create much
247*fd71220bSRobert Mustacchi 	 * more useful semantic errors rather than this generic error as it
248*fd71220bSRobert Mustacchi 	 * basically requires someone to go into the code to figure out what
249*fd71220bSRobert Mustacchi 	 * happened. Basically, we want something like with update.
250*fd71220bSRobert Mustacchi 	 */
251*fd71220bSRobert Mustacchi 	if (ioctl(ctrl->xc_fd, KGPIO_IOC_DPIO_CREATE, &create) != 0) {
252*fd71220bSRobert Mustacchi 		int e = errno;
253*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to create "
254*fd71220bSRobert Mustacchi 		    "dpio %s: %s", name, strerror(e)));
255*fd71220bSRobert Mustacchi 	}
256*fd71220bSRobert Mustacchi 
257*fd71220bSRobert Mustacchi 	return (xpio_success(xpio));
258*fd71220bSRobert Mustacchi }
259*fd71220bSRobert Mustacchi 
260*fd71220bSRobert Mustacchi bool
xpio_dpio_destroy(xpio_ctrl_t * ctrl,xpio_gpio_info_t * gi)261*fd71220bSRobert Mustacchi xpio_dpio_destroy(xpio_ctrl_t *ctrl, xpio_gpio_info_t *gi)
262*fd71220bSRobert Mustacchi {
263*fd71220bSRobert Mustacchi 	kgpio_dpio_destroy_t destroy;
264*fd71220bSRobert Mustacchi 	xpio_t *xpio = ctrl->xc_xpio;
265*fd71220bSRobert Mustacchi 
266*fd71220bSRobert Mustacchi 	if (gi == NULL) {
267*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_BAD_PTR, 0, "encountered "
268*fd71220bSRobert Mustacchi 		    "invalid xpio_gpio_info_t pointer: %p", gi));
269*fd71220bSRobert Mustacchi 	}
270*fd71220bSRobert Mustacchi 
271*fd71220bSRobert Mustacchi 	destroy.kdd_id = gi->xgi_id;
272*fd71220bSRobert Mustacchi 
273*fd71220bSRobert Mustacchi 
274*fd71220bSRobert Mustacchi 	/*
275*fd71220bSRobert Mustacchi 	 * At some point it'd be good for us to take this apart and create much
276*fd71220bSRobert Mustacchi 	 * more useful semantic errors rather than this generic error as it
277*fd71220bSRobert Mustacchi 	 * basically requires someone to go into the code to figure out what
278*fd71220bSRobert Mustacchi 	 * happened. Basically, we want something like with update.
279*fd71220bSRobert Mustacchi 	 */
280*fd71220bSRobert Mustacchi 	if (ioctl(ctrl->xc_fd, KGPIO_IOC_DPIO_DESTROY, &destroy) != 0) {
281*fd71220bSRobert Mustacchi 		int e = errno;
282*fd71220bSRobert Mustacchi 		return (xpio_error(xpio, XPIO_ERR_KGPIO, e, "failed to destroy "
283*fd71220bSRobert Mustacchi 		    "dpio %s/%u: %s", ctrl->xc_name, gi->xgi_id, strerror(e)));
284*fd71220bSRobert Mustacchi 	}
285*fd71220bSRobert Mustacchi 	return (xpio_success(xpio));
286*fd71220bSRobert Mustacchi }
287