diff options
author | James Bottomley <James.Bottomley@suse.de> | 2010-05-18 10:33:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-05-18 10:37:41 -0400 |
commit | 95bb335c0ebe96afe926387a1ef3a096bd884a82 (patch) | |
tree | 56115332b4f2f7ef300c36248a6a7d20db2e639d /drivers/s390/scsi/zfcp_qdio.c | |
parent | 1b4d0d8ea7b3cbd107f345ab766416f9b38ce66a (diff) | |
parent | 9cccde93fed1ca988eb2fb17ab9194bf7b5ed1b0 (diff) |
[SCSI] Merge scsi-misc-2.6 into scsi-rc-fixes-2.6
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/s390/scsi/zfcp_qdio.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 108 |
1 files changed, 61 insertions, 47 deletions
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index dbfa312a7f50..28117e130e2c 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Setup and helper functions to access QDIO. | 4 | * Setup and helper functions to access QDIO. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2009 | 6 | * Copyright IBM Corporation 2002, 2010 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -151,8 +151,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, | |||
151 | } | 151 | } |
152 | 152 | ||
153 | static struct qdio_buffer_element * | 153 | static struct qdio_buffer_element * |
154 | zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | 154 | zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) |
155 | unsigned long sbtype) | ||
156 | { | 155 | { |
157 | struct qdio_buffer_element *sbale; | 156 | struct qdio_buffer_element *sbale; |
158 | 157 | ||
@@ -180,17 +179,16 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | |||
180 | 179 | ||
181 | /* set storage-block type for new SBAL */ | 180 | /* set storage-block type for new SBAL */ |
182 | sbale = zfcp_qdio_sbale_curr(qdio, q_req); | 181 | sbale = zfcp_qdio_sbale_curr(qdio, q_req); |
183 | sbale->flags |= sbtype; | 182 | sbale->flags |= q_req->sbtype; |
184 | 183 | ||
185 | return sbale; | 184 | return sbale; |
186 | } | 185 | } |
187 | 186 | ||
188 | static struct qdio_buffer_element * | 187 | static struct qdio_buffer_element * |
189 | zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | 188 | zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) |
190 | unsigned int sbtype) | ||
191 | { | 189 | { |
192 | if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) | 190 | if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL) |
193 | return zfcp_qdio_sbal_chain(qdio, q_req, sbtype); | 191 | return zfcp_qdio_sbal_chain(qdio, q_req); |
194 | q_req->sbale_curr++; | 192 | q_req->sbale_curr++; |
195 | return zfcp_qdio_sbale_curr(qdio, q_req); | 193 | return zfcp_qdio_sbale_curr(qdio, q_req); |
196 | } | 194 | } |
@@ -206,62 +204,38 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio, | |||
206 | zfcp_qdio_zero_sbals(sbal, first, count); | 204 | zfcp_qdio_zero_sbals(sbal, first, count); |
207 | } | 205 | } |
208 | 206 | ||
209 | static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio, | ||
210 | struct zfcp_qdio_req *q_req, | ||
211 | unsigned int sbtype, void *start_addr, | ||
212 | unsigned int total_length) | ||
213 | { | ||
214 | struct qdio_buffer_element *sbale; | ||
215 | unsigned long remaining, length; | ||
216 | void *addr; | ||
217 | |||
218 | /* split segment up */ | ||
219 | for (addr = start_addr, remaining = total_length; remaining > 0; | ||
220 | addr += length, remaining -= length) { | ||
221 | sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype); | ||
222 | if (!sbale) { | ||
223 | atomic_inc(&qdio->req_q_full); | ||
224 | zfcp_qdio_undo_sbals(qdio, q_req); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | /* new piece must not exceed next page boundary */ | ||
229 | length = min(remaining, | ||
230 | (PAGE_SIZE - ((unsigned long)addr & | ||
231 | (PAGE_SIZE - 1)))); | ||
232 | sbale->addr = addr; | ||
233 | sbale->length = length; | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | /** | 207 | /** |
239 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list | 208 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list |
240 | * @fsf_req: request to be processed | 209 | * @qdio: pointer to struct zfcp_qdio |
241 | * @sbtype: SBALE flags | 210 | * @q_req: pointer to struct zfcp_qdio_req |
242 | * @sg: scatter-gather list | 211 | * @sg: scatter-gather list |
243 | * @max_sbals: upper bound for number of SBALs to be used | 212 | * @max_sbals: upper bound for number of SBALs to be used |
244 | * Returns: number of bytes, or error (negativ) | 213 | * Returns: number of bytes, or error (negativ) |
245 | */ | 214 | */ |
246 | int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | 215 | int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, |
247 | unsigned long sbtype, struct scatterlist *sg, | 216 | struct scatterlist *sg, int max_sbals) |
248 | int max_sbals) | ||
249 | { | 217 | { |
250 | struct qdio_buffer_element *sbale; | 218 | struct qdio_buffer_element *sbale; |
251 | int retval, bytes = 0; | 219 | int bytes = 0; |
252 | 220 | ||
253 | /* figure out last allowed SBAL */ | 221 | /* figure out last allowed SBAL */ |
254 | zfcp_qdio_sbal_limit(qdio, q_req, max_sbals); | 222 | zfcp_qdio_sbal_limit(qdio, q_req, max_sbals); |
255 | 223 | ||
256 | /* set storage-block type for this request */ | 224 | /* set storage-block type for this request */ |
257 | sbale = zfcp_qdio_sbale_req(qdio, q_req); | 225 | sbale = zfcp_qdio_sbale_req(qdio, q_req); |
258 | sbale->flags |= sbtype; | 226 | sbale->flags |= q_req->sbtype; |
259 | 227 | ||
260 | for (; sg; sg = sg_next(sg)) { | 228 | for (; sg; sg = sg_next(sg)) { |
261 | retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype, | 229 | sbale = zfcp_qdio_sbale_next(qdio, q_req); |
262 | sg_virt(sg), sg->length); | 230 | if (!sbale) { |
263 | if (retval < 0) | 231 | atomic_inc(&qdio->req_q_full); |
264 | return retval; | 232 | zfcp_qdio_undo_sbals(qdio, q_req); |
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | sbale->addr = sg_virt(sg); | ||
237 | sbale->length = sg->length; | ||
238 | |||
265 | bytes += sg->length; | 239 | bytes += sg->length; |
266 | } | 240 | } |
267 | 241 | ||
@@ -272,6 +246,46 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | |||
272 | return bytes; | 246 | return bytes; |
273 | } | 247 | } |
274 | 248 | ||
249 | static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) | ||
250 | { | ||
251 | struct zfcp_qdio_queue *req_q = &qdio->req_q; | ||
252 | |||
253 | spin_lock_bh(&qdio->req_q_lock); | ||
254 | if (atomic_read(&req_q->count)) | ||
255 | return 1; | ||
256 | spin_unlock_bh(&qdio->req_q_lock); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary | ||
262 | * @qdio: pointer to struct zfcp_qdio | ||
263 | * | ||
264 | * The req_q_lock must be held by the caller of this function, and | ||
265 | * this function may only be called from process context; it will | ||
266 | * sleep when waiting for a free sbal. | ||
267 | * | ||
268 | * Returns: 0 on success, -EIO if there is no free sbal after waiting. | ||
269 | */ | ||
270 | int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) | ||
271 | { | ||
272 | long ret; | ||
273 | |||
274 | spin_unlock_bh(&qdio->req_q_lock); | ||
275 | ret = wait_event_interruptible_timeout(qdio->req_q_wq, | ||
276 | zfcp_qdio_sbal_check(qdio), 5 * HZ); | ||
277 | if (ret > 0) | ||
278 | return 0; | ||
279 | if (!ret) { | ||
280 | atomic_inc(&qdio->req_q_full); | ||
281 | /* assume hanging outbound queue, try queue recovery */ | ||
282 | zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL); | ||
283 | } | ||
284 | |||
285 | spin_lock_bh(&qdio->req_q_lock); | ||
286 | return -EIO; | ||
287 | } | ||
288 | |||
275 | /** | 289 | /** |
276 | * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO | 290 | * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO |
277 | * @qdio: pointer to struct zfcp_qdio | 291 | * @qdio: pointer to struct zfcp_qdio |