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
3639212Sgibbs#include <sys/queue.h>
37203108Smav#include <cam/cam.h>
3839212Sgibbs
3939212Sgibbs/*
4039212Sgibbs * This structure implements a heap based priority queue.  The queue
4139212Sgibbs * assumes that the objects stored in it begin with a cam_qentry
4239212Sgibbs * structure holding the priority information used to sort the objects.
4339212Sgibbs * This structure is opaque to clients (outside of the XPT layer) to allow
4439212Sgibbs * the implementation to change without affecting them.
4539212Sgibbs */
4639212Sgibbsstruct camq {
4739212Sgibbs	cam_pinfo **queue_array;
4839212Sgibbs	int	   array_size;
4939212Sgibbs	int	   entries;
5039212Sgibbs	u_int32_t  generation;
51256216Smav	u_int32_t  qfrozen_cnt;
5239212Sgibbs};
5339212Sgibbs
5460938SjakeTAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
5560938SjakeLIST_HEAD(ccb_hdr_list, ccb_hdr);
5660938SjakeSLIST_HEAD(ccb_hdr_slist, ccb_hdr);
5739212Sgibbs
5839212Sgibbsstruct cam_ccbq {
5939212Sgibbs	struct	camq queue;
60256220Smav	struct ccb_hdr_tailq	queue_extra_head;
61256220Smav	int	queue_extra_entries;
6239212Sgibbs	int	devq_openings;
63256216Smav	int	devq_allocating;
64256216Smav	int	dev_openings;
6539212Sgibbs	int	dev_active;
6639212Sgibbs	int	held;
6739212Sgibbs};
6839212Sgibbs
6939212Sgibbsstruct cam_ed;
7039212Sgibbs
7139212Sgibbsstruct cam_devq {
7239212Sgibbs	struct	camq send_queue;
7339212Sgibbs	int	send_openings;
7439212Sgibbs	int	send_active;
7539212Sgibbs};
7639212Sgibbs
7739212Sgibbs
7839212Sgibbsstruct cam_devq *cam_devq_alloc(int devices, int openings);
7939212Sgibbs
8039212Sgibbsint		 cam_devq_init(struct cam_devq *devq, int devices,
8139212Sgibbs			       int openings);
8239212Sgibbs
8339212Sgibbsvoid		 cam_devq_free(struct cam_devq *devq);
8439212Sgibbs
8539212Sgibbsu_int32_t	 cam_devq_resize(struct cam_devq *camq, int openings);
8639212Sgibbs
8739212Sgibbs/*
8839212Sgibbs * Allocate a cam_ccb_queue structure and initialize it.
8939212Sgibbs */
9039212Sgibbsstruct cam_ccbq	*cam_ccbq_alloc(int openings);
9139212Sgibbs
9239212Sgibbsu_int32_t	cam_ccbq_resize(struct cam_ccbq *ccbq, int devices);
9339212Sgibbs
9439212Sgibbsint		cam_ccbq_init(struct cam_ccbq *ccbq, int openings);
9539212Sgibbs
9639212Sgibbsvoid		cam_ccbq_free(struct cam_ccbq *ccbq);
9739212Sgibbs
98198377Smavvoid		cam_ccbq_fini(struct cam_ccbq *ccbq);
99198377Smav
10039212Sgibbs/*
10139212Sgibbs * Allocate and initialize a cam_queue structure.
10239212Sgibbs */
10339212Sgibbsstruct camq	*camq_alloc(int size);
10439212Sgibbs
10539212Sgibbs/*
10639212Sgibbs * Resize a cam queue
10739212Sgibbs */
10839212Sgibbsu_int32_t	camq_resize(struct camq *queue, int new_size);
10939212Sgibbs
11039212Sgibbs/*
11139212Sgibbs * Initialize a camq structure.  Return 0 on success, 1 on failure.
11239212Sgibbs */
11339212Sgibbsint		camq_init(struct camq *camq, int size);
11439212Sgibbs
11539212Sgibbs/*
11639212Sgibbs * Free a cam_queue structure.  This should only be called if a controller
11739212Sgibbs * driver failes somehow during its attach routine or is unloaded and has
11839212Sgibbs * obtained a cam_queue structure.
11939212Sgibbs */
12039212Sgibbsvoid		camq_free(struct camq *queue);
12139212Sgibbs
12239212Sgibbs/*
12339212Sgibbs * Finialize any internal storage or state of a cam_queue.
12439212Sgibbs */
12539212Sgibbsvoid		camq_fini(struct camq *queue);
12639212Sgibbs
12739212Sgibbs/*
12839212Sgibbs * cam_queue_insert: Given a CAM queue with at least one open spot,
12939212Sgibbs * insert the new entry maintaining order.
13039212Sgibbs */
13139212Sgibbsvoid		camq_insert(struct camq *queue, cam_pinfo *new_entry);
13239212Sgibbs
13339212Sgibbs/*
13439212Sgibbs * camq_remove: Remove and arbitrary entry from the queue maintaining
13539212Sgibbs * queue order.
13639212Sgibbs */
13739212Sgibbscam_pinfo	*camq_remove(struct camq *queue, int index);
13845844Sgibbs#define CAMQ_HEAD 1	/* Head of queue index */
13939212Sgibbs
14045844Sgibbs/* Index the first element in the heap */
14145844Sgibbs#define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
14245844Sgibbs
143203108Smav/* Get the first element priority. */
144203108Smav#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ?			\
145203108Smav			    ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
146203108Smav
14739212Sgibbs/*
14839212Sgibbs * camq_change_priority: Raise or lower the priority of an entry
14939212Sgibbs * maintaining queue order.
15039212Sgibbs */
15139212Sgibbsvoid		camq_change_priority(struct camq *queue, int index,
15239212Sgibbs				     u_int32_t new_priority);
15339212Sgibbs
15439212Sgibbsstatic __inline int
15539212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
15639212Sgibbs
15739212Sgibbsstatic __inline void
15839212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq);
15939212Sgibbs
160256216Smavstatic __inline void
16139212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
16239212Sgibbs
163256216Smavstatic __inline void
16439212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
16539212Sgibbs
16639212Sgibbsstatic __inline union ccb *
16739212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index);
16839212Sgibbs
16939212Sgibbsstatic __inline void
17039212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *queue, union ccb *send_ccb);
17139212Sgibbs
17239212Sgibbsstatic __inline void
17339212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb);
17439212Sgibbs
17539212Sgibbsstatic __inline void
17639212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq);
17739212Sgibbs
17839212Sgibbs
17939212Sgibbsstatic __inline int
18039212Sgibbscam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
18139212Sgibbs{
182256220Smav	return (ccbq->queue.entries + ccbq->queue_extra_entries);
18339212Sgibbs}
18439212Sgibbs
18539212Sgibbsstatic __inline void
18639212Sgibbscam_ccbq_take_opening(struct cam_ccbq *ccbq)
18739212Sgibbs{
18839212Sgibbs	ccbq->devq_openings--;
18939212Sgibbs	ccbq->held++;
19039212Sgibbs}
19139212Sgibbs
192256216Smavstatic __inline void
19339212Sgibbscam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
19439212Sgibbs{
195256220Smav	struct ccb_hdr *old_ccb;
196256220Smav	struct camq *queue = &ccbq->queue;
197256220Smav
19839212Sgibbs	ccbq->held--;
199256220Smav
200256220Smav	/*
201256220Smav	 * If queue is already full, try to resize.
202256220Smav	 * If resize fail, push CCB with lowest priority out to the TAILQ.
203256220Smav	 */
204256220Smav	if (queue->entries == queue->array_size &&
205256220Smav	    camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
206256220Smav		old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
207256220Smav		TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
208256220Smav		    xpt_links.tqe);
209256220Smav		old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
210256220Smav		ccbq->queue_extra_entries++;
211256220Smav	}
212256220Smav
213256220Smav	camq_insert(queue, &new_ccb->ccb_h.pinfo);
21439212Sgibbs}
21539212Sgibbs
216256216Smavstatic __inline void
21739212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
21839212Sgibbs{
219256220Smav	struct ccb_hdr *cccb, *bccb;
220256220Smav	struct camq *queue = &ccbq->queue;
221256220Smav
222256220Smav	/* If the CCB is on the TAILQ, remove it from there. */
223256220Smav	if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
224256220Smav		TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
225256220Smav		    xpt_links.tqe);
226256220Smav		ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
227256220Smav		ccbq->queue_extra_entries--;
228256220Smav		return;
229256220Smav	}
230256220Smav
231256220Smav	camq_remove(queue, ccb->ccb_h.pinfo.index);
232256220Smav
233256220Smav	/*
234256220Smav	 * If there are some CCBs on TAILQ, find the best one and move it
235256220Smav	 * to the emptied space in the queue.
236256220Smav	 */
237256220Smav	bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
238256220Smav	if (bccb == NULL)
239256220Smav		return;
240256220Smav	TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
241256220Smav		if (bccb->pinfo.priority > cccb->pinfo.priority ||
242256220Smav		    (bccb->pinfo.priority == cccb->pinfo.priority &&
243256220Smav		     GENERATIONCMP(bccb->pinfo.generation, >,
244256220Smav		      cccb->pinfo.generation)))
245256220Smav		        bccb = cccb;
246256220Smav	}
247256220Smav	TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
248256220Smav	ccbq->queue_extra_entries--;
249256220Smav	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++;
26439212Sgibbs	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--;
27239212Sgibbs	ccbq->dev_openings++;
27339212Sgibbs	ccbq->held++;
27439212Sgibbs}
27539212Sgibbs
27639212Sgibbsstatic __inline void
27739212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq)
27839212Sgibbs{
27939212Sgibbs	ccbq->held--;
28039212Sgibbs	ccbq->devq_openings++;
28139212Sgibbs}
28239212Sgibbs
28355206Speter#endif /* _KERNEL */
28439212Sgibbs#endif  /* _CAM_CAM_QUEUE_H */
285