xref: /freebsd/sys/dev/hyperv/netvsc/hn_nvs.c (revision 74d9553e43cfafc29448d0bb836916aa21dea0de)
1 /*-
2  * Copyright (c) 2009-2012,2016 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 __FBSDID("$FreeBSD$");
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_var.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 
63 static int			hn_nvs_conn_chim(struct hn_softc *);
64 static int			hn_nvs_conn_rxbuf(struct hn_softc *);
65 static void			hn_nvs_disconn_chim(struct hn_softc *);
66 static void			hn_nvs_disconn_rxbuf(struct hn_softc *);
67 static int			hn_nvs_conf_ndis(struct hn_softc *, int);
68 static int			hn_nvs_init_ndis(struct hn_softc *);
69 static int			hn_nvs_doinit(struct hn_softc *, uint32_t);
70 static int			hn_nvs_init(struct hn_softc *);
71 static const void		*hn_nvs_xact_execute(struct hn_softc *,
72 				    struct vmbus_xact *, void *, int,
73 				    size_t *, uint32_t);
74 static void			hn_nvs_sent_none(struct hn_nvs_sendctx *,
75 				    struct hn_softc *, struct vmbus_channel *,
76 				    const void *, int);
77 
78 struct hn_nvs_sendctx		hn_nvs_sendctx_none =
79     HN_NVS_SENDCTX_INITIALIZER(hn_nvs_sent_none, NULL);
80 
81 static 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 
88 static const void *
89 hn_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 
132 static __inline int
133 hn_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 
140 static int
141 hn_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 
210 cleanup:
211 	if (xact != NULL)
212 		vmbus_xact_put(xact);
213 	hn_nvs_disconn_rxbuf(sc);
214 	return (error);
215 }
216 
217 static int
218 hn_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) {
276 		/*
277 		 * Can't use chimney sending buffer; done!
278 		 */
279 		if_printf(sc->hn_ifp, "zero chimney sending buffer "
280 		    "section size\n");
281 		sc->hn_chim_szmax = 0;
282 		sc->hn_chim_cnt = 0;
283 		sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
284 		return (0);
285 	}
286 
287 	sc->hn_chim_szmax = sectsz;
288 	sc->hn_chim_cnt = HN_CHIM_SIZE / sc->hn_chim_szmax;
289 	if (HN_CHIM_SIZE % sc->hn_chim_szmax != 0) {
290 		if_printf(sc->hn_ifp, "chimney sending sections are "
291 		    "not properly aligned\n");
292 	}
293 	if (sc->hn_chim_cnt % LONG_BIT != 0) {
294 		if_printf(sc->hn_ifp, "discard %d chimney sending sections\n",
295 		    sc->hn_chim_cnt % LONG_BIT);
296 	}
297 
298 	sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT;
299 	sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long),
300 	    M_DEVBUF, M_WAITOK | M_ZERO);
301 
302 	/* Done! */
303 	sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
304 	if (bootverbose) {
305 		if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
306 		    sc->hn_chim_szmax, sc->hn_chim_cnt);
307 	}
308 	return (0);
309 
310 cleanup:
311 	if (xact != NULL)
312 		vmbus_xact_put(xact);
313 	hn_nvs_disconn_chim(sc);
314 	return (error);
315 }
316 
317 static void
318 hn_nvs_disconn_rxbuf(struct hn_softc *sc)
319 {
320 	int error;
321 
322 	if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
323 		struct hn_nvs_rxbuf_disconn disconn;
324 
325 		/*
326 		 * Disconnect RXBUF from NVS.
327 		 */
328 		memset(&disconn, 0, sizeof(disconn));
329 		disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
330 		disconn.nvs_sig = HN_NVS_RXBUF_SIG;
331 
332 		/* NOTE: No response. */
333 		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
334 		if (error) {
335 			if_printf(sc->hn_ifp,
336 			    "send nvs rxbuf disconn failed: %d\n", error);
337 			/*
338 			 * Fine for a revoked channel, since the hypervisor
339 			 * does not drain TX bufring for a revoked channel.
340 			 */
341 			if (!vmbus_chan_is_revoked(sc->hn_prichan))
342 				sc->hn_flags |= HN_FLAG_RXBUF_REF;
343 		}
344 		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
345 
346 		/*
347 		 * Wait for the hypervisor to receive this NVS request.
348 		 *
349 		 * NOTE:
350 		 * The TX bufring will not be drained by the hypervisor,
351 		 * if the primary channel is revoked.
352 		 */
353 		while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
354 		    !vmbus_chan_is_revoked(sc->hn_prichan))
355 			pause("waittx", 1);
356 		/*
357 		 * Linger long enough for NVS to disconnect RXBUF.
358 		 */
359 		pause("lingtx", (200 * hz) / 1000);
360 	}
361 
362 	if (sc->hn_rxbuf_gpadl != 0) {
363 		/*
364 		 * Disconnect RXBUF from primary channel.
365 		 */
366 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
367 		    sc->hn_rxbuf_gpadl);
368 		if (error) {
369 			if_printf(sc->hn_ifp,
370 			    "rxbuf gpadl disconn failed: %d\n", error);
371 			sc->hn_flags |= HN_FLAG_RXBUF_REF;
372 		}
373 		sc->hn_rxbuf_gpadl = 0;
374 	}
375 }
376 
377 static void
378 hn_nvs_disconn_chim(struct hn_softc *sc)
379 {
380 	int error;
381 
382 	if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
383 		struct hn_nvs_chim_disconn disconn;
384 
385 		/*
386 		 * Disconnect chimney sending buffer from NVS.
387 		 */
388 		memset(&disconn, 0, sizeof(disconn));
389 		disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
390 		disconn.nvs_sig = HN_NVS_CHIM_SIG;
391 
392 		/* NOTE: No response. */
393 		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
394 		if (error) {
395 			if_printf(sc->hn_ifp,
396 			    "send nvs chim disconn failed: %d\n", error);
397 			/*
398 			 * Fine for a revoked channel, since the hypervisor
399 			 * does not drain TX bufring for a revoked channel.
400 			 */
401 			if (!vmbus_chan_is_revoked(sc->hn_prichan))
402 				sc->hn_flags |= HN_FLAG_CHIM_REF;
403 		}
404 		sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
405 
406 		/*
407 		 * Wait for the hypervisor to receive this NVS request.
408 		 *
409 		 * NOTE:
410 		 * The TX bufring will not be drained by the hypervisor,
411 		 * if the primary channel is revoked.
412 		 */
413 		while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
414 		    !vmbus_chan_is_revoked(sc->hn_prichan))
415 			pause("waittx", 1);
416 		/*
417 		 * Linger long enough for NVS to disconnect chimney
418 		 * sending buffer.
419 		 */
420 		pause("lingtx", (200 * hz) / 1000);
421 	}
422 
423 	if (sc->hn_chim_gpadl != 0) {
424 		/*
425 		 * Disconnect chimney sending buffer from primary channel.
426 		 */
427 		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
428 		    sc->hn_chim_gpadl);
429 		if (error) {
430 			if_printf(sc->hn_ifp,
431 			    "chim gpadl disconn failed: %d\n", error);
432 			sc->hn_flags |= HN_FLAG_CHIM_REF;
433 		}
434 		sc->hn_chim_gpadl = 0;
435 	}
436 
437 	if (sc->hn_chim_bmap != NULL) {
438 		free(sc->hn_chim_bmap, M_DEVBUF);
439 		sc->hn_chim_bmap = NULL;
440 		sc->hn_chim_bmap_cnt = 0;
441 	}
442 }
443 
444 static int
445 hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver)
446 {
447 	struct vmbus_xact *xact;
448 	struct hn_nvs_init *init;
449 	const struct hn_nvs_init_resp *resp;
450 	size_t resp_len;
451 	uint32_t status;
452 
453 	xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
454 	if (xact == NULL) {
455 		if_printf(sc->hn_ifp, "no xact for nvs init\n");
456 		return (ENXIO);
457 	}
458 	init = vmbus_xact_req_data(xact);
459 	init->nvs_type = HN_NVS_TYPE_INIT;
460 	init->nvs_ver_min = nvs_ver;
461 	init->nvs_ver_max = nvs_ver;
462 
463 	resp_len = sizeof(*resp);
464 	resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len,
465 	    HN_NVS_TYPE_INIT_RESP);
466 	if (resp == NULL) {
467 		if_printf(sc->hn_ifp, "exec init failed\n");
468 		vmbus_xact_put(xact);
469 		return (EIO);
470 	}
471 
472 	status = resp->nvs_status;
473 	vmbus_xact_put(xact);
474 
475 	if (status != HN_NVS_STATUS_OK) {
476 		if (bootverbose) {
477 			/*
478 			 * Caller may try another NVS version, and will log
479 			 * error if there are no more NVS versions to try,
480 			 * so don't bark out loud here.
481 			 */
482 			if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
483 			    nvs_ver);
484 		}
485 		return (EINVAL);
486 	}
487 	return (0);
488 }
489 
490 /*
491  * Configure MTU and enable VLAN.
492  */
493 static int
494 hn_nvs_conf_ndis(struct hn_softc *sc, int mtu)
495 {
496 	struct hn_nvs_ndis_conf conf;
497 	int error;
498 
499 	memset(&conf, 0, sizeof(conf));
500 	conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
501 	conf.nvs_mtu = mtu;
502 	conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
503 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
504 		conf.nvs_caps |= HN_NVS_NDIS_CONF_SRIOV;
505 
506 	/* NOTE: No response. */
507 	error = hn_nvs_req_send(sc, &conf, sizeof(conf));
508 	if (error) {
509 		if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
510 		return (error);
511 	}
512 
513 	if (bootverbose)
514 		if_printf(sc->hn_ifp, "nvs ndis conf done\n");
515 	sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN;
516 	return (0);
517 }
518 
519 static int
520 hn_nvs_init_ndis(struct hn_softc *sc)
521 {
522 	struct hn_nvs_ndis_init ndis;
523 	int error;
524 
525 	memset(&ndis, 0, sizeof(ndis));
526 	ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
527 	ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
528 	ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver);
529 
530 	/* NOTE: No response. */
531 	error = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
532 	if (error)
533 		if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error);
534 	return (error);
535 }
536 
537 static int
538 hn_nvs_init(struct hn_softc *sc)
539 {
540 	int i, error;
541 
542 	if (device_is_attached(sc->hn_dev)) {
543 		/*
544 		 * NVS version and NDIS version MUST NOT be changed.
545 		 */
546 		if (bootverbose) {
547 			if_printf(sc->hn_ifp, "reinit NVS version 0x%x, "
548 			    "NDIS version %u.%u\n", sc->hn_nvs_ver,
549 			    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
550 			    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
551 		}
552 
553 		error = hn_nvs_doinit(sc, sc->hn_nvs_ver);
554 		if (error) {
555 			if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
556 			    "failed: %d\n", sc->hn_nvs_ver, error);
557 			return (error);
558 		}
559 		goto done;
560 	}
561 
562 	/*
563 	 * Find the supported NVS version and set NDIS version accordingly.
564 	 */
565 	for (i = 0; i < nitems(hn_nvs_version); ++i) {
566 		error = hn_nvs_doinit(sc, hn_nvs_version[i]);
567 		if (!error) {
568 			sc->hn_nvs_ver = hn_nvs_version[i];
569 
570 			/* Set NDIS version according to NVS version. */
571 			sc->hn_ndis_ver = HN_NDIS_VERSION_6_30;
572 			if (sc->hn_nvs_ver <= HN_NVS_VERSION_4)
573 				sc->hn_ndis_ver = HN_NDIS_VERSION_6_1;
574 
575 			if (bootverbose) {
576 				if_printf(sc->hn_ifp, "NVS version 0x%x, "
577 				    "NDIS version %u.%u\n", sc->hn_nvs_ver,
578 				    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
579 				    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
580 			}
581 			goto done;
582 		}
583 	}
584 	if_printf(sc->hn_ifp, "no NVS available\n");
585 	return (ENXIO);
586 
587 done:
588 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
589 		sc->hn_caps |= HN_CAP_HASHVAL;
590 	return (0);
591 }
592 
593 int
594 hn_nvs_attach(struct hn_softc *sc, int mtu)
595 {
596 	int error;
597 
598 	/*
599 	 * Initialize NVS.
600 	 */
601 	error = hn_nvs_init(sc);
602 	if (error)
603 		return (error);
604 
605 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
606 		/*
607 		 * Configure NDIS before initializing it.
608 		 */
609 		error = hn_nvs_conf_ndis(sc, mtu);
610 		if (error)
611 			return (error);
612 	}
613 
614 	/*
615 	 * Initialize NDIS.
616 	 */
617 	error = hn_nvs_init_ndis(sc);
618 	if (error)
619 		return (error);
620 
621 	/*
622 	 * Connect RXBUF.
623 	 */
624 	error = hn_nvs_conn_rxbuf(sc);
625 	if (error)
626 		return (error);
627 
628 	/*
629 	 * Connect chimney sending buffer.
630 	 */
631 	error = hn_nvs_conn_chim(sc);
632 	if (error) {
633 		hn_nvs_disconn_rxbuf(sc);
634 		return (error);
635 	}
636 	return (0);
637 }
638 
639 void
640 hn_nvs_detach(struct hn_softc *sc)
641 {
642 
643 	/* NOTE: there are no requests to stop the NVS. */
644 	hn_nvs_disconn_rxbuf(sc);
645 	hn_nvs_disconn_chim(sc);
646 }
647 
648 void
649 hn_nvs_sent_xact(struct hn_nvs_sendctx *sndc,
650     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
651     const void *data, int dlen)
652 {
653 
654 	vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
655 }
656 
657 static void
658 hn_nvs_sent_none(struct hn_nvs_sendctx *sndc __unused,
659     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
660     const void *data __unused, int dlen __unused)
661 {
662 	/* EMPTY */
663 }
664 
665 int
666 hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
667 {
668 	struct vmbus_xact *xact;
669 	struct hn_nvs_subch_req *req;
670 	const struct hn_nvs_subch_resp *resp;
671 	int error, nsubch_req;
672 	uint32_t nsubch;
673 	size_t resp_len;
674 
675 	nsubch_req = *nsubch0;
676 	KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
677 
678 	xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
679 	if (xact == NULL) {
680 		if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
681 		return (ENXIO);
682 	}
683 	req = vmbus_xact_req_data(xact);
684 	req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
685 	req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
686 	req->nvs_nsubch = nsubch_req;
687 
688 	resp_len = sizeof(*resp);
689 	resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
690 	    HN_NVS_TYPE_SUBCH_RESP);
691 	if (resp == NULL) {
692 		if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
693 		error = EIO;
694 		goto done;
695 	}
696 	if (resp->nvs_status != HN_NVS_STATUS_OK) {
697 		if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
698 		    resp->nvs_status);
699 		error = EIO;
700 		goto done;
701 	}
702 
703 	nsubch = resp->nvs_nsubch;
704 	if (nsubch > nsubch_req) {
705 		if_printf(sc->hn_ifp, "%u subchans are allocated, "
706 		    "requested %d\n", nsubch, nsubch_req);
707 		nsubch = nsubch_req;
708 	}
709 	*nsubch0 = nsubch;
710 	error = 0;
711 done:
712 	vmbus_xact_put(xact);
713 	return (error);
714 }
715 
716 int
717 hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
718     struct hn_nvs_sendctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
719 {
720 
721 	return hn_nvs_send_rndis_sglist(chan, HN_NVS_RNDIS_MTYPE_CTRL,
722 	    sndc, gpa, gpa_cnt);
723 }
724 
725 void
726 hn_nvs_set_datapath(struct hn_softc *sc, uint32_t path)
727 {
728 	struct hn_nvs_datapath dp;
729 
730 	memset(&dp, 0, sizeof(dp));
731 	dp.nvs_type = HN_NVS_TYPE_SET_DATAPATH;
732 	dp.nvs_active_path = path;
733 
734 	hn_nvs_req_send(sc, &dp, sizeof(dp));
735 }
736