mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 08:35:08 +08:00
3ab0181015
We use different integer types throughout zfcp to store the FSF request ID and related values; some places use 'unsigned long' and others 'u64'. On s390x these are effectively the same type, but this might cause confusions and is generally inconsistent. The specification for the used hardware specifies this value as a 64-bit number, and ultimately we use this value to communicate with the hardware, so it makes sense to change the type of all these variables to 'u64' where we can. The only exception being when we store it in the 'host_scribble' field of a 'struct scsi_cmnd'; for this case we add a build time check to make sure they are compatible. Link: https://lore.kernel.org/r/9c9cbe5acc2b419a22dce2fed847e3db91b60201.1677000450.git.bblock@linux.ibm.com Signed-off-by: Benjamin Block <bblock@linux.ibm.com> Reviewed-by: Steffen Maier <maier@linux.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
215 lines
5.4 KiB
C
215 lines
5.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* zfcp device driver
|
|
*
|
|
* Data structure and helper functions for tracking pending FSF
|
|
* requests.
|
|
*
|
|
* Copyright IBM Corp. 2009, 2023
|
|
*/
|
|
|
|
#ifndef ZFCP_REQLIST_H
|
|
#define ZFCP_REQLIST_H
|
|
|
|
#include <linux/types.h>
|
|
|
|
/* number of hash buckets */
|
|
#define ZFCP_REQ_LIST_BUCKETS 128u
|
|
|
|
/**
|
|
* struct zfcp_reqlist - Container for request list (reqlist)
|
|
* @lock: Spinlock for protecting the hash list
|
|
* @buckets: Array of hashbuckets, each is a list of requests in this bucket
|
|
*/
|
|
struct zfcp_reqlist {
|
|
spinlock_t lock;
|
|
struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
|
|
};
|
|
|
|
static inline size_t zfcp_reqlist_hash(u64 req_id)
|
|
{
|
|
return req_id % ZFCP_REQ_LIST_BUCKETS;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_alloc - Allocate and initialize reqlist
|
|
*
|
|
* Returns pointer to allocated reqlist on success, or NULL on
|
|
* allocation failure.
|
|
*/
|
|
static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
|
|
{
|
|
size_t i;
|
|
struct zfcp_reqlist *rl;
|
|
|
|
rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
|
|
if (!rl)
|
|
return NULL;
|
|
|
|
spin_lock_init(&rl->lock);
|
|
|
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
INIT_LIST_HEAD(&rl->buckets[i]);
|
|
|
|
return rl;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_isempty - Check whether the request list empty
|
|
* @rl: pointer to reqlist
|
|
*
|
|
* Returns: 1 if list is empty, 0 if not
|
|
*/
|
|
static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
if (!list_empty(&rl->buckets[i]))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_free - Free allocated memory for reqlist
|
|
* @rl: The reqlist where to free memory
|
|
*/
|
|
static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
|
|
{
|
|
/* sanity check */
|
|
BUG_ON(!zfcp_reqlist_isempty(rl));
|
|
|
|
kfree(rl);
|
|
}
|
|
|
|
static inline struct zfcp_fsf_req *
|
|
_zfcp_reqlist_find(struct zfcp_reqlist *rl, u64 req_id)
|
|
{
|
|
struct zfcp_fsf_req *req;
|
|
size_t i;
|
|
|
|
i = zfcp_reqlist_hash(req_id);
|
|
list_for_each_entry(req, &rl->buckets[i], list)
|
|
if (req->req_id == req_id)
|
|
return req;
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_find - Lookup FSF request by its request id
|
|
* @rl: The reqlist where to lookup the FSF request
|
|
* @req_id: The request id to look for
|
|
*
|
|
* Returns a pointer to the FSF request with the specified request id
|
|
* or NULL if there is no known FSF request with this id.
|
|
*/
|
|
static inline struct zfcp_fsf_req *
|
|
zfcp_reqlist_find(struct zfcp_reqlist *rl, u64 req_id)
|
|
{
|
|
unsigned long flags;
|
|
struct zfcp_fsf_req *req;
|
|
|
|
spin_lock_irqsave(&rl->lock, flags);
|
|
req = _zfcp_reqlist_find(rl, req_id);
|
|
spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
|
return req;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
|
|
* @rl: reqlist where to search and remove entry
|
|
* @req_id: The request id of the request to look for
|
|
*
|
|
* This functions tries to find the FSF request with the specified
|
|
* id and then removes it from the reqlist. The reqlist lock is held
|
|
* during both steps of the operation.
|
|
*
|
|
* Returns: Pointer to the FSF request if the request has been found,
|
|
* NULL if it has not been found.
|
|
*/
|
|
static inline struct zfcp_fsf_req *
|
|
zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, u64 req_id)
|
|
{
|
|
unsigned long flags;
|
|
struct zfcp_fsf_req *req;
|
|
|
|
spin_lock_irqsave(&rl->lock, flags);
|
|
req = _zfcp_reqlist_find(rl, req_id);
|
|
if (req)
|
|
list_del(&req->list);
|
|
spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
|
return req;
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_add - Add entry to reqlist
|
|
* @rl: reqlist where to add the entry
|
|
* @req: The entry to add
|
|
*
|
|
* The request id always increases. As an optimization new requests
|
|
* are added here with list_add_tail at the end of the bucket lists
|
|
* while old requests are looked up starting at the beginning of the
|
|
* lists.
|
|
*/
|
|
static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
|
|
struct zfcp_fsf_req *req)
|
|
{
|
|
size_t i;
|
|
unsigned long flags;
|
|
|
|
i = zfcp_reqlist_hash(req->req_id);
|
|
|
|
spin_lock_irqsave(&rl->lock, flags);
|
|
list_add_tail(&req->list, &rl->buckets[i]);
|
|
spin_unlock_irqrestore(&rl->lock, flags);
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_move - Move all entries from reqlist to simple list
|
|
* @rl: The zfcp_reqlist where to remove all entries
|
|
* @list: The list where to move all entries
|
|
*/
|
|
static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
|
|
struct list_head *list)
|
|
{
|
|
size_t i;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&rl->lock, flags);
|
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
list_splice_init(&rl->buckets[i], list);
|
|
spin_unlock_irqrestore(&rl->lock, flags);
|
|
}
|
|
|
|
/**
|
|
* zfcp_reqlist_apply_for_all() - apply a function to every request.
|
|
* @rl: the requestlist that contains the target requests.
|
|
* @f: the function to apply to each request; the first parameter of the
|
|
* function will be the target-request; the second parameter is the same
|
|
* pointer as given with the argument @data.
|
|
* @data: freely chosen argument; passed through to @f as second parameter.
|
|
*
|
|
* Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
|
|
* table (not a 'safe' variant, so don't modify the list).
|
|
*
|
|
* Holds @rl->lock over the entire request-iteration.
|
|
*/
|
|
static inline void
|
|
zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
|
|
void (*f)(struct zfcp_fsf_req *, void *), void *data)
|
|
{
|
|
struct zfcp_fsf_req *req;
|
|
unsigned long flags;
|
|
size_t i;
|
|
|
|
spin_lock_irqsave(&rl->lock, flags);
|
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
list_for_each_entry(req, &rl->buckets[i], list)
|
|
f(req, data);
|
|
spin_unlock_irqrestore(&rl->lock, flags);
|
|
}
|
|
|
|
#endif /* ZFCP_REQLIST_H */
|