QSIG fully implemented
[obnox/wireshark/wip.git] / epan / dissectors / packet-fcp.c
index 48dfabb79add3c676ab97e35898f8489f77a0eb9..e12e2ab708c8ea0b43d765bbb011c312e36fd651 100644 (file)
@@ -4,8 +4,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -46,9 +46,9 @@
 #include <epan/packet.h>
 #include <epan/conversation.h>
 #include <epan/etypes.h>
+#include "packet-scsi.h"
 #include "packet-fc.h"
 #include "packet-fcp.h"
-#include "packet-scsi.h"
 
 /* Initialize the protocol and registered fields */
 static int proto_fcp         = -1;
@@ -61,6 +61,7 @@ static int hf_fcp_addlcdblen = -1;
 static int hf_fcp_rddata     = -1;
 static int hf_fcp_wrdata     = -1;
 static int hf_fcp_dl         = -1;
+static int hf_fcp_bidir_dl   = -1;
 static int hf_fcp_data_ro    = -1;
 static int hf_fcp_burstlen   = -1;
 static int hf_fcp_rspflags   = -1;
@@ -87,12 +88,19 @@ static int hf_fcp_rsp_flags_resid_under = -1;
 static int hf_fcp_rsp_flags_resid_over = -1;
 static int hf_fcp_rsp_flags_sns_vld = -1;
 static int hf_fcp_rsp_flags_res_vld = -1;
+static int hf_fcp_request_in = -1;
+static int hf_fcp_response_in = -1;
+static int hf_fcp_time = -1;
 
 /* Initialize the subtree pointers */
 static gint ett_fcp = -1;
 static gint ett_fcp_taskmgmt = -1;
 static gint ett_fcp_rsp_flags = -1;
 
+typedef struct _fcp_conv_data_t {
+    emem_tree_t *luns;
+} fcp_conv_data_t;
+
 static dissector_table_t fcp_dissector;
 static dissector_handle_t data_handle;
 
@@ -136,52 +144,6 @@ static const value_string fcp_rsp_code_val[] = {
 };
 
 
-typedef struct _fcp_conv_key {
-    guint32 conv_idx;
-} fcp_conv_key_t;
-
-typedef struct _fcp_conv_data {
-    guint32 fcp_dl;
-    gint32 fcp_lun;
-       nstime_t abs_ts;
-} fcp_conv_data_t;
-
-GHashTable *fcp_req_hash = NULL;
-
-/*
- * Hash Functions
- */
-static gint
-fcp_equal(gconstpointer v, gconstpointer w)
-{
-  const fcp_conv_key_t *v1 = v;
-  const fcp_conv_key_t *v2 = w;
-
-  return (v1->conv_idx == v2->conv_idx);
-}
-
-static guint
-fcp_hash (gconstpointer v)
-{
-       const fcp_conv_key_t *key = v;
-       guint val;
-
-       val = key->conv_idx;
-
-       return val;
-}
-
-/*
- * Protocol initialization
- */
-static void
-fcp_init_protocol(void)
-{
-    if (fcp_req_hash)
-        g_hash_table_destroy(fcp_req_hash);
-
-    fcp_req_hash = g_hash_table_new(fcp_hash, fcp_equal);
-}
 
 static const true_false_string fcp_mgmt_flags_obsolete_tfs = {
    "OBSOLETE BIT is SET",
@@ -229,7 +191,7 @@ dissect_task_mgmt_flags (packet_info *pinfo, proto_tree *parent_tree, tvbuff_t *
 
        if (!flags)
                proto_item_append_text(item, " (No values set)");
-                               
+
        proto_tree_add_boolean(tree, hf_fcp_mgmt_flags_obsolete, tvb, offset, 1, flags);
        if (flags&0x80){
                proto_item_append_text(item, "  OBSOLETE");
@@ -430,21 +392,17 @@ dissect_rsp_flags(proto_tree *parent_tree, tvbuff_t *tvb, int offset)
        }
 }
 
-/* Code to actually dissect the packets */
 static void
-dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree)
+dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree, conversation_t *conversation, fc_hdr *fchdr, fcp_conv_data_t *fcp_conv_data)
 {
     int offset = 0;
     int len,
         add_len = 0;
-    guint8 flags, lun0;
-    conversation_t *conversation;
-    fcp_conv_data_t *cdata;
-    fcp_conv_key_t ckey, *req_key;
-    scsi_task_id_t task_key;
-    guint16 lun=0xffff;
+    guint8 flags, rwflags, lun0;
+        guint16 lun=0xffff;
     tvbuff_t *cdb_tvb;
     int tvb_len, tvb_rlen;
+    itl_nexus_t *itl=NULL;
 
     /* Determine the length of the FCP part of the packet */
     flags = tvb_get_guint8 (tvb, offset+10);
@@ -458,63 +416,6 @@ dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, pro
         len = FCP_DEF_CMND_LEN;
     }
 
-    /* We track the conversation to determine how many bytes is required */
-    /* by the data that is sent back or sent next by the initiator as part */
-    /* of this command. The state is destroyed in the response dissector */
-
-    conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                      pinfo->ptype, pinfo->oxid,
-                                      pinfo->rxid, NO_PORT2);
-    if (!conversation) {
-       /* NO_PORT2: Dont check RXID, iFCP traces i have all have 
-        * RXID==0xffff in the command PDU.   ronnie */
-        conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                         pinfo->ptype, pinfo->oxid,
-                                         pinfo->rxid, NO_PORT2);
-    }
-
-    ckey.conv_idx = conversation->index;
-    task_key.conv_id = conversation->index;
-    task_key.task_id = conversation->index;
-    pinfo->private_data = (void *)&task_key;
-
-    cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
-                                                    &ckey);
-    /*
-     * XXX - the fetch of the fcp_dl value will throw an exception on
-     * a short frame before we get a chance to dissect the stuff before
-     * it.
-     *
-     * XXX - this doesn't appear to store the data length with the
-     * FCP packet with the data, so this might not work correctly
-     * if you select a command packet, select the corresponding data
-     * packet, and then select another data packet with a different
-     * length.
-     */
-    if (cdata) {
-        /* Since we never free the memory used by an exchange, this maybe a
-         * case of another request using the same exchange as a previous
-         * req.
-         */
-        cdata->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
-        cdata->abs_ts = pinfo->fd->abs_ts;
-    }
-    else {
-        req_key = se_alloc (sizeof(fcp_conv_key_t));
-        req_key->conv_idx = conversation->index;
-
-        cdata = se_alloc (sizeof(fcp_conv_data_t));
-        cdata->fcp_dl = tvb_get_ntohl (tvb, offset+12+16+add_len);
-        cdata->abs_ts = pinfo->fd->abs_ts;
-
-        g_hash_table_insert (fcp_req_hash, req_key, cdata);
-    }
-
-    /* XXX this one is redundant  right?  ronnie
-    dissect_scsi_cdb (tvb, pinfo, tree, offset+12, 16+add_len,
-                      SCSI_DEV_UNKNOWN, lun);
-    */
-
     proto_tree_add_uint_hidden(tree, hf_fcp_type, tvb, offset, 0, 0);
 
     lun0 = tvb_get_guint8 (tvb, offset);
@@ -525,23 +426,40 @@ dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, pro
      * real single-level LUN, all 8 bytes except byte 1 must be 0.
      */
     if (lun0) {
-      cdata->fcp_lun = -1;
       proto_tree_add_item(tree, hf_fcp_multilun, tvb, offset, 8, 0);
       lun=tvb_get_guint8(tvb, offset)&0x3f;
       lun<<=8;
       lun|=tvb_get_guint8(tvb, offset+1);
-    }
-    else {
-      cdata->fcp_lun = tvb_get_guint8 (tvb, offset+1);
+    } else {
       proto_tree_add_item(tree, hf_fcp_singlelun, tvb, offset+1,
                           1, 0);
       lun=tvb_get_guint8(tvb, offset+1);
     }
 
+    if (fchdr->itlq)
+        fchdr->itlq->lun=lun;
+
+    itl=(itl_nexus_t *)se_tree_lookup32(fcp_conv_data->luns, lun);
+    if(!itl){
+        itl=se_alloc(sizeof(itl_nexus_t));
+        itl->cmdset=0xff;
+       itl->conversation=conversation;
+        se_tree_insert32(fcp_conv_data->luns, lun, itl);
+    }
+
     proto_tree_add_item(tree, hf_fcp_crn, tvb, offset+8, 1, 0);
     proto_tree_add_item(tree, hf_fcp_taskattr, tvb, offset+9, 1, 0);
     dissect_task_mgmt_flags(pinfo, tree, tvb, offset+10);
     proto_tree_add_item(tree, hf_fcp_addlcdblen, tvb, offset+11, 1, 0);
+    rwflags=tvb_get_guint8(tvb, offset+11);
+    if(fchdr->itlq){
+       if(rwflags&0x02){
+           fchdr->itlq->task_flags|=SCSI_DATA_READ;
+       }
+       if(rwflags&0x01){
+           fchdr->itlq->task_flags|=SCSI_DATA_WRITE;
+       }
+    }
     proto_tree_add_item(tree, hf_fcp_rddata, tvb, offset+11, 1, 0);
     proto_tree_add_item(tree, hf_fcp_wrdata, tvb, offset+11, 1, 0);
 
@@ -552,46 +470,30 @@ dissect_fcp_cmnd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, pro
     if(tvb_rlen>(16+add_len))
       tvb_rlen=16+add_len;
     cdb_tvb=tvb_new_subset(tvb, offset+12, tvb_len, tvb_rlen);
-    dissect_scsi_cdb(cdb_tvb, pinfo, parent_tree, SCSI_DEV_UNKNOWN, lun);
+    dissect_scsi_cdb(cdb_tvb, pinfo, parent_tree, SCSI_DEV_UNKNOWN, fchdr->itlq, itl);
 
     proto_tree_add_item(tree, hf_fcp_dl, tvb, offset+12+16+add_len,
                         4, 0);
-}
-
-static void
-dissect_fcp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree)
-{
-    conversation_t *conversation;
-    fcp_conv_data_t *cdata = NULL;
-    fcp_conv_key_t ckey;
-    scsi_task_id_t task_key;
-
-    /* Retrieve conversation state to determine expected payload */
-    conversation = find_conversation (pinfo->fd->num, &pinfo->dst, &pinfo->src,
-                                      pinfo->ptype, pinfo->oxid,
-                                      pinfo->rxid, NO_PORT2);
-    if (conversation) {
-        ckey.conv_idx = conversation->index;
-
-        cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
-                                                        &ckey);
-        task_key.conv_id = conversation->index;
-        task_key.task_id = conversation->index;
-        pinfo->private_data = (void *)&task_key;
-    }
-    else {
-        pinfo->private_data = NULL;
+    if(fchdr->itlq){
+       fchdr->itlq->data_length=tvb_get_ntohl(tvb, offset+12+16+add_len);
     }
 
-    if (cdata->fcp_lun >= 0)
-        proto_tree_add_uint_hidden(tree, hf_fcp_singlelun, tvb,
-                                    0, 0, cdata->fcp_lun);
+    if( ((rwflags&0x03)==0x03)
+    &&  tvb_length_remaining(tvb, offset+12+16+add_len+4)>=4){
+       proto_tree_add_item(tree, hf_fcp_bidir_dl, tvb, offset+12+16+add_len+4,
+                        4, 0);
+       if(fchdr->itlq){
+           fchdr->itlq->bidir_data_length=tvb_get_ntohl(tvb, offset+12+16+add_len+4);
+       }
 
-    if (cdata) {
-        dissect_scsi_payload(tvb, pinfo, parent_tree, FALSE, (guint16) cdata->fcp_lun);
-    } else {
-        dissect_scsi_payload(tvb, pinfo, parent_tree, FALSE, 0xffff);
     }
+
+}
+
+static void
+dissect_fcp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, conversation_t *conversation _U_, fc_hdr *fchdr, itl_nexus_t *itl)
+{
+    dissect_scsi_payload(tvb, pinfo, parent_tree, FALSE, fchdr->itlq, itl, fchdr->relative_offset);
 }
 
 /* fcp-3  9.5 table 24 */
@@ -610,17 +512,13 @@ dissect_fcp_rspinfo(tvbuff_t *tvb, proto_tree *tree, int offset)
 }
 
 static void
-dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree)
+dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree, conversation_t *conversation _U_, fc_hdr *fchdr, itl_nexus_t *itl)
 {
     guint32 offset = 0;
     gint32 snslen = 0,
            rsplen = 0;
     guint8 flags;
     guint8 status;
-    conversation_t *conversation;
-    fcp_conv_data_t *cdata = NULL;
-    fcp_conv_key_t ckey;
-    scsi_task_id_t task_key;
 
     status = tvb_get_guint8 (tvb, offset+11);
 
@@ -629,23 +527,9 @@ dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, prot
                          val_to_str (status, scsi_status_val, "0x%x"));
     }
 
-    /* Response marks the end of the conversation. So destroy state */
-    conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                      pinfo->ptype, pinfo->oxid,
-                                      pinfo->rxid, NO_PORT2);
-    if (conversation) {
-        ckey.conv_idx = conversation->index;
-
-        cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
-                                                        &ckey);
-        task_key.conv_id = task_key.task_id = conversation->index;
-        pinfo->private_data = (void *)&task_key;
-    }
-
     proto_tree_add_uint_hidden(tree, hf_fcp_type, tvb, offset, 0, 0);
 
 
-
         /* 8 reserved bytes */
         offset+=8;
 
@@ -660,9 +544,7 @@ dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, prot
 
         /* scsi status code */
         proto_tree_add_item(tree, hf_fcp_scsistatus, tvb, offset, 1, 0);
-        if(cdata){
-            dissect_scsi_rsp(tvb, pinfo, parent_tree, (guint16) cdata->fcp_lun, tvb_get_guint8(tvb, offset));
-        }
+        dissect_scsi_rsp(tvb, pinfo, parent_tree, fchdr->itlq, itl, tvb_get_guint8(tvb, offset));
         offset++;
 
         /* residual count */
@@ -690,7 +572,7 @@ dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, prot
         /* rsp_info */
         if(rsplen){
             tvbuff_t *rspinfo_tvb;
-       
+
             rspinfo_tvb=tvb_new_subset(tvb, offset, MIN(rsplen, tvb_length_remaining(tvb, offset)), rsplen);
             dissect_fcp_rspinfo(tvb, tree, 0);
 
@@ -700,11 +582,11 @@ dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, prot
         /* sense info */
         if(snslen){
             tvbuff_t *sns_tvb;
-       
+
             sns_tvb=tvb_new_subset(tvb, offset, MIN(snslen, tvb_length_remaining(tvb, offset)), snslen);
             dissect_scsi_snsinfo (sns_tvb, pinfo, parent_tree, 0,
                                   snslen,
-                                 (guint16) (cdata?cdata->fcp_lun:0xffff) );
+                                 fchdr->itlq, itl);
 
             offset+=snslen;
         }
@@ -716,54 +598,13 @@ dissect_fcp_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, prot
             }
             offset+=4;
         }
-
-
-        if (cdata) {
-            /*
-             * XXX - this isn't done if an exception is thrown.
-             */
-            g_hash_table_remove (fcp_req_hash, &ckey);
-        }
 }
 
 static void
-dissect_fcp_xfer_rdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, proto_tree *tree)
+dissect_fcp_xfer_rdy(tvbuff_t *tvb, proto_tree *tree)
 {
     int offset = 0;
-    conversation_t *conversation;
-    fcp_conv_data_t *cdata = NULL;
-    fcp_conv_key_t ckey, *req_key;
-
-
-    /* Retrieve conversation state to determine expected payload */
-    conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                      pinfo->ptype, pinfo->oxid,
-                                      pinfo->rxid, NO_PORT2);
-    if (!conversation) {
-        conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst,
-                                         pinfo->ptype, pinfo->oxid,
-                                         pinfo->rxid, NO_PORT2);
-    }
-
-    if (conversation) {
-        ckey.conv_idx = conversation->index;
 
-        cdata = (fcp_conv_data_t *)g_hash_table_lookup (fcp_req_hash,
-                                                        &ckey);
-        if (cdata != NULL) {
-            cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
-        }
-        else {
-            req_key = se_alloc (sizeof(fcp_conv_key_t));
-            req_key->conv_idx = conversation->index;
-
-            cdata = se_alloc (sizeof(fcp_conv_data_t));
-            cdata->fcp_dl = tvb_get_ntohl (tvb, offset+4);
-            cdata->fcp_lun = -1;
-
-            g_hash_table_insert (fcp_req_hash, req_key, cdata);
-        }
-    }
 
     proto_tree_add_uint_hidden(tree, hf_fcp_type, tvb, offset, 0, 0);
 
@@ -774,11 +615,14 @@ dissect_fcp_xfer_rdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
 static void
 dissect_fcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-    proto_item *ti;
+    proto_item *ti=NULL;
     proto_tree *fcp_tree = NULL;
-
-/* Set up structures needed to add the protocol subtree and manage it */
+    fc_hdr *fchdr;
     guint8 r_ctl;
+    fcp_conv_data_t *fcp_conv_data=NULL;
+    itl_nexus_t *itl=NULL;
+
+    fchdr=(fc_hdr *)pinfo->private_data;
 
     /* Make entries in Protocol column and Info column on summary display */
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -800,21 +644,55 @@ dissect_fcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         fcp_tree = proto_item_add_subtree(ti, ett_fcp);
     }
 
+
+    fcp_conv_data=conversation_get_proto_data(fchdr->conversation, proto_fcp);
+    if(!fcp_conv_data){
+        fcp_conv_data=se_alloc(sizeof(fcp_conv_data_t));
+        fcp_conv_data->luns=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "FCP Luns");
+        conversation_add_proto_data(fchdr->conversation, proto_fcp, fcp_conv_data);
+    }
+
+    if(r_ctl!=FCP_IU_CMD){
+        itl=(itl_nexus_t *)se_tree_lookup32(fcp_conv_data->luns, fchdr->itlq->lun);
+    }
+
+    /* put a request_in in all frames except the command frame */
+    if((r_ctl!=FCP_IU_CMD)&&(fchdr->itlq->first_exchange_frame)){
+        proto_item *it;
+        it=proto_tree_add_uint(fcp_tree, hf_fcp_singlelun, tvb, 0, 0, fchdr->itlq->lun);
+        PROTO_ITEM_SET_GENERATED(it);
+        it=proto_tree_add_uint(fcp_tree, hf_fcp_request_in, tvb, 0, 0, fchdr->itlq->first_exchange_frame);
+        PROTO_ITEM_SET_GENERATED(it);
+        /* only put the response time in the actual response frame */
+        if(r_ctl==FCP_IU_RSP){
+            nstime_t delta_ts;
+            nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &fchdr->itlq->fc_time);
+            it=proto_tree_add_time(ti, hf_fcp_time, tvb, 0, 0, &delta_ts);
+            PROTO_ITEM_SET_GENERATED(it);
+        }
+    }
+    /* put a response_in in all frames except the response frame */
+    if((r_ctl!=FCP_IU_RSP)&&(fchdr->itlq->last_exchange_frame)){
+        proto_item *it;
+        it=proto_tree_add_uint(fcp_tree, hf_fcp_response_in, tvb, 0, 0, fchdr->itlq->last_exchange_frame);
+        PROTO_ITEM_SET_GENERATED(it);
+    }
+
     switch (r_ctl) {
     case FCP_IU_DATA:
-        dissect_fcp_data(tvb, pinfo, tree, fcp_tree);
+        dissect_fcp_data(tvb, pinfo, tree, fchdr->conversation, fchdr, itl);
         break;
     case FCP_IU_CONFIRM:
         /* Nothing to be done here */
         break;
     case FCP_IU_XFER_RDY:
-        dissect_fcp_xfer_rdy(tvb, pinfo, tree, fcp_tree);
+        dissect_fcp_xfer_rdy(tvb, fcp_tree);
         break;
     case FCP_IU_CMD:
-        dissect_fcp_cmnd(tvb, pinfo, tree, fcp_tree);
+        dissect_fcp_cmnd(tvb, pinfo, tree, fcp_tree, fchdr->conversation, fchdr, fcp_conv_data);
         break;
     case FCP_IU_RSP:
-        dissect_fcp_rsp(tvb, pinfo, tree, fcp_tree);
+        dissect_fcp_rsp(tvb, pinfo, tree, fcp_tree, fchdr->conversation, fchdr, itl);
         break;
     default:
         call_dissector(data_handle, tvb, pinfo, tree);
@@ -824,7 +702,7 @@ dissect_fcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
 }
 
-/* Register the protocol with Ethereal */
+/* Register the protocol with Wireshark */
 
 /* this format is require because a script is used to build the C function
    that calls all the protocol registration.
@@ -843,7 +721,7 @@ proto_register_fcp (void)
          {"Multi-Level LUN", "fcp.multilun", FT_BYTES, BASE_HEX, NULL, 0x0,
           "", HFILL}},
         { &hf_fcp_singlelun,
-          {"LUN", "fcp.lun", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL}},
+          {"LUN", "fcp.lun", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL}},
         { &hf_fcp_crn,
           {"Command Ref Num", "fcp.crn", FT_UINT8, BASE_DEC, NULL, 0x0, "",
            HFILL}},
@@ -862,6 +740,8 @@ proto_register_fcp (void)
           {"WRDATA", "fcp.wrdata", FT_BOOLEAN, 8, NULL, 0x01, "", HFILL}},
         { &hf_fcp_dl,
           {"FCP_DL", "fcp.dl", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
+        { &hf_fcp_bidir_dl,
+          {"FCP_BIDIRECTIONAL_READ_DL", "fcp.bidir_dl", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
         { &hf_fcp_data_ro,
           {"FCP_DATA_RO", "fcp.data_ro", FT_UINT32, BASE_DEC, NULL, 0x0, "",
            HFILL}},
@@ -892,36 +772,45 @@ proto_register_fcp (void)
         { &hf_fcp_scsistatus,
           {"SCSI Status", "fcp.status", FT_UINT8, BASE_HEX,
            VALS (scsi_status_val), 0x0, "", HFILL}},
-       { &hf_fcp_mgmt_flags_obsolete, 
+       { &hf_fcp_mgmt_flags_obsolete,
          { "Obsolete", "fcp.mgmt.flags.obsolete", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_obsolete_tfs), 0x80, "", HFILL }},
-       { &hf_fcp_mgmt_flags_clear_aca, 
+       { &hf_fcp_mgmt_flags_clear_aca,
          { "Clear ACA", "fcp.mgmt.flags.clear_aca", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_clear_aca_tfs), 0x40, "", HFILL }},
-       { &hf_fcp_mgmt_flags_target_reset, 
+       { &hf_fcp_mgmt_flags_target_reset,
          { "Target Reset", "fcp.mgmt.flags.target_reset", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_target_reset_tfs), 0x20, "", HFILL }},
-       { &hf_fcp_mgmt_flags_lu_reset, 
+       { &hf_fcp_mgmt_flags_lu_reset,
          { "LU Reset", "fcp.mgmt.flags.lu_reset", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_lu_reset_tfs), 0x10, "", HFILL }},
-       { &hf_fcp_mgmt_flags_rsvd, 
+       { &hf_fcp_mgmt_flags_rsvd,
          { "Rsvd", "fcp.mgmt.flags.rsvd", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_rsvd_tfs), 0x08, "", HFILL }},
-       { &hf_fcp_mgmt_flags_clear_task_set, 
+       { &hf_fcp_mgmt_flags_clear_task_set,
          { "Clear Task Set", "fcp.mgmt.flags.clear_task_set", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_clear_task_set_tfs), 0x04, "", HFILL }},
-       { &hf_fcp_mgmt_flags_abort_task_set, 
+       { &hf_fcp_mgmt_flags_abort_task_set,
          { "Abort Task Set", "fcp.mgmt.flags.abort_task_set", FT_BOOLEAN, 8, TFS(&fcp_mgmt_flags_abort_task_set_tfs), 0x02, "", HFILL }},
-       { &hf_fcp_rsp_flags_bidi, 
+       { &hf_fcp_rsp_flags_bidi,
          { "Bidi Rsp", "fcp.rsp.flags.bidi", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_bidi_tfs), 0x80, "", HFILL }},
-       { &hf_fcp_rsp_flags_bidi_rru, 
+       { &hf_fcp_rsp_flags_bidi_rru,
          { "Bidi Read Resid Under", "fcp.rsp.flags.bidi_rru", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_bidi_rru_tfs), 0x40, "", HFILL }},
-       { &hf_fcp_rsp_flags_bidi_rro, 
+       { &hf_fcp_rsp_flags_bidi_rro,
          { "Bidi Read Resid Over", "fcp.rsp.flags.bidi_rro", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_bidi_rro_tfs), 0x20, "", HFILL }},
-       { &hf_fcp_rsp_flags_conf_req, 
+       { &hf_fcp_rsp_flags_conf_req,
          { "Conf Req", "fcp.rsp.flags.conf_req", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_conf_req_tfs), 0x10, "", HFILL }},
-       { &hf_fcp_rsp_flags_resid_under, 
+       { &hf_fcp_rsp_flags_resid_under,
          { "Resid Under", "fcp.rsp.flags.resid_under", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_resid_under_tfs), 0x08, "", HFILL }},
-       { &hf_fcp_rsp_flags_resid_over, 
+       { &hf_fcp_rsp_flags_resid_over,
          { "Resid Over", "fcp.rsp.flags.resid_over", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_resid_over_tfs), 0x04, "", HFILL }},
-       { &hf_fcp_rsp_flags_sns_vld, 
+       { &hf_fcp_rsp_flags_sns_vld,
          { "SNS Vld", "fcp.rsp.flags.sns_vld", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_sns_vld_tfs), 0x02, "", HFILL }},
-       { &hf_fcp_rsp_flags_res_vld, 
+       { &hf_fcp_rsp_flags_res_vld,
          { "RES Vld", "fcp.rsp.flags.res_vld", FT_BOOLEAN, 8, TFS(&fcp_rsp_flags_res_vld_tfs), 0x01, "", HFILL }},
+        { &hf_fcp_request_in,
+          { "Request In", "fcp.request_in", FT_FRAMENUM, BASE_NONE, NULL,
+           0, "The frame number for the request", HFILL }},
+        { &hf_fcp_response_in,
+          { "Response In", "fcp.response_in", FT_FRAMENUM, BASE_NONE, NULL,
+           0, "The frame number of the response", HFILL }},
+        { &hf_fcp_time,
+          { "Time from FCP_CMND", "fcp.time", FT_RELATIVE_TIME, BASE_NONE, NULL,
+           0, "Time since the FCP_CMND frame", HFILL }},
     };
 
     /* Setup protocol subtree array */
@@ -940,7 +829,6 @@ proto_register_fcp (void)
     proto_register_subtree_array(ett, array_length(ett));
     fcp_dissector = register_dissector_table ("fcp.type", "FCP Type", FT_UINT8,
                                               BASE_HEX);
-    register_init_routine (&fcp_init_protocol);
 }
 
 /* If this dissector uses sub-dissector registration add a registration routine.