This patch is intended to provide a working example of a use case
for bidi and varlen CDBs. The actual patches will be sent via the
open-iscsi project.

- Use proposed SCSI implementation for iSCSI bidirectional commands.
- Use proposed block layer implementation for iSCSI extended CDBs.
- Dynamically build AHSs for extended cdbs and bidirectional requests.
- Follow iscsi rfc-3720 concerning datasn and r2tsn with bidirectional commands,
  these must be the same counter.
[- Remove check for first-burst bigger than max-burst so iSCSI regression tests 
can pass.
   this is the wrong fix and will be removed in actual patches]

Signed-off-by: Benny Halevy <[EMAIL PROTECTED]>
Signed-off-by: Boaz Harrosh <[EMAIL PROTECTED]>

---
 drivers/infiniband/ulp/iser/iscsi_iser.c |    4 +-
 drivers/scsi/iscsi_tcp.c                 |  190 +++++++++++++++++++++++-------
 drivers/scsi/iscsi_tcp.h                 |   10 +-
 drivers/scsi/libiscsi.c                  |   33 +++--
 include/scsi/iscsi_proto.h               |    8 ++
 include/scsi/libiscsi.h                  |   18 +++-
 6 files changed, 200 insertions(+), 63 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c 
b/drivers/infiniband/ulp/iser/iscsi_iser.c
index dd221ed..a0eae0c 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -140,10 +140,10 @@ iscsi_iser_cmd_init(struct iscsi_cmd_tas
        iser_ctask->iser_conn    = iser_conn;

        if (sc->sc_data_direction == DMA_TO_DEVICE) {
-               BUG_ON(ctask->total_length == 0);
+               BUG_ON(iscsi_out_total_length(ctask) == 0);

                debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
-                          ctask->itt, ctask->total_length, ctask->imm_count,
+                          ctask->itt, iscsi_out_total_length(ctask), 
ctask->imm_count,
                           ctask->unsol_count);
        }

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index d0b139c..2bc57a5 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -109,7 +109,9 @@ iscsi_hdr_digest(struct iscsi_conn *conn
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;

        crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
-       buf->sg.length = tcp_conn->hdr_size;
+       buf->sg.length += sizeof(__u32);
+       debug_tcp("iscsi_hdr_digest: &crc %p crc 0x%02x%02x%02x%02x\n",
+                 crc, crc[0], crc[1], crc[2], crc[3]);
 }

 static inline int
@@ -229,14 +231,21 @@ iscsi_data_rsp(struct iscsi_conn *conn,
        if (tcp_conn->in.datalen == 0)
                return 0;

-       if (ctask->datasn != datasn)
+       if (tcp_ctask->exp_datasn != datasn) {
+               debug_tcp("%s: ctask->datasn(%d) != rhdr->datasn(%d)\n",
+                         __FUNCTION__, tcp_ctask->exp_datasn, datasn);
                return ISCSI_ERR_DATASN;
+       }

-       ctask->datasn++;
+       tcp_ctask->exp_datasn++;

        tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
-       if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
+       if (tcp_ctask->data_offset + tcp_conn->in.datalen > 
iscsi_in_total_length(ctask)) {
+               debug_tcp("%s: data_offset(%d) + data_len(%d) > 
total_length_in(%d)\n",
+                         __FUNCTION__, tcp_ctask->data_offset,
+                         tcp_conn->in.datalen, iscsi_in_total_length(ctask));
                return ISCSI_ERR_DATA_OFFSET;
+       }

        if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
                struct scsi_cmnd *sc = ctask->sc;
@@ -246,7 +255,7 @@ iscsi_data_rsp(struct iscsi_conn *conn,
                        int res_count = be32_to_cpu(rhdr->residual_count);

                        if (res_count > 0 &&
-                           res_count <= sc->request_bufflen) {
+                           res_count <= iscsi_in_total_length(ctask)) {
                                sc->resid = res_count;
                                sc->result = (DID_OK << 16) | rhdr->cmd_status;
                        } else
@@ -281,6 +290,7 @@ iscsi_solicit_data_init(struct iscsi_con
 {
        struct iscsi_data *hdr;
        struct scsi_cmnd *sc = ctask->sc;
+       struct scsi_cmnd_buff scb;

        hdr = &r2t->dtask.hdr;
        memset(hdr, 0, sizeof(struct iscsi_data));
@@ -308,12 +318,13 @@ iscsi_solicit_data_init(struct iscsi_con
        iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
                           sizeof(struct iscsi_hdr));

-       if (sc->use_sg) {
+       scsi_get_out_buff(sc, &scb);
+       if (scb.use_sg) {
                int i, sg_count = 0;
-               struct scatterlist *sg = sc->request_buffer;
+               struct scatterlist *sg = scb.buffer;

                r2t->sg = NULL;
-               for (i = 0; i < sc->use_sg; i++, sg += 1) {
+               for (i = 0; i < scb.use_sg; i++, sg += 1) {
                        /* FIXME: prefetch ? */
                        if (sg_count + sg->length > r2t->data_offset) {
                                int page_offset;
@@ -337,7 +348,7 @@ iscsi_solicit_data_init(struct iscsi_con
                BUG_ON(r2t->sg == NULL);
        } else {
                iscsi_buf_init_iov(&r2t->sendbuf,
-                           (char*)sc->request_buffer + r2t->data_offset,
+                           (char*)scb.buffer + r2t->data_offset,
                            r2t->data_count);
                r2t->sg = NULL;
        }
@@ -365,15 +376,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
                return ISCSI_ERR_DATALEN;
        }

-       if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
+       if (tcp_ctask->exp_datasn != r2tsn)
                return ISCSI_ERR_R2TSN;

        rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
        if (rc)
                return rc;

-       /* FIXME: use R2TSN to detect missing R2T */
-
        /* fill-in new R2T associated with the task */
        spin_lock(&session->lock);
        if (!ctask->sc || ctask->mtask ||
@@ -401,11 +410,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
                            r2t->data_length, session->max_burst);

        r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-       if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+       if (r2t->data_offset + r2t->data_length > 
iscsi_out_total_length(ctask)) {
                spin_unlock(&session->lock);
                printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
                       "offset %u and total length %d\n", r2t->data_length,
-                      r2t->data_offset, ctask->total_length);
+                      r2t->data_offset, iscsi_out_total_length(ctask));
                return ISCSI_ERR_DATALEN;
        }

@@ -414,7 +423,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s

        iscsi_solicit_data_init(conn, ctask, r2t);

-       tcp_ctask->exp_r2tsn = r2tsn + 1;
+       tcp_ctask->exp_datasn = r2tsn + 1;
        __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
        tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
        list_move_tail(&ctask->running, &conn->xmitqueue);
@@ -512,8 +521,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
                tcp_conn->in.ctask = session->cmds[itt];
                if (ahslen)
                        rc = ISCSI_ERR_AHSLEN;
-               else if (tcp_conn->in.ctask->sc->sc_data_direction ==
-                                                               DMA_TO_DEVICE)
+               else if (tcp_conn->in.ctask->sc->sc_data_direction == 
DMA_TO_DEVICE ||
+                        tcp_conn->in.ctask->sc->sc_data_direction == 
DMA_BIDIRECTIONAL)
                        rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
                else
                        rc = ISCSI_ERR_PROTO;
@@ -609,7 +618,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *
               size, tcp_conn->in.offset, tcp_conn->in.copied);

        BUG_ON(size <= 0);
-       BUG_ON(tcp_ctask->sent + size > ctask->total_length);
+       BUG_ON(tcp_ctask->sent + size > iscsi_in_total_length(ctask));

        rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
                           (char*)buf + (offset + tcp_conn->data_copied), size);
@@ -704,28 +713,30 @@ static int iscsi_scsi_data_in(struct isc
        struct scsi_cmnd *sc = ctask->sc;
        struct scatterlist *sg;
        int i, offset, rc = 0;
+       struct scsi_cmnd_buff scb;

        BUG_ON((void*)ctask != sc->SCp.ptr);

+       scsi_get_in_buff(sc, &scb);
        /*
         * copying Data-In into the Scsi_Cmnd
         */
-       if (!sc->use_sg) {
+       if (!scb.use_sg) {
                i = ctask->data_count;
-               rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer,
-                                     sc->request_bufflen,
+               rc = iscsi_ctask_copy(tcp_conn, ctask, scb.buffer,
+                                     scb.bufflen,
                                      tcp_ctask->data_offset);
                if (rc == -EAGAIN)
                        return rc;
                if (conn->datadgst_en)
-                       iscsi_recv_digest_update(tcp_conn, sc->request_buffer,
+                       iscsi_recv_digest_update(tcp_conn, scb.buffer,
                                                 i);
                rc = 0;
                goto done;
        }

        offset = tcp_ctask->data_offset;
-       sg = sc->request_buffer;
+       sg = scb.buffer;

        if (tcp_ctask->data_offset)
                for (i = 0; i < tcp_ctask->sg_count; i++)
@@ -734,7 +745,7 @@ static int iscsi_scsi_data_in(struct isc
        if (offset < 0)
                offset = 0;

-       for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) {
+       for (i = tcp_ctask->sg_count; i < scb.use_sg; i++) {
                char *dest;

                dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
@@ -749,7 +760,7 @@ static int iscsi_scsi_data_in(struct isc
                                if (!offset)
                                        crypto_hash_update(
                                                        &tcp_conn->rx_hash,
-                                                       &sg[i], 1);
+                                                       &sg[i], sg[i].length);
                                else
                                        partial_sg_digest_update(
                                                        &tcp_conn->rx_hash,
@@ -1141,7 +1152,8 @@ iscsi_sendhdr(struct iscsi_conn *conn, s
                flags |= MSG_MORE;

        res = iscsi_send(conn, buf, size, flags);
-       debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
+       debug_tcp("sendhdr %d bytes, length %d sent %d res %d\n",
+                 size, buf->sg.length, buf->sent, res);
        if (res >= 0) {
                if (size != res)
                        return -EAGAIN;
@@ -1217,6 +1229,7 @@ iscsi_solicit_data_cont(struct iscsi_con
        struct iscsi_data *hdr;
        struct scsi_cmnd *sc = ctask->sc;
        int new_offset;
+       struct scsi_cmnd_buff scb;

        hdr = &r2t->dtask.hdr;
        memset(hdr, 0, sizeof(struct iscsi_data));
@@ -1245,12 +1258,13 @@ iscsi_solicit_data_cont(struct iscsi_con
        if (iscsi_buf_left(&r2t->sendbuf))
                return;

-       if (sc->use_sg) {
+       scsi_get_out_buff(sc, &scb);
+       if (scb.use_sg) {
                iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
                r2t->sg += 1;
        } else {
                iscsi_buf_init_iov(&r2t->sendbuf,
-                           (char*)sc->request_buffer + new_offset,
+                           (char*)scb.buffer + new_offset,
                            r2t->data_count);
                r2t->sg = NULL;
        }
@@ -1279,39 +1293,133 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task
 {
        struct scsi_cmnd *sc = ctask->sc;
        struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+       int hdrlength, rlen;
+       unsigned short ahslength;
+       struct iscsi_ecdb_ahdr *ecdb_ahdr;
+       struct scsi_cmnd_buff scb;

        BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));

+       /*
+        * extended headers immediately follow tcp_ctask->hdr hence ctask->hdr
+        * must point there
+        */
+       tcp_ctask->hdrext = tcp_ctask->hdrextbuf;
+       BUG_ON(tcp_ctask->hdrext != (char *)ctask->hdr + 
sizeof(tcp_ctask->hdr));
+
        tcp_ctask->sent = 0;
        tcp_ctask->sg_count = 0;
+       tcp_ctask->exp_datasn = 0;
+
+       /*
+        * make an extended cdb AHS
+        */
+       if (sc->request->varlen_cdb && (sc->request->varlen_cdb_len > 
MAX_COMMAND_SIZE)) {
+               int pad_len;
+
+               ecdb_ahdr = (struct iscsi_ecdb_ahdr *)tcp_ctask->hdrext;
+               rlen = sc->request->varlen_cdb_len - MAX_COMMAND_SIZE;
+
+               BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
+               ahslength = rlen + sizeof(ecdb_ahdr->reserved);

-       if (sc->sc_data_direction == DMA_TO_DEVICE) {
+               /* need to pad ecdb? */
+               pad_len = rlen & (ISCSI_PAD_LEN - 1);
+               if (pad_len) {
+                       pad_len = ISCSI_PAD_LEN - pad_len;
+                       memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+                       ahslength += pad_len;
+               }
+
+               ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+               ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+               ecdb_ahdr->reserved = 0;
+               memcpy(ecdb_ahdr->ecdb, 
sc->request->varlen_cdb+MAX_COMMAND_SIZE, rlen);
+
+               tcp_ctask->hdrext += ahslength + sizeof(ecdb_ahdr->ahslength) +
+                               sizeof(ecdb_ahdr->ahstype);
+               debug_scsi("iscsi_tcp_cmd_init: extended cdb:"
+                       " varlen_cdb_len %d rlen %d pad_len %d ahs_length %d 
total_ahs_length %Zd\n",
+                       sc->request->varlen_cdb_len, rlen, pad_len, ahslength,
+                       ((char *)tcp_ctask->hdrext - (char 
*)tcp_ctask->hdrextbuf) );
+       }
+
+       switch (sc->sc_data_direction) {
+       case DMA_BIDIRECTIONAL: {
+               struct iscsi_rlength_ahdr *rlen_ahdr;
+
+               scsi_get_in_buff(sc, &scb);
+               BUG_ON(scb.buffer == NULL);
+               BUG_ON(scb.bufflen == 0);
+
+               rlen_ahdr = (struct iscsi_rlength_ahdr*)tcp_ctask->hdrext;
+               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(scb.bufflen);
+
+               tcp_ctask->hdrext += sizeof(*rlen_ahdr);
+               
+               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)
+               );
+       }
+       /* FALLTHROUGH */
+       case DMA_TO_DEVICE:
                tcp_ctask->xmstate = XMSTATE_W_HDR;
-               tcp_ctask->exp_r2tsn = 0;
-               BUG_ON(ctask->total_length == 0);
+               BUG_ON(iscsi_out_total_length(ctask) == 0);

-               if (sc->use_sg) {
-                       struct scatterlist *sg = sc->request_buffer;
+               scsi_get_out_buff(sc, &scb);
+               BUG_ON(scb.buffer == NULL);
+               BUG_ON(scb.bufflen == 0);
+               if (scb.use_sg) {
+                       struct scatterlist *sg = scb.buffer;

                        iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
                        tcp_ctask->sg = sg + 1;
-                       tcp_ctask->bad_sg = sg + sc->use_sg;
+                       tcp_ctask->bad_sg = sg + scb.use_sg;
                } else {
                        iscsi_buf_init_iov(&tcp_ctask->sendbuf,
-                                          sc->request_buffer,
-                                          sc->request_bufflen);
+                                          scb.buffer,
+                                          scb.bufflen);
                        tcp_ctask->sg = NULL;
                        tcp_ctask->bad_sg = NULL;
                }
                debug_scsi("cmd [itt 0x%x total %d imm_data %d "
                           "unsol count %d, unsol offset %d]\n",
-                          ctask->itt, ctask->total_length, ctask->imm_count,
-                          ctask->unsol_count, ctask->unsol_offset);
-       } else
+                          ctask->itt, iscsi_out_total_length(ctask), 
ctask->imm_count,
+                          ctask->unsol_count, ctask->unsol_offset);
+               break;
+
+       case DMA_FROM_DEVICE:
+       case DMA_NONE:
                tcp_ctask->xmstate = XMSTATE_R_HDR;
+               break;
+
+       default:
+               BUG_ON(1);
+       }
+
+       /* calculate size of additional header segments (AHSs) */
+       hdrlength = (char *)tcp_ctask->hdrext -
+                   ((char *)&tcp_ctask->hdr + sizeof(tcp_ctask->hdr));
+
+       BUG_ON(hdrlength & (ISCSI_PAD_LEN-1));
+       hdrlength /= ISCSI_PAD_LEN;
+
+       BUG_ON(hdrlength >= 256);
+       tcp_ctask->hdr.hlength = hdrlength & 0xFF;
+
+       debug_scsi("iscsi_tcp_cmd_init: total_pdu_length %Zd "
+                  "hlength %d dlength %d data_length %d\n",
+                  tcp_ctask->hdrext - (char *)&tcp_ctask->hdr,
+                  tcp_ctask->hdr.hlength, ntoh24(ctask->hdr->dlength),
+                  be32_to_cpu(ctask->hdr->data_length));

-       iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
-                           sizeof(struct iscsi_hdr));
+       iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&tcp_ctask->hdr,
+                          tcp_ctask->hdrext - (char *)&tcp_ctask->hdr);
 }

 /**
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 3273683..24620ee 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -47,7 +47,7 @@ #define XMSTATE_W_RESEND_DATA_DIGEST  0x8

 #define ISCSI_PAD_LEN                  4
 #define ISCSI_SG_TABLESIZE             SG_ALL
-#define ISCSI_TCP_MAX_CMD_LEN          16
+#define ISCSI_TCP_MAX_CMD_LEN          260  /* FIXME: SCSI_MAX_VARLEN_CDB_LEN 
*/

 struct crypto_hash;
 struct socket;
@@ -141,8 +141,10 @@ struct iscsi_r2t_info {

 struct iscsi_tcp_cmd_task {
        struct iscsi_cmd        hdr;
-       char                    hdrext[4*sizeof(__u16)+ /* AHS */
-                                   sizeof(__u32)];     /* HeaderDigest */
+       char                    hdrextbuf[sizeof(struct iscsi_ecdb_ahdr) +
+                                         sizeof(struct iscsi_rlength_ahdr) +
+                                         sizeof(__u32)];       /* HeaderDigest 
*/
+       char                    *hdrext;
        char                    pad[ISCSI_PAD_LEN];
        int                     pad_count;              /* padded bytes */
        struct iscsi_buf        headbuf;                /* header buf (xmit) */
@@ -152,7 +154,7 @@ struct iscsi_tcp_cmd_task {
        struct scatterlist      *sg;                    /* per-cmd SG list  */
        struct scatterlist      *bad_sg;                /* assert statement */
        int                     sg_count;               /* SG's to process  */
-       uint32_t                exp_r2tsn;
+       uint32_t                exp_datasn;             /* expected target's 
R2TSN/DataSN */
        int                     data_offset;
        struct iscsi_r2t_info   *r2t;                   /* in progress R2T    */
        struct iscsi_queue      r2tpool;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e11b23c..08e4528 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -120,10 +120,16 @@ static void iscsi_prep_scsi_cmd_pdu(stru
         session->cmdsn++;
         hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
         memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
-        memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+       if (sc->cmd_len < MAX_COMMAND_SIZE) {
+               memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - 
sc->cmd_len);
+       }

        ctask->data_count = 0;
-       if (sc->sc_data_direction == DMA_TO_DEVICE) {
+       switch (sc->sc_data_direction) {
+       case DMA_BIDIRECTIONAL:
+               hdr->flags |= ISCSI_FLAG_CMD_READ;
+               /* FALLTHROUGH */
+       case DMA_TO_DEVICE:
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
                /*
                 * Write counters:
@@ -145,11 +151,11 @@ static void iscsi_prep_scsi_cmd_pdu(stru
                ctask->unsol_datasn = 0;

                if (session->imm_data_en) {
-                       if (ctask->total_length >= session->first_burst)
+                       if (iscsi_out_total_length(ctask) >= 
session->first_burst)
                                ctask->imm_count = min(session->first_burst,
                                                        conn->max_xmit_dlength);
                        else
-                               ctask->imm_count = min(ctask->total_length,
+                               ctask->imm_count = 
min(iscsi_out_total_length(ctask),
                                                        conn->max_xmit_dlength);
                        hton24(ctask->hdr->dlength, ctask->imm_count);
                } else
@@ -157,20 +163,20 @@ static void iscsi_prep_scsi_cmd_pdu(stru

                if (!session->initial_r2t_en) {
                        ctask->unsol_count = min(session->first_burst,
-                               ctask->total_length) - ctask->imm_count;
+                               iscsi_out_total_length(ctask)) - 
ctask->imm_count;
                        ctask->unsol_offset = ctask->imm_count;
                }

                if (!ctask->unsol_count)
                        /* No unsolicit Data-Out's */
                        ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-       } else {
-               ctask->datasn = 0;
+               break;
+       case DMA_FROM_DEVICE:
+               hdr->flags |= ISCSI_FLAG_CMD_READ;
+               /* FALLTHROUGH */
+       default:
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
-
-               if (sc->sc_data_direction == DMA_FROM_DEVICE)
-                       hdr->flags |= ISCSI_FLAG_CMD_READ;
        }

        conn->scsicmd_pdus_cnt++;
@@ -817,7 +823,6 @@ int iscsi_queuecommand(struct scsi_cmnd
        ctask->conn = conn;
        ctask->sc = sc;
        INIT_LIST_HEAD(&ctask->running);
-       ctask->total_length = sc->request_bufflen;
        iscsi_prep_scsi_cmd_pdu(ctask);

        session->tt->init_cmd_task(ctask);
@@ -826,7 +831,9 @@ int iscsi_queuecommand(struct scsi_cmnd
        debug_scsi(
               "ctask enq [%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",
+               sc->sc_data_direction == DMA_TO_DEVICE ? "write" :
+                 sc->sc_data_direction == DMA_BIDIRECTIONAL ? "bidirectional" :
+                 sc->sc_data_direction == DMA_FROM_DEVICE ? "read" : "none",
                conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
        spin_unlock(&session->lock);
@@ -1633,7 +1640,7 @@ int iscsi_conn_start(struct iscsi_cls_co
                printk("iscsi: invalid burst lengths: "
                       "first_burst %d max_burst %d\n",
                       session->first_burst, session->max_burst);
-               return -EINVAL;
+//             return -EINVAL;
        }

        spin_lock_bh(&session->lock);
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 02f6e4b..e530734 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -139,6 +139,14 @@ struct iscsi_rlength_ahdr {
        __be32 read_length;
 };

+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+       __be16 ahslength;       /* CDB length - 15, including reserved byte */
+       uint8_t ahstype;
+       uint8_t reserved;
+       uint8_t ecdb[260 - 16]; /* 4-byte aligned extended CDB spillover */
+};
+
 /* SCSI Response Header */
 struct iscsi_cmd_rsp {
        uint8_t opcode;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ea0816d..6701ea6 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -25,6 +25,7 @@ #define LIBISCSI_H

 #include <linux/types.h>
 #include <linux/mutex.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <scsi/iscsi_proto.h>
@@ -33,7 +34,6 @@ #include <scsi/iscsi_if.h>
 struct scsi_transport_template;
 struct scsi_device;
 struct Scsi_Host;
-struct scsi_cmnd;
 struct socket;
 struct iscsi_transport;
 struct iscsi_cls_session;
@@ -99,7 +99,6 @@ struct iscsi_cmd_task {
         */
        struct iscsi_cmd        *hdr;
        int                     itt;            /* this ITT */
-       int                     datasn;         /* DataSN */

        uint32_t                unsol_datasn;
        int                     imm_count;      /* imm-data (bytes)   */
@@ -108,7 +107,6 @@ struct iscsi_cmd_task {
        int                     unsol_offset;
        int                     data_count;     /* remaining Data-Out */
        struct scsi_cmnd        *sc;            /* associated SCSI cmd*/
-       int                     total_length;
        struct iscsi_conn       *conn;          /* used connection    */
        struct iscsi_mgmt_task  *mtask;         /* tmf mtask in progr */

@@ -119,6 +117,20 @@ struct iscsi_cmd_task {
        void                    *dd_data;       /* driver/transport data */
 };

+static inline int
+iscsi_out_total_length(struct iscsi_cmd_task* ctask)
+{
+       return ctask->sc->request_bufflen;
+}
+
+static inline int
+iscsi_in_total_length(struct iscsi_cmd_task* ctask)
+{
+       return is_bidi_cmnd(ctask->sc) ?
+               ctask->sc->bidi_read_sdb.request_bufflen :
+               ctask->sc->request_bufflen;
+}
+
 struct iscsi_conn {
        struct iscsi_cls_conn   *cls_conn;      /* ptr to class connection */
        void                    *dd_data;       /* iscsi_transport data */
-- 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to