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