[SCSI] zfcp: Issue FCP command without holding SCSI host_lock
[linux-2.6.git] / drivers / s390 / scsi / zfcp_reqlist.h
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
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  */
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  */
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  */
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 *
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 *
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 *
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  */
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  */
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 */