simple-mtpfs kernel panic

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

simple-mtpfs kernel panic

Christian Schulte
Hi misc@,

during transferring some files from my laptop to my Android mobile
mounted using simple-mtpfs, the machine rebooted and /var/crash now
contains the following files:

$ ls -h /var/crash/
bounds      bsd.0       bsd.0.core  minfree

I read crash(8) but cannot get any meaningful information from gdb for
me. If someone is interested, I can send those files (amd64). It just
happened once and I cannot reproduce it.

$ dmesg -M /var/crash/bsd.0.core -N /var/crash/bsd.0
ugen2 at uhub0 port 2 "LGE LG-E610v" rev 2.00/2.33 addr 2
fusefs: libfuse vnode reclaim failed
panic: ehci_device_clear_toggle: queue active
Starting stack trace...
panic() at panic+0x10b
ehci_device_clear_toggle() at ehci_device_clear_toggle+0x2b
usbd_clear_endpoint_stall() at usbd_clear_endpoint_stall+0x24
ugen_do_write() at ugen_do_write+0x175
ugenwrite() at ugenwrite+0x48
spec_write() at spec_write+0xbb
VOP_WRITE() at VOP_WRITE+0x3f
vn_write() at vn_write+0x98
dofilewritev() at dofilewritev+0x205
sys_write() at sys_write+0x89
syscall() at syscall+0x2b8
--- syscall (number 4) ---
end of kernel
end trace frame: 0x1, count: 246
0x5c7f4107c9a:
End of stack trace.
syncing disks... 4 done

Regards,
--
Christian

Reply | Threaded
Open this post in threaded view
|

Re: simple-mtpfs kernel panic

Olivier ANTOINE-2
Hi,

Looks like this bug: <https://marc.info/?l=openbsd-bugs&m=147306540522232>

I can also reproduce this with:

$ while true ; do adb shell ls / ; adb kill-server ; done

The code which is triggered in /sys/dev/usb/ehci.c:

ehci_device_clear_toggle(struct usbd_pipe *pipe)
{
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;

#ifdef DIAGNOSTIC
        if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
                panic("ehci_device_clear_toggle: queue active");
#endif
        epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
}

Don't know if it's hardware specific. But I can confirm that it hit me too.

--
Olivier A.

Reply | Threaded
Open this post in threaded view
|

Re: simple-mtpfs kernel panic

Martin Pieuchot
On 01/10/17(Sun) 20:35, Olivier Antoine wrote:

> Hi,
>
> Looks like this bug: <https://marc.info/?l=openbsd-bugs&m=147306540522232>
>
> I can also reproduce this with:
>
> $ while true ; do adb shell ls / ; adb kill-server ; done
>
> The code which is triggered in /sys/dev/usb/ehci.c:
>
> ehci_device_clear_toggle(struct usbd_pipe *pipe)
> {
>         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
>
> #ifdef DIAGNOSTIC
>         if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
>                 panic("ehci_device_clear_toggle: queue active");
> #endif
>         epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
> }
>
> Don't know if it's hardware specific. But I can confirm that it hit me too.

Bug reports without dmesg are useless, see sendbug(1).

Anyway, here's a diff that should fix the problem.  However last I
couldn't narrow down possible regressions.  So make sure everything
works with it, including suspend/resume.

Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.200
diff -u -p -r1.200 ehci.c
--- ehci.c 15 May 2017 10:52:08 -0000 1.200
+++ ehci.c 3 Oct 2017 09:24:08 -0000
@@ -116,6 +116,7 @@ usbd_status ehci_open(struct usbd_pipe *
 int ehci_setaddr(struct usbd_device *, int);
 void ehci_poll(struct usbd_bus *);
 void ehci_softintr(void *);
+int ehci_start(struct ehci_softc *);
 int ehci_intr1(struct ehci_softc *);
 void ehci_check_intr(struct ehci_softc *, struct usbd_xfer *);
 void ehci_check_qh_intr(struct ehci_softc *, struct usbd_xfer *);
@@ -188,12 +189,11 @@ int ehci_alloc_sitd_chain(struct ehci_s
 void ehci_abort_isoc_xfer(struct usbd_xfer *xfer,
     usbd_status status);
 
-usbd_status ehci_device_setintr(struct ehci_softc *, struct ehci_soft_qh *,
-    int ival);
+struct ehci_soft_qh * ehci_intr_get_sqh(struct usbd_pipe *);
 
-void ehci_add_qh(struct ehci_soft_qh *, struct ehci_soft_qh *);
-void ehci_rem_qh(struct ehci_softc *, struct ehci_soft_qh *);
-void ehci_set_qh_qtd(struct ehci_soft_qh *, struct ehci_soft_qtd *);
+void ehci_add_qh(struct usbd_pipe *, struct ehci_soft_qh *,
+    struct ehci_soft_qtd *);
+void ehci_rem_qh(struct ehci_softc *, struct usbd_pipe *);
 void ehci_sync_hc(struct ehci_softc *);
 
 void ehci_close_pipe(struct usbd_pipe *);
@@ -295,7 +295,7 @@ ehci_reverse_bits(u_int8_t c, int nbits)
 usbd_status
 ehci_init(struct ehci_softc *sc)
 {
- u_int32_t sparams, cparams, hcr;
+ uint32_t sparams;
  u_int i, j;
  usbd_status err;
  struct ehci_soft_qh *sqh;
@@ -316,20 +316,8 @@ ehci_init(struct ehci_softc *sc)
  sparams = EREAD4(sc, EHCI_HCSPARAMS);
  DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
  sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
- cparams = EREAD4(sc, EHCI_HCCPARAMS);
- DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
-
- /* MUST clear segment register if 64 bit capable. */
- if (EHCI_HCC_64BIT(cparams))
- EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-
  sc->sc_bus.usbrev = USBREV_2_0;
 
- DPRINTF(("%s: resetting\n", sc->sc_bus.bdev.dv_xname));
- err = ehci_reset(sc);
- if (err)
- return (err);
-
  if (ehcixfer == NULL) {
  ehcixfer = malloc(sizeof(struct pool), M_DEVBUF, M_NOWAIT);
  if (ehcixfer == NULL) {
@@ -365,8 +353,6 @@ ehci_init(struct ehci_softc *sc)
  for (i = 0; i < sc->sc_flsize; i++)
  sc->sc_flist[i] = htole32(EHCI_LINK_TERMINATE);
 
- EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
-
  sc->sc_softitds = mallocarray(sc->sc_flsize,
     sizeof(struct ehci_soft_itd *), M_USB, M_NOWAIT | M_ZERO);
  if (sc->sc_softitds == NULL) {
@@ -412,7 +398,6 @@ ehci_init(struct ehci_softc *sc)
  sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
  sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
  sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
- sqh->sqtd = NULL;
  usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  }
@@ -443,18 +428,47 @@ ehci_init(struct ehci_softc *sc)
  sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
  sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
  sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
- sqh->sqtd = NULL;
  usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
  /* Point to async list */
  sc->sc_async_head = sqh;
- EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
 
  timeout_set(&sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc);
 
  rw_init(&sc->sc_doorbell_lock, "ehcidb");
 
+ return (ehci_start(sc));
+
+#if 0
+ bad2:
+ ehci_free_sqh(sc, sc->sc_async_head);
+#endif
+ bad1:
+ free(sc->sc_softitds, M_USB, sc->sc_flsize);
+ usb_freemem(&sc->sc_bus, &sc->sc_fldma);
+ return (err);
+}
+
+int
+ehci_start(struct ehci_softc *sc)
+{
+ uint32_t hcr, cparams;
+ int error, i;
+
+ error = ehci_reset(sc);
+ if (error)
+ return (error);
+
+ cparams = EREAD4(sc, EHCI_HCCPARAMS);
+ /* MUST clear segment register if 64 bit capable. */
+ if (EHCI_HCC_64BIT(cparams))
+ EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
+
+ EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
+ EOWRITE4(sc, EHCI_ASYNCLISTADDR,
+    sc->sc_async_head->physaddr | EHCI_LINK_QH);
+
  /* Turn on controller */
  EOWRITE4(sc, EHCI_USBCMD,
     EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
@@ -474,23 +488,13 @@ ehci_init(struct ehci_softc *sc)
  }
  if (hcr) {
  printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
- return (USBD_IOERROR);
+ return (EIO);
  }
 
  /* Enable interrupts */
  EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 
- return (USBD_NORMAL_COMPLETION);
-
-#if 0
- bad2:
- ehci_free_sqh(sc, sc->sc_async_head);
-#endif
- bad1:
- free(sc->sc_softitds, M_USB,
-    sc->sc_flsize * sizeof(struct ehci_soft_itd *));
- usb_freemem(&sc->sc_bus, &sc->sc_fldma);
- return (err);
+ return (0);
 }
 
 int
@@ -732,6 +736,7 @@ ehci_check_qh_intr(struct ehci_softc *sc
  return;
  }
  done:
+ ehci_rem_qh(sc, xfer->pipe);
  TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
  timeout_del(&xfer->timeout_handle);
  usb_rem_task(xfer->pipe->device, &xfer->abort_task);
@@ -864,7 +869,7 @@ ehci_idone(struct usbd_xfer *xfer)
 {
  struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
  struct ehci_soft_qtd *sqtd;
- u_int32_t status = 0, nstatus = 0;
+ uint32_t status = 0, nstatus = 0;
  int actlen, cerr;
 
 #ifdef DIAGNOSTIC
@@ -956,7 +961,7 @@ int
 ehci_activate(struct device *self, int act)
 {
  struct ehci_softc *sc = (struct ehci_softc *)self;
- u_int32_t cmd, hcr, cparams;
+ uint32_t cmd, hcr;
  int i, rv = 0;
 
  switch (act) {
@@ -969,6 +974,11 @@ ehci_activate(struct device *self, int a
     sc->sc_bus.bdev.dv_xname);
  return (-1);
  }
+ if (sc->sc_async_head->next != sc->sc_async_head) {
+ printf("%s: asynchronous list not empty\n",
+    sc->sc_bus.bdev.dv_xname);
+ return (-1);
+ }
 #endif
 
  sc->sc_bus.use_polling++;
@@ -1010,16 +1020,9 @@ ehci_activate(struct device *self, int a
  case DVACT_RESUME:
  sc->sc_bus.use_polling++;
 
- ehci_reset(sc);
+ ehci_start(sc);
 
- cparams = EREAD4(sc, EHCI_HCCPARAMS);
- /* MUST clear segment register if 64 bit capable. */
- if (EHCI_HCC_64BIT(cparams))
- EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-
- EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
- EOWRITE4(sc, EHCI_ASYNCLISTADDR,
-      sc->sc_async_head->physaddr | EHCI_LINK_QH);
+ usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
 
  hcr = 0;
  for (i = 1; i <= sc->sc_noport; i++) {
@@ -1041,32 +1044,6 @@ ehci_activate(struct device *self, int a
  }
  }
 
- /* Turn on controller */
- EOWRITE4(sc, EHCI_USBCMD,
-    EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
-    (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
-    EHCI_CMD_ASE |
-    EHCI_CMD_PSE |
-    EHCI_CMD_RS);
-
- /* Take over port ownership */
- EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
- for (i = 0; i < 100; i++) {
- usb_delay_ms(&sc->sc_bus, 1);
- hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
- if (!hcr)
- break;
- }
-
- if (hcr) {
- printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
- /* XXX should we bail here? */
- }
-
- EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
-
- usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
-
  sc->sc_bus.use_polling--;
  rv = config_activate_children(self, act);
  break;
@@ -1150,13 +1127,7 @@ ehci_freex(struct usbd_bus *bus, struct
 void
 ehci_device_clear_toggle(struct usbd_pipe *pipe)
 {
- struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
-
-#ifdef DIAGNOSTIC
- if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
- panic("ehci_device_clear_toggle: queue active");
-#endif
- epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
+ pipe->endpoint->savedtoggle = 0;
 }
 
 #ifdef EHCI_DEBUG
@@ -1353,29 +1324,17 @@ ehci_open(struct usbd_pipe *pipe)
  struct usbd_device *dev = pipe->device;
  struct ehci_softc *sc = (struct ehci_softc *)dev->bus;
  usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
- u_int8_t addr = dev->address;
  u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
  struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
  struct ehci_soft_qh *sqh;
  usbd_status err;
- int s;
- int ival, speed, naks;
- int hshubaddr, hshubport;
 
- DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d\n",
+ DPRINTFN(1, ("%s: pipe=%p, addr=%d, endpt=%d\n", __func__,
     pipe, addr, ed->bEndpointAddress));
 
  if (sc->sc_bus.dying)
  return (USBD_IOERROR);
 
- if (dev->myhsport) {
- hshubaddr = dev->myhsport->parent->address;
- hshubport = dev->myhsport->portno;
- } else {
- hshubaddr = 0;
- hshubport = 0;
- }
-
  /* Root Hub */
  if (pipe->device->depth == 0) {
  switch (ed->bEndpointAddress) {
@@ -1391,59 +1350,11 @@ ehci_open(struct usbd_pipe *pipe)
  return (USBD_NORMAL_COMPLETION);
  }
 
- /* XXX All this stuff is only valid for async. */
- switch (dev->speed) {
- case USB_SPEED_LOW:
- speed = EHCI_QH_SPEED_LOW;
- break;
- case USB_SPEED_FULL:
- speed = EHCI_QH_SPEED_FULL;
- break;
- case USB_SPEED_HIGH:
- speed = EHCI_QH_SPEED_HIGH;
- break;
- default:
- panic("ehci_open: bad device speed %d", dev->speed);
- }
-
- naks = 8; /* XXX */
-
  /* Allocate sqh for everything, save isoc xfers */
  if (xfertype != UE_ISOCHRONOUS) {
  sqh = ehci_alloc_sqh(sc);
  if (sqh == NULL)
  return (USBD_NOMEM);
- /* qh_link filled when the QH is added */
- sqh->qh.qh_endp = htole32(
-    EHCI_QH_SET_ADDR(addr) |
-    EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
-    EHCI_QH_SET_EPS(speed) |
-    (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
-    EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
-    (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
-    EHCI_QH_CTL : 0) |
-    EHCI_QH_SET_NRL(naks)
- );
- sqh->qh.qh_endphub = htole32(
-    EHCI_QH_SET_MULT(1) |
-    EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
- );
- if (speed != EHCI_QH_SPEED_HIGH) {
- sqh->qh.qh_endphub |= htole32(
-    EHCI_QH_SET_HUBA(hshubaddr) |
-    EHCI_QH_SET_PORT(hshubport) |
-    EHCI_QH_SET_CMASK(0x1c) /* XXX */
- );
- }
- sqh->qh.qh_curqtd = htole32(EHCI_LINK_TERMINATE);
- /* Fill the overlay qTD */
- sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
- sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
- sqh->qh.qh_qtd.qtd_status =
-    htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
-
- usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  epipe->sqh = sqh;
  } /*xfertype == UE_ISOC*/
 
@@ -1456,32 +1367,20 @@ ehci_open(struct usbd_pipe *pipe)
  return (err);
  }
  pipe->methods = &ehci_device_ctrl_methods;
- s = splusb();
- ehci_add_qh(sqh, sc->sc_async_head);
- splx(s);
  break;
  case UE_BULK:
  pipe->methods = &ehci_device_bulk_methods;
- s = splusb();
- ehci_add_qh(sqh, sc->sc_async_head);
- splx(s);
  break;
  case UE_INTERRUPT:
  pipe->methods = &ehci_device_intr_methods;
- ival = pipe->interval;
- if (ival == USBD_DEFAULT_INTERVAL)
- ival = ed->bInterval;
- s = splusb();
- err = ehci_device_setintr(sc, sqh, ival);
- splx(s);
- return (err);
+ break;
  case UE_ISOCHRONOUS:
- switch (speed) {
- case EHCI_QH_SPEED_HIGH:
- case EHCI_QH_SPEED_FULL:
+ switch (pipe->device->speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
  pipe->methods = &ehci_device_isoc_methods;
  break;
- case EHCI_QH_SPEED_LOW:
+ case USB_SPEED_LOW:
  default:
  return (USBD_INVAL);
  }
@@ -1504,16 +1403,92 @@ ehci_open(struct usbd_pipe *pipe)
  return (USBD_NORMAL_COMPLETION);
 }
 
-/*
- * Add an ED to the schedule.  Called at splusb().
- * If in the async schedule, it will always have a next.
- * If in the intr schedule it may not.
- */
 void
-ehci_add_qh(struct ehci_soft_qh *sqh, struct ehci_soft_qh *head)
+ehci_add_qh(struct usbd_pipe *pipe, struct ehci_soft_qh *head,
+    struct ehci_soft_qtd *start)
 {
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+ struct ehci_soft_qh *sqh = epipe->sqh;
+ usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+ uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
+ uint8_t addr = pipe->device->address;
+ int i, hshubaddr, hshubport, speed;
+ int naks = 8; /* XXX */
+
+ KASSERT(xfertype != UE_ISOCHRONOUS);
+
  splsoftassert(IPL_SOFTUSB);
 
+ if (pipe->device->myhsport) {
+ hshubaddr = pipe->device->myhsport->parent->address;
+ hshubport = pipe->device->myhsport->portno;
+ } else {
+ hshubaddr = 0;
+ hshubport = 0;
+ }
+
+ /* XXX All this stuff is only valid for async. */
+ switch (pipe->device->speed) {
+ case USB_SPEED_LOW:
+ speed = EHCI_QH_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ speed = EHCI_QH_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ speed = EHCI_QH_SPEED_HIGH;
+ break;
+ default:
+ panic("%s: bad device speed %d", __func__, pipe->device->speed);
+ }
+
+ /* qh_link is filled below */
+ sqh->qh.qh_endp = htole32(
+    EHCI_QH_SET_ADDR(addr) |
+    EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
+    EHCI_QH_SET_EPS(speed) |
+    (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
+    EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
+    (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
+    EHCI_QH_CTL : 0) |
+    EHCI_QH_SET_NRL(naks)
+    );
+ sqh->qh.qh_endphub = htole32(
+    EHCI_QH_SET_MULT(1) |
+    EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
+ );
+ if (speed != EHCI_QH_SPEED_HIGH) {
+ sqh->qh.qh_endphub |= htole32(
+    EHCI_QH_SET_HUBA(hshubaddr) |
+    EHCI_QH_SET_PORT(hshubport) |
+    EHCI_QH_SET_CMASK(0x1c) /* XXX */
+ );
+ }
+ sqh->qh.qh_curqtd = 0;
+
+ sqh->qh.qh_qtd.qtd_next = htole32(start->physaddr);
+ sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+ if (xfertype == UE_CONTROL)
+ sqh->qh.qh_qtd.qtd_status = 0;
+ else
+ sqh->qh.qh_qtd.qtd_status =
+    htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
+
+ /* Reset reserved fields */
+ for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
+ sqh->qh.qh_qtd.qtd_buffer[i] = 0;
+ sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
+ }
+ usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ /*
+ * Add an ED to the schedule.
+ *
+ * If in the async schedule, it will always have a next.
+ * If in the intr schedule it may not.
+ */
+
  usb_syncmem(&head->dma, head->offs + offsetof(struct ehci_qh, qh_link),
     sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE);
  sqh->next = head->next;
@@ -1534,10 +1509,13 @@ ehci_add_qh(struct ehci_soft_qh *sqh, st
  * Will always have a 'next' if it's in the async list as it's circular.
  */
 void
-ehci_rem_qh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
+ehci_rem_qh(struct ehci_softc *sc, struct usbd_pipe *pipe)
 {
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+ struct ehci_soft_qh *sqh = epipe->sqh;
+
  splsoftassert(IPL_SOFTUSB);
- /* XXX */
+
  usb_syncmem(&sqh->dma, sqh->offs + offsetof(struct ehci_qh, qh_link),
     sizeof(sqh->qh.qh_link), BUS_DMASYNC_POSTWRITE);
  sqh->prev->qh.qh_link = sqh->qh.qh_link;
@@ -1548,42 +1526,8 @@ ehci_rem_qh(struct ehci_softc *sc, struc
     sqh->prev->offs + offsetof(struct ehci_qh, qh_link),
     sizeof(sqh->prev->qh.qh_link), BUS_DMASYNC_PREWRITE);
 
- ehci_sync_hc(sc);
-}
-
-void
-ehci_set_qh_qtd(struct ehci_soft_qh *sqh, struct ehci_soft_qtd *sqtd)
-{
- int i;
- u_int32_t status;
-
- /* Save toggle bit and ping status. */
- usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
- status = sqh->qh.qh_qtd.qtd_status &
-    htole32(EHCI_QTD_TOGGLE_MASK |
- EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));
- /* Set HALTED to make hw leave it alone. */
- sqh->qh.qh_qtd.qtd_status =
-    htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));
- usb_syncmem(&sqh->dma,
-    sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-    sizeof(sqh->qh.qh_qtd.qtd_status),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- sqh->qh.qh_curqtd = 0;
- sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
- sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
- for (i = 0; i < EHCI_QTD_NBUFFERS; i++)
- sqh->qh.qh_qtd.qtd_buffer[i] = 0;
- sqh->sqtd = sqtd;
- usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- /* Set !HALTED && !ACTIVE to start execution, preserve some fields */
- sqh->qh.qh_qtd.qtd_status = status;
- usb_syncmem(&sqh->dma,
-    sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-    sizeof(sqh->qh.qh_qtd.qtd_status),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+ pipe->endpoint->savedtoggle =
+    EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
 }
 
 /*
@@ -2471,7 +2415,6 @@ ehci_alloc_sqtd_chain(struct ehci_softc
 void
 ehci_free_sqtd_chain(struct ehci_softc *sc, struct ehci_xfer *ex)
 {
- struct ehci_pipe *epipe = (struct ehci_pipe *)ex->xfer.pipe;
  struct ehci_soft_qtd *sqtd, *next;
 
  DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p\n", ex->sqtdstart));
@@ -2481,7 +2424,6 @@ ehci_free_sqtd_chain(struct ehci_softc *
  ehci_free_sqtd(sc, sqtd);
  }
  ex->sqtdstart = ex->sqtdend = NULL;
- epipe->sqh->sqtd = NULL;
 }
 
 struct ehci_soft_itd *
@@ -2565,14 +2507,7 @@ ehci_close_pipe(struct usbd_pipe *pipe)
 {
  struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
  struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
- struct ehci_soft_qh *sqh = epipe->sqh;
- int s;
 
- s = splusb();
- ehci_rem_qh(sc, sqh);
- splx(s);
- pipe->endpoint->savedtoggle =
-    EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
  ehci_free_sqh(sc, epipe->sqh);
 }
 
@@ -2590,16 +2525,15 @@ void
 ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
 {
  struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
- struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
  struct ehci_xfer *ex = (struct ehci_xfer*)xfer;
- struct ehci_soft_qh *sqh = epipe->sqh;
- struct ehci_soft_qtd *sqtd;
  int s;
 
  if (sc->sc_bus.dying || xfer->status == USBD_NOT_STARTED) {
  s = splusb();
- if (xfer->status != USBD_NOT_STARTED)
+ if (xfer->status != USBD_NOT_STARTED) {
+ ehci_rem_qh(sc, xfer->pipe);
  TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
+ }
  xfer->status = status; /* make software ignore it */
  timeout_del(&xfer->timeout_handle);
  usb_rem_task(xfer->device, &xfer->abort_task);
@@ -2632,51 +2566,21 @@ ehci_abort_xfer(struct usbd_xfer *xfer,
  return;
  }
 
- /*
- * Step 1: Make interrupt routine and timeouts ignore xfer.
- */
  s = splusb();
  ex->ehci_xfer_flags |= EHCI_XFER_ABORTING;
- xfer->status = status; /* make software ignore it */
+
+ /* Remove the Queue Head. */
+ ehci_rem_qh(sc, xfer->pipe);
  TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
+
+ xfer->status = status; /* make software ignore it */
  timeout_del(&xfer->timeout_handle);
  usb_rem_task(xfer->device, &xfer->abort_task);
- splx(s);
 
  /*
- * Step 2: Deactivate all of the qTDs that we will be removing,
- * otherwise the queue head may go active again.
- */
- usb_syncmem(&sqh->dma,
-    sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-    sizeof(sqh->qh.qh_qtd.qtd_status),
-    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
- sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
- usb_syncmem(&sqh->dma,
-    sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-    sizeof(sqh->qh.qh_qtd.qtd_status),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
- for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
- usb_syncmem(&sqtd->dma,
-    sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-    sizeof(sqtd->qtd.qtd_status),
-    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
- sqtd->qtd.qtd_status = htole32(EHCI_QTD_HALTED);
- usb_syncmem(&sqtd->dma,
-    sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-    sizeof(sqtd->qtd.qtd_status),
-    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- }
- ehci_sync_hc(sc);
-
- /*
- * Step 3: Make sure the soft interrupt routine has run. This
+ * Make sure the soft interrupt routine has run. This
  * should remove any completed items off the queue.
- * The hardware has no reference to completed items (TDs).
- * It's safe to remove them at any time.
  */
- s = splusb();
  sc->sc_softwake = 1;
  usb_schedsoftintr(&sc->sc_bus);
  tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
@@ -2849,7 +2753,6 @@ ehci_device_ctrl_start(struct usbd_xfer
  struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
  usb_device_request_t *req = &xfer->request;
  struct ehci_soft_qtd *setup, *stat, *next;
- struct ehci_soft_qh *sqh;
  u_int len = UGETW(req->wLength);
  usbd_status err;
  int s;
@@ -2870,8 +2773,6 @@ ehci_device_ctrl_start(struct usbd_xfer
  goto bad2;
  }
 
- sqh = epipe->sqh;
-
  /* Set up data transaction */
  if (len != 0) {
  struct ehci_soft_qtd *end;
@@ -2931,14 +2832,13 @@ ehci_device_ctrl_start(struct usbd_xfer
  ex->isdone = 0;
 #endif
 
- /* Insert qTD in QH list. */
  s = splusb();
- ehci_set_qh_qtd(sqh, setup);
  if (xfer->timeout && !sc->sc_bus.use_polling) {
  timeout_del(&xfer->timeout_handle);
  timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
  timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
  }
+ ehci_add_qh(xfer->pipe, sc->sc_async_head, setup);
  TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
  xfer->status = USBD_IN_PROGRESS;
  splx(s);
@@ -2998,10 +2898,8 @@ usbd_status
 ehci_device_bulk_start(struct usbd_xfer *xfer)
 {
  struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
- struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
  struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
  struct ehci_soft_qtd *data, *dataend;
- struct ehci_soft_qh *sqh;
  usbd_status err;
  int s;
 
@@ -3010,8 +2908,6 @@ ehci_device_bulk_start(struct usbd_xfer
  if (sc->sc_bus.dying)
  return (USBD_IOERROR);
 
- sqh = epipe->sqh;
-
  err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
  if (err) {
  xfer->status = err;
@@ -3030,12 +2926,12 @@ ehci_device_bulk_start(struct usbd_xfer
 #endif
 
  s = splusb();
- ehci_set_qh_qtd(sqh, data);
  if (xfer->timeout && !sc->sc_bus.use_polling) {
  timeout_del(&xfer->timeout_handle);
  timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
  timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
  }
+ ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
  TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
  xfer->status = USBD_IN_PROGRESS;
  splx(s);
@@ -3069,12 +2965,18 @@ ehci_device_bulk_done(struct usbd_xfer *
  }
 }
 
-usbd_status
-ehci_device_setintr(struct ehci_softc *sc, struct ehci_soft_qh *sqh, int ival)
+struct ehci_soft_qh *
+ehci_intr_get_sqh(struct usbd_pipe *pipe)
 {
+ struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
+ struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
  struct ehci_soft_islot *isp;
+ int ival = pipe->interval;
  int islot, lev;
 
+ if (ival == USBD_DEFAULT_INTERVAL)
+ ival = pipe->endpoint->edesc->bInterval;
+
  /* Find a poll rate that is large enough. */
  for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--)
  if (EHCI_ILEV_IVAL(lev) <= ival)
@@ -3084,11 +2986,10 @@ ehci_device_setintr(struct ehci_softc *s
  /* XXX could do better than picking at random */
  islot = EHCI_IQHIDX(lev, arc4random());
 
- sqh->islot = islot;
+ epipe->sqh->islot = islot;
  isp = &sc->sc_islots[islot];
- ehci_add_qh(sqh, isp->sqh);
 
- return (USBD_NORMAL_COMPLETION);
+ return (isp->sqh);
 }
 
 usbd_status
@@ -3113,9 +3014,7 @@ ehci_device_intr_start(struct usbd_xfer
 {
  struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
  struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
- struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
  struct ehci_soft_qtd *data, *dataend;
- struct ehci_soft_qh *sqh;
  usbd_status err;
  int s;
 
@@ -3124,8 +3023,6 @@ ehci_device_intr_start(struct usbd_xfer
  if (sc->sc_bus.dying)
  return (USBD_IOERROR);
 
- sqh = epipe->sqh;
-
  err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
  if (err) {
  xfer->status = err;
@@ -3143,12 +3040,12 @@ ehci_device_intr_start(struct usbd_xfer
 #endif
 
  s = splusb();
- ehci_set_qh_qtd(sqh, data);
  if (xfer->timeout && !sc->sc_bus.use_polling) {
  timeout_del(&xfer->timeout_handle);
  timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
  timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
  }
+ ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
  TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
  xfer->status = USBD_IN_PROGRESS;
  splx(s);
@@ -3179,48 +3076,15 @@ void
 ehci_device_intr_done(struct usbd_xfer *xfer)
 {
  struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
- struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
  struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
- struct ehci_soft_qtd *data, *dataend;
- struct ehci_soft_qh *sqh;
- usbd_status err;
- int s;
 
  if (xfer->pipe->repeat) {
  ehci_free_sqtd_chain(sc, ex);
-
  usb_syncmem(&xfer->dmabuf, 0, xfer->length,
     usbd_xfer_isread(xfer) ?
     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
- sqh = epipe->sqh;
-
- err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
- if (err) {
- xfer->status = err;
- return;
- }
 
- /* Set up interrupt info. */
- ex->sqtdstart = data;
- ex->sqtdend = dataend;
-#ifdef DIAGNOSTIC
- if (!ex->isdone) {
- printf("ehci_device_intr_done: not done, ex=%p\n",
- ex);
- }
- ex->isdone = 0;
-#endif
-
- s = splusb();
- ehci_set_qh_qtd(sqh, data);
- if (xfer->timeout && !sc->sc_bus.use_polling) {
- timeout_del(&xfer->timeout_handle);
- timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
- timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
- }
- TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
- xfer->status = USBD_IN_PROGRESS;
- splx(s);
+ ehci_device_intr_start(xfer);
  } else if (xfer->status != USBD_NOMEM) {
  ehci_free_sqtd_chain(sc, ex);
  }
Index: ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.37
diff -u -p -r1.37 ehcivar.h
--- ehcivar.h 2 Oct 2016 06:36:39 -0000 1.37
+++ ehcivar.h 3 Oct 2017 09:24:08 -0000
@@ -46,7 +46,6 @@ struct ehci_soft_qh {
  struct ehci_qh qh;
  struct ehci_soft_qh *next;
  struct ehci_soft_qh *prev;
- struct ehci_soft_qtd *sqtd;
  ehci_physaddr_t physaddr;
  struct usb_dma dma;             /* QH's DMA infos */
  int offs;                       /* QH's offset in struct usb_dma */

Reply | Threaded
Open this post in threaded view
|

Re: simple-mtpfs kernel panic

Olivier ANTOINE-2
Hi,

I tested this patch. From what I've seen, it works perfectly.
After suspend / resume, I did not notice any problem.

Thanks for the resolution of this bug.



On Tue, Oct 3, 2017 at 11:27 AM, Martin Pieuchot <[hidden email]> wrote:

> On 01/10/17(Sun) 20:35, Olivier Antoine wrote:
>> Hi,
>>
>> Looks like this bug: <https://marc.info/?l=openbsd-bugs&m=147306540522232>
>>
>> I can also reproduce this with:
>>
>> $ while true ; do adb shell ls / ; adb kill-server ; done
>>
>> The code which is triggered in /sys/dev/usb/ehci.c:
>>
>> ehci_device_clear_toggle(struct usbd_pipe *pipe)
>> {
>>         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
>>
>> #ifdef DIAGNOSTIC
>>         if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
>>                 panic("ehci_device_clear_toggle: queue active");
>> #endif
>>         epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
>> }
>>
>> Don't know if it's hardware specific. But I can confirm that it hit me too.
>
> Bug reports without dmesg are useless, see sendbug(1).
>
> Anyway, here's a diff that should fix the problem.  However last I
> couldn't narrow down possible regressions.  So make sure everything
> works with it, including suspend/resume.
>
> Index: ehci.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/ehci.c,v
> retrieving revision 1.200
> diff -u -p -r1.200 ehci.c
> --- ehci.c      15 May 2017 10:52:08 -0000      1.200
> +++ ehci.c      3 Oct 2017 09:24:08 -0000
> @@ -116,6 +116,7 @@ usbd_status ehci_open(struct usbd_pipe *
>  int            ehci_setaddr(struct usbd_device *, int);
>  void           ehci_poll(struct usbd_bus *);
>  void           ehci_softintr(void *);
> +int            ehci_start(struct ehci_softc *);
>  int            ehci_intr1(struct ehci_softc *);
>  void           ehci_check_intr(struct ehci_softc *, struct usbd_xfer *);
>  void           ehci_check_qh_intr(struct ehci_softc *, struct usbd_xfer *);
> @@ -188,12 +189,11 @@ int               ehci_alloc_sitd_chain(struct ehci_s
>  void           ehci_abort_isoc_xfer(struct usbd_xfer *xfer,
>                     usbd_status status);
>
> -usbd_status    ehci_device_setintr(struct ehci_softc *, struct ehci_soft_qh *,
> -                           int ival);
> +struct ehci_soft_qh * ehci_intr_get_sqh(struct usbd_pipe *);
>
> -void           ehci_add_qh(struct ehci_soft_qh *, struct ehci_soft_qh *);
> -void           ehci_rem_qh(struct ehci_softc *, struct ehci_soft_qh *);
> -void           ehci_set_qh_qtd(struct ehci_soft_qh *, struct ehci_soft_qtd *);
> +void           ehci_add_qh(struct usbd_pipe *, struct ehci_soft_qh *,
> +                   struct ehci_soft_qtd *);
> +void           ehci_rem_qh(struct ehci_softc *, struct usbd_pipe *);
>  void           ehci_sync_hc(struct ehci_softc *);
>
>  void           ehci_close_pipe(struct usbd_pipe *);
> @@ -295,7 +295,7 @@ ehci_reverse_bits(u_int8_t c, int nbits)
>  usbd_status
>  ehci_init(struct ehci_softc *sc)
>  {
> -       u_int32_t sparams, cparams, hcr;
> +       uint32_t sparams;
>         u_int i, j;
>         usbd_status err;
>         struct ehci_soft_qh *sqh;
> @@ -316,20 +316,8 @@ ehci_init(struct ehci_softc *sc)
>         sparams = EREAD4(sc, EHCI_HCSPARAMS);
>         DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
>         sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
> -       cparams = EREAD4(sc, EHCI_HCCPARAMS);
> -       DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
> -
> -       /* MUST clear segment register if 64 bit capable. */
> -       if (EHCI_HCC_64BIT(cparams))
> -               EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
> -
>         sc->sc_bus.usbrev = USBREV_2_0;
>
> -       DPRINTF(("%s: resetting\n", sc->sc_bus.bdev.dv_xname));
> -       err = ehci_reset(sc);
> -       if (err)
> -               return (err);
> -
>         if (ehcixfer == NULL) {
>                 ehcixfer = malloc(sizeof(struct pool), M_DEVBUF, M_NOWAIT);
>                 if (ehcixfer == NULL) {
> @@ -365,8 +353,6 @@ ehci_init(struct ehci_softc *sc)
>         for (i = 0; i < sc->sc_flsize; i++)
>                 sc->sc_flist[i] = htole32(EHCI_LINK_TERMINATE);
>
> -       EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
> -
>         sc->sc_softitds = mallocarray(sc->sc_flsize,
>             sizeof(struct ehci_soft_itd *), M_USB, M_NOWAIT | M_ZERO);
>         if (sc->sc_softitds == NULL) {
> @@ -412,7 +398,6 @@ ehci_init(struct ehci_softc *sc)
>                 sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
>                 sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
>                 sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
> -               sqh->sqtd = NULL;
>                 usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
>                     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
>         }
> @@ -443,18 +428,47 @@ ehci_init(struct ehci_softc *sc)
>         sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
>         sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
>         sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
> -       sqh->sqtd = NULL;
>         usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
>             BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
>
>         /* Point to async list */
>         sc->sc_async_head = sqh;
> -       EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
>
>         timeout_set(&sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc);
>
>         rw_init(&sc->sc_doorbell_lock, "ehcidb");
>
> +       return (ehci_start(sc));
> +
> +#if 0
> + bad2:
> +       ehci_free_sqh(sc, sc->sc_async_head);
> +#endif
> + bad1:
> +       free(sc->sc_softitds, M_USB, sc->sc_flsize);
> +       usb_freemem(&sc->sc_bus, &sc->sc_fldma);
> +       return (err);
> +}
> +
> +int
> +ehci_start(struct ehci_softc *sc)
> +{
> +       uint32_t hcr, cparams;
> +       int error, i;
> +
> +       error = ehci_reset(sc);
> +       if (error)
> +               return (error);
> +
> +       cparams = EREAD4(sc, EHCI_HCCPARAMS);
> +       /* MUST clear segment register if 64 bit capable. */
> +       if (EHCI_HCC_64BIT(cparams))
> +               EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
> +
> +       EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
> +       EOWRITE4(sc, EHCI_ASYNCLISTADDR,
> +           sc->sc_async_head->physaddr | EHCI_LINK_QH);
> +
>         /* Turn on controller */
>         EOWRITE4(sc, EHCI_USBCMD,
>             EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
> @@ -474,23 +488,13 @@ ehci_init(struct ehci_softc *sc)
>         }
>         if (hcr) {
>                 printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
> -               return (USBD_IOERROR);
> +               return (EIO);
>         }
>
>         /* Enable interrupts */
>         EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
>
> -       return (USBD_NORMAL_COMPLETION);
> -
> -#if 0
> - bad2:
> -       ehci_free_sqh(sc, sc->sc_async_head);
> -#endif
> - bad1:
> -       free(sc->sc_softitds, M_USB,
> -           sc->sc_flsize * sizeof(struct ehci_soft_itd *));
> -       usb_freemem(&sc->sc_bus, &sc->sc_fldma);
> -       return (err);
> +       return (0);
>  }
>
>  int
> @@ -732,6 +736,7 @@ ehci_check_qh_intr(struct ehci_softc *sc
>                 return;
>         }
>   done:
> +       ehci_rem_qh(sc, xfer->pipe);
>         TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
>         timeout_del(&xfer->timeout_handle);
>         usb_rem_task(xfer->pipe->device, &xfer->abort_task);
> @@ -864,7 +869,7 @@ ehci_idone(struct usbd_xfer *xfer)
>  {
>         struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
>         struct ehci_soft_qtd *sqtd;
> -       u_int32_t status = 0, nstatus = 0;
> +       uint32_t status = 0, nstatus = 0;
>         int actlen, cerr;
>
>  #ifdef DIAGNOSTIC
> @@ -956,7 +961,7 @@ int
>  ehci_activate(struct device *self, int act)
>  {
>         struct ehci_softc *sc = (struct ehci_softc *)self;
> -       u_int32_t cmd, hcr, cparams;
> +       uint32_t cmd, hcr;
>         int i, rv = 0;
>
>         switch (act) {
> @@ -969,6 +974,11 @@ ehci_activate(struct device *self, int a
>                             sc->sc_bus.bdev.dv_xname);
>                         return (-1);
>                 }
> +               if (sc->sc_async_head->next != sc->sc_async_head) {
> +                       printf("%s: asynchronous list not empty\n",
> +                           sc->sc_bus.bdev.dv_xname);
> +                       return (-1);
> +               }
>  #endif
>
>                 sc->sc_bus.use_polling++;
> @@ -1010,16 +1020,9 @@ ehci_activate(struct device *self, int a
>         case DVACT_RESUME:
>                 sc->sc_bus.use_polling++;
>
> -               ehci_reset(sc);
> +               ehci_start(sc);
>
> -               cparams = EREAD4(sc, EHCI_HCCPARAMS);
> -               /* MUST clear segment register if 64 bit capable. */
> -               if (EHCI_HCC_64BIT(cparams))
> -                       EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
> -
> -               EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
> -               EOWRITE4(sc, EHCI_ASYNCLISTADDR,
> -                   sc->sc_async_head->physaddr | EHCI_LINK_QH);
> +               usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
>
>                 hcr = 0;
>                 for (i = 1; i <= sc->sc_noport; i++) {
> @@ -1041,32 +1044,6 @@ ehci_activate(struct device *self, int a
>                         }
>                 }
>
> -               /* Turn on controller */
> -               EOWRITE4(sc, EHCI_USBCMD,
> -                   EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
> -                   (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
> -                   EHCI_CMD_ASE |
> -                   EHCI_CMD_PSE |
> -                   EHCI_CMD_RS);
> -
> -               /* Take over port ownership */
> -               EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
> -               for (i = 0; i < 100; i++) {
> -                       usb_delay_ms(&sc->sc_bus, 1);
> -                       hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
> -                       if (!hcr)
> -                               break;
> -               }
> -
> -               if (hcr) {
> -                       printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
> -                       /* XXX should we bail here? */
> -               }
> -
> -               EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
> -
> -               usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
> -
>                 sc->sc_bus.use_polling--;
>                 rv = config_activate_children(self, act);
>                 break;
> @@ -1150,13 +1127,7 @@ ehci_freex(struct usbd_bus *bus, struct
>  void
>  ehci_device_clear_toggle(struct usbd_pipe *pipe)
>  {
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
> -
> -#ifdef DIAGNOSTIC
> -       if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
> -               panic("ehci_device_clear_toggle: queue active");
> -#endif
> -       epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
> +       pipe->endpoint->savedtoggle = 0;
>  }
>
>  #ifdef EHCI_DEBUG
> @@ -1353,29 +1324,17 @@ ehci_open(struct usbd_pipe *pipe)
>         struct usbd_device *dev = pipe->device;
>         struct ehci_softc *sc = (struct ehci_softc *)dev->bus;
>         usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
> -       u_int8_t addr = dev->address;
>         u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
>         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
>         struct ehci_soft_qh *sqh;
>         usbd_status err;
> -       int s;
> -       int ival, speed, naks;
> -       int hshubaddr, hshubport;
>
> -       DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d\n",
> +       DPRINTFN(1, ("%s: pipe=%p, addr=%d, endpt=%d\n", __func__,
>             pipe, addr, ed->bEndpointAddress));
>
>         if (sc->sc_bus.dying)
>                 return (USBD_IOERROR);
>
> -       if (dev->myhsport) {
> -               hshubaddr = dev->myhsport->parent->address;
> -               hshubport = dev->myhsport->portno;
> -       } else {
> -               hshubaddr = 0;
> -               hshubport = 0;
> -       }
> -
>         /* Root Hub */
>         if (pipe->device->depth == 0) {
>                 switch (ed->bEndpointAddress) {
> @@ -1391,59 +1350,11 @@ ehci_open(struct usbd_pipe *pipe)
>                 return (USBD_NORMAL_COMPLETION);
>         }
>
> -       /* XXX All this stuff is only valid for async. */
> -       switch (dev->speed) {
> -       case USB_SPEED_LOW:
> -               speed = EHCI_QH_SPEED_LOW;
> -               break;
> -       case USB_SPEED_FULL:
> -               speed = EHCI_QH_SPEED_FULL;
> -               break;
> -       case USB_SPEED_HIGH:
> -               speed = EHCI_QH_SPEED_HIGH;
> -               break;
> -       default:
> -               panic("ehci_open: bad device speed %d", dev->speed);
> -       }
> -
> -       naks = 8;               /* XXX */
> -
>         /* Allocate sqh for everything, save isoc xfers */
>         if (xfertype != UE_ISOCHRONOUS) {
>                 sqh = ehci_alloc_sqh(sc);
>                 if (sqh == NULL)
>                         return (USBD_NOMEM);
> -               /* qh_link filled when the QH is added */
> -               sqh->qh.qh_endp = htole32(
> -                   EHCI_QH_SET_ADDR(addr) |
> -                   EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
> -                   EHCI_QH_SET_EPS(speed) |
> -                   (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
> -                   EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
> -                   (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
> -                   EHCI_QH_CTL : 0) |
> -                   EHCI_QH_SET_NRL(naks)
> -               );
> -               sqh->qh.qh_endphub = htole32(
> -                   EHCI_QH_SET_MULT(1) |
> -                   EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
> -               );
> -               if (speed != EHCI_QH_SPEED_HIGH) {
> -                       sqh->qh.qh_endphub |= htole32(
> -                           EHCI_QH_SET_HUBA(hshubaddr) |
> -                           EHCI_QH_SET_PORT(hshubport) |
> -                           EHCI_QH_SET_CMASK(0x1c) /* XXX */
> -                       );
> -               }
> -               sqh->qh.qh_curqtd = htole32(EHCI_LINK_TERMINATE);
> -               /* Fill the overlay qTD */
> -               sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
> -               sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
> -               sqh->qh.qh_qtd.qtd_status =
> -                   htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
> -
> -               usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
> -                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
>                 epipe->sqh = sqh;
>         } /*xfertype == UE_ISOC*/
>
> @@ -1456,32 +1367,20 @@ ehci_open(struct usbd_pipe *pipe)
>                         return (err);
>                 }
>                 pipe->methods = &ehci_device_ctrl_methods;
> -               s = splusb();
> -               ehci_add_qh(sqh, sc->sc_async_head);
> -               splx(s);
>                 break;
>         case UE_BULK:
>                 pipe->methods = &ehci_device_bulk_methods;
> -               s = splusb();
> -               ehci_add_qh(sqh, sc->sc_async_head);
> -               splx(s);
>                 break;
>         case UE_INTERRUPT:
>                 pipe->methods = &ehci_device_intr_methods;
> -               ival = pipe->interval;
> -               if (ival == USBD_DEFAULT_INTERVAL)
> -                       ival = ed->bInterval;
> -               s = splusb();
> -               err = ehci_device_setintr(sc, sqh, ival);
> -               splx(s);
> -               return (err);
> +               break;
>         case UE_ISOCHRONOUS:
> -               switch (speed) {
> -               case EHCI_QH_SPEED_HIGH:
> -               case EHCI_QH_SPEED_FULL:
> +               switch (pipe->device->speed) {
> +               case USB_SPEED_HIGH:
> +               case USB_SPEED_FULL:
>                         pipe->methods = &ehci_device_isoc_methods;
>                         break;
> -               case EHCI_QH_SPEED_LOW:
> +               case USB_SPEED_LOW:
>                 default:
>                         return (USBD_INVAL);
>                 }
> @@ -1504,16 +1403,92 @@ ehci_open(struct usbd_pipe *pipe)
>         return (USBD_NORMAL_COMPLETION);
>  }
>
> -/*
> - * Add an ED to the schedule.  Called at splusb().
> - * If in the async schedule, it will always have a next.
> - * If in the intr schedule it may not.
> - */
>  void
> -ehci_add_qh(struct ehci_soft_qh *sqh, struct ehci_soft_qh *head)
> +ehci_add_qh(struct usbd_pipe *pipe, struct ehci_soft_qh *head,
> +    struct ehci_soft_qtd *start)
>  {
> +       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
> +       struct ehci_soft_qh *sqh = epipe->sqh;
> +       usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
> +       uint8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
> +       uint8_t addr = pipe->device->address;
> +       int i, hshubaddr, hshubport, speed;
> +       int naks = 8;           /* XXX */
> +
> +       KASSERT(xfertype != UE_ISOCHRONOUS);
> +
>         splsoftassert(IPL_SOFTUSB);
>
> +       if (pipe->device->myhsport) {
> +               hshubaddr = pipe->device->myhsport->parent->address;
> +               hshubport = pipe->device->myhsport->portno;
> +       } else {
> +               hshubaddr = 0;
> +               hshubport = 0;
> +       }
> +
> +       /* XXX All this stuff is only valid for async. */
> +       switch (pipe->device->speed) {
> +       case USB_SPEED_LOW:
> +               speed = EHCI_QH_SPEED_LOW;
> +               break;
> +       case USB_SPEED_FULL:
> +               speed = EHCI_QH_SPEED_FULL;
> +               break;
> +       case USB_SPEED_HIGH:
> +               speed = EHCI_QH_SPEED_HIGH;
> +               break;
> +       default:
> +               panic("%s: bad device speed %d", __func__, pipe->device->speed);
> +       }
> +
> +       /* qh_link is filled below */
> +       sqh->qh.qh_endp = htole32(
> +           EHCI_QH_SET_ADDR(addr) |
> +           EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
> +           EHCI_QH_SET_EPS(speed) |
> +           (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
> +           EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
> +           (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
> +           EHCI_QH_CTL : 0) |
> +           EHCI_QH_SET_NRL(naks)
> +           );
> +       sqh->qh.qh_endphub = htole32(
> +           EHCI_QH_SET_MULT(1) |
> +           EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
> +       );
> +       if (speed != EHCI_QH_SPEED_HIGH) {
> +               sqh->qh.qh_endphub |= htole32(
> +                   EHCI_QH_SET_HUBA(hshubaddr) |
> +                   EHCI_QH_SET_PORT(hshubport) |
> +                   EHCI_QH_SET_CMASK(0x1c) /* XXX */
> +               );
> +       }
> +       sqh->qh.qh_curqtd = 0;
> +
> +       sqh->qh.qh_qtd.qtd_next = htole32(start->physaddr);
> +       sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
> +       if (xfertype == UE_CONTROL)
> +               sqh->qh.qh_qtd.qtd_status = 0;
> +       else
> +               sqh->qh.qh_qtd.qtd_status =
> +                   htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
> +
> +       /* Reset reserved fields */
> +       for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
> +               sqh->qh.qh_qtd.qtd_buffer[i] = 0;
> +               sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
> +       }
> +       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
> +           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> +
> +       /*
> +        * Add an ED to the schedule.
> +        *
> +        * If in the async schedule, it will always have a next.
> +        * If in the intr schedule it may not.
> +        */
> +
>         usb_syncmem(&head->dma, head->offs + offsetof(struct ehci_qh, qh_link),
>             sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE);
>         sqh->next = head->next;
> @@ -1534,10 +1509,13 @@ ehci_add_qh(struct ehci_soft_qh *sqh, st
>   * Will always have a 'next' if it's in the async list as it's circular.
>   */
>  void
> -ehci_rem_qh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
> +ehci_rem_qh(struct ehci_softc *sc, struct usbd_pipe *pipe)
>  {
> +       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
> +       struct ehci_soft_qh *sqh = epipe->sqh;
> +
>         splsoftassert(IPL_SOFTUSB);
> -       /* XXX */
> +
>         usb_syncmem(&sqh->dma, sqh->offs + offsetof(struct ehci_qh, qh_link),
>             sizeof(sqh->qh.qh_link), BUS_DMASYNC_POSTWRITE);
>         sqh->prev->qh.qh_link = sqh->qh.qh_link;
> @@ -1548,42 +1526,8 @@ ehci_rem_qh(struct ehci_softc *sc, struc
>             sqh->prev->offs + offsetof(struct ehci_qh, qh_link),
>             sizeof(sqh->prev->qh.qh_link), BUS_DMASYNC_PREWRITE);
>
> -       ehci_sync_hc(sc);
> -}
> -
> -void
> -ehci_set_qh_qtd(struct ehci_soft_qh *sqh, struct ehci_soft_qtd *sqtd)
> -{
> -       int i;
> -       u_int32_t status;
> -
> -       /* Save toggle bit and ping status. */
> -       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
> -           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
> -       status = sqh->qh.qh_qtd.qtd_status &
> -           htole32(EHCI_QTD_TOGGLE_MASK |
> -               EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));
> -       /* Set HALTED to make hw leave it alone. */
> -       sqh->qh.qh_qtd.qtd_status =
> -           htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));
> -       usb_syncmem(&sqh->dma,
> -           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
> -           sizeof(sqh->qh.qh_qtd.qtd_status),
> -           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> -       sqh->qh.qh_curqtd = 0;
> -       sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
> -       sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
> -       for (i = 0; i < EHCI_QTD_NBUFFERS; i++)
> -               sqh->qh.qh_qtd.qtd_buffer[i] = 0;
> -       sqh->sqtd = sqtd;
> -       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
> -           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> -       /* Set !HALTED && !ACTIVE to start execution, preserve some fields */
> -       sqh->qh.qh_qtd.qtd_status = status;
> -       usb_syncmem(&sqh->dma,
> -           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
> -           sizeof(sqh->qh.qh_qtd.qtd_status),
> -           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> +       pipe->endpoint->savedtoggle =
> +           EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
>  }
>
>  /*
> @@ -2471,7 +2415,6 @@ ehci_alloc_sqtd_chain(struct ehci_softc
>  void
>  ehci_free_sqtd_chain(struct ehci_softc *sc, struct ehci_xfer *ex)
>  {
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)ex->xfer.pipe;
>         struct ehci_soft_qtd *sqtd, *next;
>
>         DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p\n", ex->sqtdstart));
> @@ -2481,7 +2424,6 @@ ehci_free_sqtd_chain(struct ehci_softc *
>                 ehci_free_sqtd(sc, sqtd);
>         }
>         ex->sqtdstart = ex->sqtdend = NULL;
> -       epipe->sqh->sqtd = NULL;
>  }
>
>  struct ehci_soft_itd *
> @@ -2565,14 +2507,7 @@ ehci_close_pipe(struct usbd_pipe *pipe)
>  {
>         struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
>         struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
> -       struct ehci_soft_qh *sqh = epipe->sqh;
> -       int s;
>
> -       s = splusb();
> -       ehci_rem_qh(sc, sqh);
> -       splx(s);
> -       pipe->endpoint->savedtoggle =
> -           EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
>         ehci_free_sqh(sc, epipe->sqh);
>  }
>
> @@ -2590,16 +2525,15 @@ void
>  ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
>  {
>         struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
>         struct ehci_xfer *ex = (struct ehci_xfer*)xfer;
> -       struct ehci_soft_qh *sqh = epipe->sqh;
> -       struct ehci_soft_qtd *sqtd;
>         int s;
>
>         if (sc->sc_bus.dying || xfer->status == USBD_NOT_STARTED) {
>                 s = splusb();
> -               if (xfer->status != USBD_NOT_STARTED)
> +               if (xfer->status != USBD_NOT_STARTED) {
> +                       ehci_rem_qh(sc, xfer->pipe);
>                         TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
> +               }
>                 xfer->status = status;  /* make software ignore it */
>                 timeout_del(&xfer->timeout_handle);
>                 usb_rem_task(xfer->device, &xfer->abort_task);
> @@ -2632,51 +2566,21 @@ ehci_abort_xfer(struct usbd_xfer *xfer,
>                 return;
>         }
>
> -       /*
> -        * Step 1: Make interrupt routine and timeouts ignore xfer.
> -        */
>         s = splusb();
>         ex->ehci_xfer_flags |= EHCI_XFER_ABORTING;
> -       xfer->status = status;  /* make software ignore it */
> +
> +       /* Remove the Queue Head. */
> +       ehci_rem_qh(sc, xfer->pipe);
>         TAILQ_REMOVE(&sc->sc_intrhead, ex, inext);
> +
> +       xfer->status = status;  /* make software ignore it */
>         timeout_del(&xfer->timeout_handle);
>         usb_rem_task(xfer->device, &xfer->abort_task);
> -       splx(s);
>
>         /*
> -        * Step 2: Deactivate all of the qTDs that we will be removing,
> -        * otherwise the queue head may go active again.
> -        */
> -       usb_syncmem(&sqh->dma,
> -           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
> -           sizeof(sqh->qh.qh_qtd.qtd_status),
> -           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
> -       sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
> -       usb_syncmem(&sqh->dma,
> -           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
> -           sizeof(sqh->qh.qh_qtd.qtd_status),
> -           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> -
> -       for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
> -               usb_syncmem(&sqtd->dma,
> -                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
> -                   sizeof(sqtd->qtd.qtd_status),
> -                   BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
> -               sqtd->qtd.qtd_status = htole32(EHCI_QTD_HALTED);
> -               usb_syncmem(&sqtd->dma,
> -                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
> -                   sizeof(sqtd->qtd.qtd_status),
> -                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
> -       }
> -       ehci_sync_hc(sc);
> -
> -       /*
> -        * Step 3: Make sure the soft interrupt routine has run. This
> +        * Make sure the soft interrupt routine has run. This
>          * should remove any completed items off the queue.
> -        * The hardware has no reference to completed items (TDs).
> -        * It's safe to remove them at any time.
>          */
> -       s = splusb();
>         sc->sc_softwake = 1;
>         usb_schedsoftintr(&sc->sc_bus);
>         tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
> @@ -2849,7 +2753,6 @@ ehci_device_ctrl_start(struct usbd_xfer
>         struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
>         usb_device_request_t *req = &xfer->request;
>         struct ehci_soft_qtd *setup, *stat, *next;
> -       struct ehci_soft_qh *sqh;
>         u_int len = UGETW(req->wLength);
>         usbd_status err;
>         int s;
> @@ -2870,8 +2773,6 @@ ehci_device_ctrl_start(struct usbd_xfer
>                 goto bad2;
>         }
>
> -       sqh = epipe->sqh;
> -
>         /* Set up data transaction */
>         if (len != 0) {
>                 struct ehci_soft_qtd *end;
> @@ -2931,14 +2832,13 @@ ehci_device_ctrl_start(struct usbd_xfer
>         ex->isdone = 0;
>  #endif
>
> -       /* Insert qTD in QH list. */
>         s = splusb();
> -       ehci_set_qh_qtd(sqh, setup);
>         if (xfer->timeout && !sc->sc_bus.use_polling) {
>                 timeout_del(&xfer->timeout_handle);
>                 timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
>                 timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
>         }
> +       ehci_add_qh(xfer->pipe, sc->sc_async_head, setup);
>         TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
>         xfer->status = USBD_IN_PROGRESS;
>         splx(s);
> @@ -2998,10 +2898,8 @@ usbd_status
>  ehci_device_bulk_start(struct usbd_xfer *xfer)
>  {
>         struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
>         struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
>         struct ehci_soft_qtd *data, *dataend;
> -       struct ehci_soft_qh *sqh;
>         usbd_status err;
>         int s;
>
> @@ -3010,8 +2908,6 @@ ehci_device_bulk_start(struct usbd_xfer
>         if (sc->sc_bus.dying)
>                 return (USBD_IOERROR);
>
> -       sqh = epipe->sqh;
> -
>         err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
>         if (err) {
>                 xfer->status = err;
> @@ -3030,12 +2926,12 @@ ehci_device_bulk_start(struct usbd_xfer
>  #endif
>
>         s = splusb();
> -       ehci_set_qh_qtd(sqh, data);
>         if (xfer->timeout && !sc->sc_bus.use_polling) {
>                 timeout_del(&xfer->timeout_handle);
>                 timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
>                 timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
>         }
> +       ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
>         TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
>         xfer->status = USBD_IN_PROGRESS;
>         splx(s);
> @@ -3069,12 +2965,18 @@ ehci_device_bulk_done(struct usbd_xfer *
>         }
>  }
>
> -usbd_status
> -ehci_device_setintr(struct ehci_softc *sc, struct ehci_soft_qh *sqh, int ival)
> +struct ehci_soft_qh *
> +ehci_intr_get_sqh(struct usbd_pipe *pipe)
>  {
> +       struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
> +       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
>         struct ehci_soft_islot *isp;
> +       int ival = pipe->interval;
>         int islot, lev;
>
> +       if (ival == USBD_DEFAULT_INTERVAL)
> +               ival = pipe->endpoint->edesc->bInterval;
> +
>         /* Find a poll rate that is large enough. */
>         for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--)
>                 if (EHCI_ILEV_IVAL(lev) <= ival)
> @@ -3084,11 +2986,10 @@ ehci_device_setintr(struct ehci_softc *s
>         /* XXX could do better than picking at random */
>         islot = EHCI_IQHIDX(lev, arc4random());
>
> -       sqh->islot = islot;
> +       epipe->sqh->islot = islot;
>         isp = &sc->sc_islots[islot];
> -       ehci_add_qh(sqh, isp->sqh);
>
> -       return (USBD_NORMAL_COMPLETION);
> +       return (isp->sqh);
>  }
>
>  usbd_status
> @@ -3113,9 +3014,7 @@ ehci_device_intr_start(struct usbd_xfer
>  {
>         struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
>         struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
>         struct ehci_soft_qtd *data, *dataend;
> -       struct ehci_soft_qh *sqh;
>         usbd_status err;
>         int s;
>
> @@ -3124,8 +3023,6 @@ ehci_device_intr_start(struct usbd_xfer
>         if (sc->sc_bus.dying)
>                 return (USBD_IOERROR);
>
> -       sqh = epipe->sqh;
> -
>         err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
>         if (err) {
>                 xfer->status = err;
> @@ -3143,12 +3040,12 @@ ehci_device_intr_start(struct usbd_xfer
>  #endif
>
>         s = splusb();
> -       ehci_set_qh_qtd(sqh, data);
>         if (xfer->timeout && !sc->sc_bus.use_polling) {
>                 timeout_del(&xfer->timeout_handle);
>                 timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
>                 timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
>         }
> +       ehci_add_qh(xfer->pipe, sc->sc_async_head, data);
>         TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
>         xfer->status = USBD_IN_PROGRESS;
>         splx(s);
> @@ -3179,48 +3076,15 @@ void
>  ehci_device_intr_done(struct usbd_xfer *xfer)
>  {
>         struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
> -       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
>         struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
> -       struct ehci_soft_qtd *data, *dataend;
> -       struct ehci_soft_qh *sqh;
> -       usbd_status err;
> -       int s;
>
>         if (xfer->pipe->repeat) {
>                 ehci_free_sqtd_chain(sc, ex);
> -
>                 usb_syncmem(&xfer->dmabuf, 0, xfer->length,
>                     usbd_xfer_isread(xfer) ?
>                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
> -               sqh = epipe->sqh;
> -
> -               err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
> -               if (err) {
> -                       xfer->status = err;
> -                       return;
> -               }
>
> -               /* Set up interrupt info. */
> -               ex->sqtdstart = data;
> -               ex->sqtdend = dataend;
> -#ifdef DIAGNOSTIC
> -               if (!ex->isdone) {
> -                       printf("ehci_device_intr_done: not done, ex=%p\n",
> -                                       ex);
> -               }
> -               ex->isdone = 0;
> -#endif
> -
> -               s = splusb();
> -               ehci_set_qh_qtd(sqh, data);
> -               if (xfer->timeout && !sc->sc_bus.use_polling) {
> -                       timeout_del(&xfer->timeout_handle);
> -                       timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
> -                       timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
> -               }
> -               TAILQ_INSERT_TAIL(&sc->sc_intrhead, ex, inext);
> -               xfer->status = USBD_IN_PROGRESS;
> -               splx(s);
> +               ehci_device_intr_start(xfer);
>         } else if (xfer->status != USBD_NOMEM) {
>                 ehci_free_sqtd_chain(sc, ex);
>         }
> Index: ehcivar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
> retrieving revision 1.37
> diff -u -p -r1.37 ehcivar.h
> --- ehcivar.h   2 Oct 2016 06:36:39 -0000       1.37
> +++ ehcivar.h   3 Oct 2017 09:24:08 -0000
> @@ -46,7 +46,6 @@ struct ehci_soft_qh {
>         struct ehci_qh qh;
>         struct ehci_soft_qh *next;
>         struct ehci_soft_qh *prev;
> -       struct ehci_soft_qtd *sqtd;
>         ehci_physaddr_t physaddr;
>         struct usb_dma dma;             /* QH's DMA infos */
>         int offs;                       /* QH's offset in struct usb_dma */