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