summaryrefslogtreecommitdiffstats
path: root/sys/cam/cam_queue.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/cam_queue.h')
-rw-r--r--sys/cam/cam_queue.h105
1 files changed, 100 insertions, 5 deletions
diff --git a/sys/cam/cam_queue.h b/sys/cam/cam_queue.h
index 31f9bc2..dd9f9a7 100644
--- a/sys/cam/cam_queue.h
+++ b/sys/cam/cam_queue.h
@@ -34,6 +34,7 @@
#ifdef _KERNEL
#include <sys/queue.h>
+#include <cam/cam.h>
/*
* This structure implements a heap based priority queue. The queue
@@ -47,7 +48,7 @@ struct camq {
int array_size;
int entries;
u_int32_t generation;
- u_int32_t qfrozen_cnt;
+ u_int32_t qfrozen_cnt[CAM_RL_VALUES];
};
TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
@@ -140,6 +141,10 @@ cam_pinfo *camq_remove(struct camq *queue, int index);
/* Index the first element in the heap */
#define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
+/* Get the first element priority. */
+#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ? \
+ ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
+
/*
* camq_change_priority: Raise or lower the priority of an entry
* maintaining queue order.
@@ -153,10 +158,10 @@ cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
static __inline void
cam_ccbq_take_opening(struct cam_ccbq *ccbq);
-static __inline void
+static __inline int
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
-static __inline void
+static __inline int
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
static __inline union ccb *
@@ -185,17 +190,31 @@ cam_ccbq_take_opening(struct cam_ccbq *ccbq)
ccbq->held++;
}
-static __inline void
+static __inline int
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
{
ccbq->held--;
camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo);
+ if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+ new_ccb->ccb_h.pinfo.priority)] > 0) {
+ ccbq->devq_openings++;
+ ccbq->held++;
+ return (1);
+ } else
+ return (0);
}
-static __inline void
+static __inline int
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
{
camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index);
+ if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+ ccb->ccb_h.pinfo.priority)] > 0) {
+ ccbq->devq_openings--;
+ ccbq->held--;
+ return (1);
+ } else
+ return (0);
}
static __inline union ccb *
@@ -229,5 +248,81 @@ cam_ccbq_release_opening(struct cam_ccbq *ccbq)
ccbq->devq_openings++;
}
+static __inline int
+cam_ccbq_freeze(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+ int i, frozen = 0;
+ cam_rl p, n;
+
+ /* Find pevious run level. */
+ for (p = 0; p < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[p] == 0; p++);
+ /* Find new run level. */
+ n = min(rl, p);
+ /* Apply new run level. */
+ for (i = rl; i < CAM_RL_VALUES; i++)
+ ccbq->queue.qfrozen_cnt[i] += cnt;
+ /* Update ccbq statistics. */
+ if (n == p)
+ return (0);
+ for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+ cam_rl rrl =
+ CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+ if (rrl < n)
+ continue;
+ if (rrl >= p)
+ break;
+ ccbq->devq_openings++;
+ ccbq->held++;
+ frozen++;
+ }
+ return (frozen);
+}
+
+static __inline int
+cam_ccbq_release(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+ int i, released = 0;
+ cam_rl p, n;
+
+ /* Apply new run level. */
+ for (i = rl; i < CAM_RL_VALUES; i++)
+ ccbq->queue.qfrozen_cnt[i] -= cnt;
+ /* Find new run level. */
+ for (n = 0; n < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[n] == 0; n++);
+ /* Find previous run level. */
+ p = min(rl, n);
+ /* Update ccbq statistics. */
+ if (n == p)
+ return (0);
+ for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+ cam_rl rrl =
+ CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+ if (rrl < p)
+ continue;
+ if (rrl >= n)
+ break;
+ ccbq->devq_openings--;
+ ccbq->held--;
+ released++;
+ }
+ return (released);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen(struct cam_ccbq *ccbq, cam_rl rl)
+{
+
+ return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen_top(struct cam_ccbq *ccbq)
+{
+ cam_rl rl;
+
+ rl = CAM_PRIORITY_TO_RL(CAMQ_GET_PRIO(&ccbq->queue));
+ return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_QUEUE_H */
OpenPOWER on IntegriCloud