ef270ab1b6
The ocs_fc(4) driver supports the following hardware: Emulex 16/8G FC GEN 5 HBAS LPe15004 FC Host Bus Adapters LPe160XX FC Host Bus Adapters Emulex 32/16G FC GEN 6 HBAS LPe3100X FC Host Bus Adapters LPe3200X FC Host Bus Adapters The driver supports target and initiator mode, and also supports FC-Tape. Note that the driver only currently works on little endian platforms. It is only included in the module build for amd64 and i386, and in GENERIC on amd64 only. Submitted by: Ram Kishore Vegesna <ram.vegesna@broadcom.com> Reviewed by: mav MFC after: 5 days Relnotes: yes Sponsored by: Broadcom Differential Revision: https://reviews.freebsd.org/D11423
450 lines
11 KiB
C
450 lines
11 KiB
C
/*-
|
|
* Copyright (c) 2017 Broadcom. All rights reserved.
|
|
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* OCS linked list API
|
|
*
|
|
*/
|
|
|
|
#if !defined(__OCS_LIST_H__)
|
|
#define __OCS_LIST_H__
|
|
|
|
#define OCS_LIST_DEBUG
|
|
|
|
#if defined(OCS_LIST_DEBUG)
|
|
|
|
|
|
#define ocs_list_magic_decl uint32_t magic;
|
|
#define OCS_LIST_LIST_MAGIC 0xcafe0000
|
|
#define OCS_LIST_LINK_MAGIC 0xcafe0001
|
|
#define ocs_list_set_list_magic list->magic = OCS_LIST_LIST_MAGIC
|
|
#define ocs_list_set_link_magic list->magic = OCS_LIST_LINK_MAGIC
|
|
|
|
#define ocs_list_assert(cond, ...) \
|
|
if (!(cond)) { \
|
|
return __VA_ARGS__; \
|
|
}
|
|
#else
|
|
#define ocs_list_magic_decl
|
|
#define ocs_list_assert(cond, ...)
|
|
#define ocs_list_set_list_magic
|
|
#define ocs_list_set_link_magic
|
|
#endif
|
|
|
|
/**
|
|
* @brief list/link structure
|
|
*
|
|
* used for both the list object, and the link object(s). offset
|
|
* is specified when the list is initialized; this implies that a list
|
|
* will always point to objects of the same type. offset is not used
|
|
* when ocs_list_t is used as a link (ocs_list_link_t).
|
|
*
|
|
*/
|
|
|
|
typedef struct ocs_list_s ocs_list_t;
|
|
struct ocs_list_s {
|
|
ocs_list_magic_decl /*<< used if debugging is enabled */
|
|
ocs_list_t *next; /*<< pointer to head of list (or next if link) */
|
|
ocs_list_t *prev; /*<< pointer to tail of list (or previous if link) */
|
|
uint32_t offset; /*<< offset in bytes to the link element of the objects in list */
|
|
};
|
|
typedef ocs_list_t ocs_list_link_t;
|
|
|
|
/* item2link - return pointer to link given pointer to an item */
|
|
#define item2link(list, item) ((ocs_list_t*) (((uint8_t*)(item)) + (list)->offset))
|
|
|
|
/* link2item - return pointer to item given pointer to a link */
|
|
#define link2item(list, link) ((void*) (((uint8_t*)(link)) - (list)->offset))
|
|
|
|
/**
|
|
* @brief Initialize a list
|
|
*
|
|
* A list object is initialized. Helper define is used to call _ocs_list_init() with
|
|
* offsetof(type, link)
|
|
*
|
|
* @param list Pointer to list
|
|
* @param offset Offset in bytes in item to the link element
|
|
*
|
|
* @return none
|
|
*/
|
|
static inline void
|
|
_ocs_list_init(ocs_list_t *list, uint32_t offset)
|
|
{
|
|
ocs_list_assert(list);
|
|
ocs_list_set_list_magic;
|
|
|
|
list->next = list;
|
|
list->prev = list;
|
|
list->offset = offset;
|
|
}
|
|
#define ocs_list_init(head, type, link) _ocs_list_init(head, offsetof(type, link))
|
|
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Test if a list is empty
|
|
*
|
|
* @param list Pointer to list head
|
|
*
|
|
* @return 1 if empty, 0 otherwise
|
|
*/
|
|
static inline int32_t
|
|
ocs_list_empty(ocs_list_t *list)
|
|
{
|
|
ocs_list_assert(list, 1);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, 1);
|
|
return list->next == list;
|
|
}
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Test if a list is valid (ready for use)
|
|
*
|
|
* @param list Pointer to list head
|
|
*
|
|
* @return true if list is usable, false otherwise
|
|
*/
|
|
static inline int
|
|
ocs_list_valid(ocs_list_t *list)
|
|
{
|
|
return (list->magic == OCS_LIST_LIST_MAGIC);
|
|
}
|
|
|
|
/**
|
|
* @brief Insert link between two other links
|
|
*
|
|
* Inserts a link in between two other links
|
|
*
|
|
* @param a Pointer to first link
|
|
* @param b Pointer to next link
|
|
* @param c Pointer to link to insert between a and b
|
|
*
|
|
* @return none
|
|
*/
|
|
static inline void
|
|
_ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
|
|
{
|
|
ocs_list_assert(a);
|
|
ocs_list_assert((a->magic == OCS_LIST_LIST_MAGIC) || (a->magic == OCS_LIST_LINK_MAGIC));
|
|
ocs_list_assert(a->next);
|
|
ocs_list_assert(a->prev);
|
|
ocs_list_assert(b);
|
|
ocs_list_assert((b->magic == OCS_LIST_LIST_MAGIC) || (b->magic == OCS_LIST_LINK_MAGIC));
|
|
ocs_list_assert(b->next);
|
|
ocs_list_assert(b->prev);
|
|
ocs_list_assert(c);
|
|
ocs_list_assert((c->magic == OCS_LIST_LIST_MAGIC) || (c->magic == OCS_LIST_LINK_MAGIC));
|
|
ocs_list_assert(!c->next);
|
|
ocs_list_assert(!c->prev);
|
|
|
|
ocs_list_assert(a->offset == b->offset);
|
|
ocs_list_assert(b->offset == c->offset);
|
|
|
|
c->next = a->next;
|
|
c->prev = b->prev;
|
|
a->next = c;
|
|
b->prev = c;
|
|
}
|
|
|
|
#if defined(OCS_LIST_DEBUG)
|
|
/**
|
|
* @brief Initialize a list link for debug purposes
|
|
*
|
|
* For debugging a linked list link element has a magic number that is initialized,
|
|
* and the offset value initialzied and used for subsequent assertions.
|
|
*
|
|
*
|
|
* @param list Pointer to list head
|
|
* @param link Pointer to link to be initialized
|
|
*
|
|
* @return none
|
|
*/
|
|
static inline void
|
|
ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
|
|
{
|
|
ocs_list_assert(list);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
|
|
ocs_list_assert(link);
|
|
|
|
if (link->magic == 0) {
|
|
link->magic = OCS_LIST_LINK_MAGIC;
|
|
link->offset = list->offset;
|
|
link->next = NULL;
|
|
link->prev = NULL;
|
|
}
|
|
}
|
|
#else
|
|
#define ocs_list_init_link(...)
|
|
#endif
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Add an item to the head of the list
|
|
*
|
|
* @param list Pointer to list head
|
|
* @param item Item to add
|
|
*/
|
|
static inline void
|
|
ocs_list_add_head(ocs_list_t *list, void *item)
|
|
{
|
|
ocs_list_t *link;
|
|
|
|
ocs_list_assert(list);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
|
|
ocs_list_assert(item);
|
|
|
|
link = item2link(list, item);
|
|
ocs_list_init_link(list, link);
|
|
|
|
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
|
|
ocs_list_assert(link->offset == list->offset);
|
|
ocs_list_assert(link->next == NULL);
|
|
ocs_list_assert(link->prev == NULL);
|
|
|
|
_ocs_list_insert_link(list, list->next, item2link(list, item));
|
|
}
|
|
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Add an item to the tail of the list
|
|
*
|
|
* @param list Head of the list
|
|
* @param item Item to add
|
|
*/
|
|
static inline void
|
|
ocs_list_add_tail(ocs_list_t *list, void *item)
|
|
{
|
|
ocs_list_t *link;
|
|
|
|
ocs_list_assert(list);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
|
|
ocs_list_assert(item);
|
|
|
|
link = item2link(list, item);
|
|
ocs_list_init_link(list, link);
|
|
|
|
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
|
|
ocs_list_assert(link->offset == list->offset);
|
|
ocs_list_assert(link->next == NULL);
|
|
ocs_list_assert(link->prev == NULL);
|
|
|
|
_ocs_list_insert_link(list->prev, list, link);
|
|
}
|
|
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Return the first item in the list
|
|
*
|
|
* @param list Head of the list
|
|
*
|
|
* @return pointer to the first item, NULL otherwise
|
|
*/
|
|
static inline void *
|
|
ocs_list_get_head(ocs_list_t *list)
|
|
{
|
|
ocs_list_assert(list, NULL);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
|
|
return ocs_list_empty(list) ? NULL : link2item(list, list->next);
|
|
}
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Return the first item in the list
|
|
*
|
|
* @param list head of the list
|
|
*
|
|
* @return pointer to the last item, NULL otherwise
|
|
*/
|
|
static inline void *
|
|
ocs_list_get_tail(ocs_list_t *list)
|
|
{
|
|
ocs_list_assert(list, NULL);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
|
|
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
|
|
}
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Return the last item in the list
|
|
*
|
|
* @param list Pointer to list head
|
|
*
|
|
* @return pointer to the last item, NULL otherwise
|
|
*/
|
|
static inline void *ocs_list_tail(ocs_list_t *list)
|
|
{
|
|
ocs_list_assert(list, NULL);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
|
|
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
|
|
}
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Get the next item on the list
|
|
*
|
|
* @param list head of the list
|
|
* @param item current item
|
|
*
|
|
* @return pointer to the next item, NULL otherwise
|
|
*/
|
|
static inline void *ocs_list_next(ocs_list_t *list, void *item)
|
|
{
|
|
ocs_list_t *link;
|
|
|
|
if (item == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ocs_list_assert(list, NULL);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
|
|
ocs_list_assert(item, NULL);
|
|
|
|
link = item2link(list, item);
|
|
|
|
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
|
|
ocs_list_assert(link->offset == list->offset, NULL);
|
|
ocs_list_assert(link->next, NULL);
|
|
ocs_list_assert(link->prev, NULL);
|
|
|
|
if ((link->next) == list) {
|
|
return NULL;
|
|
}
|
|
|
|
return link2item(list, link->next);
|
|
}
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Remove and return an item from the head of the list
|
|
*
|
|
* @param list head of the list
|
|
*
|
|
* @return pointer to returned item, or NULL if list is empty
|
|
*/
|
|
#define ocs_list_remove_head(list) ocs_list_remove(list, ocs_list_get_head(list))
|
|
|
|
/**
|
|
* @ingroup os
|
|
* @brief Remove an item from the list
|
|
*
|
|
* @param list Head of the list
|
|
* @param item Item to remove
|
|
*
|
|
* @return pointer to item, or NULL if item is not found.
|
|
*/
|
|
static inline void *ocs_list_remove(ocs_list_t *list, void *item)
|
|
{
|
|
ocs_list_t *link;
|
|
ocs_list_t *prev;
|
|
ocs_list_t *next;
|
|
|
|
if (item == NULL) {
|
|
return NULL;
|
|
}
|
|
ocs_list_assert(list, NULL);
|
|
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
|
|
|
|
link = item2link(list, item);
|
|
|
|
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
|
|
ocs_list_assert(link->offset == list->offset, NULL);
|
|
ocs_list_assert(link->next, NULL);
|
|
ocs_list_assert(link->prev, NULL);
|
|
|
|
prev = link->prev;
|
|
next = link->next;
|
|
|
|
prev->next = next;
|
|
next->prev = prev;
|
|
|
|
link->next = link->prev = NULL;
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* @brief Iterate a linked list
|
|
*
|
|
* Iterate a linked list.
|
|
*
|
|
* @param list Pointer to list
|
|
* @param item Pointer to iterated item
|
|
*
|
|
* note, item is NULL after full list is traversed.
|
|
|
|
* @return none
|
|
*/
|
|
|
|
#define ocs_list_foreach(list, item) \
|
|
for (item = ocs_list_get_head((list)); item; item = ocs_list_next((list), item) )
|
|
|
|
/**
|
|
* @brief Iterate a linked list safely
|
|
*
|
|
* Iterate a linked list safely, meaning that the iterated item
|
|
* may be safely removed from the list.
|
|
*
|
|
* @param list Pointer to list
|
|
* @param item Pointer to iterated item
|
|
* @param nxt Pointer to saveed iterated item
|
|
*
|
|
* note, item is NULL after full list is traversed.
|
|
*
|
|
* @return none
|
|
*/
|
|
|
|
#define ocs_list_foreach_safe(list, item, nxt) \
|
|
for (item = ocs_list_get_head(list), nxt = item ? ocs_list_next(list, item) : NULL; item; \
|
|
item = nxt, nxt = ocs_list_next(list, item))
|
|
|
|
/**
|
|
* @brief Test if object is on a list
|
|
*
|
|
* Returns True if object is on a list
|
|
*
|
|
* @param link Pointer to list link
|
|
*
|
|
* @return returns True if object is on a list
|
|
*/
|
|
static inline int32_t
|
|
ocs_list_on_list(ocs_list_link_t *link)
|
|
{
|
|
return (link->next != NULL);
|
|
}
|
|
|
|
#endif /* __OCS_LIST_H__ */
|