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;
6539212Sgibbs	int	devq_openings;
66249466Smav	int	dev_openings;
6739212Sgibbs	int	dev_active;
6839212Sgibbs	int	held;
6939212Sgibbs};
7039212Sgibbs
7139212Sgibbsstruct cam_ed;
7239212Sgibbs
7339212Sgibbsstruct cam_devq {
74260387Sscottl	struct mtx	 send_mtx;
75260387Sscottl	struct camq	 send_queue;
76260387Sscottl	int		 send_openings;
77260387Sscottl	int		 send_active;
7839212Sgibbs};
7939212Sgibbs
8039212Sgibbs
8139212Sgibbsstruct cam_devq *cam_devq_alloc(int devices, int openings);
8239212Sgibbs
8339212Sgibbsint		 cam_devq_init(struct cam_devq *devq, int devices,
8439212Sgibbs			       int openings);
8539212Sgibbs
8639212Sgibbsvoid		 cam_devq_free(struct cam_devq *devq);
8739212Sgibbs
8839212Sgibbsu_int32_t	 cam_devq_resize(struct cam_devq *camq, int openings);
8939212Sgibbs
9039212Sgibbs/*
9139212Sgibbs * Allocate a cam_ccb_queue structure and initialize it.
9239212Sgibbs */
9339212Sgibbsstruct cam_ccbq	*cam_ccbq_alloc(int openings);
9439212Sgibbs
9539212Sgibbsu_int32_t	cam_ccbq_resize(struct cam_ccbq *ccbq, int devices);
9639212Sgibbs
9739212Sgibbsint		cam_ccbq_init(struct cam_ccbq *ccbq, int openings);
9839212Sgibbs
9939212Sgibbsvoid		cam_ccbq_free(struct cam_ccbq *ccbq);
10039212Sgibbs
101198377Smavvoid		cam_ccbq_fini(struct cam_ccbq *ccbq);
102198377Smav
10339212Sgibbs/*
10439212Sgibbs * Allocate and initialize a cam_queue structure.
10539212Sgibbs */
10639212Sgibbsstruct camq	*camq_alloc(int size);
10739212Sgibbs
10839212Sgibbs/*
10939212Sgibbs * Resize a cam queue
11039212Sgibbs */
11139212Sgibbsu_int32_t	camq_resize(struct camq *queue, int new_size);
11239212Sgibbs
11339212Sgibbs/*
11439212Sgibbs * Initialize a camq structure.  Return 0 on success, 1 on failure.
11539212Sgibbs */
11639212Sgibbsint		camq_init(struct camq *camq, int size);
11739212Sgibbs
11839212Sgibbs/*
11939212Sgibbs * Free a cam_queue structure.  This should only be called if a controller
12039212Sgibbs * driver failes somehow during its attach routine or is unloaded and has
12139212Sgibbs * obtained a cam_queue structure.
12239212Sgibbs */
12339212Sgibbsvoid		camq_free(struct camq *queue);
12439212Sgibbs
12539212Sgibbs/*
12639212Sgibbs * Finialize any internal storage or state of a cam_queue.
12739212Sgibbs */
12839212Sgibbsvoid		camq_fini(struct camq *queue);
12939212Sgibbs
13039212Sgibbs/*
13139212Sgibbs * cam_queue_insert: Given a CAM queue with at least one open spot,
13239212Sgibbs * insert the new entry maintaining order.
13339212Sgibbs */
13439212Sgibbsvoid		camq_insert(struct camq *queue, cam_pinfo *new_entry);
13539212Sgibbs
13639212Sgibbs/*
13739212Sgibbs * camq_remove: Remove and arbitrary entry from the queue maintaining
13839212Sgibbs * queue order.
13939212Sgibbs */
14039212Sgibbscam_pinfo	*camq_remove(struct camq *queue, int index);
14145844Sgibbs#define CAMQ_HEAD 1	/* Head of queue index */
14239212Sgibbs
14345844Sgibbs/* Index the first element in the heap */
14445844Sgibbs#define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
14545844Sgibbs
146203108Smav/* Get the first element priority. */
147203108Smav#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ?			\
148203108Smav			    ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
149203108Smav
15039212Sgibbs/*
15139212Sgibbs * camq_change_priority: Raise or lower the priority of an entry
15239212Sgibbs * maintaining queue order.
15339212Sgibbs */
15439212Sgibbsvoid		camq_change_priority(struct camq *queue, int index,
15539212Sgibbs				     u_int32_t new_priority);
15639212Sgibbs
15739212Sgibbsstatic __inline int
15839212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
15939212Sgibbs
16039212Sgibbsstatic __inline void
16139212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq);
16239212Sgibbs
163249481Smavstatic __inline void
16439212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
16539212Sgibbs
166249481Smavstatic __inline void
16739212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
16839212Sgibbs
16939212Sgibbsstatic __inline union ccb *
17039212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index);
17139212Sgibbs
17239212Sgibbsstatic __inline void
17339212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *queue, union ccb *send_ccb);
17439212Sgibbs
17539212Sgibbsstatic __inline void
17639212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb);
17739212Sgibbs
17839212Sgibbsstatic __inline void
17939212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq);
18039212Sgibbs
18139212Sgibbs
18239212Sgibbsstatic __inline int
18339212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
18439212Sgibbs{
185253958Smav	return (ccbq->queue.entries + ccbq->queue_extra_entries);
18639212Sgibbs}
18739212Sgibbs
18839212Sgibbsstatic __inline void
18939212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq)
19039212Sgibbs{
19139212Sgibbs	ccbq->devq_openings--;
19239212Sgibbs	ccbq->held++;
19339212Sgibbs}
19439212Sgibbs
195249481Smavstatic __inline void
19639212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
19739212Sgibbs{
198253958Smav	struct ccb_hdr *old_ccb;
199253958Smav	struct camq *queue = &ccbq->queue;
200253958Smav
20139212Sgibbs	ccbq->held--;
202253958Smav
203253958Smav	/*
204253958Smav	 * If queue is already full, try to resize.
205253958Smav	 * If resize fail, push CCB with lowest priority out to the TAILQ.
206253958Smav	 */
207253958Smav	if (queue->entries == queue->array_size &&
208253958Smav	    camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
209253958Smav		old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
210253958Smav		TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
211253958Smav		    xpt_links.tqe);
212253958Smav		old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
213253958Smav		ccbq->queue_extra_entries++;
214253958Smav	}
215253958Smav
216253958Smav	camq_insert(queue, &new_ccb->ccb_h.pinfo);
21739212Sgibbs}
21839212Sgibbs
219249481Smavstatic __inline void
22039212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
22139212Sgibbs{
222253958Smav	struct ccb_hdr *cccb, *bccb;
223253958Smav	struct camq *queue = &ccbq->queue;
224253958Smav
225253958Smav	/* If the CCB is on the TAILQ, remove it from there. */
226253958Smav	if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
227253958Smav		TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
228253958Smav		    xpt_links.tqe);
229253958Smav		ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
230253958Smav		ccbq->queue_extra_entries--;
231253958Smav		return;
232253958Smav	}
233253958Smav
234253958Smav	camq_remove(queue, ccb->ccb_h.pinfo.index);
235253958Smav
236253958Smav	/*
237253958Smav	 * If there are some CCBs on TAILQ, find the best one and move it
238253958Smav	 * to the emptied space in the queue.
239253958Smav	 */
240253958Smav	bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
241253958Smav	if (bccb == NULL)
242253958Smav		return;
243253958Smav	TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
244253958Smav		if (bccb->pinfo.priority > cccb->pinfo.priority ||
245253958Smav		    (bccb->pinfo.priority == cccb->pinfo.priority &&
246253958Smav		     GENERATIONCMP(bccb->pinfo.generation, >,
247253958Smav		      cccb->pinfo.generation)))
248253958Smav		        bccb = cccb;
249253958Smav	}
250253958Smav	TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
251253958Smav	ccbq->queue_extra_entries--;
252253958Smav	camq_insert(queue, &bccb->pinfo);
25339212Sgibbs}
25439212Sgibbs
25539212Sgibbsstatic __inline union ccb *
25639212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index)
25739212Sgibbs{
25839212Sgibbs	return((union ccb *)ccbq->queue.queue_array[index]);
25939212Sgibbs}
26039212Sgibbs
26139212Sgibbsstatic __inline void
26239212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *ccbq, union ccb *send_ccb)
26339212Sgibbs{
26439212Sgibbs
26539212Sgibbs	send_ccb->ccb_h.pinfo.index = CAM_ACTIVE_INDEX;
26639212Sgibbs	ccbq->dev_active++;
26739212Sgibbs	ccbq->dev_openings--;
26839212Sgibbs}
26939212Sgibbs
27039212Sgibbsstatic __inline void
27139212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb)
27239212Sgibbs{
273199281Smav
27439212Sgibbs	ccbq->dev_active--;
27539212Sgibbs	ccbq->dev_openings++;
27639212Sgibbs	ccbq->held++;
27739212Sgibbs}
27839212Sgibbs
27939212Sgibbsstatic __inline void
28039212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq)
28139212Sgibbs{
28239212Sgibbs	ccbq->held--;
28339212Sgibbs	ccbq->devq_openings++;
28439212Sgibbs}
28539212Sgibbs
28655206Speter#endif /* _KERNEL */
28739212Sgibbs#endif  /* _CAM_CAM_QUEUE_H */
288