|
@@ -176,6 +176,31 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
|
|
|
+{
|
|
|
+ struct scsi_cmnd *sc = ctask->sc;
|
|
|
+ struct iscsi_rlength_ahdr *rlen_ahdr;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rlen_ahdr = iscsi_next_hdr(ctask);
|
|
|
+ rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ rlen_ahdr->ahslength =
|
|
|
+ cpu_to_be16(sizeof(rlen_ahdr->read_length) +
|
|
|
+ sizeof(rlen_ahdr->reserved));
|
|
|
+ rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
|
|
|
+ rlen_ahdr->reserved = 0;
|
|
|
+ rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
|
|
|
+
|
|
|
+ debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
|
|
|
+ "rlen_ahdr->ahslength(%d)\n",
|
|
|
+ be32_to_cpu(rlen_ahdr->read_length),
|
|
|
+ be16_to_cpu(rlen_ahdr->ahslength));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
|
|
|
* @ctask: iscsi cmd task
|
|
@@ -200,7 +225,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
|
|
|
hdr->flags = ISCSI_ATTR_SIMPLE;
|
|
|
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
|
|
|
hdr->itt = build_itt(ctask->itt, session->age);
|
|
|
- hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
|
|
|
hdr->cmdsn = cpu_to_be32(session->cmdsn);
|
|
|
session->cmdsn++;
|
|
|
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)
|
|
|
memcpy(hdr->cdb, sc->cmnd, cmd_len);
|
|
|
|
|
|
ctask->imm_count = 0;
|
|
|
+ if (scsi_bidi_cmnd(sc)) {
|
|
|
+ hdr->flags |= ISCSI_FLAG_CMD_READ;
|
|
|
+ rc = iscsi_prep_bidi_ahs(ctask);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
if (sc->sc_data_direction == DMA_TO_DEVICE) {
|
|
|
+ unsigned out_len = scsi_out(sc)->length;
|
|
|
+ hdr->data_length = cpu_to_be32(out_len);
|
|
|
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
|
|
|
/*
|
|
|
* Write counters:
|
|
@@ -237,19 +269,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
|
|
|
ctask->unsol_datasn = 0;
|
|
|
|
|
|
if (session->imm_data_en) {
|
|
|
- if (scsi_bufflen(sc) >= session->first_burst)
|
|
|
+ if (out_len >= session->first_burst)
|
|
|
ctask->imm_count = min(session->first_burst,
|
|
|
conn->max_xmit_dlength);
|
|
|
else
|
|
|
- ctask->imm_count = min(scsi_bufflen(sc),
|
|
|
+ ctask->imm_count = min(out_len,
|
|
|
conn->max_xmit_dlength);
|
|
|
hton24(hdr->dlength, ctask->imm_count);
|
|
|
} else
|
|
|
zero_data(hdr->dlength);
|
|
|
|
|
|
if (!session->initial_r2t_en) {
|
|
|
- ctask->unsol_count = min((session->first_burst),
|
|
|
- (scsi_bufflen(sc))) - ctask->imm_count;
|
|
|
+ ctask->unsol_count = min(session->first_burst, out_len)
|
|
|
+ - ctask->imm_count;
|
|
|
ctask->unsol_offset = ctask->imm_count;
|
|
|
}
|
|
|
|
|
@@ -259,6 +291,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
|
|
|
} else {
|
|
|
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
|
|
|
zero_data(hdr->dlength);
|
|
|
+ hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
|
|
|
|
|
|
if (sc->sc_data_direction == DMA_FROM_DEVICE)
|
|
|
hdr->flags |= ISCSI_FLAG_CMD_READ;
|
|
@@ -277,10 +310,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
|
|
|
return EIO;
|
|
|
|
|
|
conn->scsicmd_pdus_cnt++;
|
|
|
- debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
|
|
|
- "cmdsn %d win %d]\n",
|
|
|
- sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
|
|
|
- conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
|
|
|
+ debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
|
|
|
+ "len %d bidi_len %d cmdsn %d win %d]\n",
|
|
|
+ scsi_bidi_cmnd(sc) ? "bidirectional" :
|
|
|
+ sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
|
|
|
+ conn->id, sc, sc->cmnd[0], ctask->itt,
|
|
|
+ scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
|
|
|
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
|
|
|
return 0;
|
|
|
}
|
|
@@ -343,7 +378,12 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
|
|
|
conn->session->tt->cleanup_cmd_task(conn, ctask);
|
|
|
|
|
|
sc->result = err;
|
|
|
- scsi_set_resid(sc, scsi_bufflen(sc));
|
|
|
+ if (!scsi_bidi_cmnd(sc))
|
|
|
+ scsi_set_resid(sc, scsi_bufflen(sc));
|
|
|
+ else {
|
|
|
+ scsi_out(sc)->resid = scsi_out(sc)->length;
|
|
|
+ scsi_in(sc)->resid = scsi_in(sc)->length;
|
|
|
+ }
|
|
|
if (conn->ctask == ctask)
|
|
|
conn->ctask = NULL;
|
|
|
/* release ref from queuecommand */
|
|
@@ -478,6 +518,18 @@ invalid_datalen:
|
|
|
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
|
|
|
}
|
|
|
|
|
|
+ if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
|
|
|
+ ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
|
|
|
+ int res_count = be32_to_cpu(rhdr->bi_residual_count);
|
|
|
+
|
|
|
+ if (scsi_bidi_cmnd(sc) && res_count > 0 &&
|
|
|
+ (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
|
|
|
+ res_count <= scsi_in(sc)->length))
|
|
|
+ scsi_in(sc)->resid = res_count;
|
|
|
+ else
|
|
|
+ sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
|
|
|
+ }
|
|
|
+
|
|
|
if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
|
|
|
ISCSI_FLAG_CMD_OVERFLOW)) {
|
|
|
int res_count = be32_to_cpu(rhdr->residual_count);
|
|
@@ -485,13 +537,11 @@ invalid_datalen:
|
|
|
if (res_count > 0 &&
|
|
|
(rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
|
|
|
res_count <= scsi_bufflen(sc)))
|
|
|
+ /* write side for bidi or uni-io set_resid */
|
|
|
scsi_set_resid(sc, res_count);
|
|
|
else
|
|
|
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
|
|
|
- } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
|
|
|
- ISCSI_FLAG_CMD_BIDI_OVERFLOW))
|
|
|
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
|
|
|
-
|
|
|
+ }
|
|
|
out:
|
|
|
debug_scsi("done [sc %lx res %d itt 0x%x]\n",
|
|
|
(long)sc, sc->result, ctask->itt);
|
|
@@ -1147,7 +1197,12 @@ reject:
|
|
|
fault:
|
|
|
spin_unlock(&session->lock);
|
|
|
debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
|
|
|
- scsi_set_resid(sc, scsi_bufflen(sc));
|
|
|
+ if (!scsi_bidi_cmnd(sc))
|
|
|
+ scsi_set_resid(sc, scsi_bufflen(sc));
|
|
|
+ else {
|
|
|
+ scsi_out(sc)->resid = scsi_out(sc)->length;
|
|
|
+ scsi_in(sc)->resid = scsi_in(sc)->length;
|
|
|
+ }
|
|
|
sc->scsi_done(sc);
|
|
|
spin_lock(host->host_lock);
|
|
|
return 0;
|