hn_nvs.c revision 315437
193790Sdes/*-
293790Sdes * Copyright (c) 2009-2012,2016 Microsoft Corp.
3112044Sobrien * Copyright (c) 2010-2012 Citrix Inc.
4112044Sobrien * Copyright (c) 2012 NetApp Inc.
593790Sdes * All rights reserved.
6112044Sobrien *
7112044Sobrien * Redistribution and use in source and binary forms, with or without
8112044Sobrien * modification, are permitted provided that the following conditions
993790Sdes * are met:
10254960Swill * 1. Redistributions of source code must retain the above copyright
11112044Sobrien *    notice unmodified, this list of conditions, and the following
12112044Sobrien *    disclaimer.
13112044Sobrien * 2. Redistributions in binary form must reproduce the above copyright
14112044Sobrien *    notice, this list of conditions and the following disclaimer in the
15112044Sobrien *    documentation and/or other materials provided with the distribution.
1693790Sdes *
1793790Sdes * 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/*
30 * Network Virtualization Service.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/10/sys/dev/hyperv/netvsc/hn_nvs.c 315437 2017-03-17 03:03:58Z sephe $");
35
36#include "opt_inet6.h"
37#include "opt_inet.h"
38
39#include <sys/param.h>
40#include <sys/kernel.h>
41#include <sys/limits.h>
42#include <sys/socket.h>
43#include <sys/systm.h>
44#include <sys/taskqueue.h>
45
46#include <net/if.h>
47#include <net/if_arp.h>
48#include <net/if_media.h>
49
50#include <netinet/in.h>
51#include <netinet/tcp_lro.h>
52
53#include <dev/hyperv/include/hyperv.h>
54#include <dev/hyperv/include/hyperv_busdma.h>
55#include <dev/hyperv/include/vmbus.h>
56#include <dev/hyperv/include/vmbus_xact.h>
57
58#include <dev/hyperv/netvsc/ndis.h>
59#include <dev/hyperv/netvsc/if_hnreg.h>
60#include <dev/hyperv/netvsc/if_hnvar.h>
61#include <dev/hyperv/netvsc/hn_nvs.h>
62
63static int			hn_nvs_conn_chim(struct hn_softc *);
64static int			hn_nvs_conn_rxbuf(struct hn_softc *);
65static void			hn_nvs_disconn_chim(struct hn_softc *);
66static void			hn_nvs_disconn_rxbuf(struct hn_softc *);
67static int			hn_nvs_conf_ndis(struct hn_softc *, int);
68static int			hn_nvs_init_ndis(struct hn_softc *);
69static int			hn_nvs_doinit(struct hn_softc *, uint32_t);
70static int			hn_nvs_init(struct hn_softc *);
71static const void		*hn_nvs_xact_execute(struct hn_softc *,
72				    struct vmbus_xact *, void *, int,
73				    size_t *, uint32_t);
74static void			hn_nvs_sent_none(struct hn_nvs_sendctx *,
75				    struct hn_softc *, struct vmbus_channel *,
76				    const void *, int);
77
78struct hn_nvs_sendctx		hn_nvs_sendctx_none =
79    HN_NVS_SENDCTX_INITIALIZER(hn_nvs_sent_none, NULL);
80
81static const uint32_t		hn_nvs_version[] = {
82	HN_NVS_VERSION_5,
83	HN_NVS_VERSION_4,
84	HN_NVS_VERSION_2,
85	HN_NVS_VERSION_1
86};
87
88static const void *
89hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
90    void *req, int reqlen, size_t *resplen0, uint32_t type)
91{
92	struct hn_nvs_sendctx sndc;
93	size_t resplen, min_resplen = *resplen0;
94	const struct hn_nvs_hdr *hdr;
95	int error;
96
97	KASSERT(min_resplen >= sizeof(*hdr),
98	    ("invalid minimum response len %zu", min_resplen));
99
100	/*
101	 * Execute the xact setup by the caller.
102	 */
103	hn_nvs_sendctx_init(&sndc, hn_nvs_sent_xact, xact);
104
105	vmbus_xact_activate(xact);
106	error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC,
107	    req, reqlen, &sndc);
108	if (error) {
109		vmbus_xact_deactivate(xact);
110		return (NULL);
111	}
112	hdr = vmbus_chan_xact_wait(sc->hn_prichan, xact, &resplen,
113	    HN_CAN_SLEEP(sc));
114
115	/*
116	 * Check this NVS response message.
117	 */
118	if (resplen < min_resplen) {
119		if_printf(sc->hn_ifp, "invalid NVS resp len %zu\n", resplen);
120		return (NULL);
121	}
122	if (hdr->nvs_type != type) {
123		if_printf(sc->hn_ifp, "unexpected NVS resp 0x%08x, "
124		    "expect 0x%08x\n", hdr->nvs_type, type);
125		return (NULL);
126	}
127	/* All pass! */
128	*resplen0 = resplen;
129	return (hdr);
130}
131
132static __inline int
133hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen)
134{
135
136	return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE,
137	    req, reqlen, &hn_nvs_sendctx_none));
138}
139
140static int
141hn_nvs_conn_rxbuf(struct hn_softc *sc)
142{
143	struct vmbus_xact *xact = NULL;
144	struct hn_nvs_rxbuf_conn *conn;
145	const struct hn_nvs_rxbuf_connresp *resp;
146	size_t resp_len;
147	uint32_t status;
148	int error, rxbuf_size;
149
150	/*
151	 * Limit RXBUF size for old NVS.
152	 */
153	if (sc->hn_nvs_ver <= HN_NVS_VERSION_2)
154		rxbuf_size = HN_RXBUF_SIZE_COMPAT;
155	else
156		rxbuf_size = HN_RXBUF_SIZE;
157
158	/*
159	 * Connect the RXBUF GPADL to the primary channel.
160	 *
161	 * NOTE:
162	 * Only primary channel has RXBUF connected to it.  Sub-channels
163	 * just share this RXBUF.
164	 */
165	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
166	    sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
167	if (error) {
168		if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n",
169		    error);
170		goto cleanup;
171	}
172
173	/*
174	 * Connect RXBUF to NVS.
175	 */
176
177	xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn));
178	if (xact == NULL) {
179		if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n");
180		error = ENXIO;
181		goto cleanup;
182	}
183	conn = vmbus_xact_req_data(xact);
184	conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
185	conn->nvs_gpadl = sc->hn_rxbuf_gpadl;
186	conn->nvs_sig = HN_NVS_RXBUF_SIG;
187
188	resp_len = sizeof(*resp);
189	resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len,
190	    HN_NVS_TYPE_RXBUF_CONNRESP);
191	if (resp == NULL) {
192		if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n");
193		error = EIO;
194		goto cleanup;
195	}
196
197	status = resp->nvs_status;
198	vmbus_xact_put(xact);
199	xact = NULL;
200
201	if (status != HN_NVS_STATUS_OK) {
202		if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status);
203		error = EIO;
204		goto cleanup;
205	}
206	sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED;
207
208	return (0);
209
210cleanup:
211	if (xact != NULL)
212		vmbus_xact_put(xact);
213	hn_nvs_disconn_rxbuf(sc);
214	return (error);
215}
216
217static int
218hn_nvs_conn_chim(struct hn_softc *sc)
219{
220	struct vmbus_xact *xact = NULL;
221	struct hn_nvs_chim_conn *chim;
222	const struct hn_nvs_chim_connresp *resp;
223	size_t resp_len;
224	uint32_t status, sectsz;
225	int error;
226
227	/*
228	 * Connect chimney sending buffer GPADL to the primary channel.
229	 *
230	 * NOTE:
231	 * Only primary channel has chimney sending buffer connected to it.
232	 * Sub-channels just share this chimney sending buffer.
233	 */
234	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
235  	    sc->hn_chim_dma.hv_paddr, HN_CHIM_SIZE, &sc->hn_chim_gpadl);
236	if (error) {
237		if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error);
238		goto cleanup;
239	}
240
241	/*
242	 * Connect chimney sending buffer to NVS
243	 */
244
245	xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim));
246	if (xact == NULL) {
247		if_printf(sc->hn_ifp, "no xact for nvs chim conn\n");
248		error = ENXIO;
249		goto cleanup;
250	}
251	chim = vmbus_xact_req_data(xact);
252	chim->nvs_type = HN_NVS_TYPE_CHIM_CONN;
253	chim->nvs_gpadl = sc->hn_chim_gpadl;
254	chim->nvs_sig = HN_NVS_CHIM_SIG;
255
256	resp_len = sizeof(*resp);
257	resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len,
258	    HN_NVS_TYPE_CHIM_CONNRESP);
259	if (resp == NULL) {
260		if_printf(sc->hn_ifp, "exec nvs chim conn failed\n");
261		error = EIO;
262		goto cleanup;
263	}
264
265	status = resp->nvs_status;
266	sectsz = resp->nvs_sectsz;
267	vmbus_xact_put(xact);
268	xact = NULL;
269
270	if (status != HN_NVS_STATUS_OK) {
271		if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status);
272		error = EIO;
273		goto cleanup;
274	}
275	if (sectsz == 0 || sectsz % sizeof(uint32_t) != 0) {
276		/*
277		 * Can't use chimney sending buffer; done!
278		 */
279		if (sectsz == 0) {
280			if_printf(sc->hn_ifp, "zero chimney sending buffer "
281			    "section size\n");
282		} else {
283			if_printf(sc->hn_ifp, "misaligned chimney sending "
284			    "buffers, section size: %u\n", sectsz);
285		}
286		sc->hn_chim_szmax = 0;
287		sc->hn_chim_cnt = 0;
288		sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
289		return (0);
290	}
291
292	sc->hn_chim_szmax = sectsz;
293	sc->hn_chim_cnt = HN_CHIM_SIZE / sc->hn_chim_szmax;
294	if (HN_CHIM_SIZE % sc->hn_chim_szmax != 0) {
295		if_printf(sc->hn_ifp, "chimney sending sections are "
296		    "not properly aligned\n");
297	}
298	if (sc->hn_chim_cnt % LONG_BIT != 0) {
299		if_printf(sc->hn_ifp, "discard %d chimney sending sections\n",
300		    sc->hn_chim_cnt % LONG_BIT);
301	}
302
303	sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT;
304	sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long),
305	    M_DEVBUF, M_WAITOK | M_ZERO);
306
307	/* Done! */
308	sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
309	if (bootverbose) {
310		if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
311		    sc->hn_chim_szmax, sc->hn_chim_cnt);
312	}
313	return (0);
314
315cleanup:
316	if (xact != NULL)
317		vmbus_xact_put(xact);
318	hn_nvs_disconn_chim(sc);
319	return (error);
320}
321
322static void
323hn_nvs_disconn_rxbuf(struct hn_softc *sc)
324{
325	int error;
326
327	if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
328		struct hn_nvs_rxbuf_disconn disconn;
329
330		/*
331		 * Disconnect RXBUF from NVS.
332		 */
333		memset(&disconn, 0, sizeof(disconn));
334		disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
335		disconn.nvs_sig = HN_NVS_RXBUF_SIG;
336
337		/* NOTE: No response. */
338		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
339		if (error) {
340			if_printf(sc->hn_ifp,
341			    "send nvs rxbuf disconn failed: %d\n", error);
342			/*
343			 * Fine for a revoked channel, since the hypervisor
344			 * does not drain TX bufring for a revoked channel.
345			 */
346			if (!vmbus_chan_is_revoked(sc->hn_prichan))
347				sc->hn_flags |= HN_FLAG_RXBUF_REF;
348		}
349		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
350
351		/*
352		 * Wait for the hypervisor to receive this NVS request.
353		 *
354		 * NOTE:
355		 * The TX bufring will not be drained by the hypervisor,
356		 * if the primary channel is revoked.
357		 */
358		while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
359		    !vmbus_chan_is_revoked(sc->hn_prichan))
360			pause("waittx", 1);
361		/*
362		 * Linger long enough for NVS to disconnect RXBUF.
363		 */
364		pause("lingtx", (200 * hz) / 1000);
365	}
366
367	if (sc->hn_rxbuf_gpadl != 0) {
368		/*
369		 * Disconnect RXBUF from primary channel.
370		 */
371		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
372		    sc->hn_rxbuf_gpadl);
373		if (error) {
374			if_printf(sc->hn_ifp,
375			    "rxbuf gpadl disconn failed: %d\n", error);
376			sc->hn_flags |= HN_FLAG_RXBUF_REF;
377		}
378		sc->hn_rxbuf_gpadl = 0;
379	}
380}
381
382static void
383hn_nvs_disconn_chim(struct hn_softc *sc)
384{
385	int error;
386
387	if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
388		struct hn_nvs_chim_disconn disconn;
389
390		/*
391		 * Disconnect chimney sending buffer from NVS.
392		 */
393		memset(&disconn, 0, sizeof(disconn));
394		disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
395		disconn.nvs_sig = HN_NVS_CHIM_SIG;
396
397		/* NOTE: No response. */
398		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
399		if (error) {
400			if_printf(sc->hn_ifp,
401			    "send nvs chim disconn failed: %d\n", error);
402			/*
403			 * Fine for a revoked channel, since the hypervisor
404			 * does not drain TX bufring for a revoked channel.
405			 */
406			if (!vmbus_chan_is_revoked(sc->hn_prichan))
407				sc->hn_flags |= HN_FLAG_CHIM_REF;
408		}
409		sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
410
411		/*
412		 * Wait for the hypervisor to receive this NVS request.
413		 *
414		 * NOTE:
415		 * The TX bufring will not be drained by the hypervisor,
416		 * if the primary channel is revoked.
417		 */
418		while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
419		    !vmbus_chan_is_revoked(sc->hn_prichan))
420			pause("waittx", 1);
421		/*
422		 * Linger long enough for NVS to disconnect chimney
423		 * sending buffer.
424		 */
425		pause("lingtx", (200 * hz) / 1000);
426	}
427
428	if (sc->hn_chim_gpadl != 0) {
429		/*
430		 * Disconnect chimney sending buffer from primary channel.
431		 */
432		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
433		    sc->hn_chim_gpadl);
434		if (error) {
435			if_printf(sc->hn_ifp,
436			    "chim gpadl disconn failed: %d\n", error);
437			sc->hn_flags |= HN_FLAG_CHIM_REF;
438		}
439		sc->hn_chim_gpadl = 0;
440	}
441
442	if (sc->hn_chim_bmap != NULL) {
443		free(sc->hn_chim_bmap, M_DEVBUF);
444		sc->hn_chim_bmap = NULL;
445		sc->hn_chim_bmap_cnt = 0;
446	}
447}
448
449static int
450hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver)
451{
452	struct vmbus_xact *xact;
453	struct hn_nvs_init *init;
454	const struct hn_nvs_init_resp *resp;
455	size_t resp_len;
456	uint32_t status;
457
458	xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
459	if (xact == NULL) {
460		if_printf(sc->hn_ifp, "no xact for nvs init\n");
461		return (ENXIO);
462	}
463	init = vmbus_xact_req_data(xact);
464	init->nvs_type = HN_NVS_TYPE_INIT;
465	init->nvs_ver_min = nvs_ver;
466	init->nvs_ver_max = nvs_ver;
467
468	resp_len = sizeof(*resp);
469	resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len,
470	    HN_NVS_TYPE_INIT_RESP);
471	if (resp == NULL) {
472		if_printf(sc->hn_ifp, "exec init failed\n");
473		vmbus_xact_put(xact);
474		return (EIO);
475	}
476
477	status = resp->nvs_status;
478	vmbus_xact_put(xact);
479
480	if (status != HN_NVS_STATUS_OK) {
481		if (bootverbose) {
482			/*
483			 * Caller may try another NVS version, and will log
484			 * error if there are no more NVS versions to try,
485			 * so don't bark out loud here.
486			 */
487			if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
488			    nvs_ver);
489		}
490		return (EINVAL);
491	}
492	return (0);
493}
494
495/*
496 * Configure MTU and enable VLAN.
497 */
498static int
499hn_nvs_conf_ndis(struct hn_softc *sc, int mtu)
500{
501	struct hn_nvs_ndis_conf conf;
502	int error;
503
504	memset(&conf, 0, sizeof(conf));
505	conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
506	conf.nvs_mtu = mtu;
507	conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
508	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
509		conf.nvs_caps |= HN_NVS_NDIS_CONF_SRIOV;
510
511	/* NOTE: No response. */
512	error = hn_nvs_req_send(sc, &conf, sizeof(conf));
513	if (error) {
514		if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
515		return (error);
516	}
517
518	if (bootverbose)
519		if_printf(sc->hn_ifp, "nvs ndis conf done\n");
520	sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN;
521	return (0);
522}
523
524static int
525hn_nvs_init_ndis(struct hn_softc *sc)
526{
527	struct hn_nvs_ndis_init ndis;
528	int error;
529
530	memset(&ndis, 0, sizeof(ndis));
531	ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
532	ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
533	ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver);
534
535	/* NOTE: No response. */
536	error = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
537	if (error)
538		if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error);
539	return (error);
540}
541
542static int
543hn_nvs_init(struct hn_softc *sc)
544{
545	int i, error;
546
547	if (device_is_attached(sc->hn_dev)) {
548		/*
549		 * NVS version and NDIS version MUST NOT be changed.
550		 */
551		if (bootverbose) {
552			if_printf(sc->hn_ifp, "reinit NVS version 0x%x, "
553			    "NDIS version %u.%u\n", sc->hn_nvs_ver,
554			    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
555			    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
556		}
557
558		error = hn_nvs_doinit(sc, sc->hn_nvs_ver);
559		if (error) {
560			if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
561			    "failed: %d\n", sc->hn_nvs_ver, error);
562			return (error);
563		}
564		goto done;
565	}
566
567	/*
568	 * Find the supported NVS version and set NDIS version accordingly.
569	 */
570	for (i = 0; i < nitems(hn_nvs_version); ++i) {
571		error = hn_nvs_doinit(sc, hn_nvs_version[i]);
572		if (!error) {
573			sc->hn_nvs_ver = hn_nvs_version[i];
574
575			/* Set NDIS version according to NVS version. */
576			sc->hn_ndis_ver = HN_NDIS_VERSION_6_30;
577			if (sc->hn_nvs_ver <= HN_NVS_VERSION_4)
578				sc->hn_ndis_ver = HN_NDIS_VERSION_6_1;
579
580			if (bootverbose) {
581				if_printf(sc->hn_ifp, "NVS version 0x%x, "
582				    "NDIS version %u.%u\n", sc->hn_nvs_ver,
583				    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
584				    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
585			}
586			goto done;
587		}
588	}
589	if_printf(sc->hn_ifp, "no NVS available\n");
590	return (ENXIO);
591
592done:
593	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
594		sc->hn_caps |= HN_CAP_HASHVAL;
595	return (0);
596}
597
598int
599hn_nvs_attach(struct hn_softc *sc, int mtu)
600{
601	int error;
602
603	/*
604	 * Initialize NVS.
605	 */
606	error = hn_nvs_init(sc);
607	if (error)
608		return (error);
609
610	if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
611		/*
612		 * Configure NDIS before initializing it.
613		 */
614		error = hn_nvs_conf_ndis(sc, mtu);
615		if (error)
616			return (error);
617	}
618
619	/*
620	 * Initialize NDIS.
621	 */
622	error = hn_nvs_init_ndis(sc);
623	if (error)
624		return (error);
625
626	/*
627	 * Connect RXBUF.
628	 */
629	error = hn_nvs_conn_rxbuf(sc);
630	if (error)
631		return (error);
632
633	/*
634	 * Connect chimney sending buffer.
635	 */
636	error = hn_nvs_conn_chim(sc);
637	if (error) {
638		hn_nvs_disconn_rxbuf(sc);
639		return (error);
640	}
641	return (0);
642}
643
644void
645hn_nvs_detach(struct hn_softc *sc)
646{
647
648	/* NOTE: there are no requests to stop the NVS. */
649	hn_nvs_disconn_rxbuf(sc);
650	hn_nvs_disconn_chim(sc);
651}
652
653void
654hn_nvs_sent_xact(struct hn_nvs_sendctx *sndc,
655    struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
656    const void *data, int dlen)
657{
658
659	vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
660}
661
662static void
663hn_nvs_sent_none(struct hn_nvs_sendctx *sndc __unused,
664    struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
665    const void *data __unused, int dlen __unused)
666{
667	/* EMPTY */
668}
669
670int
671hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
672{
673	struct vmbus_xact *xact;
674	struct hn_nvs_subch_req *req;
675	const struct hn_nvs_subch_resp *resp;
676	int error, nsubch_req;
677	uint32_t nsubch;
678	size_t resp_len;
679
680	nsubch_req = *nsubch0;
681	KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
682
683	xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
684	if (xact == NULL) {
685		if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
686		return (ENXIO);
687	}
688	req = vmbus_xact_req_data(xact);
689	req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
690	req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
691	req->nvs_nsubch = nsubch_req;
692
693	resp_len = sizeof(*resp);
694	resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
695	    HN_NVS_TYPE_SUBCH_RESP);
696	if (resp == NULL) {
697		if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
698		error = EIO;
699		goto done;
700	}
701	if (resp->nvs_status != HN_NVS_STATUS_OK) {
702		if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
703		    resp->nvs_status);
704		error = EIO;
705		goto done;
706	}
707
708	nsubch = resp->nvs_nsubch;
709	if (nsubch > nsubch_req) {
710		if_printf(sc->hn_ifp, "%u subchans are allocated, "
711		    "requested %d\n", nsubch, nsubch_req);
712		nsubch = nsubch_req;
713	}
714	*nsubch0 = nsubch;
715	error = 0;
716done:
717	vmbus_xact_put(xact);
718	return (error);
719}
720
721int
722hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
723    struct hn_nvs_sendctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
724{
725
726	return hn_nvs_send_rndis_sglist(chan, HN_NVS_RNDIS_MTYPE_CTRL,
727	    sndc, gpa, gpa_cnt);
728}
729
730void
731hn_nvs_set_datapath(struct hn_softc *sc, uint32_t path)
732{
733	struct hn_nvs_datapath dp;
734
735	memset(&dp, 0, sizeof(dp));
736	dp.nvs_type = HN_NVS_TYPE_SET_DATAPATH;
737	dp.nvs_active_path = path;
738
739	hn_nvs_req_send(sc, &dp, sizeof(dp));
740}
741