]> err.no Git - linux-2.6/commitdiff
[SCSI] libiscsi, iscsi_tcp, iscsi_iser: check that burst lengths are valid.
authorMike Christie <michaelc@cs.wisc.edu>
Thu, 31 Aug 2006 22:09:24 +0000 (18:09 -0400)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Sat, 2 Sep 2006 18:37:04 +0000 (13:37 -0500)
iSCSI RFC states that the first burst length must be smaller than the
max burst length. We currently assume targets will be good, but that may
not be the case, so this patch adds a check.

This patch also moves the unsol data out offset to the lib so the LLDs
do not have to track it.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/iscsi_tcp.h
drivers/scsi/libiscsi.c
include/scsi/libiscsi.h

index 1437d7ee3b1901727fcb1e7ba7ffd0408949704e..101e407eaa43d534b5d2b9e3374bf4f2c536b733 100644 (file)
@@ -141,18 +141,11 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
 
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
                BUG_ON(ctask->total_length == 0);
-               /* bytes to be sent via RDMA operations */
-               iser_ctask->rdma_data_count = ctask->total_length -
-                                        ctask->imm_count -
-                                        ctask->unsol_count;
 
-               debug_scsi("cmd [itt %x total %d imm %d unsol_data %d "
-                          "rdma_data %d]\n",
+               debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
                           ctask->itt, ctask->total_length, ctask->imm_count,
-                          ctask->unsol_count, iser_ctask->rdma_data_count);
-       } else
-               /* bytes to be sent via RDMA operations */
-               iser_ctask->rdma_data_count = ctask->total_length;
+                          ctask->unsol_count);
+       }
 
        iser_ctask_rdma_init(iser_ctask);
 }
@@ -196,13 +189,10 @@ iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
 {
        struct iscsi_data  hdr;
        int error = 0;
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
 
        /* Send data-out PDUs while there's still unsolicited data to send */
        while (ctask->unsol_count > 0) {
-               iscsi_prep_unsolicit_data_pdu(ctask, &hdr,
-                                             iser_ctask->rdma_data_count);
-
+               iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
                debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
                           hdr.itt, ctask->data_count);
 
index 3350ba690cfe1ef770e8df27456b724ad00008f9..7c3d0c96d889f950b238c36f37159c02583fae58 100644 (file)
@@ -257,7 +257,6 @@ struct iscsi_iser_conn {
 struct iscsi_iser_cmd_task {
        struct iser_desc             desc;
        struct iscsi_iser_conn       *iser_conn;
-       int                          rdma_data_count;/* RDMA bytes           */
        enum iser_task_status        status;
        int                          command_sent;  /* set if command  sent  */
        int                          dir[ISER_DIRS_NUM];      /* set if dir use*/
index 058f094f945aba2f3b4d536cf9388af2dd05c157..a97a3a4e99eb58dd3aced42d95d1c85ed449f064 100644 (file)
@@ -1264,19 +1264,6 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                            r2t->data_count);
 }
 
-static void
-iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-       struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-       struct iscsi_data_task *dtask;
-
-       dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
-       iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
-                                     tcp_ctask->r2t_data_count);
-       iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
-                          sizeof(struct iscsi_hdr));
-}
-
 /**
  * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  * @conn: iscsi connection
@@ -1326,14 +1313,11 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
                if (ctask->unsol_count)
                        tcp_ctask->xmstate |= XMSTATE_UNS_HDR |
                                                XMSTATE_UNS_INIT;
-               tcp_ctask->r2t_data_count = ctask->total_length -
-                                   ctask->imm_count -
-                                   ctask->unsol_count;
 
-               debug_scsi("cmd [itt 0x%x total %d imm %d imm_data %d "
-                          "r2t_data %d]\n",
+               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, tcp_ctask->r2t_data_count);
+                          ctask->unsol_count, ctask->unsol_offset);
        } else
                tcp_ctask->xmstate = XMSTATE_R_HDR;
 
@@ -1531,8 +1515,10 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 
        tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
        if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
-               iscsi_unsolicit_data_init(conn, ctask);
-               dtask = tcp_ctask->dtask;
+               dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
+               iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
+               iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
+                                  sizeof(struct iscsi_hdr));
                if (conn->hdrdgst_en)
                        iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
                                        (u8*)dtask->hdrext);
@@ -1720,7 +1706,6 @@ data_out_done:
         * Done with this R2T. Check if there are more
         * outstanding R2Ts ready to be processed.
         */
-       BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
        if (conn->datadgst_en) {
                rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
                                            &dtask->digest, 1);
@@ -1732,7 +1717,6 @@ data_out_done:
                debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
        }
 
-       tcp_ctask->r2t_data_count -= r2t->data_length;
        tcp_ctask->r2t = NULL;
        spin_lock_bh(&session->lock);
        __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
index 6a4ee704e46e8cf29dbea2423f1a9f38de8c27d6..aace8f70dfd761deca96c31b65b48dc5e0c43f77 100644 (file)
@@ -157,7 +157,6 @@ struct iscsi_tcp_cmd_task {
        struct scatterlist      *bad_sg;                /* assert statement */
        int                     sg_count;               /* SG's to process  */
        uint32_t                exp_r2tsn;
-       int                     r2t_data_count;         /* R2T Data-Out bytes */
        int                     data_offset;
        struct iscsi_r2t_info   *r2t;                   /* in progress R2T    */
        struct iscsi_queue      r2tpool;
index 5884cd26d53af32ce9fcaf0a8e2d4e12d46dd90a..a7c6e70f4ef85c0aecf9421c013601d0cce2b7b9 100644 (file)
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
 EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
 
 void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
-                                  struct iscsi_data *hdr,
-                                  int transport_data_cnt)
+                                  struct iscsi_data *hdr)
 {
        struct iscsi_conn *conn = ctask->conn;
 
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
 
        hdr->itt = ctask->hdr->itt;
        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-
-       hdr->offset = cpu_to_be32(ctask->total_length -
-                                 transport_data_cnt -
-                                 ctask->unsol_count);
+       hdr->offset = cpu_to_be32(ctask->unsol_offset);
 
        if (ctask->unsol_count > conn->max_xmit_dlength) {
                hton24(hdr->dlength, conn->max_xmit_dlength);
                ctask->data_count = conn->max_xmit_dlength;
+               ctask->unsol_offset += ctask->data_count;
                hdr->flags = 0;
        } else {
                hton24(hdr->dlength, ctask->unsol_count);
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
         memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
         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) {
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
                /*
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                 */
                ctask->imm_count = 0;
                ctask->unsol_count = 0;
+               ctask->unsol_offset = 0;
                ctask->unsol_datasn = 0;
 
                if (session->imm_data_en) {
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                } else
                        zero_data(ctask->hdr->dlength);
 
-               if (!session->initial_r2t_en)
+               if (!session->initial_r2t_en) {
                        ctask->unsol_count = min(session->first_burst,
                                ctask->total_length) - 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;
@@ -1520,11 +1522,18 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
 
-       if (session == NULL) {
+       if (!session) {
                printk(KERN_ERR "iscsi: can't start unbound connection\n");
                return -EPERM;
        }
 
+       if (session->first_burst > session->max_burst) {
+               printk("iscsi: invalid burst lengths: "
+                      "first_burst %d max_burst %d\n",
+                      session->first_burst, session->max_burst);
+               return -EINVAL;
+       }
+
        spin_lock_bh(&session->lock);
        conn->c_stage = ISCSI_CONN_STARTED;
        session->state = ISCSI_STATE_LOGGED_IN;
index 41904f611d122d358dcfa3a1075add55e4ed0b5f..4900650bd08124642ff2539a61ceda6f10cc5a33 100644 (file)
@@ -102,6 +102,8 @@ struct iscsi_cmd_task {
        uint32_t                unsol_datasn;
        int                     imm_count;      /* imm-data (bytes)   */
        int                     unsol_count;    /* unsolicited (bytes)*/
+       /* offset in unsolicited stream (bytes); */
+       int                     unsol_offset;
        int                     data_count;     /* remaining Data-Out */
        struct scsi_cmnd        *sc;            /* associated SCSI cmd*/
        int                     total_length;
@@ -290,8 +292,7 @@ extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
 extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
                                    struct iscsi_nopin *);
 extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
-                                       struct iscsi_data *hdr,
-                                       int transport_data_cnt);
+                                       struct iscsi_data *hdr);
 extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
                                char *, uint32_t);
 extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,