when a usb transfer (xfer) is started, the underlying hci driver
adds a timeout that adds a usb task that aborts the xfer.

if an xfer is synchronous, the upper usb layer sleeps waiting for
the xfer to complete.  it will also be woken up by the above mentioned
abort task if the xfer times out.

but what happens if a synchronous xfer run in the task thread stalls?
it can't be aborted by the abort task, because that won't run until
after the xfer wakes up!

I'm pretty sure this is what's causing the boot hangs in PR 6491 and
the one reported on m...@.

afaics, this issue is not new, but now that we're using the task
thread for attach/detach, we're more likely to hit it.

the patch below solves the issue by running another task thread that
is to be used ONLY for abort tasks.  I first looked at making the
upper usb layer timeout on it's own, but that's not possible without
major redesign.  I also thought about making the abort tasks workq
tasks, but that doesn't work because there is more than one way to
abort an xfer, and we may need to abort the abort task.  workqs have
no way to remove tasks from the queue but this is possible with
usb tasks.

it's not terribly easy to trigger an xfer timeout, but I did get at
least two, and things did recover.

unless someone sees a problem, or has a better solution, I think this
should go in soon.

yes, I had to hit each driver that uses usb tasks, but I think it's
also better to be explicit, now that we have 3 different types of
usb tasks ...

-- 
[email protected]
SDF Public Access UNIX System - http://sdf.lonestar.org

Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.112
diff -u -p ehci.c
--- ehci.c      29 Sep 2010 20:06:38 -0000      1.112
+++ ehci.c      17 Oct 2010 22:12:50 -0000
@@ -1221,7 +1221,7 @@ ehci_allocx(struct usbd_bus *bus)
        if (xfer != NULL) {
                memset(xfer, 0, sizeof(struct ehci_xfer));
                usb_init_task(&EXFER(xfer)->abort_task, ehci_timeout_task,
-                   xfer);
+                   xfer, USB_TASK_TYPE_ABORT);
                EXFER(xfer)->ehci_xfer_flags = 0;
 #ifdef DIAGNOSTIC
                EXFER(xfer)->isdone = 1;
Index: if_atu.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_atu.c,v
retrieving revision 1.94
diff -u -p if_atu.c
--- if_atu.c    21 Nov 2009 14:18:34 -0000      1.94
+++ if_atu.c    17 Oct 2010 22:12:51 -0000
@@ -1467,7 +1467,7 @@ atu_complete_attach(struct atu_softc *sc)
        /* setup ifmedia interface */
        ieee80211_media_init(ifp, atu_media_change, atu_media_status);
 
-       usb_init_task(&sc->sc_task, atu_task, sc);
+       usb_init_task(&sc->sc_task, atu_task, sc, USB_TASK_TYPE_GENERIC);
 
 #if NBPFILTER > 0
        bpfattach(&sc->sc_radiobpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
Index: if_aue.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_aue.c,v
retrieving revision 1.79
diff -u -p if_aue.c
--- if_aue.c    24 Sep 2010 08:33:58 -0000      1.79
+++ if_aue.c    17 Oct 2010 22:12:51 -0000
@@ -734,8 +734,10 @@ aue_attach(struct device *parent, struct device *self,
                return;
        }
 
-       usb_init_task(&sc->aue_tick_task, aue_tick_task, sc);
-       usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc);
+       usb_init_task(&sc->aue_tick_task, aue_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->aue_stop_task, (void (*)(void *))aue_stop, sc,
+           USB_TASK_TYPE_GENERIC);
        rw_init(&sc->aue_mii_lock, "auemii");
 
        err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &iface);
Index: if_axe.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_axe.c,v
retrieving revision 1.99
diff -u -p if_axe.c
--- if_axe.c    24 Sep 2010 03:21:21 -0000      1.99
+++ if_axe.c    17 Oct 2010 22:12:51 -0000
@@ -676,9 +676,11 @@ axe_attach(struct device *parent, struct device *self,
 
        sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
 
-       usb_init_task(&sc->axe_tick_task, axe_tick_task, sc);
+       usb_init_task(&sc->axe_tick_task, axe_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
        rw_init(&sc->axe_mii_lock, "axemii");
-       usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc);
+       usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc,
+           USB_TASK_TYPE_GENERIC);
 
        err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface);
        if (err) {
Index: if_cue.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_cue.c,v
retrieving revision 1.53
diff -u -p if_cue.c
--- if_cue.c    24 Sep 2010 08:33:58 -0000      1.53
+++ if_cue.c    17 Oct 2010 22:12:51 -0000
@@ -470,8 +470,10 @@ cue_attach(struct device *parent, struct device *self,
        sc->cue_product = uaa->product;
        sc->cue_vendor = uaa->vendor;
 
-       usb_init_task(&sc->cue_tick_task, cue_tick_task, sc);
-       usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc);
+       usb_init_task(&sc->cue_tick_task, cue_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc,
+           USB_TASK_TYPE_GENERIC);
 
        err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
        if (err) {
Index: if_mos.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_mos.c,v
retrieving revision 1.8
diff -u -p if_mos.c
--- if_mos.c    24 Sep 2010 08:33:58 -0000      1.8
+++ if_mos.c    17 Oct 2010 22:12:51 -0000
@@ -652,9 +652,11 @@ mos_attach(struct device *parent, struct device *self,
                return;
        }
 
-       usb_init_task(&sc->mos_tick_task, mos_tick_task, sc);
+       usb_init_task(&sc->mos_tick_task, mos_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
        rw_init(&sc->mos_mii_lock, "mosmii");
-       usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc);
+       usb_init_task(&sc->mos_stop_task, (void (*)(void *))mos_stop, sc,
+           USB_TASK_TYPE_GENERIC);
 
        err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &sc->mos_iface);
        if (err) {
Index: if_otus.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_otus.c,v
retrieving revision 1.18
diff -u -p if_otus.c
--- if_otus.c   27 Aug 2010 17:08:00 -0000      1.18
+++ if_otus.c   17 Oct 2010 22:12:51 -0000
@@ -203,7 +203,7 @@ otus_attach(struct device *parent, struct device *self
 
        sc->sc_udev = uaa->device;
 
-       usb_init_task(&sc->sc_task, otus_task, sc);
+       usb_init_task(&sc->sc_task, otus_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, otus_next_scan, sc);
        timeout_set(&sc->calib_to, otus_calibrate_to, sc);
 
Index: if_ral.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_ral.c,v
retrieving revision 1.113
diff -u -p if_ral.c
--- if_ral.c    27 Aug 2010 17:08:01 -0000      1.113
+++ if_ral.c    17 Oct 2010 22:12:51 -0000
@@ -273,7 +273,7 @@ ural_attach(struct device *parent, struct device *self
                return;
        }
 
-       usb_init_task(&sc->sc_task, ural_task, sc);
+       usb_init_task(&sc->sc_task, ural_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, ural_next_scan, sc);
 
        sc->amrr.amrr_min_success_threshold =  1;
Index: if_rum.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_rum.c,v
retrieving revision 1.90
diff -u -p if_rum.c
--- if_rum.c    27 Aug 2010 17:08:01 -0000      1.90
+++ if_rum.c    17 Oct 2010 22:12:52 -0000
@@ -328,7 +328,7 @@ rum_attach(struct device *parent, struct device *self,
                return;
        }
 
-       usb_init_task(&sc->sc_task, rum_task, sc);
+       usb_init_task(&sc->sc_task, rum_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, rum_next_scan, sc);
 
        sc->amrr.amrr_min_success_threshold =  1;
Index: if_run.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_run.c,v
retrieving revision 1.71
diff -u -p if_run.c
--- if_run.c    27 Aug 2010 17:08:01 -0000      1.71
+++ if_run.c    17 Oct 2010 22:12:52 -0000
@@ -471,7 +471,7 @@ run_attach(struct device *parent, struct device *self,
                return;
        }
 
-       usb_init_task(&sc->sc_task, run_task, sc);
+       usb_init_task(&sc->sc_task, run_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, run_next_scan, sc);
        timeout_set(&sc->calib_to, run_calibrate_to, sc);
 
Index: if_uath.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_uath.c,v
retrieving revision 1.43
diff -u -p if_uath.c
--- if_uath.c   27 Aug 2010 17:08:01 -0000      1.43
+++ if_uath.c   17 Oct 2010 22:12:52 -0000
@@ -298,7 +298,7 @@ uath_attach(struct device *parent, struct device *self
        /*
         * Only post-firmware devices here.
         */
-       usb_init_task(&sc->sc_task, uath_task, sc);
+       usb_init_task(&sc->sc_task, uath_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, uath_next_scan, sc);
        timeout_set(&sc->stat_to, uath_stat, sc);
 
Index: if_udav.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_udav.c,v
retrieving revision 1.46
diff -u -p if_udav.c
--- if_udav.c   27 Aug 2010 07:08:22 -0000      1.46
+++ if_udav.c   17 Oct 2010 22:12:52 -0000
@@ -211,9 +211,11 @@ udav_attach(struct device *parent, struct device *self
                goto bad;
        }
 
-       usb_init_task(&sc->sc_tick_task, udav_tick_task, sc);
+       usb_init_task(&sc->sc_tick_task, udav_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
        rw_init(&sc->sc_mii_lock, "udavmii");
-       usb_init_task(&sc->sc_stop_task, (void (*)(void *)) udav_stop_task, sc);
+       usb_init_task(&sc->sc_stop_task, (void (*)(void *)) udav_stop_task, sc,
+           USB_TASK_TYPE_GENERIC);
 
        /* get control interface */
        err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface);
Index: if_upgt.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_upgt.c,v
retrieving revision 1.50
diff -u -p if_upgt.c
--- if_upgt.c   27 Aug 2010 17:08:01 -0000      1.50
+++ if_upgt.c   17 Oct 2010 22:12:52 -0000
@@ -273,8 +273,9 @@ upgt_attach(struct device *parent, struct device *self
        }
 
        /* setup tasks and timeouts */
-       usb_init_task(&sc->sc_task_newstate, upgt_newstate_task, sc);
-       usb_init_task(&sc->sc_task_tx, upgt_tx_task, sc);
+       usb_init_task(&sc->sc_task_newstate, upgt_newstate_task, sc,
+           USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_task_tx, upgt_tx_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, upgt_next_scan, sc);
        timeout_set(&sc->led_to, upgt_set_led_blink, sc);
 
Index: if_url.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_url.c,v
retrieving revision 1.56
diff -u -p if_url.c
--- if_url.c    27 Aug 2010 07:08:22 -0000      1.56
+++ if_url.c    17 Oct 2010 22:12:52 -0000
@@ -208,9 +208,11 @@ url_attach(struct device *parent, struct device *self,
                goto bad;
        }
 
-       usb_init_task(&sc->sc_tick_task, url_tick_task, sc);
+       usb_init_task(&sc->sc_tick_task, url_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
        rw_init(&sc->sc_mii_lock, "urlmii");
-       usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc);
+       usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc,
+           USB_TASK_TYPE_GENERIC);
 
        /* get control interface */
        err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
Index: if_urtw.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_urtw.c,v
retrieving revision 1.31
diff -u -p if_urtw.c
--- if_urtw.c   27 Aug 2010 17:08:01 -0000      1.31
+++ if_urtw.c   17 Oct 2010 22:12:53 -0000
@@ -690,8 +690,9 @@ urtw_attach(struct device *parent, struct device *self
        /* XXX for what? */
        sc->sc_preamble_mode = 2;
 
-       usb_init_task(&sc->sc_task, urtw_task, sc);
-       usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc);
+       usb_init_task(&sc->sc_task, urtw_task, sc, USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_ledtask, urtw_ledusbtask, sc,
+           USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, urtw_next_scan, sc);
        timeout_set(&sc->sc_led_ch, urtw_ledtask, sc);
 
Index: if_zyd.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_zyd.c,v
retrieving revision 1.82
diff -u -p if_zyd.c
--- if_zyd.c    27 Aug 2010 17:08:01 -0000      1.82
+++ if_zyd.c    17 Oct 2010 22:12:53 -0000
@@ -323,7 +323,7 @@ zyd_complete_attach(struct zyd_softc *sc)
        usbd_status error;
        int i;
 
-       usb_init_task(&sc->sc_task, zyd_task, sc);
+       usb_init_task(&sc->sc_task, zyd_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->scan_to, zyd_next_scan, sc);
 
        sc->amrr.amrr_min_success_threshold =  1;
Index: ohci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohci.c,v
retrieving revision 1.99
diff -u -p ohci.c
--- ohci.c      7 Sep 2010 16:21:46 -0000       1.99
+++ ohci.c      17 Oct 2010 22:12:53 -0000
@@ -1894,7 +1894,8 @@ ohci_timeout(void *addr)
        }
 
        /* Execute the abort in a process context. */
-       usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr);
+       usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr,
+           USB_TASK_TYPE_ABORT);
        usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task);
 }
 
Index: udcf.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/udcf.c,v
retrieving revision 1.48
diff -u -p udcf.c
--- udcf.c      24 Sep 2010 08:33:59 -0000      1.48
+++ udcf.c      17 Oct 2010 22:12:53 -0000
@@ -206,10 +206,10 @@ udcf_attach(struct device *parent, struct device *self
                break;
        }
 
-       usb_init_task(&sc->sc_task, udcf_probe, sc);
-       usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc);
-       usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc);
-       usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc);
+       usb_init_task(&sc->sc_task, udcf_probe, sc, USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc, 
USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc, 
USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc, 
USB_TASK_TYPE_GENERIC);
 
        timeout_set(&sc->sc_to, udcf_intr, sc);
        timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc);
@@ -218,7 +218,8 @@ udcf_attach(struct device *parent, struct device *self
        timeout_set(&sc->sc_it_to, udcf_it_intr, sc);
 
        if (sc->sc_detect_ct) {
-               usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc);
+               usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc,
+                   USB_TASK_TYPE_GENERIC);
                timeout_set(&sc->sc_ct_to, udcf_ct_intr, sc);
        }
        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
Index: ueagle.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ueagle.c,v
retrieving revision 1.28
diff -u -p ueagle.c
--- ueagle.c    24 Sep 2010 08:33:59 -0000      1.28
+++ ueagle.c    17 Oct 2010 22:12:53 -0000
@@ -210,7 +210,8 @@ ueagle_attach(struct device *parent, struct device *se
            sc->sc_dev.dv_xname, addr[0], addr[1], addr[2], addr[3],
            addr[4], addr[5]);
 
-       usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc);
+       usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc,
+           USB_TASK_TYPE_GENERIC);
 
        ifp->if_softc = sc;
        ifp->if_flags = IFF_SIMPLEX;
Index: uhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhci.c,v
retrieving revision 1.83
diff -u -p uhci.c
--- uhci.c      20 Sep 2010 06:54:10 -0000      1.83
+++ uhci.c      17 Oct 2010 22:12:54 -0000
@@ -1447,7 +1447,8 @@ uhci_timeout(void *addr)
        }
 
        /* Execute the abort in a process context. */
-       usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
+       usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer,
+           USB_TASK_TYPE_ABORT);
        usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
 }
 
Index: umbg.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/umbg.c,v
retrieving revision 1.12
diff -u -p umbg.c
--- umbg.c      24 Sep 2010 08:33:59 -0000      1.12
+++ umbg.c      17 Oct 2010 22:12:54 -0000
@@ -200,7 +200,7 @@ umbg_attach(struct device *parent, struct device *self
        sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
        sensordev_install(&sc->sc_sensordev);
 
-       usb_init_task(&sc->sc_task, umbg_task, sc);
+       usb_init_task(&sc->sc_task, umbg_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->sc_to, umbg_intr, sc);
        timeout_set(&sc->sc_it_to, umbg_it_intr, sc);
 
? usb-abort.diff
Index: usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.68
diff -u -p usb.c
--- usb.c       23 Sep 2010 06:30:37 -0000      1.68
+++ usb.c       17 Oct 2010 22:12:54 -0000
@@ -100,17 +100,20 @@ struct usb_softc {
        struct timeval   sc_ptime;
 };
 
+TAILQ_HEAD(, usb_task) usb_abort_tasks;
 TAILQ_HEAD(, usb_task) usb_explore_tasks;
-TAILQ_HEAD(, usb_task) usb_tasks;
+TAILQ_HEAD(, usb_task) usb_generic_tasks;
 
-int usb_run_tasks;
+int usb_run_tasks, usb_run_abort_tasks;
 int explore_pending;
 
 void   usb_explore(void *);
 void   usb_first_explore(void *);
-void   usb_create_task_thread(void *);
+void   usb_create_task_threads(void *);
 void   usb_task_thread(void *);
 struct proc *usb_task_thread_proc = NULL;
+void   usb_abort_task_thread(void *);
+struct proc *usb_abort_task_thread_proc = NULL;
 
 #define USB_MAX_EVENTS 100
 struct usb_event_q {
@@ -195,7 +198,8 @@ usb_attach(struct device *parent, struct device *self,
        sc->sc_bus->flags |= USB_BUS_CONFIG_PENDING;
 
        /* explore task */
-       usb_init_task(&sc->sc_explore_task, usb_explore, sc);
+       usb_init_task(&sc->sc_explore_task, usb_explore, sc,
+           USB_TASK_TYPE_EXPLORE);
 
        ue.u.ue_ctrlr.ue_bus = sc->sc_dev.dv_unit;
        usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
@@ -252,10 +256,11 @@ usb_attach(struct device *parent, struct device *self,
 void
 usb_begin_tasks(void)
 {
+       TAILQ_INIT(&usb_abort_tasks);
        TAILQ_INIT(&usb_explore_tasks);
-       TAILQ_INIT(&usb_tasks);
-       usb_run_tasks = 1;
-       kthread_create_deferred(usb_create_task_thread, NULL);
+       TAILQ_INIT(&usb_generic_tasks);
+       usb_run_tasks = usb_run_abort_tasks = 1;
+       kthread_create_deferred(usb_create_task_threads, NULL);
 }
 
 /*
@@ -264,13 +269,18 @@ usb_begin_tasks(void)
 void
 usb_end_tasks(void)
 {
-       usb_run_tasks = 0;
+       usb_run_tasks = usb_run_abort_tasks = 0;
+       wakeup(&usb_run_abort_tasks);
        wakeup(&usb_run_tasks);
 }
 
 void
-usb_create_task_thread(void *arg)
+usb_create_task_threads(void *arg)
 {
+       if (kthread_create(usb_abort_task_thread, NULL,
+           &usb_abort_task_thread_proc, "usbatsk"))
+               panic("unable to create usb abort task thread");
+
        if (kthread_create(usb_task_thread, NULL,
            &usb_task_thread_proc, "usbtask"))
                panic("unable to create usb task thread");
@@ -286,7 +296,8 @@ usb_add_task(usbd_device_handle dev, struct usb_task *
 {
        int s;
 
-       DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue));
+       DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task,
+           task->onqueue, task->type));
 
        /* Don't add task if the device's root hub is dying. */
        if (dev->bus->dying)
@@ -294,14 +305,24 @@ usb_add_task(usbd_device_handle dev, struct usb_task *
 
        s = splusb();
        if (!task->onqueue) {
-               if (task->fun == usb_explore)
+               switch (task->type) {
+               case USB_TASK_TYPE_ABORT:
+                       TAILQ_INSERT_TAIL(&usb_abort_tasks, task, next);
+                       break;
+               case USB_TASK_TYPE_EXPLORE:
                        TAILQ_INSERT_TAIL(&usb_explore_tasks, task, next);
-               else
-                       TAILQ_INSERT_TAIL(&usb_tasks, task, next);
+                       break;
+               case USB_TASK_TYPE_GENERIC:
+                       TAILQ_INSERT_TAIL(&usb_generic_tasks, task, next);
+                       break;
+               }
                task->onqueue = 1;
                task->dev = dev;
        }
-       wakeup(&usb_run_tasks);
+       if (task->type == USB_TASK_TYPE_ABORT)
+               wakeup(&usb_run_abort_tasks);
+       else
+               wakeup(&usb_run_tasks);
        splx(s);
 }
 
@@ -310,14 +331,22 @@ usb_rem_task(usbd_device_handle dev, struct usb_task *
 {
        int s;
 
-       DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue));
+       DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task,
+           task->onqueue, task->type));
 
        s = splusb();
        if (task->onqueue) {
-               if (task->fun == usb_explore)
+               switch (task->type) {
+               case USB_TASK_TYPE_ABORT:
+                       TAILQ_REMOVE(&usb_abort_tasks, task, next);
+                       break;
+               case USB_TASK_TYPE_EXPLORE:
                        TAILQ_REMOVE(&usb_explore_tasks, task, next);
-               else
-                       TAILQ_REMOVE(&usb_tasks, task, next);
+                       break;
+               case USB_TASK_TYPE_GENERIC:
+                       TAILQ_REMOVE(&usb_generic_tasks, task, next);
+                       break;
+               }
                task->onqueue = 0;
        }
        splx(s);
@@ -328,7 +357,8 @@ usb_rem_wait_task(usbd_device_handle dev, struct usb_t
 {
        int s;
 
-       DPRINTFN(2,("%s: task=%p onqueue=%d\n", __func__, task, task->onqueue));
+       DPRINTFN(2,("%s: task=%p onqueue=%d type=%d\n", __func__, task,
+           task->onqueue, task->type));
 
        s = splusb();
        usb_rem_task(dev, task);
@@ -391,10 +421,47 @@ usb_task_thread(void *arg)
        while (usb_run_tasks) {
                if ((task = TAILQ_FIRST(&usb_explore_tasks)) != NULL)
                        TAILQ_REMOVE(&usb_explore_tasks, task, next);
-               else if ((task = TAILQ_FIRST(&usb_tasks)) != NULL)
-                       TAILQ_REMOVE(&usb_tasks, task, next);
+               else if ((task = TAILQ_FIRST(&usb_generic_tasks)) != NULL)
+                       TAILQ_REMOVE(&usb_generic_tasks, task, next);
                else {
                        tsleep(&usb_run_tasks, PWAIT, "usbtsk", 0);
+                       continue;
+               }
+               task->onqueue = 0;
+               /* Don't execute the task if the root hub is gone. */
+               if (task->dev->bus->dying)
+                       continue;
+               task->running = 1;
+               splx(s);
+               task->fun(task->arg);
+               s = splusb();
+               task->running = 0;
+               wakeup(task);
+       }
+       splx(s);
+
+       kthread_exit(0);
+}
+
+/*
+ * This thread is ONLY for the HCI drivers to be able to abort xfers.
+ * Synchronous xfers sleep the task thread, so the aborts need to happen
+ * in a different thread.
+ */
+void
+usb_abort_task_thread(void *arg)
+{
+       struct usb_task *task;
+       int s;
+
+       DPRINTF(("usb_xfer_abort_thread: start\n"));
+
+       s = splusb();
+       while (usb_run_abort_tasks) {
+               if ((task = TAILQ_FIRST(&usb_abort_tasks)) != NULL)
+                       TAILQ_REMOVE(&usb_abort_tasks, task, next);
+               else {
+                       tsleep(&usb_run_abort_tasks, PWAIT, "usbatsk", 0);
                        continue;
                }
                task->onqueue = 0;
Index: usbdi.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.h,v
retrieving revision 1.34
diff -u -p usbdi.h
--- usbdi.h     23 Sep 2010 06:30:37 -0000      1.34
+++ usbdi.h     17 Oct 2010 22:12:54 -0000
@@ -184,6 +184,10 @@ struct usb_task {
        usbd_device_handle dev;
        void (*fun)(void *);
        void *arg;
+       char type;
+#define USB_TASK_TYPE_GENERIC  0
+#define USB_TASK_TYPE_EXPLORE  1
+#define USB_TASK_TYPE_ABORT    2
        char onqueue;
        char running;
 };
@@ -191,7 +195,12 @@ struct usb_task {
 void usb_add_task(usbd_device_handle, struct usb_task *);
 void usb_rem_task(usbd_device_handle, struct usb_task *);
 void usb_rem_wait_task(usbd_device_handle, struct usb_task *);
-#define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->onqueue = 
0, (t)->running = 0)
+#define usb_init_task(t, f, a, y) \
+       ((t)->fun = (f),        \
+       (t)->arg = (a),         \
+       (t)->type = (y),        \
+       (t)->onqueue = 0,       \
+       (t)->running = 0)
 
 struct usb_devno {
        u_int16_t ud_vendor;
Index: uvideo.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uvideo.c,v
retrieving revision 1.142
diff -u -p uvideo.c
--- uvideo.c    9 Oct 2010 09:48:03 -0000       1.142
+++ uvideo.c    17 Oct 2010 22:12:54 -0000
@@ -1795,7 +1795,8 @@ uvideo_vs_init(struct uvideo_softc *sc)
 #ifdef UVIDEO_DUMP
        if (uvideo_debug_file_open(sc) != 0)
                return (USBD_INVAL);
-       usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_frame, sc);
+       usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_frame, sc,
+           USB_TASK_TYPE_GENERIC);
 #endif
        return (USBD_NORMAL_COMPLETION);
 }

Reply via email to