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$
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
51250199Sgrehan
52250199Sgrehan/*
53250199Sgrehan * Forward declarations
54250199Sgrehan */
55250199Sgrehanstatic void hv_nv_on_channel_callback(void *context);
56250199Sgrehanstatic int  hv_nv_init_send_buffer_with_net_vsp(struct hv_device *device);
57250199Sgrehanstatic int  hv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device);
58250199Sgrehanstatic int  hv_nv_destroy_send_buffer(netvsc_dev *net_dev);
59250199Sgrehanstatic int  hv_nv_destroy_rx_buffer(netvsc_dev *net_dev);
60250199Sgrehanstatic int  hv_nv_connect_to_vsp(struct hv_device *device);
61250199Sgrehanstatic void hv_nv_on_send_completion(struct hv_device *device,
62250199Sgrehan				     hv_vm_packet_descriptor *pkt);
63250199Sgrehanstatic void hv_nv_on_receive(struct hv_device *device,
64250199Sgrehan			     hv_vm_packet_descriptor *pkt);
65250199Sgrehanstatic void hv_nv_send_receive_completion(struct hv_device *device,
66250199Sgrehan					  uint64_t tid);
67250199Sgrehan
68250199Sgrehan
69250199Sgrehan/*
70250199Sgrehan *
71250199Sgrehan */
72250199Sgrehanstatic inline netvsc_dev *
73250199Sgrehanhv_nv_alloc_net_device(struct hv_device *device)
74250199Sgrehan{
75250199Sgrehan	netvsc_dev *net_dev;
76250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
77250199Sgrehan
78250199Sgrehan	net_dev = malloc(sizeof(netvsc_dev), M_DEVBUF, M_NOWAIT | M_ZERO);
79250199Sgrehan	if (net_dev == NULL) {
80250199Sgrehan		return (NULL);
81250199Sgrehan	}
82250199Sgrehan
83250199Sgrehan	net_dev->dev = device;
84250199Sgrehan	net_dev->destroy = FALSE;
85250199Sgrehan	sc->net_dev = net_dev;
86250199Sgrehan
87250199Sgrehan	return (net_dev);
88250199Sgrehan}
89250199Sgrehan
90250199Sgrehan/*
91250199Sgrehan *
92250199Sgrehan */
93250199Sgrehanstatic inline netvsc_dev *
94250199Sgrehanhv_nv_get_outbound_net_device(struct hv_device *device)
95250199Sgrehan{
96250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
97250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
98250199Sgrehan
99250199Sgrehan	if ((net_dev != NULL) && net_dev->destroy) {
100250199Sgrehan		return (NULL);
101250199Sgrehan	}
102250199Sgrehan
103250199Sgrehan	return (net_dev);
104250199Sgrehan}
105250199Sgrehan
106250199Sgrehan/*
107250199Sgrehan *
108250199Sgrehan */
109250199Sgrehanstatic inline netvsc_dev *
110250199Sgrehanhv_nv_get_inbound_net_device(struct hv_device *device)
111250199Sgrehan{
112250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
113250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
114250199Sgrehan
115250199Sgrehan	if (net_dev == NULL) {
116250199Sgrehan		return (net_dev);
117250199Sgrehan	}
118250199Sgrehan	/*
119250199Sgrehan	 * When the device is being destroyed; we only
120250199Sgrehan	 * permit incoming packets if and only if there
121250199Sgrehan	 * are outstanding sends.
122250199Sgrehan	 */
123250199Sgrehan	if (net_dev->destroy && net_dev->num_outstanding_sends == 0) {
124250199Sgrehan		return (NULL);
125250199Sgrehan	}
126250199Sgrehan
127250199Sgrehan	return (net_dev);
128250199Sgrehan}
129250199Sgrehan
130250199Sgrehan/*
131250199Sgrehan * Net VSC initialize receive buffer with net VSP
132250199Sgrehan *
133250199Sgrehan * Net VSP:  Network virtual services client, also known as the
134250199Sgrehan *     Hyper-V extensible switch and the synthetic data path.
135250199Sgrehan */
136250199Sgrehanstatic int
137250199Sgrehanhv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device)
138250199Sgrehan{
139250199Sgrehan	netvsc_dev *net_dev;
140250199Sgrehan	nvsp_msg *init_pkt;
141250199Sgrehan	int ret = 0;
142250199Sgrehan
143250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
144250199Sgrehan	if (!net_dev) {
145250199Sgrehan		return (ENODEV);
146250199Sgrehan	}
147250199Sgrehan
148250199Sgrehan	net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_DEVBUF,
149250199Sgrehan	    M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
150250199Sgrehan	if (net_dev->rx_buf == NULL) {
151250199Sgrehan		ret = ENOMEM;
152250199Sgrehan		goto cleanup;
153250199Sgrehan	}
154250199Sgrehan
155250199Sgrehan	/*
156250199Sgrehan	 * Establish the GPADL handle for this buffer on this channel.
157250199Sgrehan	 * Note:  This call uses the vmbus connection rather than the
158250199Sgrehan	 * channel to establish the gpadl handle.
159250199Sgrehan	 * GPADL:  Guest physical address descriptor list.
160250199Sgrehan	 */
161250199Sgrehan	ret = hv_vmbus_channel_establish_gpadl(
162250199Sgrehan		device->channel, net_dev->rx_buf,
163250199Sgrehan		net_dev->rx_buf_size, &net_dev->rx_buf_gpadl_handle);
164250199Sgrehan	if (ret != 0) {
165250199Sgrehan		goto cleanup;
166250199Sgrehan	}
167250199Sgrehan
168250199Sgrehan	/* sema_wait(&ext->channel_init_sema); KYS CHECK */
169250199Sgrehan
170250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
171250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
172250199Sgrehan
173250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
174250199Sgrehan
175250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf;
176250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
177250199Sgrehan	    net_dev->rx_buf_gpadl_handle;
178250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
179250199Sgrehan	    NETVSC_RECEIVE_BUFFER_ID;
180250199Sgrehan
181250199Sgrehan	/* Send the gpadl notification request */
182250199Sgrehan
183250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
184266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
185250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
186250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
187250199Sgrehan	if (ret != 0) {
188250199Sgrehan		goto cleanup;
189250199Sgrehan	}
190250199Sgrehan
191250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
192250199Sgrehan
193250199Sgrehan	/* Check the response */
194250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status
195250199Sgrehan	    != nvsp_status_success) {
196250199Sgrehan		ret = EINVAL;
197250199Sgrehan		goto cleanup;
198250199Sgrehan	}
199250199Sgrehan
200250199Sgrehan	net_dev->rx_section_count =
201250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections;
202250199Sgrehan
203250199Sgrehan	net_dev->rx_sections = malloc(net_dev->rx_section_count *
204250199Sgrehan	    sizeof(nvsp_1_rx_buf_section), M_DEVBUF, M_NOWAIT);
205250199Sgrehan	if (net_dev->rx_sections == NULL) {
206250199Sgrehan		ret = EINVAL;
207250199Sgrehan		goto cleanup;
208250199Sgrehan	}
209250199Sgrehan	memcpy(net_dev->rx_sections,
210250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections,
211250199Sgrehan	    net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section));
212250199Sgrehan
213250199Sgrehan
214250199Sgrehan	/*
215250199Sgrehan	 * For first release, there should only be 1 section that represents
216250199Sgrehan	 * the entire receive buffer
217250199Sgrehan	 */
218250199Sgrehan	if (net_dev->rx_section_count != 1
219250199Sgrehan	    || net_dev->rx_sections->offset != 0) {
220250199Sgrehan		ret = EINVAL;
221250199Sgrehan		goto cleanup;
222250199Sgrehan	}
223250199Sgrehan
224250199Sgrehan	goto exit;
225250199Sgrehan
226250199Sgrehancleanup:
227250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
228250199Sgrehan
229250199Sgrehanexit:
230250199Sgrehan	return (ret);
231250199Sgrehan}
232250199Sgrehan
233250199Sgrehan/*
234250199Sgrehan * Net VSC initialize send buffer with net VSP
235250199Sgrehan */
236250199Sgrehanstatic int
237250199Sgrehanhv_nv_init_send_buffer_with_net_vsp(struct hv_device *device)
238250199Sgrehan{
239250199Sgrehan	netvsc_dev *net_dev;
240250199Sgrehan	nvsp_msg *init_pkt;
241250199Sgrehan	int ret = 0;
242250199Sgrehan
243250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
244250199Sgrehan	if (!net_dev) {
245250199Sgrehan		return (ENODEV);
246250199Sgrehan	}
247250199Sgrehan
248250199Sgrehan	net_dev->send_buf  = contigmalloc(net_dev->send_buf_size, M_DEVBUF,
249250199Sgrehan	    M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
250250199Sgrehan	if (net_dev->send_buf == NULL) {
251250199Sgrehan		ret = ENOMEM;
252250199Sgrehan		goto cleanup;
253250199Sgrehan	}
254250199Sgrehan
255250199Sgrehan	/*
256250199Sgrehan	 * Establish the gpadl handle for this buffer on this channel.
257250199Sgrehan	 * Note:  This call uses the vmbus connection rather than the
258250199Sgrehan	 * channel to establish the gpadl handle.
259250199Sgrehan	 */
260250199Sgrehan	ret = hv_vmbus_channel_establish_gpadl(device->channel,
261250199Sgrehan	    net_dev->send_buf, net_dev->send_buf_size,
262250199Sgrehan	    &net_dev->send_buf_gpadl_handle);
263250199Sgrehan	if (ret != 0) {
264250199Sgrehan		goto cleanup;
265250199Sgrehan	}
266250199Sgrehan
267250199Sgrehan	/* Notify the NetVsp of the gpadl handle */
268250199Sgrehan
269250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
270250199Sgrehan
271250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
272250199Sgrehan
273250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf;
274250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
275250199Sgrehan	    net_dev->send_buf_gpadl_handle;
276250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
277250199Sgrehan	    NETVSC_SEND_BUFFER_ID;
278250199Sgrehan
279250199Sgrehan	/* Send the gpadl notification request */
280250199Sgrehan
281250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
282266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
283250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
284250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
285250199Sgrehan	if (ret != 0) {
286250199Sgrehan		goto cleanup;
287250199Sgrehan	}
288250199Sgrehan
289250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
290250199Sgrehan
291250199Sgrehan	/* Check the response */
292250199Sgrehan	if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status
293250199Sgrehan	    != nvsp_status_success) {
294250199Sgrehan		ret = EINVAL;
295250199Sgrehan		goto cleanup;
296250199Sgrehan	}
297250199Sgrehan
298250199Sgrehan	net_dev->send_section_size =
299250199Sgrehan	    init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size;
300250199Sgrehan
301250199Sgrehan	goto exit;
302250199Sgrehan
303250199Sgrehancleanup:
304250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
305250199Sgrehan
306250199Sgrehanexit:
307250199Sgrehan	return (ret);
308250199Sgrehan}
309250199Sgrehan
310250199Sgrehan/*
311250199Sgrehan * Net VSC destroy receive buffer
312250199Sgrehan */
313250199Sgrehanstatic int
314250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
315250199Sgrehan{
316250199Sgrehan	nvsp_msg *revoke_pkt;
317250199Sgrehan	int ret = 0;
318250199Sgrehan
319250199Sgrehan	/*
320250199Sgrehan	 * If we got a section count, it means we received a
321250199Sgrehan	 * send_rx_buf_complete msg
322250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
323250199Sgrehan	 * we need to send a revoke msg here
324250199Sgrehan	 */
325250199Sgrehan	if (net_dev->rx_section_count) {
326250199Sgrehan		/* Send the revoke receive buffer */
327250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
328250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
329250199Sgrehan
330250199Sgrehan		revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf;
331250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id =
332250199Sgrehan		    NETVSC_RECEIVE_BUFFER_ID;
333250199Sgrehan
334250199Sgrehan		ret = hv_vmbus_channel_send_packet(net_dev->dev->channel,
335250199Sgrehan		    revoke_pkt, sizeof(nvsp_msg),
336266794Smarius		    (uint64_t)(uintptr_t)revoke_pkt,
337250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
338250199Sgrehan
339250199Sgrehan		/*
340250199Sgrehan		 * If we failed here, we might as well return and have a leak
341250199Sgrehan		 * rather than continue and a bugchk
342250199Sgrehan		 */
343250199Sgrehan		if (ret != 0) {
344250199Sgrehan			return (ret);
345250199Sgrehan		}
346250199Sgrehan	}
347250199Sgrehan
348250199Sgrehan	/* Tear down the gpadl on the vsp end */
349250199Sgrehan	if (net_dev->rx_buf_gpadl_handle) {
350250199Sgrehan		ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel,
351250199Sgrehan		    net_dev->rx_buf_gpadl_handle);
352250199Sgrehan		/*
353250199Sgrehan		 * If we failed here, we might as well return and have a leak
354250199Sgrehan		 * rather than continue and a bugchk
355250199Sgrehan		 */
356250199Sgrehan		if (ret != 0) {
357250199Sgrehan			return (ret);
358250199Sgrehan		}
359250199Sgrehan		net_dev->rx_buf_gpadl_handle = 0;
360250199Sgrehan	}
361250199Sgrehan
362250199Sgrehan	if (net_dev->rx_buf) {
363250199Sgrehan		/* Free up the receive buffer */
364250199Sgrehan		contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_DEVBUF);
365250199Sgrehan		net_dev->rx_buf = NULL;
366250199Sgrehan	}
367250199Sgrehan
368250199Sgrehan	if (net_dev->rx_sections) {
369250199Sgrehan		free(net_dev->rx_sections, M_DEVBUF);
370250199Sgrehan		net_dev->rx_sections = NULL;
371250199Sgrehan		net_dev->rx_section_count = 0;
372250199Sgrehan	}
373250199Sgrehan
374250199Sgrehan	return (ret);
375250199Sgrehan}
376250199Sgrehan
377250199Sgrehan/*
378250199Sgrehan * Net VSC destroy send buffer
379250199Sgrehan */
380250199Sgrehanstatic int
381250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev)
382250199Sgrehan{
383250199Sgrehan	nvsp_msg *revoke_pkt;
384250199Sgrehan	int ret = 0;
385250199Sgrehan
386250199Sgrehan	/*
387250199Sgrehan	 * If we got a section count, it means we received a
388250199Sgrehan	 * send_rx_buf_complete msg
389250199Sgrehan	 * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
390250199Sgrehan	 * we need to send a revoke msg here
391250199Sgrehan	 */
392250199Sgrehan	if (net_dev->send_section_size) {
393250199Sgrehan		/* Send the revoke send buffer */
394250199Sgrehan		revoke_pkt = &net_dev->revoke_packet;
395250199Sgrehan		memset(revoke_pkt, 0, sizeof(nvsp_msg));
396250199Sgrehan
397250199Sgrehan		revoke_pkt->hdr.msg_type =
398250199Sgrehan		    nvsp_msg_1_type_revoke_send_buf;
399250199Sgrehan		revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id =
400250199Sgrehan		    NETVSC_SEND_BUFFER_ID;
401250199Sgrehan
402250199Sgrehan		ret = hv_vmbus_channel_send_packet(net_dev->dev->channel,
403250199Sgrehan		    revoke_pkt, sizeof(nvsp_msg),
404266794Smarius		    (uint64_t)(uintptr_t)revoke_pkt,
405250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
406250199Sgrehan		/*
407250199Sgrehan		 * If we failed here, we might as well return and have a leak
408250199Sgrehan		 * rather than continue and a bugchk
409250199Sgrehan		 */
410250199Sgrehan		if (ret != 0) {
411250199Sgrehan			return (ret);
412250199Sgrehan		}
413250199Sgrehan	}
414250199Sgrehan
415250199Sgrehan	/* Tear down the gpadl on the vsp end */
416250199Sgrehan	if (net_dev->send_buf_gpadl_handle) {
417250199Sgrehan		ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel,
418250199Sgrehan		    net_dev->send_buf_gpadl_handle);
419250199Sgrehan
420250199Sgrehan		/*
421250199Sgrehan		 * If we failed here, we might as well return and have a leak
422250199Sgrehan		 * rather than continue and a bugchk
423250199Sgrehan		 */
424250199Sgrehan		if (ret != 0) {
425250199Sgrehan			return (ret);
426250199Sgrehan		}
427250199Sgrehan		net_dev->send_buf_gpadl_handle = 0;
428250199Sgrehan	}
429250199Sgrehan
430250199Sgrehan	if (net_dev->send_buf) {
431250199Sgrehan		/* Free up the receive buffer */
432250199Sgrehan		contigfree(net_dev->send_buf, net_dev->send_buf_size, M_DEVBUF);
433250199Sgrehan		net_dev->send_buf = NULL;
434250199Sgrehan	}
435250199Sgrehan
436250199Sgrehan	return (ret);
437250199Sgrehan}
438250199Sgrehan
439250199Sgrehan
440250199Sgrehan/*
441250199Sgrehan * Attempt to negotiate the caller-specified NVSP version
442250199Sgrehan *
443250199Sgrehan * For NVSP v2, Server 2008 R2 does not set
444250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers
445250199Sgrehan * to the negotiated version, so we cannot rely on that.
446250199Sgrehan */
447250199Sgrehanstatic int
448250199Sgrehanhv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev,
449250199Sgrehan			      uint32_t nvsp_ver)
450250199Sgrehan{
451250199Sgrehan	nvsp_msg *init_pkt;
452250199Sgrehan	int ret;
453250199Sgrehan
454250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
455250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
456250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_type_init;
457250199Sgrehan
458250199Sgrehan	/*
459250199Sgrehan	 * Specify parameter as the only acceptable protocol version
460250199Sgrehan	 */
461250199Sgrehan	init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver;
462250199Sgrehan	init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
463250199Sgrehan
464250199Sgrehan	/* Send the init request */
465250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
466266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
467250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
468250199Sgrehan	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
469250199Sgrehan	if (ret != 0)
470250199Sgrehan		return (-1);
471250199Sgrehan
472250199Sgrehan	sema_wait(&net_dev->channel_init_sema);
473250199Sgrehan
474250199Sgrehan	if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success)
475250199Sgrehan		return (EINVAL);
476250199Sgrehan
477250199Sgrehan	return (0);
478250199Sgrehan}
479250199Sgrehan
480250199Sgrehan/*
481250199Sgrehan * Send NDIS version 2 config packet containing MTU.
482250199Sgrehan *
483250199Sgrehan * Not valid for NDIS version 1.
484250199Sgrehan */
485250199Sgrehanstatic int
486250199Sgrehanhv_nv_send_ndis_config(struct hv_device *device, uint32_t mtu)
487250199Sgrehan{
488250199Sgrehan	netvsc_dev *net_dev;
489250199Sgrehan	nvsp_msg *init_pkt;
490250199Sgrehan	int ret;
491250199Sgrehan
492250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
493250199Sgrehan	if (!net_dev)
494250199Sgrehan		return (-ENODEV);
495250199Sgrehan
496250199Sgrehan	/*
497250199Sgrehan	 * Set up configuration packet, write MTU
498250199Sgrehan	 * Indicate we are capable of handling VLAN tags
499250199Sgrehan	 */
500250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
501250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
502250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config;
503250199Sgrehan	init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu;
504250199Sgrehan	init_pkt->
505250199Sgrehan		msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q
506250199Sgrehan		= 1;
507250199Sgrehan
508250199Sgrehan	/* Send the configuration packet */
509250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
510266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
511250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
512250199Sgrehan	if (ret != 0)
513250199Sgrehan		return (-EINVAL);
514250199Sgrehan
515250199Sgrehan	return (0);
516250199Sgrehan}
517250199Sgrehan
518250199Sgrehan/*
519250199Sgrehan * Net VSC connect to VSP
520250199Sgrehan */
521250199Sgrehanstatic int
522250199Sgrehanhv_nv_connect_to_vsp(struct hv_device *device)
523250199Sgrehan{
524250199Sgrehan	netvsc_dev *net_dev;
525250199Sgrehan	nvsp_msg *init_pkt;
526250199Sgrehan	uint32_t nvsp_vers;
527250199Sgrehan	uint32_t ndis_version;
528250199Sgrehan	int ret = 0;
529250199Sgrehan	device_t dev = device->device;
530250199Sgrehan	hn_softc_t *sc = device_get_softc(dev);
531250199Sgrehan	struct ifnet *ifp = sc->arpcom.ac_ifp;
532250199Sgrehan
533250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
534250199Sgrehan	if (!net_dev) {
535250199Sgrehan		return (ENODEV);
536250199Sgrehan	}
537250199Sgrehan
538250199Sgrehan	/*
539250199Sgrehan	 * Negotiate the NVSP version.  Try NVSP v2 first.
540250199Sgrehan	 */
541250199Sgrehan	nvsp_vers = NVSP_PROTOCOL_VERSION_2;
542250199Sgrehan	ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers);
543250199Sgrehan	if (ret != 0) {
544250199Sgrehan		/* NVSP v2 failed, try NVSP v1 */
545250199Sgrehan		nvsp_vers = NVSP_PROTOCOL_VERSION_1;
546250199Sgrehan		ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers);
547250199Sgrehan		if (ret != 0) {
548250199Sgrehan			/* NVSP v1 failed, return bad status */
549250199Sgrehan			return (ret);
550250199Sgrehan		}
551250199Sgrehan	}
552250199Sgrehan	net_dev->nvsp_version = nvsp_vers;
553250199Sgrehan
554250199Sgrehan	/*
555250199Sgrehan	 * Set the MTU if supported by this NVSP protocol version
556250199Sgrehan	 * This needs to be right after the NVSP init message per Haiyang
557250199Sgrehan	 */
558250199Sgrehan	if (nvsp_vers >= NVSP_PROTOCOL_VERSION_2)
559250199Sgrehan		ret = hv_nv_send_ndis_config(device, ifp->if_mtu);
560250199Sgrehan
561250199Sgrehan	/*
562250199Sgrehan	 * Send the NDIS version
563250199Sgrehan	 */
564250199Sgrehan	init_pkt = &net_dev->channel_init_packet;
565250199Sgrehan
566250199Sgrehan	memset(init_pkt, 0, sizeof(nvsp_msg));
567250199Sgrehan
568250199Sgrehan	/*
569250199Sgrehan	 * Updated to version 5.1, minimum, for VLAN per Haiyang
570250199Sgrehan	 */
571250199Sgrehan	ndis_version = NDIS_VERSION;
572250199Sgrehan
573250199Sgrehan	init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers;
574250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers =
575250199Sgrehan	    (ndis_version & 0xFFFF0000) >> 16;
576250199Sgrehan	init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers =
577250199Sgrehan	    ndis_version & 0xFFFF;
578250199Sgrehan
579250199Sgrehan	/* Send the init request */
580250199Sgrehan
581250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
582266794Smarius	    sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
583250199Sgrehan	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
584250199Sgrehan	if (ret != 0) {
585250199Sgrehan		goto cleanup;
586250199Sgrehan	}
587250199Sgrehan	/*
588250199Sgrehan	 * TODO:  BUGBUG - We have to wait for the above msg since the netvsp
589250199Sgrehan	 * uses KMCL which acknowledges packet (completion packet)
590250199Sgrehan	 * since our Vmbus always set the
591250199Sgrehan	 * HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag
592250199Sgrehan	 */
593250199Sgrehan	/* sema_wait(&NetVscChannel->channel_init_sema); */
594250199Sgrehan
595250199Sgrehan	/* Post the big receive buffer to NetVSP */
596250199Sgrehan	ret = hv_nv_init_rx_buffer_with_net_vsp(device);
597250199Sgrehan	if (ret == 0)
598250199Sgrehan		ret = hv_nv_init_send_buffer_with_net_vsp(device);
599250199Sgrehan
600250199Sgrehancleanup:
601250199Sgrehan	return (ret);
602250199Sgrehan}
603250199Sgrehan
604250199Sgrehan/*
605250199Sgrehan * Net VSC disconnect from VSP
606250199Sgrehan */
607250199Sgrehanstatic void
608250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev)
609250199Sgrehan{
610250199Sgrehan	hv_nv_destroy_rx_buffer(net_dev);
611250199Sgrehan	hv_nv_destroy_send_buffer(net_dev);
612250199Sgrehan}
613250199Sgrehan
614250199Sgrehan/*
615250199Sgrehan * Net VSC on device add
616250199Sgrehan *
617250199Sgrehan * Callback when the device belonging to this driver is added
618250199Sgrehan */
619250199Sgrehannetvsc_dev *
620250199Sgrehanhv_nv_on_device_add(struct hv_device *device, void *additional_info)
621250199Sgrehan{
622250199Sgrehan	netvsc_dev *net_dev;
623250199Sgrehan	netvsc_packet *packet;
624250199Sgrehan	netvsc_packet *next_packet;
625250199Sgrehan	int i, ret = 0;
626250199Sgrehan
627250199Sgrehan	net_dev = hv_nv_alloc_net_device(device);
628250199Sgrehan	if (!net_dev)
629250199Sgrehan		goto cleanup;
630250199Sgrehan
631250199Sgrehan	/* Initialize the NetVSC channel extension */
632250199Sgrehan	net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
633250199Sgrehan	mtx_init(&net_dev->rx_pkt_list_lock, "HV-RPL", NULL,
634250199Sgrehan	    MTX_SPIN | MTX_RECURSE);
635250199Sgrehan
636250199Sgrehan	net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE;
637250199Sgrehan
638250199Sgrehan	/* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
639250199Sgrehan	STAILQ_INIT(&net_dev->myrx_packet_list);
640250199Sgrehan
641250199Sgrehan	/*
642250199Sgrehan	 * malloc a sufficient number of netvsc_packet buffers to hold
643250199Sgrehan	 * a packet list.  Add them to the netvsc device packet queue.
644250199Sgrehan	 */
645250199Sgrehan	for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
646250199Sgrehan		packet = malloc(sizeof(netvsc_packet) +
647250199Sgrehan		    (NETVSC_RECEIVE_SG_COUNT * sizeof(hv_vmbus_page_buffer)),
648250199Sgrehan		    M_DEVBUF, M_NOWAIT | M_ZERO);
649250199Sgrehan		if (!packet) {
650250199Sgrehan			break;
651250199Sgrehan		}
652250199Sgrehan		STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet,
653250199Sgrehan		    mylist_entry);
654250199Sgrehan	}
655250199Sgrehan
656250199Sgrehan	sema_init(&net_dev->channel_init_sema, 0, "netdev_sema");
657250199Sgrehan
658250199Sgrehan	/*
659250199Sgrehan	 * Open the channel
660250199Sgrehan	 */
661250199Sgrehan	ret = hv_vmbus_channel_open(device->channel,
662250199Sgrehan	    NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE,
663250199Sgrehan	    NULL, 0, hv_nv_on_channel_callback, device);
664250199Sgrehan	if (ret != 0)
665250199Sgrehan		goto cleanup;
666250199Sgrehan
667250199Sgrehan	/*
668250199Sgrehan	 * Connect with the NetVsp
669250199Sgrehan	 */
670250199Sgrehan	ret = hv_nv_connect_to_vsp(device);
671250199Sgrehan	if (ret != 0)
672250199Sgrehan		goto close;
673250199Sgrehan
674250199Sgrehan	return (net_dev);
675250199Sgrehan
676250199Sgrehanclose:
677250199Sgrehan	/* Now, we can close the channel safely */
678250199Sgrehan
679250199Sgrehan	hv_vmbus_channel_close(device->channel);
680250199Sgrehan
681250199Sgrehancleanup:
682250199Sgrehan	/*
683250199Sgrehan	 * Free the packet buffers on the netvsc device packet queue.
684250199Sgrehan	 * Release other resources.
685250199Sgrehan	 */
686250199Sgrehan	if (net_dev) {
687250199Sgrehan		sema_destroy(&net_dev->channel_init_sema);
688250199Sgrehan
689250199Sgrehan		packet = STAILQ_FIRST(&net_dev->myrx_packet_list);
690250199Sgrehan		while (packet != NULL) {
691250199Sgrehan			next_packet = STAILQ_NEXT(packet, mylist_entry);
692250199Sgrehan			free(packet, M_DEVBUF);
693250199Sgrehan			packet = next_packet;
694250199Sgrehan		}
695250199Sgrehan		/* Reset the list to initial state */
696250199Sgrehan		STAILQ_INIT(&net_dev->myrx_packet_list);
697250199Sgrehan
698250199Sgrehan		mtx_destroy(&net_dev->rx_pkt_list_lock);
699250199Sgrehan
700250199Sgrehan		free(net_dev, M_DEVBUF);
701250199Sgrehan	}
702250199Sgrehan
703250199Sgrehan	return (NULL);
704250199Sgrehan}
705250199Sgrehan
706250199Sgrehan/*
707250199Sgrehan * Net VSC on device remove
708250199Sgrehan */
709250199Sgrehanint
710250199Sgrehanhv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
711250199Sgrehan{
712250199Sgrehan	netvsc_packet *net_vsc_pkt;
713250199Sgrehan	netvsc_packet *next_net_vsc_pkt;
714250199Sgrehan	hn_softc_t *sc = device_get_softc(device->device);
715250199Sgrehan	netvsc_dev *net_dev = sc->net_dev;;
716250199Sgrehan
717250199Sgrehan	/* Stop outbound traffic ie sends and receives completions */
718250199Sgrehan	mtx_lock(&device->channel->inbound_lock);
719250199Sgrehan	net_dev->destroy = TRUE;
720250199Sgrehan	mtx_unlock(&device->channel->inbound_lock);
721250199Sgrehan
722250199Sgrehan	/* Wait for all send completions */
723250199Sgrehan	while (net_dev->num_outstanding_sends) {
724250199Sgrehan		DELAY(100);
725250199Sgrehan	}
726250199Sgrehan
727250199Sgrehan	hv_nv_disconnect_from_vsp(net_dev);
728250199Sgrehan
729250199Sgrehan	/* At this point, no one should be accessing net_dev except in here */
730250199Sgrehan
731250199Sgrehan	/* Now, we can close the channel safely */
732250199Sgrehan
733250199Sgrehan	if (!destroy_channel) {
734250199Sgrehan		device->channel->state =
735250199Sgrehan		    HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE;
736250199Sgrehan	}
737250199Sgrehan
738250199Sgrehan	hv_vmbus_channel_close(device->channel);
739250199Sgrehan
740250199Sgrehan	/* Release all resources */
741250199Sgrehan	net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list);
742250199Sgrehan	while (net_vsc_pkt != NULL) {
743250199Sgrehan		next_net_vsc_pkt = STAILQ_NEXT(net_vsc_pkt, mylist_entry);
744250199Sgrehan		free(net_vsc_pkt, M_DEVBUF);
745250199Sgrehan		net_vsc_pkt = next_net_vsc_pkt;
746250199Sgrehan	}
747250199Sgrehan
748250199Sgrehan	/* Reset the list to initial state */
749250199Sgrehan	STAILQ_INIT(&net_dev->myrx_packet_list);
750250199Sgrehan
751250199Sgrehan	mtx_destroy(&net_dev->rx_pkt_list_lock);
752250199Sgrehan	sema_destroy(&net_dev->channel_init_sema);
753250199Sgrehan	free(net_dev, M_DEVBUF);
754250199Sgrehan
755250199Sgrehan	return (0);
756250199Sgrehan}
757250199Sgrehan
758250199Sgrehan/*
759250199Sgrehan * Net VSC on send completion
760250199Sgrehan */
761250199Sgrehanstatic void
762250199Sgrehanhv_nv_on_send_completion(struct hv_device *device, hv_vm_packet_descriptor *pkt)
763250199Sgrehan{
764250199Sgrehan	netvsc_dev *net_dev;
765250199Sgrehan	nvsp_msg *nvsp_msg_pkt;
766250199Sgrehan	netvsc_packet *net_vsc_pkt;
767250199Sgrehan
768250199Sgrehan	net_dev = hv_nv_get_inbound_net_device(device);
769250199Sgrehan	if (!net_dev) {
770250199Sgrehan		return;
771250199Sgrehan	}
772250199Sgrehan
773250199Sgrehan	nvsp_msg_pkt =
774250199Sgrehan	    (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3));
775250199Sgrehan
776250199Sgrehan	if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete
777250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
778250199Sgrehan			== nvsp_msg_1_type_send_rx_buf_complete
779250199Sgrehan		|| nvsp_msg_pkt->hdr.msg_type
780250199Sgrehan			== nvsp_msg_1_type_send_send_buf_complete) {
781250199Sgrehan		/* Copy the response back */
782250199Sgrehan		memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt,
783250199Sgrehan		    sizeof(nvsp_msg));
784250199Sgrehan		sema_post(&net_dev->channel_init_sema);
785250199Sgrehan	} else if (nvsp_msg_pkt->hdr.msg_type ==
786250199Sgrehan				   nvsp_msg_1_type_send_rndis_pkt_complete) {
787250199Sgrehan		/* Get the send context */
788250199Sgrehan		net_vsc_pkt =
789250199Sgrehan		    (netvsc_packet *)(unsigned long)pkt->transaction_id;
790250199Sgrehan
791250199Sgrehan		/* Notify the layer above us */
792250199Sgrehan		net_vsc_pkt->compl.send.on_send_completion(
793250199Sgrehan		    net_vsc_pkt->compl.send.send_completion_context);
794250199Sgrehan
795250199Sgrehan		atomic_subtract_int(&net_dev->num_outstanding_sends, 1);
796250199Sgrehan	}
797250199Sgrehan}
798250199Sgrehan
799250199Sgrehan/*
800250199Sgrehan * Net VSC on send
801250199Sgrehan * Sends a packet on the specified Hyper-V device.
802250199Sgrehan * Returns 0 on success, non-zero on failure.
803250199Sgrehan */
804250199Sgrehanint
805250199Sgrehanhv_nv_on_send(struct hv_device *device, netvsc_packet *pkt)
806250199Sgrehan{
807250199Sgrehan	netvsc_dev *net_dev;
808250199Sgrehan	nvsp_msg send_msg;
809250199Sgrehan	int ret;
810250199Sgrehan
811250199Sgrehan	net_dev = hv_nv_get_outbound_net_device(device);
812250199Sgrehan	if (!net_dev)
813250199Sgrehan		return (ENODEV);
814250199Sgrehan
815250199Sgrehan	send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt;
816250199Sgrehan	if (pkt->is_data_pkt) {
817250199Sgrehan		/* 0 is RMC_DATA */
818250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0;
819250199Sgrehan	} else {
820250199Sgrehan		/* 1 is RMC_CONTROL */
821250199Sgrehan		send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1;
822250199Sgrehan	}
823250199Sgrehan
824250199Sgrehan	/* Not using send buffer section */
825250199Sgrehan	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx =
826250199Sgrehan	    0xFFFFFFFF;
827250199Sgrehan	send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 0;
828250199Sgrehan
829250199Sgrehan	if (pkt->page_buf_count) {
830250199Sgrehan		ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel,
831250199Sgrehan		    pkt->page_buffers, pkt->page_buf_count,
832266794Smarius		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt);
833250199Sgrehan	} else {
834250199Sgrehan		ret = hv_vmbus_channel_send_packet(device->channel,
835266794Smarius		    &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt,
836250199Sgrehan		    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
837250199Sgrehan		    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
838250199Sgrehan	}
839250199Sgrehan
840250199Sgrehan	/* Record outstanding send only if send_packet() succeeded */
841250199Sgrehan	if (ret == 0)
842250199Sgrehan		atomic_add_int(&net_dev->num_outstanding_sends, 1);
843250199Sgrehan
844250199Sgrehan	return (ret);
845250199Sgrehan}
846250199Sgrehan
847250199Sgrehan/*
848250199Sgrehan * Net VSC on receive
849250199Sgrehan *
850250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively
851250199Sgrehan * with virtual addresses.
852250199Sgrehan */
853250199Sgrehanstatic void
854250199Sgrehanhv_nv_on_receive(struct hv_device *device, hv_vm_packet_descriptor *pkt)
855250199Sgrehan{
856250199Sgrehan	netvsc_dev *net_dev;
857250199Sgrehan	hv_vm_transfer_page_packet_header *vm_xfer_page_pkt;
858250199Sgrehan	nvsp_msg *nvsp_msg_pkt;
859250199Sgrehan	netvsc_packet *net_vsc_pkt = NULL;
860250199Sgrehan	unsigned long start;
861250199Sgrehan	xfer_page_packet *xfer_page_pkt = NULL;
862250199Sgrehan	STAILQ_HEAD(PKT_LIST, netvsc_packet_) mylist_head =
863250199Sgrehan	    STAILQ_HEAD_INITIALIZER(mylist_head);
864250199Sgrehan	int count = 0;
865250199Sgrehan	int i = 0;
866250199Sgrehan
867250199Sgrehan	net_dev = hv_nv_get_inbound_net_device(device);
868250199Sgrehan	if (!net_dev)
869250199Sgrehan		return;
870250199Sgrehan
871250199Sgrehan	/*
872250199Sgrehan	 * All inbound packets other than send completion should be
873250199Sgrehan	 * xfer page packet.
874250199Sgrehan	 */
875250199Sgrehan	if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES)
876250199Sgrehan		return;
877250199Sgrehan
878250199Sgrehan	nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt
879250199Sgrehan		+ (pkt->data_offset8 << 3));
880250199Sgrehan
881250199Sgrehan	/* Make sure this is a valid nvsp packet */
882250199Sgrehan	if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt)
883250199Sgrehan		return;
884250199Sgrehan
885250199Sgrehan	vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt;
886250199Sgrehan
887250199Sgrehan	if (vm_xfer_page_pkt->transfer_page_set_id
888250199Sgrehan		!= NETVSC_RECEIVE_BUFFER_ID) {
889250199Sgrehan		return;
890250199Sgrehan	}
891250199Sgrehan
892250199Sgrehan	STAILQ_INIT(&mylist_head);
893250199Sgrehan
894250199Sgrehan	/*
895250199Sgrehan	 * Grab free packets (range count + 1) to represent this xfer page
896250199Sgrehan	 * packet.  +1 to represent the xfer page packet itself.  We grab it
897250199Sgrehan	 * here so that we know exactly how many we can fulfill.
898250199Sgrehan	 */
899250199Sgrehan	mtx_lock_spin(&net_dev->rx_pkt_list_lock);
900250199Sgrehan	while (!STAILQ_EMPTY(&net_dev->myrx_packet_list)) {
901250199Sgrehan		net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list);
902250199Sgrehan		STAILQ_REMOVE_HEAD(&net_dev->myrx_packet_list, mylist_entry);
903250199Sgrehan
904250199Sgrehan		STAILQ_INSERT_TAIL(&mylist_head, net_vsc_pkt, mylist_entry);
905250199Sgrehan
906250199Sgrehan		if (++count == vm_xfer_page_pkt->range_count + 1)
907250199Sgrehan			break;
908250199Sgrehan	}
909250199Sgrehan
910250199Sgrehan	mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
911250199Sgrehan
912250199Sgrehan	/*
913250199Sgrehan	 * We need at least 2 netvsc pkts (1 to represent the xfer page
914250199Sgrehan	 * and at least 1 for the range) i.e. we can handle some of the
915250199Sgrehan	 * xfer page packet ranges...
916250199Sgrehan	 */
917250199Sgrehan	if (count < 2) {
918250199Sgrehan		/* Return netvsc packet to the freelist */
919250199Sgrehan		mtx_lock_spin(&net_dev->rx_pkt_list_lock);
920250199Sgrehan		for (i=count; i != 0; i--) {
921250199Sgrehan			net_vsc_pkt = STAILQ_FIRST(&mylist_head);
922250199Sgrehan			STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
923250199Sgrehan
924250199Sgrehan			STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list,
925250199Sgrehan			    net_vsc_pkt, mylist_entry);
926250199Sgrehan		}
927250199Sgrehan		mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
928250199Sgrehan
929250199Sgrehan		hv_nv_send_receive_completion(device,
930250199Sgrehan		    vm_xfer_page_pkt->d.transaction_id);
931250199Sgrehan
932250199Sgrehan		return;
933250199Sgrehan	}
934250199Sgrehan
935250199Sgrehan	/* Take the first packet in the list */
936250199Sgrehan	xfer_page_pkt = (xfer_page_packet *)STAILQ_FIRST(&mylist_head);
937250199Sgrehan	STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
938250199Sgrehan
939250199Sgrehan	/* This is how many data packets we can supply */
940250199Sgrehan	xfer_page_pkt->count = count - 1;
941250199Sgrehan
942250199Sgrehan	/* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */
943250199Sgrehan	for (i=0; i < (count - 1); i++) {
944250199Sgrehan		net_vsc_pkt = STAILQ_FIRST(&mylist_head);
945250199Sgrehan		STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry);
946250199Sgrehan
947250199Sgrehan		/*
948250199Sgrehan		 * Initialize the netvsc packet
949250199Sgrehan		 */
950250199Sgrehan		net_vsc_pkt->xfer_page_pkt = xfer_page_pkt;
951250199Sgrehan		net_vsc_pkt->compl.rx.rx_completion_context = net_vsc_pkt;
952250199Sgrehan		net_vsc_pkt->device = device;
953250199Sgrehan		/* Save this so that we can send it back */
954250199Sgrehan		net_vsc_pkt->compl.rx.rx_completion_tid =
955250199Sgrehan		    vm_xfer_page_pkt->d.transaction_id;
956250199Sgrehan
957250199Sgrehan		net_vsc_pkt->tot_data_buf_len =
958250199Sgrehan		    vm_xfer_page_pkt->ranges[i].byte_count;
959250199Sgrehan		net_vsc_pkt->page_buf_count = 1;
960250199Sgrehan
961250199Sgrehan		net_vsc_pkt->page_buffers[0].length =
962250199Sgrehan		    vm_xfer_page_pkt->ranges[i].byte_count;
963250199Sgrehan
964250199Sgrehan		/* The virtual address of the packet in the receive buffer */
965250199Sgrehan		start = ((unsigned long)net_dev->rx_buf +
966250199Sgrehan		    vm_xfer_page_pkt->ranges[i].byte_offset);
967250199Sgrehan		start = ((unsigned long)start) & ~(PAGE_SIZE - 1);
968250199Sgrehan
969250199Sgrehan		/* Page number of the virtual page containing packet start */
970250199Sgrehan		net_vsc_pkt->page_buffers[0].pfn = start >> PAGE_SHIFT;
971250199Sgrehan
972250199Sgrehan		/* Calculate the page relative offset */
973250199Sgrehan		net_vsc_pkt->page_buffers[0].offset =
974250199Sgrehan		    vm_xfer_page_pkt->ranges[i].byte_offset & (PAGE_SIZE - 1);
975250199Sgrehan
976250199Sgrehan		/*
977250199Sgrehan		 * In this implementation, we are dealing with virtual
978250199Sgrehan		 * addresses exclusively.  Since we aren't using physical
979250199Sgrehan		 * addresses at all, we don't care if a packet crosses a
980250199Sgrehan		 * page boundary.  For this reason, the original code to
981250199Sgrehan		 * check for and handle page crossings has been removed.
982250199Sgrehan		 */
983250199Sgrehan
984250199Sgrehan		/*
985250199Sgrehan		 * Pass it to the upper layer.  The receive completion call
986250199Sgrehan		 * has been moved into this function.
987250199Sgrehan		 */
988250199Sgrehan		hv_rf_on_receive(device, net_vsc_pkt);
989250199Sgrehan
990250199Sgrehan		/*
991250199Sgrehan		 * Moved completion call back here so that all received
992250199Sgrehan		 * messages (not just data messages) will trigger a response
993250199Sgrehan		 * message back to the host.
994250199Sgrehan		 */
995250199Sgrehan		hv_nv_on_receive_completion(net_vsc_pkt);
996250199Sgrehan	}
997250199Sgrehan}
998250199Sgrehan
999250199Sgrehan/*
1000250199Sgrehan * Net VSC send receive completion
1001250199Sgrehan */
1002250199Sgrehanstatic void
1003250199Sgrehanhv_nv_send_receive_completion(struct hv_device *device, uint64_t tid)
1004250199Sgrehan{
1005250199Sgrehan	nvsp_msg rx_comp_msg;
1006250199Sgrehan	int retries = 0;
1007250199Sgrehan	int ret = 0;
1008250199Sgrehan
1009250199Sgrehan	rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete;
1010250199Sgrehan
1011250199Sgrehan	/* Pass in the status */
1012250199Sgrehan	rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status =
1013250199Sgrehan	    nvsp_status_success;
1014250199Sgrehan
1015250199Sgrehanretry_send_cmplt:
1016250199Sgrehan	/* Send the completion */
1017250199Sgrehan	ret = hv_vmbus_channel_send_packet(device->channel, &rx_comp_msg,
1018250199Sgrehan	    sizeof(nvsp_msg), tid, HV_VMBUS_PACKET_TYPE_COMPLETION, 0);
1019250199Sgrehan	if (ret == 0) {
1020250199Sgrehan		/* success */
1021250199Sgrehan		/* no-op */
1022250199Sgrehan	} else if (ret == EAGAIN) {
1023250199Sgrehan		/* no more room... wait a bit and attempt to retry 3 times */
1024250199Sgrehan		retries++;
1025250199Sgrehan
1026250199Sgrehan		if (retries < 4) {
1027250199Sgrehan			DELAY(100);
1028250199Sgrehan			goto retry_send_cmplt;
1029250199Sgrehan		}
1030250199Sgrehan	}
1031250199Sgrehan}
1032250199Sgrehan
1033250199Sgrehan/*
1034250199Sgrehan * Net VSC on receive completion
1035250199Sgrehan *
1036250199Sgrehan * Send a receive completion packet to RNDIS device (ie NetVsp)
1037250199Sgrehan */
1038250199Sgrehanvoid
1039250199Sgrehanhv_nv_on_receive_completion(void *context)
1040250199Sgrehan{
1041250199Sgrehan	netvsc_packet *packet = (netvsc_packet *)context;
1042250199Sgrehan	struct hv_device *device = (struct hv_device *)packet->device;
1043250199Sgrehan	netvsc_dev    *net_dev;
1044250199Sgrehan	uint64_t       tid = 0;
1045250199Sgrehan	boolean_t send_rx_completion = FALSE;
1046250199Sgrehan
1047250199Sgrehan	/*
1048250199Sgrehan	 * Even though it seems logical to do a hv_nv_get_outbound_net_device()
1049250199Sgrehan	 * here to send out receive completion, we are using
1050250199Sgrehan	 * hv_nv_get_inbound_net_device() since we may have disabled
1051250199Sgrehan	 * outbound traffic already.
1052250199Sgrehan	 */
1053250199Sgrehan	net_dev = hv_nv_get_inbound_net_device(device);
1054250199Sgrehan	if (net_dev == NULL)
1055250199Sgrehan		return;
1056250199Sgrehan
1057250199Sgrehan	/* Overloading use of the lock. */
1058250199Sgrehan	mtx_lock_spin(&net_dev->rx_pkt_list_lock);
1059250199Sgrehan
1060250199Sgrehan	packet->xfer_page_pkt->count--;
1061250199Sgrehan
1062250199Sgrehan	/*
1063250199Sgrehan	 * Last one in the line that represent 1 xfer page packet.
1064250199Sgrehan	 * Return the xfer page packet itself to the free list.
1065250199Sgrehan	 */
1066250199Sgrehan	if (packet->xfer_page_pkt->count == 0) {
1067250199Sgrehan		send_rx_completion = TRUE;
1068250199Sgrehan		tid = packet->compl.rx.rx_completion_tid;
1069250199Sgrehan		STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list,
1070250199Sgrehan		    (netvsc_packet *)(packet->xfer_page_pkt), mylist_entry);
1071250199Sgrehan	}
1072250199Sgrehan
1073250199Sgrehan	/* Put the packet back on the free list */
1074250199Sgrehan	STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, mylist_entry);
1075250199Sgrehan	mtx_unlock_spin(&net_dev->rx_pkt_list_lock);
1076250199Sgrehan
1077250199Sgrehan	/* Send a receive completion for the xfer page packet */
1078250199Sgrehan	if (send_rx_completion)
1079250199Sgrehan		hv_nv_send_receive_completion(device, tid);
1080250199Sgrehan}
1081250199Sgrehan
1082250199Sgrehan/*
1083250199Sgrehan * Net VSC on channel callback
1084250199Sgrehan */
1085250199Sgrehanstatic void
1086250199Sgrehanhv_nv_on_channel_callback(void *context)
1087250199Sgrehan{
1088250199Sgrehan	/* Fixme:  Magic number */
1089250199Sgrehan	const int net_pkt_size = 2048;
1090250199Sgrehan	struct hv_device *device = (struct hv_device *)context;
1091250199Sgrehan	netvsc_dev *net_dev;
1092250199Sgrehan	uint32_t bytes_rxed;
1093250199Sgrehan	uint64_t request_id;
1094250199Sgrehan	uint8_t  *packet;
1095250199Sgrehan	hv_vm_packet_descriptor *desc;
1096250199Sgrehan	uint8_t *buffer;
1097250199Sgrehan	int     bufferlen = net_pkt_size;
1098250199Sgrehan	int     ret = 0;
1099250199Sgrehan
1100250199Sgrehan	packet = malloc(net_pkt_size * sizeof(uint8_t), M_DEVBUF, M_NOWAIT);
1101250199Sgrehan	if (!packet)
1102250199Sgrehan		return;
1103250199Sgrehan
1104250199Sgrehan	buffer = packet;
1105250199Sgrehan
1106250199Sgrehan	net_dev = hv_nv_get_inbound_net_device(device);
1107250199Sgrehan	if (net_dev == NULL)
1108250199Sgrehan		goto out;
1109250199Sgrehan
1110250199Sgrehan	do {
1111250199Sgrehan		ret = hv_vmbus_channel_recv_packet_raw(device->channel,
1112250199Sgrehan		    buffer, bufferlen, &bytes_rxed, &request_id);
1113250199Sgrehan		if (ret == 0) {
1114250199Sgrehan			if (bytes_rxed > 0) {
1115250199Sgrehan				desc = (hv_vm_packet_descriptor *)buffer;
1116250199Sgrehan				switch (desc->type) {
1117250199Sgrehan				case HV_VMBUS_PACKET_TYPE_COMPLETION:
1118250199Sgrehan					hv_nv_on_send_completion(device, desc);
1119250199Sgrehan					break;
1120250199Sgrehan				case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES:
1121250199Sgrehan					hv_nv_on_receive(device, desc);
1122250199Sgrehan					break;
1123250199Sgrehan				default:
1124250199Sgrehan					break;
1125250199Sgrehan				}
1126250199Sgrehan			} else {
1127250199Sgrehan				break;
1128250199Sgrehan			}
1129250199Sgrehan		} else if (ret == ENOBUFS) {
1130250199Sgrehan			/* Handle large packet */
1131250199Sgrehan			free(buffer, M_DEVBUF);
1132250199Sgrehan			buffer = malloc(bytes_rxed, M_DEVBUF, M_NOWAIT);
1133250199Sgrehan			if (buffer == NULL) {
1134250199Sgrehan				break;
1135250199Sgrehan			}
1136250199Sgrehan			bufferlen = bytes_rxed;
1137250199Sgrehan		}
1138250199Sgrehan	} while (1);
1139250199Sgrehan
1140250199Sgrehanout:
1141250199Sgrehan	free(buffer, M_DEVBUF);
1142250199Sgrehan}
1143250199Sgrehan
1144