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: stable/11/sys/cam/cam_queue.h 308352 2016-11-05 20:23:18Z markj $
2939212Sgibbs */
3039212Sgibbs
3139212Sgibbs#ifndef _CAM_CAM_QUEUE_H
3239212Sgibbs#define _CAM_CAM_QUEUE_H 1
3339212Sgibbs
3455206Speter#ifdef _KERNEL
3539212Sgibbs
36256843Smav#include <sys/lock.h>
37256843Smav#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;
64256843Smav	int	total_openings;
65271588Smav	int	allocated;
66249466Smav	int	dev_openings;
6739212Sgibbs	int	dev_active;
6839212Sgibbs};
6939212Sgibbs
7039212Sgibbsstruct cam_ed;
7139212Sgibbs
7239212Sgibbsstruct cam_devq {
73256843Smav	struct mtx	 send_mtx;
74256843Smav	struct camq	 send_queue;
75256843Smav	int		 send_openings;
76256843Smav	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{
190271588Smav
191271588Smav	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
200308352Smarkj	KASSERT((new_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0 &&
201308352Smarkj	    (new_ccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0,
202308352Smarkj	    ("%s: Cannot queue ccb %p func_code %#x", __func__, new_ccb,
203308352Smarkj	     new_ccb->ccb_h.func_code));
204308352Smarkj
205253958Smav	/*
206253958Smav	 * If queue is already full, try to resize.
207253958Smav	 * If resize fail, push CCB with lowest priority out to the TAILQ.
208253958Smav	 */
209253958Smav	if (queue->entries == queue->array_size &&
210253958Smav	    camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
211253958Smav		old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
212253958Smav		TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
213253958Smav		    xpt_links.tqe);
214253958Smav		old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
215253958Smav		ccbq->queue_extra_entries++;
216253958Smav	}
217253958Smav
218253958Smav	camq_insert(queue, &new_ccb->ccb_h.pinfo);
21939212Sgibbs}
22039212Sgibbs
221249481Smavstatic __inline void
22239212Sgibbscam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
22339212Sgibbs{
224253958Smav	struct ccb_hdr *cccb, *bccb;
225253958Smav	struct camq *queue = &ccbq->queue;
226308352Smarkj	cam_pinfo *removed_entry __unused;
227253958Smav
228253958Smav	/* If the CCB is on the TAILQ, remove it from there. */
229253958Smav	if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
230253958Smav		TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
231253958Smav		    xpt_links.tqe);
232253958Smav		ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
233253958Smav		ccbq->queue_extra_entries--;
234253958Smav		return;
235253958Smav	}
236253958Smav
237308352Smarkj	removed_entry = camq_remove(queue, ccb->ccb_h.pinfo.index);
238308352Smarkj	KASSERT(removed_entry == &ccb->ccb_h.pinfo,
239308352Smarkj	    ("%s: Removed wrong entry from queue (%p != %p)", __func__,
240308352Smarkj	     removed_entry, &ccb->ccb_h.pinfo));
241253958Smav
242253958Smav	/*
243253958Smav	 * If there are some CCBs on TAILQ, find the best one and move it
244253958Smav	 * to the emptied space in the queue.
245253958Smav	 */
246253958Smav	bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
247253958Smav	if (bccb == NULL)
248253958Smav		return;
249253958Smav	TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
250253958Smav		if (bccb->pinfo.priority > cccb->pinfo.priority ||
251253958Smav		    (bccb->pinfo.priority == cccb->pinfo.priority &&
252253958Smav		     GENERATIONCMP(bccb->pinfo.generation, >,
253253958Smav		      cccb->pinfo.generation)))
254253958Smav		        bccb = cccb;
255253958Smav	}
256253958Smav	TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
257253958Smav	ccbq->queue_extra_entries--;
258253958Smav	camq_insert(queue, &bccb->pinfo);
25939212Sgibbs}
26039212Sgibbs
26139212Sgibbsstatic __inline union ccb *
26239212Sgibbscam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index)
26339212Sgibbs{
26439212Sgibbs	return((union ccb *)ccbq->queue.queue_array[index]);
26539212Sgibbs}
26639212Sgibbs
26739212Sgibbsstatic __inline void
26839212Sgibbscam_ccbq_send_ccb(struct cam_ccbq *ccbq, union ccb *send_ccb)
26939212Sgibbs{
27039212Sgibbs
27139212Sgibbs	send_ccb->ccb_h.pinfo.index = CAM_ACTIVE_INDEX;
27239212Sgibbs	ccbq->dev_active++;
273271588Smav	ccbq->dev_openings--;
27439212Sgibbs}
27539212Sgibbs
27639212Sgibbsstatic __inline void
27739212Sgibbscam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb)
27839212Sgibbs{
279199281Smav
28039212Sgibbs	ccbq->dev_active--;
281271588Smav	ccbq->dev_openings++;
28239212Sgibbs}
28339212Sgibbs
28439212Sgibbsstatic __inline void
28539212Sgibbscam_ccbq_release_opening(struct cam_ccbq *ccbq)
28639212Sgibbs{
287271588Smav
288271588Smav	ccbq->allocated--;
28939212Sgibbs}
29039212Sgibbs
29155206Speter#endif /* _KERNEL */
29239212Sgibbs#endif  /* _CAM_CAM_QUEUE_H */
293