summaryrefslogtreecommitdiffstats
path: root/sys/cam/cam_periph.c
diff options
context:
space:
mode:
authormarkj <markj@FreeBSD.org>2016-11-05 20:22:12 +0000
committermarkj <markj@FreeBSD.org>2016-11-05 20:22:12 +0000
commit6fd3dc36f273bab3ad80c02d4e2ebe2665262b3e (patch)
tree71fbf0420f32ae17557665feac7e6e2c01a1d9a3 /sys/cam/cam_periph.c
parent69e992c924ecbc411a5e990d427621647e3b2faa (diff)
downloadFreeBSD-src-6fd3dc36f273bab3ad80c02d4e2ebe2665262b3e.zip
FreeBSD-src-6fd3dc36f273bab3ad80c02d4e2ebe2665262b3e.tar.gz
MFC r306529:
cam_periph_ccbwait could return while ccb in progress
Diffstat (limited to 'sys/cam/cam_periph.c')
-rw-r--r--sys/cam/cam_periph.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 091b96f..942a6c3 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -975,16 +975,6 @@ cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
PRELE(curproc);
}
-void
-cam_periph_ccbwait(union ccb *ccb)
-{
-
- if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
- || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
- xpt_path_sleep(ccb->ccb_h.path, &ccb->ccb_h.cbfcnp, PRIBIO,
- "cbwait", 0);
-}
-
int
cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr,
int (*error_routine)(union ccb *ccb,
@@ -1048,13 +1038,38 @@ cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr,
}
static void
+cam_periph_done_panic(struct cam_periph *periph, union ccb *done_ccb)
+{
+
+ panic("%s: already done with ccb %p", __func__, done_ccb);
+}
+
+static void
cam_periph_done(struct cam_periph *periph, union ccb *done_ccb)
{
/* Caller will release the CCB */
+ xpt_path_assert(done_ccb->ccb_h.path, MA_OWNED);
+ done_ccb->ccb_h.cbfcnp = cam_periph_done_panic;
wakeup(&done_ccb->ccb_h.cbfcnp);
}
+static void
+cam_periph_ccbwait(union ccb *ccb)
+{
+
+ if ((ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) {
+ while (ccb->ccb_h.cbfcnp != cam_periph_done_panic)
+ xpt_path_sleep(ccb->ccb_h.path, &ccb->ccb_h.cbfcnp,
+ PRIBIO, "cbwait", 0);
+ }
+ KASSERT(ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX &&
+ (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG,
+ ("%s: proceeding with incomplete ccb: ccb=%p, func_code=%#x, "
+ "status=%#x, index=%d", __func__, ccb, ccb->ccb_h.func_code,
+ ccb->ccb_h.status, ccb->ccb_h.pinfo.index));
+}
+
int
cam_periph_runccb(union ccb *ccb,
int (*error_routine)(union ccb *ccb,
@@ -1069,6 +1084,9 @@ cam_periph_runccb(union ccb *ccb,
starttime = NULL;
xpt_path_assert(ccb->ccb_h.path, MA_OWNED);
+ KASSERT((ccb->ccb_h.flags & CAM_UNLOCKED) == 0,
+ ("%s: ccb=%p, func_code=%#x, flags=%#x", __func__, ccb,
+ ccb->ccb_h.func_code, ccb->ccb_h.flags));
/*
* If the user has supplied a stats structure, and if we understand
@@ -1088,9 +1106,10 @@ cam_periph_runccb(union ccb *ccb,
cam_periph_ccbwait(ccb);
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
error = 0;
- else if (error_routine != NULL)
+ else if (error_routine != NULL) {
+ ccb->ccb_h.cbfcnp = cam_periph_done;
error = (*error_routine)(ccb, camflags, sense_flags);
- else
+ } else
error = 0;
} while (error == ERESTART);
OpenPOWER on IntegriCloud