hn_nvs.c revision 301952
1250199Sgrehan/*-
2250199Sgrehan * Copyright (c) 2009-2012 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 301952 2016-06-16 05:24:00Z 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);
60250199Sgrehanstatic int  hv_nv_init_send_buffer_with_net_vsp(struct hv_device *device);
61250199Sgrehanstatic int  hv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device);
62250199Sgrehanstatic int  hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
63250199Sgrehanstatic int  hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
64250199Sgrehanstatic int  hv_nv_connect_to_vsp(struct hv_device *device);
65285236Swhustatic void hv_nv_on_send_completion(netvsc_dev *net_dev,
66301943Ssephe    struct hv_device *device, struct hv_vmbus_channel *, hv_vm_packet_descriptor *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,
70301912Ssephe    struct hv_device *device, struct hv_vmbus_channel *chan,
71301912Ssephe    hv_vm_packet_descriptor *pkt);
72250199Sgrehan
73250199Sgrehan/*
74250199Sgrehan *
75250199Sgrehan */
76250199Sgrehanstatic inline netvsc_dev *
77250199Sgrehanhv_nv_alloc_net_device(struct hv_device *device)
78250199Sgrehan{
79250199Sgrehan	netvsc_dev *net_dev;
80250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
81250199Sgrehan
82301859Ssephe	net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_WAITOK | M_ZERO);
83250199Sgrehan
84250199Sgrehan	net_dev->dev = device;
85250199Sgrehan	net_dev->destroy = FALSE;
86250199Sgrehan	sc->net_dev = net_dev;
87250199Sgrehan
88250199Sgrehan	return (net_dev);
89250199Sgrehan}
90250199Sgrehan
91250199Sgrehan/*
92250199Sgrehan *
93250199Sgrehan */
94250199Sgrehanstatic inline netvsc_dev *
95250199Sgrehanhv_nv_get_outbound_net_device(struct hv_device *device)
96250199Sgrehan{
97250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
98250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
99250199Sgrehan
100250199Sgrehan	if ((net_dev != NULL) && net_dev->destroy) {
101250199Sgrehan		return (NULL);
102250199Sgrehan	}
103250199Sgrehan
104250199Sgrehan	return (net_dev);
105250199Sgrehan}
106250199Sgrehan
107250199Sgrehan/*
108250199Sgrehan *
109250199Sgrehan */
110250199Sgrehanstatic inline netvsc_dev *
111250199Sgrehanhv_nv_get_inbound_net_device(struct hv_device *device)
112250199Sgrehan{
113250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
114250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
115250199Sgrehan
116250199Sgrehan	if (net_dev == NULL) {
117250199Sgrehan		return (net_dev);
118250199Sgrehan	}
119250199Sgrehan	/*
120250199Sgrehan	 * When the device is being destroyed; we only
121250199Sgrehan	 * permit incoming packets if and only if there
122250199Sgrehan	 * are outstanding sends.
123250199Sgrehan	 */
124301912Ssephe	if (net_dev->destroy) {
125250199Sgrehan		return (NULL);
126250199Sgrehan	}
127250199Sgrehan
128250199Sgrehan	return (net_dev);
129250199Sgrehan}
130250199Sgrehan
131285236Swhuint
132285236Swhuhv_nv_get_next_send_section(netvsc_dev *net_dev)
133285236Swhu{
134285236Swhu	unsigned long bitsmap_words = net_dev->bitsmap_words;
135285236Swhu	unsigned long *bitsmap = net_dev->send_section_bitsmap;
136285236Swhu	unsigned long idx;
137285236Swhu	int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
138285236Swhu	int i;
139285236Swhu
140285236Swhu	for (i = 0; i < bitsmap_words; i++) {
141301857Ssephe		idx = ffsl(~bitsmap[i]);
142285236Swhu		if (0 == idx)
143285236Swhu			continue;
144285236Swhu
145285236Swhu		idx--;
146301857Ssephe		KASSERT(i * BITS_PER_LONG + idx < net_dev->send_section_count,
147301857Ssephe		    ("invalid i %d and idx %lu", i, idx));
148285236Swhu
149301857Ssephe		if (atomic_testandset_long(&bitsmap[i], idx))
150285236Swhu			continue;
151285236Swhu
152285236Swhu		ret = i * BITS_PER_LONG + idx;
153285236Swhu		break;
154285236Swhu	}
155285236Swhu
156285236Swhu	return (ret);
157285236Swhu}
158285236Swhu
159250199Sgrehan/*
160250199Sgrehan * Net VSC initialize receive buffer with net VSP
161250199Sgrehan *
162250199Sgrehan * Net VSP:  Network virtual services client, also known as the
163250199Sgrehan *     Hyper-V extensible switch and the synthetic data path.
164250199Sgrehan */
165250199Sgrehanstatic int
166250199Sgrehanhv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device)
167250199Sgrehan{
168250199Sgrehan	netvsc_dev *net_dev;
169250199Sgrehan	nvsp_msg *init_pkt;
170250199Sgrehan	int ret = 0;
171250199Sgrehan
172250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
173250199Sgrehan	if (!net_dev) {
174250199Sgrehan		return (ENODEV);
175250199Sgrehan	}
176250199Sgrehan
177285236Swhu	net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC,
178250199Sgrehan	    M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
179250199Sgrehan
180250199Sgrehan	/*
181250199Sgrehan	 * Establish the GPADL handle for this buffer on this channel.
182250199Sgrehan	 * Note:  This call uses the vmbus connection rather than the
183250199Sgrehan	 * channel to establish the gpadl handle.
184250199Sgrehan	 * GPADL:  Guest physical address descriptor list.
185250199Sgrehan	 */
186250199Sgrehan	ret = hv_vmbus_channel_establish_gpadl(
187250199Sgrehan		device->channel, net_dev->rx_buf,
188250199Sgrehan		net_dev->rx_buf_size, &net_dev->rx_buf_gpadl_handle);
189250199Sgrehan	if (ret != 0) {
190250199Sgrehan		goto cleanup;
191250199Sgrehan	}
192250199Sgrehan
193250199Sgrehan	/* sema_wait(&ext->channel_init_sema); KYS CHECK */
194250199Sgrehan
195250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
196250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
197250199Sgrehan
198250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
199250199Sgrehan
200250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf;
201250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
202250199Sgrehan	    net_dev->rx_buf_gpadl_handle;
203250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
204250199Sgrehan	    NETVSC_RECEIVE_BUFFER_ID;
205250199Sgrehan
206250199Sgrehan	/* Send the gpadl notification request */
207250199Sgrehan
208250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
209266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
210250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
211250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
212250199Sgrehan	if (ret != 0) {
213250199Sgrehan		goto cleanup;
214250199Sgrehan	}
215250199Sgrehan
216250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
217250199Sgrehan
218250199Sgrehan	/* Check the response */
219250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status
220250199Sgrehan	    != nvsp_status_success) {
221250199Sgrehan		ret = EINVAL;
222250199Sgrehan		goto cleanup;
223250199Sgrehan	}
224250199Sgrehan
225250199Sgrehan	net_dev->rx_section_count =
226250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections;
227250199Sgrehan
228250199Sgrehan	net_dev->rx_sections = malloc(net_dev->rx_section_count *
229301859Ssephe	    sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_WAITOK);
230250199Sgrehan	memcpy(net_dev->rx_sections,
231250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections,
232250199Sgrehan	    net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section));
233250199Sgrehan
234250199Sgrehan
235250199Sgrehan	/*
236250199Sgrehan	 * For first release, there should only be 1 section that represents
237250199Sgrehan	 * the entire receive buffer
238250199Sgrehan	 */
239250199Sgrehan	if (net_dev->rx_section_count != 1
240250199Sgrehan	    || net_dev->rx_sections->offset != 0) {
241250199Sgrehan		ret = EINVAL;
242250199Sgrehan		goto cleanup;
243250199Sgrehan	}
244250199Sgrehan
245250199Sgrehan	goto exit;
246250199Sgrehan
247250199Sgrehancleanup:
248250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
249250199Sgrehan
250250199Sgrehanexit:
251250199Sgrehan	return (ret);
252250199Sgrehan}
253250199Sgrehan
254250199Sgrehan/*
255250199Sgrehan * Net VSC initialize send buffer with net VSP
256250199Sgrehan */
257250199Sgrehanstatic int
258250199Sgrehanhv_nv_init_send_buffer_with_net_vsp(struct hv_device *device)
259250199Sgrehan{
260250199Sgrehan	netvsc_dev *net_dev;
261250199Sgrehan	nvsp_msg *init_pkt;
262250199Sgrehan	int ret = 0;
263250199Sgrehan
264250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
265250199Sgrehan	if (!net_dev) {
266250199Sgrehan		return (ENODEV);
267250199Sgrehan	}
268250199Sgrehan
269285236Swhu	net_dev->send_buf  = contigmalloc(net_dev->send_buf_size, M_NETVSC,
270250199Sgrehan	    M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
271250199Sgrehan	if (net_dev->send_buf == NULL) {
272250199Sgrehan		ret = ENOMEM;
273250199Sgrehan		goto cleanup;
274250199Sgrehan	}
275250199Sgrehan
276250199Sgrehan	/*
277250199Sgrehan	 * Establish the gpadl handle for this buffer on this channel.
278250199Sgrehan	 * Note:  This call uses the vmbus connection rather than the
279250199Sgrehan	 * channel to establish the gpadl handle.
280250199Sgrehan	 */
281250199Sgrehan	ret = hv_vmbus_channel_establish_gpadl(device->channel,
282285236Swhu  	    net_dev->send_buf, net_dev->send_buf_size,
283250199Sgrehan	    &net_dev->send_buf_gpadl_handle);
284250199Sgrehan	if (ret != 0) {
285250199Sgrehan		goto cleanup;
286250199Sgrehan	}
287250199Sgrehan
288250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
289250199Sgrehan
290250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
291250199Sgrehan
292250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
293250199Sgrehan
294250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf;
295250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
296250199Sgrehan	    net_dev->send_buf_gpadl_handle;
297250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
298250199Sgrehan	    NETVSC_SEND_BUFFER_ID;
299250199Sgrehan
300250199Sgrehan	/* Send the gpadl notification request */
301250199Sgrehan
302250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
303285236Swhu  	    sizeof(nvsp_msg), (uint64_t)init_pkt,
304250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
305250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
306250199Sgrehan	if (ret != 0) {
307250199Sgrehan		goto cleanup;
308250199Sgrehan	}
309250199Sgrehan
310250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
311250199Sgrehan
312250199Sgrehan	/* Check the response */
313250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status
314250199Sgrehan	    != nvsp_status_success) {
315250199Sgrehan		ret = EINVAL;
316250199Sgrehan		goto cleanup;
317250199Sgrehan	}
318250199Sgrehan
319250199Sgrehan	net_dev->send_section_size =
320250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size;
321285236Swhu	net_dev->send_section_count =
322285236Swhu	    net_dev->send_buf_size / net_dev->send_section_size;
323285236Swhu	net_dev->bitsmap_words = howmany(net_dev->send_section_count,
324285236Swhu	    BITS_PER_LONG);
325285236Swhu	net_dev->send_section_bitsmap =
326285236Swhu	    malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC,
327301859Ssephe	    M_WAITOK | M_ZERO);
328250199Sgrehan
329250199Sgrehan	goto exit;
330250199Sgrehan
331250199Sgrehancleanup:
332250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
333250199Sgrehan
334250199Sgrehanexit:
335250199Sgrehan	return (ret);
336250199Sgrehan}
337250199Sgrehan
338250199Sgrehan/*
339250199Sgrehan * Net VSC destroy receive buffer
340250199Sgrehan */
341250199Sgrehanstatic int
342250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
343250199Sgrehan{
344250199Sgrehan	nvsp_msg *revoke_pkt;
345250199Sgrehan	int ret = 0;
346250199Sgrehan
347250199Sgrehan	/*
348250199Sgrehan	 * If we got a section count, it means we received a
349250199Sgrehan	 * send_rx_buf_complete msg
350250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
351250199Sgrehan	 * we need to send a revoke msg here
352250199Sgrehan	 */
353250199Sgrehan	if (net_dev->rx_section_count) {
354250199Sgrehan		/* Send the revoke receive buffer */
355250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
356250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
357250199Sgrehan
358250199Sgrehan		revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf;
359250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id =
360250199Sgrehan		    NETVSC_RECEIVE_BUFFER_ID;
361250199Sgrehan
362250199Sgrehan		ret = hv_vmbus_channel_send_packet(net_dev->dev->channel,
363250199Sgrehan		    revoke_pkt, sizeof(nvsp_msg),
364266794Smarius		    (uint64_t)(uintptr_t)revoke_pkt,
365250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
366250199Sgrehan
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	}
375250199Sgrehan
376250199Sgrehan	/* Tear down the gpadl on the vsp end */
377250199Sgrehan	if (net_dev->rx_buf_gpadl_handle) {
378250199Sgrehan		ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel,
379250199Sgrehan		    net_dev->rx_buf_gpadl_handle);
380250199Sgrehan		/*
381250199Sgrehan		 * If we failed here, we might as well return and have a leak
382250199Sgrehan		 * rather than continue and a bugchk
383250199Sgrehan		 */
384250199Sgrehan		if (ret != 0) {
385250199Sgrehan			return (ret);
386250199Sgrehan		}
387250199Sgrehan		net_dev->rx_buf_gpadl_handle = 0;
388250199Sgrehan	}
389250199Sgrehan
390250199Sgrehan	if (net_dev->rx_buf) {
391250199Sgrehan		/* Free up the receive buffer */
392285236Swhu		contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC);
393250199Sgrehan		net_dev->rx_buf = NULL;
394250199Sgrehan	}
395250199Sgrehan
396250199Sgrehan	if (net_dev->rx_sections) {
397285236Swhu		free(net_dev->rx_sections, M_NETVSC);
398250199Sgrehan		net_dev->rx_sections = NULL;
399250199Sgrehan		net_dev->rx_section_count = 0;
400250199Sgrehan	}
401250199Sgrehan
402250199Sgrehan	return (ret);
403250199Sgrehan}
404250199Sgrehan
405250199Sgrehan/*
406250199Sgrehan * Net VSC destroy send buffer
407250199Sgrehan */
408250199Sgrehanstatic int
409250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev)
410250199Sgrehan{
411250199Sgrehan	nvsp_msg *revoke_pkt;
412250199Sgrehan	int ret = 0;
413250199Sgrehan
414250199Sgrehan	/*
415250199Sgrehan	 * If we got a section count, it means we received a
416250199Sgrehan	 * send_rx_buf_complete msg
417250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
418250199Sgrehan	 * we need to send a revoke msg here
419250199Sgrehan	 */
420250199Sgrehan	if (net_dev->send_section_size) {
421250199Sgrehan		/* Send the revoke send buffer */
422250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
423250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
424250199Sgrehan
425250199Sgrehan		revoke_pkt->hdr.msg_type =
426250199Sgrehan		    nvsp_msg_1_type_revoke_send_buf;
427250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id =
428250199Sgrehan		    NETVSC_SEND_BUFFER_ID;
429250199Sgrehan
430250199Sgrehan		ret = hv_vmbus_channel_send_packet(net_dev->dev->channel,
431250199Sgrehan		    revoke_pkt, sizeof(nvsp_msg),
432266794Smarius		    (uint64_t)(uintptr_t)revoke_pkt,
433250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
434250199Sgrehan		/*
435250199Sgrehan		 * If we failed here, we might as well return and have a leak
436250199Sgrehan		 * rather than continue and a bugchk
437250199Sgrehan		 */
438250199Sgrehan		if (ret != 0) {
439250199Sgrehan			return (ret);
440250199Sgrehan		}
441250199Sgrehan	}
442250199Sgrehan
443250199Sgrehan	/* Tear down the gpadl on the vsp end */
444250199Sgrehan	if (net_dev->send_buf_gpadl_handle) {
445250199Sgrehan		ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel,
446250199Sgrehan		    net_dev->send_buf_gpadl_handle);
447250199Sgrehan
448250199Sgrehan		/*
449250199Sgrehan		 * If we failed here, we might as well return and have a leak
450250199Sgrehan		 * rather than continue and a bugchk
451250199Sgrehan		 */
452250199Sgrehan		if (ret != 0) {
453250199Sgrehan			return (ret);
454250199Sgrehan		}
455250199Sgrehan		net_dev->send_buf_gpadl_handle = 0;
456250199Sgrehan	}
457250199Sgrehan
458250199Sgrehan	if (net_dev->send_buf) {
459250199Sgrehan		/* Free up the receive buffer */
460285236Swhu		contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC);
461250199Sgrehan		net_dev->send_buf = NULL;
462250199Sgrehan	}
463250199Sgrehan
464285236Swhu	if (net_dev->send_section_bitsmap) {
465285236Swhu		free(net_dev->send_section_bitsmap, M_NETVSC);
466285236Swhu	}
467285236Swhu
468250199Sgrehan	return (ret);
469250199Sgrehan}
470250199Sgrehan
471250199Sgrehan
472250199Sgrehan/*
473250199Sgrehan * Attempt to negotiate the caller-specified NVSP version
474250199Sgrehan *
475250199Sgrehan * For NVSP v2, Server 2008 R2 does not set
476250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers
477250199Sgrehan * to the negotiated version, so we cannot rely on that.
478250199Sgrehan */
479250199Sgrehanstatic int
480250199Sgrehanhv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev,
481285236Swhu    uint32_t nvsp_ver)
482250199Sgrehan{
483250199Sgrehan	nvsp_msg *init_pkt;
484250199Sgrehan	int ret;
485250199Sgrehan
486250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
487250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
488250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_type_init;
489250199Sgrehan
490250199Sgrehan	/*
491250199Sgrehan	 * Specify parameter as the only acceptable protocol version
492250199Sgrehan	 */
493250199Sgrehan	init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver;
494250199Sgrehan	init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
495250199Sgrehan
496250199Sgrehan	/* Send the init request */
497250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
498266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
499250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
500250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
501250199Sgrehan	if (ret != 0)
502250199Sgrehan		return (-1);
503250199Sgrehan
504250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
505250199Sgrehan
506250199Sgrehan	if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success)
507250199Sgrehan		return (EINVAL);
508250199Sgrehan
509250199Sgrehan	return (0);
510250199Sgrehan}
511250199Sgrehan
512250199Sgrehan/*
513250199Sgrehan * Send NDIS version 2 config packet containing MTU.
514250199Sgrehan *
515250199Sgrehan * Not valid for NDIS version 1.
516250199Sgrehan */
517250199Sgrehanstatic int
518250199Sgrehanhv_nv_send_ndis_config(struct hv_device *device, uint32_t mtu)
519250199Sgrehan{
520250199Sgrehan	netvsc_dev *net_dev;
521250199Sgrehan	nvsp_msg *init_pkt;
522250199Sgrehan	int ret;
523250199Sgrehan
524250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
525250199Sgrehan	if (!net_dev)
526250199Sgrehan		return (-ENODEV);
527250199Sgrehan
528250199Sgrehan	/*
529250199Sgrehan	 * Set up configuration packet, write MTU
530250199Sgrehan	 * Indicate we are capable of handling VLAN tags
531250199Sgrehan	 */
532250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
533250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
534250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config;
535250199Sgrehan	init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu;
536250199Sgrehan	init_pkt->
537250199Sgrehan		msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q
538250199Sgrehan		= 1;
539250199Sgrehan
540250199Sgrehan	/* Send the configuration packet */
541250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
542266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
543250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
544250199Sgrehan	if (ret != 0)
545250199Sgrehan		return (-EINVAL);
546250199Sgrehan
547250199Sgrehan	return (0);
548250199Sgrehan}
549250199Sgrehan
550250199Sgrehan/*
551250199Sgrehan * Net VSC connect to VSP
552250199Sgrehan */
553250199Sgrehanstatic int
554250199Sgrehanhv_nv_connect_to_vsp(struct hv_device *device)
555250199Sgrehan{
556250199Sgrehan	netvsc_dev *net_dev;
557250199Sgrehan	nvsp_msg *init_pkt;
558250199Sgrehan	uint32_t ndis_version;
559285236Swhu	uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1,
560285236Swhu	    NVSP_PROTOCOL_VERSION_2,
561285236Swhu	    NVSP_PROTOCOL_VERSION_4,
562285236Swhu	    NVSP_PROTOCOL_VERSION_5 };
563285236Swhu	int i;
564285236Swhu	int protocol_number = nitems(protocol_list);
565250199Sgrehan	int ret = 0;
566250199Sgrehan	device_t dev = device->device;
567250199Sgrehan	hn_softc_t *sc = device_get_softc(dev);
568250199Sgrehan	struct ifnet *ifp = sc->arpcom.ac_ifp;
569250199Sgrehan
570250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
571250199Sgrehan	if (!net_dev) {
572250199Sgrehan		return (ENODEV);
573250199Sgrehan	}
574250199Sgrehan
575250199Sgrehan	/*
576285236Swhu	 * Negotiate the NVSP version.  Try the latest NVSP first.
577250199Sgrehan	 */
578285236Swhu	for (i = protocol_number - 1; i >= 0; i--) {
579285236Swhu		if (hv_nv_negotiate_nvsp_protocol(device, net_dev,
580285236Swhu		    protocol_list[i]) == 0) {
581285236Swhu			net_dev->nvsp_version = protocol_list[i];
582285236Swhu			if (bootverbose)
583285236Swhu				device_printf(dev, "Netvsc: got version 0x%x\n",
584285236Swhu				    net_dev->nvsp_version);
585285236Swhu			break;
586250199Sgrehan		}
587250199Sgrehan	}
588250199Sgrehan
589285236Swhu	if (i < 0) {
590285236Swhu		if (bootverbose)
591285236Swhu			device_printf(dev, "failed to negotiate a valid "
592285236Swhu			    "protocol.\n");
593285236Swhu		return (EPROTO);
594285236Swhu	}
595285236Swhu
596250199Sgrehan	/*
597250199Sgrehan	 * Set the MTU if supported by this NVSP protocol version
598250199Sgrehan	 * This needs to be right after the NVSP init message per Haiyang
599250199Sgrehan	 */
600285236Swhu	if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
601250199Sgrehan		ret = hv_nv_send_ndis_config(device, ifp->if_mtu);
602250199Sgrehan
603250199Sgrehan	/*
604250199Sgrehan	 * Send the NDIS version
605250199Sgrehan	 */
606250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
607250199Sgrehan
608250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
609250199Sgrehan
610285236Swhu	if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) {
611285236Swhu		ndis_version = NDIS_VERSION_6_1;
612285236Swhu	} else {
613285236Swhu		ndis_version = NDIS_VERSION_6_30;
614285236Swhu	}
615250199Sgrehan
616250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers;
617250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers =
618250199Sgrehan	    (ndis_version & 0xFFFF0000) >> 16;
619250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers =
620250199Sgrehan	    ndis_version & 0xFFFF;
621250199Sgrehan
622250199Sgrehan	/* Send the init request */
623250199Sgrehan
624250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
625266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
626250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
627250199Sgrehan	if (ret != 0) {
628250199Sgrehan		goto cleanup;
629250199Sgrehan	}
630250199Sgrehan	/*
631250199Sgrehan	 * TODO:  BUGBUG - We have to wait for the above msg since the netvsp
632250199Sgrehan	 * uses KMCL which acknowledges packet (completion packet)
633250199Sgrehan	 * since our Vmbus always set the
634250199Sgrehan	 * HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag
635250199Sgrehan	 */
636250199Sgrehan	/* sema_wait(&NetVscChannel->channel_init_sema); */
637250199Sgrehan
638250199Sgrehan	/* Post the big receive buffer to NetVSP */
639295789Ssephe	if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
640295789Ssephe		net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
641295789Ssephe	else
642295789Ssephe		net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
643295789Ssephe	net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
644295789Ssephe
645250199Sgrehan	ret = hv_nv_init_rx_buffer_with_net_vsp(device);
646250199Sgrehan	if (ret == 0)
647250199Sgrehan		ret = hv_nv_init_send_buffer_with_net_vsp(device);
648250199Sgrehan
649250199Sgrehancleanup:
650250199Sgrehan	return (ret);
651250199Sgrehan}
652250199Sgrehan
653250199Sgrehan/*
654250199Sgrehan * Net VSC disconnect from VSP
655250199Sgrehan */
656250199Sgrehanstatic void
657250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev)
658250199Sgrehan{
659250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
660250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
661250199Sgrehan}
662250199Sgrehan
663250199Sgrehan/*
664301943Ssephe * Callback handler for subchannel offer
665301943Ssephe * @@param context new subchannel
666301943Ssephe */
667301943Ssephestatic void
668301943Ssephehv_nv_subchan_callback(void *xchan)
669301943Ssephe{
670301943Ssephe	struct hv_vmbus_channel *chan = xchan;
671301943Ssephe	netvsc_dev *net_dev;
672301943Ssephe	uint16_t chn_index = chan->offer_msg.offer.sub_channel_index;
673301943Ssephe	struct hv_device *device = chan->device;
674301943Ssephe	hn_softc_t *sc = device_get_softc(device->device);
675301943Ssephe	int ret;
676301943Ssephe
677301943Ssephe	net_dev = sc->net_dev;
678301943Ssephe
679301943Ssephe	if (chn_index >= net_dev->num_channel) {
680301943Ssephe		/* Would this ever happen? */
681301943Ssephe		return;
682301943Ssephe	}
683301943Ssephe	netvsc_subchan_callback(sc, chan);
684301943Ssephe
685301943Ssephe	chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK);
686301943Ssephe	ret = hv_vmbus_channel_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE,
687301943Ssephe	    NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0,
688301943Ssephe	    hv_nv_on_channel_callback, chan);
689301943Ssephe}
690301943Ssephe
691301943Ssephe/*
692250199Sgrehan * Net VSC on device add
693250199Sgrehan *
694250199Sgrehan * Callback when the device belonging to this driver is added
695250199Sgrehan */
696250199Sgrehannetvsc_dev *
697250199Sgrehanhv_nv_on_device_add(struct hv_device *device, void *additional_info)
698250199Sgrehan{
699301918Ssephe	struct hv_vmbus_channel *chan = device->channel;
700250199Sgrehan	netvsc_dev *net_dev;
701285236Swhu	int ret = 0;
702250199Sgrehan
703250199Sgrehan	net_dev = hv_nv_alloc_net_device(device);
704301918Ssephe	if (net_dev == NULL)
705301918Ssephe		return NULL;
706250199Sgrehan
707250199Sgrehan	/* Initialize the NetVSC channel extension */
708250199Sgrehan
709250199Sgrehan	sema_init(&net_dev->channel_init_sema, 0, "netdev_sema");
710250199Sgrehan
711301918Ssephe	chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK);
712301918Ssephe
713250199Sgrehan	/*
714250199Sgrehan	 * Open the channel
715250199Sgrehan	 */
716301918Ssephe	ret = hv_vmbus_channel_open(chan,
717250199Sgrehan	    NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE,
718301918Ssephe	    NULL, 0, hv_nv_on_channel_callback, chan);
719301918Ssephe	if (ret != 0) {
720301918Ssephe		free(chan->hv_chan_rdbuf, M_NETVSC);
721250199Sgrehan		goto cleanup;
722301918Ssephe	}
723301943Ssephe	chan->sc_creation_callback = hv_nv_subchan_callback;
724250199Sgrehan
725250199Sgrehan	/*
726250199Sgrehan	 * Connect with the NetVsp
727250199Sgrehan	 */
728250199Sgrehan	ret = hv_nv_connect_to_vsp(device);
729250199Sgrehan	if (ret != 0)
730250199Sgrehan		goto close;
731250199Sgrehan
732250199Sgrehan	return (net_dev);
733250199Sgrehan
734250199Sgrehanclose:
735250199Sgrehan	/* Now, we can close the channel safely */
736301918Ssephe	free(chan->hv_chan_rdbuf, M_NETVSC);
737301918Ssephe	hv_vmbus_channel_close(chan);
738250199Sgrehan
739250199Sgrehancleanup:
740250199Sgrehan	/*
741250199Sgrehan	 * Free the packet buffers on the netvsc device packet queue.
742250199Sgrehan	 * Release other resources.
743250199Sgrehan	 */
744301952Ssephe	sema_destroy(&net_dev->channel_init_sema);
745301952Ssephe	free(net_dev, M_NETVSC);
746250199Sgrehan
747250199Sgrehan	return (NULL);
748250199Sgrehan}
749250199Sgrehan
750250199Sgrehan/*
751250199Sgrehan * Net VSC on device remove
752250199Sgrehan */
753250199Sgrehanint
754250199Sgrehanhv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
755250199Sgrehan{
756250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
757250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
758250199Sgrehan
759250199Sgrehan	/* Stop outbound traffic ie sends and receives completions */
760250199Sgrehan	net_dev->destroy = TRUE;
761250199Sgrehan
762250199Sgrehan	hv_nv_disconnect_from_vsp(net_dev);
763250199Sgrehan
764250199Sgrehan	/* At this point, no one should be accessing net_dev except in here */
765250199Sgrehan
766250199Sgrehan	/* Now, we can close the channel safely */
767250199Sgrehan
768250199Sgrehan	if (!destroy_channel) {
769250199Sgrehan		device->channel->state =
770250199Sgrehan		    HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE;
771250199Sgrehan	}
772250199Sgrehan
773301918Ssephe	free(device->channel->hv_chan_rdbuf, M_NETVSC);
774250199Sgrehan	hv_vmbus_channel_close(device->channel);
775250199Sgrehan
776250199Sgrehan	sema_destroy(&net_dev->channel_init_sema);
777285236Swhu	free(net_dev, M_NETVSC);
778250199Sgrehan
779250199Sgrehan	return (0);
780250199Sgrehan}
781250199Sgrehan
782250199Sgrehan/*
783250199Sgrehan * Net VSC on send completion
784250199Sgrehan */
785285236Swhustatic void
786285236Swhuhv_nv_on_send_completion(netvsc_dev *net_dev,
787301943Ssephe    struct hv_device *device, struct hv_vmbus_channel *chan,
788301943Ssephe    hv_vm_packet_descriptor *pkt)
789250199Sgrehan{
790250199Sgrehan	nvsp_msg *nvsp_msg_pkt;
791250199Sgrehan	netvsc_packet *net_vsc_pkt;
792250199Sgrehan
793250199Sgrehan	nvsp_msg_pkt =
794250199Sgrehan	    (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
795250199Sgrehan
796250199Sgrehan	if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
797250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
798250199Sgrehan			== nvsp_msg_1_type_send_rx_buf_complete
799250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
800301943Ssephe			== nvsp_msg_1_type_send_send_buf_complete
801301943Ssephe		|| nvsp_msg_pkt->hdr.msg_type
802301943Ssephe			== nvsp_msg5_type_subchannel) {
803250199Sgrehan		/* Copy the response back */
804250199Sgrehan		memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt,
805285236Swhu		    sizeof(nvsp_msg));
806250199Sgrehan		sema_post(&net_dev->channel_init_sema);
807250199Sgrehan	} else if (nvsp_msg_pkt->hdr.msg_type ==
808285236Swhu		    nvsp_msg_1_type_send_rndis_pkt_complete) {
809250199Sgrehan		/* Get the send context */
810250199Sgrehan		net_vsc_pkt =
811250199Sgrehan		    (netvsc_packet *)(unsigned long)pkt->transaction_id;
812285236Swhu		if (NULL != net_vsc_pkt) {
813285236Swhu			if (net_vsc_pkt->send_buf_section_idx !=
814285236Swhu			    NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
815301857Ssephe				u_long mask;
816301857Ssephe				int idx;
817301857Ssephe
818301857Ssephe				idx = net_vsc_pkt->send_buf_section_idx /
819301857Ssephe				    BITS_PER_LONG;
820301857Ssephe				KASSERT(idx < net_dev->bitsmap_words,
821301857Ssephe				    ("invalid section index %u",
822301857Ssephe				     net_vsc_pkt->send_buf_section_idx));
823301857Ssephe				mask = 1UL <<
824301857Ssephe				    (net_vsc_pkt->send_buf_section_idx %
825301857Ssephe				     BITS_PER_LONG);
826301857Ssephe
827301857Ssephe				KASSERT(net_dev->send_section_bitsmap[idx] &
828301857Ssephe				    mask,
829301857Ssephe				    ("index bitmap 0x%lx, section index %u, "
830301857Ssephe				     "bitmap idx %d, bitmask 0x%lx",
831301857Ssephe				     net_dev->send_section_bitsmap[idx],
832301857Ssephe				     net_vsc_pkt->send_buf_section_idx,
833301857Ssephe				     idx, mask));
834301857Ssephe				atomic_clear_long(
835301857Ssephe				    &net_dev->send_section_bitsmap[idx], mask);
836285236Swhu			}
837285236Swhu
838285236Swhu			/* Notify the layer above us */
839301943Ssephe			net_vsc_pkt->compl.send.on_send_completion(chan,
840285236Swhu			    net_vsc_pkt->compl.send.send_completion_context);
841250199Sgrehan
842285236Swhu		}
843250199Sgrehan	}
844250199Sgrehan}
845250199Sgrehan
846250199Sgrehan/*
847250199Sgrehan * Net VSC on send
848250199Sgrehan * Sends a packet on the specified Hyper-V device.
849250199Sgrehan * Returns 0 on success, non-zero on failure.
850250199Sgrehan */
851250199Sgrehanint
852301912Ssephehv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt)
853250199Sgrehan{
854250199Sgrehan	nvsp_msg send_msg;
855250199Sgrehan	int ret;
856250199Sgrehan
857250199Sgrehan	send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt;
858250199Sgrehan	if (pkt->is_data_pkt) {
859250199Sgrehan		/* 0 is RMC_DATA */
860250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0;
861250199Sgrehan	} else {
862250199Sgrehan		/* 1 is RMC_CONTROL */
863250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1;
864250199Sgrehan	}
865250199Sgrehan
866250199Sgrehan	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
867285236Swhu	    pkt->send_buf_section_idx;
868285236Swhu	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size =
869285236Swhu	    pkt->send_buf_section_size;
870250199Sgrehan
871250199Sgrehan	if (pkt->page_buf_count) {
872301912Ssephe		ret = hv_vmbus_channel_send_packet_pagebuffer(chan,
873250199Sgrehan		    pkt->page_buffers, pkt->page_buf_count,
874266794Smarius		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
875250199Sgrehan	} else {
876301912Ssephe		ret = hv_vmbus_channel_send_packet(chan,
877266794Smarius		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt,
878250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
879250199Sgrehan		    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
880250199Sgrehan	}
881250199Sgrehan
882250199Sgrehan	return (ret);
883250199Sgrehan}
884250199Sgrehan
885250199Sgrehan/*
886250199Sgrehan * Net VSC on receive
887250199Sgrehan *
888250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively
889250199Sgrehan * with virtual addresses.
890250199Sgrehan */
891285236Swhustatic void
892285236Swhuhv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device,
893301912Ssephe    struct hv_vmbus_channel *chan, hv_vm_packet_descriptor *pkt)
894250199Sgrehan{
895250199Sgrehan	hv_vm_transfer_page_packet_header *vm_xfer_page_pkt;
896250199Sgrehan	nvsp_msg *nvsp_msg_pkt;
897285236Swhu	netvsc_packet vsc_pkt;
898285236Swhu	netvsc_packet *net_vsc_pkt = &vsc_pkt;
899285236Swhu	device_t dev = device->device;
900250199Sgrehan	int count = 0;
901250199Sgrehan	int i = 0;
902285236Swhu	int status = nvsp_status_success;
903250199Sgrehan
904250199Sgrehan	/*
905250199Sgrehan	 * All inbound packets other than send completion should be
906250199Sgrehan	 * xfer page packet.
907250199Sgrehan	 */
908285236Swhu	if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) {
909285236Swhu		device_printf(dev, "packet type %d is invalid!\n", pkt->type);
910250199Sgrehan		return;
911285236Swhu	}
912250199Sgrehan
913250199Sgrehan	nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt
914250199Sgrehan		+ (pkt->data_offset8 << 3));
915250199Sgrehan
916250199Sgrehan	/* Make sure this is a valid nvsp packet */
917285236Swhu	if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) {
918285236Swhu		device_printf(dev, "packet hdr type %d is invalid!\n",
919285236Swhu		    pkt->type);
920250199Sgrehan		return;
921285236Swhu	}
922250199Sgrehan
923250199Sgrehan	vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt;
924250199Sgrehan
925285236Swhu	if (vm_xfer_page_pkt->transfer_page_set_id !=
926285236Swhu	    NETVSC_RECEIVE_BUFFER_ID) {
927285236Swhu		device_printf(dev, "transfer_page_set_id %d is invalid!\n",
928285236Swhu		    vm_xfer_page_pkt->transfer_page_set_id);
929250199Sgrehan		return;
930250199Sgrehan	}
931250199Sgrehan
932285236Swhu	count = vm_xfer_page_pkt->range_count;
933285236Swhu	net_vsc_pkt->device = device;
934250199Sgrehan
935285236Swhu	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
936285236Swhu	for (i = 0; i < count; i++) {
937285236Swhu		net_vsc_pkt->status = nvsp_status_success;
938285236Swhu		net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf +
939285236Swhu		    vm_xfer_page_pkt->ranges[i].byte_offset);
940285236Swhu		net_vsc_pkt->tot_data_buf_len =
941285236Swhu		    vm_xfer_page_pkt->ranges[i].byte_count;
942250199Sgrehan
943301912Ssephe		hv_rf_on_receive(net_dev, device, chan, net_vsc_pkt);
944285236Swhu		if (net_vsc_pkt->status != nvsp_status_success) {
945285236Swhu			status = nvsp_status_failure;
946285236Swhu		}
947250199Sgrehan	}
948285236Swhu
949250199Sgrehan	/*
950285236Swhu	 * Moved completion call back here so that all received
951285236Swhu	 * messages (not just data messages) will trigger a response
952285236Swhu	 * message back to the host.
953250199Sgrehan	 */
954301918Ssephe	hv_nv_on_receive_completion(chan, vm_xfer_page_pkt->d.transaction_id,
955285236Swhu	    status);
956250199Sgrehan}
957250199Sgrehan
958250199Sgrehan/*
959285236Swhu * Net VSC on receive completion
960285236Swhu *
961285236Swhu * Send a receive completion packet to RNDIS device (ie NetVsp)
962250199Sgrehan */
963301918Ssephestatic void
964301918Ssephehv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid,
965285236Swhu    uint32_t status)
966250199Sgrehan{
967250199Sgrehan	nvsp_msg rx_comp_msg;
968250199Sgrehan	int retries = 0;
969250199Sgrehan	int ret = 0;
970250199Sgrehan
971250199Sgrehan	rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete;
972250199Sgrehan
973250199Sgrehan	/* Pass in the status */
974250199Sgrehan	rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status =
975285236Swhu	    status;
976250199Sgrehan
977250199Sgrehanretry_send_cmplt:
978250199Sgrehan	/* Send the completion */
979301918Ssephe	ret = hv_vmbus_channel_send_packet(chan, &rx_comp_msg,
980250199Sgrehan	    sizeof(nvsp_msg), tid, HV_VMBUS_PACKET_TYPE_COMPLETION, 0);
981250199Sgrehan	if (ret == 0) {
982250199Sgrehan		/* success */
983250199Sgrehan		/* no-op */
984250199Sgrehan	} else if (ret == EAGAIN) {
985250199Sgrehan		/* no more room... wait a bit and attempt to retry 3 times */
986250199Sgrehan		retries++;
987250199Sgrehan
988250199Sgrehan		if (retries < 4) {
989250199Sgrehan			DELAY(100);
990250199Sgrehan			goto retry_send_cmplt;
991250199Sgrehan		}
992250199Sgrehan	}
993250199Sgrehan}
994250199Sgrehan
995250199Sgrehan/*
996301943Ssephe * Net VSC receiving vRSS send table from VSP
997301943Ssephe */
998301943Ssephestatic void
999301943Ssephehv_nv_send_table(struct hv_device *device, hv_vm_packet_descriptor *pkt)
1000301943Ssephe{
1001301943Ssephe	netvsc_dev *net_dev;
1002301943Ssephe	nvsp_msg *nvsp_msg_pkt;
1003301943Ssephe	int i;
1004301943Ssephe	uint32_t count, *table;
1005301943Ssephe
1006301943Ssephe	net_dev = hv_nv_get_inbound_net_device(device);
1007301943Ssephe	if (!net_dev)
1008301943Ssephe        	return;
1009301943Ssephe
1010301943Ssephe	nvsp_msg_pkt =
1011301943Ssephe	    (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
1012301943Ssephe
1013301943Ssephe	if (nvsp_msg_pkt->hdr.msg_type !=
1014301943Ssephe	    nvsp_msg5_type_send_indirection_table) {
1015301943Ssephe		printf("Netvsc: !Warning! receive msg type not "
1016301943Ssephe			"send_indirection_table. type = %d\n",
1017301943Ssephe			nvsp_msg_pkt->hdr.msg_type);
1018301943Ssephe		return;
1019301943Ssephe	}
1020301943Ssephe
1021301943Ssephe	count = nvsp_msg_pkt->msgs.vers_5_msgs.send_table.count;
1022301943Ssephe	if (count != VRSS_SEND_TABLE_SIZE) {
1023301943Ssephe        	printf("Netvsc: Received wrong send table size: %u\n", count);
1024301943Ssephe	        return;
1025301943Ssephe	}
1026301943Ssephe
1027301943Ssephe	table = (uint32_t *)
1028301943Ssephe	    ((unsigned long)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table +
1029301943Ssephe	     nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset);
1030301943Ssephe
1031301943Ssephe	for (i = 0; i < count; i++)
1032301943Ssephe        	net_dev->vrss_send_table[i] = table[i];
1033301943Ssephe}
1034301943Ssephe
1035301943Ssephe/*
1036250199Sgrehan * Net VSC on channel callback
1037250199Sgrehan */
1038250199Sgrehanstatic void
1039301912Ssephehv_nv_on_channel_callback(void *xchan)
1040250199Sgrehan{
1041301912Ssephe	struct hv_vmbus_channel *chan = xchan;
1042301912Ssephe	struct hv_device *device = chan->device;
1043250199Sgrehan	netvsc_dev *net_dev;
1044285236Swhu	device_t dev = device->device;
1045250199Sgrehan	uint32_t bytes_rxed;
1046250199Sgrehan	uint64_t request_id;
1047285236Swhu 	hv_vm_packet_descriptor *desc;
1048250199Sgrehan	uint8_t *buffer;
1049285236Swhu	int bufferlen = NETVSC_PACKET_SIZE;
1050285236Swhu	int ret = 0;
1051250199Sgrehan
1052285236Swhu	net_dev = hv_nv_get_inbound_net_device(device);
1053285236Swhu	if (net_dev == NULL)
1054250199Sgrehan		return;
1055250199Sgrehan
1056301918Ssephe	buffer = chan->hv_chan_rdbuf;
1057250199Sgrehan
1058250199Sgrehan	do {
1059301912Ssephe		ret = hv_vmbus_channel_recv_packet_raw(chan,
1060250199Sgrehan		    buffer, bufferlen, &bytes_rxed, &request_id);
1061250199Sgrehan		if (ret == 0) {
1062250199Sgrehan			if (bytes_rxed > 0) {
1063250199Sgrehan				desc = (hv_vm_packet_descriptor *)buffer;
1064250199Sgrehan				switch (desc->type) {
1065250199Sgrehan				case HV_VMBUS_PACKET_TYPE_COMPLETION:
1066301943Ssephe					hv_nv_on_send_completion(net_dev, device,
1067301943Ssephe					    chan, desc);
1068250199Sgrehan					break;
1069250199Sgrehan				case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES:
1070301912Ssephe					hv_nv_on_receive(net_dev, device, chan, desc);
1071250199Sgrehan					break;
1072301943Ssephe				case HV_VMBUS_PACKET_TYPE_DATA_IN_BAND:
1073301943Ssephe					hv_nv_send_table(device, desc);
1074301943Ssephe					break;
1075250199Sgrehan				default:
1076285236Swhu					device_printf(dev,
1077285236Swhu					    "hv_cb recv unknow type %d "
1078285236Swhu					    " packet\n", desc->type);
1079250199Sgrehan					break;
1080250199Sgrehan				}
1081250199Sgrehan			} else {
1082250199Sgrehan				break;
1083250199Sgrehan			}
1084250199Sgrehan		} else if (ret == ENOBUFS) {
1085250199Sgrehan			/* Handle large packet */
1086285236Swhu			if (bufferlen > NETVSC_PACKET_SIZE) {
1087285236Swhu				free(buffer, M_NETVSC);
1088285236Swhu				buffer = NULL;
1089285236Swhu			}
1090285236Swhu
1091285236Swhu			/* alloc new buffer */
1092285236Swhu			buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT);
1093250199Sgrehan			if (buffer == NULL) {
1094285236Swhu				device_printf(dev,
1095285236Swhu				    "hv_cb malloc buffer failed, len=%u\n",
1096285236Swhu				    bytes_rxed);
1097285236Swhu				bufferlen = 0;
1098250199Sgrehan				break;
1099250199Sgrehan			}
1100250199Sgrehan			bufferlen = bytes_rxed;
1101250199Sgrehan		}
1102250199Sgrehan	} while (1);
1103250199Sgrehan
1104285236Swhu	if (bufferlen > NETVSC_PACKET_SIZE)
1105285236Swhu		free(buffer, M_NETVSC);
1106295948Ssephe
1107301912Ssephe	hv_rf_channel_rollup(chan);
1108250199Sgrehan}
1109