diff options
| -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; |
