aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_qdio.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2010-05-18 10:33:43 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-05-18 10:37:41 -0400
commit95bb335c0ebe96afe926387a1ef3a096bd884a82 (patch)
tree56115332b4f2f7ef300c36248a6a7d20db2e639d /drivers/s390/scsi/zfcp_qdio.c
parent1b4d0d8ea7b3cbd107f345ab766416f9b38ce66a (diff)
parent9cccde93fed1ca988eb2fb17ab9194bf7b5ed1b0 (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.c108
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
153static struct qdio_buffer_element * 153static struct qdio_buffer_element *
154zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, 154zfcp_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
188static struct qdio_buffer_element * 187static struct qdio_buffer_element *
189zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, 188zfcp_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
209static 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 */
246int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, 215int 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
249static 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 */
270int 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