win-pvdrivers

changeset 973:b6d85bc1ce2d

Better handling of request cancellation.
author James Harper <james.harper@bendigoit.com.au>
date Sun Apr 15 14:33:29 2012 +1000 (2012-04-15)
parents ef1f25e2c281
children 9cea419e4b1d
files xenusb/sources xenusb/xenusb.h xenusb/xenusb_devurb.c xenusb/xenusb_fdo.c
line diff
     1.1 --- a/xenusb/sources	Sun Apr 15 14:27:22 2012 +1000
     1.2 +++ b/xenusb/sources	Sun Apr 15 14:33:29 2012 +1000
     1.3 @@ -4,4 +4,9 @@ TARGETTYPE=DRIVER
     1.4  KMDF_VERSION_MAJOR=1
     1.5  NTTARGETFILES=$(NTTARGETFILES) $(OBJ_PATH)\$(O)\$(TARGETNAME).inf
     1.6  TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\wdmsec.lib $(DDK_LIB_PATH)\Rtlver.lib $(DDK_LIB_PATH)\..\..\wlh\*\aux_klib.lib
     1.7 +!IF $(386)
     1.8 +TARGETLIBS=$(TARGETLIBS) $(LIBLFDS_DIR)\bin\i386\liblfds.lib
     1.9 +!ELSE
    1.10 +TARGETLIBS=$(TARGETLIBS) $(LIBLFDS_DIR)\bin\AMD64\liblfds.lib
    1.11 +!ENDIF
    1.12  SOURCES=xenusb.rc xenusb.c xenusb_fdo.c xenusb_hub.c xenusb_huburb.c xenusb_devurb.c xenusb_decode.c
     2.1 --- a/xenusb/xenusb.h	Sun Apr 15 14:27:22 2012 +1000
     2.2 +++ b/xenusb/xenusb.h	Sun Apr 15 14:33:29 2012 +1000
     2.3 @@ -42,6 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fi
     2.4  #include <errno.h>
     2.5  #define NTSTRSAFE_LIB
     2.6  #include <ntstrsafe.h>
     2.7 +#include <liblfds.h>
     2.8  
     2.9  #define __DRIVER_NAME "XenUSB"
    2.10  
    2.11 @@ -101,25 +102,14 @@ Foundation, Inc., 51 Franklin Street, Fi
    2.12  #define LINUX_URB_ZERO_PACKET         0x0040  /* Finish bulk OUT with short packet */
    2.13  #define LINUX_URB_NO_INTERRUPT        0x0080  /* HINT: no non-error interrupt needed */
    2.14  
    2.15 -//#define PRE_DECLARE_TYPE_TYPEDEF(x) struct _##x; typedef struct _##x x##_t
    2.16 -
    2.17 -struct _usbif_shadow;
    2.18 -typedef struct _usbif_shadow usbif_shadow_t;
    2.19 -
    2.20 -struct _usbif_shadow {
    2.21 -  uint16_t id;
    2.22 -  WDFREQUEST request;
    2.23 -  usbif_urb_request_t req_storage; /* used by cancel/unlink */
    2.24 -  usbif_urb_request_t *req;
    2.25 -  usbif_urb_response_t *rsp;
    2.26 -  PMDL mdl; /* can be null for requests with no data */
    2.27 -  ULONG total_length;
    2.28 -  usbif_shadow_t *next; /* collect then process responses as they come off the ring */
    2.29 -};
    2.30 +struct _pvurb;
    2.31 +struct _partial_pvurb;
    2.32 +typedef struct _pvurb pvurb_t;
    2.33 +typedef struct _partial_pvurb partial_pvurb_t;
    2.34  
    2.35  /* needs to be at least USB_URB_RING_SIZE number of requests available */
    2.36 -#define MAX_SHADOW_ENTRIES 64
    2.37 -#define SHADOW_ENTRIES max(MAX_SHADOW_ENTRIES, USB_URB_RING_SIZE)
    2.38 +#define MAX_ID_COUNT 64
    2.39 +#define ID_COUNT min(MAX_ID_COUNT, USB_URB_RING_SIZE)
    2.40  
    2.41  /*
    2.42  for IOCTL_PVUSB_SUBMIT_URB, the pvusb_urb_t struct is passed as Parameters.Others.Arg1
    2.43 @@ -128,12 +118,28 @@ req must have pipe, transfer_flags, buff
    2.44  
    2.45  #define IOCTL_INTERNAL_PVUSB_SUBMIT_URB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
    2.46  
    2.47 -typedef struct _pvurb {
    2.48 +struct _partial_pvurb {
    2.49 +  LIST_ENTRY entry;
    2.50 +  pvurb_t *pvurb;
    2.51 +  partial_pvurb_t *other_partial_pvurb; /* link to the cancelled or cancelling partial_pvurb */
    2.52    usbif_urb_request_t req;
    2.53    usbif_urb_response_t rsp;
    2.54 -  PMDL mdl; /* can be null for requests with no data */
    2.55 +  PMDL mdl;
    2.56 +  BOOLEAN on_ring; /* is (or has been) on the hardware ring */
    2.57 +};
    2.58 +  
    2.59 +struct _pvurb {
    2.60 +  /* set by xenusb_devurb.c */
    2.61 +  usbif_urb_request_t req;  /* only pipe, transfer_flags, isoc/intr filled out by submitter */
    2.62 +  PMDL mdl;                 /* can be null for requests with no data */
    2.63 +  /* set by xenusb_fdo.c */
    2.64 +  usbif_urb_response_t rsp; /* only status, actual_length, error_count valid */
    2.65 +  NTSTATUS status;
    2.66 +  WDFREQUEST request;
    2.67 +  ULONG ref;                /* reference counting */
    2.68    ULONG total_length;
    2.69 -} pvurb_t;
    2.70 +  pvurb_t *next; /* collect then process responses as they come off the ring */
    2.71 +};
    2.72  
    2.73  struct _xenusb_endpoint_t;
    2.74  struct _xenusb_interface_t;
    2.75 @@ -147,7 +153,6 @@ typedef struct _xenusb_device_t xenusb_d
    2.76  typedef struct _xenusb_endpoint_t {
    2.77    xenusb_interface_t *interface;
    2.78    ULONG pipe_value;
    2.79 -  //WDFTIMER interrupt_timer;
    2.80    WDFQUEUE queue;
    2.81    WDFSPINLOCK lock;
    2.82    USB_ENDPOINT_DESCRIPTOR endpoint_descriptor;
    2.83 @@ -155,7 +160,6 @@ typedef struct _xenusb_endpoint_t {
    2.84  //WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(pxenusb_endpoint_t, GetEndpoint)
    2.85  
    2.86  typedef struct _xenusb_interface_t {
    2.87 -  //ULONG pipe_value;
    2.88    xenusb_config_t *config;
    2.89    USB_INTERFACE_DESCRIPTOR interface_descriptor;
    2.90    xenusb_endpoint_t *endpoints[0];
    2.91 @@ -212,9 +216,8 @@ typedef struct {
    2.92    
    2.93    WDFDEVICE root_hub_device;
    2.94  
    2.95 -  usbif_shadow_t shadows[MAX_SHADOW_ENTRIES];
    2.96 -  USHORT shadow_free_list[MAX_SHADOW_ENTRIES];
    2.97 -  USHORT shadow_free;
    2.98 +  struct stack_state *id_ss;
    2.99 +  partial_pvurb_t *partial_pvurbs[MAX_ID_COUNT];
   2.100  
   2.101    PUCHAR config_page;
   2.102  
   2.103 @@ -225,11 +228,14 @@ typedef struct {
   2.104    KSPIN_LOCK urb_ring_lock;
   2.105    usbif_urb_sring_t *urb_sring;
   2.106    usbif_urb_front_ring_t urb_ring;
   2.107 +  LIST_ENTRY partial_pvurb_queue;
   2.108 +  LIST_ENTRY partial_pvurb_ring;
   2.109  
   2.110    KSPIN_LOCK conn_ring_lock;
   2.111    usbif_conn_sring_t *conn_sring;
   2.112    usbif_conn_front_ring_t conn_ring;
   2.113  
   2.114 +  domid_t backend_id;
   2.115    evtchn_port_t event_channel;
   2.116  
   2.117    XENPCI_VECTORS vectors;
   2.118 @@ -273,26 +279,22 @@ typedef struct {
   2.119    //xenusb_compatible_id_details_t xucid[1];
   2.120  } XENUSB_PDO_IDENTIFICATION_DESCRIPTION, *PXENUSB_PDO_IDENTIFICATION_DESCRIPTION;
   2.121  
   2.122 -/* call with ring lock held */
   2.123 -static usbif_shadow_t *
   2.124 -get_shadow_from_freelist(PXENUSB_DEVICE_DATA xudd)
   2.125 -{
   2.126 -  if (xudd->shadow_free == 0)
   2.127 -  {
   2.128 -    KdPrint((__DRIVER_NAME "     No more shadow entries\n"));
   2.129 -    return NULL;
   2.130 +
   2.131 +static uint16_t
   2.132 +get_id_from_freelist(PXENUSB_DEVICE_DATA xudd) {
   2.133 +  ULONG_PTR _id;
   2.134 +  if (!stack_pop(xudd->id_ss, (VOID *)&_id)) {
   2.135 +    KdPrint((__DRIVER_NAME "     No more id's\n"));
   2.136 +    return (uint16_t)-1;
   2.137    }
   2.138 -  xudd->shadow_free--;
   2.139 -  return &xudd->shadows[xudd->shadow_free_list[xudd->shadow_free]];
   2.140 +  return (uint16_t)_id;
   2.141  }
   2.142  
   2.143  /* call with ring lock held */
   2.144  static VOID
   2.145 -put_shadow_on_freelist(PXENUSB_DEVICE_DATA xudd, usbif_shadow_t *shadow)
   2.146 -{
   2.147 -  xudd->shadow_free_list[xudd->shadow_free] = (USHORT)shadow->id;
   2.148 -  shadow->request = NULL;
   2.149 -  xudd->shadow_free++;
   2.150 +put_id_on_freelist(PXENUSB_DEVICE_DATA xudd, uint16_t id) {
   2.151 +  ULONG_PTR _id = id;
   2.152 +  stack_push(xudd->id_ss, (VOID *)_id);
   2.153  }
   2.154  
   2.155  static
   2.156 @@ -322,17 +324,6 @@ XenUsb_GetResponse(PXENVBD_DEVICE_DATA x
   2.157  }
   2.158  #endif
   2.159  
   2.160 -
   2.161 -/*
   2.162 -EVT_WDF_DEVICE_PREPARE_HARDWARE XenUsb_EvtDevicePrepareHardware;
   2.163 -EVT_WDF_DEVICE_RELEASE_HARDWARE XenUsb_EvtDeviceReleaseHardware;
   2.164 -EVT_WDF_DEVICE_D0_ENTRY XenUsb_EvtDeviceD0Entry;
   2.165 -EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED XenUsb_EvtDeviceD0EntryPostInterruptsEnabled;
   2.166 -EVT_WDF_DEVICE_D0_EXIT XenUsb_EvtDeviceD0Exit;
   2.167 -EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED XenUsb_EvtDeviceD0ExitPreInterruptsDisabled;
   2.168 -EVT_WDF_DEVICE_QUERY_REMOVE XenUsb_EvtDeviceQueryRemove;
   2.169 -*/
   2.170 -
   2.171  EVT_WDF_DRIVER_DEVICE_ADD XenUsb_EvtDriverDeviceAdd;
   2.172  
   2.173  EVT_WDF_CHILD_LIST_CREATE_DEVICE XenUsb_EvtChildListCreateDevice;
     3.1 --- a/xenusb/xenusb_devurb.c	Sun Apr 15 14:27:22 2012 +1000
     3.2 +++ b/xenusb/xenusb_devurb.c	Sun Apr 15 14:33:29 2012 +1000
     3.3 @@ -27,7 +27,7 @@ XenUsb_GetUsbdStatusFromPvStatus(ULONG p
     3.4    {
     3.5    case 0:
     3.6      return USBD_STATUS_SUCCESS;
     3.7 -  case -EPROTO: /*  ? */
     3.8 +  case -EPROTO: /*  -71 */
     3.9      FUNCTION_MSG("pvstatus = -EPROTO\n");
    3.10      return USBD_STATUS_CRC;
    3.11    case -EPIPE: /* see linux code - EPIPE is when the HCD returned a stall */
    3.12 @@ -41,9 +41,9 @@ XenUsb_GetUsbdStatusFromPvStatus(ULONG p
    3.13      shadow->urb->UrbHeader.Status USBD_STATUS_ERROR_SHORT_TRANSFER;
    3.14      break;
    3.15  #endif
    3.16 -  case -ESHUTDOWN:
    3.17 -    FUNCTION_MSG("pvstatus = -USBD_STATUS_INTERNAL_HC_ERROR\n");
    3.18 -    return USBD_STATUS_INTERNAL_HC_ERROR;
    3.19 +  case -ESHUTDOWN: /* -108 */
    3.20 +    FUNCTION_MSG("pvstatus = -ESHUTDOWN (USBD_STATUS_DEVICE_GONE)\n");
    3.21 +    return USBD_STATUS_DEVICE_GONE;
    3.22    default:
    3.23      FUNCTION_MSG("pvstatus = %d\n", pvstatus);
    3.24      return USBD_STATUS_INTERNAL_HC_ERROR;
     4.1 --- a/xenusb/xenusb_fdo.c	Sun Apr 15 14:27:22 2012 +1000
     4.2 +++ b/xenusb/xenusb_fdo.c	Sun Apr 15 14:33:29 2012 +1000
     4.3 @@ -34,6 +34,8 @@ static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTRO
     4.4  static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL XenUsb_EvtIoInternalDeviceControl;
     4.5  static EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL XenUsb_EvtIoInternalDeviceControl_PVURB;
     4.6  static EVT_WDF_IO_QUEUE_IO_DEFAULT XenUsb_EvtIoDefault;
     4.7 +static EVT_WDF_REQUEST_CANCEL XenUsb_EvtRequestCancelPvUrb;
     4.8 +
     4.9  //static EVT_WDF_PROGRAM_DMA XenUsb_ExecuteRequestCallback;
    4.10  
    4.11  NTSTATUS
    4.12 @@ -90,6 +92,40 @@ XenUsb_EvtDeviceWdmIrpPreprocessQUERY_IN
    4.13    return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
    4.14  }
    4.15  
    4.16 +/* called with urb ring lock held */
    4.17 +static VOID
    4.18 +PutRequestsOnRing(PXENUSB_DEVICE_DATA xudd) {
    4.19 +  partial_pvurb_t *partial_pvurb;
    4.20 +  uint16_t id;
    4.21 +  int notify;
    4.22 +
    4.23 +  FUNCTION_ENTER();
    4.24 +  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
    4.25 +
    4.26 +  while ((partial_pvurb = (partial_pvurb_t *)RemoveHeadList((PLIST_ENTRY)&xudd->partial_pvurb_queue)) != (partial_pvurb_t *)&xudd->partial_pvurb_queue) {
    4.27 +    FUNCTION_MSG("partial_pvurb = %p\n", partial_pvurb);
    4.28 +    /* if this partial_pvurb is cancelling another we don't need to check if the cancelled partial_pvurb is on the ring - that is taken care of in HandleEvent */
    4.29 +    id = get_id_from_freelist(xudd);
    4.30 +    if (id == (uint16_t)-1) {
    4.31 +      FUNCTION_MSG("no free ring slots\n");
    4.32 +      InsertHeadList(&xudd->partial_pvurb_queue, &partial_pvurb->entry);
    4.33 +      break;
    4.34 +    }
    4.35 +    InsertTailList(&xudd->partial_pvurb_ring, &partial_pvurb->entry);
    4.36 +    xudd->partial_pvurbs[id] = partial_pvurb;
    4.37 +    partial_pvurb->req.id = id;    
    4.38 +    *RING_GET_REQUEST(&xudd->urb_ring, xudd->urb_ring.req_prod_pvt) = partial_pvurb->req;
    4.39 +    xudd->urb_ring.req_prod_pvt++;
    4.40 +  }
    4.41 +  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xudd->urb_ring, notify);
    4.42 +  if (notify) {
    4.43 +    FUNCTION_MSG("Notifying\n");
    4.44 +    xudd->vectors.EvtChn_Notify(xudd->vectors.context, xudd->event_channel);
    4.45 +  }
    4.46 +  
    4.47 +  FUNCTION_EXIT();
    4.48 +}
    4.49 +
    4.50  /* called at DISPATCH_LEVEL */
    4.51  static BOOLEAN
    4.52  XenUsb_HandleEvent(PVOID context)
    4.53 @@ -101,8 +137,8 @@ XenUsb_HandleEvent(PVOID context)
    4.54    usbif_conn_response_t *conn_rsp;
    4.55    usbif_conn_request_t *conn_req;
    4.56    int more_to_do;
    4.57 -  usbif_shadow_t *complete_head = NULL, *complete_tail = NULL;
    4.58 -  usbif_shadow_t *shadow;
    4.59 +  pvurb_t *pvurb, *complete_head = NULL, *complete_tail = NULL;
    4.60 +  partial_pvurb_t *partial_pvurb;
    4.61    BOOLEAN port_changed = FALSE;
    4.62  
    4.63    FUNCTION_ENTER();
    4.64 @@ -117,43 +153,65 @@ XenUsb_HandleEvent(PVOID context)
    4.65      {
    4.66        urb_rsp = RING_GET_RESPONSE(&xudd->urb_ring, cons);
    4.67  //      FUNCTION_MSG("urb_rsp->id = %d\n", urb_rsp->id);
    4.68 -      shadow = &xudd->shadows[urb_rsp->id];
    4.69 +      partial_pvurb = xudd->partial_pvurbs[urb_rsp->id];
    4.70 +      RemoveEntryList(&partial_pvurb->entry);
    4.71 +      partial_pvurb->rsp = *urb_rsp;
    4.72  //      FUNCTION_MSG("shadow = %p\n", shadow);
    4.73  //      FUNCTION_MSG("shadow->rsp = %p\n", shadow->rsp);
    4.74 -      if (usbif_pipeunlink(shadow->req->pipe)) {
    4.75 -        FUNCTION_MSG("is a cancel request for request %p\n", shadow->request);
    4.76 +      if (usbif_pipeunlink(partial_pvurb->req.pipe)) {
    4.77 +        FUNCTION_MSG("is a cancel request for request %p\n", partial_pvurb->pvurb->request);
    4.78          FUNCTION_MSG("urb_ring rsp status = %d\n", urb_rsp->status);
    4.79          // status should be 115 == EINPROGRESS
    4.80 -        put_shadow_on_freelist(xudd, shadow);
    4.81 -        /* nothing else to do - clean up when the real request comes off the ring */
    4.82        } else {
    4.83 -        *shadow->rsp = *urb_rsp;
    4.84 -  //      FUNCTION_MSG("A\n");
    4.85 -        shadow->next = NULL;
    4.86 -  //      FUNCTION_MSG("B\n");
    4.87 -        shadow->total_length += urb_rsp->actual_length;
    4.88 +        partial_pvurb->pvurb->total_length += urb_rsp->actual_length;
    4.89 +        if (!partial_pvurb->pvurb->rsp.status)
    4.90 +          partial_pvurb->pvurb->rsp.status = urb_rsp->status;
    4.91 +        partial_pvurb->pvurb->rsp.error_count += urb_rsp->error_count;;
    4.92 +        if (partial_pvurb->mdl) {
    4.93 +          int i;
    4.94 +          for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) {
    4.95 +            xudd->vectors.GntTbl_EndAccess(xudd->vectors.context,
    4.96 +              partial_pvurb->req.seg[i].gref, FALSE, (ULONG)'XUSB');
    4.97 +          }
    4.98 +        }
    4.99  
   4.100 -        KdPrint((__DRIVER_NAME "     urb_ring rsp id = %d\n", shadow->rsp->id));
   4.101 -        KdPrint((__DRIVER_NAME "     urb_ring rsp start_frame = %d\n", shadow->rsp->start_frame));
   4.102 -        KdPrint((__DRIVER_NAME "     urb_ring rsp status = %d\n", shadow->rsp->status));
   4.103 -        KdPrint((__DRIVER_NAME "     urb_ring rsp actual_length = %d\n", shadow->rsp->actual_length));
   4.104 -        KdPrint((__DRIVER_NAME "     urb_ring rsp error_count = %d\n", shadow->rsp->error_count));
   4.105 -        KdPrint((__DRIVER_NAME "     urb_ring total_length = %d\n", shadow->total_length));
   4.106 -        
   4.107 -        status = WdfRequestUnmarkCancelable(shadow->request);
   4.108 -        if (status == STATUS_CANCELLED) {
   4.109 -          FUNCTION_MSG("Cancel was called\n");
   4.110 +        KdPrint((__DRIVER_NAME "     urb_ring rsp id = %d\n", partial_pvurb->rsp.id));
   4.111 +        KdPrint((__DRIVER_NAME "     urb_ring rsp start_frame = %d\n", partial_pvurb->rsp.start_frame));
   4.112 +        KdPrint((__DRIVER_NAME "     urb_ring rsp status = %d\n", partial_pvurb->rsp.status));
   4.113 +        KdPrint((__DRIVER_NAME "     urb_ring rsp actual_length = %d\n", partial_pvurb->rsp.actual_length));
   4.114 +        KdPrint((__DRIVER_NAME "     urb_ring rsp error_count = %d\n", partial_pvurb->rsp.error_count));
   4.115 +      }
   4.116 +      if (partial_pvurb->other_partial_pvurb) {
   4.117 +        if (!partial_pvurb->other_partial_pvurb->on_ring) {
   4.118 +          /* cancel hasn't been put on the ring yet - remove it */
   4.119 +          RemoveEntryList(&partial_pvurb->other_partial_pvurb->entry);
   4.120 +          ASSERT(usbif_pipeunlink(partial_pvurb->other_partial_pvurb->req.pipe));
   4.121 +          partial_pvurb->pvurb->ref--;
   4.122 +          ExFreePoolWithTag(partial_pvurb->other_partial_pvurb, XENUSB_POOL_TAG);
   4.123          }
   4.124 +      }
   4.125 +      partial_pvurb->pvurb->ref--;
   4.126 +      switch (partial_pvurb->rsp.status) {
   4.127 +      case EINPROGRESS: /* unlink request */
   4.128 +      case ECONNRESET:  /* cancelled request */
   4.129 +        ASSERT(partial_pvurb->pvurb->status == STATUS_CANCELLED);
   4.130 +        break;
   4.131 +      default:
   4.132 +        break;
   4.133 +      }
   4.134 +      put_id_on_freelist(xudd, partial_pvurb->rsp.id);
   4.135 +      FUNCTION_MSG("B pvurb = %p\n", partial_pvurb->pvurb);
   4.136 +      FUNCTION_MSG("B request = %p\n", partial_pvurb->pvurb->request);
   4.137 +      partial_pvurb->pvurb->next = NULL;
   4.138 +      if (!partial_pvurb->pvurb->ref) {
   4.139          if (complete_tail) {
   4.140 -          complete_tail->next = shadow;
   4.141 +          complete_tail->next = partial_pvurb->pvurb;
   4.142          } else {
   4.143 -          complete_head = shadow;
   4.144 +          complete_head = partial_pvurb->pvurb;
   4.145          }
   4.146 -        complete_tail = shadow;
   4.147 +        complete_tail = partial_pvurb->pvurb;
   4.148        }
   4.149 -//      FUNCTION_MSG("C\n");
   4.150      }
   4.151 -//    FUNCTION_MSG("D\n");
   4.152  
   4.153      xudd->urb_ring.rsp_cons = cons;
   4.154      if (cons != xudd->urb_ring.req_prod_pvt) {
   4.155 @@ -163,8 +221,23 @@ XenUsb_HandleEvent(PVOID context)
   4.156        more_to_do = FALSE;
   4.157      }
   4.158    }
   4.159 +  PutRequestsOnRing(xudd);
   4.160    KeReleaseSpinLockFromDpcLevel(&xudd->urb_ring_lock);
   4.161  
   4.162 +  pvurb = complete_head;
   4.163 +  while (pvurb != NULL) {
   4.164 +    FUNCTION_MSG("C pvurb = %p\n", pvurb);
   4.165 +    FUNCTION_MSG("C request = %p\n", pvurb->request);
   4.166 +    complete_head = pvurb->next;
   4.167 +    status = WdfRequestUnmarkCancelable(pvurb->request);
   4.168 +    if (status == STATUS_CANCELLED) {
   4.169 +      FUNCTION_MSG("Cancel was called\n");
   4.170 +    }
   4.171 +    
   4.172 +    WdfRequestCompleteWithInformation(pvurb->request, pvurb->status, pvurb->total_length); /* the WDFREQUEST is always successfull here even if the pvurb->rsp has an error */
   4.173 +    pvurb = complete_head;
   4.174 +  }
   4.175 +
   4.176    more_to_do = TRUE;
   4.177    KeAcquireSpinLockAtDpcLevel(&xudd->conn_ring_lock);
   4.178    while (more_to_do)
   4.179 @@ -214,21 +287,6 @@ XenUsb_HandleEvent(PVOID context)
   4.180    }
   4.181    KeReleaseSpinLockFromDpcLevel(&xudd->conn_ring_lock);
   4.182  
   4.183 -  shadow = complete_head;
   4.184 -  while (shadow != NULL) {
   4.185 -    complete_head = shadow->next;
   4.186 -    if (shadow->req->buffer_length) {
   4.187 -      int i;
   4.188 -      for (i = 0; i < shadow->req->nr_buffer_segs; i++) {
   4.189 -        xudd->vectors.GntTbl_EndAccess(xudd->vectors.context,
   4.190 -          shadow->req->seg[i].gref, FALSE, (ULONG)'XUSB');
   4.191 -      }
   4.192 -    }
   4.193 -    WdfRequestCompleteWithInformation(shadow->request, (shadow->rsp->status==ECONNRESET)?STATUS_CANCELLED:STATUS_SUCCESS, shadow->total_length); /* the WDFREQUEST is always successfull here even if the shadow->rsp has an error */
   4.194 -    put_shadow_on_freelist(xudd, shadow);
   4.195 -    shadow = complete_head;
   4.196 -  }
   4.197 -
   4.198    if (port_changed) {
   4.199      PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(xudd->root_hub_device);
   4.200      XenUsbHub_ProcessHubInterruptEvent(xupdd->usb_device->configs[0]->interfaces[0]->endpoints[0]);
   4.201 @@ -250,19 +308,21 @@ XenUsb_StartXenbusInit(PXENUSB_DEVICE_DA
   4.202    xudd->event_channel = 0;
   4.203  
   4.204    ptr = xudd->config_page;
   4.205 -  while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
   4.206 -  {
   4.207 -    switch(type)
   4.208 -    {
   4.209 +  while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END) {
   4.210 +    switch(type) {
   4.211      case XEN_INIT_TYPE_READ_STRING_BACK:
   4.212 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_READ_STRING_BACK - %s = %s\n", setting, value));
   4.213 +      break;
   4.214      case XEN_INIT_TYPE_READ_STRING_FRONT:
   4.215 -      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
   4.216 +      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_READ_STRING_FRONT - %s = %s\n", setting, value));
   4.217 +      if (strcmp(setting, "backend-id") == 0) {
   4.218 +        xudd->backend_id = (domid_t)atoi(value);
   4.219 +      }
   4.220        break;
   4.221      case XEN_INIT_TYPE_VECTORS:
   4.222        KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_VECTORS\n"));
   4.223        if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
   4.224 -        ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
   4.225 -      {
   4.226 +        ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC) {
   4.227          KdPrint((__DRIVER_NAME "     vectors mismatch (magic = %08x, length = %d)\n",
   4.228            ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
   4.229          KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
   4.230 @@ -275,12 +335,6 @@ XenUsb_StartXenbusInit(PXENUSB_DEVICE_DA
   4.231        KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
   4.232        xudd->device_state = (PXENPCI_DEVICE_STATE)value;
   4.233        break;
   4.234 -#if 0
   4.235 -    case XEN_INIT_TYPE_GRANT_ENTRIES:
   4.236 -      KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_GRANT_ENTRIES - entries = %d\n", PtrToUlong(setting)));
   4.237 -      memcpy(xudd->dump_grant_refs, value, PtrToUlong(setting) * sizeof(grant_ref_t));
   4.238 -      break;
   4.239 -#endif
   4.240      default:
   4.241        KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_%d\n", type));
   4.242        break;
   4.243 @@ -339,12 +393,9 @@ XenUsb_CompleteXenbusInit(PXENUSB_DEVICE
   4.244      return STATUS_BAD_INITIAL_PC;
   4.245    }
   4.246    
   4.247 -  xudd->shadow_free = 0;
   4.248 -  memset(xudd->shadows, 0, sizeof(usbif_shadow_t) * SHADOW_ENTRIES);
   4.249 -  for (i = 0; i < SHADOW_ENTRIES; i++)
   4.250 -  {
   4.251 -    xudd->shadows[i].id = (uint16_t)i;
   4.252 -    put_shadow_on_freelist(xudd, &xudd->shadows[i]);
   4.253 +  stack_new(&xudd->id_ss, ID_COUNT);
   4.254 +  for (i = 0; i < ID_COUNT; i++)  {
   4.255 +    put_id_on_freelist(xudd, (uint16_t)i);
   4.256    }
   4.257    
   4.258    return STATUS_SUCCESS;
   4.259 @@ -400,6 +451,7 @@ XenUsb_EvtDevicePrepareHardware(WDFDEVIC
   4.260    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "conn-ring-ref", NULL, NULL);
   4.261    #pragma warning(suppress:4054)
   4.262    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL_DPC, "event-channel", (PVOID)XenUsb_HandleEvent, xudd);
   4.263 +  ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_FRONT, "backend-id", NULL, NULL);
   4.264    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
   4.265    __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
   4.266    ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
   4.267 @@ -826,47 +878,63 @@ XenUsb_EvtIoDeviceControl(
   4.268    FUNCTION_EXIT();
   4.269  }
   4.270  
   4.271 -EVT_WDF_REQUEST_CANCEL XenUsb_EvtRequestCancelPvUrb;
   4.272 -
   4.273  VOID
   4.274 -XenUsb_EvtRequestCancelPvUrb(
   4.275 -  WDFREQUEST request)
   4.276 -{
   4.277 +XenUsb_EvtRequestCancelPvUrb(WDFREQUEST request) {
   4.278    WDFDEVICE device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(request));
   4.279    PXENUSB_DEVICE_DATA xudd = GetXudd(device);
   4.280    WDF_REQUEST_PARAMETERS wrp;
   4.281 -  usbif_shadow_t *shadow;
   4.282 +  partial_pvurb_t *partial_pvurb;
   4.283    pvurb_t *pvurb;
   4.284    KIRQL old_irql;
   4.285 -  int notify;
   4.286  
   4.287    FUNCTION_ENTER();
   4.288    FUNCTION_MSG("cancelling request %p\n", request);
   4.289 -  
   4.290 +
   4.291    WDF_REQUEST_PARAMETERS_INIT(&wrp);
   4.292 +  KeAcquireSpinLock(&xudd->urb_ring_lock, &old_irql);
   4.293 +
   4.294    WdfRequestGetParameters(request, &wrp);
   4.295    pvurb = (pvurb_t *)wrp.Parameters.Others.Arg1;
   4.296    FUNCTION_MSG("pvurb = %p\n", pvurb);
   4.297    ASSERT(pvurb);
   4.298 -  // acquire ring lock
   4.299 -  shadow = get_shadow_from_freelist(xudd);
   4.300 -  ASSERT(shadow); /* not sure what to do if we were to run out of shadow entries */
   4.301 -  shadow->request = request;
   4.302 -  shadow->req = &shadow->req_storage;
   4.303 -  *shadow->req = pvurb->req;
   4.304 -  shadow->req->id = shadow->id;
   4.305 -  shadow->req->pipe = usbif_setunlink_pipe(shadow->req->pipe);
   4.306 -  shadow->req->u.unlink.unlink_id = pvurb->req.id;
   4.307 -  KeAcquireSpinLock(&xudd->urb_ring_lock, &old_irql);
   4.308 -  *RING_GET_REQUEST(&xudd->urb_ring, xudd->urb_ring.req_prod_pvt) = *shadow->req;
   4.309 -  xudd->urb_ring.req_prod_pvt++;
   4.310 -  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xudd->urb_ring, notify);
   4.311 -  if (notify) {
   4.312 -    KdPrint((__DRIVER_NAME "     Notifying\n"));
   4.313 -    xudd->vectors.EvtChn_Notify(xudd->vectors.context, xudd->event_channel);
   4.314 +
   4.315 +  partial_pvurb = (partial_pvurb_t *)xudd->partial_pvurb_queue.Flink;
   4.316 +  while (partial_pvurb != (partial_pvurb_t *)&xudd->partial_pvurb_queue) {
   4.317 +    partial_pvurb_t *next_partial_pvurb = (partial_pvurb_t *)partial_pvurb->entry.Flink;
   4.318 +    ASSERT(!partial_pvurb->on_ring);
   4.319 +    FUNCTION_MSG("partial_pvurb = %p is not yet on ring\n", partial_pvurb);
   4.320 +    RemoveEntryList(&partial_pvurb->entry);
   4.321 +    ExFreePoolWithTag(partial_pvurb, XENUSB_POOL_TAG);
   4.322 +    pvurb->ref--;
   4.323 +    partial_pvurb = next_partial_pvurb;
   4.324    }
   4.325 -  KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql);  
   4.326 -  
   4.327 +  partial_pvurb = (partial_pvurb_t *)xudd->partial_pvurb_ring.Flink;
   4.328 +  while (partial_pvurb != (partial_pvurb_t *)&xudd->partial_pvurb_ring) {
   4.329 +    partial_pvurb_t *next_partial_pvurb = (partial_pvurb_t *)partial_pvurb->entry.Flink;
   4.330 +    partial_pvurb_t *partial_pvurb_cancel;
   4.331 +    FUNCTION_MSG("partial_pvurb = %p is on ring\n", partial_pvurb);
   4.332 +    ASSERT(partial_pvurb->on_ring);
   4.333 +    partial_pvurb_cancel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*partial_pvurb_cancel), XENUSB_POOL_TAG); /* todo - use lookaside */
   4.334 +    ASSERT(partial_pvurb_cancel); /* what would we do if this failed? */
   4.335 +    partial_pvurb_cancel->req = partial_pvurb->req;
   4.336 +    partial_pvurb_cancel->req.pipe = usbif_setunlink_pipe(partial_pvurb_cancel->req.pipe);
   4.337 +    partial_pvurb_cancel->req.u.unlink.unlink_id = partial_pvurb->req.id;
   4.338 +    partial_pvurb_cancel->pvurb = pvurb;
   4.339 +    partial_pvurb_cancel->mdl = NULL;
   4.340 +    partial_pvurb_cancel->other_partial_pvurb = partial_pvurb;
   4.341 +    partial_pvurb->other_partial_pvurb = partial_pvurb_cancel;
   4.342 +    partial_pvurb_cancel->on_ring = FALSE;
   4.343 +    pvurb->ref++;
   4.344 +    InsertHeadList(&xudd->partial_pvurb_queue, &partial_pvurb_cancel->entry);
   4.345 +    partial_pvurb = next_partial_pvurb;
   4.346 +  }
   4.347 +  if (pvurb->ref) {
   4.348 +    PutRequestsOnRing(xudd);
   4.349 +    KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql);
   4.350 +  } else {
   4.351 +    KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql);
   4.352 +    WdfRequestComplete(request, STATUS_CANCELLED);
   4.353 +  }
   4.354    FUNCTION_EXIT();
   4.355  }
   4.356  
   4.357 @@ -882,11 +950,9 @@ XenUsb_EvtIoInternalDeviceControl_PVURB(
   4.358    WDFDEVICE device = WdfIoQueueGetDevice(queue);
   4.359    PXENUSB_DEVICE_DATA xudd = GetXudd(device);
   4.360    WDF_REQUEST_PARAMETERS wrp;
   4.361 -  usbif_shadow_t *shadow;
   4.362    pvurb_t *pvurb;
   4.363 +  partial_pvurb_t *partial_pvurb;
   4.364    KIRQL old_irql;
   4.365 -  int i;
   4.366 -  int notify;
   4.367    
   4.368    UNREFERENCED_PARAMETER(input_buffer_length);
   4.369    UNREFERENCED_PARAMETER(output_buffer_length);
   4.370 @@ -899,61 +965,53 @@ XenUsb_EvtIoInternalDeviceControl_PVURB(
   4.371    WDF_REQUEST_PARAMETERS_INIT(&wrp);
   4.372    WdfRequestGetParameters(request, &wrp);
   4.373    pvurb = (pvurb_t *)wrp.Parameters.Others.Arg1;
   4.374 -  FUNCTION_MSG("pvurb = %p\n", pvurb);
   4.375 +  FUNCTION_MSG("A pvurb = %p\n", pvurb);
   4.376    ASSERT(pvurb);
   4.377 -
   4.378 -  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
   4.379 -
   4.380 -  shadow = get_shadow_from_freelist(xudd);
   4.381 -//  FUNCTION_MSG("shadow = %p\n", shadow);
   4.382 -//  FUNCTION_MSG("shadow->id = %p\n", shadow->id);
   4.383 -  ASSERT(shadow);
   4.384 -  shadow->request = request;
   4.385 -  shadow->req = &pvurb->req;
   4.386 -//  FUNCTION_MSG("shadow->req = %p\n", shadow->req);
   4.387 -  shadow->rsp = &pvurb->rsp;
   4.388 -//  FUNCTION_MSG("shadow->rsp = %p\n", shadow->rsp);
   4.389 -  shadow->req->id = shadow->id;
   4.390 -  shadow->mdl = pvurb->mdl;
   4.391 -  shadow->total_length = 0;
   4.392 -  
   4.393 -  if (!shadow->mdl) {
   4.394 -    shadow->req->nr_buffer_segs = 0;
   4.395 -    shadow->req->buffer_length = 0;
   4.396 -  } else {
   4.397 -    ULONG remaining = MmGetMdlByteCount(shadow->mdl);
   4.398 -    USHORT offset = (USHORT)MmGetMdlByteOffset(shadow->mdl);
   4.399 -    shadow->req->buffer_length = (USHORT)MmGetMdlByteCount(shadow->mdl);
   4.400 -    shadow->req->nr_buffer_segs = (USHORT)ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(shadow->mdl), MmGetMdlByteCount(shadow->mdl));
   4.401 -    for (i = 0; i < shadow->req->nr_buffer_segs; i++) {
   4.402 -      shadow->req->seg[i].gref = xudd->vectors.GntTbl_GrantAccess(xudd->vectors.context, 0,
   4.403 -           (ULONG)MmGetMdlPfnArray(shadow->mdl)[i], FALSE, INVALID_GRANT_REF, (ULONG)'XUSB');
   4.404 -      shadow->req->seg[i].offset = (USHORT)offset;
   4.405 -      shadow->req->seg[i].length = (USHORT)min((USHORT)remaining, (USHORT)PAGE_SIZE - offset);
   4.406 -      offset = 0;
   4.407 -      remaining -= shadow->req->seg[i].length;
   4.408 -      KdPrint((__DRIVER_NAME "     seg = %d\n", i));
   4.409 -      KdPrint((__DRIVER_NAME "      gref = %d\n", shadow->req->seg[i].gref));
   4.410 -      KdPrint((__DRIVER_NAME "      offset = %d\n", shadow->req->seg[i].offset));
   4.411 -      KdPrint((__DRIVER_NAME "      length = %d\n", shadow->req->seg[i].length));
   4.412 -    }
   4.413 -    KdPrint((__DRIVER_NAME "     buffer_length = %d\n", shadow->req->buffer_length));
   4.414 -    KdPrint((__DRIVER_NAME "     nr_buffer_segs = %d\n", shadow->req->nr_buffer_segs));
   4.415 +  FUNCTION_MSG("A request = %p\n", pvurb->request);
   4.416 +  RtlZeroMemory(&pvurb->rsp, sizeof(pvurb->rsp));
   4.417 +  pvurb->status = STATUS_SUCCESS;
   4.418 +  pvurb->request = request;
   4.419 +  pvurb->ref = 1;
   4.420 +  pvurb->total_length = 0;
   4.421 +  partial_pvurb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*partial_pvurb), XENUSB_POOL_TAG); /* todo - use lookaside */
   4.422 +  if (!partial_pvurb) {
   4.423 +    WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
   4.424 +    FUNCTION_EXIT();
   4.425 +    return;
   4.426    }
   4.427 -
   4.428    KeAcquireSpinLock(&xudd->urb_ring_lock, &old_irql);
   4.429    status = WdfRequestMarkCancelableEx(request, XenUsb_EvtRequestCancelPvUrb);
   4.430 -  if (status == STATUS_CANCELLED) {
   4.431 -    FUNCTION_MSG("request already cancelled");
   4.432 -    // ...
   4.433 +  partial_pvurb->req = pvurb->req;
   4.434 +  partial_pvurb->mdl = pvurb->mdl; /* 1:1 right now, but may need to split up large pvurb into smaller partial_pvurb's */
   4.435 +  partial_pvurb->pvurb = pvurb;
   4.436 +  partial_pvurb->other_partial_pvurb = NULL;
   4.437 +  partial_pvurb->on_ring = FALSE;
   4.438 +  if (!partial_pvurb->mdl) {
   4.439 +    partial_pvurb->req.nr_buffer_segs = 0;
   4.440 +    partial_pvurb->req.buffer_length = 0;
   4.441 +  } else {
   4.442 +    ULONG remaining = MmGetMdlByteCount(partial_pvurb->mdl);
   4.443 +    USHORT offset = (USHORT)MmGetMdlByteOffset(partial_pvurb->mdl);
   4.444 +    int i;
   4.445 +    partial_pvurb->req.buffer_length = (USHORT)MmGetMdlByteCount(partial_pvurb->mdl);
   4.446 +    partial_pvurb->req.nr_buffer_segs = (USHORT)ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(partial_pvurb->mdl), MmGetMdlByteCount(partial_pvurb->mdl));
   4.447 +    for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) {
   4.448 +      partial_pvurb->req.seg[i].gref = xudd->vectors.GntTbl_GrantAccess(xudd->vectors.context, xudd->backend_id,
   4.449 +           (ULONG)MmGetMdlPfnArray(partial_pvurb->mdl)[i], FALSE, INVALID_GRANT_REF, (ULONG)'XUSB');
   4.450 +      partial_pvurb->req.seg[i].offset = (USHORT)offset;
   4.451 +      partial_pvurb->req.seg[i].length = (USHORT)min((USHORT)remaining, (USHORT)PAGE_SIZE - offset);
   4.452 +      offset = 0;
   4.453 +      remaining -= partial_pvurb->req.seg[i].length;
   4.454 +      KdPrint((__DRIVER_NAME "     seg = %d\n", i));
   4.455 +      KdPrint((__DRIVER_NAME "      gref = %d\n", partial_pvurb->req.seg[i].gref));
   4.456 +      KdPrint((__DRIVER_NAME "      offset = %d\n", partial_pvurb->req.seg[i].offset));
   4.457 +      KdPrint((__DRIVER_NAME "      length = %d\n", partial_pvurb->req.seg[i].length));
   4.458 +    }
   4.459 +    KdPrint((__DRIVER_NAME "     buffer_length = %d\n", partial_pvurb->req.buffer_length));
   4.460 +    KdPrint((__DRIVER_NAME "     nr_buffer_segs = %d\n", partial_pvurb->req.nr_buffer_segs));
   4.461    }
   4.462 -  *RING_GET_REQUEST(&xudd->urb_ring, xudd->urb_ring.req_prod_pvt) = *shadow->req;
   4.463 -  xudd->urb_ring.req_prod_pvt++;
   4.464 -  RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xudd->urb_ring, notify);
   4.465 -  if (notify) {
   4.466 -    KdPrint((__DRIVER_NAME "     Notifying\n"));
   4.467 -    xudd->vectors.EvtChn_Notify(xudd->vectors.context, xudd->event_channel);
   4.468 -  }
   4.469 +  InsertTailList(&xudd->partial_pvurb_queue, &partial_pvurb->entry);
   4.470 +  PutRequestsOnRing(xudd);
   4.471    KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql);  
   4.472    
   4.473    FUNCTION_EXIT();
   4.474 @@ -1105,6 +1163,8 @@ XenUsb_EvtDriverDeviceAdd(WDFDRIVER driv
   4.475  
   4.476    xudd = GetXudd(device);
   4.477    xudd->child_list = WdfFdoGetDefaultChildList(device);
   4.478 +  InitializeListHead(&xudd->partial_pvurb_queue);
   4.479 +  InitializeListHead(&xudd->partial_pvurb_ring);
   4.480  
   4.481    KeInitializeSpinLock(&xudd->urb_ring_lock);
   4.482