1139743Simp/*-
239212Sgibbs * CAM request queue management definitions.
339212Sgibbs *
439212Sgibbs * Copyright (c) 1997 Justin T. Gibbs.
539212Sgibbs * All rights reserved.
639212Sgibbs *
739212Sgibbs * Redistribution and use in source and binary forms, with or without
839212Sgibbs * modification, are permitted provided that the following conditions
939212Sgibbs * are met:
1039212Sgibbs * 1. Redistributions of source code must retain the above copyright
1139212Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239212Sgibbs *    without modification, immediately at the beginning of the file.
1339212Sgibbs * 2. The name of the author may not be used to endorse or promote products
1439212Sgibbs *    derived from this software without specific prior written permission.
1539212Sgibbs *
1639212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2039212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639212Sgibbs * SUCH DAMAGE.
2739212Sgibbs *
2850477Speter * $FreeBSD$
2939212Sgibbs */
3039212Sgibbs
3139212Sgibbs#ifndef _CAM_CAM_QUEUE_H
3239212Sgibbs#define _CAM_CAM_QUEUE_H 1
3339212Sgibbs
3455206Speter#ifdef _KERNEL
3539212Sgibbs
36260387Sscottl#include <sys/lock.h>
37260387Sscottl#include <sys/mutex.h>
3839212Sgibbs#include <sys/queue.h>
39203108Smav#include <cam/cam.h>
4039212Sgibbs
4139212Sgibbs/*
4239212Sgibbs * This structure implements a heap based priority queue.  The queue
4339212Sgibbs * assumes that the objects stored in it begin with a cam_qentry
4439212Sgibbs * structure holding the priority information used to sort the objects.
4539212Sgibbs * This structure is opaque to clients (outside of the XPT layer) to allow
4639212Sgibbs * the implementation to change without affecting them.
4739212Sgibbs */
4839212Sgibbsstruct camq {
4939212Sgibbs	cam_pinfo **queue_array;
5039212Sgibbs	int	   array_size;
5139212Sgibbs	int	   entries;
5239212Sgibbs	u_int32_t  generation;
53249466Smav	u_int32_t  qfrozen_cnt;
5439212Sgibbs};
5539212Sgibbs
5660938SjakeTAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
5760938SjakeLIST_HEAD(ccb_hdr_list, ccb_hdr);
5860938SjakeSLIST_HEAD(ccb_hdr_slist, ccb_hdr);
5939212Sgibbs
6039212Sgibbsstruct cam_ccbq {
6139212Sgibbs	struct	camq queue;
62253958Smav	struct ccb_hdr_tailq	queue_extra_head;
63253958Smav	int	queue_extra_entries;
64260387Sscottl	int	total_openings;
65273078Smav	int	allocated;
66249466Smav	int	dev_openings;
6739212Sgibbs	int	dev_active;
6839212Sgibbs};
6939212Sgibbs
7039212Sgibbsstruct cam_ed;
7139212Sgibbs
7239212Sgibbsstruct cam_devq {
73260387Sscottl	struct mtx	 send_mtx;
74260387Sscottl	struct camq	 send_queue;
75260387Sscottl	int		 send_openings;
76260387Sscottl	int		 send_active;
7739212Sgibbs};
7839212Sgibbs
7939212Sgibbs
8039212Sgibbsstruct cam_devq *cam_devq_alloc(int devices, int openings);
8139212Sgibbs
8239212Sgibbsint		 cam_devq_init(struct cam_devq *devq, int devices,
8339212Sgibbs			       int openings);
8439212Sgibbs
8539212Sgibbsvoid		 cam_devq_free(struct cam_devq *devq);
8639212Sgibbs
8739212Sgibbsu_int32_t	 cam_devq_resize(struct cam_devq *camq, int openings);
8839212Sgibbs
8939212Sgibbs/*
9039212Sgibbs * Allocate a cam_ccb_queue structure and initialize it.
9139212Sgibbs */
9239212Sgibbsstruct cam_ccbq	*cam_ccbq_alloc(int openings);
9339212Sgibbs
9439212Sgibbsu_int32_t	cam_ccbq_resize(struct cam_ccbq *ccbq, int devices);
9539212Sgibbs
9639212Sgibbsint		cam_ccbq_init(struct cam_ccbq *ccbq, int openings);
9739212Sgibbs
9839212Sgibbsvoid		cam_ccbq_free(struct cam_ccbq *ccbq);
9939212Sgibbs
100198377Smavvoid		cam_ccbq_fini(struct cam_ccbq *ccbq);
101198377Smav
10239212Sgibbs/*
10339212Sgibbs * Allocate and initialize a cam_queue structure.
10439212Sgibbs */
10539212Sgibbsstruct camq	*camq_alloc(int size);
10639212Sgibbs
10739212Sgibbs/*
10839212Sgibbs * Resize a cam queue
10939212Sgibbs */
11039212Sgibbsu_int32_t	camq_resize(struct camq *queue, int new_size);
11139212Sgibbs
11239212Sgibbs/*
11339212Sgibbs * Initialize a camq structure.  Return 0 on success, 1 on failure.
11439212Sgibbs */
11539212Sgibbsint		camq_init(struct camq *camq, int size);
11639212Sgibbs
11739212Sgibbs/*
11839212Sgibbs * Free a cam_queue structure.  This should only be called if a controller
11939212Sgibbs * driver failes somehow during its attach routine or is unloaded and has
12039212Sgibbs * obtained a cam_queue structure.
12139212Sgibbs */
12239212Sgibbsvoid		camq_free(struct camq *queue);
12339212Sgibbs
12439212Sgibbs/*
12539212Sgibbs * Finialize any internal storage or state of a cam_queue.
12639212Sgibbs */
12739212Sgibbsvoid		camq_fini(struct camq *queue);
12839212Sgibbs
12939212Sgibbs/*
13039212Sgibbs * cam_queue_insert: Given a CAM queue with at least one open spot,
13139212Sgibbs * insert the new entry maintaining order.
13239212Sgibbs */
13339212Sgibbsvoid		camq_insert(struct camq *queue, cam_pinfo *new_entry);
13439212Sgibbs
13539212Sgibbs/*
13639212Sgibbs * camq_remove: Remove and arbitrary entry from the queue maintaining
13739212Sgibbs * queue order.
13839212Sgibbs */
13939212Sgibbscam_pinfo	*camq_remove(struct camq *queue, int index);
14045844Sgibbs#define CAMQ_HEAD 1	/* Head of queue index */
14139212Sgibbs
14245844Sgibbs/* Index the first element in the heap */
14345844Sgibbs#define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
14445844Sgibbs
145203108Smav/* Get the first element priority. */
146203108Smav#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ?			\
147203108Smav			    ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
148203108Smav
14939212Sgibbs/*
15039212Sgibbs * camq_change_priority: Raise or lower the priority of an entry
15139212Sgibbs * maintaining queue order.
15239212Sgibbs */
15339212Sgibbsvoid		camq_change_priority(struct camq *queue, int index,
15439212Sgibbs				     u_int32_t new_priority);
15539212Sgibbs
15639212Sgibbsstatic __inline int
15739212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
15839212Sgibbs
15939212Sgibbsstatic __inline void
16039212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq);
16139212Sgibbs
162249481Smavstatic __inline void
16339212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
16439212Sgibbs
165249481Smavstatic __inline void
16639212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
16739212Sgibbs
16839212Sgibbsstatic __inline union ccb *
16939212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index);
17039212Sgibbs
17139212Sgibbsstatic __inline void
17239212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *queue, union ccb *send_ccb);
17339212Sgibbs
17439212Sgibbsstatic __inline void
17539212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb);
17639212Sgibbs
17739212Sgibbsstatic __inline void
17839212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq);
17939212Sgibbs
18039212Sgibbs
18139212Sgibbsstatic __inline int
18239212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
18339212Sgibbs{
184253958Smav	return (ccbq->queue.entries + ccbq->queue_extra_entries);
18539212Sgibbs}
18639212Sgibbs
18739212Sgibbsstatic __inline void
18839212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq)
18939212Sgibbs{
190273078Smav
191273078Smav	ccbq->allocated++;
19239212Sgibbs}
19339212Sgibbs
194249481Smavstatic __inline void
19539212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
19639212Sgibbs{
197253958Smav	struct ccb_hdr *old_ccb;
198253958Smav	struct camq *queue = &ccbq->queue;
199253958Smav
200253958Smav	/*
201253958Smav	 * If queue is already full, try to resize.
202253958Smav	 * If resize fail, push CCB with lowest priority out to the TAILQ.
203253958Smav	 */
204253958Smav	if (queue->entries == queue->array_size &&
205253958Smav	    camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
206253958Smav		old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
207253958Smav		TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
208253958Smav		    xpt_links.tqe);
209253958Smav		old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
210253958Smav		ccbq->queue_extra_entries++;
211253958Smav	}
212253958Smav
213253958Smav	camq_insert(queue, &new_ccb->ccb_h.pinfo);
21439212Sgibbs}
21539212Sgibbs
216249481Smavstatic __inline void
21739212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
21839212Sgibbs{
219253958Smav	struct ccb_hdr *cccb, *bccb;
220253958Smav	struct camq *queue = &ccbq->queue;
221253958Smav
222253958Smav	/* If the CCB is on the TAILQ, remove it from there. */
223253958Smav	if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
224253958Smav		TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
225253958Smav		    xpt_links.tqe);
226253958Smav		ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
227253958Smav		ccbq->queue_extra_entries--;
228253958Smav		return;
229253958Smav	}
230253958Smav
231253958Smav	camq_remove(queue, ccb->ccb_h.pinfo.index);
232253958Smav
233253958Smav	/*
234253958Smav	 * If there are some CCBs on TAILQ, find the best one and move it
235253958Smav	 * to the emptied space in the queue.
236253958Smav	 */
237253958Smav	bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
238253958Smav	if (bccb == NULL)
239253958Smav		return;
240253958Smav	TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
241253958Smav		if (bccb->pinfo.priority > cccb->pinfo.priority ||
242253958Smav		    (bccb->pinfo.priority == cccb->pinfo.priority &&
243253958Smav		     GENERATIONCMP(bccb->pinfo.generation, >,
244253958Smav		      cccb->pinfo.generation)))
245253958Smav		        bccb = cccb;
246253958Smav	}
247253958Smav	TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
248253958Smav	ccbq->queue_extra_entries--;
249253958Smav	camq_insert(queue, &bccb->pinfo);
25039212Sgibbs}
25139212Sgibbs
25239212Sgibbsstatic __inline union ccb *
25339212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index)
25439212Sgibbs{
25539212Sgibbs	return((union ccb *)ccbq->queue.queue_array[index]);
25639212Sgibbs}
25739212Sgibbs
25839212Sgibbsstatic __inline void
25939212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *ccbq, union ccb *send_ccb)
26039212Sgibbs{
26139212Sgibbs
26239212Sgibbs	send_ccb->ccb_h.pinfo.index = CAM_ACTIVE_INDEX;
26339212Sgibbs	ccbq->dev_active++;
264273078Smav	ccbq->dev_openings--;
26539212Sgibbs}
26639212Sgibbs
26739212Sgibbsstatic __inline void
26839212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb)
26939212Sgibbs{
270199281Smav
27139212Sgibbs	ccbq->dev_active--;
272273078Smav	ccbq->dev_openings++;
27339212Sgibbs}
27439212Sgibbs
27539212Sgibbsstatic __inline void
27639212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq)
27739212Sgibbs{
278273078Smav
279273078Smav	ccbq->allocated--;
28039212Sgibbs}
28139212Sgibbs
28255206Speter#endif /* _KERNEL */
28339212Sgibbs#endif  /* _CAM_CAM_QUEUE_H */
284