1139743Simp/*-
239212Sgibbs * CAM request queue management functions.
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 */
28116161Sobrien
29116161Sobrien#include <sys/cdefs.h>
30116161Sobrien__FBSDID("$FreeBSD$");
31116161Sobrien
3239212Sgibbs#include <sys/param.h>
3339212Sgibbs#include <sys/systm.h>
3439212Sgibbs#include <sys/types.h>
3539212Sgibbs#include <sys/malloc.h>
36147723Savatar#include <sys/kernel.h>
3739212Sgibbs
3839212Sgibbs#include <cam/cam.h>
3939212Sgibbs#include <cam/cam_ccb.h>
4039212Sgibbs#include <cam/cam_queue.h>
4139212Sgibbs#include <cam/cam_debug.h>
4239212Sgibbs
43227293Sedstatic MALLOC_DEFINE(M_CAMQ, "CAM queue", "CAM queue buffers");
44227293Sedstatic MALLOC_DEFINE(M_CAMDEVQ, "CAM dev queue", "CAM dev queue buffers");
45227293Sedstatic MALLOC_DEFINE(M_CAMCCBQ, "CAM ccb queue", "CAM ccb queue buffers");
46147723Savatar
4739212Sgibbsstatic __inline int
4839212Sgibbs		queue_cmp(cam_pinfo **queue_array, int i, int j);
4939212Sgibbsstatic __inline void
5039212Sgibbs		swap(cam_pinfo **queue_array, int i, int j);
5139212Sgibbsstatic void	heap_up(cam_pinfo **queue_array, int new_index);
5239212Sgibbsstatic void	heap_down(cam_pinfo **queue_array, int index,
5339212Sgibbs			  int last_index);
5439212Sgibbs
5539212Sgibbsstruct camq *
5639212Sgibbscamq_alloc(int size)
5739212Sgibbs{
5839212Sgibbs	struct camq *camq;
5939212Sgibbs
60147723Savatar	camq = (struct camq *)malloc(sizeof(*camq), M_CAMQ, M_NOWAIT);
6139212Sgibbs	if (camq != NULL) {
6239212Sgibbs		if (camq_init(camq, size) != 0) {
63147723Savatar			free(camq, M_CAMQ);
6439212Sgibbs			camq = NULL;
6539212Sgibbs		}
6639212Sgibbs	}
6739212Sgibbs	return (camq);
6839212Sgibbs}
6939212Sgibbs
7039212Sgibbsint
7139212Sgibbscamq_init(struct camq *camq, int size)
7239212Sgibbs{
7339212Sgibbs	bzero(camq, sizeof(*camq));
7439212Sgibbs	camq->array_size = size;
7539212Sgibbs	if (camq->array_size != 0) {
7639212Sgibbs		camq->queue_array = (cam_pinfo**)malloc(size*sizeof(cam_pinfo*),
77147723Savatar							M_CAMQ, M_NOWAIT);
7839212Sgibbs		if (camq->queue_array == NULL) {
7939212Sgibbs			printf("camq_init: - cannot malloc array!\n");
8039212Sgibbs			return (1);
8139212Sgibbs		}
8245844Sgibbs		/*
8345844Sgibbs		 * Heap algorithms like everything numbered from 1, so
8445844Sgibbs		 * offset our pointer into the heap array by one element.
8545844Sgibbs		 */
8645844Sgibbs		camq->queue_array--;
8739212Sgibbs	}
8839212Sgibbs	return (0);
8939212Sgibbs}
9039212Sgibbs
9139212Sgibbs/*
9239212Sgibbs * Free a camq structure.  This should only be called if a controller
9339212Sgibbs * driver failes somehow during its attach routine or is unloaded and has
9439212Sgibbs * obtained a camq structure.  The XPT should ensure that the queue
9539212Sgibbs * is empty before calling this routine.
9639212Sgibbs */
9739212Sgibbsvoid
9839212Sgibbscamq_free(struct camq *queue)
9939212Sgibbs{
10039212Sgibbs	if (queue != NULL) {
10139212Sgibbs		camq_fini(queue);
102147723Savatar		free(queue, M_CAMQ);
10339212Sgibbs	}
10439212Sgibbs}
10539212Sgibbs
10639212Sgibbsvoid
10739212Sgibbscamq_fini(struct camq *queue)
10839212Sgibbs{
10939212Sgibbs	if (queue->queue_array != NULL) {
11045844Sgibbs		/*
11145844Sgibbs		 * Heap algorithms like everything numbered from 1, so
11245844Sgibbs		 * our pointer into the heap array is offset by one element.
11345844Sgibbs		 */
11445844Sgibbs		queue->queue_array++;
115147723Savatar		free(queue->queue_array, M_CAMQ);
11639212Sgibbs	}
11739212Sgibbs}
11839212Sgibbs
11939212Sgibbsu_int32_t
12039212Sgibbscamq_resize(struct camq *queue, int new_size)
12139212Sgibbs{
12239212Sgibbs	cam_pinfo **new_array;
12339212Sgibbs
124241028Smav	KASSERT(new_size >= queue->entries, ("camq_resize: "
125241028Smav	    "New queue size can't accomodate queued entries (%d < %d).",
126241028Smav	    new_size, queue->entries));
12739212Sgibbs	new_array = (cam_pinfo **)malloc(new_size * sizeof(cam_pinfo *),
128147723Savatar					 M_CAMQ, M_NOWAIT);
12939212Sgibbs	if (new_array == NULL) {
13039212Sgibbs		/* Couldn't satisfy request */
13139212Sgibbs		return (CAM_RESRC_UNAVAIL);
13239212Sgibbs	}
13345844Sgibbs	/*
13445844Sgibbs	 * Heap algorithms like everything numbered from 1, so
13545844Sgibbs	 * remember that our pointer into the heap array is offset
13645844Sgibbs	 * by one element.
13745844Sgibbs	 */
13839212Sgibbs	if (queue->queue_array != NULL) {
13945844Sgibbs		queue->queue_array++;
14039212Sgibbs		bcopy(queue->queue_array, new_array,
14139212Sgibbs		      queue->entries * sizeof(cam_pinfo *));
142147723Savatar		free(queue->queue_array, M_CAMQ);
14339212Sgibbs	}
14445844Sgibbs	queue->queue_array = new_array-1;
14539212Sgibbs	queue->array_size = new_size;
14639212Sgibbs	return (CAM_REQ_CMP);
14739212Sgibbs}
14839212Sgibbs
14939212Sgibbs/*
15039212Sgibbs * camq_insert: Given an array of cam_pinfo* elememnts with
15145844Sgibbs * the Heap(1, num_elements) property and array_size - num_elements >= 1,
15245844Sgibbs * output Heap(1, num_elements+1) including new_entry in the array.
15339212Sgibbs */
15439212Sgibbsvoid
15539212Sgibbscamq_insert(struct camq *queue, cam_pinfo *new_entry)
15639212Sgibbs{
157241028Smav
158241028Smav	KASSERT(queue->entries < queue->array_size,
159241028Smav	    ("camq_insert: Attempt to insert into a full queue (%d >= %d)",
160241028Smav	    queue->entries, queue->array_size));
16145844Sgibbs	queue->entries++;
16239212Sgibbs	queue->queue_array[queue->entries] = new_entry;
16339212Sgibbs	new_entry->index = queue->entries;
16439212Sgibbs	if (queue->entries != 0)
16539212Sgibbs		heap_up(queue->queue_array, queue->entries);
16639212Sgibbs}
16739212Sgibbs
16839212Sgibbs/*
16939212Sgibbs * camq_remove:  Given an array of cam_pinfo* elevements with the
17045844Sgibbs * Heap(1, num_elements) property and an index such that 1 <= index <=
17145844Sgibbs * num_elements, remove that entry and restore the Heap(1, num_elements-1)
17239212Sgibbs * property.
17339212Sgibbs */
17439212Sgibbscam_pinfo *
17539212Sgibbscamq_remove(struct camq *queue, int index)
17639212Sgibbs{
17739212Sgibbs	cam_pinfo *removed_entry;
17839212Sgibbs
17945844Sgibbs	if (index == 0 || index > queue->entries)
18039212Sgibbs		return (NULL);
18139212Sgibbs	removed_entry = queue->queue_array[index];
18239212Sgibbs	if (queue->entries != index) {
18339212Sgibbs		queue->queue_array[index] = queue->queue_array[queue->entries];
18439212Sgibbs		queue->queue_array[index]->index = index;
18545844Sgibbs		heap_down(queue->queue_array, index, queue->entries - 1);
18639212Sgibbs	}
18739212Sgibbs	removed_entry->index = CAM_UNQUEUED_INDEX;
18845844Sgibbs	queue->entries--;
18939212Sgibbs	return (removed_entry);
19039212Sgibbs}
19139212Sgibbs
19239212Sgibbs/*
19339212Sgibbs * camq_change_priority:  Given an array of cam_pinfo* elements with the
19445844Sgibbs * Heap(1, num_entries) property, an index such that 1 <= index <= num_elements,
195108470Sschweikh * and a new priority for the element at index, change the priority of
19639212Sgibbs * element index and restore the Heap(0, num_elements) property.
19739212Sgibbs */
19839212Sgibbsvoid
19939212Sgibbscamq_change_priority(struct camq *queue, int index, u_int32_t new_priority)
20039212Sgibbs{
20139212Sgibbs	if (new_priority > queue->queue_array[index]->priority) {
20239212Sgibbs		queue->queue_array[index]->priority = new_priority;
20339212Sgibbs		heap_down(queue->queue_array, index, queue->entries);
20439212Sgibbs	} else {
20539212Sgibbs		/* new_priority <= old_priority */
20639212Sgibbs		queue->queue_array[index]->priority = new_priority;
20739212Sgibbs		heap_up(queue->queue_array, index);
20839212Sgibbs	}
20939212Sgibbs}
21039212Sgibbs
21139212Sgibbsstruct cam_devq *
21239212Sgibbscam_devq_alloc(int devices, int openings)
21339212Sgibbs{
21439212Sgibbs	struct cam_devq *devq;
21539212Sgibbs
216147723Savatar	devq = (struct cam_devq *)malloc(sizeof(*devq), M_CAMDEVQ, M_NOWAIT);
21739212Sgibbs	if (devq == NULL) {
21839212Sgibbs		printf("cam_devq_alloc: - cannot malloc!\n");
21939212Sgibbs		return (NULL);
22039212Sgibbs	}
22139212Sgibbs	if (cam_devq_init(devq, devices, openings) != 0) {
222147723Savatar		free(devq, M_CAMDEVQ);
22339212Sgibbs		return (NULL);
22439212Sgibbs	}
22539212Sgibbs
22639212Sgibbs	return (devq);
22739212Sgibbs}
22839212Sgibbs
22939212Sgibbsint
23039212Sgibbscam_devq_init(struct cam_devq *devq, int devices, int openings)
23139212Sgibbs{
23239212Sgibbs	bzero(devq, sizeof(*devq));
233249466Smav	if (camq_init(&devq->send_queue, devices) != 0)
23439212Sgibbs		return (1);
23539212Sgibbs	devq->send_openings = openings;
23639212Sgibbs	devq->send_active = 0;
23739212Sgibbs	return (0);
23839212Sgibbs}
23939212Sgibbs
24039212Sgibbsvoid
24139212Sgibbscam_devq_free(struct cam_devq *devq)
24239212Sgibbs{
24349862Sgibbs	camq_fini(&devq->send_queue);
244147723Savatar	free(devq, M_CAMDEVQ);
24539212Sgibbs}
24639212Sgibbs
24739212Sgibbsu_int32_t
24839212Sgibbscam_devq_resize(struct cam_devq *camq, int devices)
24939212Sgibbs{
25039212Sgibbs	u_int32_t retval;
25139212Sgibbs
252249466Smav	retval = camq_resize(&camq->send_queue, devices);
25339212Sgibbs	return (retval);
25439212Sgibbs}
25539212Sgibbs
25639212Sgibbsstruct cam_ccbq *
25739212Sgibbscam_ccbq_alloc(int openings)
25839212Sgibbs{
25939212Sgibbs	struct cam_ccbq *ccbq;
26039212Sgibbs
261147723Savatar	ccbq = (struct cam_ccbq *)malloc(sizeof(*ccbq), M_CAMCCBQ, M_NOWAIT);
26239212Sgibbs	if (ccbq == NULL) {
26339212Sgibbs		printf("cam_ccbq_alloc: - cannot malloc!\n");
26439212Sgibbs		return (NULL);
26539212Sgibbs	}
26639212Sgibbs	if (cam_ccbq_init(ccbq, openings) != 0) {
267147723Savatar		free(ccbq, M_CAMCCBQ);
26839212Sgibbs		return (NULL);
26939212Sgibbs	}
27039212Sgibbs
27139212Sgibbs	return (ccbq);
27239212Sgibbs}
27339212Sgibbs
27439212Sgibbsvoid
27539212Sgibbscam_ccbq_free(struct cam_ccbq *ccbq)
27639212Sgibbs{
27739212Sgibbs	if (ccbq) {
278198377Smav		cam_ccbq_fini(ccbq);
279147723Savatar		free(ccbq, M_CAMCCBQ);
28039212Sgibbs	}
28139212Sgibbs}
28239212Sgibbs
28339212Sgibbsu_int32_t
28439212Sgibbscam_ccbq_resize(struct cam_ccbq *ccbq, int new_size)
28539212Sgibbs{
28639212Sgibbs	int delta;
28739212Sgibbs
28839212Sgibbs	delta = new_size - (ccbq->dev_active + ccbq->dev_openings);
289253958Smav	ccbq->devq_openings += delta;
290253958Smav	ccbq->dev_openings += delta;
29139212Sgibbs
292253958Smav	new_size = imax(64, 1 << fls(new_size + new_size / 2));
293253958Smav	if (new_size > ccbq->queue.array_size)
294253958Smav		return (camq_resize(&ccbq->queue, new_size));
295253958Smav	else
29639212Sgibbs		return (CAM_REQ_CMP);
29739212Sgibbs}
29839212Sgibbs
29939212Sgibbsint
30039212Sgibbscam_ccbq_init(struct cam_ccbq *ccbq, int openings)
30139212Sgibbs{
30239212Sgibbs	bzero(ccbq, sizeof(*ccbq));
303253958Smav	if (camq_init(&ccbq->queue,
304253958Smav	    imax(64, 1 << fls(openings + openings / 2))) != 0)
30539212Sgibbs		return (1);
30639212Sgibbs	ccbq->devq_openings = openings;
307249466Smav	ccbq->dev_openings = openings;
30839212Sgibbs	return (0);
30939212Sgibbs}
31039212Sgibbs
311198377Smavvoid
312198377Smavcam_ccbq_fini(struct cam_ccbq *ccbq)
313198377Smav{
314198377Smav
315198377Smav	camq_fini(&ccbq->queue);
316198377Smav}
317198377Smav
31839212Sgibbs/*
31939212Sgibbs * Heap routines for manipulating CAM queues.
32039212Sgibbs */
32139212Sgibbs/*
32239212Sgibbs * queue_cmp: Given an array of cam_pinfo* elements and indexes i
32339212Sgibbs * and j, return less than 0, 0, or greater than 0 if i is less than,
32439212Sgibbs * equal too, or greater than j respectively.
32539212Sgibbs */
32639212Sgibbsstatic __inline int
32739212Sgibbsqueue_cmp(cam_pinfo **queue_array, int i, int j)
32839212Sgibbs{
32939212Sgibbs	if (queue_array[i]->priority == queue_array[j]->priority)
33039212Sgibbs		return (  queue_array[i]->generation
33139212Sgibbs			- queue_array[j]->generation );
33239212Sgibbs	else
33339212Sgibbs		return (  queue_array[i]->priority
33439212Sgibbs			- queue_array[j]->priority );
33539212Sgibbs}
33639212Sgibbs
33739212Sgibbs/*
33839212Sgibbs * swap: Given an array of cam_pinfo* elements and indexes i and j,
33939212Sgibbs * exchange elements i and j.
34039212Sgibbs */
34139212Sgibbsstatic __inline void
34239212Sgibbsswap(cam_pinfo **queue_array, int i, int j)
34339212Sgibbs{
34439212Sgibbs	cam_pinfo *temp_qentry;
34539212Sgibbs
34639212Sgibbs	temp_qentry = queue_array[j];
34739212Sgibbs	queue_array[j] = queue_array[i];
34839212Sgibbs	queue_array[i] = temp_qentry;
34939212Sgibbs	queue_array[j]->index = j;
35039212Sgibbs	queue_array[i]->index = i;
35139212Sgibbs}
35239212Sgibbs
35339212Sgibbs/*
35439212Sgibbs * heap_up:  Given an array of cam_pinfo* elements with the
35545844Sgibbs * Heap(1, new_index-1) property and a new element in location
35645844Sgibbs * new_index, output Heap(1, new_index).
35739212Sgibbs */
35839212Sgibbsstatic void
35939212Sgibbsheap_up(cam_pinfo **queue_array, int new_index)
36039212Sgibbs{
36139212Sgibbs	int child;
36239212Sgibbs	int parent;
36339212Sgibbs
36439212Sgibbs	child = new_index;
36539212Sgibbs
36645844Sgibbs	while (child != 1) {
36739212Sgibbs
36845844Sgibbs		parent = child >> 1;
36939212Sgibbs		if (queue_cmp(queue_array, parent, child) <= 0)
37039212Sgibbs			break;
37139212Sgibbs		swap(queue_array, parent, child);
37239212Sgibbs		child = parent;
37339212Sgibbs	}
37439212Sgibbs}
37539212Sgibbs
37639212Sgibbs/*
37739212Sgibbs * heap_down:  Given an array of cam_pinfo* elements with the
37845844Sgibbs * Heap(index + 1, num_entries) property with index containing
37945844Sgibbs * an unsorted entry, output Heap(index, num_entries).
38039212Sgibbs */
38139212Sgibbsstatic void
38239212Sgibbsheap_down(cam_pinfo **queue_array, int index, int num_entries)
38339212Sgibbs{
38439212Sgibbs	int child;
38539212Sgibbs	int parent;
38639212Sgibbs
38739212Sgibbs	parent = index;
38845844Sgibbs	child = parent << 1;
38945844Sgibbs	for (; child <= num_entries; child = parent << 1) {
39039212Sgibbs
39145844Sgibbs		if (child < num_entries) {
39239212Sgibbs			/* child+1 is the right child of parent */
39339212Sgibbs			if (queue_cmp(queue_array, child + 1, child) < 0)
39439212Sgibbs				child++;
39539212Sgibbs		}
39639212Sgibbs		/* child is now the least child of parent */
39739212Sgibbs		if (queue_cmp(queue_array, parent, child) <= 0)
39839212Sgibbs			break;
39939212Sgibbs		swap(queue_array, child, parent);
40039212Sgibbs		parent = child;
40139212Sgibbs	}
40239212Sgibbs}
403