xref: /freebsd/sys/dev/hyperv/netvsc/hn_nvs.c (revision 7f9dff23d3092aa33ad45b2b63e52469b3c13a6e)
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 
504 	/* NOTE: No response. */
505 	error = hn_nvs_req_send(sc, &conf, sizeof(conf));
506 	if (error) {
507 		if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
508 		return (error);
509 	}
510 
511 	if (bootverbose)
512 		if_printf(sc->hn_ifp, "nvs ndis conf done\n");
513 	sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN;
514 	return (0);
515 }
516 
517 static int
518 hn_nvs_init_ndis(struct hn_softc *sc)
519 {
520 	struct hn_nvs_ndis_init ndis;
521 	int error;
522 
523 	memset(&ndis, 0, sizeof(ndis));
524 	ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
525 	ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
526 	ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver);
527 
528 	/* NOTE: No response. */
529 	error = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
530 	if (error)
531 		if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error);
532 	return (error);
533 }
534 
535 static int
536 hn_nvs_init(struct hn_softc *sc)
537 {
538 	int i, error;
539 
540 	if (device_is_attached(sc->hn_dev)) {
541 		/*
542 		 * NVS version and NDIS version MUST NOT be changed.
543 		 */
544 		if (bootverbose) {
545 			if_printf(sc->hn_ifp, "reinit NVS version 0x%x, "
546 			    "NDIS version %u.%u\n", sc->hn_nvs_ver,
547 			    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
548 			    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
549 		}
550 
551 		error = hn_nvs_doinit(sc, sc->hn_nvs_ver);
552 		if (error) {
553 			if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
554 			    "failed: %d\n", sc->hn_nvs_ver, error);
555 			return (error);
556 		}
557 		goto done;
558 	}
559 
560 	/*
561 	 * Find the supported NVS version and set NDIS version accordingly.
562 	 */
563 	for (i = 0; i < nitems(hn_nvs_version); ++i) {
564 		error = hn_nvs_doinit(sc, hn_nvs_version[i]);
565 		if (!error) {
566 			sc->hn_nvs_ver = hn_nvs_version[i];
567 
568 			/* Set NDIS version according to NVS version. */
569 			sc->hn_ndis_ver = HN_NDIS_VERSION_6_30;
570 			if (sc->hn_nvs_ver <= HN_NVS_VERSION_4)
571 				sc->hn_ndis_ver = HN_NDIS_VERSION_6_1;
572 
573 			if (bootverbose) {
574 				if_printf(sc->hn_ifp, "NVS version 0x%x, "
575 				    "NDIS version %u.%u\n", sc->hn_nvs_ver,
576 				    HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
577 				    HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
578 			}
579 			goto done;
580 		}
581 	}
582 	if_printf(sc->hn_ifp, "no NVS available\n");
583 	return (ENXIO);
584 
585 done:
586 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
587 		sc->hn_caps |= HN_CAP_HASHVAL;
588 	return (0);
589 }
590 
591 int
592 hn_nvs_attach(struct hn_softc *sc, int mtu)
593 {
594 	int error;
595 
596 	/*
597 	 * Initialize NVS.
598 	 */
599 	error = hn_nvs_init(sc);
600 	if (error)
601 		return (error);
602 
603 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
604 		/*
605 		 * Configure NDIS before initializing it.
606 		 */
607 		error = hn_nvs_conf_ndis(sc, mtu);
608 		if (error)
609 			return (error);
610 	}
611 
612 	/*
613 	 * Initialize NDIS.
614 	 */
615 	error = hn_nvs_init_ndis(sc);
616 	if (error)
617 		return (error);
618 
619 	/*
620 	 * Connect RXBUF.
621 	 */
622 	error = hn_nvs_conn_rxbuf(sc);
623 	if (error)
624 		return (error);
625 
626 	/*
627 	 * Connect chimney sending buffer.
628 	 */
629 	error = hn_nvs_conn_chim(sc);
630 	if (error) {
631 		hn_nvs_disconn_rxbuf(sc);
632 		return (error);
633 	}
634 	return (0);
635 }
636 
637 void
638 hn_nvs_detach(struct hn_softc *sc)
639 {
640 
641 	/* NOTE: there are no requests to stop the NVS. */
642 	hn_nvs_disconn_rxbuf(sc);
643 	hn_nvs_disconn_chim(sc);
644 }
645 
646 void
647 hn_nvs_sent_xact(struct hn_nvs_sendctx *sndc,
648     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
649     const void *data, int dlen)
650 {
651 
652 	vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
653 }
654 
655 static void
656 hn_nvs_sent_none(struct hn_nvs_sendctx *sndc __unused,
657     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
658     const void *data __unused, int dlen __unused)
659 {
660 	/* EMPTY */
661 }
662 
663 int
664 hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
665 {
666 	struct vmbus_xact *xact;
667 	struct hn_nvs_subch_req *req;
668 	const struct hn_nvs_subch_resp *resp;
669 	int error, nsubch_req;
670 	uint32_t nsubch;
671 	size_t resp_len;
672 
673 	nsubch_req = *nsubch0;
674 	KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
675 
676 	xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
677 	if (xact == NULL) {
678 		if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
679 		return (ENXIO);
680 	}
681 	req = vmbus_xact_req_data(xact);
682 	req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
683 	req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
684 	req->nvs_nsubch = nsubch_req;
685 
686 	resp_len = sizeof(*resp);
687 	resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
688 	    HN_NVS_TYPE_SUBCH_RESP);
689 	if (resp == NULL) {
690 		if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
691 		error = EIO;
692 		goto done;
693 	}
694 	if (resp->nvs_status != HN_NVS_STATUS_OK) {
695 		if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
696 		    resp->nvs_status);
697 		error = EIO;
698 		goto done;
699 	}
700 
701 	nsubch = resp->nvs_nsubch;
702 	if (nsubch > nsubch_req) {
703 		if_printf(sc->hn_ifp, "%u subchans are allocated, "
704 		    "requested %d\n", nsubch, nsubch_req);
705 		nsubch = nsubch_req;
706 	}
707 	*nsubch0 = nsubch;
708 	error = 0;
709 done:
710 	vmbus_xact_put(xact);
711 	return (error);
712 }
713 
714 int
715 hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
716     struct hn_nvs_sendctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
717 {
718 
719 	return hn_nvs_send_rndis_sglist(chan, HN_NVS_RNDIS_MTYPE_CTRL,
720 	    sndc, gpa, gpa_cnt);
721 }
722