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