aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/cam_iosched.c3
-rw-r--r--sys/cam/cam_iosched.h38
-rw-r--r--sys/cam/cam_xpt.c7
3 files changed, 44 insertions, 4 deletions
diff --git a/sys/cam/cam_iosched.c b/sys/cam/cam_iosched.c
index 98d0dc7d0829..8b77b7d6c44f 100644
--- a/sys/cam/cam_iosched.c
+++ b/sys/cam/cam_iosched.c
@@ -1428,7 +1428,8 @@ cam_iosched_bio_complete(struct cam_iosched_softc *isc, struct bio *bp,
}
if (!(bp->bio_flags & BIO_ERROR))
- cam_iosched_io_metric_update(isc, done_ccb->ccb_h.qos.sim_data,
+ cam_iosched_io_metric_update(isc,
+ cam_iosched_sbintime_t(done_ccb->ccb_h.qos.periph_data),
bp->bio_cmd, bp->bio_bcount);
#endif
return retval;
diff --git a/sys/cam/cam_iosched.h b/sys/cam/cam_iosched.h
index 544c9006544e..150b8e90fb41 100644
--- a/sys/cam/cam_iosched.h
+++ b/sys/cam/cam_iosched.h
@@ -41,6 +41,44 @@ struct sysctl_oid;
union ccb;
struct bio;
+/*
+ * For 64-bit platforms, we know that uintptr_t is the same size as sbintime_t
+ * so we can store values in it. For 32-bit systems, however, uintptr_t is only
+ * 32-bits, so it won't fit. For those systems, store 24 bits of fraction and 8
+ * bits of seconds. This allows us to measure an interval of up to ~256s, which
+ * is ~200x what our current uses require. Provide some convenience functions to
+ * get the time, subtract two times and convert back to sbintime_t in a safe way
+ * that can be centralized.
+ */
+#ifdef __LP64__
+#define CAM_IOSCHED_TIME_SHIFT 0
+#else
+#define CAM_IOSCHED_TIME_SHIFT 8
+#endif
+static inline uintptr_t
+cam_iosched_now(void)
+{
+
+ /* Cast here is to avoid right shifting a signed value */
+ return (uintptr_t)((uint64_t)sbinuptime() >> CAM_IOSCHED_TIME_SHIFT);
+}
+
+static inline uintptr_t
+cam_iosched_delta_t(uintptr_t then)
+{
+
+ /* Since the types are identical, wrapping works correctly */
+ return (cam_iosched_now() - then);
+}
+
+static inline sbintime_t
+cam_iosched_sbintime_t(uintptr_t delta)
+{
+
+ /* Cast here is to widen the type so the left shift doesn't lose precision */
+ return (sbintime_t)((uint64_t)delta << CAM_IOSCHED_TIME_SHIFT);
+}
+
int cam_iosched_init(struct cam_iosched_softc **, struct cam_periph *periph);
void cam_iosched_fini(struct cam_iosched_softc *);
void cam_iosched_sysctl_init(struct cam_iosched_softc *, struct sysctl_ctx_list *, struct sysctl_oid *);
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index b29c0aa7079f..ec7169dd7b15 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <cam/cam.h>
#include <cam/cam_ccb.h>
+#include <cam/cam_iosched.h>
#include <cam/cam_periph.h>
#include <cam/cam_queue.h>
#include <cam/cam_sim.h>
@@ -3494,7 +3495,7 @@ xpt_run_devq(struct cam_devq *devq)
mtx_lock(mtx);
else
mtx = NULL;
- work_ccb->ccb_h.qos.sim_data = sbinuptime(); // xxx uintprt_t too small 32bit platforms
+ work_ccb->ccb_h.qos.periph_data = cam_iosched_now();
(*(sim->sim_action))(sim, work_ccb);
if (mtx)
mtx_unlock(mtx);
@@ -4641,7 +4642,7 @@ xpt_done(union ccb *done_ccb)
return;
/* Store the time the ccb was in the sim */
- done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data;
+ done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data);
hash = (done_ccb->ccb_h.path_id + done_ccb->ccb_h.target_id +
done_ccb->ccb_h.target_lun) % cam_num_doneqs;
queue = &cam_doneqs[hash];
@@ -4664,7 +4665,7 @@ xpt_done_direct(union ccb *done_ccb)
return;
/* Store the time the ccb was in the sim */
- done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data;
+ done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data);
xpt_done_process(&done_ccb->ccb_h);
}