Emulex Logo
OneCore™ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_list.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  *
36  * OCS linked list API
37  *
38  */
39 
40 #if !defined(__OCS_LIST_H__)
41 #define __OCS_LIST_H__
42 
43 #define OCS_LIST_DEBUG
44 
45 #if defined(OCS_LIST_DEBUG)
46 
47 extern void _ocs_list_assertmsg(const char *label, const char *filename, int linenum);
48 
49 #define ocs_list_magic_decl uint32_t magic;
50 #define OCS_LIST_LIST_MAGIC 0xcafe0000
51 #define OCS_LIST_LINK_MAGIC 0xcafe0001
52 #define ocs_list_set_list_magic list->magic = OCS_LIST_LIST_MAGIC
53 #define ocs_list_set_link_magic list->magic = OCS_LIST_LINK_MAGIC
54 
55 #define ocs_list_assert(cond, ...) \
56  if (!(cond)) { \
57  _ocs_list_assertmsg(#cond, __FILE__, __LINE__); \
58  return __VA_ARGS__; \
59  }
60 #else
61 #define ocs_list_magic_decl
62 #define ocs_list_assert(cond, ...)
63 #define ocs_list_set_list_magic
64 #define ocs_list_set_link_magic
65 #endif
66 
67 /**
68  * @brief list/link structure
69  *
70  * used for both the list object, and the link object(s). offset
71  * is specified when the list is initialized; this implies that a list
72  * will always point to objects of the same type. offset is not used
73  * when ocs_list_t is used as a link (ocs_list_link_t).
74  *
75  */
76 
77 typedef struct ocs_list_s ocs_list_t;
78 struct ocs_list_s {
79  ocs_list_magic_decl /*<< used if debugging is enabled */
80  ocs_list_t *next; /*<< pointer to head of list (or next if link) */
81  ocs_list_t *prev; /*<< pointer to tail of list (or previous if link) */
82  uint32_t offset; /*<< offset in bytes to the link element of the objects in list */
83 };
84 typedef ocs_list_t ocs_list_link_t;
85 
86 /* item2link - return pointer to link given pointer to an item */
87 #define item2link(list, item) ((ocs_list_t*) (((uint8_t*)(item)) + (list)->offset))
88 
89 /* link2item - return pointer to item given pointer to a link */
90 #define link2item(list, link) ((void*) (((uint8_t*)(link)) - (list)->offset))
91 
92 /**
93  * @brief Initialize a list
94  *
95  * A list object is initialized. Helper define is used to call _ocs_list_init() with
96  * offsetof(type, link)
97  *
98  * @param list Pointer to list
99  * @param offset Offset in bytes in item to the link element
100  *
101  * @return none
102  */
103 static inline void
104 _ocs_list_init(ocs_list_t *list, uint32_t offset)
105 {
106  ocs_list_assert(list);
108 
109  list->next = list;
110  list->prev = list;
111  list->offset = offset;
112 }
113 #define ocs_list_init(head, type, link) _ocs_list_init(head, offsetof(type, link))
114 
115 
116 /**
117  * @ingroup os
118  * @brief Test if a list is empty
119  *
120  * @param list Pointer to list head
121  *
122  * @return 1 if empty, 0 otherwise
123  */
124 static inline int32_t
125 ocs_list_empty(ocs_list_t *list)
126 {
127  ocs_list_assert(list, 1);
128  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, 1);
129  return list->next == list;
130 }
131 
132 /**
133  * @ingroup os
134  * @brief Test if a list has single entry
135  *
136  * @param list Pointer to list head
137  *
138  * @return 1 if list is singular, 0 otherwise
139  */
140 static inline int32_t
141 ocs_list_is_singular(ocs_list_t *list)
142 {
143  return !ocs_list_empty(list) && (list->next == list->prev);
144 }
145 
146 /**
147  * @ingroup os
148  * @brief Test if a list is valid (ready for use)
149  *
150  * @param list Pointer to list head
151  *
152  * @return true if list is usable, false otherwise
153  */
154 static inline int
155 ocs_list_valid(ocs_list_t *list)
156 {
157  return (list->magic == OCS_LIST_LIST_MAGIC);
158 }
159 
160 /**
161  * @brief Insert link between two other links
162  *
163  * Inserts a link in between two other links
164  *
165  * @param a Pointer to first link
166  * @param b Pointer to next link
167  * @param c Pointer to link to insert between a and b
168  *
169  * @return none
170  */
171 static inline void
172 _ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
173 {
174  ocs_list_assert(a);
175  ocs_list_assert((a->magic == OCS_LIST_LIST_MAGIC) || (a->magic == OCS_LIST_LINK_MAGIC));
176  ocs_list_assert(a->next);
177  ocs_list_assert(a->prev);
178  ocs_list_assert(b);
179  ocs_list_assert((b->magic == OCS_LIST_LIST_MAGIC) || (b->magic == OCS_LIST_LINK_MAGIC));
180  ocs_list_assert(b->next);
181  ocs_list_assert(b->prev);
182  ocs_list_assert(c);
183  ocs_list_assert((c->magic == OCS_LIST_LIST_MAGIC) || (c->magic == OCS_LIST_LINK_MAGIC));
184  ocs_list_assert(!c->next);
185  ocs_list_assert(!c->prev);
186 
187  ocs_list_assert(a->offset == b->offset);
188  ocs_list_assert(b->offset == c->offset);
189 
190  c->next = a->next;
191  c->prev = b->prev;
192  a->next = c;
193  b->prev = c;
194 }
195 
196 #if defined(OCS_LIST_DEBUG)
197 /**
198  * @brief Initialize a list link for debug purposes
199  *
200  * For debugging a linked list link element has a magic number that is initialized,
201  * and the offset value initialzied and used for subsequent assertions.
202  *
203  *
204  * @param list Pointer to list head
205  * @param link Pointer to link to be initialized
206  *
207  * @return none
208  */
209 static inline void
210 ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
211 {
212  ocs_list_assert(list);
213  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
214  ocs_list_assert(link);
215 
216  if (link->magic == 0) {
217  link->magic = OCS_LIST_LINK_MAGIC;
218  link->offset = list->offset;
219  link->next = NULL;
220  link->prev = NULL;
221  }
222 }
223 #else
224 #define ocs_list_init_link(...)
225 #endif
226 
227 /**
228  * @ingroup os
229  * @brief Add an item to the head of the list
230  *
231  * @param list Pointer to list head
232  * @param item Item to add
233  */
234 static inline void
235 ocs_list_add_head(ocs_list_t *list, void *item)
236 {
237  ocs_list_t *link;
238 
239  ocs_list_assert(list);
240  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
241  ocs_list_assert(item);
242 
243  link = item2link(list, item);
244  ocs_list_init_link(list, link);
245 
246  ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
247  ocs_list_assert(link->offset == list->offset);
248  ocs_list_assert(link->next == NULL);
249  ocs_list_assert(link->prev == NULL);
250 
251  _ocs_list_insert_link(list, list->next, item2link(list, item));
252 }
253 
254 
255 /**
256  * @ingroup os
257  * @brief Add an item to the tail of the list
258  *
259  * @param list Head of the list
260  * @param item Item to add
261  */
262 static inline void
263 ocs_list_add_tail(ocs_list_t *list, void *item)
264 {
265  ocs_list_t *link;
266 
267  ocs_list_assert(list);
268  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
269  ocs_list_assert(item);
270 
271  link = item2link(list, item);
272  ocs_list_init_link(list, link);
273 
274  ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
275  ocs_list_assert(link->offset == list->offset);
276  ocs_list_assert(link->next == NULL);
277  ocs_list_assert(link->prev == NULL);
278 
279  _ocs_list_insert_link(list->prev, list, link);
280 }
281 
282 
283 /**
284  * @ingroup os
285  * @brief Return the first item in the list
286  *
287  * @param list Head of the list
288  *
289  * @return pointer to the first item, NULL otherwise
290  */
291 static inline void *
292 ocs_list_get_head(ocs_list_t *list)
293 {
294  ocs_list_assert(list, NULL);
295  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
296  return ocs_list_empty(list) ? NULL : link2item(list, list->next);
297 }
298 
299 /**
300  * @ingroup os
301  * @brief Return the first item in the list
302  *
303  * @param list head of the list
304  *
305  * @return pointer to the last item, NULL otherwise
306  */
307 static inline void *
308 ocs_list_get_tail(ocs_list_t *list)
309 {
310  ocs_list_assert(list, NULL);
311  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
312  return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
313 }
314 
315 /**
316  * @ingroup os
317  * @brief Return the last item in the list
318  *
319  * @param list Pointer to list head
320  *
321  * @return pointer to the last item, NULL otherwise
322  */
323 static inline void *ocs_list_tail(ocs_list_t *list)
324 {
325  ocs_list_assert(list, NULL);
326  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
327  return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
328 }
329 
330 /**
331  * @ingroup os
332  * @brief Get the next item on the list
333  *
334  * @param list head of the list
335  * @param item current item
336  *
337  * @return pointer to the next item, NULL otherwise
338  */
339 static inline void *ocs_list_next(ocs_list_t *list, void *item)
340 {
341  ocs_list_t *link;
342 
343  //TODO: this is needed, not sure why
344  if (item == NULL) {
345  return NULL;
346  }
347 
348  ocs_list_assert(list, NULL);
349  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
350  ocs_list_assert(item, NULL);
351 
352  link = item2link(list, item);
353 
354  ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
355  ocs_list_assert(link->offset == list->offset, NULL);
356  ocs_list_assert(link->next, NULL);
357  ocs_list_assert(link->prev, NULL);
358 
359  if ((link->next) == list) {
360  return NULL;
361  }
362 
363  return link2item(list, link->next);
364 }
365 
366 /**
367  * @ingroup os
368  * @brief Remove and return an item from the head of the list
369  *
370  * @param list head of the list
371  *
372  * @return pointer to returned item, or NULL if list is empty
373  */
374 #define ocs_list_remove_head(list) ocs_list_remove(list, ocs_list_get_head(list))
375 
376 /**
377  * @ingroup os
378  * @brief Remove an item from the list
379  *
380  * @param list Head of the list
381  * @param item Item to remove
382  *
383  * @return pointer to item, or NULL if item is not found.
384  */
385 static inline void *ocs_list_remove(ocs_list_t *list, void *item)
386 {
387  ocs_list_t *link;
388  ocs_list_t *prev;
389  ocs_list_t *next;
390 
391  if (item == NULL) {
392  return NULL;
393  }
394  ocs_list_assert(list, NULL);
395  ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
396 
397  link = item2link(list, item);
398 
399  ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
400  ocs_list_assert(link->offset == list->offset, NULL);
401  ocs_list_assert(link->next, NULL);
402  ocs_list_assert(link->prev, NULL);
403 
404  prev = link->prev;
405  next = link->next;
406 
407  prev->next = next;
408  next->prev = prev;
409 
410  link->next = link->prev = NULL;
411 
412  return item;
413 }
414 
415 /**
416  * @brief Iterate a linked list
417  *
418  * Iterate a linked list.
419  *
420  * @param list Pointer to list
421  * @param item Pointer to iterated item
422  *
423  * note, item is NULL after full list is traversed.
424 
425  * @return none
426  */
427 
428 #define ocs_list_foreach(list, item) \
429  for (item = ocs_list_get_head((list)); item; item = ocs_list_next((list), item) )
430 
431 /**
432  * @brief Iterate a linked list safely
433  *
434  * Iterate a linked list safely, meaning that the iterated item
435  * may be safely removed from the list.
436  *
437  * @param list Pointer to list
438  * @param item Pointer to iterated item
439  * @param nxt Pointer to saveed iterated item
440  *
441  * note, item is NULL after full list is traversed.
442  *
443  * @return none
444  */
445 
446 #define ocs_list_foreach_safe(list, item, nxt) \
447  for (item = ocs_list_get_head(list), nxt = item ? ocs_list_next(list, item) : NULL; item; \
448  item = nxt, nxt = ocs_list_next(list, item))
449 
450 /**
451  * @brief Test if object is on a list
452  *
453  * Returns True if object is on a list
454  *
455  * @param link Pointer to list link
456  *
457  * @return returns True if object is on a list
458  */
459 static inline int32_t
461 {
462  return (link->next != NULL);
463 }
464 
465 #endif // __OCS_LIST_H__
466 
467 /**
468  * @page linux_os_overview OS APIs
469  * - @ref os
470  *
471  * <div class="overview">
472  * <img src="elx_linux_os.jpg" alt="OS Component" title="OS Component" align="right"/>
473  *
474  * <h2>Linux OS</h2>
475  *
476  * The Linux OS component consists of the OS abstraction and PCI subcomponents,
477  * as described in the following sections.
478  *
479  * <h3>OS Abstraction</h3>
480  *
481  * The transport, HAL, and SLI layers achieve operating system independence through
482  * the use of an OS abstraction. The required functionality includes:
483  * <ul><li>Defining all common objects (that is, DMA, SLI port, domain, and remote node).
484  * <li>Declaring endianess and providing functions for converting between host order
485  * and big-endian byte order.
486  * <li>Busy-wait or delay function.
487  * <li>Memory copy and set routines.
488  * <li>Memory allocation, free, and cache coherency functions for both CPU and DMA
489  * memory types.
490  * <li>Locking for concurrency protection.
491  * <li>Linked list and associated operations.
492  * <li>Bitmap and associated operations.
493  * <li>PCI register access.
494  * </ul>
495  *
496  * In most cases, the OS abstractions have been implemented with macros or in-line functions.
497  *
498  * <h3>PCI</h3>
499  *
500  * The ocs_lnx.c file contains code for performing PCI-related operations and interrupt
501  * handling. The ocs_pci_probe() and ocs_pci_remove() functions provide two main PCI operations:
502  * <ul><li>ocs_pci_probe() – allocates required structures, sets up interrupt handling, and
503  * sets up the hardware through the HAL. It also registers callback functions with
504  * the HAL, and requests the HAL to bring the port online.
505  * <li>ocs_pci_remove() – performs the reverse of ocs_pci_probe(). It requests the HAL to
506  * shutdown the port, releases resources, and unregisters the interrupt handler.
507  * </ul>
508  *
509  * Interrupt handling begins with the interrupt service routine, ocs_intr_msix(). This
510  * function launches a tasklet to perform interrupt services. This tasklet (ocs_tasklet) calls
511  * ocs_hal_process() in the HAL to process the interrupt.
512  *
513  * The ocs_lnx.c file also contains module parameters that can be set when the module is
514  * loaded. See the
515  * <i><a href="../../../../../doc/ocs_sdk_quick_start_guide.pdf" target="_blank">OneCore Storage Quick Start Guide</a></i>
516  * for a list of available module parameters.
517  * <br><br>
518  * </div><!-- overview -->
519  */
520 
521 
522 
523 /**
524  * @page uspace_linux_os_overview OS APIs
525  * - @ref os
526  *
527  * <div class="overview">
528  * <img src="elx_uspace_linux_os.jpg" alt="OS Component" title="OS Component" align="right"/>
529  *
530  * <h2>Linux OS</h2>
531  *
532  * The Linux OS component consists of the OS abstraction subcomponent,
533  * as described in the following section.
534  * @n @n
535  * @b Note: For the kernel space drivers, the OS component includes the PCI subcomponent.
536  * However, for the user space drivers, the PCI subcomponent is managed in the
537  * <a href="kernel_mod_overview.html">Kernel Module</a>.
538  *
539  * <h3>OS Abstraction</h3>
540  *
541  * The transport, HAL, and SLI layers achieve operating system independence through
542  * the use of an OS abstraction. The required functionality includes:
543  * <ul><li>Defining all common objects (that is, DMA, SLI port, domain, and remote node).
544  * <li>Declaring endianess and providing functions for converting between host order
545  * and big-endian byte order.
546  * <li>Busy-wait or delay function.
547  * <li>Memory copy and set routines.
548  * <li>Memory allocation, free, and cache coherency functions for both CPU and DMA
549  * memory types.
550  * <li>Locking for concurrency protection.
551  * <li>Linked list and associated operations.
552  * <li>Bitmap and associated operations.
553  * <li>PCI register access.
554  * </ul>
555  *
556  * In most cases, the OS abstractions have been implemented with macros or in-line functions.
557  * <br><br>
558  * </div><!-- overview -->
559  */
560 
561 /**
562  * @page bsd_os_overview OS APIs
563  * - @ref os
564  *
565  * <div class="overview">
566  * <img src="elx_bsd_os.jpg" alt="OS Component" title="OS Component" align="right"/>
567  *
568  * <h2>FreeBSD OS</h2>
569  *
570  * The FreeBSD OS component consists of the OS abstraction and PCI subcomponents,
571  * as described in the following sections.
572  *
573  * <h3>OS Abstraction</h3>
574  *
575  * The transport, HAL, and SLI layers achieve operating system independence through
576  * the use of an OS abstraction. The required functionality includes:
577  * <ul><li>Defining all common objects (that is, DMA, SLI port, domain, and remote node).
578  * <li>Declaring endianess and providing functions for converting between host order
579  * and big-endian byte order.
580  * <li>Busy-wait or delay function.
581  * <li>Memory copy and set routines.
582  * <li>Memory allocation, free, and cache coherency functions for both CPU and DMA
583  * memory types.
584  * <li>Locking for concurrency protection.
585  * <li>Linked list and associated operations.
586  * <li>Bitmap and associated operations.
587  * <li>PCI register access.
588  * </ul>
589  *
590  * In most cases, the OS abstractions have been implemented with macros or in-line functions.
591  * <br><br>
592  * <h3>PCI</h3>
593  *
594  * The PCI component, contained in ocs_pci.c file, is the main entry point to the driver and
595  * implements the standard FreeBSD methods:
596  * <ul><li>ocs_pci_probe() – determines if the driver supports the provided PCI vendor and device.
597  * ID.</li>
598  * <li>ocs_pci_attach() – performs device initialization and register with CAM.</li>
599  * <li>ocs_pci_detach() – stops the device.</li>
600  * <li>ocs_pci_shutdown() – frees allocated resources.</li></ul>
601  *
602  * The driver also allocates interrupt resources through this component,
603  * either using MSI-X or INTx (legacy) interrupts. @n @n
604  *
605  * The ocs_pci.c file also contains module parameters that can be set when the module is
606  * loaded. See the
607  * <i><a href="../../../../../doc/ocs_sdk_quick_start_guide.pdf" target="_blank">OneCore Storage Quick Start Guide</a></i>
608  * for a list of available module parameters.
609  * <br><br>
610  * </div><!-- overview -->
611  */
#define item2link(list, item)
Definition: ocs_list.h:87
static int32_t ocs_list_on_list(ocs_list_link_t *link)
Test if object is on a list.
Definition: ocs_list.h:460
ocs_list_t ocs_list_link_t
Definition: ocs_list.h:84
ocs_list_magic_decl ocs_list_t * next
Definition: ocs_list.h:80
static void _ocs_list_init(ocs_list_t *list, uint32_t offset)
Initialize a list.
Definition: ocs_list.h:104
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
list/link structure
Definition: ocs_list.h:78
#define ocs_list_assert(cond,...)
Definition: ocs_list.h:55
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
static int32_t ocs_list_is_singular(ocs_list_t *list)
Test if a list has single entry.
Definition: ocs_list.h:141
#define ocs_list_set_list_magic
Definition: ocs_list.h:52
#define OCS_LIST_LIST_MAGIC
Definition: ocs_list.h:50
void _ocs_list_assertmsg(const char *label, const char *filename, int linenum)
Definition: ocs_list.c:35
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
static void * ocs_list_get_tail(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:308
static int ocs_list_valid(ocs_list_t *list)
Test if a list is valid (ready for use)
Definition: ocs_list.h:155
#define OCS_LIST_LINK_MAGIC
Definition: ocs_list.h:51
ocs_list_t * prev
Definition: ocs_list.h:81
static void _ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
Insert link between two other links.
Definition: ocs_list.h:172
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
static void ocs_list_add_head(ocs_list_t *list, void *item)
Add an item to the head of the list.
Definition: ocs_list.h:235
static void * ocs_list_tail(ocs_list_t *list)
Return the last item in the list.
Definition: ocs_list.h:323
static void * ocs_list_next(ocs_list_t *list, void *item)
Get the next item on the list.
Definition: ocs_list.h:339
#define ocs_list_magic_decl
Definition: ocs_list.h:49
#define link2item(list, link)
Definition: ocs_list.h:90
static void ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
Initialize a list link for debug purposes.
Definition: ocs_list.h:210
uint32_t offset
Definition: ocs_list.h:82