diff options
author | iedowse <iedowse@FreeBSD.org> | 2005-02-14 02:17:53 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2005-02-14 02:17:53 +0000 |
commit | 142aa8a840a9a8f0bb93e21d623560b94228bb22 (patch) | |
tree | f7e757aeac9873f45a43f3ab87a8323764cb9705 /sys/dev/usb/umass.c | |
parent | 0f68b77a1a9141ef1942b164128d198bc10fb7f8 (diff) | |
download | FreeBSD-src-142aa8a840a9a8f0bb93e21d623560b94228bb22.zip FreeBSD-src-142aa8a840a9a8f0bb93e21d623560b94228bb22.tar.gz |
Abort any active transfers when the device detaches. This fixes a
few situations where we used to crash, but by no means all of them.
Diffstat (limited to 'sys/dev/usb/umass.c')
-rw-r--r-- | sys/dev/usb/umass.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index 98f8fdf..1704a94 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1133,6 +1133,15 @@ USB_DETACH(umass) sc->flags |= UMASS_FLAGS_GONE; + /* abort all the pipes in case there are transfers active. */ + usbd_abort_default_pipe(sc->sc_udev); + if (sc->bulkout_pipe) + usbd_abort_pipe(sc->bulkout_pipe); + if (sc->bulkin_pipe) + usbd_abort_pipe(sc->bulkin_pipe); + if (sc->intrin_pipe) + usbd_abort_pipe(sc->intrin_pipe); + usb_uncallout_drain(sc->cam_scsi_rescan_ch, umass_cam_rescan, sc); if ((sc->proto & UMASS_PROTO_SCSI) || (sc->proto & UMASS_PROTO_ATAPI) || @@ -1444,6 +1453,14 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, USBDEVNAME(sc->sc_dev), sc->transfer_state, states[sc->transfer_state], xfer, usbd_errstr(err))); + /* Give up if the device has detached. */ + if (sc->flags & UMASS_FLAGS_GONE) { + sc->transfer_state = TSTATE_IDLE; + sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, + STATUS_CMD_FAILED); + return; + } + switch (sc->transfer_state) { /***** Bulk Transfer *****/ @@ -1897,6 +1914,14 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, USBDEVNAME(sc->sc_dev), sc->transfer_state, states[sc->transfer_state], xfer, usbd_errstr(err))); + /* Give up if the device has detached. */ + if (sc->flags & UMASS_FLAGS_GONE) { + sc->transfer_state = TSTATE_IDLE; + sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, + STATUS_CMD_FAILED); + return; + } + switch (sc->transfer_state) { /***** CBI Transfer *****/ @@ -2608,6 +2633,13 @@ umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status) union ccb *ccb = (union ccb *) priv; struct ccb_scsiio *csio = &ccb->csio; /* deref union */ + /* If the device is gone, just fail the request. */ + if (sc->flags & UMASS_FLAGS_GONE) { + ccb->ccb_h.status = CAM_TID_INVALID; + xpt_done(ccb); + return; + } + csio->resid = residue; switch (status) { @@ -2685,6 +2717,12 @@ umass_cam_sense_cb(struct umass_softc *sc, void *priv, int residue, int status) unsigned char *rcmd; int rcmdlen; + if (sc->flags & UMASS_FLAGS_GONE) { + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; + xpt_done(ccb); + return; + } + switch (status) { case STATUS_CMD_OK: case STATUS_CMD_UNKNOWN: @@ -2778,6 +2816,12 @@ umass_cam_quirk_cb(struct umass_softc *sc, void *priv, int residue, int status) DPRINTF(UDMASS_SCSI, ("%s: Test unit ready returned status %d\n", USBDEVNAME(sc->sc_dev), status)); + + if (sc->flags & UMASS_FLAGS_GONE) { + ccb->ccb_h.status = CAM_TID_INVALID; + xpt_done(ccb); + return; + } #if 0 ccb->ccb_h.status = CAM_REQ_CMP; #endif |