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