xref: /illumos-gate/usr/src/uts/intel/io/amdzen/zen_udf.c (revision 71815ce7)
1549e0fd3SRobert Mustacchi /*
2549e0fd3SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3549e0fd3SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4549e0fd3SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5549e0fd3SRobert Mustacchi  * 1.0 of the CDDL.
6549e0fd3SRobert Mustacchi  *
7549e0fd3SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8549e0fd3SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9549e0fd3SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10549e0fd3SRobert Mustacchi  */
11549e0fd3SRobert Mustacchi 
12549e0fd3SRobert Mustacchi /*
13*71815ce7SRobert Mustacchi  * Copyright 2022 Oxide Computer Company
14549e0fd3SRobert Mustacchi  */
15549e0fd3SRobert Mustacchi 
16549e0fd3SRobert Mustacchi /*
17bbf21555SRichard Lowe  * A companion to zen_udf(4D) that allows user access to read the data fabric
18549e0fd3SRobert Mustacchi  * for development purposes.
19549e0fd3SRobert Mustacchi  */
20549e0fd3SRobert Mustacchi 
21549e0fd3SRobert Mustacchi #include <sys/types.h>
22549e0fd3SRobert Mustacchi #include <sys/file.h>
23549e0fd3SRobert Mustacchi #include <sys/errno.h>
24549e0fd3SRobert Mustacchi #include <sys/open.h>
25549e0fd3SRobert Mustacchi #include <sys/cred.h>
26549e0fd3SRobert Mustacchi #include <sys/ddi.h>
27549e0fd3SRobert Mustacchi #include <sys/sunddi.h>
28549e0fd3SRobert Mustacchi #include <sys/stat.h>
29549e0fd3SRobert Mustacchi #include <sys/conf.h>
30549e0fd3SRobert Mustacchi #include <sys/devops.h>
31549e0fd3SRobert Mustacchi #include <sys/cmn_err.h>
32549e0fd3SRobert Mustacchi #include <sys/policy.h>
33549e0fd3SRobert Mustacchi #include <amdzen_client.h>
34549e0fd3SRobert Mustacchi 
35549e0fd3SRobert Mustacchi #include <zen_udf.h>
36549e0fd3SRobert Mustacchi 
37549e0fd3SRobert Mustacchi typedef struct zen_udf {
38549e0fd3SRobert Mustacchi 	dev_info_t *zudf_dip;
39549e0fd3SRobert Mustacchi 	uint_t zudf_ndfs;
40549e0fd3SRobert Mustacchi } zen_udf_t;
41549e0fd3SRobert Mustacchi 
42549e0fd3SRobert Mustacchi static zen_udf_t zen_udf_data;
43549e0fd3SRobert Mustacchi 
44549e0fd3SRobert Mustacchi static int
zen_udf_open(dev_t * devp,int flags,int otype,cred_t * credp)45549e0fd3SRobert Mustacchi zen_udf_open(dev_t *devp, int flags, int otype, cred_t *credp)
46549e0fd3SRobert Mustacchi {
47549e0fd3SRobert Mustacchi 	minor_t m;
48549e0fd3SRobert Mustacchi 	zen_udf_t *zen_udf = &zen_udf_data;
49549e0fd3SRobert Mustacchi 
50549e0fd3SRobert Mustacchi 	if (crgetzoneid(credp) != GLOBAL_ZONEID ||
51549e0fd3SRobert Mustacchi 	    secpolicy_hwmanip(credp) != 0) {
52549e0fd3SRobert Mustacchi 		return (EPERM);
53549e0fd3SRobert Mustacchi 	}
54549e0fd3SRobert Mustacchi 
55549e0fd3SRobert Mustacchi 	if ((flags & (FEXCL | FNDELAY | FNONBLOCK)) != 0) {
56549e0fd3SRobert Mustacchi 		return (EINVAL);
57549e0fd3SRobert Mustacchi 	}
58549e0fd3SRobert Mustacchi 
59549e0fd3SRobert Mustacchi 	if (otype != OTYP_CHR) {
60549e0fd3SRobert Mustacchi 		return (EINVAL);
61549e0fd3SRobert Mustacchi 	}
62549e0fd3SRobert Mustacchi 
63549e0fd3SRobert Mustacchi 	m = getminor(*devp);
64549e0fd3SRobert Mustacchi 	if (m >= zen_udf->zudf_ndfs) {
65549e0fd3SRobert Mustacchi 		return (ENXIO);
66549e0fd3SRobert Mustacchi 	}
67549e0fd3SRobert Mustacchi 
68549e0fd3SRobert Mustacchi 	return (0);
69549e0fd3SRobert Mustacchi }
70549e0fd3SRobert Mustacchi 
71549e0fd3SRobert Mustacchi static int
zen_udf_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)72549e0fd3SRobert Mustacchi zen_udf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
73549e0fd3SRobert Mustacchi     int *rvalp)
74549e0fd3SRobert Mustacchi {
75549e0fd3SRobert Mustacchi 	uint_t dfno;
76549e0fd3SRobert Mustacchi 	zen_udf_t *zen_udf = &zen_udf_data;
77549e0fd3SRobert Mustacchi 	zen_udf_io_t zui;
78*71815ce7SRobert Mustacchi 	df_reg_def_t def;
79549e0fd3SRobert Mustacchi 
80549e0fd3SRobert Mustacchi 	if (cmd != ZEN_UDF_READ32 && cmd != ZEN_UDF_READ64) {
81549e0fd3SRobert Mustacchi 		return (ENOTTY);
82549e0fd3SRobert Mustacchi 	}
83549e0fd3SRobert Mustacchi 
84549e0fd3SRobert Mustacchi 	dfno = getminor(dev);
85549e0fd3SRobert Mustacchi 	if (dfno >= zen_udf->zudf_ndfs) {
86549e0fd3SRobert Mustacchi 		return (ENXIO);
87549e0fd3SRobert Mustacchi 	}
88549e0fd3SRobert Mustacchi 
89549e0fd3SRobert Mustacchi 	if (crgetzoneid(credp) != GLOBAL_ZONEID ||
90549e0fd3SRobert Mustacchi 	    secpolicy_hwmanip(credp) != 0) {
91549e0fd3SRobert Mustacchi 		return (EPERM);
92549e0fd3SRobert Mustacchi 	}
93549e0fd3SRobert Mustacchi 
94549e0fd3SRobert Mustacchi 	if (ddi_copyin((void *)arg, &zui, sizeof (zui), mode & FKIOCTL) != 0) {
95549e0fd3SRobert Mustacchi 		return (EFAULT);
96549e0fd3SRobert Mustacchi 	}
97549e0fd3SRobert Mustacchi 
98*71815ce7SRobert Mustacchi 	/*
99*71815ce7SRobert Mustacchi 	 * Cons up a register definition based on the user request. We set the
100*71815ce7SRobert Mustacchi 	 * gen to our current one.
101*71815ce7SRobert Mustacchi 	 */
102*71815ce7SRobert Mustacchi 	def.drd_gens = amdzen_c_df_rev();
103*71815ce7SRobert Mustacchi 	def.drd_func = zui.zui_func;
104*71815ce7SRobert Mustacchi 	def.drd_reg = zui.zui_reg;
105*71815ce7SRobert Mustacchi 
106549e0fd3SRobert Mustacchi 	if (cmd == ZEN_UDF_READ32) {
107549e0fd3SRobert Mustacchi 		int ret;
108549e0fd3SRobert Mustacchi 		uint32_t data;
109549e0fd3SRobert Mustacchi 
110*71815ce7SRobert Mustacchi 		ret = amdzen_c_df_read32(dfno, zui.zui_inst, def, &data);
111549e0fd3SRobert Mustacchi 		if (ret != 0) {
112549e0fd3SRobert Mustacchi 			return (ret);
113549e0fd3SRobert Mustacchi 		}
114549e0fd3SRobert Mustacchi 
115549e0fd3SRobert Mustacchi 		zui.zui_data = data;
116549e0fd3SRobert Mustacchi 	} else {
117549e0fd3SRobert Mustacchi 		int ret;
118549e0fd3SRobert Mustacchi 
119*71815ce7SRobert Mustacchi 		ret = amdzen_c_df_read64(dfno, zui.zui_inst, def,
120*71815ce7SRobert Mustacchi 		    &zui.zui_data);
121549e0fd3SRobert Mustacchi 		if (ret != 0) {
122549e0fd3SRobert Mustacchi 			return (ret);
123549e0fd3SRobert Mustacchi 		}
124549e0fd3SRobert Mustacchi 	}
125549e0fd3SRobert Mustacchi 
126549e0fd3SRobert Mustacchi 	if (ddi_copyout(&zui, (void *)arg, sizeof (zui), mode & FKIOCTL) != 0) {
127549e0fd3SRobert Mustacchi 		return (EFAULT);
128549e0fd3SRobert Mustacchi 	}
129549e0fd3SRobert Mustacchi 
130549e0fd3SRobert Mustacchi 	return (0);
131549e0fd3SRobert Mustacchi }
132549e0fd3SRobert Mustacchi 
133549e0fd3SRobert Mustacchi static int
zen_udf_close(dev_t dev,int flag,int otyp,cred_t * credp)134549e0fd3SRobert Mustacchi zen_udf_close(dev_t dev, int flag, int otyp, cred_t *credp)
135549e0fd3SRobert Mustacchi {
136549e0fd3SRobert Mustacchi 	return (0);
137549e0fd3SRobert Mustacchi }
138549e0fd3SRobert Mustacchi 
139549e0fd3SRobert Mustacchi static void
zen_udf_cleanup(zen_udf_t * zen_udf)140549e0fd3SRobert Mustacchi zen_udf_cleanup(zen_udf_t *zen_udf)
141549e0fd3SRobert Mustacchi {
142549e0fd3SRobert Mustacchi 	ddi_remove_minor_node(zen_udf->zudf_dip, NULL);
143549e0fd3SRobert Mustacchi 	zen_udf->zudf_ndfs = 0;
144549e0fd3SRobert Mustacchi 	zen_udf->zudf_dip = NULL;
145549e0fd3SRobert Mustacchi }
146549e0fd3SRobert Mustacchi 
147549e0fd3SRobert Mustacchi static int
zen_udf_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)148549e0fd3SRobert Mustacchi zen_udf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
149549e0fd3SRobert Mustacchi {
150549e0fd3SRobert Mustacchi 	zen_udf_t *zen_udf = &zen_udf_data;
151549e0fd3SRobert Mustacchi 
152549e0fd3SRobert Mustacchi 	if (cmd == DDI_RESUME) {
153549e0fd3SRobert Mustacchi 		return (DDI_SUCCESS);
154549e0fd3SRobert Mustacchi 	} else if (cmd != DDI_ATTACH) {
155549e0fd3SRobert Mustacchi 		return (DDI_FAILURE);
156549e0fd3SRobert Mustacchi 	}
157549e0fd3SRobert Mustacchi 
158549e0fd3SRobert Mustacchi 	if (zen_udf->zudf_dip != NULL) {
159549e0fd3SRobert Mustacchi 		dev_err(dip, CE_WARN, "!zen_udf is already attached to a "
160549e0fd3SRobert Mustacchi 		    "dev_info_t: %p", zen_udf->zudf_dip);
161549e0fd3SRobert Mustacchi 		return (DDI_FAILURE);
162549e0fd3SRobert Mustacchi 	}
163549e0fd3SRobert Mustacchi 
164549e0fd3SRobert Mustacchi 	zen_udf->zudf_dip = dip;
165549e0fd3SRobert Mustacchi 	zen_udf->zudf_ndfs = amdzen_c_df_count();
166549e0fd3SRobert Mustacchi 	for (uint_t i = 0; i < zen_udf->zudf_ndfs; i++) {
167549e0fd3SRobert Mustacchi 		char buf[32];
168549e0fd3SRobert Mustacchi 
169549e0fd3SRobert Mustacchi 		(void) snprintf(buf, sizeof (buf), "zen_udf.%u", i);
170549e0fd3SRobert Mustacchi 		if (ddi_create_minor_node(dip, buf, S_IFCHR, i, DDI_PSEUDO,
171549e0fd3SRobert Mustacchi 		    0) != DDI_SUCCESS) {
172549e0fd3SRobert Mustacchi 			dev_err(dip, CE_WARN, "!failed to create minor %s",
173549e0fd3SRobert Mustacchi 			    buf);
174549e0fd3SRobert Mustacchi 			goto err;
175549e0fd3SRobert Mustacchi 		}
176549e0fd3SRobert Mustacchi 	}
177549e0fd3SRobert Mustacchi 
178549e0fd3SRobert Mustacchi 	return (DDI_SUCCESS);
179549e0fd3SRobert Mustacchi 
180549e0fd3SRobert Mustacchi err:
181549e0fd3SRobert Mustacchi 	zen_udf_cleanup(zen_udf);
182549e0fd3SRobert Mustacchi 	return (DDI_FAILURE);
183549e0fd3SRobert Mustacchi }
184549e0fd3SRobert Mustacchi 
185549e0fd3SRobert Mustacchi static int
zen_udf_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)186549e0fd3SRobert Mustacchi zen_udf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
187549e0fd3SRobert Mustacchi {
188549e0fd3SRobert Mustacchi 	zen_udf_t *zen_udf = &zen_udf_data;
189549e0fd3SRobert Mustacchi 	minor_t m;
190549e0fd3SRobert Mustacchi 
191549e0fd3SRobert Mustacchi 	switch (cmd) {
192549e0fd3SRobert Mustacchi 	case DDI_INFO_DEVT2DEVINFO:
193549e0fd3SRobert Mustacchi 		m = getminor((dev_t)arg);
194549e0fd3SRobert Mustacchi 		if (m >= zen_udf->zudf_ndfs) {
195549e0fd3SRobert Mustacchi 			return (DDI_FAILURE);
196549e0fd3SRobert Mustacchi 		}
197549e0fd3SRobert Mustacchi 		*resultp = (void *)zen_udf->zudf_dip;
198549e0fd3SRobert Mustacchi 		break;
199549e0fd3SRobert Mustacchi 	case DDI_INFO_DEVT2INSTANCE:
200549e0fd3SRobert Mustacchi 		m = getminor((dev_t)arg);
201549e0fd3SRobert Mustacchi 		if (m >= zen_udf->zudf_ndfs) {
202549e0fd3SRobert Mustacchi 			return (DDI_FAILURE);
203549e0fd3SRobert Mustacchi 		}
204549e0fd3SRobert Mustacchi 		*resultp = (void *)(uintptr_t)ddi_get_instance(
205549e0fd3SRobert Mustacchi 		    zen_udf->zudf_dip);
206549e0fd3SRobert Mustacchi 		break;
207549e0fd3SRobert Mustacchi 	default:
208549e0fd3SRobert Mustacchi 		return (DDI_FAILURE);
209549e0fd3SRobert Mustacchi 	}
210549e0fd3SRobert Mustacchi 	return (DDI_SUCCESS);
211549e0fd3SRobert Mustacchi }
212549e0fd3SRobert Mustacchi 
213549e0fd3SRobert Mustacchi static int
zen_udf_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)214549e0fd3SRobert Mustacchi zen_udf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
215549e0fd3SRobert Mustacchi {
216549e0fd3SRobert Mustacchi 	zen_udf_t *zen_udf = &zen_udf_data;
217549e0fd3SRobert Mustacchi 
218549e0fd3SRobert Mustacchi 	if (cmd == DDI_SUSPEND) {
219549e0fd3SRobert Mustacchi 		return (DDI_SUCCESS);
220549e0fd3SRobert Mustacchi 	} else if (cmd != DDI_DETACH) {
221549e0fd3SRobert Mustacchi 		return (DDI_FAILURE);
222549e0fd3SRobert Mustacchi 	}
223549e0fd3SRobert Mustacchi 
224549e0fd3SRobert Mustacchi 	if (zen_udf->zudf_dip != dip) {
225549e0fd3SRobert Mustacchi 		dev_err(dip, CE_WARN, "!asked to detach zen_udf, but dip "
226549e0fd3SRobert Mustacchi 		    "doesn't match");
227549e0fd3SRobert Mustacchi 		return (DDI_FAILURE);
228549e0fd3SRobert Mustacchi 	}
229549e0fd3SRobert Mustacchi 
230549e0fd3SRobert Mustacchi 	zen_udf_cleanup(zen_udf);
231549e0fd3SRobert Mustacchi 	return (DDI_SUCCESS);
232549e0fd3SRobert Mustacchi }
233549e0fd3SRobert Mustacchi 
234549e0fd3SRobert Mustacchi static struct cb_ops zen_udf_cb_ops = {
235549e0fd3SRobert Mustacchi 	.cb_open = zen_udf_open,
236549e0fd3SRobert Mustacchi 	.cb_close = zen_udf_close,
237549e0fd3SRobert Mustacchi 	.cb_strategy = nodev,
238549e0fd3SRobert Mustacchi 	.cb_print = nodev,
239549e0fd3SRobert Mustacchi 	.cb_dump = nodev,
240549e0fd3SRobert Mustacchi 	.cb_read = nodev,
241549e0fd3SRobert Mustacchi 	.cb_write = nodev,
242549e0fd3SRobert Mustacchi 	.cb_ioctl = zen_udf_ioctl,
243549e0fd3SRobert Mustacchi 	.cb_devmap = nodev,
244549e0fd3SRobert Mustacchi 	.cb_mmap = nodev,
245549e0fd3SRobert Mustacchi 	.cb_segmap = nodev,
246549e0fd3SRobert Mustacchi 	.cb_chpoll = nochpoll,
247549e0fd3SRobert Mustacchi 	.cb_prop_op = ddi_prop_op,
248549e0fd3SRobert Mustacchi 	.cb_flag = D_MP,
249549e0fd3SRobert Mustacchi 	.cb_rev = CB_REV,
250549e0fd3SRobert Mustacchi 	.cb_aread = nodev,
251549e0fd3SRobert Mustacchi 	.cb_awrite = nodev
252549e0fd3SRobert Mustacchi };
253549e0fd3SRobert Mustacchi 
254549e0fd3SRobert Mustacchi static struct dev_ops zen_udf_dev_ops = {
255549e0fd3SRobert Mustacchi 	.devo_rev = DEVO_REV,
256549e0fd3SRobert Mustacchi 	.devo_refcnt = 0,
257549e0fd3SRobert Mustacchi 	.devo_getinfo = zen_udf_getinfo,
258549e0fd3SRobert Mustacchi 	.devo_identify = nulldev,
259549e0fd3SRobert Mustacchi 	.devo_probe = nulldev,
260549e0fd3SRobert Mustacchi 	.devo_attach = zen_udf_attach,
261549e0fd3SRobert Mustacchi 	.devo_detach = zen_udf_detach,
262549e0fd3SRobert Mustacchi 	.devo_reset = nodev,
263549e0fd3SRobert Mustacchi 	.devo_quiesce = ddi_quiesce_not_needed,
264549e0fd3SRobert Mustacchi 	.devo_cb_ops = &zen_udf_cb_ops
265549e0fd3SRobert Mustacchi };
266549e0fd3SRobert Mustacchi 
267549e0fd3SRobert Mustacchi static struct modldrv zen_udf_modldrv = {
268549e0fd3SRobert Mustacchi 	.drv_modops = &mod_driverops,
269549e0fd3SRobert Mustacchi 	.drv_linkinfo = "AMD User DF Access",
270549e0fd3SRobert Mustacchi 	.drv_dev_ops = &zen_udf_dev_ops
271549e0fd3SRobert Mustacchi };
272549e0fd3SRobert Mustacchi 
273549e0fd3SRobert Mustacchi static struct modlinkage zen_udf_modlinkage = {
274549e0fd3SRobert Mustacchi 	.ml_rev = MODREV_1,
275549e0fd3SRobert Mustacchi 	.ml_linkage = { &zen_udf_modldrv, NULL }
276549e0fd3SRobert Mustacchi };
277549e0fd3SRobert Mustacchi 
278549e0fd3SRobert Mustacchi int
_init(void)279549e0fd3SRobert Mustacchi _init(void)
280549e0fd3SRobert Mustacchi {
281549e0fd3SRobert Mustacchi 	return (mod_install(&zen_udf_modlinkage));
282549e0fd3SRobert Mustacchi }
283549e0fd3SRobert Mustacchi 
284549e0fd3SRobert Mustacchi int
_info(struct modinfo * modinfop)285549e0fd3SRobert Mustacchi _info(struct modinfo *modinfop)
286549e0fd3SRobert Mustacchi {
287549e0fd3SRobert Mustacchi 	return (mod_info(&zen_udf_modlinkage, modinfop));
288549e0fd3SRobert Mustacchi }
289549e0fd3SRobert Mustacchi 
290549e0fd3SRobert Mustacchi int
_fini(void)291549e0fd3SRobert Mustacchi _fini(void)
292549e0fd3SRobert Mustacchi {
293549e0fd3SRobert Mustacchi 	return (mod_remove(&zen_udf_modlinkage));
294549e0fd3SRobert Mustacchi }
295