hn_nvs.c revision 307081
1250199Sgrehan/*-
2302045Ssephe * Copyright (c) 2009-2012,2016 Microsoft Corp.
3250199Sgrehan * Copyright (c) 2010-2012 Citrix Inc.
4250199Sgrehan * Copyright (c) 2012 NetApp Inc.
5250199Sgrehan * All rights reserved.
6250199Sgrehan *
7250199Sgrehan * Redistribution and use in source and binary forms, with or without
8250199Sgrehan * modification, are permitted provided that the following conditions
9250199Sgrehan * are met:
10250199Sgrehan * 1. Redistributions of source code must retain the above copyright
11250199Sgrehan *    notice unmodified, this list of conditions, and the following
12250199Sgrehan *    disclaimer.
13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
14250199Sgrehan *    notice, this list of conditions and the following disclaimer in the
15250199Sgrehan *    documentation and/or other materials provided with the distribution.
16250199Sgrehan *
17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27266794Smarius *
28266794Smarius * $FreeBSD: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c 307081 2016-10-12 02:15:06Z sephe $
29250199Sgrehan */
30250199Sgrehan
31250199Sgrehan/**
32250199Sgrehan * HyperV vmbus network VSC (virtual services client) module
33250199Sgrehan *
34250199Sgrehan */
35250199Sgrehan
36250199Sgrehan
37250199Sgrehan#include <sys/param.h>
38250199Sgrehan#include <sys/kernel.h>
39250199Sgrehan#include <sys/socket.h>
40250199Sgrehan#include <sys/lock.h>
41250199Sgrehan#include <net/if.h>
42250199Sgrehan#include <net/if_arp.h>
43250199Sgrehan#include <machine/bus.h>
44250199Sgrehan#include <machine/atomic.h>
45250199Sgrehan
46250199Sgrehan#include <dev/hyperv/include/hyperv.h>
47250199Sgrehan#include "hv_net_vsc.h"
48250199Sgrehan#include "hv_rndis.h"
49250199Sgrehan#include "hv_rndis_filter.h"
50250199Sgrehan
51301918Ssephe/* priv1 and priv2 are consumed by the main driver */
52301918Ssephe#define hv_chan_rdbuf	hv_chan_priv3
53301918Ssephe
54285236SwhuMALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
55250199Sgrehan
56250199Sgrehan/*
57250199Sgrehan * Forward declarations
58250199Sgrehan */
59301943Ssephestatic void hv_nv_on_channel_callback(void *xchan);
60307022Ssephestatic int  hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc);
61307022Ssephestatic int  hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *);
62250199Sgrehanstatic int  hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
63250199Sgrehanstatic int  hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
64307022Ssephestatic int  hv_nv_connect_to_vsp(struct hn_softc *sc);
65285236Swhustatic void hv_nv_on_send_completion(netvsc_dev *net_dev,
66307080Ssephe    struct hv_vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt);
67301918Ssephestatic void hv_nv_on_receive_completion(struct hv_vmbus_channel *chan,
68301918Ssephe    uint64_t tid, uint32_t status);
69285236Swhustatic void hv_nv_on_receive(netvsc_dev *net_dev,
70307022Ssephe    struct hn_softc *sc, struct hv_vmbus_channel *chan,
71307080Ssephe    const struct vmbus_chanpkt_hdr *pkt);
72250199Sgrehan
73250199Sgrehan/*
74250199Sgrehan *
75250199Sgrehan */
76250199Sgrehanstatic inline netvsc_dev *
77307022Ssephehv_nv_alloc_net_device(struct hn_softc *sc)
78250199Sgrehan{
79250199Sgrehan	netvsc_dev *net_dev;
80250199Sgrehan
81301859Ssephe	net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_WAITOK | M_ZERO);
82250199Sgrehan
83307022Ssephe	net_dev->sc = sc;
84250199Sgrehan	net_dev->destroy = FALSE;
85250199Sgrehan	sc->net_dev = net_dev;
86250199Sgrehan
87250199Sgrehan	return (net_dev);
88250199Sgrehan}
89250199Sgrehan
90250199Sgrehan/*
91307022Ssephe * XXX unnecessary; nuke it.
92250199Sgrehan */
93250199Sgrehanstatic inline netvsc_dev *
94307022Ssephehv_nv_get_outbound_net_device(struct hn_softc *sc)
95250199Sgrehan{
96307022Ssephe	return sc->net_dev;
97250199Sgrehan}
98250199Sgrehan
99250199Sgrehan/*
100307022Ssephe * XXX unnecessary; nuke it.
101250199Sgrehan */
102250199Sgrehanstatic inline netvsc_dev *
103307022Ssephehv_nv_get_inbound_net_device(struct hn_softc *sc)
104250199Sgrehan{
105307022Ssephe	return sc->net_dev;
106250199Sgrehan}
107250199Sgrehan
108285236Swhuint
109285236Swhuhv_nv_get_next_send_section(netvsc_dev *net_dev)
110285236Swhu{
111285236Swhu	unsigned long bitsmap_words = net_dev->bitsmap_words;
112285236Swhu	unsigned long *bitsmap = net_dev->send_section_bitsmap;
113285236Swhu	unsigned long idx;
114285236Swhu	int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
115285236Swhu	int i;
116285236Swhu
117285236Swhu	for (i = 0; i < bitsmap_words; i++) {
118301857Ssephe		idx = ffsl(~bitsmap[i]);
119285236Swhu		if (0 == idx)
120285236Swhu			continue;
121285236Swhu
122285236Swhu		idx--;
123301857Ssephe		KASSERT(i * BITS_PER_LONG + idx < net_dev->send_section_count,
124301857Ssephe		    ("invalid i %d and idx %lu", i, idx));
125285236Swhu
126301857Ssephe		if (atomic_testandset_long(&bitsmap[i], idx))
127285236Swhu			continue;
128285236Swhu
129285236Swhu		ret = i * BITS_PER_LONG + idx;
130285236Swhu		break;
131285236Swhu	}
132285236Swhu
133285236Swhu	return (ret);
134285236Swhu}
135285236Swhu
136250199Sgrehan/*
137250199Sgrehan * Net VSC initialize receive buffer with net VSP
138250199Sgrehan *
139250199Sgrehan * Net VSP:  Network virtual services client, also known as the
140250199Sgrehan *     Hyper-V extensible switch and the synthetic data path.
141250199Sgrehan */
142250199Sgrehanstatic int
143307022Ssephehv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
144250199Sgrehan{
145250199Sgrehan	netvsc_dev *net_dev;
146250199Sgrehan	nvsp_msg *init_pkt;
147250199Sgrehan	int ret = 0;
148250199Sgrehan
149307022Ssephe	net_dev = hv_nv_get_outbound_net_device(sc);
150250199Sgrehan	if (!net_dev) {
151250199Sgrehan		return (ENODEV);
152250199Sgrehan	}
153250199Sgrehan
154307081Ssephe	net_dev->rx_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
155307081Ssephe	    PAGE_SIZE, 0, net_dev->rx_buf_size, &net_dev->rxbuf_dma,
156307081Ssephe	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
157307081Ssephe	if (net_dev->rx_buf == NULL) {
158307081Ssephe		device_printf(sc->hn_dev, "allocate rxbuf failed\n");
159307081Ssephe		return ENOMEM;
160307081Ssephe	}
161250199Sgrehan
162250199Sgrehan	/*
163307081Ssephe	 * Connect the RXBUF GPADL to the primary channel.
164307081Ssephe	 *
165307081Ssephe	 * NOTE:
166307081Ssephe	 * Only primary channel has RXBUF connected to it.  Sub-channels
167307081Ssephe	 * just share this RXBUF.
168250199Sgrehan	 */
169307081Ssephe	ret = vmbus_chan_gpadl_connect(sc->hn_prichan,
170307081Ssephe	    net_dev->rxbuf_dma.hv_paddr, net_dev->rx_buf_size,
171307081Ssephe	    &net_dev->rx_buf_gpadl_handle);
172250199Sgrehan	if (ret != 0) {
173307081Ssephe		device_printf(sc->hn_dev, "rxbuf gpadl connect failed: %d\n",
174307081Ssephe		    ret);
175250199Sgrehan		goto cleanup;
176250199Sgrehan	}
177250199Sgrehan
178250199Sgrehan	/* sema_wait(&ext->channel_init_sema); KYS CHECK */
179250199Sgrehan
180250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
181250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
182250199Sgrehan
183250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
184250199Sgrehan
185250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf;
186250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
187250199Sgrehan	    net_dev->rx_buf_gpadl_handle;
188250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
189250199Sgrehan	    NETVSC_RECEIVE_BUFFER_ID;
190250199Sgrehan
191250199Sgrehan	/* Send the gpadl notification request */
192250199Sgrehan
193307079Ssephe	ret = vmbus_chan_send(sc->hn_prichan,
194307079Ssephe	    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
195307079Ssephe	    init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
196250199Sgrehan	if (ret != 0) {
197250199Sgrehan		goto cleanup;
198250199Sgrehan	}
199250199Sgrehan
200250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
201250199Sgrehan
202250199Sgrehan	/* Check the response */
203250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status
204250199Sgrehan	    != nvsp_status_success) {
205250199Sgrehan		ret = EINVAL;
206250199Sgrehan		goto cleanup;
207250199Sgrehan	}
208250199Sgrehan
209250199Sgrehan	net_dev->rx_section_count =
210250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections;
211250199Sgrehan
212250199Sgrehan	net_dev->rx_sections = malloc(net_dev->rx_section_count *
213301859Ssephe	    sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_WAITOK);
214250199Sgrehan	memcpy(net_dev->rx_sections,
215250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections,
216250199Sgrehan	    net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section));
217250199Sgrehan
218250199Sgrehan
219250199Sgrehan	/*
220250199Sgrehan	 * For first release, there should only be 1 section that represents
221250199Sgrehan	 * the entire receive buffer
222250199Sgrehan	 */
223250199Sgrehan	if (net_dev->rx_section_count != 1
224250199Sgrehan	    || net_dev->rx_sections->offset != 0) {
225250199Sgrehan		ret = EINVAL;
226250199Sgrehan		goto cleanup;
227250199Sgrehan	}
228250199Sgrehan
229250199Sgrehan	goto exit;
230250199Sgrehan
231250199Sgrehancleanup:
232250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
233250199Sgrehan
234250199Sgrehanexit:
235250199Sgrehan	return (ret);
236250199Sgrehan}
237250199Sgrehan
238250199Sgrehan/*
239250199Sgrehan * Net VSC initialize send buffer with net VSP
240250199Sgrehan */
241250199Sgrehanstatic int
242307022Ssephehv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
243250199Sgrehan{
244250199Sgrehan	netvsc_dev *net_dev;
245250199Sgrehan	nvsp_msg *init_pkt;
246250199Sgrehan	int ret = 0;
247250199Sgrehan
248307022Ssephe	net_dev = hv_nv_get_outbound_net_device(sc);
249250199Sgrehan	if (!net_dev) {
250250199Sgrehan		return (ENODEV);
251250199Sgrehan	}
252250199Sgrehan
253307081Ssephe	net_dev->send_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev),
254307081Ssephe	    PAGE_SIZE, 0, net_dev->send_buf_size, &net_dev->txbuf_dma,
255307081Ssephe	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
256250199Sgrehan	if (net_dev->send_buf == NULL) {
257307081Ssephe		device_printf(sc->hn_dev, "allocate chimney txbuf failed\n");
258307081Ssephe		return ENOMEM;
259250199Sgrehan	}
260250199Sgrehan
261250199Sgrehan	/*
262307081Ssephe	 * Connect chimney sending buffer GPADL to the primary channel.
263307081Ssephe	 *
264307081Ssephe	 * NOTE:
265307081Ssephe	 * Only primary channel has chimney sending buffer connected to it.
266307081Ssephe	 * Sub-channels just share this chimney sending buffer.
267250199Sgrehan	 */
268307081Ssephe	ret = vmbus_chan_gpadl_connect(sc->hn_prichan,
269307081Ssephe  	    net_dev->txbuf_dma.hv_paddr, net_dev->send_buf_size,
270250199Sgrehan	    &net_dev->send_buf_gpadl_handle);
271250199Sgrehan	if (ret != 0) {
272307081Ssephe		device_printf(sc->hn_dev, "chimney sending buffer gpadl "
273307081Ssephe		    "connect failed: %d\n", ret);
274250199Sgrehan		goto cleanup;
275250199Sgrehan	}
276250199Sgrehan
277250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
278250199Sgrehan
279250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
280250199Sgrehan
281250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
282250199Sgrehan
283250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf;
284250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
285250199Sgrehan	    net_dev->send_buf_gpadl_handle;
286250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
287250199Sgrehan	    NETVSC_SEND_BUFFER_ID;
288250199Sgrehan
289250199Sgrehan	/* Send the gpadl notification request */
290250199Sgrehan
291307079Ssephe	ret = vmbus_chan_send(sc->hn_prichan,
292307079Ssephe	    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
293307079Ssephe  	    init_pkt, sizeof(nvsp_msg), (uint64_t)init_pkt);
294250199Sgrehan	if (ret != 0) {
295250199Sgrehan		goto cleanup;
296250199Sgrehan	}
297250199Sgrehan
298250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
299250199Sgrehan
300250199Sgrehan	/* Check the response */
301250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status
302250199Sgrehan	    != nvsp_status_success) {
303250199Sgrehan		ret = EINVAL;
304250199Sgrehan		goto cleanup;
305250199Sgrehan	}
306250199Sgrehan
307250199Sgrehan	net_dev->send_section_size =
308250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size;
309285236Swhu	net_dev->send_section_count =
310285236Swhu	    net_dev->send_buf_size / net_dev->send_section_size;
311285236Swhu	net_dev->bitsmap_words = howmany(net_dev->send_section_count,
312285236Swhu	    BITS_PER_LONG);
313285236Swhu	net_dev->send_section_bitsmap =
314285236Swhu	    malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC,
315301859Ssephe	    M_WAITOK | M_ZERO);
316250199Sgrehan
317250199Sgrehan	goto exit;
318250199Sgrehan
319250199Sgrehancleanup:
320250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
321250199Sgrehan
322250199Sgrehanexit:
323250199Sgrehan	return (ret);
324250199Sgrehan}
325250199Sgrehan
326250199Sgrehan/*
327250199Sgrehan * Net VSC destroy receive buffer
328250199Sgrehan */
329250199Sgrehanstatic int
330250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
331250199Sgrehan{
332250199Sgrehan	nvsp_msg *revoke_pkt;
333250199Sgrehan	int ret = 0;
334250199Sgrehan
335250199Sgrehan	/*
336250199Sgrehan	 * If we got a section count, it means we received a
337250199Sgrehan	 * send_rx_buf_complete msg
338250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
339250199Sgrehan	 * we need to send a revoke msg here
340250199Sgrehan	 */
341250199Sgrehan	if (net_dev->rx_section_count) {
342250199Sgrehan		/* Send the revoke receive buffer */
343250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
344250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
345250199Sgrehan
346250199Sgrehan		revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf;
347250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id =
348250199Sgrehan		    NETVSC_RECEIVE_BUFFER_ID;
349250199Sgrehan
350307079Ssephe		ret = vmbus_chan_send(net_dev->sc->hn_prichan,
351307079Ssephe		    VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
352307079Ssephe		    (uint64_t)(uintptr_t)revoke_pkt);
353250199Sgrehan
354250199Sgrehan		/*
355250199Sgrehan		 * If we failed here, we might as well return and have a leak
356250199Sgrehan		 * rather than continue and a bugchk
357250199Sgrehan		 */
358250199Sgrehan		if (ret != 0) {
359250199Sgrehan			return (ret);
360250199Sgrehan		}
361250199Sgrehan	}
362250199Sgrehan
363250199Sgrehan	/* Tear down the gpadl on the vsp end */
364250199Sgrehan	if (net_dev->rx_buf_gpadl_handle) {
365307022Ssephe		ret = hv_vmbus_channel_teardown_gpdal(net_dev->sc->hn_prichan,
366250199Sgrehan		    net_dev->rx_buf_gpadl_handle);
367250199Sgrehan		/*
368250199Sgrehan		 * If we failed here, we might as well return and have a leak
369250199Sgrehan		 * rather than continue and a bugchk
370250199Sgrehan		 */
371250199Sgrehan		if (ret != 0) {
372250199Sgrehan			return (ret);
373250199Sgrehan		}
374250199Sgrehan		net_dev->rx_buf_gpadl_handle = 0;
375250199Sgrehan	}
376250199Sgrehan
377250199Sgrehan	if (net_dev->rx_buf) {
378250199Sgrehan		/* Free up the receive buffer */
379307081Ssephe		hyperv_dmamem_free(&net_dev->rxbuf_dma, net_dev->rx_buf);
380250199Sgrehan		net_dev->rx_buf = NULL;
381250199Sgrehan	}
382250199Sgrehan
383250199Sgrehan	if (net_dev->rx_sections) {
384285236Swhu		free(net_dev->rx_sections, M_NETVSC);
385250199Sgrehan		net_dev->rx_sections = NULL;
386250199Sgrehan		net_dev->rx_section_count = 0;
387250199Sgrehan	}
388250199Sgrehan
389250199Sgrehan	return (ret);
390250199Sgrehan}
391250199Sgrehan
392250199Sgrehan/*
393250199Sgrehan * Net VSC destroy send buffer
394250199Sgrehan */
395250199Sgrehanstatic int
396250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev)
397250199Sgrehan{
398250199Sgrehan	nvsp_msg *revoke_pkt;
399250199Sgrehan	int ret = 0;
400250199Sgrehan
401250199Sgrehan	/*
402250199Sgrehan	 * If we got a section count, it means we received a
403250199Sgrehan	 * send_rx_buf_complete msg
404250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
405250199Sgrehan	 * we need to send a revoke msg here
406250199Sgrehan	 */
407250199Sgrehan	if (net_dev->send_section_size) {
408250199Sgrehan		/* Send the revoke send buffer */
409250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
410250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
411250199Sgrehan
412250199Sgrehan		revoke_pkt->hdr.msg_type =
413250199Sgrehan		    nvsp_msg_1_type_revoke_send_buf;
414250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id =
415250199Sgrehan		    NETVSC_SEND_BUFFER_ID;
416250199Sgrehan
417307079Ssephe		ret = vmbus_chan_send(net_dev->sc->hn_prichan,
418307079Ssephe		    VMBUS_CHANPKT_TYPE_INBAND, 0,
419250199Sgrehan		    revoke_pkt, sizeof(nvsp_msg),
420307079Ssephe		    (uint64_t)(uintptr_t)revoke_pkt);
421250199Sgrehan		/*
422250199Sgrehan		 * If we failed here, we might as well return and have a leak
423250199Sgrehan		 * rather than continue and a bugchk
424250199Sgrehan		 */
425250199Sgrehan		if (ret != 0) {
426250199Sgrehan			return (ret);
427250199Sgrehan		}
428250199Sgrehan	}
429250199Sgrehan
430250199Sgrehan	/* Tear down the gpadl on the vsp end */
431250199Sgrehan	if (net_dev->send_buf_gpadl_handle) {
432307022Ssephe		ret = hv_vmbus_channel_teardown_gpdal(net_dev->sc->hn_prichan,
433250199Sgrehan		    net_dev->send_buf_gpadl_handle);
434250199Sgrehan
435250199Sgrehan		/*
436250199Sgrehan		 * If we failed here, we might as well return and have a leak
437250199Sgrehan		 * rather than continue and a bugchk
438250199Sgrehan		 */
439250199Sgrehan		if (ret != 0) {
440250199Sgrehan			return (ret);
441250199Sgrehan		}
442250199Sgrehan		net_dev->send_buf_gpadl_handle = 0;
443250199Sgrehan	}
444250199Sgrehan
445250199Sgrehan	if (net_dev->send_buf) {
446250199Sgrehan		/* Free up the receive buffer */
447307081Ssephe		hyperv_dmamem_free(&net_dev->txbuf_dma, net_dev->send_buf);
448250199Sgrehan		net_dev->send_buf = NULL;
449250199Sgrehan	}
450250199Sgrehan
451285236Swhu	if (net_dev->send_section_bitsmap) {
452285236Swhu		free(net_dev->send_section_bitsmap, M_NETVSC);
453285236Swhu	}
454285236Swhu
455250199Sgrehan	return (ret);
456250199Sgrehan}
457250199Sgrehan
458250199Sgrehan
459250199Sgrehan/*
460250199Sgrehan * Attempt to negotiate the caller-specified NVSP version
461250199Sgrehan *
462250199Sgrehan * For NVSP v2, Server 2008 R2 does not set
463250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers
464250199Sgrehan * to the negotiated version, so we cannot rely on that.
465250199Sgrehan */
466250199Sgrehanstatic int
467307022Ssephehv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
468285236Swhu    uint32_t nvsp_ver)
469250199Sgrehan{
470250199Sgrehan	nvsp_msg *init_pkt;
471250199Sgrehan	int ret;
472250199Sgrehan
473250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
474250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
475250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_type_init;
476250199Sgrehan
477250199Sgrehan	/*
478250199Sgrehan	 * Specify parameter as the only acceptable protocol version
479250199Sgrehan	 */
480250199Sgrehan	init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver;
481250199Sgrehan	init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
482250199Sgrehan
483250199Sgrehan	/* Send the init request */
484307079Ssephe	ret = vmbus_chan_send(sc->hn_prichan,
485307079Ssephe	    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
486307079Ssephe	    init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
487250199Sgrehan	if (ret != 0)
488250199Sgrehan		return (-1);
489250199Sgrehan
490250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
491250199Sgrehan
492250199Sgrehan	if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success)
493250199Sgrehan		return (EINVAL);
494250199Sgrehan
495250199Sgrehan	return (0);
496250199Sgrehan}
497250199Sgrehan
498250199Sgrehan/*
499250199Sgrehan * Send NDIS version 2 config packet containing MTU.
500250199Sgrehan *
501250199Sgrehan * Not valid for NDIS version 1.
502250199Sgrehan */
503250199Sgrehanstatic int
504307022Ssephehv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu)
505250199Sgrehan{
506250199Sgrehan	netvsc_dev *net_dev;
507250199Sgrehan	nvsp_msg *init_pkt;
508250199Sgrehan	int ret;
509250199Sgrehan
510307022Ssephe	net_dev = hv_nv_get_outbound_net_device(sc);
511250199Sgrehan	if (!net_dev)
512250199Sgrehan		return (-ENODEV);
513250199Sgrehan
514250199Sgrehan	/*
515250199Sgrehan	 * Set up configuration packet, write MTU
516250199Sgrehan	 * Indicate we are capable of handling VLAN tags
517250199Sgrehan	 */
518250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
519250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
520250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config;
521250199Sgrehan	init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu;
522250199Sgrehan	init_pkt->
523250199Sgrehan		msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q
524250199Sgrehan		= 1;
525250199Sgrehan
526250199Sgrehan	/* Send the configuration packet */
527307079Ssephe	ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
528307079Ssephe	    init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
529250199Sgrehan	if (ret != 0)
530250199Sgrehan		return (-EINVAL);
531250199Sgrehan
532250199Sgrehan	return (0);
533250199Sgrehan}
534250199Sgrehan
535250199Sgrehan/*
536250199Sgrehan * Net VSC connect to VSP
537250199Sgrehan */
538250199Sgrehanstatic int
539307022Ssephehv_nv_connect_to_vsp(struct hn_softc *sc)
540250199Sgrehan{
541250199Sgrehan	netvsc_dev *net_dev;
542250199Sgrehan	nvsp_msg *init_pkt;
543250199Sgrehan	uint32_t ndis_version;
544285236Swhu	uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1,
545285236Swhu	    NVSP_PROTOCOL_VERSION_2,
546285236Swhu	    NVSP_PROTOCOL_VERSION_4,
547285236Swhu	    NVSP_PROTOCOL_VERSION_5 };
548285236Swhu	int i;
549285236Swhu	int protocol_number = nitems(protocol_list);
550250199Sgrehan	int ret = 0;
551307022Ssephe	device_t dev = sc->hn_dev;
552250199Sgrehan	struct ifnet *ifp = sc->arpcom.ac_ifp;
553250199Sgrehan
554307022Ssephe	net_dev = hv_nv_get_outbound_net_device(sc);
555250199Sgrehan
556250199Sgrehan	/*
557285236Swhu	 * Negotiate the NVSP version.  Try the latest NVSP first.
558250199Sgrehan	 */
559285236Swhu	for (i = protocol_number - 1; i >= 0; i--) {
560307022Ssephe		if (hv_nv_negotiate_nvsp_protocol(sc, net_dev,
561285236Swhu		    protocol_list[i]) == 0) {
562285236Swhu			net_dev->nvsp_version = protocol_list[i];
563285236Swhu			if (bootverbose)
564285236Swhu				device_printf(dev, "Netvsc: got version 0x%x\n",
565285236Swhu				    net_dev->nvsp_version);
566285236Swhu			break;
567250199Sgrehan		}
568250199Sgrehan	}
569250199Sgrehan
570285236Swhu	if (i < 0) {
571285236Swhu		if (bootverbose)
572285236Swhu			device_printf(dev, "failed to negotiate a valid "
573285236Swhu			    "protocol.\n");
574285236Swhu		return (EPROTO);
575285236Swhu	}
576285236Swhu
577250199Sgrehan	/*
578250199Sgrehan	 * Set the MTU if supported by this NVSP protocol version
579250199Sgrehan	 * This needs to be right after the NVSP init message per Haiyang
580250199Sgrehan	 */
581285236Swhu	if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
582307022Ssephe		ret = hv_nv_send_ndis_config(sc, ifp->if_mtu);
583250199Sgrehan
584250199Sgrehan	/*
585250199Sgrehan	 * Send the NDIS version
586250199Sgrehan	 */
587250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
588250199Sgrehan
589250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
590250199Sgrehan
591285236Swhu	if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) {
592285236Swhu		ndis_version = NDIS_VERSION_6_1;
593285236Swhu	} else {
594285236Swhu		ndis_version = NDIS_VERSION_6_30;
595285236Swhu	}
596250199Sgrehan
597250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers;
598250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers =
599250199Sgrehan	    (ndis_version & 0xFFFF0000) >> 16;
600250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers =
601250199Sgrehan	    ndis_version & 0xFFFF;
602250199Sgrehan
603250199Sgrehan	/* Send the init request */
604250199Sgrehan
605307079Ssephe	ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
606307079Ssephe	    init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt);
607250199Sgrehan	if (ret != 0) {
608250199Sgrehan		goto cleanup;
609250199Sgrehan	}
610250199Sgrehan	/*
611250199Sgrehan	 * TODO:  BUGBUG - We have to wait for the above msg since the netvsp
612250199Sgrehan	 * uses KMCL which acknowledges packet (completion packet)
613307034Ssephe	 * since our Vmbus always set the VMBUS_CHANPKT_FLAG_RC flag
614250199Sgrehan	 */
615250199Sgrehan	/* sema_wait(&NetVscChannel->channel_init_sema); */
616250199Sgrehan
617250199Sgrehan	/* Post the big receive buffer to NetVSP */
618295789Ssephe	if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
619295789Ssephe		net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
620295789Ssephe	else
621295789Ssephe		net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
622295789Ssephe	net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
623295789Ssephe
624307022Ssephe	ret = hv_nv_init_rx_buffer_with_net_vsp(sc);
625250199Sgrehan	if (ret == 0)
626307022Ssephe		ret = hv_nv_init_send_buffer_with_net_vsp(sc);
627250199Sgrehan
628250199Sgrehancleanup:
629250199Sgrehan	return (ret);
630250199Sgrehan}
631250199Sgrehan
632250199Sgrehan/*
633250199Sgrehan * Net VSC disconnect from VSP
634250199Sgrehan */
635250199Sgrehanstatic void
636250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev)
637250199Sgrehan{
638250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
639250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
640250199Sgrehan}
641250199Sgrehan
642302048Ssephevoid
643302048Ssephehv_nv_subchan_attach(struct hv_vmbus_channel *chan)
644301943Ssephe{
645301943Ssephe
646301943Ssephe	chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK);
647302048Ssephe	hv_vmbus_channel_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE,
648301943Ssephe	    NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0,
649301943Ssephe	    hv_nv_on_channel_callback, chan);
650301943Ssephe}
651301943Ssephe
652301943Ssephe/*
653250199Sgrehan * Net VSC on device add
654250199Sgrehan *
655250199Sgrehan * Callback when the device belonging to this driver is added
656250199Sgrehan */
657250199Sgrehannetvsc_dev *
658307022Ssephehv_nv_on_device_add(struct hn_softc *sc, void *additional_info)
659250199Sgrehan{
660307022Ssephe	struct hv_vmbus_channel *chan = sc->hn_prichan;
661250199Sgrehan	netvsc_dev *net_dev;
662285236Swhu	int ret = 0;
663250199Sgrehan
664307022Ssephe	net_dev = hv_nv_alloc_net_device(sc);
665301918Ssephe	if (net_dev == NULL)
666301918Ssephe		return NULL;
667250199Sgrehan
668250199Sgrehan	/* Initialize the NetVSC channel extension */
669250199Sgrehan
670250199Sgrehan	sema_init(&net_dev->channel_init_sema, 0, "netdev_sema");
671250199Sgrehan
672301918Ssephe	chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK);
673301918Ssephe
674250199Sgrehan	/*
675250199Sgrehan	 * Open the channel
676250199Sgrehan	 */
677301918Ssephe	ret = hv_vmbus_channel_open(chan,
678250199Sgrehan	    NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE,
679301918Ssephe	    NULL, 0, hv_nv_on_channel_callback, chan);
680301918Ssephe	if (ret != 0) {
681301918Ssephe		free(chan->hv_chan_rdbuf, M_NETVSC);
682250199Sgrehan		goto cleanup;
683301918Ssephe	}
684250199Sgrehan
685250199Sgrehan	/*
686250199Sgrehan	 * Connect with the NetVsp
687250199Sgrehan	 */
688307022Ssephe	ret = hv_nv_connect_to_vsp(sc);
689250199Sgrehan	if (ret != 0)
690250199Sgrehan		goto close;
691250199Sgrehan
692250199Sgrehan	return (net_dev);
693250199Sgrehan
694250199Sgrehanclose:
695250199Sgrehan	/* Now, we can close the channel safely */
696301918Ssephe	free(chan->hv_chan_rdbuf, M_NETVSC);
697301918Ssephe	hv_vmbus_channel_close(chan);
698250199Sgrehan
699250199Sgrehancleanup:
700250199Sgrehan	/*
701250199Sgrehan	 * Free the packet buffers on the netvsc device packet queue.
702250199Sgrehan	 * Release other resources.
703250199Sgrehan	 */
704301952Ssephe	sema_destroy(&net_dev->channel_init_sema);
705301952Ssephe	free(net_dev, M_NETVSC);
706250199Sgrehan
707250199Sgrehan	return (NULL);
708250199Sgrehan}
709250199Sgrehan
710250199Sgrehan/*
711250199Sgrehan * Net VSC on device remove
712250199Sgrehan */
713250199Sgrehanint
714307022Ssephehv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
715250199Sgrehan{
716250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
717250199Sgrehan
718250199Sgrehan	/* Stop outbound traffic ie sends and receives completions */
719250199Sgrehan	net_dev->destroy = TRUE;
720250199Sgrehan
721250199Sgrehan	hv_nv_disconnect_from_vsp(net_dev);
722250199Sgrehan
723250199Sgrehan	/* At this point, no one should be accessing net_dev except in here */
724250199Sgrehan
725250199Sgrehan	/* Now, we can close the channel safely */
726250199Sgrehan
727307022Ssephe	free(sc->hn_prichan->hv_chan_rdbuf, M_NETVSC);
728307022Ssephe	hv_vmbus_channel_close(sc->hn_prichan);
729250199Sgrehan
730250199Sgrehan	sema_destroy(&net_dev->channel_init_sema);
731285236Swhu	free(net_dev, M_NETVSC);
732250199Sgrehan
733250199Sgrehan	return (0);
734250199Sgrehan}
735250199Sgrehan
736250199Sgrehan/*
737250199Sgrehan * Net VSC on send completion
738250199Sgrehan */
739285236Swhustatic void
740307022Ssephehv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan,
741307080Ssephe    const struct vmbus_chanpkt_hdr *pkt)
742250199Sgrehan{
743307080Ssephe	const nvsp_msg *nvsp_msg_pkt;
744250199Sgrehan	netvsc_packet *net_vsc_pkt;
745250199Sgrehan
746307080Ssephe	nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
747250199Sgrehan
748250199Sgrehan	if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
749250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
750250199Sgrehan			== nvsp_msg_1_type_send_rx_buf_complete
751250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
752301943Ssephe			== nvsp_msg_1_type_send_send_buf_complete
753301943Ssephe		|| nvsp_msg_pkt->hdr.msg_type
754301943Ssephe			== nvsp_msg5_type_subchannel) {
755250199Sgrehan		/* Copy the response back */
756250199Sgrehan		memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt,
757285236Swhu		    sizeof(nvsp_msg));
758250199Sgrehan		sema_post(&net_dev->channel_init_sema);
759250199Sgrehan	} else if (nvsp_msg_pkt->hdr.msg_type ==
760285236Swhu		    nvsp_msg_1_type_send_rndis_pkt_complete) {
761250199Sgrehan		/* Get the send context */
762250199Sgrehan		net_vsc_pkt =
763307080Ssephe		    (netvsc_packet *)(unsigned long)pkt->cph_xactid;
764285236Swhu		if (NULL != net_vsc_pkt) {
765285236Swhu			if (net_vsc_pkt->send_buf_section_idx !=
766285236Swhu			    NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
767301857Ssephe				u_long mask;
768301857Ssephe				int idx;
769301857Ssephe
770301857Ssephe				idx = net_vsc_pkt->send_buf_section_idx /
771301857Ssephe				    BITS_PER_LONG;
772301857Ssephe				KASSERT(idx < net_dev->bitsmap_words,
773301857Ssephe				    ("invalid section index %u",
774301857Ssephe				     net_vsc_pkt->send_buf_section_idx));
775301857Ssephe				mask = 1UL <<
776301857Ssephe				    (net_vsc_pkt->send_buf_section_idx %
777301857Ssephe				     BITS_PER_LONG);
778301857Ssephe
779301857Ssephe				KASSERT(net_dev->send_section_bitsmap[idx] &
780301857Ssephe				    mask,
781301857Ssephe				    ("index bitmap 0x%lx, section index %u, "
782301857Ssephe				     "bitmap idx %d, bitmask 0x%lx",
783301857Ssephe				     net_dev->send_section_bitsmap[idx],
784301857Ssephe				     net_vsc_pkt->send_buf_section_idx,
785301857Ssephe				     idx, mask));
786301857Ssephe				atomic_clear_long(
787301857Ssephe				    &net_dev->send_section_bitsmap[idx], mask);
788285236Swhu			}
789285236Swhu
790285236Swhu			/* Notify the layer above us */
791301943Ssephe			net_vsc_pkt->compl.send.on_send_completion(chan,
792285236Swhu			    net_vsc_pkt->compl.send.send_completion_context);
793250199Sgrehan
794285236Swhu		}
795250199Sgrehan	}
796250199Sgrehan}
797250199Sgrehan
798250199Sgrehan/*
799250199Sgrehan * Net VSC on send
800250199Sgrehan * Sends a packet on the specified Hyper-V device.
801250199Sgrehan * Returns 0 on success, non-zero on failure.
802250199Sgrehan */
803250199Sgrehanint
804301912Ssephehv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt)
805250199Sgrehan{
806250199Sgrehan	nvsp_msg send_msg;
807250199Sgrehan	int ret;
808250199Sgrehan
809250199Sgrehan	send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt;
810250199Sgrehan	if (pkt->is_data_pkt) {
811250199Sgrehan		/* 0 is RMC_DATA */
812250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0;
813250199Sgrehan	} else {
814250199Sgrehan		/* 1 is RMC_CONTROL */
815250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1;
816250199Sgrehan	}
817250199Sgrehan
818250199Sgrehan	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
819285236Swhu	    pkt->send_buf_section_idx;
820285236Swhu	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size =
821285236Swhu	    pkt->send_buf_section_size;
822250199Sgrehan
823307034Ssephe	if (pkt->gpa_cnt) {
824307034Ssephe		ret = vmbus_chan_send_sglist(chan, pkt->gpa, pkt->gpa_cnt,
825266794Smarius		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
826250199Sgrehan	} else {
827307079Ssephe		ret = vmbus_chan_send(chan,
828307079Ssephe		    VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
829307079Ssephe		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
830250199Sgrehan	}
831250199Sgrehan
832250199Sgrehan	return (ret);
833250199Sgrehan}
834250199Sgrehan
835250199Sgrehan/*
836250199Sgrehan * Net VSC on receive
837250199Sgrehan *
838250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively
839250199Sgrehan * with virtual addresses.
840250199Sgrehan */
841285236Swhustatic void
842307022Ssephehv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc,
843307080Ssephe    struct hv_vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
844250199Sgrehan{
845307080Ssephe	const struct vmbus_chanpkt_rxbuf *pkt;
846307080Ssephe	const nvsp_msg *nvsp_msg_pkt;
847285236Swhu	netvsc_packet vsc_pkt;
848285236Swhu	netvsc_packet *net_vsc_pkt = &vsc_pkt;
849307022Ssephe	device_t dev = sc->hn_dev;
850250199Sgrehan	int count = 0;
851250199Sgrehan	int i = 0;
852285236Swhu	int status = nvsp_status_success;
853250199Sgrehan
854307080Ssephe	nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkthdr);
855250199Sgrehan
856250199Sgrehan	/* Make sure this is a valid nvsp packet */
857285236Swhu	if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) {
858307080Ssephe		device_printf(dev, "packet hdr type %u is invalid!\n",
859307080Ssephe		    nvsp_msg_pkt->hdr.msg_type);
860250199Sgrehan		return;
861285236Swhu	}
862250199Sgrehan
863307080Ssephe	pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr;
864250199Sgrehan
865307080Ssephe	if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) {
866307080Ssephe		device_printf(dev, "rxbuf_id %d is invalid!\n",
867307080Ssephe		    pkt->cp_rxbuf_id);
868250199Sgrehan		return;
869250199Sgrehan	}
870250199Sgrehan
871307080Ssephe	count = pkt->cp_rxbuf_cnt;
872250199Sgrehan
873285236Swhu	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
874285236Swhu	for (i = 0; i < count; i++) {
875285236Swhu		net_vsc_pkt->status = nvsp_status_success;
876307080Ssephe		net_vsc_pkt->data = ((uint8_t *)net_dev->rx_buf +
877307080Ssephe		    pkt->cp_rxbuf[i].rb_ofs);
878307080Ssephe		net_vsc_pkt->tot_data_buf_len = pkt->cp_rxbuf[i].rb_len;
879250199Sgrehan
880307022Ssephe		hv_rf_on_receive(net_dev, chan, net_vsc_pkt);
881285236Swhu		if (net_vsc_pkt->status != nvsp_status_success) {
882285236Swhu			status = nvsp_status_failure;
883285236Swhu		}
884250199Sgrehan	}
885285236Swhu
886250199Sgrehan	/*
887285236Swhu	 * Moved completion call back here so that all received
888285236Swhu	 * messages (not just data messages) will trigger a response
889285236Swhu	 * message back to the host.
890250199Sgrehan	 */
891307080Ssephe	hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid, status);
892250199Sgrehan}
893250199Sgrehan
894250199Sgrehan/*
895285236Swhu * Net VSC on receive completion
896285236Swhu *
897285236Swhu * Send a receive completion packet to RNDIS device (ie NetVsp)
898250199Sgrehan */
899301918Ssephestatic void
900301918Ssephehv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid,
901285236Swhu    uint32_t status)
902250199Sgrehan{
903250199Sgrehan	nvsp_msg rx_comp_msg;
904250199Sgrehan	int retries = 0;
905250199Sgrehan	int ret = 0;
906250199Sgrehan
907250199Sgrehan	rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete;
908250199Sgrehan
909250199Sgrehan	/* Pass in the status */
910250199Sgrehan	rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status =
911285236Swhu	    status;
912250199Sgrehan
913250199Sgrehanretry_send_cmplt:
914250199Sgrehan	/* Send the completion */
915307079Ssephe	ret = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 0,
916307079Ssephe	    &rx_comp_msg, sizeof(nvsp_msg), tid);
917250199Sgrehan	if (ret == 0) {
918250199Sgrehan		/* success */
919250199Sgrehan		/* no-op */
920250199Sgrehan	} else if (ret == EAGAIN) {
921250199Sgrehan		/* no more room... wait a bit and attempt to retry 3 times */
922250199Sgrehan		retries++;
923250199Sgrehan
924250199Sgrehan		if (retries < 4) {
925250199Sgrehan			DELAY(100);
926250199Sgrehan			goto retry_send_cmplt;
927250199Sgrehan		}
928250199Sgrehan	}
929250199Sgrehan}
930250199Sgrehan
931250199Sgrehan/*
932301943Ssephe * Net VSC receiving vRSS send table from VSP
933301943Ssephe */
934301943Ssephestatic void
935307080Ssephehv_nv_send_table(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
936301943Ssephe{
937301943Ssephe	netvsc_dev *net_dev;
938307080Ssephe	const nvsp_msg *nvsp_msg_pkt;
939301943Ssephe	int i;
940307080Ssephe	uint32_t count;
941307080Ssephe	const uint32_t *table;
942301943Ssephe
943307022Ssephe	net_dev = hv_nv_get_inbound_net_device(sc);
944301943Ssephe	if (!net_dev)
945301943Ssephe        	return;
946301943Ssephe
947307080Ssephe	nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt);
948301943Ssephe
949301943Ssephe	if (nvsp_msg_pkt->hdr.msg_type !=
950301943Ssephe	    nvsp_msg5_type_send_indirection_table) {
951301943Ssephe		printf("Netvsc: !Warning! receive msg type not "
952301943Ssephe			"send_indirection_table. type = %d\n",
953301943Ssephe			nvsp_msg_pkt->hdr.msg_type);
954301943Ssephe		return;
955301943Ssephe	}
956301943Ssephe
957301943Ssephe	count = nvsp_msg_pkt->msgs.vers_5_msgs.send_table.count;
958301943Ssephe	if (count != VRSS_SEND_TABLE_SIZE) {
959301943Ssephe        	printf("Netvsc: Received wrong send table size: %u\n", count);
960301943Ssephe	        return;
961301943Ssephe	}
962301943Ssephe
963307080Ssephe	table = (const uint32_t *)
964307080Ssephe	    ((const uint8_t *)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
965301943Ssephe	     nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset);
966301943Ssephe
967301943Ssephe	for (i = 0; i < count; i++)
968301943Ssephe        	net_dev->vrss_send_table[i] = table[i];
969301943Ssephe}
970301943Ssephe
971301943Ssephe/*
972250199Sgrehan * Net VSC on channel callback
973250199Sgrehan */
974250199Sgrehanstatic void
975301912Ssephehv_nv_on_channel_callback(void *xchan)
976250199Sgrehan{
977301912Ssephe	struct hv_vmbus_channel *chan = xchan;
978307022Ssephe	device_t dev = chan->ch_dev;
979307022Ssephe	struct hn_softc *sc = device_get_softc(dev);
980250199Sgrehan	netvsc_dev *net_dev;
981307080Ssephe	void *buffer;
982285236Swhu	int bufferlen = NETVSC_PACKET_SIZE;
983250199Sgrehan
984307022Ssephe	net_dev = hv_nv_get_inbound_net_device(sc);
985285236Swhu	if (net_dev == NULL)
986250199Sgrehan		return;
987250199Sgrehan
988301918Ssephe	buffer = chan->hv_chan_rdbuf;
989307080Ssephe	do {
990307080Ssephe		struct vmbus_chanpkt_hdr *pkt = buffer;
991307080Ssephe		uint32_t bytes_rxed;
992307080Ssephe		int ret;
993250199Sgrehan
994307080Ssephe		bytes_rxed = bufferlen;
995307080Ssephe		ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed);
996250199Sgrehan		if (ret == 0) {
997250199Sgrehan			if (bytes_rxed > 0) {
998307080Ssephe				switch (pkt->cph_type) {
999307034Ssephe				case VMBUS_CHANPKT_TYPE_COMP:
1000307022Ssephe					hv_nv_on_send_completion(net_dev, chan,
1001307080Ssephe					    pkt);
1002250199Sgrehan					break;
1003307034Ssephe				case VMBUS_CHANPKT_TYPE_RXBUF:
1004307080Ssephe					hv_nv_on_receive(net_dev, sc, chan, pkt);
1005250199Sgrehan					break;
1006307034Ssephe				case VMBUS_CHANPKT_TYPE_INBAND:
1007307080Ssephe					hv_nv_send_table(sc, pkt);
1008301943Ssephe					break;
1009250199Sgrehan				default:
1010285236Swhu					device_printf(dev,
1011307080Ssephe					    "unknown chan pkt %u\n",
1012307080Ssephe					    pkt->cph_type);
1013250199Sgrehan					break;
1014250199Sgrehan				}
1015250199Sgrehan			}
1016250199Sgrehan		} else if (ret == ENOBUFS) {
1017250199Sgrehan			/* Handle large packet */
1018285236Swhu			if (bufferlen > NETVSC_PACKET_SIZE) {
1019285236Swhu				free(buffer, M_NETVSC);
1020285236Swhu				buffer = NULL;
1021285236Swhu			}
1022285236Swhu
1023285236Swhu			/* alloc new buffer */
1024285236Swhu			buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT);
1025250199Sgrehan			if (buffer == NULL) {
1026285236Swhu				device_printf(dev,
1027285236Swhu				    "hv_cb malloc buffer failed, len=%u\n",
1028285236Swhu				    bytes_rxed);
1029285236Swhu				bufferlen = 0;
1030250199Sgrehan				break;
1031250199Sgrehan			}
1032250199Sgrehan			bufferlen = bytes_rxed;
1033307080Ssephe		} else {
1034307080Ssephe			/* No more packets */
1035307080Ssephe			break;
1036250199Sgrehan		}
1037250199Sgrehan	} while (1);
1038250199Sgrehan
1039285236Swhu	if (bufferlen > NETVSC_PACKET_SIZE)
1040285236Swhu		free(buffer, M_NETVSC);
1041295948Ssephe
1042301912Ssephe	hv_rf_channel_rollup(chan);
1043250199Sgrehan}
1044