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/cdefs.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/types.h> 35 #include <sys/malloc.h> 36 #include <sys/kernel.h> 37 38 #include <cam/cam.h> 39 #include <cam/cam_ccb.h> 40 #include <cam/cam_queue.h> 41 #include <cam/cam_debug.h> 42 43 static MALLOC_DEFINE(M_CAMQ, "CAM queue", "CAM queue buffers"); 44 static MALLOC_DEFINE(M_CAMDEVQ, "CAM dev queue", "CAM dev queue buffers"); 45 static MALLOC_DEFINE(M_CAMCCBQ, "CAM ccb queue", "CAM ccb queue buffers"); 46 47 static void heap_up(cam_pinfo **queue_array, int new_index); 48 static void heap_down(cam_pinfo **queue_array, int index, 49 int last_index); 50 51 int 52 camq_init(struct camq *camq, int size) 53 { 54 bzero(camq, sizeof(*camq)); 55 camq->array_size = size; 56 if (camq->array_size != 0) { 57 /* 58 * Heap algorithms like everything numbered from 1, so 59 * allocate one more to account for 0 base. 60 */ 61 camq->queue_array = malloc((size + 1) * sizeof(cam_pinfo*), 62 M_CAMQ, M_NOWAIT); 63 if (camq->queue_array == NULL) { 64 printf("camq_init: - cannot malloc array!\n"); 65 return (1); 66 } 67 } 68 return (0); 69 } 70 71 /* 72 * Free a camq structure. This should only be called if a controller 73 * driver fails somehow during its attach routine or is unloaded and has 74 * obtained a camq structure. The XPT should ensure that the queue 75 * is empty before calling this routine. 76 */ 77 void 78 camq_fini(struct camq *queue) 79 { 80 if (queue->queue_array != NULL) { 81 free(queue->queue_array, M_CAMQ); 82 } 83 } 84 85 uint32_t 86 camq_resize(struct camq *queue, int new_size) 87 { 88 cam_pinfo **new_array; 89 90 KASSERT(new_size >= queue->entries, ("camq_resize: " 91 "New queue size can't accommodate queued entries (%d < %d).", 92 new_size, queue->entries)); 93 new_array = malloc((new_size + 1) * sizeof(cam_pinfo *), M_CAMQ, 94 M_NOWAIT); 95 if (new_array == NULL) { 96 /* Couldn't satisfy request */ 97 return (CAM_RESRC_UNAVAIL); 98 } 99 /* 100 * Heap algorithms like everything numbered from 1, so 101 * remember that our pointer into the heap array is offset 102 * by one element. 103 */ 104 if (queue->queue_array != NULL) { 105 bcopy(queue->queue_array, new_array, 106 (queue->entries + 1) * sizeof(cam_pinfo *)); 107 free(queue->queue_array, M_CAMQ); 108 } 109 queue->queue_array = new_array; 110 queue->array_size = new_size; 111 return (CAM_REQ_CMP); 112 } 113 114 /* 115 * camq_insert: Given an array of cam_pinfo* elememnts with 116 * the Heap(1, num_elements) property and array_size - num_elements >= 1, 117 * output Heap(1, num_elements+1) including new_entry in the array. 118 */ 119 void 120 camq_insert(struct camq *queue, cam_pinfo *new_entry) 121 { 122 123 KASSERT(queue->entries < queue->array_size, 124 ("camq_insert: Attempt to insert into a full queue (%d >= %d)", 125 queue->entries, queue->array_size)); 126 queue->entries++; 127 queue->queue_array[queue->entries] = new_entry; 128 new_entry->index = queue->entries; 129 if (queue->entries != 0) 130 heap_up(queue->queue_array, queue->entries); 131 } 132 133 /* 134 * camq_remove: Given an array of cam_pinfo* elevements with the 135 * Heap(1, num_elements) property and an index such that 1 <= index <= 136 * num_elements, remove that entry and restore the Heap(1, num_elements-1) 137 * property. 138 */ 139 cam_pinfo * 140 camq_remove(struct camq *queue, int index) 141 { 142 cam_pinfo *removed_entry; 143 144 if (index <= 0 || index > queue->entries) 145 panic("%s: Attempt to remove out-of-bounds index %d " 146 "from queue %p of size %d", __func__, index, queue, 147 queue->entries); 148 149 removed_entry = queue->queue_array[index]; 150 if (queue->entries != index) { 151 queue->queue_array[index] = queue->queue_array[queue->entries]; 152 queue->queue_array[index]->index = index; 153 heap_down(queue->queue_array, index, queue->entries - 1); 154 } 155 removed_entry->index = CAM_UNQUEUED_INDEX; 156 queue->entries--; 157 return (removed_entry); 158 } 159 160 /* 161 * camq_change_priority: Given an array of cam_pinfo* elements with the 162 * Heap(1, num_entries) property, an index such that 1 <= index <= num_elements, 163 * and a new priority for the element at index, change the priority of 164 * element index and restore the Heap(0, num_elements) property. 165 */ 166 void 167 camq_change_priority(struct camq *queue, int index, uint32_t new_priority) 168 { 169 if (new_priority > queue->queue_array[index]->priority) { 170 queue->queue_array[index]->priority = new_priority; 171 heap_down(queue->queue_array, index, queue->entries); 172 } else { 173 /* new_priority <= old_priority */ 174 queue->queue_array[index]->priority = new_priority; 175 heap_up(queue->queue_array, index); 176 } 177 } 178 179 struct cam_devq * 180 cam_devq_alloc(int devices, int openings) 181 { 182 struct cam_devq *devq; 183 184 devq = (struct cam_devq *)malloc(sizeof(*devq), M_CAMDEVQ, M_NOWAIT); 185 if (devq == NULL) { 186 printf("cam_devq_alloc: - cannot malloc!\n"); 187 return (NULL); 188 } 189 if (cam_devq_init(devq, devices, openings) != 0) { 190 free(devq, M_CAMDEVQ); 191 return (NULL); 192 } 193 return (devq); 194 } 195 196 int 197 cam_devq_init(struct cam_devq *devq, int devices, int openings) 198 { 199 200 bzero(devq, sizeof(*devq)); 201 mtx_init(&devq->send_mtx, "CAM queue lock", NULL, MTX_DEF); 202 if (camq_init(&devq->send_queue, devices) != 0) 203 return (1); 204 devq->send_openings = openings; 205 devq->send_active = 0; 206 return (0); 207 } 208 209 void 210 cam_devq_free(struct cam_devq *devq) 211 { 212 213 camq_fini(&devq->send_queue); 214 mtx_destroy(&devq->send_mtx); 215 free(devq, M_CAMDEVQ); 216 } 217 218 uint32_t 219 cam_devq_resize(struct cam_devq *camq, int devices) 220 { 221 uint32_t retval; 222 223 retval = camq_resize(&camq->send_queue, devices); 224 return (retval); 225 } 226 227 struct cam_ccbq * 228 cam_ccbq_alloc(int openings) 229 { 230 struct cam_ccbq *ccbq; 231 232 ccbq = (struct cam_ccbq *)malloc(sizeof(*ccbq), M_CAMCCBQ, M_NOWAIT); 233 if (ccbq == NULL) { 234 printf("cam_ccbq_alloc: - cannot malloc!\n"); 235 return (NULL); 236 } 237 if (cam_ccbq_init(ccbq, openings) != 0) { 238 free(ccbq, M_CAMCCBQ); 239 return (NULL); 240 } 241 242 return (ccbq); 243 } 244 245 void 246 cam_ccbq_free(struct cam_ccbq *ccbq) 247 { 248 if (ccbq) { 249 cam_ccbq_fini(ccbq); 250 free(ccbq, M_CAMCCBQ); 251 } 252 } 253 254 uint32_t 255 cam_ccbq_resize(struct cam_ccbq *ccbq, int new_size) 256 { 257 int delta; 258 259 delta = new_size - (ccbq->dev_active + ccbq->dev_openings); 260 ccbq->total_openings += delta; 261 ccbq->dev_openings += delta; 262 263 new_size = imax(64, 1 << fls(new_size + new_size / 2)); 264 if (new_size > ccbq->queue.array_size) 265 return (camq_resize(&ccbq->queue, new_size)); 266 else 267 return (CAM_REQ_CMP); 268 } 269 270 int 271 cam_ccbq_init(struct cam_ccbq *ccbq, int openings) 272 { 273 bzero(ccbq, sizeof(*ccbq)); 274 if (camq_init(&ccbq->queue, 275 imax(64, 1 << fls(openings + openings / 2))) != 0) 276 return (1); 277 ccbq->total_openings = openings; 278 ccbq->dev_openings = openings; 279 return (0); 280 } 281 282 void 283 cam_ccbq_fini(struct cam_ccbq *ccbq) 284 { 285 286 camq_fini(&ccbq->queue); 287 } 288 289 /* 290 * Heap routines for manipulating CAM queues. 291 */ 292 /* 293 * queue_cmp: Given an array of cam_pinfo* elements and indexes i 294 * and j, return less than 0, 0, or greater than 0 if i is less than, 295 * equal too, or greater than j respectively. 296 */ 297 static __inline int 298 queue_cmp(cam_pinfo **queue_array, int i, int j) 299 { 300 if (queue_array[i]->priority == queue_array[j]->priority) 301 return ( queue_array[i]->generation 302 - queue_array[j]->generation ); 303 else 304 return ( queue_array[i]->priority 305 - queue_array[j]->priority ); 306 } 307 308 /* 309 * swap: Given an array of cam_pinfo* elements and indexes i and j, 310 * exchange elements i and j. 311 */ 312 static __inline void 313 swap(cam_pinfo **queue_array, int i, int j) 314 { 315 cam_pinfo *temp_qentry; 316 317 temp_qentry = queue_array[j]; 318 queue_array[j] = queue_array[i]; 319 queue_array[i] = temp_qentry; 320 queue_array[j]->index = j; 321 queue_array[i]->index = i; 322 } 323 324 /* 325 * heap_up: Given an array of cam_pinfo* elements with the 326 * Heap(1, new_index-1) property and a new element in location 327 * new_index, output Heap(1, new_index). 328 */ 329 static void 330 heap_up(cam_pinfo **queue_array, int new_index) 331 { 332 int child; 333 int parent; 334 335 child = new_index; 336 337 while (child != 1) { 338 parent = child >> 1; 339 if (queue_cmp(queue_array, parent, child) <= 0) 340 break; 341 swap(queue_array, parent, child); 342 child = parent; 343 } 344 } 345 346 /* 347 * heap_down: Given an array of cam_pinfo* elements with the 348 * Heap(index + 1, num_entries) property with index containing 349 * an unsorted entry, output Heap(index, num_entries). 350 */ 351 static void 352 heap_down(cam_pinfo **queue_array, int index, int num_entries) 353 { 354 int child; 355 int parent; 356 357 parent = index; 358 child = parent << 1; 359 for (; child <= num_entries; child = parent << 1) { 360 if (child < num_entries) { 361 /* child+1 is the right child of parent */ 362 if (queue_cmp(queue_array, child + 1, child) < 0) 363 child++; 364 } 365 /* child is now the least child of parent */ 366 if (queue_cmp(queue_array, parent, child) <= 0) 367 break; 368 swap(queue_array, child, parent); 369 parent = child; 370 } 371 } 372