Hi,
when powering down, sd(4) will trigger a powerdown on it's umass(4)
USB stick. If the device fails to respond, for whatever reason, the
umass(4) code will do multiple reset mechanism, and one of those uses
a control transfer. Unfortunately the control transfer is not passed
the sc_xfer_flags, which are *only* used to supply USBD_SYNCHRONOUS
to allow the polling mode to work.
Without USBD_SYNCHRONOUS, umass_polled_transfer()'s call to
usbd_transfer() will immediately return, and it will never complete.
The code will return to scsi, where it will wait until the "cookie"
is cleared. Since this is polling mode, there's no asynchronous call-
back, and the cookie will never be cleared. Thus we will msleep and
wait forever.
By also using sc->sc_xfer_flags on the control transfer, it will run
synchronously. There's still another bug that happens when even more
transfers fail, since then umass_bbb_transfer()'s call to umass_bbb_
reset() will cause the SCSI done handler to be called a second time
resulting in a panic.
But that's a bug in the state machine for error handling, which can be
fixed later on. Also a panic during powerdown is better than hanging
indefinitely.
ok?
Patrick
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c
index 53d783ff396..f871a3d9c41 100644
--- a/sys/dev/usb/umass.c
+++ b/sys/dev/usb/umass.c
@@ -789,18 +789,18 @@ umass_setup_ctrl_transfer(struct umass_softc *sc,
usb_device_request_t *req,
/* Initialise a USB control transfer and then schedule it */
usbd_setup_default_xfer(xfer, sc->sc_udev, (void *) sc,
- USBD_DEFAULT_TIMEOUT, req, buffer, buflen, flags,
- sc->sc_methods->wire_state);
+ USBD_DEFAULT_TIMEOUT, req, buffer, buflen,
+ flags | sc->sc_xfer_flags, sc->sc_methods->wire_state);
if (sc->sc_udev->bus->use_polling) {
DPRINTF(UDMASS_XFER,("%s: start polled ctrl xfer buffer=%p "
"buflen=%d flags=0x%x\n", sc->sc_dev.dv_xname, buffer,
- buflen, flags));
+ buflen, flags | sc->sc_xfer_flags));
err = umass_polled_transfer(sc, xfer);
} else {
DPRINTF(UDMASS_XFER,("%s: start ctrl xfer buffer=%p buflen=%d "
"flags=0x%x\n", sc->sc_dev.dv_xname, buffer, buflen,
- flags));
+ flags | sc->sc_xfer_flags));
err = usbd_transfer(xfer);
}
if (err && err != USBD_IN_PROGRESS) {