The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/cam_queue.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c4ebbc8a5550b0c3d64410c87aae378b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.