|
@@ -0,0 +1,183 @@
|
|
|
+/*
|
|
|
+ * zfcp device driver
|
|
|
+ *
|
|
|
+ * Data structure and helper functions for tracking pending FSF
|
|
|
+ * requests.
|
|
|
+ *
|
|
|
+ * Copyright IBM Corporation 2009
|
|
|
+ */
|
|
|
+
|
|
|
+#ifndef ZFCP_REQLIST_H
|
|
|
+#define ZFCP_REQLIST_H
|
|
|
+
|
|
|
+/* number of hash buckets */
|
|
|
+#define ZFCP_REQ_LIST_BUCKETS 128
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct zfcp_reqlist - Container for request list (reqlist)
|
|
|
+ * @lock: Spinlock for protecting the hash list
|
|
|
+ * @list: Array of hashbuckets, each is a list of requests in this bucket
|
|
|
+ */
|
|
|
+struct zfcp_reqlist {
|
|
|
+ spinlock_t lock;
|
|
|
+ struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
|
|
|
+};
|
|
|
+
|
|
|
+static inline int zfcp_reqlist_hash(unsigned long req_id)
|
|
|
+{
|
|
|
+ return req_id % ZFCP_REQ_LIST_BUCKETS;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_alloc - Allocate and initialize reqlist
|
|
|
+ *
|
|
|
+ * Returns pointer to allocated reqlist on success, or NULL on
|
|
|
+ * allocation failure.
|
|
|
+ */
|
|
|
+static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+ struct zfcp_reqlist *rl;
|
|
|
+
|
|
|
+ rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
|
|
|
+ if (!rl)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ spin_lock_init(&rl->lock);
|
|
|
+
|
|
|
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
|
+ INIT_LIST_HEAD(&rl->buckets[i]);
|
|
|
+
|
|
|
+ return rl;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_isempty - Check whether the request list empty
|
|
|
+ * @rl: pointer to reqlist
|
|
|
+ *
|
|
|
+ * Returns: 1 if list is empty, 0 if not
|
|
|
+ */
|
|
|
+static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
|
+ if (!list_empty(&rl->buckets[i]))
|
|
|
+ return 0;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_free - Free allocated memory for reqlist
|
|
|
+ * @rl: The reqlist where to free memory
|
|
|
+ */
|
|
|
+static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
|
|
|
+{
|
|
|
+ /* sanity check */
|
|
|
+ BUG_ON(!zfcp_reqlist_isempty(rl));
|
|
|
+
|
|
|
+ kfree(rl);
|
|
|
+}
|
|
|
+
|
|
|
+static inline struct zfcp_fsf_req *
|
|
|
+_zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
|
|
|
+{
|
|
|
+ struct zfcp_fsf_req *req;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ i = zfcp_reqlist_hash(req_id);
|
|
|
+ list_for_each_entry(req, &rl->buckets[i], list)
|
|
|
+ if (req->req_id == req_id)
|
|
|
+ return req;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_find - Lookup FSF request by its request id
|
|
|
+ * @rl: The reqlist where to lookup the FSF request
|
|
|
+ * @req_id: The request id to look for
|
|
|
+ *
|
|
|
+ * Returns a pointer to the FSF request with the specified request id
|
|
|
+ * or NULL if there is no known FSF request with this id.
|
|
|
+ */
|
|
|
+static inline struct zfcp_fsf_req *
|
|
|
+zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct zfcp_fsf_req *req;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&rl->lock, flags);
|
|
|
+ req = _zfcp_reqlist_find(rl, req_id);
|
|
|
+ spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
+
|
|
|
+ return req;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
|
|
|
+ * @rl: reqlist where to search and remove entry
|
|
|
+ * @req_id: The request id of the request to look for
|
|
|
+ *
|
|
|
+ * This functions tries to find the FSF request with the specified
|
|
|
+ * id and then removes it from the reqlist. The reqlist lock is held
|
|
|
+ * during both steps of the operation.
|
|
|
+ *
|
|
|
+ * Returns: Pointer to the FSF request if the request has been found,
|
|
|
+ * NULL if it has not been found.
|
|
|
+ */
|
|
|
+static inline struct zfcp_fsf_req *
|
|
|
+zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, unsigned long req_id)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct zfcp_fsf_req *req;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&rl->lock, flags);
|
|
|
+ req = _zfcp_reqlist_find(rl, req_id);
|
|
|
+ if (req)
|
|
|
+ list_del(&req->list);
|
|
|
+ spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
+
|
|
|
+ return req;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_add - Add entry to reqlist
|
|
|
+ * @rl: reqlist where to add the entry
|
|
|
+ * @req: The entry to add
|
|
|
+ *
|
|
|
+ * The request id always increases. As an optimization new requests
|
|
|
+ * are added here with list_add_tail at the end of the bucket lists
|
|
|
+ * while old requests are looked up starting at the beginning of the
|
|
|
+ * lists.
|
|
|
+ */
|
|
|
+static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
|
|
|
+ struct zfcp_fsf_req *req)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ i = zfcp_reqlist_hash(req->req_id);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&rl->lock, flags);
|
|
|
+ list_add_tail(&req->list, &rl->buckets[i]);
|
|
|
+ spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * zfcp_reqlist_move - Move all entries from reqlist to simple list
|
|
|
+ * @rl: The zfcp_reqlist where to remove all entries
|
|
|
+ * @list: The list where to move all entries
|
|
|
+ */
|
|
|
+static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
|
|
|
+ struct list_head *list)
|
|
|
+{
|
|
|
+ unsigned int i;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&rl->lock, flags);
|
|
|
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
|
|
+ list_splice_init(&rl->buckets[i], list);
|
|
|
+ spin_unlock_irqrestore(&rl->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* ZFCP_REQLIST_H */
|