vmbus_chan.c revision 311366
1/*-
2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2012 NetApp Inc.
4 * Copyright (c) 2012 Citrix Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c 311366 2017-01-05 05:41:33Z sephe $");
31
32#include <sys/param.h>
33#include <sys/bus.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/malloc.h>
37#include <sys/mutex.h>
38#include <sys/smp.h>
39#include <sys/sysctl.h>
40#include <sys/systm.h>
41
42#include <machine/atomic.h>
43#include <machine/stdarg.h>
44
45#include <dev/hyperv/include/hyperv_busdma.h>
46#include <dev/hyperv/include/vmbus_xact.h>
47#include <dev/hyperv/vmbus/hyperv_var.h>
48#include <dev/hyperv/vmbus/vmbus_reg.h>
49#include <dev/hyperv/vmbus/vmbus_var.h>
50#include <dev/hyperv/vmbus/vmbus_brvar.h>
51#include <dev/hyperv/vmbus/vmbus_chanvar.h>
52
53static void			vmbus_chan_update_evtflagcnt(
54				    struct vmbus_softc *,
55				    const struct vmbus_channel *);
56static int			vmbus_chan_close_internal(
57				    struct vmbus_channel *);
58static int			vmbus_chan_sysctl_mnf(SYSCTL_HANDLER_ARGS);
59static void			vmbus_chan_sysctl_create(
60				    struct vmbus_channel *);
61static struct vmbus_channel	*vmbus_chan_alloc(struct vmbus_softc *);
62static void			vmbus_chan_free(struct vmbus_channel *);
63static int			vmbus_chan_add(struct vmbus_channel *);
64static void			vmbus_chan_cpu_default(struct vmbus_channel *);
65static int			vmbus_chan_release(struct vmbus_channel *);
66static void			vmbus_chan_set_chmap(struct vmbus_channel *);
67static void			vmbus_chan_clear_chmap(struct vmbus_channel *);
68static void			vmbus_chan_detach(struct vmbus_channel *);
69static bool			vmbus_chan_wait_revoke(
70				    const struct vmbus_channel *);
71
72static void			vmbus_chan_ins_prilist(struct vmbus_softc *,
73				    struct vmbus_channel *);
74static void			vmbus_chan_rem_prilist(struct vmbus_softc *,
75				    struct vmbus_channel *);
76static void			vmbus_chan_ins_list(struct vmbus_softc *,
77				    struct vmbus_channel *);
78static void			vmbus_chan_rem_list(struct vmbus_softc *,
79				    struct vmbus_channel *);
80static void			vmbus_chan_ins_sublist(struct vmbus_channel *,
81				    struct vmbus_channel *);
82static void			vmbus_chan_rem_sublist(struct vmbus_channel *,
83				    struct vmbus_channel *);
84
85static void			vmbus_chan_task(void *, int);
86static void			vmbus_chan_task_nobatch(void *, int);
87static void			vmbus_chan_clrchmap_task(void *, int);
88static void			vmbus_prichan_attach_task(void *, int);
89static void			vmbus_subchan_attach_task(void *, int);
90static void			vmbus_prichan_detach_task(void *, int);
91static void			vmbus_subchan_detach_task(void *, int);
92
93static void			vmbus_chan_msgproc_choffer(struct vmbus_softc *,
94				    const struct vmbus_message *);
95static void			vmbus_chan_msgproc_chrescind(
96				    struct vmbus_softc *,
97				    const struct vmbus_message *);
98
99static int			vmbus_chan_printf(const struct vmbus_channel *,
100				    const char *, ...) __printflike(2, 3);
101
102/*
103 * Vmbus channel message processing.
104 */
105static const vmbus_chanmsg_proc_t
106vmbus_chan_msgprocs[VMBUS_CHANMSG_TYPE_MAX] = {
107	VMBUS_CHANMSG_PROC(CHOFFER,	vmbus_chan_msgproc_choffer),
108	VMBUS_CHANMSG_PROC(CHRESCIND,	vmbus_chan_msgproc_chrescind),
109
110	VMBUS_CHANMSG_PROC_WAKEUP(CHOPEN_RESP),
111	VMBUS_CHANMSG_PROC_WAKEUP(GPADL_CONNRESP),
112	VMBUS_CHANMSG_PROC_WAKEUP(GPADL_DISCONNRESP)
113};
114
115/*
116 * Notify host that there are data pending on our TX bufring.
117 */
118static __inline void
119vmbus_chan_signal_tx(const struct vmbus_channel *chan)
120{
121	atomic_set_long(chan->ch_evtflag, chan->ch_evtflag_mask);
122	if (chan->ch_txflags & VMBUS_CHAN_TXF_HASMNF)
123		atomic_set_int(chan->ch_montrig, chan->ch_montrig_mask);
124	else
125		hypercall_signal_event(chan->ch_monprm_dma.hv_paddr);
126}
127
128static void
129vmbus_chan_ins_prilist(struct vmbus_softc *sc, struct vmbus_channel *chan)
130{
131
132	mtx_assert(&sc->vmbus_prichan_lock, MA_OWNED);
133	if (atomic_testandset_int(&chan->ch_stflags,
134	    VMBUS_CHAN_ST_ONPRIL_SHIFT))
135		panic("channel is already on the prilist");
136	TAILQ_INSERT_TAIL(&sc->vmbus_prichans, chan, ch_prilink);
137}
138
139static void
140vmbus_chan_rem_prilist(struct vmbus_softc *sc, struct vmbus_channel *chan)
141{
142
143	mtx_assert(&sc->vmbus_prichan_lock, MA_OWNED);
144	if (atomic_testandclear_int(&chan->ch_stflags,
145	    VMBUS_CHAN_ST_ONPRIL_SHIFT) == 0)
146		panic("channel is not on the prilist");
147	TAILQ_REMOVE(&sc->vmbus_prichans, chan, ch_prilink);
148}
149
150static void
151vmbus_chan_ins_sublist(struct vmbus_channel *prichan,
152    struct vmbus_channel *chan)
153{
154
155	mtx_assert(&prichan->ch_subchan_lock, MA_OWNED);
156
157	if (atomic_testandset_int(&chan->ch_stflags,
158	    VMBUS_CHAN_ST_ONSUBL_SHIFT))
159		panic("channel is already on the sublist");
160	TAILQ_INSERT_TAIL(&prichan->ch_subchans, chan, ch_sublink);
161
162	/* Bump sub-channel count. */
163	prichan->ch_subchan_cnt++;
164}
165
166static void
167vmbus_chan_rem_sublist(struct vmbus_channel *prichan,
168    struct vmbus_channel *chan)
169{
170
171	mtx_assert(&prichan->ch_subchan_lock, MA_OWNED);
172
173	KASSERT(prichan->ch_subchan_cnt > 0,
174	    ("invalid subchan_cnt %d", prichan->ch_subchan_cnt));
175	prichan->ch_subchan_cnt--;
176
177	if (atomic_testandclear_int(&chan->ch_stflags,
178	    VMBUS_CHAN_ST_ONSUBL_SHIFT) == 0)
179		panic("channel is not on the sublist");
180	TAILQ_REMOVE(&prichan->ch_subchans, chan, ch_sublink);
181}
182
183static void
184vmbus_chan_ins_list(struct vmbus_softc *sc, struct vmbus_channel *chan)
185{
186
187	mtx_assert(&sc->vmbus_chan_lock, MA_OWNED);
188	if (atomic_testandset_int(&chan->ch_stflags,
189	    VMBUS_CHAN_ST_ONLIST_SHIFT))
190		panic("channel is already on the list");
191	TAILQ_INSERT_TAIL(&sc->vmbus_chans, chan, ch_link);
192}
193
194static void
195vmbus_chan_rem_list(struct vmbus_softc *sc, struct vmbus_channel *chan)
196{
197
198	mtx_assert(&sc->vmbus_chan_lock, MA_OWNED);
199	if (atomic_testandclear_int(&chan->ch_stflags,
200	    VMBUS_CHAN_ST_ONLIST_SHIFT) == 0)
201		panic("channel is not on the list");
202	TAILQ_REMOVE(&sc->vmbus_chans, chan, ch_link);
203}
204
205static int
206vmbus_chan_sysctl_mnf(SYSCTL_HANDLER_ARGS)
207{
208	struct vmbus_channel *chan = arg1;
209	int mnf = 0;
210
211	if (chan->ch_txflags & VMBUS_CHAN_TXF_HASMNF)
212		mnf = 1;
213	return sysctl_handle_int(oidp, &mnf, 0, req);
214}
215
216static void
217vmbus_chan_sysctl_create(struct vmbus_channel *chan)
218{
219	struct sysctl_oid *ch_tree, *chid_tree, *br_tree;
220	struct sysctl_ctx_list *ctx;
221	uint32_t ch_id;
222	char name[16];
223
224	/*
225	 * Add sysctl nodes related to this channel to this
226	 * channel's sysctl ctx, so that they can be destroyed
227	 * independently upon close of this channel, which can
228	 * happen even if the device is not detached.
229	 */
230	ctx = &chan->ch_sysctl_ctx;
231	sysctl_ctx_init(ctx);
232
233	/*
234	 * Create dev.NAME.UNIT.channel tree.
235	 */
236	ch_tree = SYSCTL_ADD_NODE(ctx,
237	    SYSCTL_CHILDREN(device_get_sysctl_tree(chan->ch_dev)),
238	    OID_AUTO, "channel", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
239	if (ch_tree == NULL)
240		return;
241
242	/*
243	 * Create dev.NAME.UNIT.channel.CHANID tree.
244	 */
245	if (VMBUS_CHAN_ISPRIMARY(chan))
246		ch_id = chan->ch_id;
247	else
248		ch_id = chan->ch_prichan->ch_id;
249	snprintf(name, sizeof(name), "%d", ch_id);
250	chid_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(ch_tree),
251	    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
252	if (chid_tree == NULL)
253		return;
254
255	if (!VMBUS_CHAN_ISPRIMARY(chan)) {
256		/*
257		 * Create dev.NAME.UNIT.channel.CHANID.sub tree.
258		 */
259		ch_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(chid_tree),
260		    OID_AUTO, "sub", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
261		if (ch_tree == NULL)
262			return;
263
264		/*
265		 * Create dev.NAME.UNIT.channel.CHANID.sub.SUBIDX tree.
266		 *
267		 * NOTE:
268		 * chid_tree is changed to this new sysctl tree.
269		 */
270		snprintf(name, sizeof(name), "%d", chan->ch_subidx);
271		chid_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(ch_tree),
272		    OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
273		if (chid_tree == NULL)
274			return;
275
276		SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO,
277		    "chanid", CTLFLAG_RD, &chan->ch_id, 0, "channel id");
278	}
279
280	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO,
281	    "cpu", CTLFLAG_RD, &chan->ch_cpuid, 0, "owner CPU id");
282	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO,
283	    "mnf", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
284	    chan, 0, vmbus_chan_sysctl_mnf, "I",
285	    "has monitor notification facilities");
286
287	br_tree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO,
288	    "br", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
289	if (br_tree != NULL) {
290		/*
291		 * Create sysctl tree for RX bufring.
292		 */
293		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_rxbr.rxbr, "rx");
294		/*
295		 * Create sysctl tree for TX bufring.
296		 */
297		vmbus_br_sysctl_create(ctx, br_tree, &chan->ch_txbr.txbr, "tx");
298	}
299}
300
301int
302vmbus_chan_open(struct vmbus_channel *chan, int txbr_size, int rxbr_size,
303    const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg)
304{
305	struct vmbus_chan_br cbr;
306	int error;
307
308	/*
309	 * Allocate the TX+RX bufrings.
310	 */
311	KASSERT(chan->ch_bufring == NULL, ("bufrings are allocated"));
312	chan->ch_bufring = hyperv_dmamem_alloc(bus_get_dma_tag(chan->ch_dev),
313	    PAGE_SIZE, 0, txbr_size + rxbr_size, &chan->ch_bufring_dma,
314	    BUS_DMA_WAITOK);
315	if (chan->ch_bufring == NULL) {
316		vmbus_chan_printf(chan, "bufring allocation failed\n");
317		return (ENOMEM);
318	}
319
320	cbr.cbr = chan->ch_bufring;
321	cbr.cbr_paddr = chan->ch_bufring_dma.hv_paddr;
322	cbr.cbr_txsz = txbr_size;
323	cbr.cbr_rxsz = rxbr_size;
324
325	error = vmbus_chan_open_br(chan, &cbr, udata, udlen, cb, cbarg);
326	if (error) {
327		if (error == EISCONN) {
328			/*
329			 * XXX
330			 * The bufring GPADL is still connected; abandon
331			 * this bufring, instead of having mysterious
332			 * crash or trashed data later on.
333			 */
334			vmbus_chan_printf(chan, "chan%u bufring GPADL "
335			    "is still connected upon channel open error; "
336			    "leak %d bytes memory\n", chan->ch_id,
337			    txbr_size + rxbr_size);
338		} else {
339			hyperv_dmamem_free(&chan->ch_bufring_dma,
340			    chan->ch_bufring);
341		}
342		chan->ch_bufring = NULL;
343	}
344	return (error);
345}
346
347int
348vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr,
349    const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg)
350{
351	struct vmbus_softc *sc = chan->ch_vmbus;
352	const struct vmbus_chanmsg_chopen_resp *resp;
353	const struct vmbus_message *msg;
354	struct vmbus_chanmsg_chopen *req;
355	struct vmbus_msghc *mh;
356	uint32_t status;
357	int error, txbr_size, rxbr_size;
358	task_fn_t *task_fn;
359	uint8_t *br;
360
361	if (udlen > VMBUS_CHANMSG_CHOPEN_UDATA_SIZE) {
362		vmbus_chan_printf(chan,
363		    "invalid udata len %d for chan%u\n", udlen, chan->ch_id);
364		return (EINVAL);
365	}
366
367	br = cbr->cbr;
368	txbr_size = cbr->cbr_txsz;
369	rxbr_size = cbr->cbr_rxsz;
370	KASSERT((txbr_size & PAGE_MASK) == 0,
371	    ("send bufring size is not multiple page"));
372	KASSERT((rxbr_size & PAGE_MASK) == 0,
373	    ("recv bufring size is not multiple page"));
374	KASSERT((cbr->cbr_paddr & PAGE_MASK) == 0,
375	    ("bufring is not page aligned"));
376
377	/*
378	 * Zero out the TX/RX bufrings, in case that they were used before.
379	 */
380	memset(br, 0, txbr_size + rxbr_size);
381
382	if (atomic_testandset_int(&chan->ch_stflags,
383	    VMBUS_CHAN_ST_OPENED_SHIFT))
384		panic("double-open chan%u", chan->ch_id);
385
386	chan->ch_cb = cb;
387	chan->ch_cbarg = cbarg;
388
389	vmbus_chan_update_evtflagcnt(sc, chan);
390
391	chan->ch_tq = VMBUS_PCPU_GET(chan->ch_vmbus, event_tq, chan->ch_cpuid);
392	if (chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD)
393		task_fn = vmbus_chan_task;
394	else
395		task_fn = vmbus_chan_task_nobatch;
396	TASK_INIT(&chan->ch_task, 0, task_fn, chan);
397
398	/* TX bufring comes first */
399	vmbus_txbr_setup(&chan->ch_txbr, br, txbr_size);
400	/* RX bufring immediately follows TX bufring */
401	vmbus_rxbr_setup(&chan->ch_rxbr, br + txbr_size, rxbr_size);
402
403	/* Create sysctl tree for this channel */
404	vmbus_chan_sysctl_create(chan);
405
406	/*
407	 * Connect the bufrings, both RX and TX, to this channel.
408	 */
409	KASSERT(chan->ch_bufring_gpadl == 0,
410	    ("bufring GPADL is still connected"));
411	error = vmbus_chan_gpadl_connect(chan, cbr->cbr_paddr,
412	    txbr_size + rxbr_size, &chan->ch_bufring_gpadl);
413	if (error) {
414		vmbus_chan_printf(chan,
415		    "failed to connect bufring GPADL to chan%u\n", chan->ch_id);
416		goto failed;
417	}
418
419	/*
420	 * Install this channel, before it is opened, but after everything
421	 * else has been setup.
422	 */
423	vmbus_chan_set_chmap(chan);
424
425	/*
426	 * Open channel w/ the bufring GPADL on the target CPU.
427	 */
428	mh = vmbus_msghc_get(sc, sizeof(*req));
429	if (mh == NULL) {
430		vmbus_chan_printf(chan,
431		    "can not get msg hypercall for chopen(chan%u)\n",
432		    chan->ch_id);
433		error = ENXIO;
434		goto failed;
435	}
436
437	req = vmbus_msghc_dataptr(mh);
438	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHOPEN;
439	req->chm_chanid = chan->ch_id;
440	req->chm_openid = chan->ch_id;
441	req->chm_gpadl = chan->ch_bufring_gpadl;
442	req->chm_vcpuid = chan->ch_vcpuid;
443	req->chm_txbr_pgcnt = txbr_size >> PAGE_SHIFT;
444	if (udlen > 0)
445		memcpy(req->chm_udata, udata, udlen);
446
447	error = vmbus_msghc_exec(sc, mh);
448	if (error) {
449		vmbus_chan_printf(chan,
450		    "chopen(chan%u) msg hypercall exec failed: %d\n",
451		    chan->ch_id, error);
452		vmbus_msghc_put(sc, mh);
453		goto failed;
454	}
455
456	msg = vmbus_msghc_wait_result(sc, mh);
457	resp = (const struct vmbus_chanmsg_chopen_resp *)msg->msg_data;
458	status = resp->chm_status;
459
460	vmbus_msghc_put(sc, mh);
461
462	if (status == 0) {
463		if (bootverbose)
464			vmbus_chan_printf(chan, "chan%u opened\n", chan->ch_id);
465		return (0);
466	}
467
468	vmbus_chan_printf(chan, "failed to open chan%u\n", chan->ch_id);
469	error = ENXIO;
470
471failed:
472	sysctl_ctx_free(&chan->ch_sysctl_ctx);
473	vmbus_chan_clear_chmap(chan);
474	if (chan->ch_bufring_gpadl != 0) {
475		int error1;
476
477		error1 = vmbus_chan_gpadl_disconnect(chan,
478		    chan->ch_bufring_gpadl);
479		if (error1) {
480			/*
481			 * Give caller a hint that the bufring GPADL is still
482			 * connected.
483			 */
484			error = EISCONN;
485		}
486		chan->ch_bufring_gpadl = 0;
487	}
488	atomic_clear_int(&chan->ch_stflags, VMBUS_CHAN_ST_OPENED);
489	return (error);
490}
491
492int
493vmbus_chan_gpadl_connect(struct vmbus_channel *chan, bus_addr_t paddr,
494    int size, uint32_t *gpadl0)
495{
496	struct vmbus_softc *sc = chan->ch_vmbus;
497	struct vmbus_msghc *mh;
498	struct vmbus_chanmsg_gpadl_conn *req;
499	const struct vmbus_message *msg;
500	size_t reqsz;
501	uint32_t gpadl, status;
502	int page_count, range_len, i, cnt, error;
503	uint64_t page_id;
504
505	KASSERT(*gpadl0 == 0, ("GPADL is not zero"));
506
507	/*
508	 * Preliminary checks.
509	 */
510
511	KASSERT((size & PAGE_MASK) == 0,
512	    ("invalid GPA size %d, not multiple page size", size));
513	page_count = size >> PAGE_SHIFT;
514
515	KASSERT((paddr & PAGE_MASK) == 0,
516	    ("GPA is not page aligned %jx", (uintmax_t)paddr));
517	page_id = paddr >> PAGE_SHIFT;
518
519	range_len = __offsetof(struct vmbus_gpa_range, gpa_page[page_count]);
520	/*
521	 * We don't support multiple GPA ranges.
522	 */
523	if (range_len > UINT16_MAX) {
524		vmbus_chan_printf(chan, "GPA too large, %d pages\n",
525		    page_count);
526		return EOPNOTSUPP;
527	}
528
529	/*
530	 * Allocate GPADL id.
531	 */
532	gpadl = vmbus_gpadl_alloc(sc);
533
534	/*
535	 * Connect this GPADL to the target channel.
536	 *
537	 * NOTE:
538	 * Since each message can only hold small set of page
539	 * addresses, several messages may be required to
540	 * complete the connection.
541	 */
542	if (page_count > VMBUS_CHANMSG_GPADL_CONN_PGMAX)
543		cnt = VMBUS_CHANMSG_GPADL_CONN_PGMAX;
544	else
545		cnt = page_count;
546	page_count -= cnt;
547
548	reqsz = __offsetof(struct vmbus_chanmsg_gpadl_conn,
549	    chm_range.gpa_page[cnt]);
550	mh = vmbus_msghc_get(sc, reqsz);
551	if (mh == NULL) {
552		vmbus_chan_printf(chan,
553		    "can not get msg hypercall for gpadl_conn(chan%u)\n",
554		    chan->ch_id);
555		return EIO;
556	}
557
558	req = vmbus_msghc_dataptr(mh);
559	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_GPADL_CONN;
560	req->chm_chanid = chan->ch_id;
561	req->chm_gpadl = gpadl;
562	req->chm_range_len = range_len;
563	req->chm_range_cnt = 1;
564	req->chm_range.gpa_len = size;
565	req->chm_range.gpa_ofs = 0;
566	for (i = 0; i < cnt; ++i)
567		req->chm_range.gpa_page[i] = page_id++;
568
569	error = vmbus_msghc_exec(sc, mh);
570	if (error) {
571		vmbus_chan_printf(chan,
572		    "gpadl_conn(chan%u) msg hypercall exec failed: %d\n",
573		    chan->ch_id, error);
574		vmbus_msghc_put(sc, mh);
575		return error;
576	}
577
578	while (page_count > 0) {
579		struct vmbus_chanmsg_gpadl_subconn *subreq;
580
581		if (page_count > VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX)
582			cnt = VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX;
583		else
584			cnt = page_count;
585		page_count -= cnt;
586
587		reqsz = __offsetof(struct vmbus_chanmsg_gpadl_subconn,
588		    chm_gpa_page[cnt]);
589		vmbus_msghc_reset(mh, reqsz);
590
591		subreq = vmbus_msghc_dataptr(mh);
592		subreq->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_GPADL_SUBCONN;
593		subreq->chm_gpadl = gpadl;
594		for (i = 0; i < cnt; ++i)
595			subreq->chm_gpa_page[i] = page_id++;
596
597		vmbus_msghc_exec_noresult(mh);
598	}
599	KASSERT(page_count == 0, ("invalid page count %d", page_count));
600
601	msg = vmbus_msghc_wait_result(sc, mh);
602	status = ((const struct vmbus_chanmsg_gpadl_connresp *)
603	    msg->msg_data)->chm_status;
604
605	vmbus_msghc_put(sc, mh);
606
607	if (status != 0) {
608		vmbus_chan_printf(chan, "gpadl_conn(chan%u) failed: %u\n",
609		    chan->ch_id, status);
610		return EIO;
611	}
612
613	/* Done; commit the GPADL id. */
614	*gpadl0 = gpadl;
615	if (bootverbose) {
616		vmbus_chan_printf(chan, "gpadl_conn(chan%u) succeeded\n",
617		    chan->ch_id);
618	}
619	return 0;
620}
621
622static bool
623vmbus_chan_wait_revoke(const struct vmbus_channel *chan)
624{
625#define WAIT_COUNT	200	/* 200ms */
626
627	int i;
628
629	for (i = 0; i < WAIT_COUNT; ++i) {
630		if (vmbus_chan_is_revoked(chan))
631			return (true);
632		/* Not sure about the context; use busy-wait. */
633		DELAY(1000);
634	}
635	return (false);
636
637#undef WAIT_COUNT
638}
639
640/*
641 * Disconnect the GPA from the target channel
642 */
643int
644vmbus_chan_gpadl_disconnect(struct vmbus_channel *chan, uint32_t gpadl)
645{
646	struct vmbus_softc *sc = chan->ch_vmbus;
647	struct vmbus_msghc *mh;
648	struct vmbus_chanmsg_gpadl_disconn *req;
649	int error;
650
651	KASSERT(gpadl != 0, ("GPADL is zero"));
652
653	mh = vmbus_msghc_get(sc, sizeof(*req));
654	if (mh == NULL) {
655		vmbus_chan_printf(chan,
656		    "can not get msg hypercall for gpadl_disconn(chan%u)\n",
657		    chan->ch_id);
658		return (EBUSY);
659	}
660
661	req = vmbus_msghc_dataptr(mh);
662	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_GPADL_DISCONN;
663	req->chm_chanid = chan->ch_id;
664	req->chm_gpadl = gpadl;
665
666	error = vmbus_msghc_exec(sc, mh);
667	if (error) {
668		vmbus_msghc_put(sc, mh);
669
670		if (vmbus_chan_wait_revoke(chan)) {
671			/*
672			 * Error is benign; this channel is revoked,
673			 * so this GPADL will not be touched anymore.
674			 */
675			vmbus_chan_printf(chan,
676			    "gpadl_disconn(revoked chan%u) msg hypercall "
677			    "exec failed: %d\n", chan->ch_id, error);
678			return (0);
679		}
680		vmbus_chan_printf(chan,
681		    "gpadl_disconn(chan%u) msg hypercall exec failed: %d\n",
682		    chan->ch_id, error);
683		return (error);
684	}
685
686	vmbus_msghc_wait_result(sc, mh);
687	/* Discard result; no useful information */
688	vmbus_msghc_put(sc, mh);
689
690	return (0);
691}
692
693static void
694vmbus_chan_detach(struct vmbus_channel *chan)
695{
696	int refs;
697
698	KASSERT(chan->ch_refs > 0, ("chan%u: invalid refcnt %d",
699	    chan->ch_id, chan->ch_refs));
700	refs = atomic_fetchadd_int(&chan->ch_refs, -1);
701#ifdef INVARIANTS
702	if (VMBUS_CHAN_ISPRIMARY(chan)) {
703		KASSERT(refs == 1, ("chan%u: invalid refcnt %d for prichan",
704		    chan->ch_id, refs + 1));
705	}
706#endif
707	if (refs == 1) {
708		/*
709		 * Detach the target channel.
710		 */
711		if (bootverbose) {
712			vmbus_chan_printf(chan, "chan%u detached\n",
713			    chan->ch_id);
714		}
715		taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task);
716	}
717}
718
719static void
720vmbus_chan_clrchmap_task(void *xchan, int pending __unused)
721{
722	struct vmbus_channel *chan = xchan;
723
724	critical_enter();
725	chan->ch_vmbus->vmbus_chmap[chan->ch_id] = NULL;
726	critical_exit();
727}
728
729static void
730vmbus_chan_clear_chmap(struct vmbus_channel *chan)
731{
732	struct task chmap_task;
733
734	TASK_INIT(&chmap_task, 0, vmbus_chan_clrchmap_task, chan);
735	taskqueue_enqueue(chan->ch_tq, &chmap_task);
736	taskqueue_drain(chan->ch_tq, &chmap_task);
737}
738
739static void
740vmbus_chan_set_chmap(struct vmbus_channel *chan)
741{
742	__compiler_membar();
743	chan->ch_vmbus->vmbus_chmap[chan->ch_id] = chan;
744}
745
746static int
747vmbus_chan_close_internal(struct vmbus_channel *chan)
748{
749	struct vmbus_softc *sc = chan->ch_vmbus;
750	struct vmbus_msghc *mh;
751	struct vmbus_chanmsg_chclose *req;
752	uint32_t old_stflags;
753	int error;
754
755	/*
756	 * NOTE:
757	 * Sub-channels are closed upon their primary channel closing,
758	 * so they can be closed even before they are opened.
759	 */
760	for (;;) {
761		old_stflags = chan->ch_stflags;
762		if (atomic_cmpset_int(&chan->ch_stflags, old_stflags,
763		    old_stflags & ~VMBUS_CHAN_ST_OPENED))
764			break;
765	}
766	if ((old_stflags & VMBUS_CHAN_ST_OPENED) == 0) {
767		/* Not opened yet; done */
768		if (bootverbose) {
769			vmbus_chan_printf(chan, "chan%u not opened\n",
770			    chan->ch_id);
771		}
772		return (0);
773	}
774
775	/*
776	 * Free this channel's sysctl tree attached to its device's
777	 * sysctl tree.
778	 */
779	sysctl_ctx_free(&chan->ch_sysctl_ctx);
780
781	/*
782	 * NOTE:
783	 * Order is critical.  This channel _must_ be uninstalled first,
784	 * else the channel task may be enqueued by the IDT after it has
785	 * been drained.
786	 */
787	vmbus_chan_clear_chmap(chan);
788	taskqueue_drain(chan->ch_tq, &chan->ch_task);
789	chan->ch_tq = NULL;
790
791	/*
792	 * Close this channel.
793	 */
794	mh = vmbus_msghc_get(sc, sizeof(*req));
795	if (mh == NULL) {
796		vmbus_chan_printf(chan,
797		    "can not get msg hypercall for chclose(chan%u)\n",
798		    chan->ch_id);
799		error = ENXIO;
800		goto disconnect;
801	}
802
803	req = vmbus_msghc_dataptr(mh);
804	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHCLOSE;
805	req->chm_chanid = chan->ch_id;
806
807	error = vmbus_msghc_exec_noresult(mh);
808	vmbus_msghc_put(sc, mh);
809
810	if (error) {
811		vmbus_chan_printf(chan,
812		    "chclose(chan%u) msg hypercall exec failed: %d\n",
813		    chan->ch_id, error);
814		goto disconnect;
815	}
816
817	if (bootverbose)
818		vmbus_chan_printf(chan, "chan%u closed\n", chan->ch_id);
819
820disconnect:
821	/*
822	 * Disconnect the TX+RX bufrings from this channel.
823	 */
824	if (chan->ch_bufring_gpadl != 0) {
825		int error1;
826
827		error1 = vmbus_chan_gpadl_disconnect(chan,
828		    chan->ch_bufring_gpadl);
829		if (error1) {
830			/*
831			 * XXX
832			 * The bufring GPADL is still connected; abandon
833			 * this bufring, instead of having mysterious
834			 * crash or trashed data later on.
835			 */
836			vmbus_chan_printf(chan, "chan%u bufring GPADL "
837			    "is still connected after close\n", chan->ch_id);
838			chan->ch_bufring = NULL;
839			/*
840			 * Give caller a hint that the bufring GPADL is
841			 * still connected.
842			 */
843			error = EISCONN;
844		}
845		chan->ch_bufring_gpadl = 0;
846	}
847
848	/*
849	 * Destroy the TX+RX bufrings.
850	 */
851	if (chan->ch_bufring != NULL) {
852		hyperv_dmamem_free(&chan->ch_bufring_dma, chan->ch_bufring);
853		chan->ch_bufring = NULL;
854	}
855	return (error);
856}
857
858int
859vmbus_chan_close_direct(struct vmbus_channel *chan)
860{
861	int error;
862
863#ifdef INVARIANTS
864	if (VMBUS_CHAN_ISPRIMARY(chan)) {
865		struct vmbus_channel *subchan;
866
867		/*
868		 * All sub-channels _must_ have been closed, or are _not_
869		 * opened at all.
870		 */
871		mtx_lock(&chan->ch_subchan_lock);
872		TAILQ_FOREACH(subchan, &chan->ch_subchans, ch_sublink) {
873			KASSERT(
874			   (subchan->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0,
875			   ("chan%u: subchan%u is still opened",
876			    chan->ch_id, subchan->ch_subidx));
877		}
878		mtx_unlock(&chan->ch_subchan_lock);
879	}
880#endif
881
882	error = vmbus_chan_close_internal(chan);
883	if (!VMBUS_CHAN_ISPRIMARY(chan)) {
884		/*
885		 * This sub-channel is referenced, when it is linked to
886		 * the primary channel; drop that reference now.
887		 */
888		vmbus_chan_detach(chan);
889	}
890	return (error);
891}
892
893/*
894 * Caller should make sure that all sub-channels have
895 * been added to 'chan' and all to-be-closed channels
896 * are not being opened.
897 */
898void
899vmbus_chan_close(struct vmbus_channel *chan)
900{
901	int subchan_cnt;
902
903	if (!VMBUS_CHAN_ISPRIMARY(chan)) {
904		/*
905		 * Sub-channel is closed when its primary channel
906		 * is closed; done.
907		 */
908		return;
909	}
910
911	/*
912	 * Close all sub-channels, if any.
913	 */
914	subchan_cnt = chan->ch_subchan_cnt;
915	if (subchan_cnt > 0) {
916		struct vmbus_channel **subchan;
917		int i;
918
919		subchan = vmbus_subchan_get(chan, subchan_cnt);
920		for (i = 0; i < subchan_cnt; ++i) {
921			vmbus_chan_close_internal(subchan[i]);
922			/*
923			 * This sub-channel is referenced, when it is
924			 * linked to the primary channel; drop that
925			 * reference now.
926			 */
927			vmbus_chan_detach(subchan[i]);
928		}
929		vmbus_subchan_rel(subchan, subchan_cnt);
930	}
931
932	/* Then close the primary channel. */
933	vmbus_chan_close_internal(chan);
934}
935
936void
937vmbus_chan_intr_drain(struct vmbus_channel *chan)
938{
939
940	taskqueue_drain(chan->ch_tq, &chan->ch_task);
941}
942
943int
944vmbus_chan_send(struct vmbus_channel *chan, uint16_t type, uint16_t flags,
945    void *data, int dlen, uint64_t xactid)
946{
947	struct vmbus_chanpkt pkt;
948	int pktlen, pad_pktlen, hlen, error;
949	uint64_t pad = 0;
950	struct iovec iov[3];
951	boolean_t send_evt;
952
953	hlen = sizeof(pkt);
954	pktlen = hlen + dlen;
955	pad_pktlen = VMBUS_CHANPKT_TOTLEN(pktlen);
956	KASSERT(pad_pktlen <= vmbus_txbr_maxpktsz(&chan->ch_txbr),
957	    ("invalid packet size %d", pad_pktlen));
958
959	pkt.cp_hdr.cph_type = type;
960	pkt.cp_hdr.cph_flags = flags;
961	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_hlen, hlen);
962	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_tlen, pad_pktlen);
963	pkt.cp_hdr.cph_xactid = xactid;
964
965	iov[0].iov_base = &pkt;
966	iov[0].iov_len = hlen;
967	iov[1].iov_base = data;
968	iov[1].iov_len = dlen;
969	iov[2].iov_base = &pad;
970	iov[2].iov_len = pad_pktlen - pktlen;
971
972	error = vmbus_txbr_write(&chan->ch_txbr, iov, 3, &send_evt);
973	if (!error && send_evt)
974		vmbus_chan_signal_tx(chan);
975	return error;
976}
977
978int
979vmbus_chan_send_sglist(struct vmbus_channel *chan,
980    struct vmbus_gpa sg[], int sglen, void *data, int dlen, uint64_t xactid)
981{
982	struct vmbus_chanpkt_sglist pkt;
983	int pktlen, pad_pktlen, hlen, error;
984	struct iovec iov[4];
985	boolean_t send_evt;
986	uint64_t pad = 0;
987
988	hlen = __offsetof(struct vmbus_chanpkt_sglist, cp_gpa[sglen]);
989	pktlen = hlen + dlen;
990	pad_pktlen = VMBUS_CHANPKT_TOTLEN(pktlen);
991	KASSERT(pad_pktlen <= vmbus_txbr_maxpktsz(&chan->ch_txbr),
992	    ("invalid packet size %d", pad_pktlen));
993
994	pkt.cp_hdr.cph_type = VMBUS_CHANPKT_TYPE_GPA;
995	pkt.cp_hdr.cph_flags = VMBUS_CHANPKT_FLAG_RC;
996	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_hlen, hlen);
997	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_tlen, pad_pktlen);
998	pkt.cp_hdr.cph_xactid = xactid;
999	pkt.cp_rsvd = 0;
1000	pkt.cp_gpa_cnt = sglen;
1001
1002	iov[0].iov_base = &pkt;
1003	iov[0].iov_len = sizeof(pkt);
1004	iov[1].iov_base = sg;
1005	iov[1].iov_len = sizeof(struct vmbus_gpa) * sglen;
1006	iov[2].iov_base = data;
1007	iov[2].iov_len = dlen;
1008	iov[3].iov_base = &pad;
1009	iov[3].iov_len = pad_pktlen - pktlen;
1010
1011	error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt);
1012	if (!error && send_evt)
1013		vmbus_chan_signal_tx(chan);
1014	return error;
1015}
1016
1017int
1018vmbus_chan_send_prplist(struct vmbus_channel *chan,
1019    struct vmbus_gpa_range *prp, int prp_cnt, void *data, int dlen,
1020    uint64_t xactid)
1021{
1022	struct vmbus_chanpkt_prplist pkt;
1023	int pktlen, pad_pktlen, hlen, error;
1024	struct iovec iov[4];
1025	boolean_t send_evt;
1026	uint64_t pad = 0;
1027
1028	hlen = __offsetof(struct vmbus_chanpkt_prplist,
1029	    cp_range[0].gpa_page[prp_cnt]);
1030	pktlen = hlen + dlen;
1031	pad_pktlen = VMBUS_CHANPKT_TOTLEN(pktlen);
1032	KASSERT(pad_pktlen <= vmbus_txbr_maxpktsz(&chan->ch_txbr),
1033	    ("invalid packet size %d", pad_pktlen));
1034
1035	pkt.cp_hdr.cph_type = VMBUS_CHANPKT_TYPE_GPA;
1036	pkt.cp_hdr.cph_flags = VMBUS_CHANPKT_FLAG_RC;
1037	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_hlen, hlen);
1038	VMBUS_CHANPKT_SETLEN(pkt.cp_hdr.cph_tlen, pad_pktlen);
1039	pkt.cp_hdr.cph_xactid = xactid;
1040	pkt.cp_rsvd = 0;
1041	pkt.cp_range_cnt = 1;
1042
1043	iov[0].iov_base = &pkt;
1044	iov[0].iov_len = sizeof(pkt);
1045	iov[1].iov_base = prp;
1046	iov[1].iov_len = __offsetof(struct vmbus_gpa_range, gpa_page[prp_cnt]);
1047	iov[2].iov_base = data;
1048	iov[2].iov_len = dlen;
1049	iov[3].iov_base = &pad;
1050	iov[3].iov_len = pad_pktlen - pktlen;
1051
1052	error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt);
1053	if (!error && send_evt)
1054		vmbus_chan_signal_tx(chan);
1055	return error;
1056}
1057
1058int
1059vmbus_chan_recv(struct vmbus_channel *chan, void *data, int *dlen0,
1060    uint64_t *xactid)
1061{
1062	struct vmbus_chanpkt_hdr pkt;
1063	int error, dlen, hlen;
1064
1065	error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt));
1066	if (error)
1067		return (error);
1068
1069	if (__predict_false(pkt.cph_hlen < VMBUS_CHANPKT_HLEN_MIN)) {
1070		vmbus_chan_printf(chan, "invalid hlen %u\n", pkt.cph_hlen);
1071		/* XXX this channel is dead actually. */
1072		return (EIO);
1073	}
1074	if (__predict_false(pkt.cph_hlen > pkt.cph_tlen)) {
1075		vmbus_chan_printf(chan, "invalid hlen %u and tlen %u\n",
1076		    pkt.cph_hlen, pkt.cph_tlen);
1077		/* XXX this channel is dead actually. */
1078		return (EIO);
1079	}
1080
1081	hlen = VMBUS_CHANPKT_GETLEN(pkt.cph_hlen);
1082	dlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen) - hlen;
1083
1084	if (*dlen0 < dlen) {
1085		/* Return the size of this packet's data. */
1086		*dlen0 = dlen;
1087		return (ENOBUFS);
1088	}
1089
1090	*xactid = pkt.cph_xactid;
1091	*dlen0 = dlen;
1092
1093	/* Skip packet header */
1094	error = vmbus_rxbr_read(&chan->ch_rxbr, data, dlen, hlen);
1095	KASSERT(!error, ("vmbus_rxbr_read failed"));
1096
1097	return (0);
1098}
1099
1100int
1101vmbus_chan_recv_pkt(struct vmbus_channel *chan,
1102    struct vmbus_chanpkt_hdr *pkt, int *pktlen0)
1103{
1104	int error, pktlen, pkt_hlen;
1105
1106	pkt_hlen = sizeof(*pkt);
1107	error = vmbus_rxbr_peek(&chan->ch_rxbr, pkt, pkt_hlen);
1108	if (error)
1109		return (error);
1110
1111	if (__predict_false(pkt->cph_hlen < VMBUS_CHANPKT_HLEN_MIN)) {
1112		vmbus_chan_printf(chan, "invalid hlen %u\n", pkt->cph_hlen);
1113		/* XXX this channel is dead actually. */
1114		return (EIO);
1115	}
1116	if (__predict_false(pkt->cph_hlen > pkt->cph_tlen)) {
1117		vmbus_chan_printf(chan, "invalid hlen %u and tlen %u\n",
1118		    pkt->cph_hlen, pkt->cph_tlen);
1119		/* XXX this channel is dead actually. */
1120		return (EIO);
1121	}
1122
1123	pktlen = VMBUS_CHANPKT_GETLEN(pkt->cph_tlen);
1124	if (*pktlen0 < pktlen) {
1125		/* Return the size of this packet. */
1126		*pktlen0 = pktlen;
1127		return (ENOBUFS);
1128	}
1129	*pktlen0 = pktlen;
1130
1131	/*
1132	 * Skip the fixed-size packet header, which has been filled
1133	 * by the above vmbus_rxbr_peek().
1134	 */
1135	error = vmbus_rxbr_read(&chan->ch_rxbr, pkt + 1,
1136	    pktlen - pkt_hlen, pkt_hlen);
1137	KASSERT(!error, ("vmbus_rxbr_read failed"));
1138
1139	return (0);
1140}
1141
1142static void
1143vmbus_chan_task(void *xchan, int pending __unused)
1144{
1145	struct vmbus_channel *chan = xchan;
1146	vmbus_chan_callback_t cb = chan->ch_cb;
1147	void *cbarg = chan->ch_cbarg;
1148
1149	/*
1150	 * Optimize host to guest signaling by ensuring:
1151	 * 1. While reading the channel, we disable interrupts from
1152	 *    host.
1153	 * 2. Ensure that we process all posted messages from the host
1154	 *    before returning from this callback.
1155	 * 3. Once we return, enable signaling from the host. Once this
1156	 *    state is set we check to see if additional packets are
1157	 *    available to read. In this case we repeat the process.
1158	 *
1159	 * NOTE: Interrupt has been disabled in the ISR.
1160	 */
1161	for (;;) {
1162		uint32_t left;
1163
1164		cb(chan, cbarg);
1165
1166		left = vmbus_rxbr_intr_unmask(&chan->ch_rxbr);
1167		if (left == 0) {
1168			/* No more data in RX bufring; done */
1169			break;
1170		}
1171		vmbus_rxbr_intr_mask(&chan->ch_rxbr);
1172	}
1173}
1174
1175static void
1176vmbus_chan_task_nobatch(void *xchan, int pending __unused)
1177{
1178	struct vmbus_channel *chan = xchan;
1179
1180	chan->ch_cb(chan, chan->ch_cbarg);
1181}
1182
1183static __inline void
1184vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags,
1185    int flag_cnt)
1186{
1187	int f;
1188
1189	for (f = 0; f < flag_cnt; ++f) {
1190		uint32_t chid_base;
1191		u_long flags;
1192		int chid_ofs;
1193
1194		if (event_flags[f] == 0)
1195			continue;
1196
1197		flags = atomic_swap_long(&event_flags[f], 0);
1198		chid_base = f << VMBUS_EVTFLAG_SHIFT;
1199
1200		while ((chid_ofs = ffsl(flags)) != 0) {
1201			struct vmbus_channel *chan;
1202
1203			--chid_ofs; /* NOTE: ffsl is 1-based */
1204			flags &= ~(1UL << chid_ofs);
1205
1206			chan = sc->vmbus_chmap[chid_base + chid_ofs];
1207			if (__predict_false(chan == NULL)) {
1208				/* Channel is closed. */
1209				continue;
1210			}
1211			__compiler_membar();
1212
1213			if (chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD)
1214				vmbus_rxbr_intr_mask(&chan->ch_rxbr);
1215			taskqueue_enqueue(chan->ch_tq, &chan->ch_task);
1216		}
1217	}
1218}
1219
1220void
1221vmbus_event_proc(struct vmbus_softc *sc, int cpu)
1222{
1223	struct vmbus_evtflags *eventf;
1224
1225	/*
1226	 * On Host with Win8 or above, the event page can be checked directly
1227	 * to get the id of the channel that has the pending interrupt.
1228	 */
1229	eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
1230	vmbus_event_flags_proc(sc, eventf->evt_flags,
1231	    VMBUS_PCPU_GET(sc, event_flags_cnt, cpu));
1232}
1233
1234void
1235vmbus_event_proc_compat(struct vmbus_softc *sc, int cpu)
1236{
1237	struct vmbus_evtflags *eventf;
1238
1239	eventf = VMBUS_PCPU_GET(sc, event_flags, cpu) + VMBUS_SINT_MESSAGE;
1240	if (atomic_testandclear_long(&eventf->evt_flags[0], 0)) {
1241		vmbus_event_flags_proc(sc, sc->vmbus_rx_evtflags,
1242		    VMBUS_CHAN_MAX_COMPAT >> VMBUS_EVTFLAG_SHIFT);
1243	}
1244}
1245
1246static void
1247vmbus_chan_update_evtflagcnt(struct vmbus_softc *sc,
1248    const struct vmbus_channel *chan)
1249{
1250	volatile int *flag_cnt_ptr;
1251	int flag_cnt;
1252
1253	flag_cnt = (chan->ch_id / VMBUS_EVTFLAG_LEN) + 1;
1254	flag_cnt_ptr = VMBUS_PCPU_PTR(sc, event_flags_cnt, chan->ch_cpuid);
1255
1256	for (;;) {
1257		int old_flag_cnt;
1258
1259		old_flag_cnt = *flag_cnt_ptr;
1260		if (old_flag_cnt >= flag_cnt)
1261			break;
1262		if (atomic_cmpset_int(flag_cnt_ptr, old_flag_cnt, flag_cnt)) {
1263			if (bootverbose) {
1264				vmbus_chan_printf(chan,
1265				    "chan%u update cpu%d flag_cnt to %d\n",
1266				    chan->ch_id, chan->ch_cpuid, flag_cnt);
1267			}
1268			break;
1269		}
1270	}
1271}
1272
1273static struct vmbus_channel *
1274vmbus_chan_alloc(struct vmbus_softc *sc)
1275{
1276	struct vmbus_channel *chan;
1277
1278	chan = malloc(sizeof(*chan), M_DEVBUF, M_WAITOK | M_ZERO);
1279
1280	chan->ch_monprm = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
1281	    HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param),
1282	    &chan->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
1283	if (chan->ch_monprm == NULL) {
1284		device_printf(sc->vmbus_dev, "monprm alloc failed\n");
1285		free(chan, M_DEVBUF);
1286		return NULL;
1287	}
1288
1289	chan->ch_refs = 1;
1290	chan->ch_vmbus = sc;
1291	mtx_init(&chan->ch_subchan_lock, "vmbus subchan", NULL, MTX_DEF);
1292	sx_init(&chan->ch_orphan_lock, "vmbus chorphan");
1293	TAILQ_INIT(&chan->ch_subchans);
1294	vmbus_rxbr_init(&chan->ch_rxbr);
1295	vmbus_txbr_init(&chan->ch_txbr);
1296
1297	return chan;
1298}
1299
1300static void
1301vmbus_chan_free(struct vmbus_channel *chan)
1302{
1303
1304	KASSERT(TAILQ_EMPTY(&chan->ch_subchans) && chan->ch_subchan_cnt == 0,
1305	    ("still owns sub-channels"));
1306	KASSERT((chan->ch_stflags &
1307	    (VMBUS_CHAN_ST_OPENED |
1308	     VMBUS_CHAN_ST_ONPRIL |
1309	     VMBUS_CHAN_ST_ONSUBL |
1310	     VMBUS_CHAN_ST_ONLIST)) == 0, ("free busy channel"));
1311	KASSERT(chan->ch_orphan_xact == NULL,
1312	    ("still has orphan xact installed"));
1313	KASSERT(chan->ch_refs == 0, ("chan%u: invalid refcnt %d",
1314	    chan->ch_id, chan->ch_refs));
1315
1316	hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm);
1317	mtx_destroy(&chan->ch_subchan_lock);
1318	sx_destroy(&chan->ch_orphan_lock);
1319	vmbus_rxbr_deinit(&chan->ch_rxbr);
1320	vmbus_txbr_deinit(&chan->ch_txbr);
1321	free(chan, M_DEVBUF);
1322}
1323
1324static int
1325vmbus_chan_add(struct vmbus_channel *newchan)
1326{
1327	struct vmbus_softc *sc = newchan->ch_vmbus;
1328	struct vmbus_channel *prichan;
1329
1330	if (newchan->ch_id == 0) {
1331		/*
1332		 * XXX
1333		 * Chan0 will neither be processed nor should be offered;
1334		 * skip it.
1335		 */
1336		device_printf(sc->vmbus_dev, "got chan0 offer, discard\n");
1337		return EINVAL;
1338	} else if (newchan->ch_id >= VMBUS_CHAN_MAX) {
1339		device_printf(sc->vmbus_dev, "invalid chan%u offer\n",
1340		    newchan->ch_id);
1341		return EINVAL;
1342	}
1343
1344	mtx_lock(&sc->vmbus_prichan_lock);
1345	TAILQ_FOREACH(prichan, &sc->vmbus_prichans, ch_prilink) {
1346		/*
1347		 * Sub-channel will have the same type GUID and instance
1348		 * GUID as its primary channel.
1349		 */
1350		if (memcmp(&prichan->ch_guid_type, &newchan->ch_guid_type,
1351		    sizeof(struct hyperv_guid)) == 0 &&
1352		    memcmp(&prichan->ch_guid_inst, &newchan->ch_guid_inst,
1353		    sizeof(struct hyperv_guid)) == 0)
1354			break;
1355	}
1356	if (VMBUS_CHAN_ISPRIMARY(newchan)) {
1357		if (prichan == NULL) {
1358			/* Install the new primary channel */
1359			vmbus_chan_ins_prilist(sc, newchan);
1360			mtx_unlock(&sc->vmbus_prichan_lock);
1361			goto done;
1362		} else {
1363			mtx_unlock(&sc->vmbus_prichan_lock);
1364			device_printf(sc->vmbus_dev,
1365			    "duplicated primary chan%u\n", newchan->ch_id);
1366			return EINVAL;
1367		}
1368	} else { /* Sub-channel */
1369		if (prichan == NULL) {
1370			mtx_unlock(&sc->vmbus_prichan_lock);
1371			device_printf(sc->vmbus_dev,
1372			    "no primary chan for chan%u\n", newchan->ch_id);
1373			return EINVAL;
1374		}
1375		/*
1376		 * Found the primary channel for this sub-channel and
1377		 * move on.
1378		 *
1379		 * XXX refcnt prichan
1380		 */
1381	}
1382	mtx_unlock(&sc->vmbus_prichan_lock);
1383
1384	/*
1385	 * This is a sub-channel; link it with the primary channel.
1386	 */
1387	KASSERT(!VMBUS_CHAN_ISPRIMARY(newchan),
1388	    ("new channel is not sub-channel"));
1389	KASSERT(prichan != NULL, ("no primary channel"));
1390
1391	/*
1392	 * Reference count this sub-channel; it will be dereferenced
1393	 * when this sub-channel is closed.
1394	 */
1395	KASSERT(newchan->ch_refs == 1, ("chan%u: invalid refcnt %d",
1396	    newchan->ch_id, newchan->ch_refs));
1397	atomic_add_int(&newchan->ch_refs, 1);
1398
1399	newchan->ch_prichan = prichan;
1400	newchan->ch_dev = prichan->ch_dev;
1401
1402	mtx_lock(&prichan->ch_subchan_lock);
1403	vmbus_chan_ins_sublist(prichan, newchan);
1404	mtx_unlock(&prichan->ch_subchan_lock);
1405	/*
1406	 * Notify anyone that is interested in this sub-channel,
1407	 * after this sub-channel is setup.
1408	 */
1409	wakeup(prichan);
1410done:
1411	/*
1412	 * Hook this channel up for later revocation.
1413	 */
1414	mtx_lock(&sc->vmbus_chan_lock);
1415	vmbus_chan_ins_list(sc, newchan);
1416	mtx_unlock(&sc->vmbus_chan_lock);
1417
1418	if (bootverbose) {
1419		vmbus_chan_printf(newchan, "chan%u subidx%u offer\n",
1420		    newchan->ch_id, newchan->ch_subidx);
1421	}
1422
1423	/* Select default cpu for this channel. */
1424	vmbus_chan_cpu_default(newchan);
1425
1426	return 0;
1427}
1428
1429void
1430vmbus_chan_cpu_set(struct vmbus_channel *chan, int cpu)
1431{
1432	KASSERT(cpu >= 0 && cpu < mp_ncpus, ("invalid cpu %d", cpu));
1433
1434	if (chan->ch_vmbus->vmbus_version == VMBUS_VERSION_WS2008 ||
1435	    chan->ch_vmbus->vmbus_version == VMBUS_VERSION_WIN7) {
1436		/* Only cpu0 is supported */
1437		cpu = 0;
1438	}
1439
1440	chan->ch_cpuid = cpu;
1441	chan->ch_vcpuid = VMBUS_PCPU_GET(chan->ch_vmbus, vcpuid, cpu);
1442
1443	if (bootverbose) {
1444		vmbus_chan_printf(chan,
1445		    "chan%u assigned to cpu%u [vcpu%u]\n",
1446		    chan->ch_id, chan->ch_cpuid, chan->ch_vcpuid);
1447	}
1448}
1449
1450void
1451vmbus_chan_cpu_rr(struct vmbus_channel *chan)
1452{
1453	static uint32_t vmbus_chan_nextcpu;
1454	int cpu;
1455
1456	cpu = atomic_fetchadd_int(&vmbus_chan_nextcpu, 1) % mp_ncpus;
1457	vmbus_chan_cpu_set(chan, cpu);
1458}
1459
1460static void
1461vmbus_chan_cpu_default(struct vmbus_channel *chan)
1462{
1463	/*
1464	 * By default, pin the channel to cpu0.  Devices having
1465	 * special channel-cpu mapping requirement should call
1466	 * vmbus_chan_cpu_{set,rr}().
1467	 */
1468	vmbus_chan_cpu_set(chan, 0);
1469}
1470
1471static void
1472vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
1473    const struct vmbus_message *msg)
1474{
1475	const struct vmbus_chanmsg_choffer *offer;
1476	struct vmbus_channel *chan;
1477	task_fn_t *detach_fn, *attach_fn;
1478	int error;
1479
1480	offer = (const struct vmbus_chanmsg_choffer *)msg->msg_data;
1481
1482	chan = vmbus_chan_alloc(sc);
1483	if (chan == NULL) {
1484		device_printf(sc->vmbus_dev, "allocate chan%u failed\n",
1485		    offer->chm_chanid);
1486		return;
1487	}
1488
1489	chan->ch_id = offer->chm_chanid;
1490	chan->ch_subidx = offer->chm_subidx;
1491	chan->ch_guid_type = offer->chm_chtype;
1492	chan->ch_guid_inst = offer->chm_chinst;
1493
1494	/* Batch reading is on by default */
1495	chan->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
1496
1497	chan->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
1498	if (sc->vmbus_version != VMBUS_VERSION_WS2008)
1499		chan->ch_monprm->mp_connid = offer->chm_connid;
1500
1501	if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) {
1502		int trig_idx;
1503
1504		/*
1505		 * Setup MNF stuffs.
1506		 */
1507		chan->ch_txflags |= VMBUS_CHAN_TXF_HASMNF;
1508
1509		trig_idx = offer->chm_montrig / VMBUS_MONTRIG_LEN;
1510		if (trig_idx >= VMBUS_MONTRIGS_MAX)
1511			panic("invalid monitor trigger %u", offer->chm_montrig);
1512		chan->ch_montrig =
1513		    &sc->vmbus_mnf2->mnf_trigs[trig_idx].mt_pending;
1514
1515		chan->ch_montrig_mask =
1516		    1 << (offer->chm_montrig % VMBUS_MONTRIG_LEN);
1517	}
1518
1519	/*
1520	 * Setup event flag.
1521	 */
1522	chan->ch_evtflag =
1523	    &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT];
1524	chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK);
1525
1526	/*
1527	 * Setup attach and detach tasks.
1528	 */
1529	if (VMBUS_CHAN_ISPRIMARY(chan)) {
1530		chan->ch_mgmt_tq = sc->vmbus_devtq;
1531		attach_fn = vmbus_prichan_attach_task;
1532		detach_fn = vmbus_prichan_detach_task;
1533	} else {
1534		chan->ch_mgmt_tq = sc->vmbus_subchtq;
1535		attach_fn = vmbus_subchan_attach_task;
1536		detach_fn = vmbus_subchan_detach_task;
1537	}
1538	TASK_INIT(&chan->ch_attach_task, 0, attach_fn, chan);
1539	TASK_INIT(&chan->ch_detach_task, 0, detach_fn, chan);
1540
1541	error = vmbus_chan_add(chan);
1542	if (error) {
1543		device_printf(sc->vmbus_dev, "add chan%u failed: %d\n",
1544		    chan->ch_id, error);
1545		atomic_subtract_int(&chan->ch_refs, 1);
1546		vmbus_chan_free(chan);
1547		return;
1548	}
1549	taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_attach_task);
1550}
1551
1552static void
1553vmbus_chan_msgproc_chrescind(struct vmbus_softc *sc,
1554    const struct vmbus_message *msg)
1555{
1556	const struct vmbus_chanmsg_chrescind *note;
1557	struct vmbus_channel *chan;
1558
1559	note = (const struct vmbus_chanmsg_chrescind *)msg->msg_data;
1560	if (note->chm_chanid > VMBUS_CHAN_MAX) {
1561		device_printf(sc->vmbus_dev, "invalid revoked chan%u\n",
1562		    note->chm_chanid);
1563		return;
1564	}
1565
1566	/*
1567	 * Find and remove the target channel from the channel list.
1568	 */
1569	mtx_lock(&sc->vmbus_chan_lock);
1570	TAILQ_FOREACH(chan, &sc->vmbus_chans, ch_link) {
1571		if (chan->ch_id == note->chm_chanid)
1572			break;
1573	}
1574	if (chan == NULL) {
1575		mtx_unlock(&sc->vmbus_chan_lock);
1576		device_printf(sc->vmbus_dev, "chan%u is not offered\n",
1577		    note->chm_chanid);
1578		return;
1579	}
1580	vmbus_chan_rem_list(sc, chan);
1581	mtx_unlock(&sc->vmbus_chan_lock);
1582
1583	if (VMBUS_CHAN_ISPRIMARY(chan)) {
1584		/*
1585		 * The target channel is a primary channel; remove the
1586		 * target channel from the primary channel list now,
1587		 * instead of later, so that it will not be found by
1588		 * other sub-channel offers, which are processed in
1589		 * this thread.
1590		 */
1591		mtx_lock(&sc->vmbus_prichan_lock);
1592		vmbus_chan_rem_prilist(sc, chan);
1593		mtx_unlock(&sc->vmbus_prichan_lock);
1594	}
1595
1596	/*
1597	 * NOTE:
1598	 * The following processing order is critical:
1599	 * Set the REVOKED state flag before orphaning the installed xact.
1600	 */
1601
1602	if (atomic_testandset_int(&chan->ch_stflags,
1603	    VMBUS_CHAN_ST_REVOKED_SHIFT))
1604		panic("channel has already been revoked");
1605
1606	sx_xlock(&chan->ch_orphan_lock);
1607	if (chan->ch_orphan_xact != NULL)
1608		vmbus_xact_ctx_orphan(chan->ch_orphan_xact);
1609	sx_xunlock(&chan->ch_orphan_lock);
1610
1611	if (bootverbose)
1612		vmbus_chan_printf(chan, "chan%u revoked\n", note->chm_chanid);
1613	vmbus_chan_detach(chan);
1614}
1615
1616static int
1617vmbus_chan_release(struct vmbus_channel *chan)
1618{
1619	struct vmbus_softc *sc = chan->ch_vmbus;
1620	struct vmbus_chanmsg_chfree *req;
1621	struct vmbus_msghc *mh;
1622	int error;
1623
1624	mh = vmbus_msghc_get(sc, sizeof(*req));
1625	if (mh == NULL) {
1626		vmbus_chan_printf(chan,
1627		    "can not get msg hypercall for chfree(chan%u)\n",
1628		    chan->ch_id);
1629		return (ENXIO);
1630	}
1631
1632	req = vmbus_msghc_dataptr(mh);
1633	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE;
1634	req->chm_chanid = chan->ch_id;
1635
1636	error = vmbus_msghc_exec_noresult(mh);
1637	vmbus_msghc_put(sc, mh);
1638
1639	if (error) {
1640		vmbus_chan_printf(chan,
1641		    "chfree(chan%u) msg hypercall exec failed: %d\n",
1642		    chan->ch_id, error);
1643	} else {
1644		if (bootverbose)
1645			vmbus_chan_printf(chan, "chan%u freed\n", chan->ch_id);
1646	}
1647	return (error);
1648}
1649
1650static void
1651vmbus_prichan_detach_task(void *xchan, int pending __unused)
1652{
1653	struct vmbus_channel *chan = xchan;
1654
1655	KASSERT(VMBUS_CHAN_ISPRIMARY(chan),
1656	    ("chan%u is not primary channel", chan->ch_id));
1657
1658	/* Delete and detach the device associated with this channel. */
1659	vmbus_delete_child(chan);
1660
1661	/* Release this channel (back to vmbus). */
1662	vmbus_chan_release(chan);
1663
1664	/* Free this channel's resource. */
1665	vmbus_chan_free(chan);
1666}
1667
1668static void
1669vmbus_subchan_detach_task(void *xchan, int pending __unused)
1670{
1671	struct vmbus_channel *chan = xchan;
1672	struct vmbus_channel *pri_chan = chan->ch_prichan;
1673
1674	KASSERT(!VMBUS_CHAN_ISPRIMARY(chan),
1675	    ("chan%u is primary channel", chan->ch_id));
1676
1677	/* Release this channel (back to vmbus). */
1678	vmbus_chan_release(chan);
1679
1680	/* Unlink from its primary channel's sub-channel list. */
1681	mtx_lock(&pri_chan->ch_subchan_lock);
1682	vmbus_chan_rem_sublist(pri_chan, chan);
1683	mtx_unlock(&pri_chan->ch_subchan_lock);
1684	/* Notify anyone that is waiting for this sub-channel to vanish. */
1685	wakeup(pri_chan);
1686
1687	/* Free this channel's resource. */
1688	vmbus_chan_free(chan);
1689}
1690
1691static void
1692vmbus_prichan_attach_task(void *xchan, int pending __unused)
1693{
1694
1695	/*
1696	 * Add device for this primary channel.
1697	 */
1698	vmbus_add_child(xchan);
1699}
1700
1701static void
1702vmbus_subchan_attach_task(void *xchan __unused, int pending __unused)
1703{
1704
1705	/* Nothing */
1706}
1707
1708void
1709vmbus_chan_destroy_all(struct vmbus_softc *sc)
1710{
1711
1712	/*
1713	 * Detach all devices and destroy the corresponding primary
1714	 * channels.
1715	 */
1716	for (;;) {
1717		struct vmbus_channel *chan;
1718
1719		mtx_lock(&sc->vmbus_chan_lock);
1720		TAILQ_FOREACH(chan, &sc->vmbus_chans, ch_link) {
1721			if (VMBUS_CHAN_ISPRIMARY(chan))
1722				break;
1723		}
1724		if (chan == NULL) {
1725			/* No more primary channels; done. */
1726			mtx_unlock(&sc->vmbus_chan_lock);
1727			break;
1728		}
1729		vmbus_chan_rem_list(sc, chan);
1730		mtx_unlock(&sc->vmbus_chan_lock);
1731
1732		mtx_lock(&sc->vmbus_prichan_lock);
1733		vmbus_chan_rem_prilist(sc, chan);
1734		mtx_unlock(&sc->vmbus_prichan_lock);
1735
1736		taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task);
1737	}
1738}
1739
1740struct vmbus_channel **
1741vmbus_subchan_get(struct vmbus_channel *pri_chan, int subchan_cnt)
1742{
1743	struct vmbus_channel **ret, *chan;
1744	int i;
1745
1746	KASSERT(subchan_cnt > 0, ("invalid sub-channel count %d", subchan_cnt));
1747
1748	ret = malloc(subchan_cnt * sizeof(struct vmbus_channel *), M_TEMP,
1749	    M_WAITOK);
1750
1751	mtx_lock(&pri_chan->ch_subchan_lock);
1752
1753	while (pri_chan->ch_subchan_cnt < subchan_cnt)
1754		mtx_sleep(pri_chan, &pri_chan->ch_subchan_lock, 0, "subch", 0);
1755
1756	i = 0;
1757	TAILQ_FOREACH(chan, &pri_chan->ch_subchans, ch_sublink) {
1758		/* TODO: refcnt chan */
1759		ret[i] = chan;
1760
1761		++i;
1762		if (i == subchan_cnt)
1763			break;
1764	}
1765	KASSERT(i == subchan_cnt, ("invalid subchan count %d, should be %d",
1766	    pri_chan->ch_subchan_cnt, subchan_cnt));
1767
1768	mtx_unlock(&pri_chan->ch_subchan_lock);
1769
1770	return ret;
1771}
1772
1773void
1774vmbus_subchan_rel(struct vmbus_channel **subchan, int subchan_cnt __unused)
1775{
1776
1777	free(subchan, M_TEMP);
1778}
1779
1780void
1781vmbus_subchan_drain(struct vmbus_channel *pri_chan)
1782{
1783	mtx_lock(&pri_chan->ch_subchan_lock);
1784	while (pri_chan->ch_subchan_cnt > 0)
1785		mtx_sleep(pri_chan, &pri_chan->ch_subchan_lock, 0, "dsubch", 0);
1786	mtx_unlock(&pri_chan->ch_subchan_lock);
1787}
1788
1789void
1790vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
1791{
1792	vmbus_chanmsg_proc_t msg_proc;
1793	uint32_t msg_type;
1794
1795	msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
1796	KASSERT(msg_type < VMBUS_CHANMSG_TYPE_MAX,
1797	    ("invalid message type %u", msg_type));
1798
1799	msg_proc = vmbus_chan_msgprocs[msg_type];
1800	if (msg_proc != NULL)
1801		msg_proc(sc, msg);
1802}
1803
1804void
1805vmbus_chan_set_readbatch(struct vmbus_channel *chan, bool on)
1806{
1807	if (!on)
1808		chan->ch_flags &= ~VMBUS_CHAN_FLAG_BATCHREAD;
1809	else
1810		chan->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
1811}
1812
1813uint32_t
1814vmbus_chan_id(const struct vmbus_channel *chan)
1815{
1816	return chan->ch_id;
1817}
1818
1819uint32_t
1820vmbus_chan_subidx(const struct vmbus_channel *chan)
1821{
1822	return chan->ch_subidx;
1823}
1824
1825bool
1826vmbus_chan_is_primary(const struct vmbus_channel *chan)
1827{
1828	if (VMBUS_CHAN_ISPRIMARY(chan))
1829		return true;
1830	else
1831		return false;
1832}
1833
1834const struct hyperv_guid *
1835vmbus_chan_guid_inst(const struct vmbus_channel *chan)
1836{
1837	return &chan->ch_guid_inst;
1838}
1839
1840int
1841vmbus_chan_prplist_nelem(int br_size, int prpcnt_max, int dlen_max)
1842{
1843	int elem_size;
1844
1845	elem_size = __offsetof(struct vmbus_chanpkt_prplist,
1846	    cp_range[0].gpa_page[prpcnt_max]);
1847	elem_size += dlen_max;
1848	elem_size = VMBUS_CHANPKT_TOTLEN(elem_size);
1849
1850	return (vmbus_br_nelem(br_size, elem_size));
1851}
1852
1853bool
1854vmbus_chan_tx_empty(const struct vmbus_channel *chan)
1855{
1856
1857	return (vmbus_txbr_empty(&chan->ch_txbr));
1858}
1859
1860bool
1861vmbus_chan_rx_empty(const struct vmbus_channel *chan)
1862{
1863
1864	return (vmbus_rxbr_empty(&chan->ch_rxbr));
1865}
1866
1867static int
1868vmbus_chan_printf(const struct vmbus_channel *chan, const char *fmt, ...)
1869{
1870	va_list ap;
1871	device_t dev;
1872	int retval;
1873
1874	if (chan->ch_dev == NULL || !device_is_alive(chan->ch_dev))
1875		dev = chan->ch_vmbus->vmbus_dev;
1876	else
1877		dev = chan->ch_dev;
1878
1879	retval = device_print_prettyname(dev);
1880	va_start(ap, fmt);
1881	retval += vprintf(fmt, ap);
1882	va_end(ap);
1883
1884	return (retval);
1885}
1886
1887void
1888vmbus_chan_run_task(struct vmbus_channel *chan, struct task *task)
1889{
1890
1891	taskqueue_enqueue(chan->ch_tq, task);
1892	taskqueue_drain(chan->ch_tq, task);
1893}
1894
1895struct taskqueue *
1896vmbus_chan_mgmt_tq(const struct vmbus_channel *chan)
1897{
1898
1899	return (chan->ch_mgmt_tq);
1900}
1901
1902bool
1903vmbus_chan_is_revoked(const struct vmbus_channel *chan)
1904{
1905
1906	if (chan->ch_stflags & VMBUS_CHAN_ST_REVOKED)
1907		return (true);
1908	return (false);
1909}
1910
1911void
1912vmbus_chan_set_orphan(struct vmbus_channel *chan, struct vmbus_xact_ctx *xact)
1913{
1914
1915	sx_xlock(&chan->ch_orphan_lock);
1916	chan->ch_orphan_xact = xact;
1917	sx_xunlock(&chan->ch_orphan_lock);
1918}
1919
1920void
1921vmbus_chan_unset_orphan(struct vmbus_channel *chan)
1922{
1923
1924	sx_xlock(&chan->ch_orphan_lock);
1925	chan->ch_orphan_xact = NULL;
1926	sx_xunlock(&chan->ch_orphan_lock);
1927}
1928
1929const void *
1930vmbus_chan_xact_wait(const struct vmbus_channel *chan,
1931    struct vmbus_xact *xact, size_t *resp_len, bool can_sleep)
1932{
1933	const void *ret;
1934
1935	if (can_sleep)
1936		ret = vmbus_xact_wait(xact, resp_len);
1937	else
1938		ret = vmbus_xact_busywait(xact, resp_len);
1939	if (vmbus_chan_is_revoked(chan)) {
1940		/*
1941		 * This xact probably is interrupted, and the
1942		 * interruption can race the reply reception,
1943		 * so we have to make sure that there are nothing
1944		 * left on the RX bufring, i.e. this xact will
1945		 * not be touched, once this function returns.
1946		 *
1947		 * Since the hypervisor will not put more data
1948		 * onto the RX bufring once the channel is revoked,
1949		 * the following loop will be terminated, once all
1950		 * data are drained by the driver's channel
1951		 * callback.
1952		 */
1953		while (!vmbus_chan_rx_empty(chan)) {
1954			if (can_sleep)
1955				pause("chxact", 1);
1956			else
1957				DELAY(1000);
1958		}
1959	}
1960	return (ret);
1961}
1962