Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/cam_queue.c
39475 views
1
/*-
2
* CAM request queue management functions.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 1997 Justin T. Gibbs.
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions, and the following disclaimer,
14
* without modification, immediately at the beginning of the file.
15
* 2. The name of the author may not be used to endorse or promote products
16
* derived from this software without specific prior written permission.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/systm.h>
33
#include <sys/types.h>
34
#include <sys/malloc.h>
35
#include <sys/kernel.h>
36
37
#include <cam/cam.h>
38
#include <cam/cam_ccb.h>
39
#include <cam/cam_queue.h>
40
#include <cam/cam_debug.h>
41
42
static MALLOC_DEFINE(M_CAMQ, "CAM queue", "CAM queue buffers");
43
static MALLOC_DEFINE(M_CAMDEVQ, "CAM dev queue", "CAM dev queue buffers");
44
static MALLOC_DEFINE(M_CAMCCBQ, "CAM ccb queue", "CAM ccb queue buffers");
45
46
static void heap_up(cam_pinfo **queue_array, int new_index);
47
static void heap_down(cam_pinfo **queue_array, int index,
48
int last_index);
49
50
int
51
camq_init(struct camq *camq, int size)
52
{
53
bzero(camq, sizeof(*camq));
54
camq->array_size = size;
55
if (camq->array_size != 0) {
56
/*
57
* Heap algorithms like everything numbered from 1, so
58
* allocate one more to account for 0 base.
59
*/
60
camq->queue_array = malloc((size + 1) * sizeof(cam_pinfo*),
61
M_CAMQ, M_NOWAIT);
62
if (camq->queue_array == NULL) {
63
printf("camq_init: - cannot malloc array!\n");
64
return (1);
65
}
66
}
67
return (0);
68
}
69
70
/*
71
* Free a camq structure. This should only be called if a controller
72
* driver fails somehow during its attach routine or is unloaded and has
73
* obtained a camq structure. The XPT should ensure that the queue
74
* is empty before calling this routine.
75
*/
76
void
77
camq_fini(struct camq *queue)
78
{
79
if (queue->queue_array != NULL) {
80
free(queue->queue_array, M_CAMQ);
81
}
82
}
83
84
uint32_t
85
camq_resize(struct camq *queue, int new_size)
86
{
87
cam_pinfo **new_array;
88
89
KASSERT(new_size >= queue->entries, ("camq_resize: "
90
"New queue size can't accommodate queued entries (%d < %d).",
91
new_size, queue->entries));
92
new_array = malloc((new_size + 1) * sizeof(cam_pinfo *), M_CAMQ,
93
M_NOWAIT);
94
if (new_array == NULL) {
95
/* Couldn't satisfy request */
96
return (CAM_RESRC_UNAVAIL);
97
}
98
/*
99
* Heap algorithms like everything numbered from 1, so
100
* remember that our pointer into the heap array is offset
101
* by one element.
102
*/
103
if (queue->queue_array != NULL) {
104
bcopy(queue->queue_array, new_array,
105
(queue->entries + 1) * sizeof(cam_pinfo *));
106
free(queue->queue_array, M_CAMQ);
107
}
108
queue->queue_array = new_array;
109
queue->array_size = new_size;
110
return (CAM_REQ_CMP);
111
}
112
113
/*
114
* camq_insert: Given an array of cam_pinfo* elememnts with
115
* the Heap(1, num_elements) property and array_size - num_elements >= 1,
116
* output Heap(1, num_elements+1) including new_entry in the array.
117
*/
118
void
119
camq_insert(struct camq *queue, cam_pinfo *new_entry)
120
{
121
122
KASSERT(queue->entries < queue->array_size,
123
("camq_insert: Attempt to insert into a full queue (%d >= %d)",
124
queue->entries, queue->array_size));
125
queue->entries++;
126
queue->queue_array[queue->entries] = new_entry;
127
new_entry->index = queue->entries;
128
if (queue->entries != 0)
129
heap_up(queue->queue_array, queue->entries);
130
}
131
132
/*
133
* camq_remove: Given an array of cam_pinfo* elevements with the
134
* Heap(1, num_elements) property and an index such that 1 <= index <=
135
* num_elements, remove that entry and restore the Heap(1, num_elements-1)
136
* property.
137
*/
138
cam_pinfo *
139
camq_remove(struct camq *queue, int index)
140
{
141
cam_pinfo *removed_entry;
142
143
if (index <= 0 || index > queue->entries)
144
panic("%s: Attempt to remove out-of-bounds index %d "
145
"from queue %p of size %d", __func__, index, queue,
146
queue->entries);
147
148
removed_entry = queue->queue_array[index];
149
if (queue->entries != index) {
150
queue->queue_array[index] = queue->queue_array[queue->entries];
151
queue->queue_array[index]->index = index;
152
heap_down(queue->queue_array, index, queue->entries - 1);
153
}
154
removed_entry->index = CAM_UNQUEUED_INDEX;
155
queue->entries--;
156
return (removed_entry);
157
}
158
159
/*
160
* camq_change_priority: Given an array of cam_pinfo* elements with the
161
* Heap(1, num_entries) property, an index such that 1 <= index <= num_elements,
162
* and a new priority for the element at index, change the priority of
163
* element index and restore the Heap(0, num_elements) property.
164
*/
165
void
166
camq_change_priority(struct camq *queue, int index, uint32_t new_priority)
167
{
168
if (new_priority > queue->queue_array[index]->priority) {
169
queue->queue_array[index]->priority = new_priority;
170
heap_down(queue->queue_array, index, queue->entries);
171
} else {
172
/* new_priority <= old_priority */
173
queue->queue_array[index]->priority = new_priority;
174
heap_up(queue->queue_array, index);
175
}
176
}
177
178
struct cam_devq *
179
cam_devq_alloc(int devices, int openings)
180
{
181
struct cam_devq *devq;
182
183
devq = (struct cam_devq *)malloc(sizeof(*devq), M_CAMDEVQ, M_NOWAIT);
184
if (devq == NULL) {
185
printf("cam_devq_alloc: - cannot malloc!\n");
186
return (NULL);
187
}
188
if (cam_devq_init(devq, devices, openings) != 0) {
189
free(devq, M_CAMDEVQ);
190
return (NULL);
191
}
192
return (devq);
193
}
194
195
int
196
cam_devq_init(struct cam_devq *devq, int devices, int openings)
197
{
198
199
bzero(devq, sizeof(*devq));
200
mtx_init(&devq->send_mtx, "CAM queue lock", NULL, MTX_DEF);
201
if (camq_init(&devq->send_queue, devices) != 0)
202
return (1);
203
devq->send_openings = openings;
204
devq->send_active = 0;
205
return (0);
206
}
207
208
void
209
cam_devq_free(struct cam_devq *devq)
210
{
211
212
camq_fini(&devq->send_queue);
213
mtx_destroy(&devq->send_mtx);
214
free(devq, M_CAMDEVQ);
215
}
216
217
uint32_t
218
cam_devq_resize(struct cam_devq *camq, int devices)
219
{
220
uint32_t retval;
221
222
retval = camq_resize(&camq->send_queue, devices);
223
return (retval);
224
}
225
226
struct cam_ccbq *
227
cam_ccbq_alloc(int openings)
228
{
229
struct cam_ccbq *ccbq;
230
231
ccbq = (struct cam_ccbq *)malloc(sizeof(*ccbq), M_CAMCCBQ, M_NOWAIT);
232
if (ccbq == NULL) {
233
printf("cam_ccbq_alloc: - cannot malloc!\n");
234
return (NULL);
235
}
236
if (cam_ccbq_init(ccbq, openings) != 0) {
237
free(ccbq, M_CAMCCBQ);
238
return (NULL);
239
}
240
241
return (ccbq);
242
}
243
244
void
245
cam_ccbq_free(struct cam_ccbq *ccbq)
246
{
247
if (ccbq) {
248
cam_ccbq_fini(ccbq);
249
free(ccbq, M_CAMCCBQ);
250
}
251
}
252
253
uint32_t
254
cam_ccbq_resize(struct cam_ccbq *ccbq, int new_size)
255
{
256
int delta;
257
258
delta = new_size - (ccbq->dev_active + ccbq->dev_openings);
259
ccbq->total_openings += delta;
260
ccbq->dev_openings += delta;
261
262
new_size = imax(64, 1 << fls(new_size + new_size / 2));
263
if (new_size > ccbq->queue.array_size)
264
return (camq_resize(&ccbq->queue, new_size));
265
else
266
return (CAM_REQ_CMP);
267
}
268
269
int
270
cam_ccbq_init(struct cam_ccbq *ccbq, int openings)
271
{
272
bzero(ccbq, sizeof(*ccbq));
273
if (camq_init(&ccbq->queue,
274
imax(64, 1 << fls(openings + openings / 2))) != 0)
275
return (1);
276
ccbq->total_openings = openings;
277
ccbq->dev_openings = openings;
278
return (0);
279
}
280
281
void
282
cam_ccbq_fini(struct cam_ccbq *ccbq)
283
{
284
285
camq_fini(&ccbq->queue);
286
}
287
288
/*
289
* Heap routines for manipulating CAM queues.
290
*/
291
/*
292
* queue_cmp: Given an array of cam_pinfo* elements and indexes i
293
* and j, return less than 0, 0, or greater than 0 if i is less than,
294
* equal too, or greater than j respectively.
295
*/
296
static __inline int
297
queue_cmp(cam_pinfo **queue_array, int i, int j)
298
{
299
if (queue_array[i]->priority == queue_array[j]->priority)
300
return ( queue_array[i]->generation
301
- queue_array[j]->generation );
302
else
303
return ( queue_array[i]->priority
304
- queue_array[j]->priority );
305
}
306
307
/*
308
* swap: Given an array of cam_pinfo* elements and indexes i and j,
309
* exchange elements i and j.
310
*/
311
static __inline void
312
swap(cam_pinfo **queue_array, int i, int j)
313
{
314
cam_pinfo *temp_qentry;
315
316
temp_qentry = queue_array[j];
317
queue_array[j] = queue_array[i];
318
queue_array[i] = temp_qentry;
319
queue_array[j]->index = j;
320
queue_array[i]->index = i;
321
}
322
323
/*
324
* heap_up: Given an array of cam_pinfo* elements with the
325
* Heap(1, new_index-1) property and a new element in location
326
* new_index, output Heap(1, new_index).
327
*/
328
static void
329
heap_up(cam_pinfo **queue_array, int new_index)
330
{
331
int child;
332
int parent;
333
334
child = new_index;
335
336
while (child != 1) {
337
parent = child >> 1;
338
if (queue_cmp(queue_array, parent, child) <= 0)
339
break;
340
swap(queue_array, parent, child);
341
child = parent;
342
}
343
}
344
345
/*
346
* heap_down: Given an array of cam_pinfo* elements with the
347
* Heap(index + 1, num_entries) property with index containing
348
* an unsorted entry, output Heap(index, num_entries).
349
*/
350
static void
351
heap_down(cam_pinfo **queue_array, int index, int num_entries)
352
{
353
int child;
354
int parent;
355
356
parent = index;
357
child = parent << 1;
358
for (; child <= num_entries; child = parent << 1) {
359
if (child < num_entries) {
360
/* child+1 is the right child of parent */
361
if (queue_cmp(queue_array, child + 1, child) < 0)
362
child++;
363
}
364
/* child is now the least child of parent */
365
if (queue_cmp(queue_array, parent, child) <= 0)
366
break;
367
swap(queue_array, child, parent);
368
parent = child;
369
}
370
}
371
372