From: Boaz Harrosh <[EMAIL PROTECTED]>

Adapted from separate libiscsi and TCP patches by Boaz to update for
iscsi changes and iscsi-tcp rewrite.  Dropped some needless conversion
to scsi_out() in some places.  Original log follows.

Once bidi support is accepted at block and scsi-ml layers
below bidi support to iscsi can be applied.
The assumed bidi API from scsi-ml is based on scsi_sgtables
but it is not at all far from any other implementation as far
as iscsi code is concerned:
- scsi_bidi_cmd() - return true if the command is bidi. Note
                    that this is a deviation from previous RFCs
                    in that we no longer have sc_dma_direction
                    == DMA_BIDIRECTIONAL. The command direction is DMA_TO_DEVICE
                    but with this flag on.
- scsi_{in,out}() - Which will return the right sg_table for IN or OUT
                    operation, in a generic way.
                    The small difference here due to sgtable implementation
                    is that in the past we had scsi_in()->sglist == NULL for
                    DMA_NONE and now we have scsi_in() == NULL.

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.

Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]>
Signed-off-by: Pete Wyckoff <[EMAIL PROTECTED]>
---
 drivers/scsi/iscsi_tcp.c |   14 ++++---
 drivers/scsi/libiscsi.c  |   81 +++++++++++++++++++++++++++++++++++++++------
 2 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 9fde5ce..373639a 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -542,10 +542,11 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct 
iscsi_cmd_task *ctask)
        tcp_ctask->exp_datasn++;
 
        tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
-       if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+       if (tcp_ctask->data_offset + tcp_conn->in.datalen >
+                                                       scsi_in(sc)->length) {
                debug_tcp("%s: data_offset(%d) + data_len(%d) > 
total_length_in(%d)\n",
                          __FUNCTION__, tcp_ctask->data_offset,
-                         tcp_conn->in.datalen, scsi_bufflen(sc));
+                         tcp_conn->in.datalen, scsi_in(sc)->length);
                return ISCSI_ERR_DATA_OFFSET;
        }
 
@@ -558,8 +559,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct 
iscsi_cmd_task *ctask)
 
                        if (res_count > 0 &&
                            (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-                            res_count <= scsi_bufflen(sc)))
-                               scsi_set_resid(sc, res_count);
+                            res_count <= scsi_in(sc)->length))
+                               scsi_in(sc)->resid = res_count;
                        else
                                sc->result = (DID_BAD_TARGET << 16) |
                                        rhdr->cmd_status;
@@ -783,8 +784,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct 
iscsi_hdr *hdr)
                                  tcp_ctask->data_offset,
                                  tcp_conn->in.datalen);
                        return iscsi_segment_seek_sg(&tcp_conn->in.segment,
-                                                    scsi_sglist(ctask->sc),
-                                                    scsi_sg_count(ctask->sc),
+                                                    scsi_in(ctask->sc)->sglist,
+                                                    scsi_in(ctask->sc)->
+                                                               sg_count,
                                                     tcp_ctask->data_offset,
                                                     tcp_conn->in.datalen,
                                                     iscsi_tcp_process_data_in,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 94a8046..cb7f539 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -176,6 +176,30 @@ 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 +224,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, conn->id, 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,9 +239,18 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task 
*ctask)
        }
        memcpy(hdr->cdb, sc->cmnd, cmd_len);
 
+       if (scsi_bidi_cmnd(sc)) {
+               hdr->flags |= ISCSI_FLAG_CMD_READ;
+               rc = iscsi_prep_bidi_ahs(ctask);
+               if (rc)
+                       return rc;
+       }
+
        ctask->imm_count = 0;
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
+               unsigned int out_len = scsi_out(sc)->length;
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+               hdr->data_length = cpu_to_be32(out_len);
                /*
                 * Write counters:
                 *
@@ -238,19 +270,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)
                        hdr->flags |= ISCSI_FLAG_CMD_FINAL;
        } else {
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+               hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
                zero_data(hdr->dlength);
 
                if (sc->sc_data_direction == DMA_FROM_DEVICE)
@@ -279,9 +312,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task 
*ctask)
 
        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",
+               "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;
 }
@@ -344,7 +379,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_out(sc)->resid = scsi_out(sc)->length;
+               scsi_in(sc)->resid = scsi_in(sc)->length;
+       } else {
+               scsi_set_resid(sc, scsi_bufflen(sc));
+       }
        if (conn->ctask == ctask)
                conn->ctask = NULL;
        /* release ref from queuecommand */
@@ -488,9 +528,23 @@ invalid_datalen:
                        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;
+       }
+       if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
+                          ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
+               if (scsi_bidi_cmnd(sc)) {
+                       int res_count = be32_to_cpu(rhdr->bi_residual_count);
+
+                       if (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;
+               } else {
+                       sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+               }
+       }
 
 out:
        debug_scsi("done [sc %lx res %d itt 0x%x]\n",
@@ -1140,7 +1194,12 @@ fault:
        printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
               sc->cmnd[0], reason);
        sc->result = (DID_NO_CONNECT << 16);
-       scsi_set_resid(sc, scsi_bufflen(sc));
+       if (scsi_bidi_cmnd(sc)) {
+               scsi_out(sc)->resid = scsi_out(sc)->length;
+               scsi_in(sc)->resid = scsi_in(sc)->length;
+       } else {
+               scsi_set_resid(sc, scsi_bufflen(sc));
+       }
        sc->scsi_done(sc);
        spin_lock(host->host_lock);
        return 0;
-- 
1.5.3.6

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to