Commit c07d444407de63b2f414a8be9428f88cadba503f
Committed by
James Bottomley
1 parent
38d1c069db
Exists in
master
and in
7 other branches
[SCSI] iscsi: bidi support at the generic libiscsi level
- prepare the additional bidi_read rlength header. - access the right scsi_in() and/or scsi_out() side of things. also for resid. - Handle BIDI underflow overflow from target Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Reviewed-by: Pete Wyckoff <pw@osc.edu> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Showing 1 changed file with 70 additions and 15 deletions Side-by-side Diff
drivers/scsi/libiscsi.c
... | ... | @@ -176,6 +176,31 @@ |
176 | 176 | return 0; |
177 | 177 | } |
178 | 178 | |
179 | +static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | |
180 | +{ | |
181 | + struct scsi_cmnd *sc = ctask->sc; | |
182 | + struct iscsi_rlength_ahdr *rlen_ahdr; | |
183 | + int rc; | |
184 | + | |
185 | + rlen_ahdr = iscsi_next_hdr(ctask); | |
186 | + rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); | |
187 | + if (rc) | |
188 | + return rc; | |
189 | + | |
190 | + rlen_ahdr->ahslength = | |
191 | + cpu_to_be16(sizeof(rlen_ahdr->read_length) + | |
192 | + sizeof(rlen_ahdr->reserved)); | |
193 | + rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; | |
194 | + rlen_ahdr->reserved = 0; | |
195 | + rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); | |
196 | + | |
197 | + debug_scsi("bidi-in rlen_ahdr->read_length(%d) " | |
198 | + "rlen_ahdr->ahslength(%d)\n", | |
199 | + be32_to_cpu(rlen_ahdr->read_length), | |
200 | + be16_to_cpu(rlen_ahdr->ahslength)); | |
201 | + return 0; | |
202 | +} | |
203 | + | |
179 | 204 | /** |
180 | 205 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
181 | 206 | * @ctask: iscsi cmd task |
... | ... | @@ -200,7 +225,6 @@ |
200 | 225 | hdr->flags = ISCSI_ATTR_SIMPLE; |
201 | 226 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
202 | 227 | hdr->itt = build_itt(ctask->itt, session->age); |
203 | - hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); | |
204 | 228 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
205 | 229 | session->cmdsn++; |
206 | 230 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
207 | 231 | |
... | ... | @@ -216,7 +240,15 @@ |
216 | 240 | memcpy(hdr->cdb, sc->cmnd, cmd_len); |
217 | 241 | |
218 | 242 | ctask->imm_count = 0; |
243 | + if (scsi_bidi_cmnd(sc)) { | |
244 | + hdr->flags |= ISCSI_FLAG_CMD_READ; | |
245 | + rc = iscsi_prep_bidi_ahs(ctask); | |
246 | + if (rc) | |
247 | + return rc; | |
248 | + } | |
219 | 249 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
250 | + unsigned out_len = scsi_out(sc)->length; | |
251 | + hdr->data_length = cpu_to_be32(out_len); | |
220 | 252 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
221 | 253 | /* |
222 | 254 | * Write counters: |
223 | 255 | |
224 | 256 | |
... | ... | @@ -237,19 +269,19 @@ |
237 | 269 | ctask->unsol_datasn = 0; |
238 | 270 | |
239 | 271 | if (session->imm_data_en) { |
240 | - if (scsi_bufflen(sc) >= session->first_burst) | |
272 | + if (out_len >= session->first_burst) | |
241 | 273 | ctask->imm_count = min(session->first_burst, |
242 | 274 | conn->max_xmit_dlength); |
243 | 275 | else |
244 | - ctask->imm_count = min(scsi_bufflen(sc), | |
276 | + ctask->imm_count = min(out_len, | |
245 | 277 | conn->max_xmit_dlength); |
246 | 278 | hton24(hdr->dlength, ctask->imm_count); |
247 | 279 | } else |
248 | 280 | zero_data(hdr->dlength); |
249 | 281 | |
250 | 282 | if (!session->initial_r2t_en) { |
251 | - ctask->unsol_count = min((session->first_burst), | |
252 | - (scsi_bufflen(sc))) - ctask->imm_count; | |
283 | + ctask->unsol_count = min(session->first_burst, out_len) | |
284 | + - ctask->imm_count; | |
253 | 285 | ctask->unsol_offset = ctask->imm_count; |
254 | 286 | } |
255 | 287 | |
... | ... | @@ -259,6 +291,7 @@ |
259 | 291 | } else { |
260 | 292 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
261 | 293 | zero_data(hdr->dlength); |
294 | + hdr->data_length = cpu_to_be32(scsi_in(sc)->length); | |
262 | 295 | |
263 | 296 | if (sc->sc_data_direction == DMA_FROM_DEVICE) |
264 | 297 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
... | ... | @@ -277,10 +310,12 @@ |
277 | 310 | return EIO; |
278 | 311 | |
279 | 312 | conn->scsicmd_pdus_cnt++; |
280 | - debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | |
281 | - "cmdsn %d win %d]\n", | |
282 | - sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | |
283 | - conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), | |
313 | + debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " | |
314 | + "len %d bidi_len %d cmdsn %d win %d]\n", | |
315 | + scsi_bidi_cmnd(sc) ? "bidirectional" : | |
316 | + sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | |
317 | + conn->id, sc, sc->cmnd[0], ctask->itt, | |
318 | + scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, | |
284 | 319 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
285 | 320 | return 0; |
286 | 321 | } |
... | ... | @@ -343,7 +378,12 @@ |
343 | 378 | conn->session->tt->cleanup_cmd_task(conn, ctask); |
344 | 379 | |
345 | 380 | sc->result = err; |
346 | - scsi_set_resid(sc, scsi_bufflen(sc)); | |
381 | + if (!scsi_bidi_cmnd(sc)) | |
382 | + scsi_set_resid(sc, scsi_bufflen(sc)); | |
383 | + else { | |
384 | + scsi_out(sc)->resid = scsi_out(sc)->length; | |
385 | + scsi_in(sc)->resid = scsi_in(sc)->length; | |
386 | + } | |
347 | 387 | if (conn->ctask == ctask) |
348 | 388 | conn->ctask = NULL; |
349 | 389 | /* release ref from queuecommand */ |
... | ... | @@ -478,6 +518,18 @@ |
478 | 518 | min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); |
479 | 519 | } |
480 | 520 | |
521 | + if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | | |
522 | + ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { | |
523 | + int res_count = be32_to_cpu(rhdr->bi_residual_count); | |
524 | + | |
525 | + if (scsi_bidi_cmnd(sc) && res_count > 0 && | |
526 | + (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || | |
527 | + res_count <= scsi_in(sc)->length)) | |
528 | + scsi_in(sc)->resid = res_count; | |
529 | + else | |
530 | + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | |
531 | + } | |
532 | + | |
481 | 533 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | |
482 | 534 | ISCSI_FLAG_CMD_OVERFLOW)) { |
483 | 535 | int res_count = be32_to_cpu(rhdr->residual_count); |
484 | 536 | |
... | ... | @@ -485,13 +537,11 @@ |
485 | 537 | if (res_count > 0 && |
486 | 538 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || |
487 | 539 | res_count <= scsi_bufflen(sc))) |
540 | + /* write side for bidi or uni-io set_resid */ | |
488 | 541 | scsi_set_resid(sc, res_count); |
489 | 542 | else |
490 | 543 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
491 | - } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | | |
492 | - ISCSI_FLAG_CMD_BIDI_OVERFLOW)) | |
493 | - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | |
494 | - | |
544 | + } | |
495 | 545 | out: |
496 | 546 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
497 | 547 | (long)sc, sc->result, ctask->itt); |
... | ... | @@ -1147,7 +1197,12 @@ |
1147 | 1197 | fault: |
1148 | 1198 | spin_unlock(&session->lock); |
1149 | 1199 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); |
1150 | - scsi_set_resid(sc, scsi_bufflen(sc)); | |
1200 | + if (!scsi_bidi_cmnd(sc)) | |
1201 | + scsi_set_resid(sc, scsi_bufflen(sc)); | |
1202 | + else { | |
1203 | + scsi_out(sc)->resid = scsi_out(sc)->length; | |
1204 | + scsi_in(sc)->resid = scsi_in(sc)->length; | |
1205 | + } | |
1151 | 1206 | sc->scsi_done(sc); |
1152 | 1207 | spin_lock(host->host_lock); |
1153 | 1208 | return 0; |