win-pvdrivers

view xennet/xennet.c @ 783:644e5ddb1b47

Handle SCSI INQUIRY command better in xenvbd
author James Harper <james.harper@bendigoit.com.au>
date Mon Feb 15 20:53:57 2010 +1100 (2010-02-15)
parents 3da023729e6b
children bbc6c94b9621
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include <stdlib.h>
22 #include <io/xenbus.h>
23 #include "xennet.h"
25 /* Not really necessary but keeps PREfast happy */
26 DRIVER_INITIALIZE DriverEntry;
27 static IO_WORKITEM_ROUTINE XenNet_Resume;
28 static KDEFERRED_ROUTINE XenNet_SuspendResume;
30 /* ----- BEGIN Other people's code --------- */
31 /* from linux/include/linux/ctype.h, used under GPLv2 */
32 #define _U 0x01 /* upper */
33 #define _L 0x02 /* lower */
34 #define _D 0x04 /* digit */
35 #define _C 0x08 /* cntrl */
36 #define _P 0x10 /* punct */
37 #define _S 0x20 /* white space (space/lf/tab) */
38 #define _X 0x40 /* hex digit */
39 #define _SP 0x80 /* hard space (0x20) */
41 /* from linux/include/lib/ctype.c, used under GPLv2 */
42 unsigned char _ctype[] = {
43 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
44 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
45 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
46 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
47 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
48 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
49 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
50 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
51 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
52 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
53 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
54 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
55 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
56 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
57 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
58 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
59 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
60 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
61 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
62 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
63 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
64 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
65 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
66 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
68 /* from linux/include/linux/ctype.h, used under GPLv2 */
69 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
71 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
72 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
73 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
74 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
75 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
76 #define islower(c) ((__ismask(c)&(_L)) != 0)
77 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
78 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
79 #define isspace(c) ((__ismask(c)&(_S)) != 0)
80 #define isupper(c) ((__ismask(c)&(_U)) != 0)
81 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
83 #define TOLOWER(x) ((x) | 0x20)
85 /* from linux/lib/vsprintf.c, used under GPLv2 */
86 /* Copyright (C) 1991, 1992 Linus Torvalds
87 * Wirzenius wrote this portably, Torvalds fucked it up :-)
88 */
89 /**
90 * simple_strtoul - convert a string to an unsigned long
91 * @cp: The start of the string
92 * @endp: A pointer to the end of the parsed string will be placed here
93 * @base: The number base to use
94 */
95 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
96 {
97 unsigned long result = 0,value;
99 if (!base) {
100 base = 10;
101 if (*cp == '0') {
102 base = 8;
103 cp++;
104 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
105 cp++;
106 base = 16;
107 }
108 }
109 } else if (base == 16) {
110 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
111 cp += 2;
112 }
113 while (isxdigit(*cp) &&
114 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
115 result = result*base + value;
116 cp++;
117 }
118 if (endp)
119 *endp = (char *)cp;
120 return result;
121 }
122 /* end vsprintf.c code */
123 /* ----- END Other people's code --------- */
125 static NDIS_STATUS
126 XenNet_ConnectBackend(struct xennet_info *xi)
127 {
128 PUCHAR ptr;
129 UCHAR type;
130 PCHAR setting, value, value2;
131 UINT i;
132 ULONG backend_sg = 0;
133 ULONG backend_gso = 0;
135 FUNCTION_ENTER();
137 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
139 ptr = xi->config_page;
140 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
141 {
142 switch(type)
143 {
144 case XEN_INIT_TYPE_RING: /* frontend ring */
145 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
146 if (strcmp(setting, "tx-ring-ref") == 0)
147 {
148 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
149 } else if (strcmp(setting, "rx-ring-ref") == 0)
150 {
151 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
152 }
153 break;
154 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
155 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
156 if (strcmp(setting, "event-channel") == 0)
157 {
158 xi->event_channel = PtrToUlong(value);
159 }
160 break;
161 case XEN_INIT_TYPE_READ_STRING_FRONT:
162 break;
163 case XEN_INIT_TYPE_READ_STRING_BACK:
164 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
165 if (strcmp(setting, "mac") == 0)
166 {
167 char *s, *e;
168 s = value;
169 for (i = 0; i < ETH_ALEN; i++) {
170 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
171 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
172 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
173 }
174 s = e + 1;
175 }
176 if ((xi->curr_mac_addr[0] & 0x03) != 0x02)
177 {
178 /* only copy if curr_mac_addr is not a LUA */
179 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
180 }
181 }
182 else if (strcmp(setting, "feature-sg") == 0)
183 {
184 if (atoi(value))
185 {
186 backend_sg = 1;
187 }
188 }
189 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
190 {
191 if (atoi(value))
192 {
193 backend_gso = 1;
194 }
195 }
196 break;
197 case XEN_INIT_TYPE_VECTORS:
198 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
199 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
200 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
201 {
202 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
203 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
204 FUNCTION_EXIT();
205 return NDIS_STATUS_ADAPTER_NOT_FOUND;
206 }
207 else
208 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
209 break;
210 case XEN_INIT_TYPE_STATE_PTR:
211 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
212 xi->device_state = (PXENPCI_DEVICE_STATE)value;
213 break;
214 default:
215 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
216 break;
217 }
218 }
219 if (xi->config_sg && !backend_sg)
220 {
221 KdPrint((__DRIVER_NAME " SG not supported by backend - disabling\n"));
222 xi->config_sg = 0;
223 }
224 if (xi->config_gso && !backend_gso)
225 {
226 KdPrint((__DRIVER_NAME " GSO not supported by backend - disabling\n"));
227 xi->config_gso = 0;
228 }
229 FUNCTION_EXIT();
231 return NDIS_STATUS_SUCCESS;
232 }
234 static DDKAPI VOID
235 XenNet_Resume(PDEVICE_OBJECT device_object, PVOID context)
236 {
237 struct xennet_info *xi = context;
239 UNREFERENCED_PARAMETER(device_object);
241 FUNCTION_ENTER();
243 ASSERT(xi->resume_work_item);
244 IoFreeWorkItem(xi->resume_work_item);
245 xi->resume_work_item = NULL;
247 XenNet_TxResumeStart(xi);
248 XenNet_RxResumeStart(xi);
249 XenNet_ConnectBackend(xi);
250 XenNet_RxResumeEnd(xi);
251 XenNet_TxResumeEnd(xi);
252 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
253 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
254 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
255 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
257 FUNCTION_EXIT();
259 }
261 static VOID
262 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
263 {
264 struct xennet_info *xi = context;
265 KIRQL old_irql;
267 UNREFERENCED_PARAMETER(dpc);
268 UNREFERENCED_PARAMETER(arg1);
269 UNREFERENCED_PARAMETER(arg2);
271 FUNCTION_ENTER();
273 switch (xi->device_state->suspend_resume_state_pdo)
274 {
275 case SR_STATE_SUSPENDING:
276 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
277 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
278 if (xi->tx_id_free == NET_TX_RING_SIZE)
279 {
280 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
281 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
282 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
283 }
284 KeReleaseSpinLock(&xi->rx_lock, old_irql);
285 break;
286 case SR_STATE_RESUMING:
287 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
288 ASSERT(!xi->resume_work_item);
289 xi->resume_work_item = IoAllocateWorkItem(xi->fdo);
290 IoQueueWorkItem(xi->resume_work_item, XenNet_Resume, DelayedWorkQueue, xi);
291 break;
292 default:
293 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
294 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
295 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
296 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
297 break;
298 }
299 KeMemoryBarrier();
301 FUNCTION_EXIT();
302 }
304 static DDKAPI BOOLEAN
305 XenNet_HandleEvent(PVOID context)
306 {
307 struct xennet_info *xi = context;
308 ULONG suspend_resume_state_pdo;
310 //FUNCTION_ENTER();
311 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
312 KeMemoryBarrier();
313 // KdPrint((__DRIVER_NAME " connected = %d, inactive = %d, suspend_resume_state_pdo = %d\n",
314 // xi->connected, xi->inactive, suspend_resume_state_pdo));
315 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
316 {
317 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
318 }
319 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
320 {
321 KeInsertQueueDpc(&xi->tx_dpc, NULL, NULL);
322 KeInsertQueueDpc(&xi->rx_dpc, NULL, NULL);
323 }
324 //FUNCTION_EXIT();
325 return TRUE;
326 }
328 // Called at <= DISPATCH_LEVEL
329 static DDKAPI NDIS_STATUS
330 XenNet_Init(
331 OUT PNDIS_STATUS OpenErrorStatus,
332 OUT PUINT SelectedMediumIndex,
333 IN PNDIS_MEDIUM MediumArray,
334 IN UINT MediumArraySize,
335 IN NDIS_HANDLE MiniportAdapterHandle,
336 IN NDIS_HANDLE WrapperConfigurationContext
337 )
338 {
339 NDIS_STATUS status;
340 BOOLEAN medium_found = FALSE;
341 struct xennet_info *xi = NULL;
342 UINT nrl_length;
343 PNDIS_RESOURCE_LIST nrl;
344 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
345 KIRQL irq_level = 0;
346 ULONG irq_vector = 0;
347 ULONG irq_mode = 0;
348 NDIS_HANDLE config_handle;
349 NDIS_STRING config_param_name;
350 PNDIS_CONFIGURATION_PARAMETER config_param;
351 ULONG i;
352 PUCHAR ptr;
353 UCHAR type;
354 PCHAR setting, value;
355 ULONG length;
356 CHAR buf[128];
357 PVOID network_address;
358 UINT network_address_length;
359 BOOLEAN qemu_hide_filter = FALSE;
360 ULONG qemu_hide_flags_value = 0;
362 UNREFERENCED_PARAMETER(OpenErrorStatus);
364 FUNCTION_ENTER();
366 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
368 length = NdisReadPciSlotInformation(MiniportAdapterHandle, 0, 0, &buf, 128);
369 KdPrint((__DRIVER_NAME " NdisReadPciSlotInformation = %d\n", length));
370 /* deal with medium stuff */
371 for (i = 0; i < MediumArraySize; i++)
372 {
373 if (MediumArray[i] == NdisMedium802_3)
374 {
375 medium_found = TRUE;
376 break;
377 }
378 }
379 if (!medium_found)
380 {
381 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
382 return NDIS_STATUS_UNSUPPORTED_MEDIA;
383 }
384 *SelectedMediumIndex = i;
386 /* Alloc memory for adapter private info */
387 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
388 if (!NT_SUCCESS(status))
389 {
390 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
391 status = NDIS_STATUS_RESOURCES;
392 goto err;
393 }
394 RtlZeroMemory(xi, sizeof(*xi));
395 xi->adapter_handle = MiniportAdapterHandle;
396 xi->rx_target = RX_DFL_MIN_TARGET;
397 xi->rx_min_target = RX_DFL_MIN_TARGET;
398 xi->rx_max_target = RX_MAX_TARGET;
399 xi->inactive = TRUE;
400 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi, 0,
401 #ifdef NDIS51_MINIPORT
402 NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
403 #endif
404 |NDIS_ATTRIBUTE_DESERIALIZE
405 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK
406 |NDIS_ATTRIBUTE_BUS_MASTER,
407 NdisInterfaceInternal);
408 xi->multicast_list_size = 0;
409 xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
411 nrl_length = 0;
412 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
413 NULL, (PUINT)&nrl_length);
414 KdPrint((__DRIVER_NAME " nrl_length = %d\n", nrl_length));
415 status = NdisAllocateMemoryWithTag((PVOID)&nrl, nrl_length, XENNET_POOL_TAG);
416 if (status != NDIS_STATUS_SUCCESS)
417 {
418 KdPrint((__DRIVER_NAME " Could not get allocate memory for Adapter Resources 0x%x\n", status));
419 return NDIS_STATUS_RESOURCES;
420 }
421 NdisMQueryAdapterResources(&status, WrapperConfigurationContext,
422 nrl, (PUINT)&nrl_length);
423 if (status != NDIS_STATUS_SUCCESS)
424 {
425 KdPrint((__DRIVER_NAME " Could not get Adapter Resources 0x%x\n", status));
426 return NDIS_STATUS_RESOURCES;
427 }
428 xi->event_channel = 0;
429 xi->config_csum = 1;
430 xi->config_csum_rx_check = 1;
431 xi->config_sg = 1;
432 xi->config_gso = 61440;
433 xi->config_page = NULL;
434 xi->config_rx_interrupt_moderation = 0;
436 for (i = 0; i < nrl->Count; i++)
437 {
438 prd = &nrl->PartialDescriptors[i];
440 switch(prd->Type)
441 {
442 case CmResourceTypeInterrupt:
443 irq_vector = prd->u.Interrupt.Vector;
444 irq_level = (KIRQL)prd->u.Interrupt.Level;
445 irq_mode = (prd->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?NdisInterruptLatched:NdisInterruptLevelSensitive;
446 KdPrint((__DRIVER_NAME " irq_vector = %03x, irq_level = %03x, irq_mode = %s\n", irq_vector, irq_level,
447 (irq_mode == NdisInterruptLatched)?"NdisInterruptLatched":"NdisInterruptLevelSensitive"));
448 break;
449 case CmResourceTypeMemory:
450 if (xi->config_page)
451 {
452 KdPrint(("More than one memory range\n"));
453 return NDIS_STATUS_RESOURCES;
454 }
455 else
456 {
457 status = NdisMMapIoSpace(&xi->config_page, MiniportAdapterHandle, prd->u.Memory.Start, prd->u.Memory.Length);
458 if (!NT_SUCCESS(status))
459 {
460 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
461 NdisFreeMemory(nrl, nrl_length, 0);
462 return NDIS_STATUS_RESOURCES;
463 }
464 }
465 break;
466 }
467 }
468 NdisFreeMemory(nrl, nrl_length, 0);
469 if (!xi->config_page)
470 {
471 KdPrint(("No config page given\n"));
472 return NDIS_STATUS_RESOURCES;
473 }
475 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
477 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
478 &xi->lower_do, NULL, NULL);
479 xi->packet_filter = 0;
481 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
482 NAME_SIZE, xi->dev_desc, &length);
483 if (!NT_SUCCESS(status))
484 {
485 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
486 status = NDIS_STATUS_FAILURE;
487 goto err;
488 }
490 ptr = xi->config_page;
491 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
492 {
493 switch(type)
494 {
495 case XEN_INIT_TYPE_VECTORS:
496 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
497 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
498 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
499 {
500 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
501 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
502 FUNCTION_EXIT();
503 return NDIS_STATUS_FAILURE;
504 }
505 else
506 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
507 break;
508 case XEN_INIT_TYPE_STATE_PTR:
509 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
510 xi->device_state = (PXENPCI_DEVICE_STATE)value;
511 break;
512 #if 0
513 case XEN_INIT_TYPE_ACTIVE:
514 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_ACTIVE\n"));
515 xi->inactive = FALSE;
516 break;
517 #endif
518 case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
519 qemu_hide_flags_value = PtrToUlong(value);
520 break;
521 case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
522 qemu_hide_filter = TRUE;
523 break;
524 default:
525 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
526 break;
527 }
528 }
530 if ((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) || qemu_hide_filter)
531 xi->inactive = FALSE;
533 // now build config page
535 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
536 if (!NT_SUCCESS(status))
537 {
538 KdPrint(("Could not open config in registry (%08x)\n", status));
539 status = NDIS_STATUS_RESOURCES;
540 goto err;
541 }
543 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
544 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
545 if (!NT_SUCCESS(status))
546 {
547 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
548 xi->config_sg = 1;
549 }
550 else
551 {
552 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
553 xi->config_sg = config_param->ParameterData.IntegerData;
554 }
556 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
557 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
558 if (!NT_SUCCESS(status))
559 {
560 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
561 xi->config_gso = 0;
562 }
563 else
564 {
565 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
566 xi->config_gso = config_param->ParameterData.IntegerData;
567 if (xi->config_gso > 61440)
568 {
569 xi->config_gso = 61440;
570 KdPrint(("(clipped to %d)\n", xi->config_gso));
571 }
572 }
574 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
575 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
576 if (!NT_SUCCESS(status))
577 {
578 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
579 xi->config_csum = 1;
580 }
581 else
582 {
583 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
584 xi->config_csum = !!config_param->ParameterData.IntegerData;
585 }
587 NdisInitUnicodeString(&config_param_name, L"ChecksumOffloadRxCheck");
588 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
589 if (!NT_SUCCESS(status))
590 {
591 KdPrint(("Could not read ChecksumOffloadRxCheck value (%08x)\n", status));
592 xi->config_csum_rx_check = 1;
593 }
594 else
595 {
596 KdPrint(("ChecksumOffloadRxCheck = %d\n", config_param->ParameterData.IntegerData));
597 xi->config_csum_rx_check = !!config_param->ParameterData.IntegerData;
598 }
600 NdisInitUnicodeString(&config_param_name, L"MTU");
601 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
602 if (!NT_SUCCESS(status))
603 {
604 KdPrint(("Could not read MTU value (%08x)\n", status));
605 xi->config_mtu = 1500;
606 }
607 else
608 {
609 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
610 xi->config_mtu = config_param->ParameterData.IntegerData;
611 }
613 NdisInitUnicodeString(&config_param_name, L"RxInterruptModeration");
614 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
615 if (!NT_SUCCESS(status))
616 {
617 KdPrint(("Could not read RxInterruptModeration value (%08x)\n", status));
618 xi->config_rx_interrupt_moderation = 1500;
619 }
620 else
621 {
622 KdPrint(("RxInterruptModeration = %d\n", config_param->ParameterData.IntegerData));
623 xi->config_rx_interrupt_moderation = config_param->ParameterData.IntegerData;
624 }
627 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
628 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02))
629 {
630 KdPrint(("Could not read NetworkAddress value (%08x) or value is invalid\n", status));
631 memset(xi->curr_mac_addr, 0, ETH_ALEN);
632 }
633 else
634 {
635 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
636 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
637 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
638 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
639 }
641 xi->config_max_pkt_size = max(xi->config_mtu + XN_HDR_SIZE, xi->config_gso + XN_HDR_SIZE);
643 NdisCloseConfiguration(config_handle);
645 ptr = xi->config_page;
646 // two XEN_INIT_TYPE_RUNs means go straight to XenbusStateConnected - skip XenbusStateInitialised
647 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
648 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
649 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
650 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
651 #pragma warning(suppress:4054)
652 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
653 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
654 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
655 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
656 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
657 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
658 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->config_csum);
659 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
660 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->config_sg);
661 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
662 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->config_gso);
663 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
664 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
666 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
667 if (!NT_SUCCESS(status))
668 {
669 KdPrint(("Failed to complete device configuration (%08x)\n", status));
670 goto err;
671 }
673 status = XenNet_ConnectBackend(xi);
675 if (!NT_SUCCESS(status))
676 {
677 KdPrint(("Failed to complete device configuration (%08x)\n", status));
678 goto err;
679 }
681 if (!xi->config_sg)
682 {
683 /* without SG, GSO can be a maximum of PAGE_SIZE */
684 xi->config_gso = min(xi->config_gso, PAGE_SIZE);
685 }
687 XenNet_TxInit(xi);
688 XenNet_RxInit(xi);
690 xi->connected = TRUE;
692 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
694 FUNCTION_EXIT();
696 return NDIS_STATUS_SUCCESS;
698 err:
699 NdisFreeMemory(xi, 0, 0);
700 *OpenErrorStatus = status;
701 FUNCTION_EXIT_STATUS(status);
702 return status;
703 }
705 VOID
706 XenNet_PnPEventNotify(
707 IN NDIS_HANDLE MiniportAdapterContext,
708 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
709 IN PVOID InformationBuffer,
710 IN ULONG InformationBufferLength
711 )
712 {
713 UNREFERENCED_PARAMETER(MiniportAdapterContext);
714 UNREFERENCED_PARAMETER(PnPEvent);
715 UNREFERENCED_PARAMETER(InformationBuffer);
716 UNREFERENCED_PARAMETER(InformationBufferLength);
718 FUNCTION_ENTER();
719 switch (PnPEvent)
720 {
721 case NdisDevicePnPEventSurpriseRemoved:
722 KdPrint((__DRIVER_NAME " NdisDevicePnPEventSurpriseRemoved\n"));
723 break;
724 case NdisDevicePnPEventPowerProfileChanged :
725 KdPrint((__DRIVER_NAME " NdisDevicePnPEventPowerProfileChanged\n"));
726 break;
727 default:
728 KdPrint((__DRIVER_NAME " %d\n", PnPEvent));
729 break;
730 }
731 FUNCTION_EXIT();
732 }
734 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
735 VOID DDKAPI
736 XenNet_Shutdown(
737 IN NDIS_HANDLE MiniportAdapterContext
738 )
739 {
740 UNREFERENCED_PARAMETER(MiniportAdapterContext);
742 /* remember we are called at >= DIRQL here */
743 FUNCTION_ENTER();
744 FUNCTION_EXIT();
745 }
747 /* Opposite of XenNet_Init */
748 VOID DDKAPI
749 XenNet_Halt(
750 IN NDIS_HANDLE MiniportAdapterContext
751 )
752 {
753 struct xennet_info *xi = MiniportAdapterContext;
755 FUNCTION_ENTER();
756 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
758 xi->shutting_down = TRUE;
759 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
761 XenNet_TxShutdown(xi);
762 XenNet_RxShutdown(xi);
764 xi->connected = FALSE;
765 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
767 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
769 if (!xi->config_sg)
770 {
771 NdisMFreeMapRegisters(xi->adapter_handle);
772 }
774 NdisFreeMemory(xi, 0, 0);
776 FUNCTION_EXIT();
777 }
779 NDIS_STATUS
780 XenNet_Reset(
781 PBOOLEAN AddressingReset,
782 NDIS_HANDLE MiniportAdapterContext
783 )
784 {
785 UNREFERENCED_PARAMETER(MiniportAdapterContext);
787 *AddressingReset = FALSE;
788 return NDIS_STATUS_SUCCESS;
789 }
791 NTSTATUS DDKAPI
792 DriverEntry(
793 PDRIVER_OBJECT DriverObject,
794 PUNICODE_STRING RegistryPath
795 )
796 {
797 NTSTATUS status;
798 NDIS_HANDLE ndis_wrapper_handle = NULL;
799 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
801 FUNCTION_ENTER();
803 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
804 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
806 KdPrint((__DRIVER_NAME " NdisGetVersion = %x\n", NdisGetVersion()));
808 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
809 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
810 KdPrint((__DRIVER_NAME " ndis_wrapper_handle = %p\n", ndis_wrapper_handle));
811 if (!ndis_wrapper_handle)
812 {
813 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper failed\n"));
814 return NDIS_STATUS_FAILURE;
815 }
816 KdPrint((__DRIVER_NAME " NdisMInitializeWrapper succeeded\n"));
818 /* NDIS 5.1 driver */
819 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
820 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
822 KdPrint((__DRIVER_NAME " MajorNdisVersion = %d, MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
824 mini_chars.HaltHandler = XenNet_Halt;
825 mini_chars.InitializeHandler = XenNet_Init;
826 //mini_chars.ISRHandler = XenNet_InterruptIsr;
827 //mini_chars.HandleInterruptHandler = XenNet_InterruptDpc;
828 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
829 mini_chars.ResetHandler = XenNet_Reset;
830 mini_chars.SetInformationHandler = XenNet_SetInformation;
831 /* added in v.4 -- use multiple pkts interface */
832 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
833 mini_chars.SendPacketsHandler = XenNet_SendPackets;
834 /* don't support cancel - no point as packets are never queued for long */
835 //mini_chars.CancelSendPacketsHandler = XenNet_CancelSendPackets;
837 #ifdef NDIS51_MINIPORT
838 /* added in v.5.1 */
839 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
840 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
841 #else
842 // something else here
843 #endif
845 /* set up upper-edge interface */
846 KdPrint((__DRIVER_NAME " about to call NdisMRegisterMiniport\n"));
847 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
848 KdPrint((__DRIVER_NAME " called NdisMRegisterMiniport\n"));
849 if (!NT_SUCCESS(status))
850 {
851 KdPrint((__DRIVER_NAME " NdisMRegisterMiniport failed, status = 0x%x\n", status));
852 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
853 return status;
854 }
856 FUNCTION_EXIT();
858 return status;
859 }