xref: /freebsd/sys/cam/cam_queue.h (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1898b0535SWarner Losh /*-
28b8a9b1dSJustin T. Gibbs  * CAM request queue management definitions.
38b8a9b1dSJustin T. Gibbs  *
44d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
5bec9534dSPedro F. Giffuni  *
68b8a9b1dSJustin T. Gibbs  * Copyright (c) 1997 Justin T. Gibbs.
78b8a9b1dSJustin T. Gibbs  * All rights reserved.
88b8a9b1dSJustin T. Gibbs  *
98b8a9b1dSJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
108b8a9b1dSJustin T. Gibbs  * modification, are permitted provided that the following conditions
118b8a9b1dSJustin T. Gibbs  * are met:
128b8a9b1dSJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
138b8a9b1dSJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
148b8a9b1dSJustin T. Gibbs  *    without modification, immediately at the beginning of the file.
158b8a9b1dSJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
168b8a9b1dSJustin T. Gibbs  *    derived from this software without specific prior written permission.
178b8a9b1dSJustin T. Gibbs  *
188b8a9b1dSJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
198b8a9b1dSJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
208b8a9b1dSJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
218b8a9b1dSJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
228b8a9b1dSJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
238b8a9b1dSJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
248b8a9b1dSJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
258b8a9b1dSJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
268b8a9b1dSJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
278b8a9b1dSJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
288b8a9b1dSJustin T. Gibbs  * SUCH DAMAGE.
298b8a9b1dSJustin T. Gibbs  */
308b8a9b1dSJustin T. Gibbs 
318b8a9b1dSJustin T. Gibbs #ifndef _CAM_CAM_QUEUE_H
328b8a9b1dSJustin T. Gibbs #define _CAM_CAM_QUEUE_H 1
338b8a9b1dSJustin T. Gibbs 
34c4473420SPeter Wemm #ifdef _KERNEL
358b8a9b1dSJustin T. Gibbs 
36227d67aaSAlexander Motin #include <sys/lock.h>
37227d67aaSAlexander Motin #include <sys/mutex.h>
388b8a9b1dSJustin T. Gibbs #include <sys/queue.h>
3983c5d981SAlexander Motin #include <cam/cam.h>
408b8a9b1dSJustin T. Gibbs 
418b8a9b1dSJustin T. Gibbs /*
428b8a9b1dSJustin T. Gibbs  * This structure implements a heap based priority queue.  The queue
438b8a9b1dSJustin T. Gibbs  * assumes that the objects stored in it begin with a cam_qentry
448b8a9b1dSJustin T. Gibbs  * structure holding the priority information used to sort the objects.
458b8a9b1dSJustin T. Gibbs  * This structure is opaque to clients (outside of the XPT layer) to allow
468b8a9b1dSJustin T. Gibbs  * the implementation to change without affecting them.
478b8a9b1dSJustin T. Gibbs  */
488b8a9b1dSJustin T. Gibbs struct camq {
498b8a9b1dSJustin T. Gibbs 	cam_pinfo **queue_array;
508b8a9b1dSJustin T. Gibbs 	int	   array_size;
518b8a9b1dSJustin T. Gibbs 	int	   entries;
52*7af2f2c8SWarner Losh 	uint32_t  generation;
53*7af2f2c8SWarner Losh 	uint32_t  qfrozen_cnt;
548b8a9b1dSJustin T. Gibbs };
558b8a9b1dSJustin T. Gibbs 
56e3975643SJake Burkholder TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
57e3975643SJake Burkholder LIST_HEAD(ccb_hdr_list, ccb_hdr);
58e3975643SJake Burkholder SLIST_HEAD(ccb_hdr_slist, ccb_hdr);
598b8a9b1dSJustin T. Gibbs 
608b8a9b1dSJustin T. Gibbs struct cam_ccbq {
618b8a9b1dSJustin T. Gibbs 	struct	camq queue;
62ea541bfdSAlexander Motin 	struct ccb_hdr_tailq	queue_extra_head;
63ea541bfdSAlexander Motin 	int	queue_extra_entries;
64227d67aaSAlexander Motin 	int	total_openings;
65959ec258SAlexander Motin 	int	allocated;
668b8a9b1dSJustin T. Gibbs 	int	dev_openings;
678b8a9b1dSJustin T. Gibbs 	int	dev_active;
688b8a9b1dSJustin T. Gibbs };
698b8a9b1dSJustin T. Gibbs 
708b8a9b1dSJustin T. Gibbs struct cam_ed;
718b8a9b1dSJustin T. Gibbs 
728b8a9b1dSJustin T. Gibbs struct cam_devq {
73227d67aaSAlexander Motin 	struct mtx	 send_mtx;
748b8a9b1dSJustin T. Gibbs 	struct camq	 send_queue;
758b8a9b1dSJustin T. Gibbs 	int		 send_openings;
768b8a9b1dSJustin T. Gibbs 	int		 send_active;
778b8a9b1dSJustin T. Gibbs };
788b8a9b1dSJustin T. Gibbs 
798b8a9b1dSJustin T. Gibbs struct cam_devq *cam_devq_alloc(int devices, int openings);
808b8a9b1dSJustin T. Gibbs 
818b8a9b1dSJustin T. Gibbs int		 cam_devq_init(struct cam_devq *devq, int devices,
828b8a9b1dSJustin T. Gibbs 			       int openings);
838b8a9b1dSJustin T. Gibbs 
848b8a9b1dSJustin T. Gibbs void		 cam_devq_free(struct cam_devq *devq);
858b8a9b1dSJustin T. Gibbs 
86*7af2f2c8SWarner Losh uint32_t	 cam_devq_resize(struct cam_devq *camq, int openings);
878b8a9b1dSJustin T. Gibbs 
888b8a9b1dSJustin T. Gibbs /*
898b8a9b1dSJustin T. Gibbs  * Allocate a cam_ccb_queue structure and initialize it.
908b8a9b1dSJustin T. Gibbs  */
918b8a9b1dSJustin T. Gibbs struct cam_ccbq	*cam_ccbq_alloc(int openings);
928b8a9b1dSJustin T. Gibbs 
93*7af2f2c8SWarner Losh uint32_t	cam_ccbq_resize(struct cam_ccbq *ccbq, int devices);
948b8a9b1dSJustin T. Gibbs 
958b8a9b1dSJustin T. Gibbs int		cam_ccbq_init(struct cam_ccbq *ccbq, int openings);
968b8a9b1dSJustin T. Gibbs 
978b8a9b1dSJustin T. Gibbs void		cam_ccbq_free(struct cam_ccbq *ccbq);
988b8a9b1dSJustin T. Gibbs 
9920a7933fSAlexander Motin void		cam_ccbq_fini(struct cam_ccbq *ccbq);
10020a7933fSAlexander Motin 
1018b8a9b1dSJustin T. Gibbs /*
1028b8a9b1dSJustin T. Gibbs  * Resize a cam queue
1038b8a9b1dSJustin T. Gibbs  */
104*7af2f2c8SWarner Losh uint32_t	camq_resize(struct camq *queue, int new_size);
1058b8a9b1dSJustin T. Gibbs 
1068b8a9b1dSJustin T. Gibbs /*
1078b8a9b1dSJustin T. Gibbs  * Initialize a camq structure.  Return 0 on success, 1 on failure.
1088b8a9b1dSJustin T. Gibbs  */
1098b8a9b1dSJustin T. Gibbs int		camq_init(struct camq *camq, int size);
1108b8a9b1dSJustin T. Gibbs 
1118b8a9b1dSJustin T. Gibbs /*
1128b8a9b1dSJustin T. Gibbs  * Finialize any internal storage or state of a cam_queue.
1138b8a9b1dSJustin T. Gibbs  */
1148b8a9b1dSJustin T. Gibbs void		camq_fini(struct camq *queue);
1158b8a9b1dSJustin T. Gibbs 
1168b8a9b1dSJustin T. Gibbs /*
1178b8a9b1dSJustin T. Gibbs  * cam_queue_insert: Given a CAM queue with at least one open spot,
1188b8a9b1dSJustin T. Gibbs  * insert the new entry maintaining order.
1198b8a9b1dSJustin T. Gibbs  */
1208b8a9b1dSJustin T. Gibbs void		camq_insert(struct camq *queue, cam_pinfo *new_entry);
1218b8a9b1dSJustin T. Gibbs 
1228b8a9b1dSJustin T. Gibbs /*
1238b8a9b1dSJustin T. Gibbs  * camq_remove: Remove and arbitrary entry from the queue maintaining
1248b8a9b1dSJustin T. Gibbs  * queue order.
1258b8a9b1dSJustin T. Gibbs  */
1268b8a9b1dSJustin T. Gibbs cam_pinfo	*camq_remove(struct camq *queue, int index);
1275a526431SJustin T. Gibbs #define CAMQ_HEAD 1	/* Head of queue index */
1285a526431SJustin T. Gibbs 
1295a526431SJustin T. Gibbs /* Index the first element in the heap */
1305a526431SJustin T. Gibbs #define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
1318b8a9b1dSJustin T. Gibbs 
13283c5d981SAlexander Motin /* Get the first element priority. */
13383c5d981SAlexander Motin #define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ?			\
13483c5d981SAlexander Motin 			    ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
13583c5d981SAlexander Motin 
1368b8a9b1dSJustin T. Gibbs /*
1378b8a9b1dSJustin T. Gibbs  * camq_change_priority: Raise or lower the priority of an entry
1388b8a9b1dSJustin T. Gibbs  * maintaining queue order.
1398b8a9b1dSJustin T. Gibbs  */
1408b8a9b1dSJustin T. Gibbs void		camq_change_priority(struct camq *queue, int index,
141*7af2f2c8SWarner Losh 				     uint32_t new_priority);
1428b8a9b1dSJustin T. Gibbs 
1438b8a9b1dSJustin T. Gibbs static __inline int
cam_ccbq_pending_ccb_count(struct cam_ccbq * ccbq)1448b8a9b1dSJustin T. Gibbs cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
1458b8a9b1dSJustin T. Gibbs {
146ea541bfdSAlexander Motin 	return (ccbq->queue.entries + ccbq->queue_extra_entries);
1478b8a9b1dSJustin T. Gibbs }
1488b8a9b1dSJustin T. Gibbs 
1498b8a9b1dSJustin T. Gibbs static __inline void
cam_ccbq_take_opening(struct cam_ccbq * ccbq)1508b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(struct cam_ccbq *ccbq)
1518b8a9b1dSJustin T. Gibbs {
152959ec258SAlexander Motin 
153959ec258SAlexander Motin 	ccbq->allocated++;
1548b8a9b1dSJustin T. Gibbs }
1558b8a9b1dSJustin T. Gibbs 
1561268d481SAlexander Motin static __inline void
cam_ccbq_insert_ccb(struct cam_ccbq * ccbq,union ccb * new_ccb)1578b8a9b1dSJustin T. Gibbs cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
1588b8a9b1dSJustin T. Gibbs {
159ea541bfdSAlexander Motin 	struct ccb_hdr *old_ccb;
160ea541bfdSAlexander Motin 	struct camq *queue = &ccbq->queue;
161ea541bfdSAlexander Motin 
162f30cad33SMark Johnston 	KASSERT((new_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0 &&
163f30cad33SMark Johnston 	    (new_ccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0,
164f30cad33SMark Johnston 	    ("%s: Cannot queue ccb %p func_code %#x", __func__, new_ccb,
165f30cad33SMark Johnston 	     new_ccb->ccb_h.func_code));
166f30cad33SMark Johnston 
167ea541bfdSAlexander Motin 	/*
168ea541bfdSAlexander Motin 	 * If queue is already full, try to resize.
169ea541bfdSAlexander Motin 	 * If resize fail, push CCB with lowest priority out to the TAILQ.
170ea541bfdSAlexander Motin 	 */
171ea541bfdSAlexander Motin 	if (queue->entries == queue->array_size &&
172ea541bfdSAlexander Motin 	    camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
173ea541bfdSAlexander Motin 		old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
174ea541bfdSAlexander Motin 		TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
175ea541bfdSAlexander Motin 		    xpt_links.tqe);
176ea541bfdSAlexander Motin 		old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
177ea541bfdSAlexander Motin 		ccbq->queue_extra_entries++;
178ea541bfdSAlexander Motin 	}
179ea541bfdSAlexander Motin 
180ea541bfdSAlexander Motin 	camq_insert(queue, &new_ccb->ccb_h.pinfo);
1818b8a9b1dSJustin T. Gibbs }
1828b8a9b1dSJustin T. Gibbs 
1831268d481SAlexander Motin static __inline void
cam_ccbq_remove_ccb(struct cam_ccbq * ccbq,union ccb * ccb)1848b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
1858b8a9b1dSJustin T. Gibbs {
186ea541bfdSAlexander Motin 	struct ccb_hdr *cccb, *bccb;
187ea541bfdSAlexander Motin 	struct camq *queue = &ccbq->queue;
188f30cad33SMark Johnston 	cam_pinfo *removed_entry __unused;
189ea541bfdSAlexander Motin 
190ea541bfdSAlexander Motin 	/* If the CCB is on the TAILQ, remove it from there. */
191ea541bfdSAlexander Motin 	if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
192ea541bfdSAlexander Motin 		TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
193ea541bfdSAlexander Motin 		    xpt_links.tqe);
194ea541bfdSAlexander Motin 		ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
195ea541bfdSAlexander Motin 		ccbq->queue_extra_entries--;
196ea541bfdSAlexander Motin 		return;
197ea541bfdSAlexander Motin 	}
198ea541bfdSAlexander Motin 
199f30cad33SMark Johnston 	removed_entry = camq_remove(queue, ccb->ccb_h.pinfo.index);
200f30cad33SMark Johnston 	KASSERT(removed_entry == &ccb->ccb_h.pinfo,
201f30cad33SMark Johnston 	    ("%s: Removed wrong entry from queue (%p != %p)", __func__,
202f30cad33SMark Johnston 	     removed_entry, &ccb->ccb_h.pinfo));
203ea541bfdSAlexander Motin 
204ea541bfdSAlexander Motin 	/*
205ea541bfdSAlexander Motin 	 * If there are some CCBs on TAILQ, find the best one and move it
206ea541bfdSAlexander Motin 	 * to the emptied space in the queue.
207ea541bfdSAlexander Motin 	 */
208ea541bfdSAlexander Motin 	bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
209ea541bfdSAlexander Motin 	if (bccb == NULL)
210ea541bfdSAlexander Motin 		return;
211ea541bfdSAlexander Motin 	TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
212ea541bfdSAlexander Motin 		if (bccb->pinfo.priority > cccb->pinfo.priority ||
213ea541bfdSAlexander Motin 		    (bccb->pinfo.priority == cccb->pinfo.priority &&
214ea541bfdSAlexander Motin 		     GENERATIONCMP(bccb->pinfo.generation, >,
215ea541bfdSAlexander Motin 		      cccb->pinfo.generation)))
216ea541bfdSAlexander Motin 		        bccb = cccb;
217ea541bfdSAlexander Motin 	}
218ea541bfdSAlexander Motin 	TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
219ea541bfdSAlexander Motin 	ccbq->queue_extra_entries--;
220ea541bfdSAlexander Motin 	camq_insert(queue, &bccb->pinfo);
2218b8a9b1dSJustin T. Gibbs }
2228b8a9b1dSJustin T. Gibbs 
2238b8a9b1dSJustin T. Gibbs static __inline union ccb *
cam_ccbq_peek_ccb(struct cam_ccbq * ccbq,int index)2248b8a9b1dSJustin T. Gibbs cam_ccbq_peek_ccb(struct cam_ccbq *ccbq, int index)
2258b8a9b1dSJustin T. Gibbs {
2268b8a9b1dSJustin T. Gibbs 	return((union ccb *)ccbq->queue.queue_array[index]);
2278b8a9b1dSJustin T. Gibbs }
2288b8a9b1dSJustin T. Gibbs 
2298b8a9b1dSJustin T. Gibbs static __inline void
cam_ccbq_send_ccb(struct cam_ccbq * ccbq,union ccb * send_ccb)2308b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(struct cam_ccbq *ccbq, union ccb *send_ccb)
2318b8a9b1dSJustin T. Gibbs {
2328b8a9b1dSJustin T. Gibbs 
2338b8a9b1dSJustin T. Gibbs 	send_ccb->ccb_h.pinfo.index = CAM_ACTIVE_INDEX;
2348b8a9b1dSJustin T. Gibbs 	ccbq->dev_active++;
2358b8a9b1dSJustin T. Gibbs 	ccbq->dev_openings--;
2368b8a9b1dSJustin T. Gibbs }
2378b8a9b1dSJustin T. Gibbs 
2388b8a9b1dSJustin T. Gibbs static __inline void
cam_ccbq_ccb_done(struct cam_ccbq * ccbq,union ccb * done_ccb)2398b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(struct cam_ccbq *ccbq, union ccb *done_ccb)
2408b8a9b1dSJustin T. Gibbs {
2411f1158b2SAlexander Motin 
2428b8a9b1dSJustin T. Gibbs 	ccbq->dev_active--;
2438b8a9b1dSJustin T. Gibbs 	ccbq->dev_openings++;
2448b8a9b1dSJustin T. Gibbs }
2458b8a9b1dSJustin T. Gibbs 
2468b8a9b1dSJustin T. Gibbs static __inline void
cam_ccbq_release_opening(struct cam_ccbq * ccbq)2478b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(struct cam_ccbq *ccbq)
2488b8a9b1dSJustin T. Gibbs {
249959ec258SAlexander Motin 
250959ec258SAlexander Motin 	ccbq->allocated--;
2518b8a9b1dSJustin T. Gibbs }
2528b8a9b1dSJustin T. Gibbs 
253c4473420SPeter Wemm #endif /* _KERNEL */
2548b8a9b1dSJustin T. Gibbs #endif  /* _CAM_CAM_QUEUE_H */
255