diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2008-04-18 11:11:52 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-18 12:53:00 -0400 |
commit | c07d444407de63b2f414a8be9428f88cadba503f (patch) | |
tree | 4eabbd7adb9130392beb306cc9f1633258749851 /drivers/scsi/libiscsi.c | |
parent | 38d1c069db8c87eb6cb10ca1ede9d9b673531ddd (diff) |
[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>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 85 |
1 files changed, 70 insertions, 15 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2f6b0955ff01..010c1b9b178c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -176,6 +176,31 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | |||
176 | return 0; | 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 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 205 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
181 | * @ctask: iscsi cmd task | 206 | * @ctask: iscsi cmd task |
@@ -200,7 +225,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
200 | hdr->flags = ISCSI_ATTR_SIMPLE; | 225 | hdr->flags = ISCSI_ATTR_SIMPLE; |
201 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 226 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
202 | hdr->itt = build_itt(ctask->itt, session->age); | 227 | hdr->itt = build_itt(ctask->itt, session->age); |
203 | hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); | ||
204 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 228 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
205 | session->cmdsn++; | 229 | session->cmdsn++; |
206 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 230 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
@@ -216,7 +240,15 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
216 | memcpy(hdr->cdb, sc->cmnd, cmd_len); | 240 | memcpy(hdr->cdb, sc->cmnd, cmd_len); |
217 | 241 | ||
218 | ctask->imm_count = 0; | 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 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 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 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 252 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
221 | /* | 253 | /* |
222 | * Write counters: | 254 | * Write counters: |
@@ -237,19 +269,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
237 | ctask->unsol_datasn = 0; | 269 | ctask->unsol_datasn = 0; |
238 | 270 | ||
239 | if (session->imm_data_en) { | 271 | if (session->imm_data_en) { |
240 | if (scsi_bufflen(sc) >= session->first_burst) | 272 | if (out_len >= session->first_burst) |
241 | ctask->imm_count = min(session->first_burst, | 273 | ctask->imm_count = min(session->first_burst, |
242 | conn->max_xmit_dlength); | 274 | conn->max_xmit_dlength); |
243 | else | 275 | else |
244 | ctask->imm_count = min(scsi_bufflen(sc), | 276 | ctask->imm_count = min(out_len, |
245 | conn->max_xmit_dlength); | 277 | conn->max_xmit_dlength); |
246 | hton24(hdr->dlength, ctask->imm_count); | 278 | hton24(hdr->dlength, ctask->imm_count); |
247 | } else | 279 | } else |
248 | zero_data(hdr->dlength); | 280 | zero_data(hdr->dlength); |
249 | 281 | ||
250 | if (!session->initial_r2t_en) { | 282 | if (!session->initial_r2t_en) { |
251 | ctask->unsol_count = min((session->first_burst), | 283 | ctask->unsol_count = min(session->first_burst, out_len) |
252 | (scsi_bufflen(sc))) - ctask->imm_count; | 284 | - ctask->imm_count; |
253 | ctask->unsol_offset = ctask->imm_count; | 285 | ctask->unsol_offset = ctask->imm_count; |
254 | } | 286 | } |
255 | 287 | ||
@@ -259,6 +291,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
259 | } else { | 291 | } else { |
260 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 292 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
261 | zero_data(hdr->dlength); | 293 | zero_data(hdr->dlength); |
294 | hdr->data_length = cpu_to_be32(scsi_in(sc)->length); | ||
262 | 295 | ||
263 | if (sc->sc_data_direction == DMA_FROM_DEVICE) | 296 | if (sc->sc_data_direction == DMA_FROM_DEVICE) |
264 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 297 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
@@ -277,10 +310,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
277 | return EIO; | 310 | return EIO; |
278 | 311 | ||
279 | conn->scsicmd_pdus_cnt++; | 312 | conn->scsicmd_pdus_cnt++; |
280 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | 313 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " |
281 | "cmdsn %d win %d]\n", | 314 | "len %d bidi_len %d cmdsn %d win %d]\n", |
282 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 315 | scsi_bidi_cmnd(sc) ? "bidirectional" : |
283 | conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), | 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 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 319 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
285 | return 0; | 320 | return 0; |
286 | } | 321 | } |
@@ -343,7 +378,12 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
343 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 378 | conn->session->tt->cleanup_cmd_task(conn, ctask); |
344 | 379 | ||
345 | sc->result = err; | 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 | if (conn->ctask == ctask) | 387 | if (conn->ctask == ctask) |
348 | conn->ctask = NULL; | 388 | conn->ctask = NULL; |
349 | /* release ref from queuecommand */ | 389 | /* release ref from queuecommand */ |
@@ -478,6 +518,18 @@ invalid_datalen: | |||
478 | min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); | 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 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | | 533 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | |
482 | ISCSI_FLAG_CMD_OVERFLOW)) { | 534 | ISCSI_FLAG_CMD_OVERFLOW)) { |
483 | int res_count = be32_to_cpu(rhdr->residual_count); | 535 | int res_count = be32_to_cpu(rhdr->residual_count); |
@@ -485,13 +537,11 @@ invalid_datalen: | |||
485 | if (res_count > 0 && | 537 | if (res_count > 0 && |
486 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || | 538 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || |
487 | res_count <= scsi_bufflen(sc))) | 539 | res_count <= scsi_bufflen(sc))) |
540 | /* write side for bidi or uni-io set_resid */ | ||
488 | scsi_set_resid(sc, res_count); | 541 | scsi_set_resid(sc, res_count); |
489 | else | 542 | else |
490 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | 543 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
491 | } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | | 544 | } |
492 | ISCSI_FLAG_CMD_BIDI_OVERFLOW)) | ||
493 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | ||
494 | |||
495 | out: | 545 | out: |
496 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", | 546 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
497 | (long)sc, sc->result, ctask->itt); | 547 | (long)sc, sc->result, ctask->itt); |
@@ -1147,7 +1197,12 @@ reject: | |||
1147 | fault: | 1197 | fault: |
1148 | spin_unlock(&session->lock); | 1198 | spin_unlock(&session->lock); |
1149 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); | 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 | sc->scsi_done(sc); | 1206 | sc->scsi_done(sc); |
1152 | spin_lock(host->host_lock); | 1207 | spin_lock(host->host_lock); |
1153 | return 0; | 1208 | return 0; |