xref: /illumos-gate/usr/src/cmd/bhyve/pci_virtio_9p.c (revision 32640292339b07090f10ce34d455f98711077343)
1aa693e99SJason King /*-
2aa693e99SJason King  * Copyright (c) 2015 iXsystems Inc.
3aa693e99SJason King  * Copyright (c) 2017-2018 Jakub Klama <jceel@FreeBSD.org>
4aa693e99SJason King  * All rights reserved.
5aa693e99SJason King  *
6aa693e99SJason King  * Redistribution and use in source and binary forms, with or without
7aa693e99SJason King  * modification, are permitted provided that the following conditions
8aa693e99SJason King  * are met:
9aa693e99SJason King  * 1. Redistributions of source code must retain the above copyright
10aa693e99SJason King  *    notice, this list of conditions and the following disclaimer
11aa693e99SJason King  *    in this position and unchanged.
12aa693e99SJason King  * 2. Redistributions in binary form must reproduce the above copyright
13aa693e99SJason King  *    notice, this list of conditions and the following disclaimer in the
14aa693e99SJason King  *    documentation and/or other materials provided with the distribution.
15aa693e99SJason King  *
16aa693e99SJason King  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17aa693e99SJason King  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18aa693e99SJason King  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19aa693e99SJason King  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20aa693e99SJason King  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21aa693e99SJason King  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22aa693e99SJason King  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23aa693e99SJason King  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24aa693e99SJason King  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25aa693e99SJason King  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26aa693e99SJason King  * SUCH DAMAGE.
27aa693e99SJason King  */
28aa693e99SJason King 
29aa693e99SJason King /*
30aa693e99SJason King  * VirtIO filesystem passthrough using 9p protocol.
31aa693e99SJason King  */
32aa693e99SJason King 
33aa693e99SJason King #include <sys/cdefs.h>
34aa693e99SJason King 
35aa693e99SJason King #include <sys/param.h>
36aa693e99SJason King #include <sys/linker_set.h>
37aa693e99SJason King #include <sys/uio.h>
38aa693e99SJason King #ifndef WITHOUT_CAPSICUM
39aa693e99SJason King #include <sys/capsicum.h>
40aa693e99SJason King #endif
41aa693e99SJason King 
42aa693e99SJason King #include <errno.h>
43aa693e99SJason King #include <fcntl.h>
44aa693e99SJason King #include <stdio.h>
45aa693e99SJason King #include <stdlib.h>
46aa693e99SJason King #include <string.h>
47aa693e99SJason King #include <unistd.h>
48aa693e99SJason King #include <assert.h>
49aa693e99SJason King #include <pthread.h>
50aa693e99SJason King 
51aa693e99SJason King #include <lib9p.h>
52aa693e99SJason King #include <backend/fs.h>
53aa693e99SJason King 
54aa693e99SJason King #include "bhyverun.h"
55aa693e99SJason King #include "config.h"
56aa693e99SJason King #include "debug.h"
57aa693e99SJason King #include "pci_emul.h"
58aa693e99SJason King #include "virtio.h"
59aa693e99SJason King 
60aa693e99SJason King #ifndef __FreeBSD__
61aa693e99SJason King #include "privileges.h"
62aa693e99SJason King #endif
63aa693e99SJason King 
64aa693e99SJason King #define	VT9P_MAX_IOV	128
65aa693e99SJason King #define VT9P_RINGSZ	256
66aa693e99SJason King #define	VT9P_MAXTAGSZ	256
67aa693e99SJason King #define	VT9P_CONFIGSPACESZ	(VT9P_MAXTAGSZ + sizeof(uint16_t))
68aa693e99SJason King 
69aa693e99SJason King static int pci_vt9p_debug;
70aa693e99SJason King #define DPRINTF(params) if (pci_vt9p_debug) printf params
71aa693e99SJason King #define WPRINTF(params) printf params
72aa693e99SJason King 
73aa693e99SJason King /*
74aa693e99SJason King  * Per-device softc
75aa693e99SJason King  */
76aa693e99SJason King struct pci_vt9p_softc {
77aa693e99SJason King 	struct virtio_softc      vsc_vs;
78aa693e99SJason King 	struct vqueue_info       vsc_vq;
79aa693e99SJason King 	pthread_mutex_t          vsc_mtx;
80aa693e99SJason King 	uint64_t                 vsc_cfg;
81aa693e99SJason King 	uint64_t                 vsc_features;
82aa693e99SJason King 	char *                   vsc_rootpath;
83aa693e99SJason King 	struct pci_vt9p_config * vsc_config;
84aa693e99SJason King 	struct l9p_backend *     vsc_fs_backend;
85aa693e99SJason King 	struct l9p_server *      vsc_server;
86aa693e99SJason King         struct l9p_connection *  vsc_conn;
87aa693e99SJason King };
88aa693e99SJason King 
89aa693e99SJason King struct pci_vt9p_request {
90aa693e99SJason King 	struct pci_vt9p_softc *	vsr_sc;
91aa693e99SJason King 	struct iovec *		vsr_iov;
92aa693e99SJason King 	size_t			vsr_niov;
93aa693e99SJason King 	size_t			vsr_respidx;
94aa693e99SJason King 	size_t			vsr_iolen;
95aa693e99SJason King 	uint16_t		vsr_idx;
96aa693e99SJason King };
97aa693e99SJason King 
98aa693e99SJason King struct pci_vt9p_config {
99aa693e99SJason King 	uint16_t tag_len;
10059d65d31SAndy Fiddaman #ifdef	__FreeBSD__
101aa693e99SJason King 	char tag[0];
10259d65d31SAndy Fiddaman #else
10359d65d31SAndy Fiddaman 	char tag[VT9P_MAXTAGSZ];
10459d65d31SAndy Fiddaman #endif
105aa693e99SJason King } __attribute__((packed));
106aa693e99SJason King 
107aa693e99SJason King static int pci_vt9p_send(struct l9p_request *, const struct iovec *,
108aa693e99SJason King     const size_t, const size_t, void *);
109aa693e99SJason King static void pci_vt9p_drop(struct l9p_request *, const struct iovec *, size_t,
110aa693e99SJason King     void *);
111aa693e99SJason King static void pci_vt9p_reset(void *);
112aa693e99SJason King static void pci_vt9p_notify(void *, struct vqueue_info *);
113aa693e99SJason King static int pci_vt9p_cfgread(void *, int, int, uint32_t *);
114aa693e99SJason King static void pci_vt9p_neg_features(void *, uint64_t);
115aa693e99SJason King 
116aa693e99SJason King static struct virtio_consts vt9p_vi_consts = {
11759d65d31SAndy Fiddaman 	.vc_name =	"vt9p",
11859d65d31SAndy Fiddaman 	.vc_nvq =	1,
11959d65d31SAndy Fiddaman 	.vc_cfgsize =	VT9P_CONFIGSPACESZ,
12059d65d31SAndy Fiddaman 	.vc_reset =	pci_vt9p_reset,
12159d65d31SAndy Fiddaman 	.vc_qnotify =	pci_vt9p_notify,
12259d65d31SAndy Fiddaman 	.vc_cfgread =	pci_vt9p_cfgread,
12359d65d31SAndy Fiddaman 	.vc_apply_features = pci_vt9p_neg_features,
12459d65d31SAndy Fiddaman 	.vc_hv_caps =	(1 << 0),
125aa693e99SJason King };
126aa693e99SJason King 
127aa693e99SJason King static void
pci_vt9p_reset(void * vsc)128aa693e99SJason King pci_vt9p_reset(void *vsc)
129aa693e99SJason King {
130aa693e99SJason King 	struct pci_vt9p_softc *sc;
131aa693e99SJason King 
132aa693e99SJason King 	sc = vsc;
133aa693e99SJason King 
134aa693e99SJason King 	DPRINTF(("vt9p: device reset requested !\n"));
135aa693e99SJason King 	vi_reset_dev(&sc->vsc_vs);
136aa693e99SJason King }
137aa693e99SJason King 
138aa693e99SJason King static void
pci_vt9p_neg_features(void * vsc,uint64_t negotiated_features)139aa693e99SJason King pci_vt9p_neg_features(void *vsc, uint64_t negotiated_features)
140aa693e99SJason King {
141aa693e99SJason King 	struct pci_vt9p_softc *sc = vsc;
142aa693e99SJason King 
143aa693e99SJason King 	sc->vsc_features = negotiated_features;
144aa693e99SJason King }
145aa693e99SJason King 
146aa693e99SJason King static int
pci_vt9p_cfgread(void * vsc,int offset,int size,uint32_t * retval)147aa693e99SJason King pci_vt9p_cfgread(void *vsc, int offset, int size, uint32_t *retval)
148aa693e99SJason King {
149aa693e99SJason King 	struct pci_vt9p_softc *sc = vsc;
150aa693e99SJason King 	void *ptr;
151aa693e99SJason King 
152aa693e99SJason King 	ptr = (uint8_t *)sc->vsc_config + offset;
153aa693e99SJason King 	memcpy(retval, ptr, size);
154aa693e99SJason King 	return (0);
155aa693e99SJason King }
156aa693e99SJason King 
157aa693e99SJason King static int
pci_vt9p_get_buffer(struct l9p_request * req,struct iovec * iov,size_t * niov,void * arg __unused)158aa693e99SJason King pci_vt9p_get_buffer(struct l9p_request *req, struct iovec *iov, size_t *niov,
15959d65d31SAndy Fiddaman     void *arg __unused)
160aa693e99SJason King {
161aa693e99SJason King 	struct pci_vt9p_request *preq = req->lr_aux;
162aa693e99SJason King 	size_t n = preq->vsr_niov - preq->vsr_respidx;
163aa693e99SJason King 
164aa693e99SJason King 	memcpy(iov, preq->vsr_iov + preq->vsr_respidx,
165aa693e99SJason King 	    n * sizeof(struct iovec));
166aa693e99SJason King 	*niov = n;
167aa693e99SJason King 	return (0);
168aa693e99SJason King }
169aa693e99SJason King 
170aa693e99SJason King static int
pci_vt9p_send(struct l9p_request * req,const struct iovec * iov __unused,const size_t niov __unused,const size_t iolen,void * arg __unused)17159d65d31SAndy Fiddaman pci_vt9p_send(struct l9p_request *req, const struct iovec *iov __unused,
17259d65d31SAndy Fiddaman     const size_t niov __unused, const size_t iolen, void *arg __unused)
173aa693e99SJason King {
174aa693e99SJason King 	struct pci_vt9p_request *preq = req->lr_aux;
175aa693e99SJason King 	struct pci_vt9p_softc *sc = preq->vsr_sc;
176aa693e99SJason King 
177aa693e99SJason King 	preq->vsr_iolen = iolen;
178aa693e99SJason King 
179aa693e99SJason King 	pthread_mutex_lock(&sc->vsc_mtx);
180aa693e99SJason King 	vq_relchain(&sc->vsc_vq, preq->vsr_idx, preq->vsr_iolen);
181aa693e99SJason King 	vq_endchains(&sc->vsc_vq, 1);
182aa693e99SJason King 	pthread_mutex_unlock(&sc->vsc_mtx);
183aa693e99SJason King 	free(preq);
184aa693e99SJason King 	return (0);
185aa693e99SJason King }
186aa693e99SJason King 
187aa693e99SJason King static void
pci_vt9p_drop(struct l9p_request * req,const struct iovec * iov __unused,size_t niov __unused,void * arg __unused)18859d65d31SAndy Fiddaman pci_vt9p_drop(struct l9p_request *req, const struct iovec *iov __unused,
18959d65d31SAndy Fiddaman     size_t niov __unused, void *arg __unused)
190aa693e99SJason King {
191aa693e99SJason King 	struct pci_vt9p_request *preq = req->lr_aux;
192aa693e99SJason King 	struct pci_vt9p_softc *sc = preq->vsr_sc;
193aa693e99SJason King 
194aa693e99SJason King 	pthread_mutex_lock(&sc->vsc_mtx);
195aa693e99SJason King 	vq_relchain(&sc->vsc_vq, preq->vsr_idx, 0);
196aa693e99SJason King 	vq_endchains(&sc->vsc_vq, 1);
197aa693e99SJason King 	pthread_mutex_unlock(&sc->vsc_mtx);
198aa693e99SJason King 	free(preq);
199aa693e99SJason King }
200aa693e99SJason King 
201aa693e99SJason King static void
pci_vt9p_notify(void * vsc,struct vqueue_info * vq)202aa693e99SJason King pci_vt9p_notify(void *vsc, struct vqueue_info *vq)
203aa693e99SJason King {
204aa693e99SJason King 	struct iovec iov[VT9P_MAX_IOV];
205aa693e99SJason King 	struct pci_vt9p_softc *sc;
206aa693e99SJason King 	struct pci_vt9p_request *preq;
207b0de25cbSAndy Fiddaman 	struct vi_req req;
208b0de25cbSAndy Fiddaman 	int n;
209aa693e99SJason King 
210aa693e99SJason King 	sc = vsc;
211aa693e99SJason King 
212aa693e99SJason King 	while (vq_has_descs(vq)) {
213b0de25cbSAndy Fiddaman 		n = vq_getchain(vq, iov, VT9P_MAX_IOV, &req);
214b0de25cbSAndy Fiddaman 		assert(n >= 1 && n <= VT9P_MAX_IOV);
215aa693e99SJason King 		preq = calloc(1, sizeof(struct pci_vt9p_request));
216aa693e99SJason King #ifndef __FreeBSD__
217aa693e99SJason King 		if (preq == NULL) {
218aa693e99SJason King 			EPRINTLN("virtio-9p: allocation failure: %s",
219aa693e99SJason King 			    strerror(errno));
220aa693e99SJason King 			break;
221aa693e99SJason King 		}
222aa693e99SJason King #endif
223aa693e99SJason King 		preq->vsr_sc = sc;
224b0de25cbSAndy Fiddaman 		preq->vsr_idx = req.idx;
225aa693e99SJason King 		preq->vsr_iov = iov;
226aa693e99SJason King 		preq->vsr_niov = n;
227b0de25cbSAndy Fiddaman 		preq->vsr_respidx = req.readable;
228aa693e99SJason King 
229aa693e99SJason King 		for (int i = 0; i < n; i++) {
230aa693e99SJason King 			DPRINTF(("vt9p: vt9p_notify(): desc%d base=%p, "
231b0de25cbSAndy Fiddaman 			    "len=%zu\r\n", i, iov[i].iov_base,
232b0de25cbSAndy Fiddaman 			    iov[i].iov_len));
233aa693e99SJason King 		}
234aa693e99SJason King 
235aa693e99SJason King 		l9p_connection_recv(sc->vsc_conn, iov, preq->vsr_respidx, preq);
236aa693e99SJason King 	}
237aa693e99SJason King }
238aa693e99SJason King 
239aa693e99SJason King static int
pci_vt9p_legacy_config(nvlist_t * nvl,const char * opts)240aa693e99SJason King pci_vt9p_legacy_config(nvlist_t *nvl, const char *opts)
241aa693e99SJason King {
242aa693e99SJason King 	char *sharename = NULL, *tofree, *token, *tokens;
243aa693e99SJason King 
244aa693e99SJason King 	if (opts == NULL)
245aa693e99SJason King 		return (0);
246aa693e99SJason King 
247aa693e99SJason King 	tokens = tofree = strdup(opts);
248aa693e99SJason King 	while ((token = strsep(&tokens, ",")) != NULL) {
249aa693e99SJason King 		if (strchr(token, '=') != NULL) {
250aa693e99SJason King 			if (sharename != NULL) {
251aa693e99SJason King 				EPRINTLN(
252aa693e99SJason King 			    "virtio-9p: more than one share name given");
253aa693e99SJason King 				return (-1);
254aa693e99SJason King 			}
255aa693e99SJason King 
256aa693e99SJason King 			sharename = strsep(&token, "=");
257aa693e99SJason King 			set_config_value_node(nvl, "sharename", sharename);
258aa693e99SJason King 			set_config_value_node(nvl, "path", token);
259aa693e99SJason King 		} else
260aa693e99SJason King 			set_config_bool_node(nvl, token, true);
261aa693e99SJason King 	}
262aa693e99SJason King 	free(tofree);
263aa693e99SJason King 
264aa693e99SJason King 	return (0);
265aa693e99SJason King }
266aa693e99SJason King 
267aa693e99SJason King static int
pci_vt9p_init(struct pci_devinst * pi,nvlist_t * nvl)268*32640292SAndy Fiddaman pci_vt9p_init(struct pci_devinst *pi, nvlist_t *nvl)
269aa693e99SJason King {
270aa693e99SJason King 	struct pci_vt9p_softc *sc;
271aa693e99SJason King 	const char *value;
272aa693e99SJason King 	const char *sharename;
273aa693e99SJason King 	int rootfd;
274aa693e99SJason King 	bool ro;
275aa693e99SJason King #ifndef WITHOUT_CAPSICUM
276aa693e99SJason King 	cap_rights_t rootcap;
277aa693e99SJason King #endif
278aa693e99SJason King 
279aa693e99SJason King 	ro = get_config_bool_node_default(nvl, "ro", false);
280aa693e99SJason King 
281aa693e99SJason King #ifndef __FreeBSD__
282aa693e99SJason King 	illumos_priv_add_min(PRIV_FILE_DAC_READ, "vt9p");
283aa693e99SJason King 	illumos_priv_add_min(PRIV_FILE_DAC_SEARCH, "vt9p");
284aa693e99SJason King 
285aa693e99SJason King 	if (!ro) {
286aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_CHOWN, "vt9p");
287aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_CHOWN_SELF, "vt9p");
288aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_WRITE, "vt9p");
289aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_DAC_WRITE, "vt9p");
290aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_OWNER, "vt9p");
291aa693e99SJason King 		illumos_priv_add_min(PRIV_FILE_LINK_ANY, "vt9p");
292aa693e99SJason King 	}
293aa693e99SJason King #endif
294aa693e99SJason King 
295aa693e99SJason King 	value = get_config_value_node(nvl, "path");
296aa693e99SJason King 	if (value == NULL) {
297aa693e99SJason King 		EPRINTLN("virtio-9p: path required");
298aa693e99SJason King 		return (1);
299aa693e99SJason King 	}
300aa693e99SJason King 	rootfd = open(value, O_DIRECTORY);
301aa693e99SJason King 	if (rootfd < 0) {
302aa693e99SJason King 		EPRINTLN("virtio-9p: failed to open '%s': %s", value,
303aa693e99SJason King 		    strerror(errno));
304aa693e99SJason King 		return (-1);
305aa693e99SJason King 	}
306aa693e99SJason King 
307aa693e99SJason King 	sharename = get_config_value_node(nvl, "sharename");
308aa693e99SJason King 	if (sharename == NULL) {
309aa693e99SJason King 		EPRINTLN("virtio-9p: share name required");
310aa693e99SJason King 		return (1);
311aa693e99SJason King 	}
312aa693e99SJason King 	if (strlen(sharename) > VT9P_MAXTAGSZ) {
313aa693e99SJason King 		EPRINTLN("virtio-9p: share name too long");
314aa693e99SJason King 		return (1);
315aa693e99SJason King 	}
316aa693e99SJason King 
317aa693e99SJason King 	sc = calloc(1, sizeof(struct pci_vt9p_softc));
31859d65d31SAndy Fiddaman #ifdef	__FreeBSD__
31959d65d31SAndy Fiddaman 	sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config) +
32059d65d31SAndy Fiddaman 	    VT9P_MAXTAGSZ);
32159d65d31SAndy Fiddaman #else
322aa693e99SJason King 	if (sc == NULL) {
323aa693e99SJason King 		EPRINTLN("virtio-9p: soft state allocation failure: %s",
324aa693e99SJason King 		    strerror(errno));
325aa693e99SJason King 		return (1);
326aa693e99SJason King 	}
32759d65d31SAndy Fiddaman 	sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config));
328aa693e99SJason King 	if (sc == NULL) {
329aa693e99SJason King 		EPRINTLN("virtio-9p: vsc_config allocation failure: %s",
330aa693e99SJason King 		    strerror(errno));
331aa693e99SJason King 		return (1);
332aa693e99SJason King 	}
333aa693e99SJason King #endif
334aa693e99SJason King 
335aa693e99SJason King 	pthread_mutex_init(&sc->vsc_mtx, NULL);
336aa693e99SJason King 
337aa693e99SJason King #ifndef WITHOUT_CAPSICUM
338aa693e99SJason King 	cap_rights_init(&rootcap,
339aa693e99SJason King 	    CAP_LOOKUP, CAP_ACL_CHECK, CAP_ACL_DELETE, CAP_ACL_GET,
340aa693e99SJason King 	    CAP_ACL_SET, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT,
341aa693e99SJason King 	    CAP_CREATE, CAP_FCHMODAT, CAP_FCHOWNAT, CAP_FTRUNCATE,
342aa693e99SJason King 	    CAP_LINKAT_SOURCE, CAP_LINKAT_TARGET, CAP_MKDIRAT, CAP_MKNODAT,
343aa693e99SJason King 	    CAP_PREAD, CAP_PWRITE, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET,
344aa693e99SJason King 	    CAP_SEEK, CAP_SYMLINKAT, CAP_UNLINKAT, CAP_EXTATTR_DELETE,
345aa693e99SJason King 	    CAP_EXTATTR_GET, CAP_EXTATTR_LIST, CAP_EXTATTR_SET,
346aa693e99SJason King 	    CAP_FUTIMES, CAP_FSTATFS, CAP_FSYNC, CAP_FPATHCONF);
347aa693e99SJason King 
348aa693e99SJason King 	if (cap_rights_limit(rootfd, &rootcap) != 0)
349aa693e99SJason King 		return (1);
350aa693e99SJason King #endif
351aa693e99SJason King 
352aa693e99SJason King 	sc->vsc_config->tag_len = (uint16_t)strlen(sharename);
353aa693e99SJason King 	memcpy(sc->vsc_config->tag, sharename, sc->vsc_config->tag_len);
354aa693e99SJason King 
355aa693e99SJason King 	if (l9p_backend_fs_init(&sc->vsc_fs_backend, rootfd, ro) != 0) {
356aa693e99SJason King 		errno = ENXIO;
357aa693e99SJason King 		return (1);
358aa693e99SJason King 	}
359aa693e99SJason King 
360aa693e99SJason King 	if (l9p_server_init(&sc->vsc_server, sc->vsc_fs_backend) != 0) {
361aa693e99SJason King 		errno = ENXIO;
362aa693e99SJason King 		return (1);
363aa693e99SJason King 	}
364aa693e99SJason King 
365aa693e99SJason King 	if (l9p_connection_init(sc->vsc_server, &sc->vsc_conn) != 0) {
366aa693e99SJason King 		errno = EIO;
367aa693e99SJason King 		return (1);
368aa693e99SJason King 	}
369aa693e99SJason King 
370aa693e99SJason King 	sc->vsc_conn->lc_msize = L9P_MAX_IOV * PAGE_SIZE;
371aa693e99SJason King 	sc->vsc_conn->lc_lt.lt_get_response_buffer = pci_vt9p_get_buffer;
372aa693e99SJason King 	sc->vsc_conn->lc_lt.lt_send_response = pci_vt9p_send;
373aa693e99SJason King 	sc->vsc_conn->lc_lt.lt_drop_response = pci_vt9p_drop;
374aa693e99SJason King 
375aa693e99SJason King 	vi_softc_linkup(&sc->vsc_vs, &vt9p_vi_consts, sc, pi, &sc->vsc_vq);
376aa693e99SJason King 	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
377aa693e99SJason King 	sc->vsc_vq.vq_qsize = VT9P_RINGSZ;
378aa693e99SJason King 
379aa693e99SJason King 	/* initialize config space */
380aa693e99SJason King 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_9P);
381aa693e99SJason King 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
382aa693e99SJason King 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
383aa693e99SJason King 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_9P);
384aa693e99SJason King 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
385aa693e99SJason King 
386aa693e99SJason King 	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
387aa693e99SJason King 		return (1);
388aa693e99SJason King 	vi_set_io_bar(&sc->vsc_vs, 0);
389aa693e99SJason King 
390aa693e99SJason King 	return (0);
391aa693e99SJason King }
392aa693e99SJason King 
3934f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_de_v9p = {
394aa693e99SJason King 	.pe_emu =	"virtio-9p",
395aa693e99SJason King 	.pe_legacy_config = pci_vt9p_legacy_config,
396aa693e99SJason King 	.pe_init =	pci_vt9p_init,
397aa693e99SJason King 	.pe_barwrite =	vi_pci_write,
398aa693e99SJason King 	.pe_barread =	vi_pci_read
399aa693e99SJason King };
400aa693e99SJason King PCI_EMUL_SET(pci_de_v9p);
401