Commit c07d444407de63b2f414a8be9428f88cadba503f

Authored by Boaz Harrosh
Committed by James Bottomley
1 parent 38d1c069db

[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;