xref: /illumos-gate/usr/src/uts/common/xen/os/xvdi.c (revision 2952f70a)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
22843e1988Sjohnlev /*
237f0b8309SEdward Pilatowicz  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24843e1988Sjohnlev  * Use is subject to license terms.
25843e1988Sjohnlev  */
273599414cSJeremy Jones /*
283599414cSJeremy Jones  * Copyright (c) 2014 by Delphix. All rights reserved.
296d1e6c90SYuri Pankov  * Copyright 2018 Nexenta Systems, Inc.
303599414cSJeremy Jones  */
313599414cSJeremy Jones 
32843e1988Sjohnlev /*
33843e1988Sjohnlev  * Xen virtual device driver interfaces
34843e1988Sjohnlev  */
36843e1988Sjohnlev /*
37843e1988Sjohnlev  * todo:
38843e1988Sjohnlev  * + name space clean up:
39843e1988Sjohnlev  *	xvdi_* - public xen interfaces, for use by all leaf drivers
40843e1988Sjohnlev  *	xd_* - public xen data structures
41843e1988Sjohnlev  *	i_xvdi_* - implementation private functions
42843e1988Sjohnlev  *	xendev_* - xendev driver interfaces, both internal and in cb_ops/bus_ops
43843e1988Sjohnlev  * + add mdb dcmds to dump ring status
44843e1988Sjohnlev  * + implement xvdi_xxx to wrap xenbus_xxx read/write function
45843e1988Sjohnlev  * + convert (xendev_ring_t *) into xvdi_ring_handle_t
46843e1988Sjohnlev  */
47843e1988Sjohnlev #include <sys/conf.h>
48843e1988Sjohnlev #include <sys/param.h>
49843e1988Sjohnlev #include <sys/kmem.h>
50843e1988Sjohnlev #include <vm/seg_kmem.h>
51843e1988Sjohnlev #include <sys/debug.h>
52843e1988Sjohnlev #include <sys/modctl.h>
53843e1988Sjohnlev #include <sys/autoconf.h>
54843e1988Sjohnlev #include <sys/ddi_impldefs.h>
55843e1988Sjohnlev #include <sys/ddi_subrdefs.h>
56843e1988Sjohnlev #include <sys/ddi.h>
57843e1988Sjohnlev #include <sys/sunddi.h>
58843e1988Sjohnlev #include <sys/sunndi.h>
59843e1988Sjohnlev #include <sys/sunldi.h>
60843e1988Sjohnlev #include <sys/fs/dv_node.h>
61843e1988Sjohnlev #include <sys/avintr.h>
62843e1988Sjohnlev #include <sys/psm.h>
63843e1988Sjohnlev #include <sys/spl.h>
64843e1988Sjohnlev #include <sys/promif.h>
65843e1988Sjohnlev #include <sys/list.h>
66843e1988Sjohnlev #include <sys/bootconf.h>
67843e1988Sjohnlev #include <sys/bootsvcs.h>
68843e1988Sjohnlev #include <sys/bootinfo.h>
69843e1988Sjohnlev #include <sys/note.h>
707f0b8309SEdward Pilatowicz #include <sys/sysmacros.h>
71551bc2a6Smrj #ifdef XPV_HVM_DRIVER
72551bc2a6Smrj #include <sys/xpv_support.h>
73551bc2a6Smrj #include <sys/hypervisor.h>
74551bc2a6Smrj #include <public/grant_table.h>
75551bc2a6Smrj #include <public/xen.h>
76551bc2a6Smrj #include <public/io/xenbus.h>
77551bc2a6Smrj #include <public/io/xs_wire.h>
78551bc2a6Smrj #include <public/event_channel.h>
79551bc2a6Smrj #include <public/io/xenbus.h>
80551bc2a6Smrj #else /* XPV_HVM_DRIVER */
81551bc2a6Smrj #include <sys/hypervisor.h>
82843e1988Sjohnlev #include <sys/xen_mmu.h>
83843e1988Sjohnlev #include <xen/sys/xenbus_impl.h>
84551bc2a6Smrj #include <sys/evtchn_impl.h>
85551bc2a6Smrj #endif /* XPV_HVM_DRIVER */
86551bc2a6Smrj #include <sys/gnttab.h>
87843e1988Sjohnlev #include <xen/sys/xendev.h>
88843e1988Sjohnlev #include <vm/hat_i86.h>
89843e1988Sjohnlev #include <sys/scsi/generic/inquiry.h>
90843e1988Sjohnlev #include <util/sscanf.h>
91843e1988Sjohnlev #include <xen/public/io/xs_wire.h>
9406bbe1e0Sedp #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
9506bbe1e0Sedp #define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
9606bbe1e0Sedp 			((ch) >= 'A' && (ch) <= 'F'))
98843e1988Sjohnlev static void xvdi_ring_init_sring(xendev_ring_t *);
99843e1988Sjohnlev static void xvdi_ring_init_front_ring(xendev_ring_t *, size_t, size_t);
100551bc2a6Smrj #ifndef XPV_HVM_DRIVER
101843e1988Sjohnlev static void xvdi_ring_init_back_ring(xendev_ring_t *, size_t, size_t);
102551bc2a6Smrj #endif
103843e1988Sjohnlev static void xvdi_reinit_ring(dev_info_t *, grant_ref_t *, xendev_ring_t *);
105843e1988Sjohnlev static int i_xvdi_add_watches(dev_info_t *);
106843e1988Sjohnlev static void i_xvdi_rem_watches(dev_info_t *);
108843e1988Sjohnlev static int i_xvdi_add_watch_oestate(dev_info_t *);
109843e1988Sjohnlev static void i_xvdi_rem_watch_oestate(dev_info_t *);
110843e1988Sjohnlev static void i_xvdi_oestate_cb(struct xenbus_device *, XenbusState);
111843e1988Sjohnlev static void i_xvdi_oestate_handler(void *);
113843e1988Sjohnlev static int i_xvdi_add_watch_hpstate(dev_info_t *);
114843e1988Sjohnlev static void i_xvdi_rem_watch_hpstate(dev_info_t *);
115843e1988Sjohnlev static void i_xvdi_hpstate_cb(struct xenbus_watch *, const char **,
116843e1988Sjohnlev     unsigned int);
117843e1988Sjohnlev static void i_xvdi_hpstate_handler(void *);
119843e1988Sjohnlev static int i_xvdi_add_watch_bepath(dev_info_t *);
120843e1988Sjohnlev static void i_xvdi_rem_watch_bepath(dev_info_t *);
121843e1988Sjohnlev static void i_xvdi_bepath_cb(struct xenbus_watch *, const char **,
122843e1988Sjohnlev     unsigned in);
124843e1988Sjohnlev static void xendev_offline_device(void *);
126843e1988Sjohnlev static void i_xvdi_probe_path_cb(struct xenbus_watch *, const char **,
127843e1988Sjohnlev     unsigned int);
128843e1988Sjohnlev static void i_xvdi_probe_path_handler(void *);
130eea6c6b9SMax zhen typedef struct oestate_evt {
131eea6c6b9SMax zhen 	dev_info_t *dip;
132eea6c6b9SMax zhen 	XenbusState state;
133eea6c6b9SMax zhen } i_oestate_evt_t;
134eea6c6b9SMax zhen 
135843e1988Sjohnlev typedef struct xd_cfg {
136843e1988Sjohnlev 	xendev_devclass_t devclass;
137843e1988Sjohnlev 	char *xsdev;
138843e1988Sjohnlev 	char *xs_path_fe;
139843e1988Sjohnlev 	char *xs_path_be;
140843e1988Sjohnlev 	char *node_fe;
141843e1988Sjohnlev 	char *node_be;
142843e1988Sjohnlev 	char *device_type;
143843e1988Sjohnlev 	int xd_ipl;
144843e1988Sjohnlev 	int flags;
145843e1988Sjohnlev } i_xd_cfg_t;
147843e1988Sjohnlev #define	XD_DOM_ZERO	0x01	/* dom0 only. */
148843e1988Sjohnlev #define	XD_DOM_GUEST	0x02	/* Guest domains (i.e. non-dom0). */
149843e1988Sjohnlev #define	XD_DOM_IO	0x04	/* IO domains. */
151843e1988Sjohnlev #define	XD_DOM_ALL	(XD_DOM_ZERO | XD_DOM_GUEST)
153843e1988Sjohnlev static i_xd_cfg_t xdci[] = {
1543599414cSJeremy Jones #ifndef XPV_HVM_DRIVER
155843e1988Sjohnlev 	{ XEN_CONSOLE, NULL, NULL, NULL, "xencons", NULL,
156843e1988Sjohnlev 	    "console", IPL_CONS, XD_DOM_ALL, },
1573599414cSJeremy Jones #endif
159843e1988Sjohnlev 	{ XEN_VNET, "vif", "device/vif", "backend/vif", "xnf", "xnb",
160843e1988Sjohnlev 	    "network", IPL_VIF, XD_DOM_ALL, },
162843e1988Sjohnlev 	{ XEN_VBLK, "vbd", "device/vbd", "backend/vbd", "xdf", "xdb",
163843e1988Sjohnlev 	    "block", IPL_VBD, XD_DOM_ALL, },
1657eea693dSMark Johnson 	{ XEN_BLKTAP, "tap", NULL, "backend/tap", NULL, "xpvtap",
1667eea693dSMark Johnson 	    "block", IPL_VBD, XD_DOM_ALL, },
1677eea693dSMark Johnson 
1683599414cSJeremy Jones #ifndef XPV_HVM_DRIVER
169843e1988Sjohnlev 	{ XEN_XENBUS, NULL, NULL, NULL, "xenbus", NULL,
170843e1988Sjohnlev 	    NULL, 0, XD_DOM_ALL, },
172843e1988Sjohnlev 	{ XEN_DOMCAPS, NULL, NULL, NULL, "domcaps", NULL,
173843e1988Sjohnlev 	    NULL, 0, XD_DOM_ALL, },
175843e1988Sjohnlev 	{ XEN_BALLOON, NULL, NULL, NULL, "balloon", NULL,
176843e1988Sjohnlev 	    NULL, 0, XD_DOM_ALL, },
1773599414cSJeremy Jones #endif
179843e1988Sjohnlev 	{ XEN_EVTCHN, NULL, NULL, NULL, "evtchn", NULL,
180843e1988Sjohnlev 	    NULL, 0, XD_DOM_ZERO, },
182843e1988Sjohnlev 	{ XEN_PRIVCMD, NULL, NULL, NULL, "privcmd", NULL,
183843e1988Sjohnlev 	    NULL, 0, XD_DOM_ZERO, },
184843e1988Sjohnlev };
185843e1988Sjohnlev #define	NXDC	(sizeof (xdci) / sizeof (xdci[0]))
187843e1988Sjohnlev static void i_xvdi_enum_fe(dev_info_t *, i_xd_cfg_t *);
188843e1988Sjohnlev static void i_xvdi_enum_be(dev_info_t *, i_xd_cfg_t *);
189843e1988Sjohnlev static void i_xvdi_enum_worker(dev_info_t *, i_xd_cfg_t *, char *);
191843e1988Sjohnlev /*
192843e1988Sjohnlev  * Xen device channel device access and DMA attributes
193843e1988Sjohnlev  */
194843e1988Sjohnlev static ddi_device_acc_attr_t xendev_dc_accattr = {
196843e1988Sjohnlev };
198843e1988Sjohnlev static ddi_dma_attr_t xendev_dc_dmaattr = {
199843e1988Sjohnlev 	DMA_ATTR_V0,		/* version of this structure */
200843e1988Sjohnlev 	0,			/* lowest usable address */
201843e1988Sjohnlev 	0xffffffffffffffffULL,	/* highest usable address */
202843e1988Sjohnlev 	0x7fffffff,		/* maximum DMAable byte count */
203843e1988Sjohnlev 	MMU_PAGESIZE,		/* alignment in bytes */
204843e1988Sjohnlev 	0x7ff,			/* bitmap of burst sizes */
205843e1988Sjohnlev 	1,			/* minimum transfer */
206843e1988Sjohnlev 	0xffffffffU,		/* maximum transfer */
207843e1988Sjohnlev 	0xffffffffffffffffULL,	/* maximum segment length */
208843e1988Sjohnlev 	1,			/* maximum number of segments */
209843e1988Sjohnlev 	1,			/* granularity */
210843e1988Sjohnlev 	0,			/* flags (reserved) */
211843e1988Sjohnlev };
213843e1988Sjohnlev static dev_info_t *xendev_dip = NULL;
215843e1988Sjohnlev #define	XVDI_DBG_STATE	0x01
216843e1988Sjohnlev #define	XVDI_DBG_PROBE	0x02
218843e1988Sjohnlev #ifdef DEBUG
219ab4a9bebSjohnlev int i_xvdi_debug = 0;
221843e1988Sjohnlev #define	XVDI_DPRINTF(flag, format, ...)			\
222843e1988Sjohnlev {							\
223843e1988Sjohnlev 	if (i_xvdi_debug & (flag))			\
224843e1988Sjohnlev 		prom_printf((format), __VA_ARGS__);	\
225843e1988Sjohnlev }
226843e1988Sjohnlev #else
227843e1988Sjohnlev #define	XVDI_DPRINTF(flag, format, ...)
228843e1988Sjohnlev #endif /* DEBUG */
230843e1988Sjohnlev static i_xd_cfg_t *
i_xvdi_devclass2cfg(xendev_devclass_t devclass)231843e1988Sjohnlev i_xvdi_devclass2cfg(xendev_devclass_t devclass)
232843e1988Sjohnlev {
233843e1988Sjohnlev 	i_xd_cfg_t *xdcp;
234843e1988Sjohnlev 	int i;
236843e1988Sjohnlev 	for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++)
237843e1988Sjohnlev 		if (xdcp->devclass == devclass)
238843e1988Sjohnlev 			return (xdcp);
240843e1988Sjohnlev 	return (NULL);
241843e1988Sjohnlev }
243843e1988Sjohnlev int
xvdi_init_dev(dev_info_t * dip)244843e1988Sjohnlev xvdi_init_dev(dev_info_t *dip)
245843e1988Sjohnlev {
246843e1988Sjohnlev 	xendev_devclass_t devcls;
247843e1988Sjohnlev 	int vdevnum;
248843e1988Sjohnlev 	domid_t domid;
249843e1988Sjohnlev 	struct xendev_ppd *pdp;
250843e1988Sjohnlev 	i_xd_cfg_t *xdcp;
251843e1988Sjohnlev 	boolean_t backend;
252843e1988Sjohnlev 	char xsnamebuf[TYPICALMAXPATHLEN];
253843e1988Sjohnlev 	char *xsname;
25497869ac5Sjhd 	void *prop_str;
2553de3be76Sjhd 	unsigned int prop_len;
2566d1e6c90SYuri Pankov 	char unitaddr[16];
258843e1988Sjohnlev 	devcls = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
259843e1988Sjohnlev 	    DDI_PROP_DONTPASS, "devclass", XEN_INVAL);
260843e1988Sjohnlev 	vdevnum = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2611ca30e39Sjohnlev 	    DDI_PROP_DONTPASS, "vdev", VDEV_NOXS);
262843e1988Sjohnlev 	domid = (domid_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
263843e1988Sjohnlev 	    DDI_PROP_DONTPASS, "domain", DOMID_SELF);
265843e1988Sjohnlev 	backend = (domid != DOMID_SELF);
266843e1988Sjohnlev 	xdcp = i_xvdi_devclass2cfg(devcls);
267843e1988Sjohnlev 	if (xdcp->device_type != NULL)
268843e1988Sjohnlev 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
269843e1988Sjohnlev 		    "device_type", xdcp->device_type);
271843e1988Sjohnlev 	pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
272843e1988Sjohnlev 	pdp->xd_domain = domid;
273843e1988Sjohnlev 	pdp->xd_vdevnum = vdevnum;
274843e1988Sjohnlev 	pdp->xd_devclass = devcls;
275843e1988Sjohnlev 	pdp->xd_evtchn = INVALID_EVTCHN;
2767f0b8309SEdward Pilatowicz 	list_create(&pdp->xd_xb_watches, sizeof (xd_xb_watches_t),
2777f0b8309SEdward Pilatowicz 	    offsetof(xd_xb_watches_t, xxw_list));
2787eea693dSMark Johnson 	mutex_init(&pdp->xd_evt_lk, NULL, MUTEX_DRIVER, NULL);
2797eea693dSMark Johnson 	mutex_init(&pdp->xd_ndi_lk, NULL, MUTEX_DRIVER, NULL);
280843e1988Sjohnlev 	ddi_set_parent_data(dip, pdp);
282843e1988Sjohnlev 	/*
283843e1988Sjohnlev 	 * devices that do not need to interact with xenstore
284843e1988Sjohnlev 	 */
2851ca30e39Sjohnlev 	if (vdevnum == VDEV_NOXS) {
286843e1988Sjohnlev 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
287843e1988Sjohnlev 		    "unit-address", "0");
288843e1988Sjohnlev 		if (devcls == XEN_CONSOLE)
289843e1988Sjohnlev 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
290843e1988Sjohnlev 			    "pm-hardware-state", "needs-suspend-resume");
291843e1988Sjohnlev 		return (DDI_SUCCESS);
292843e1988Sjohnlev 	}
294843e1988Sjohnlev 	/*
295843e1988Sjohnlev 	 * PV devices that need to probe xenstore
296843e1988Sjohnlev 	 */
298843e1988Sjohnlev 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
299843e1988Sjohnlev 	    "pm-hardware-state", "needs-suspend-resume");
301843e1988Sjohnlev 	xsname = xsnamebuf;
302843e1988Sjohnlev 	if (!backend)
303843e1988Sjohnlev 		(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
304843e1988Sjohnlev 		    "%s/%d", xdcp->xs_path_fe, vdevnum);
305843e1988Sjohnlev 	else
306843e1988Sjohnlev 		(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
307843e1988Sjohnlev 		    "%s/%d/%d", xdcp->xs_path_be, domid, vdevnum);
3081d03c31eSjohnlev 	if ((xenbus_read_driver_state(xsname) >= XenbusStateClosing)) {
3091d03c31eSjohnlev 		/* Don't try to init a dev that may be closing */
3107eea693dSMark Johnson 		mutex_destroy(&pdp->xd_ndi_lk);
3117eea693dSMark Johnson 		mutex_destroy(&pdp->xd_evt_lk);
3121d03c31eSjohnlev 		kmem_free(pdp, sizeof (*pdp));
3131d03c31eSjohnlev 		ddi_set_parent_data(dip, NULL);
3141d03c31eSjohnlev 		return (DDI_FAILURE);
3151d03c31eSjohnlev 	}
317843e1988Sjohnlev 	pdp->xd_xsdev.nodename = i_ddi_strdup(xsname, KM_SLEEP);
318843e1988Sjohnlev 	pdp->xd_xsdev.devicetype = xdcp->xsdev;
319843e1988Sjohnlev 	pdp->xd_xsdev.frontend = (backend ? 0 : 1);
320843e1988Sjohnlev 	pdp->xd_xsdev.data = dip;
321843e1988Sjohnlev 	pdp->xd_xsdev.otherend_id = (backend ? domid : -1);
322843e1988Sjohnlev 	if (i_xvdi_add_watches(dip) != DDI_SUCCESS) {
323843e1988Sjohnlev 		cmn_err(CE_WARN, "xvdi_init_dev: "
324843e1988Sjohnlev 		    "cannot add watches for %s", xsname);
325843e1988Sjohnlev 		xvdi_uninit_dev(dip);
326843e1988Sjohnlev 		return (DDI_FAILURE);
327843e1988Sjohnlev 	}
32997869ac5Sjhd 	if (backend)
33097869ac5Sjhd 		return (DDI_SUCCESS);
332843e1988Sjohnlev 	/*
33397869ac5Sjhd 	 * The unit-address for frontend devices is the name of the
33497869ac5Sjhd 	 * of the xenstore node containing the device configuration
33597869ac5Sjhd 	 * and is contained in the 'vdev' property.
33697869ac5Sjhd 	 * VIF devices are named using an incrementing integer.
3376d1e6c90SYuri Pankov 	 * VBD devices are either named using the 32-bit dev_t value
33897869ac5Sjhd 	 * for linux 'hd' and 'xvd' devices, or a simple integer value
33997869ac5Sjhd 	 * in the range 0..767.  768 is the base value of the linux
34097869ac5Sjhd 	 * dev_t namespace, the dev_t value for 'hda'.
341843e1988Sjohnlev 	 */
34297869ac5Sjhd 	(void) snprintf(unitaddr, sizeof (unitaddr), "%d", vdevnum);
34397869ac5Sjhd 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unit-address",
34497869ac5Sjhd 	    unitaddr);
34697869ac5Sjhd 	switch (devcls) {
34797869ac5Sjhd 	case XEN_VNET:
34897869ac5Sjhd 		if (xenbus_read(XBT_NULL, xsname, "mac", (void *)&prop_str,
34997869ac5Sjhd 		    &prop_len) != 0)
350843e1988Sjohnlev 			break;
35197869ac5Sjhd 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "mac",
35297869ac5Sjhd 		    prop_str);
35397869ac5Sjhd 		kmem_free(prop_str, prop_len);
35497869ac5Sjhd 		break;
35597869ac5Sjhd 	case XEN_VBLK:
35697869ac5Sjhd 		/*
35797869ac5Sjhd 		 * cache a copy of the otherend name
35897869ac5Sjhd 		 * for ease of observeability
35997869ac5Sjhd 		 */
36097869ac5Sjhd 		if (xenbus_read(XBT_NULL, pdp->xd_xsdev.otherend, "dev",
36197869ac5Sjhd 		    &prop_str, &prop_len) != 0)
362843e1988Sjohnlev 			break;
36397869ac5Sjhd 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
36497869ac5Sjhd 		    "dev-address", prop_str);
36597869ac5Sjhd 		kmem_free(prop_str, prop_len);
36697869ac5Sjhd 		break;
36797869ac5Sjhd 	default:
36897869ac5Sjhd 		break;
369843e1988Sjohnlev 	}