hn_nvs.c revision 307185
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 * $FreeBSD: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c 307185 2016-10-13 06:39:06Z sephe $
29 */
30
31/**
32 * HyperV vmbus network VSC (virtual services client) module
33 *
34 */
35
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/socket.h>
40#include <sys/limits.h>
41#include <sys/lock.h>
42#include <net/if.h>
43#include <net/if_arp.h>
44#include <machine/bus.h>
45#include <machine/atomic.h>
46
47#include <dev/hyperv/include/hyperv.h>
48#include <dev/hyperv/include/vmbus_xact.h>
49#include <dev/hyperv/netvsc/hv_net_vsc.h>
50#include <dev/hyperv/netvsc/hv_rndis.h>
51#include <dev/hyperv/netvsc/hv_rndis_filter.h>
52#include <dev/hyperv/netvsc/if_hnreg.h>
53
54MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
55
56/*
57 * Forward declarations
58 */
59static void hv_nv_on_channel_callback(struct vmbus_channel *chan,
60    void *xrxr);
61static int  hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc);
62static int  hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *, int);
63static int  hv_nv_destroy_send_buffer(struct hn_softc *sc);
64static int  hv_nv_destroy_rx_buffer(struct hn_softc *sc);
65static int  hv_nv_connect_to_vsp(struct hn_softc *sc);
66static void hv_nv_on_send_completion(struct hn_softc *sc,
67    struct vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt);
68static void hv_nv_on_receive_completion(struct vmbus_channel *chan,
69    uint64_t tid);
70static void hv_nv_on_receive(struct hn_softc *sc,
71    struct hn_rx_ring *rxr, struct vmbus_channel *chan,
72    const struct vmbus_chanpkt_hdr *pkt);
73static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
74    struct hn_softc *, struct vmbus_channel *chan,
75    const void *, int);
76
77struct hn_send_ctx	hn_send_ctx_none =
78    HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
79
80uint32_t
81hn_chim_alloc(struct hn_softc *sc)
82{
83	int i, bmap_cnt = sc->hn_chim_bmap_cnt;
84	u_long *bmap = sc->hn_chim_bmap;
85	uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
86
87	for (i = 0; i < bmap_cnt; ++i) {
88		int idx;
89
90		idx = ffsl(~bmap[i]);
91		if (idx == 0)
92			continue;
93
94		--idx; /* ffsl is 1-based */
95		KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
96		    ("invalid i %d and idx %d", i, idx));
97
98		if (atomic_testandset_long(&bmap[i], idx))
99			continue;
100
101		ret = i * LONG_BIT + idx;
102		break;
103	}
104	return (ret);
105}
106
107const void *
108hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
109    void *req, int reqlen, size_t *resp_len)
110{
111	struct hn_send_ctx sndc;
112	int error;
113
114	hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
115	vmbus_xact_activate(xact);
116
117	error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC,
118	    req, reqlen, &sndc);
119	if (error) {
120		vmbus_xact_deactivate(xact);
121		return NULL;
122	}
123	return (vmbus_xact_wait(xact, resp_len));
124}
125
126static __inline int
127hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen)
128{
129
130	return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE,
131	    req, reqlen, &hn_send_ctx_none));
132}
133
134/*
135 * Net VSC initialize receive buffer with net VSP
136 *
137 * Net VSP:  Network virtual services client, also known as the
138 *     Hyper-V extensible switch and the synthetic data path.
139 */
140static int
141hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc, int rxbuf_size)
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;
149
150	KASSERT(rxbuf_size <= NETVSC_RECEIVE_BUFFER_SIZE,
151	    ("invalid rxbuf size %d", rxbuf_size));
152
153	/*
154	 * Connect the RXBUF GPADL to the primary channel.
155	 *
156	 * NOTE:
157	 * Only primary channel has RXBUF connected to it.  Sub-channels
158	 * just share this RXBUF.
159	 */
160	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
161	    sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
162	if (error) {
163		if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
164		    error);
165		goto cleanup;
166	}
167
168	/*
169	 * Connect RXBUF to NVS.
170	 */
171
172	xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn));
173	if (xact == NULL) {
174		if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n");
175		error = ENXIO;
176		goto cleanup;
177	}
178	conn = vmbus_xact_req_data(xact);
179	conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
180	conn->nvs_gpadl = sc->hn_rxbuf_gpadl;
181	conn->nvs_sig = HN_NVS_RXBUF_SIG;
182
183	resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len);
184	if (resp == NULL) {
185		if_printf(sc->hn_ifp, "exec rxbuf conn failed\n");
186		error = EIO;
187		goto cleanup;
188	}
189	if (resp_len < sizeof(*resp)) {
190		if_printf(sc->hn_ifp, "invalid rxbuf conn resp length %zu\n",
191		    resp_len);
192		error = EINVAL;
193		goto cleanup;
194	}
195	if (resp->nvs_type != HN_NVS_TYPE_RXBUF_CONNRESP) {
196		if_printf(sc->hn_ifp, "not rxbuf conn resp, type %u\n",
197		    resp->nvs_type);
198		error = EINVAL;
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, "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
215cleanup:
216	if (xact != NULL)
217		vmbus_xact_put(xact);
218	hv_nv_destroy_rx_buffer(sc);
219	return (error);
220}
221
222/*
223 * Net VSC initialize send buffer with net VSP
224 */
225static int
226hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
227{
228	struct vmbus_xact *xact = NULL;
229	struct hn_nvs_chim_conn *chim;
230	const struct hn_nvs_chim_connresp *resp;
231	size_t resp_len;
232	uint32_t status, sectsz;
233	int error;
234
235	/*
236	 * Connect chimney sending buffer GPADL to the primary channel.
237	 *
238	 * NOTE:
239	 * Only primary channel has chimney sending buffer connected to it.
240	 * Sub-channels just share this chimney sending buffer.
241	 */
242	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
243  	    sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE,
244	    &sc->hn_chim_gpadl);
245	if (error) {
246		if_printf(sc->hn_ifp, "chimney sending buffer gpadl "
247		    "connect failed: %d\n", error);
248		goto cleanup;
249	}
250
251	/*
252	 * Connect chimney sending buffer to NVS
253	 */
254
255	xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim));
256	if (xact == NULL) {
257		if_printf(sc->hn_ifp, "no xact for nvs chim conn\n");
258		error = ENXIO;
259		goto cleanup;
260	}
261	chim = vmbus_xact_req_data(xact);
262	chim->nvs_type = HN_NVS_TYPE_CHIM_CONN;
263	chim->nvs_gpadl = sc->hn_chim_gpadl;
264	chim->nvs_sig = HN_NVS_CHIM_SIG;
265
266	resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len);
267	if (resp == NULL) {
268		if_printf(sc->hn_ifp, "exec chim conn failed\n");
269		error = EIO;
270		goto cleanup;
271	}
272	if (resp_len < sizeof(*resp)) {
273		if_printf(sc->hn_ifp, "invalid chim conn resp length %zu\n",
274		    resp_len);
275		error = EINVAL;
276		goto cleanup;
277	}
278	if (resp->nvs_type != HN_NVS_TYPE_CHIM_CONNRESP) {
279		if_printf(sc->hn_ifp, "not chim conn resp, type %u\n",
280		    resp->nvs_type);
281		error = EINVAL;
282		goto cleanup;
283	}
284
285	status = resp->nvs_status;
286	sectsz = resp->nvs_sectsz;
287	vmbus_xact_put(xact);
288	xact = NULL;
289
290	if (status != HN_NVS_STATUS_OK) {
291		if_printf(sc->hn_ifp, "chim conn failed: %x\n", status);
292		error = EIO;
293		goto cleanup;
294	}
295	if (sectsz == 0) {
296		if_printf(sc->hn_ifp, "zero chimney sending buffer "
297		    "section size\n");
298		return 0;
299	}
300
301	sc->hn_chim_szmax = sectsz;
302	sc->hn_chim_cnt = NETVSC_SEND_BUFFER_SIZE / sc->hn_chim_szmax;
303	if (NETVSC_SEND_BUFFER_SIZE % sc->hn_chim_szmax != 0) {
304		if_printf(sc->hn_ifp, "chimney sending sections are "
305		    "not properly aligned\n");
306	}
307	if (sc->hn_chim_cnt % LONG_BIT != 0) {
308		if_printf(sc->hn_ifp, "discard %d chimney sending sections\n",
309		    sc->hn_chim_cnt % LONG_BIT);
310	}
311
312	sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT;
313	sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long),
314	    M_NETVSC, M_WAITOK | M_ZERO);
315
316	/* Done! */
317	sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
318	if (bootverbose) {
319		if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
320		    sc->hn_chim_szmax, sc->hn_chim_cnt);
321	}
322	return 0;
323
324cleanup:
325	if (xact != NULL)
326		vmbus_xact_put(xact);
327	hv_nv_destroy_send_buffer(sc);
328	return (error);
329}
330
331/*
332 * Net VSC destroy receive buffer
333 */
334static int
335hv_nv_destroy_rx_buffer(struct hn_softc *sc)
336{
337	int ret = 0;
338
339	if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
340		struct hn_nvs_rxbuf_disconn disconn;
341
342		/*
343		 * Disconnect RXBUF from NVS.
344		 */
345		memset(&disconn, 0, sizeof(disconn));
346		disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
347		disconn.nvs_sig = HN_NVS_RXBUF_SIG;
348
349		/* NOTE: No response. */
350		ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
351		if (ret != 0) {
352			if_printf(sc->hn_ifp,
353			    "send rxbuf disconn failed: %d\n", ret);
354			return (ret);
355		}
356		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
357	}
358
359	if (sc->hn_rxbuf_gpadl != 0) {
360		/*
361		 * Disconnect RXBUF from primary channel.
362		 */
363		ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
364		    sc->hn_rxbuf_gpadl);
365		if (ret != 0) {
366			if_printf(sc->hn_ifp,
367			    "rxbuf disconn failed: %d\n", ret);
368			return (ret);
369		}
370		sc->hn_rxbuf_gpadl = 0;
371	}
372	return (ret);
373}
374
375/*
376 * Net VSC destroy send buffer
377 */
378static int
379hv_nv_destroy_send_buffer(struct hn_softc *sc)
380{
381	int ret = 0;
382
383	if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
384		struct hn_nvs_chim_disconn disconn;
385
386		/*
387		 * Disconnect chimney sending buffer from NVS.
388		 */
389		memset(&disconn, 0, sizeof(disconn));
390		disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
391		disconn.nvs_sig = HN_NVS_CHIM_SIG;
392
393		/* NOTE: No response. */
394		ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
395		if (ret != 0) {
396			if_printf(sc->hn_ifp,
397			    "send chim disconn failed: %d\n", ret);
398			return (ret);
399		}
400		sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
401	}
402
403	if (sc->hn_chim_gpadl != 0) {
404		/*
405		 * Disconnect chimney sending buffer from primary channel.
406		 */
407		ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
408		    sc->hn_chim_gpadl);
409		if (ret != 0) {
410			if_printf(sc->hn_ifp,
411			    "chim disconn failed: %d\n", ret);
412			return (ret);
413		}
414		sc->hn_chim_gpadl = 0;
415	}
416
417	if (sc->hn_chim_bmap != NULL) {
418		free(sc->hn_chim_bmap, M_NETVSC);
419		sc->hn_chim_bmap = NULL;
420	}
421
422	return (ret);
423}
424
425static int
426hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, uint32_t nvs_ver)
427{
428	struct vmbus_xact *xact;
429	struct hn_nvs_init *init;
430	const struct hn_nvs_init_resp *resp;
431	size_t resp_len;
432	uint32_t status;
433
434	xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
435	if (xact == NULL) {
436		if_printf(sc->hn_ifp, "no xact for nvs init\n");
437		return (ENXIO);
438	}
439	init = vmbus_xact_req_data(xact);
440	init->nvs_type = HN_NVS_TYPE_INIT;
441	init->nvs_ver_min = nvs_ver;
442	init->nvs_ver_max = nvs_ver;
443
444	resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len);
445	if (resp == NULL) {
446		if_printf(sc->hn_ifp, "exec init failed\n");
447		vmbus_xact_put(xact);
448		return (EIO);
449	}
450	if (resp_len < sizeof(*resp)) {
451		if_printf(sc->hn_ifp, "invalid init resp length %zu\n",
452		    resp_len);
453		vmbus_xact_put(xact);
454		return (EINVAL);
455	}
456	if (resp->nvs_type != HN_NVS_TYPE_INIT_RESP) {
457		if_printf(sc->hn_ifp, "not init resp, type %u\n",
458		    resp->nvs_type);
459		vmbus_xact_put(xact);
460		return (EINVAL);
461	}
462
463	status = resp->nvs_status;
464	vmbus_xact_put(xact);
465
466	if (status != HN_NVS_STATUS_OK) {
467		if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
468		    nvs_ver);
469		return (EINVAL);
470	}
471	return (0);
472}
473
474/*
475 * Send NDIS version 2 config packet containing MTU.
476 *
477 * Not valid for NDIS version 1.
478 */
479static int
480hv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu)
481{
482	struct hn_nvs_ndis_conf conf;
483	int error;
484
485	memset(&conf, 0, sizeof(conf));
486	conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
487	conf.nvs_mtu = mtu;
488	conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
489
490	/* NOTE: No response. */
491	error = hn_nvs_req_send(sc, &conf, sizeof(conf));
492	if (error)
493		if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
494	return (error);
495}
496
497/*
498 * Net VSC connect to VSP
499 */
500static int
501hv_nv_connect_to_vsp(struct hn_softc *sc)
502{
503	uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1,
504	    NVSP_PROTOCOL_VERSION_2,
505	    NVSP_PROTOCOL_VERSION_4,
506	    NVSP_PROTOCOL_VERSION_5 };
507	int i;
508	int protocol_number = nitems(protocol_list);
509	int ret = 0;
510	device_t dev = sc->hn_dev;
511	struct ifnet *ifp = sc->arpcom.ac_ifp;
512	struct hn_nvs_ndis_init ndis;
513	int rxbuf_size;
514
515	/*
516	 * Negotiate the NVSP version.  Try the latest NVSP first.
517	 */
518	for (i = protocol_number - 1; i >= 0; i--) {
519		if (hv_nv_negotiate_nvsp_protocol(sc, protocol_list[i]) == 0) {
520			sc->hn_nvs_ver = protocol_list[i];
521			sc->hn_ndis_ver = NDIS_VERSION_6_30;
522			if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_4)
523				sc->hn_ndis_ver = NDIS_VERSION_6_1;
524			if (bootverbose) {
525				if_printf(sc->hn_ifp, "NVS version 0x%x, "
526				    "NDIS version %u.%u\n",
527				    sc->hn_nvs_ver,
528				    NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
529				    NDIS_VERSION_MINOR(sc->hn_ndis_ver));
530			}
531			break;
532		}
533	}
534
535	if (i < 0) {
536		if (bootverbose)
537			device_printf(dev, "failed to negotiate a valid "
538			    "protocol.\n");
539		return (EPROTO);
540	}
541
542	/*
543	 * Set the MTU if supported by this NVSP protocol version
544	 * This needs to be right after the NVSP init message per Haiyang
545	 */
546	if (sc->hn_nvs_ver >= NVSP_PROTOCOL_VERSION_2)
547		ret = hv_nv_send_ndis_config(sc, ifp->if_mtu);
548
549	/*
550	 * Initialize NDIS.
551	 */
552
553	memset(&ndis, 0, sizeof(ndis));
554	ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
555	ndis.nvs_ndis_major = NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
556	ndis.nvs_ndis_minor = NDIS_VERSION_MINOR(sc->hn_ndis_ver);
557
558	/* NOTE: No response. */
559	ret = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
560	if (ret != 0) {
561		if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", ret);
562		goto cleanup;
563	}
564
565	/* Post the big receive buffer to NetVSP */
566	if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_2)
567		rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
568	else
569		rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE;
570
571	ret = hv_nv_init_rx_buffer_with_net_vsp(sc, rxbuf_size);
572	if (ret == 0)
573		ret = hv_nv_init_send_buffer_with_net_vsp(sc);
574
575cleanup:
576	return (ret);
577}
578
579/*
580 * Net VSC disconnect from VSP
581 */
582static void
583hv_nv_disconnect_from_vsp(struct hn_softc *sc)
584{
585	hv_nv_destroy_rx_buffer(sc);
586	hv_nv_destroy_send_buffer(sc);
587}
588
589void
590hv_nv_subchan_attach(struct vmbus_channel *chan, struct hn_rx_ring *rxr)
591{
592	KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan),
593	    ("chan%u subidx %u, rxr%d mismatch",
594	     vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx));
595	vmbus_chan_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE,
596	    NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0,
597	    hv_nv_on_channel_callback, rxr);
598}
599
600/*
601 * Net VSC on device add
602 *
603 * Callback when the device belonging to this driver is added
604 */
605int
606hv_nv_on_device_add(struct hn_softc *sc, struct hn_rx_ring *rxr)
607{
608	struct vmbus_channel *chan = sc->hn_prichan;
609	int ret = 0;
610
611	/*
612	 * Open the channel
613	 */
614	KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan),
615	    ("chan%u subidx %u, rxr%d mismatch",
616	     vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx));
617	ret = vmbus_chan_open(chan,
618	    NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE,
619	    NULL, 0, hv_nv_on_channel_callback, rxr);
620	if (ret != 0)
621		goto cleanup;
622
623	/*
624	 * Connect with the NetVsp
625	 */
626	ret = hv_nv_connect_to_vsp(sc);
627	if (ret != 0)
628		goto close;
629
630	return (0);
631
632close:
633	/* Now, we can close the channel safely */
634	vmbus_chan_close(chan);
635cleanup:
636	return (ret);
637}
638
639/*
640 * Net VSC on device remove
641 */
642int
643hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
644{
645
646	hv_nv_disconnect_from_vsp(sc);
647
648	/* Now, we can close the channel safely */
649
650	vmbus_chan_close(sc->hn_prichan);
651
652	return (0);
653}
654
655void
656hn_nvs_sent_xact(struct hn_send_ctx *sndc,
657    struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
658    const void *data, int dlen)
659{
660
661	vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
662}
663
664static void
665hn_nvs_sent_none(struct hn_send_ctx *sndc __unused,
666    struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
667    const void *data __unused, int dlen __unused)
668{
669	/* EMPTY */
670}
671
672void
673hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
674{
675	u_long mask;
676	uint32_t idx;
677
678	idx = chim_idx / LONG_BIT;
679	KASSERT(idx < sc->hn_chim_bmap_cnt,
680	    ("invalid chimney index 0x%x", chim_idx));
681
682	mask = 1UL << (chim_idx % LONG_BIT);
683	KASSERT(sc->hn_chim_bmap[idx] & mask,
684	    ("index bitmap 0x%lx, chimney index %u, "
685	     "bitmap idx %d, bitmask 0x%lx",
686	     sc->hn_chim_bmap[idx], chim_idx, idx, mask));
687
688	atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
689}
690
691/*
692 * Net VSC on send completion
693 */
694static void
695hv_nv_on_send_completion(struct hn_softc *sc, struct vmbus_channel *chan,
696    const struct vmbus_chanpkt_hdr *pkt)
697{
698	struct hn_send_ctx *sndc;
699
700	sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid;
701	sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
702	    VMBUS_CHANPKT_DATALEN(pkt));
703	/*
704	 * NOTE:
705	 * 'sndc' CAN NOT be accessed anymore, since it can be freed by
706	 * its callback.
707	 */
708}
709
710/*
711 * Net VSC on send
712 * Sends a packet on the specified Hyper-V device.
713 * Returns 0 on success, non-zero on failure.
714 */
715int
716hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype,
717    struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
718{
719	struct hn_nvs_rndis rndis;
720	int ret;
721
722	rndis.nvs_type = HN_NVS_TYPE_RNDIS;
723	rndis.nvs_rndis_mtype = rndis_mtype;
724	rndis.nvs_chim_idx = sndc->hn_chim_idx;
725	rndis.nvs_chim_sz = sndc->hn_chim_sz;
726
727	if (gpa_cnt) {
728		ret = hn_nvs_send_sglist(chan, gpa, gpa_cnt,
729		    &rndis, sizeof(rndis), sndc);
730	} else {
731		ret = hn_nvs_send(chan, VMBUS_CHANPKT_FLAG_RC,
732		    &rndis, sizeof(rndis), sndc);
733	}
734
735	return (ret);
736}
737
738/*
739 * Net VSC on receive
740 *
741 * In the FreeBSD Hyper-V virtual world, this function deals exclusively
742 * with virtual addresses.
743 */
744static void
745hv_nv_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
746    struct vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
747{
748	const struct vmbus_chanpkt_rxbuf *pkt;
749	const struct hn_nvs_hdr *nvs_hdr;
750	int count = 0;
751	int i = 0;
752
753	/* Make sure that this is a RNDIS message. */
754	nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr);
755	if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) {
756		if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n",
757		    nvs_hdr->nvs_type);
758		return;
759	}
760
761	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
762
763	if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) {
764		if_printf(rxr->hn_ifp, "rxbuf_id %d is invalid!\n",
765		    pkt->cp_rxbuf_id);
766		return;
767	}
768
769	count = pkt->cp_rxbuf_cnt;
770
771	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
772	for (i = 0; i < count; i++) {
773		hv_rf_on_receive(sc, rxr,
774		    rxr->hn_rxbuf + pkt->cp_rxbuf[i].rb_ofs,
775		    pkt->cp_rxbuf[i].rb_len);
776	}
777
778	/*
779	 * Moved completion call back here so that all received
780	 * messages (not just data messages) will trigger a response
781	 * message back to the host.
782	 */
783	hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid);
784}
785
786/*
787 * Net VSC on receive completion
788 *
789 * Send a receive completion packet to RNDIS device (ie NetVsp)
790 */
791static void
792hv_nv_on_receive_completion(struct vmbus_channel *chan, uint64_t tid)
793{
794	struct hn_nvs_rndis_ack ack;
795	int retries = 0;
796	int ret = 0;
797
798	ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK;
799	ack.nvs_status = HN_NVS_STATUS_OK;
800
801retry_send_cmplt:
802	/* Send the completion */
803	ret = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP,
804	    VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid);
805	if (ret == 0) {
806		/* success */
807		/* no-op */
808	} else if (ret == EAGAIN) {
809		/* no more room... wait a bit and attempt to retry 3 times */
810		retries++;
811
812		if (retries < 4) {
813			DELAY(100);
814			goto retry_send_cmplt;
815		}
816	}
817}
818
819static void
820hn_proc_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
821{
822	const struct hn_nvs_hdr *hdr;
823
824	hdr = VMBUS_CHANPKT_CONST_DATA(pkt);
825	if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) {
826		/* Useless; ignore */
827		return;
828	}
829	if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type);
830}
831
832/*
833 * Net VSC on channel callback
834 */
835static void
836hv_nv_on_channel_callback(struct vmbus_channel *chan, void *xrxr)
837{
838	struct hn_rx_ring *rxr = xrxr;
839	struct hn_softc *sc = rxr->hn_ifp->if_softc;
840	void *buffer;
841	int bufferlen = NETVSC_PACKET_SIZE;
842
843	buffer = rxr->hn_rdbuf;
844	do {
845		struct vmbus_chanpkt_hdr *pkt = buffer;
846		uint32_t bytes_rxed;
847		int ret;
848
849		bytes_rxed = bufferlen;
850		ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed);
851		if (ret == 0) {
852			if (bytes_rxed > 0) {
853				switch (pkt->cph_type) {
854				case VMBUS_CHANPKT_TYPE_COMP:
855					hv_nv_on_send_completion(sc, chan, pkt);
856					break;
857				case VMBUS_CHANPKT_TYPE_RXBUF:
858					hv_nv_on_receive(sc, rxr, chan, pkt);
859					break;
860				case VMBUS_CHANPKT_TYPE_INBAND:
861					hn_proc_notify(sc, pkt);
862					break;
863				default:
864					if_printf(rxr->hn_ifp,
865					    "unknown chan pkt %u\n",
866					    pkt->cph_type);
867					break;
868				}
869			}
870		} else if (ret == ENOBUFS) {
871			/* Handle large packet */
872			if (bufferlen > NETVSC_PACKET_SIZE) {
873				free(buffer, M_NETVSC);
874				buffer = NULL;
875			}
876
877			/* alloc new buffer */
878			buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT);
879			if (buffer == NULL) {
880				if_printf(rxr->hn_ifp,
881				    "hv_cb malloc buffer failed, len=%u\n",
882				    bytes_rxed);
883				bufferlen = 0;
884				break;
885			}
886			bufferlen = bytes_rxed;
887		} else {
888			/* No more packets */
889			break;
890		}
891	} while (1);
892
893	if (bufferlen > NETVSC_PACKET_SIZE)
894		free(buffer, M_NETVSC);
895
896	hv_rf_channel_rollup(rxr, rxr->hn_txr);
897}
898