diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_aux.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 120 |
1 files changed, 111 insertions, 9 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 9cd789b8acd4..adc9d8f2c28f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -112,6 +112,105 @@ _zfcp_hex_dump(char *addr, int count) | |||
112 | printk("\n"); | 112 | printk("\n"); |
113 | } | 113 | } |
114 | 114 | ||
115 | |||
116 | /****************************************************************/ | ||
117 | /****** Functions to handle the request ID hash table ********/ | ||
118 | /****************************************************************/ | ||
119 | |||
120 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF | ||
121 | |||
122 | static int zfcp_reqlist_init(struct zfcp_adapter *adapter) | ||
123 | { | ||
124 | int i; | ||
125 | |||
126 | adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head), | ||
127 | GFP_KERNEL); | ||
128 | |||
129 | if (!adapter->req_list) | ||
130 | return -ENOMEM; | ||
131 | |||
132 | for (i=0; i<REQUEST_LIST_SIZE; i++) | ||
133 | INIT_LIST_HEAD(&adapter->req_list[i]); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void zfcp_reqlist_free(struct zfcp_adapter *adapter) | ||
139 | { | ||
140 | struct zfcp_fsf_req *request, *tmp; | ||
141 | unsigned int i; | ||
142 | |||
143 | for (i=0; i<REQUEST_LIST_SIZE; i++) { | ||
144 | if (list_empty(&adapter->req_list[i])) | ||
145 | continue; | ||
146 | |||
147 | list_for_each_entry_safe(request, tmp, | ||
148 | &adapter->req_list[i], list) | ||
149 | list_del(&request->list); | ||
150 | } | ||
151 | |||
152 | kfree(adapter->req_list); | ||
153 | } | ||
154 | |||
155 | void zfcp_reqlist_add(struct zfcp_adapter *adapter, | ||
156 | struct zfcp_fsf_req *fsf_req) | ||
157 | { | ||
158 | unsigned int i; | ||
159 | |||
160 | i = fsf_req->req_id % REQUEST_LIST_SIZE; | ||
161 | list_add_tail(&fsf_req->list, &adapter->req_list[i]); | ||
162 | } | ||
163 | |||
164 | void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id) | ||
165 | { | ||
166 | struct zfcp_fsf_req *request, *tmp; | ||
167 | unsigned int i, counter; | ||
168 | u64 dbg_tmp[2]; | ||
169 | |||
170 | i = req_id % REQUEST_LIST_SIZE; | ||
171 | BUG_ON(list_empty(&adapter->req_list[i])); | ||
172 | |||
173 | counter = 0; | ||
174 | list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) { | ||
175 | if (request->req_id == req_id) { | ||
176 | dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active); | ||
177 | dbg_tmp[1] = (u64) counter; | ||
178 | debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); | ||
179 | list_del(&request->list); | ||
180 | break; | ||
181 | } | ||
182 | counter++; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter, | ||
187 | unsigned long req_id) | ||
188 | { | ||
189 | struct zfcp_fsf_req *request, *tmp; | ||
190 | unsigned int i; | ||
191 | |||
192 | i = req_id % REQUEST_LIST_SIZE; | ||
193 | |||
194 | list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) | ||
195 | if (request->req_id == req_id) | ||
196 | return request; | ||
197 | |||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | ||
202 | { | ||
203 | unsigned int i; | ||
204 | |||
205 | for (i=0; i<REQUEST_LIST_SIZE; i++) | ||
206 | if (!list_empty(&adapter->req_list[i])) | ||
207 | return 0; | ||
208 | |||
209 | return 1; | ||
210 | } | ||
211 | |||
212 | #undef ZFCP_LOG_AREA | ||
213 | |||
115 | /****************************************************************/ | 214 | /****************************************************************/ |
116 | /************** Uncategorised Functions *************************/ | 215 | /************** Uncategorised Functions *************************/ |
117 | /****************************************************************/ | 216 | /****************************************************************/ |
@@ -961,8 +1060,12 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
961 | INIT_LIST_HEAD(&adapter->port_remove_lh); | 1060 | INIT_LIST_HEAD(&adapter->port_remove_lh); |
962 | 1061 | ||
963 | /* initialize list of fsf requests */ | 1062 | /* initialize list of fsf requests */ |
964 | spin_lock_init(&adapter->fsf_req_list_lock); | 1063 | spin_lock_init(&adapter->req_list_lock); |
965 | INIT_LIST_HEAD(&adapter->fsf_req_list_head); | 1064 | retval = zfcp_reqlist_init(adapter); |
1065 | if (retval) { | ||
1066 | ZFCP_LOG_INFO("request list initialization failed\n"); | ||
1067 | goto failed_low_mem_buffers; | ||
1068 | } | ||
966 | 1069 | ||
967 | /* initialize debug locks */ | 1070 | /* initialize debug locks */ |
968 | 1071 | ||
@@ -1041,8 +1144,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1041 | * !0 - struct zfcp_adapter data structure could not be removed | 1144 | * !0 - struct zfcp_adapter data structure could not be removed |
1042 | * (e.g. still used) | 1145 | * (e.g. still used) |
1043 | * locks: adapter list write lock is assumed to be held by caller | 1146 | * locks: adapter list write lock is assumed to be held by caller |
1044 | * adapter->fsf_req_list_lock is taken and released within this | ||
1045 | * function and must not be held on entry | ||
1046 | */ | 1147 | */ |
1047 | void | 1148 | void |
1048 | zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | 1149 | zfcp_adapter_dequeue(struct zfcp_adapter *adapter) |
@@ -1054,14 +1155,14 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1054 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 1155 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); |
1055 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 1156 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); |
1056 | /* sanity check: no pending FSF requests */ | 1157 | /* sanity check: no pending FSF requests */ |
1057 | spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); | 1158 | spin_lock_irqsave(&adapter->req_list_lock, flags); |
1058 | retval = !list_empty(&adapter->fsf_req_list_head); | 1159 | retval = zfcp_reqlist_isempty(adapter); |
1059 | spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); | 1160 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
1060 | if (retval) { | 1161 | if (!retval) { |
1061 | ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " | 1162 | ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " |
1062 | "%i requests outstanding\n", | 1163 | "%i requests outstanding\n", |
1063 | zfcp_get_busid_by_adapter(adapter), adapter, | 1164 | zfcp_get_busid_by_adapter(adapter), adapter, |
1064 | atomic_read(&adapter->fsf_reqs_active)); | 1165 | atomic_read(&adapter->reqs_active)); |
1065 | retval = -EBUSY; | 1166 | retval = -EBUSY; |
1066 | goto out; | 1167 | goto out; |
1067 | } | 1168 | } |
@@ -1087,6 +1188,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1087 | zfcp_free_low_mem_buffers(adapter); | 1188 | zfcp_free_low_mem_buffers(adapter); |
1088 | /* free memory of adapter data structure and queues */ | 1189 | /* free memory of adapter data structure and queues */ |
1089 | zfcp_qdio_free_queues(adapter); | 1190 | zfcp_qdio_free_queues(adapter); |
1191 | zfcp_reqlist_free(adapter); | ||
1090 | kfree(adapter->fc_stats); | 1192 | kfree(adapter->fc_stats); |
1091 | kfree(adapter->stats_reset_data); | 1193 | kfree(adapter->stats_reset_data); |
1092 | ZFCP_LOG_TRACE("freeing adapter structure\n"); | 1194 | ZFCP_LOG_TRACE("freeing adapter structure\n"); |