xref: /linux/drivers/s390/scsi/zfcp_reqlist.h (revision 3ab01810)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2b6bd2fb9SChristof Schmitt /*
3b6bd2fb9SChristof Schmitt  * zfcp device driver
4b6bd2fb9SChristof Schmitt  *
5b6bd2fb9SChristof Schmitt  * Data structure and helper functions for tracking pending FSF
6b6bd2fb9SChristof Schmitt  * requests.
7b6bd2fb9SChristof Schmitt  *
879f9abd6SBenjamin Block  * Copyright IBM Corp. 2009, 2023
9b6bd2fb9SChristof Schmitt  */
10b6bd2fb9SChristof Schmitt 
11b6bd2fb9SChristof Schmitt #ifndef ZFCP_REQLIST_H
12b6bd2fb9SChristof Schmitt #define ZFCP_REQLIST_H
13b6bd2fb9SChristof Schmitt 
1479f9abd6SBenjamin Block #include <linux/types.h>
1579f9abd6SBenjamin Block 
16b6bd2fb9SChristof Schmitt /* number of hash buckets */
1779f9abd6SBenjamin Block #define ZFCP_REQ_LIST_BUCKETS 128u
18b6bd2fb9SChristof Schmitt 
19b6bd2fb9SChristof Schmitt /**
20b6bd2fb9SChristof Schmitt  * struct zfcp_reqlist - Container for request list (reqlist)
21b6bd2fb9SChristof Schmitt  * @lock: Spinlock for protecting the hash list
22623cd180SSteffen Maier  * @buckets: Array of hashbuckets, each is a list of requests in this bucket
23b6bd2fb9SChristof Schmitt  */
24b6bd2fb9SChristof Schmitt struct zfcp_reqlist {
25b6bd2fb9SChristof Schmitt 	spinlock_t lock;
26b6bd2fb9SChristof Schmitt 	struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
27b6bd2fb9SChristof Schmitt };
28b6bd2fb9SChristof Schmitt 
zfcp_reqlist_hash(u64 req_id)29*3ab01810SBenjamin Block static inline size_t zfcp_reqlist_hash(u64 req_id)
30b6bd2fb9SChristof Schmitt {
31b6bd2fb9SChristof Schmitt 	return req_id % ZFCP_REQ_LIST_BUCKETS;
32b6bd2fb9SChristof Schmitt }
33b6bd2fb9SChristof Schmitt 
34b6bd2fb9SChristof Schmitt /**
35b6bd2fb9SChristof Schmitt  * zfcp_reqlist_alloc - Allocate and initialize reqlist
36b6bd2fb9SChristof Schmitt  *
37b6bd2fb9SChristof Schmitt  * Returns pointer to allocated reqlist on success, or NULL on
38b6bd2fb9SChristof Schmitt  * allocation failure.
39b6bd2fb9SChristof Schmitt  */
zfcp_reqlist_alloc(void)40b6bd2fb9SChristof Schmitt static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
41b6bd2fb9SChristof Schmitt {
4279f9abd6SBenjamin Block 	size_t i;
43b6bd2fb9SChristof Schmitt 	struct zfcp_reqlist *rl;
44b6bd2fb9SChristof Schmitt 
45b6bd2fb9SChristof Schmitt 	rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
46b6bd2fb9SChristof Schmitt 	if (!rl)
47b6bd2fb9SChristof Schmitt 		return NULL;
48b6bd2fb9SChristof Schmitt 
49b6bd2fb9SChristof Schmitt 	spin_lock_init(&rl->lock);
50b6bd2fb9SChristof Schmitt 
51b6bd2fb9SChristof Schmitt 	for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
52b6bd2fb9SChristof Schmitt 		INIT_LIST_HEAD(&rl->buckets[i]);
53b6bd2fb9SChristof Schmitt 
54b6bd2fb9SChristof Schmitt 	return rl;
55b6bd2fb9SChristof Schmitt }
56b6bd2fb9SChristof Schmitt 
57b6bd2fb9SChristof Schmitt /**
58b6bd2fb9SChristof Schmitt  * zfcp_reqlist_isempty - Check whether the request list empty
59b6bd2fb9SChristof Schmitt  * @rl: pointer to reqlist
60b6bd2fb9SChristof Schmitt  *
61b6bd2fb9SChristof Schmitt  * Returns: 1 if list is empty, 0 if not
62b6bd2fb9SChristof Schmitt  */
zfcp_reqlist_isempty(struct zfcp_reqlist * rl)63b6bd2fb9SChristof Schmitt static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
64b6bd2fb9SChristof Schmitt {
6579f9abd6SBenjamin Block 	size_t i;
66b6bd2fb9SChristof Schmitt 
67b6bd2fb9SChristof Schmitt 	for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
68b6bd2fb9SChristof Schmitt 		if (!list_empty(&rl->buckets[i]))
69b6bd2fb9SChristof Schmitt 			return 0;
70b6bd2fb9SChristof Schmitt 	return 1;
71b6bd2fb9SChristof Schmitt }
72b6bd2fb9SChristof Schmitt 
73b6bd2fb9SChristof Schmitt /**
74b6bd2fb9SChristof Schmitt  * zfcp_reqlist_free - Free allocated memory for reqlist
75b6bd2fb9SChristof Schmitt  * @rl: The reqlist where to free memory
76b6bd2fb9SChristof Schmitt  */
zfcp_reqlist_free(struct zfcp_reqlist * rl)77b6bd2fb9SChristof Schmitt static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
78b6bd2fb9SChristof Schmitt {
79b6bd2fb9SChristof Schmitt 	/* sanity check */
80b6bd2fb9SChristof Schmitt 	BUG_ON(!zfcp_reqlist_isempty(rl));
81b6bd2fb9SChristof Schmitt 
82b6bd2fb9SChristof Schmitt 	kfree(rl);
83b6bd2fb9SChristof Schmitt }
84b6bd2fb9SChristof Schmitt 
85b6bd2fb9SChristof Schmitt static inline struct zfcp_fsf_req *
_zfcp_reqlist_find(struct zfcp_reqlist * rl,u64 req_id)86*3ab01810SBenjamin Block _zfcp_reqlist_find(struct zfcp_reqlist *rl, u64 req_id)
87b6bd2fb9SChristof Schmitt {
88b6bd2fb9SChristof Schmitt 	struct zfcp_fsf_req *req;
8979f9abd6SBenjamin Block 	size_t i;
90b6bd2fb9SChristof Schmitt 
91b6bd2fb9SChristof Schmitt 	i = zfcp_reqlist_hash(req_id);
92b6bd2fb9SChristof Schmitt 	list_for_each_entry(req, &rl->buckets[i], list)
93b6bd2fb9SChristof Schmitt 		if (req->req_id == req_id)
94b6bd2fb9SChristof Schmitt 			return req;
95b6bd2fb9SChristof Schmitt 	return NULL;
96b6bd2fb9SChristof Schmitt }
97b6bd2fb9SChristof Schmitt 
98b6bd2fb9SChristof Schmitt /**
99b6bd2fb9SChristof Schmitt  * zfcp_reqlist_find - Lookup FSF request by its request id
100b6bd2fb9SChristof Schmitt  * @rl: The reqlist where to lookup the FSF request
101b6bd2fb9SChristof Schmitt  * @req_id: The request id to look for
102b6bd2fb9SChristof Schmitt  *
103b6bd2fb9SChristof Schmitt  * Returns a pointer to the FSF request with the specified request id
104b6bd2fb9SChristof Schmitt  * or NULL if there is no known FSF request with this id.
105b6bd2fb9SChristof Schmitt  */
106b6bd2fb9SChristof Schmitt static inline struct zfcp_fsf_req *
zfcp_reqlist_find(struct zfcp_reqlist * rl,u64 req_id)107*3ab01810SBenjamin Block zfcp_reqlist_find(struct zfcp_reqlist *rl, u64 req_id)
108b6bd2fb9SChristof Schmitt {
109b6bd2fb9SChristof Schmitt 	unsigned long flags;
110b6bd2fb9SChristof Schmitt 	struct zfcp_fsf_req *req;
111b6bd2fb9SChristof Schmitt 
112b6bd2fb9SChristof Schmitt 	spin_lock_irqsave(&rl->lock, flags);
113b6bd2fb9SChristof Schmitt 	req = _zfcp_reqlist_find(rl, req_id);
114b6bd2fb9SChristof Schmitt 	spin_unlock_irqrestore(&rl->lock, flags);
115b6bd2fb9SChristof Schmitt 
116b6bd2fb9SChristof Schmitt 	return req;
117b6bd2fb9SChristof Schmitt }
118b6bd2fb9SChristof Schmitt 
119b6bd2fb9SChristof Schmitt /**
120b6bd2fb9SChristof Schmitt  * zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
121b6bd2fb9SChristof Schmitt  * @rl: reqlist where to search and remove entry
122b6bd2fb9SChristof Schmitt  * @req_id: The request id of the request to look for
123b6bd2fb9SChristof Schmitt  *
124b6bd2fb9SChristof Schmitt  * This functions tries to find the FSF request with the specified
125b6bd2fb9SChristof Schmitt  * id and then removes it from the reqlist. The reqlist lock is held
126b6bd2fb9SChristof Schmitt  * during both steps of the operation.
127b6bd2fb9SChristof Schmitt  *
128b6bd2fb9SChristof Schmitt  * Returns: Pointer to the FSF request if the request has been found,
129b6bd2fb9SChristof Schmitt  * NULL if it has not been found.
130b6bd2fb9SChristof Schmitt  */
131b6bd2fb9SChristof Schmitt static inline struct zfcp_fsf_req *
zfcp_reqlist_find_rm(struct zfcp_reqlist * rl,u64 req_id)132*3ab01810SBenjamin Block zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, u64 req_id)
133b6bd2fb9SChristof Schmitt {
134b6bd2fb9SChristof Schmitt 	unsigned long flags;
135b6bd2fb9SChristof Schmitt 	struct zfcp_fsf_req *req;
136b6bd2fb9SChristof Schmitt 
137b6bd2fb9SChristof Schmitt 	spin_lock_irqsave(&rl->lock, flags);
138b6bd2fb9SChristof Schmitt 	req = _zfcp_reqlist_find(rl, req_id);
139b6bd2fb9SChristof Schmitt 	if (req)
140b6bd2fb9SChristof Schmitt 		list_del(&req->list);
141b6bd2fb9SChristof Schmitt 	spin_unlock_irqrestore(&rl->lock, flags);
142b6bd2fb9SChristof Schmitt 
143b6bd2fb9SChristof Schmitt 	return req;
144b6bd2fb9SChristof Schmitt }
145b6bd2fb9SChristof Schmitt 
146b6bd2fb9SChristof Schmitt /**
147b6bd2fb9SChristof Schmitt  * zfcp_reqlist_add - Add entry to reqlist
148b6bd2fb9SChristof Schmitt  * @rl: reqlist where to add the entry
149b6bd2fb9SChristof Schmitt  * @req: The entry to add
150b6bd2fb9SChristof Schmitt  *
151b6bd2fb9SChristof Schmitt  * The request id always increases. As an optimization new requests
152b6bd2fb9SChristof Schmitt  * are added here with list_add_tail at the end of the bucket lists
153b6bd2fb9SChristof Schmitt  * while old requests are looked up starting at the beginning of the
154b6bd2fb9SChristof Schmitt  * lists.
155b6bd2fb9SChristof Schmitt  */
zfcp_reqlist_add(struct zfcp_reqlist * rl,struct zfcp_fsf_req * req)156b6bd2fb9SChristof Schmitt static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
157b6bd2fb9SChristof Schmitt 				    struct zfcp_fsf_req *req)
158b6bd2fb9SChristof Schmitt {
15979f9abd6SBenjamin Block 	size_t i;
160b6bd2fb9SChristof Schmitt 	unsigned long flags;
161b6bd2fb9SChristof Schmitt 
162b6bd2fb9SChristof Schmitt 	i = zfcp_reqlist_hash(req->req_id);
163b6bd2fb9SChristof Schmitt 
164b6bd2fb9SChristof Schmitt 	spin_lock_irqsave(&rl->lock, flags);
165b6bd2fb9SChristof Schmitt 	list_add_tail(&req->list, &rl->buckets[i]);
166b6bd2fb9SChristof Schmitt 	spin_unlock_irqrestore(&rl->lock, flags);
167b6bd2fb9SChristof Schmitt }
168b6bd2fb9SChristof Schmitt 
169b6bd2fb9SChristof Schmitt /**
170b6bd2fb9SChristof Schmitt  * zfcp_reqlist_move - Move all entries from reqlist to simple list
171b6bd2fb9SChristof Schmitt  * @rl: The zfcp_reqlist where to remove all entries
172b6bd2fb9SChristof Schmitt  * @list: The list where to move all entries
173b6bd2fb9SChristof Schmitt  */
zfcp_reqlist_move(struct zfcp_reqlist * rl,struct list_head * list)174b6bd2fb9SChristof Schmitt static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
175b6bd2fb9SChristof Schmitt 				     struct list_head *list)
176b6bd2fb9SChristof Schmitt {
17779f9abd6SBenjamin Block 	size_t i;
178b6bd2fb9SChristof Schmitt 	unsigned long flags;
179b6bd2fb9SChristof Schmitt 
180b6bd2fb9SChristof Schmitt 	spin_lock_irqsave(&rl->lock, flags);
181b6bd2fb9SChristof Schmitt 	for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
182b6bd2fb9SChristof Schmitt 		list_splice_init(&rl->buckets[i], list);
183b6bd2fb9SChristof Schmitt 	spin_unlock_irqrestore(&rl->lock, flags);
184b6bd2fb9SChristof Schmitt }
185b6bd2fb9SChristof Schmitt 
186dac37e15SBenjamin Block /**
187dac37e15SBenjamin Block  * zfcp_reqlist_apply_for_all() - apply a function to every request.
188dac37e15SBenjamin Block  * @rl: the requestlist that contains the target requests.
189dac37e15SBenjamin Block  * @f: the function to apply to each request; the first parameter of the
190dac37e15SBenjamin Block  *     function will be the target-request; the second parameter is the same
191dac37e15SBenjamin Block  *     pointer as given with the argument @data.
192dac37e15SBenjamin Block  * @data: freely chosen argument; passed through to @f as second parameter.
193dac37e15SBenjamin Block  *
194dac37e15SBenjamin Block  * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
195dac37e15SBenjamin Block  * table (not a 'safe' variant, so don't modify the list).
196dac37e15SBenjamin Block  *
197dac37e15SBenjamin Block  * Holds @rl->lock over the entire request-iteration.
198dac37e15SBenjamin Block  */
199dac37e15SBenjamin Block static inline void
zfcp_reqlist_apply_for_all(struct zfcp_reqlist * rl,void (* f)(struct zfcp_fsf_req *,void *),void * data)200dac37e15SBenjamin Block zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
201dac37e15SBenjamin Block 			   void (*f)(struct zfcp_fsf_req *, void *), void *data)
202dac37e15SBenjamin Block {
203dac37e15SBenjamin Block 	struct zfcp_fsf_req *req;
204dac37e15SBenjamin Block 	unsigned long flags;
20579f9abd6SBenjamin Block 	size_t i;
206dac37e15SBenjamin Block 
207dac37e15SBenjamin Block 	spin_lock_irqsave(&rl->lock, flags);
208dac37e15SBenjamin Block 	for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
209dac37e15SBenjamin Block 		list_for_each_entry(req, &rl->buckets[i], list)
210dac37e15SBenjamin Block 			f(req, data);
211dac37e15SBenjamin Block 	spin_unlock_irqrestore(&rl->lock, flags);
212dac37e15SBenjamin Block }
213dac37e15SBenjamin Block 
214b6bd2fb9SChristof Schmitt #endif /* ZFCP_REQLIST_H */
215