Guy suggested that the dcerpc opnum value_string code could be simplified
[obnox/wireshark/wip.git] / packet-scsi.c
index 076238d2b23f37f360d9a211703799a8db5784e2..3a06fef8ffbd4df13ad4609ebd3c232844868f2c 100644 (file)
@@ -2,22 +2,22 @@
  * Routines for decoding SCSI CDBs and responses
  * Author: Dinesh G Dutt (ddutt@cisco.com)
  *
- * $Id: packet-scsi.c,v 1.11 2002/08/02 23:36:00 jmayer Exp $
+ * $Id: packet-scsi.c,v 1.32 2003/07/09 03:42:55 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 2002 Gerald Combs
- * 
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
@@ -38,7 +38,7 @@
  * There are four main routines that are provided:
  * o dissect_scsi_cdb - invoked on receiving a SCSI Command
  *   void dissect_scsi_cdb (tvbuff_t *, packet_info *, proto_tree *, guint,
- *   guint); 
+ *   guint);
  * o dissect_scsi_payload - invoked to decode SCSI responses
  *   void dissect_scsi_payload (tvbuff_t *, packet_info *, proto_tree *, guint,
  *                              gboolean, guint32);
@@ -72,7 +72,7 @@
  * SCSI command set (SPC-2/3) is decoded for all SCSI devices. If there is a
  * mixture of devices in the trace, some with Inquiry response and some
  * without, the user preference is used only for those devices whose type the
- * decoder has not been able to determine. 
+ * decoder has not been able to determine.
  *
  */
 #ifdef HAVE_CONFIG_H
 #include <string.h>
 #include <epan/strutil.h>
 #include <epan/conversation.h>
+#include <epan/int-64bit.h>
 #include "prefs.h"
 #include "packet-scsi.h"
 
 static int proto_scsi                    = -1;
 static int hf_scsi_spcopcode             = -1;
 static int hf_scsi_sbcopcode             = -1;
+static int hf_scsi_sscopcode             = -1;
+static int hf_scsi_smcopcode             = -1;
 static int hf_scsi_control               = -1;
 static int hf_scsi_inquiry_flags         = -1;
 static int hf_scsi_inquiry_evpd_page     = -1;
 static int hf_scsi_inquiry_cmdt_page     = -1;
 static int hf_scsi_alloclen              = -1;
 static int hf_scsi_logsel_flags          = -1;
-static int hf_scsi_log_pc                = -1;
+static int hf_scsi_logsel_pc             = -1;
 static int hf_scsi_paramlen              = -1;
 static int hf_scsi_logsns_flags          = -1;
+static int hf_scsi_logsns_pc             = -1;
 static int hf_scsi_logsns_pagecode       = -1;
 static int hf_scsi_paramlen16            = -1;
 static int hf_scsi_modesel_flags         = -1;
 static int hf_scsi_alloclen16            = -1;
 static int hf_scsi_modesns_pc            = -1;
-static int hf_scsi_modesns_pagecode      = -1;
+static int hf_scsi_spcpagecode           = -1;
+static int hf_scsi_sbcpagecode           = -1;
+static int hf_scsi_sscpagecode           = -1;
+static int hf_scsi_smcpagecode           = -1;
 static int hf_scsi_modesns_flags         = -1;
 static int hf_scsi_persresvin_svcaction  = -1;
 static int hf_scsi_persresvout_svcaction = -1;
@@ -128,6 +135,7 @@ static int hf_scsi_rdwr10_xferlen        = -1;
 static int hf_scsi_readdefdata_flags     = -1;
 static int hf_scsi_cdb_defectfmt         = -1;
 static int hf_scsi_reassignblks_flags    = -1;
+static int hf_scsi_inq_qualifier         = -1;
 static int hf_scsi_inq_devtype           = -1;
 static int hf_scsi_inq_version           = -1;
 static int hf_scsi_rluns_lun             = -1;
@@ -151,7 +159,6 @@ static int hf_scsi_sksv                  = -1;
 static int hf_scsi_inq_normaca           = -1;
 static int hf_scsi_persresv_key          = -1;
 static int hf_scsi_persresv_scopeaddr    = -1;
-static int hf_scsi_sscopcode             = -1;
 static int hf_scsi_add_cdblen = -1;
 static int hf_scsi_svcaction = -1;
 
@@ -162,13 +169,18 @@ static gint ett_scsi_page    = -1;
 typedef guint32 scsi_cmnd_type;
 typedef guint32 scsi_device_type;
 
-/* Valid SCSI Device Types */
+/* Valid SCSI Command Types */
 #define SCSI_CMND_SPC2                   1
 #define SCSI_CMND_SBC2                   2
 #define SCSI_CMND_SSC2                   3
+#define SCSI_CMND_SMC2                   4
 
-/* SPC-2 Commands */
+/* SPC and SPC-2 Commands */
 
+#define SCSI_SPC_CHANGE_DEFINITION       0x40
+#define SCSI_SPC_COMPARE                 0x39
+#define SCSI_SPC_COPY                    0x18
+#define SCSI_SPC_COPY_AND_VERIFY         0x3A
 #define SCSI_SPC2_INQUIRY                0x12
 #define SCSI_SPC2_EXTCOPY                0x83
 #define SCSI_SPC2_LOGSELECT              0x4C
@@ -187,8 +199,8 @@ typedef guint32 scsi_device_type;
 #define SCSI_SPC2_RELEASE10              0x57
 #define SCSI_SPC2_REPORTDEVICEID         0xA3
 #define SCSI_SPC2_REPORTLUNS             0xA0
-#define SCSI_SPC2_REQSENSE               0x03 
-#define SCSI_SPC2_RESERVE6               0x16 
+#define SCSI_SPC2_REQSENSE               0x03
+#define SCSI_SPC2_RESERVE6               0x16
 #define SCSI_SPC2_RESERVE10              0x56
 #define SCSI_SPC2_SENDDIAG               0x1D
 #define SCSI_SPC2_SETDEVICEID            0xA4
@@ -197,27 +209,32 @@ typedef guint32 scsi_device_type;
 #define SCSI_SPC2_VARLENCDB              0x7F
 
 static const value_string scsi_spc2_val[] = {
+    {SCSI_SPC_CHANGE_DEFINITION  , "Change Definition"},
+    {SCSI_SPC_COMPARE            , "Compare"},
+    {SCSI_SPC_COPY               , "Copy"},
+    {SCSI_SPC_COPY_AND_VERIFY    , "Copy And Verify"},
     {SCSI_SPC2_EXTCOPY           , "Extended Copy"},
     {SCSI_SPC2_INQUIRY           , "Inquiry"},
     {SCSI_SPC2_LOGSELECT         , "Log Select"},
     {SCSI_SPC2_LOGSENSE          , "Log Sense"},
-    {SCSI_SPC2_MODESELECT6       , "Mode Select (6)"},
-    {SCSI_SPC2_MODESELECT10      , "Mode Select (10)"},
-    {SCSI_SPC2_MODESENSE6        , "Mode Sense (6)"},
-    {SCSI_SPC2_MODESENSE10       , "Mode Sense (10)"},
+    {SCSI_SPC2_MODESELECT6       , "Mode Select(6)"},
+    {SCSI_SPC2_MODESELECT10      , "Mode Select(10)"},
+    {SCSI_SPC2_MODESENSE6        , "Mode Sense(6)"},
+    {SCSI_SPC2_MODESENSE10       , "Mode Sense(10)"},
     {SCSI_SPC2_PERSRESVIN        , "Persistent Reserve In"},
     {SCSI_SPC2_PERSRESVOUT       , "Persistent Reserve Out"},
     {SCSI_SPC2_PREVMEDREMOVAL    , "Prevent/Allow Medium Removal"},
     {SCSI_SPC2_RCVCOPYRESULTS    , "Receive Copy Results"},
     {SCSI_SPC2_RCVDIAGRESULTS    , "Receive Diagnostics Results"},
     {SCSI_SPC2_READBUFFER        , "Read Buffer"},
-    {SCSI_SPC2_RELEASE6          , "Release (6)"},
-    {SCSI_SPC2_RELEASE10         , "Release (10)"},
+    {SCSI_SPC2_RELEASE6          , "Release(6)"},
+    {SCSI_SPC2_RELEASE10         , "Release(10)"},
     {SCSI_SPC2_REPORTDEVICEID    , "Report Device ID"},
     {SCSI_SPC2_REPORTLUNS        , "Report LUNs"},
     {SCSI_SPC2_REQSENSE          , "Request Sense"},
-    {SCSI_SPC2_RESERVE6          , "Reserve (6)"},
-    {SCSI_SPC2_RESERVE10         , "Reserve (10)"},
+    {SCSI_SPC2_RESERVE6          , "Reserve(6)"},
+    {SCSI_SPC2_RESERVE10         , "Reserve(10)"},
+    {SCSI_SPC2_SENDDIAG          , "Send Diagnostic"},
     {SCSI_SPC2_TESTUNITRDY       , "Test Unit Ready"},
     {SCSI_SPC2_WRITEBUFFER       , "Write Buffer"},
     {SCSI_SPC2_VARLENCDB         , "Variable Length CDB"},
@@ -227,7 +244,7 @@ static const value_string scsi_spc2_val[] = {
 /* SBC-2 Commands */
 #define SCSI_SBC2_FORMATUNIT             0x04
 #define SCSI_SBC2_LOCKUNLKCACHE10        0x36
-#define SCSI_SPC2_LOCKUNLKCACHE16        0x92
+#define SCSI_SBC2_LOCKUNLKCACHE16        0x92
 #define SCSI_SBC2_PREFETCH10             0x34
 #define SCSI_SBC2_PREFETCH16             0x90
 #define SCSI_SBC2_READ6                  0x08
@@ -276,52 +293,52 @@ static const value_string scsi_spc2_val[] = {
 
 static const value_string scsi_sbc2_val[] = {
     {SCSI_SBC2_FORMATUNIT    , "Format Unit"},
-    {SCSI_SBC2_LOCKUNLKCACHE10, "Lock Unlock Cache (10)"},
-    {SCSI_SPC2_LOCKUNLKCACHE16, "Lock Unlock Cache (16)"},
-    {SCSI_SBC2_PREFETCH10, "Pre-Fetch (10)"},
-    {SCSI_SBC2_PREFETCH16, "Pre-Fetch (16)"},
-    {SCSI_SBC2_READ6         , "Read (6)"},
-    {SCSI_SBC2_READ10        , "Read (10)"},
-    {SCSI_SBC2_READ12        , "Read (12)"},
-    {SCSI_SBC2_READ16        , "Read (16)"},
+    {SCSI_SBC2_LOCKUNLKCACHE10, "Lock Unlock Cache(10)"},
+    {SCSI_SBC2_LOCKUNLKCACHE16, "Lock Unlock Cache(16)"},
+    {SCSI_SBC2_PREFETCH10, "Pre-Fetch(10)"},
+    {SCSI_SBC2_PREFETCH16, "Pre-Fetch(16)"},
+    {SCSI_SBC2_READ6         , "Read(6)"},
+    {SCSI_SBC2_READ10        , "Read(10)"},
+    {SCSI_SBC2_READ12        , "Read(12)"},
+    {SCSI_SBC2_READ16        , "Read(16)"},
     {SCSI_SBC2_READCAPACITY  , "Read Capacity"},
-    {SCSI_SBC2_READDEFDATA10 , "Read Defect Data (10)"},
-    {SCSI_SBC2_READDEFDATA12 , "Read Defect Data (12)"},
+    {SCSI_SBC2_READDEFDATA10 , "Read Defect Data(10)"},
+    {SCSI_SBC2_READDEFDATA12 , "Read Defect Data(12)"},
     {SCSI_SBC2_READLONG, "Read Long"},
     {SCSI_SBC2_REASSIGNBLKS  , "Reassign Blocks"},
-    {SCSI_SBC2_REBUILD16, "Rebuild (16)"},
-    {SCSI_SBC2_REBUILD32, "Rebuild (32)"},
-    {SCSI_SBC2_REGENERATE16, "Regenerate (16)"},
-    {SCSI_SBC2_REGENERATE32, "Regenerate (32)"},
-    {SCSI_SBC2_SEEK10, "Seek (10)"},
-    {SCSI_SBC2_SETLIMITS10, "Set Limits (10)"},
-    {SCSI_SBC2_SETLIMITS12, "Set Limits (12)"},
+    {SCSI_SBC2_REBUILD16, "Rebuild(16)"},
+    {SCSI_SBC2_REBUILD32, "Rebuild(32)"},
+    {SCSI_SBC2_REGENERATE16, "Regenerate(16)"},
+    {SCSI_SBC2_REGENERATE32, "Regenerate(32)"},
+    {SCSI_SBC2_SEEK10, "Seek(10)"},
+    {SCSI_SBC2_SETLIMITS10, "Set Limits(10)"},
+    {SCSI_SBC2_SETLIMITS12, "Set Limits(12)"},
     {SCSI_SBC2_STARTSTOPUNIT, "Start Stop Unit"},
-    {SCSI_SBC2_SYNCCACHE10, "Synchronize Cache (10)"},
-    {SCSI_SBC2_SYNCCACHE16, "Synchronize Cache (16)"},
-    {SCSI_SBC2_VERIFY10, "Verify (10)"},
-    {SCSI_SBC2_VERIFY12, "Verify (12)"},
-    {SCSI_SBC2_VERIFY16, "Verify (16)"},
-    {SCSI_SBC2_WRITE6        , "Write (6)"},
-    {SCSI_SBC2_WRITE10       , "Write (10)"},
-    {SCSI_SBC2_WRITE12       , "Write (12)"},
-    {SCSI_SBC2_WRITE16       , "Write (16)"},
-    {SCSI_SBC2_WRITENVERIFY10, "Write & Verify (10)"},
-    {SCSI_SBC2_WRITENVERIFY12, "Write & Verify (12)"},
-    {SCSI_SBC2_WRITENVERIFY16, "Write & Verify (16)"},
+    {SCSI_SBC2_SYNCCACHE10, "Synchronize Cache(10)"},
+    {SCSI_SBC2_SYNCCACHE16, "Synchronize Cache(16)"},
+    {SCSI_SBC2_VERIFY10, "Verify(10)"},
+    {SCSI_SBC2_VERIFY12, "Verify(12)"},
+    {SCSI_SBC2_VERIFY16, "Verify(16)"},
+    {SCSI_SBC2_WRITE6        , "Write(6)"},
+    {SCSI_SBC2_WRITE10       , "Write(10)"},
+    {SCSI_SBC2_WRITE12       , "Write(12)"},
+    {SCSI_SBC2_WRITE16       , "Write(16)"},
+    {SCSI_SBC2_WRITENVERIFY10, "Write & Verify(10)"},
+    {SCSI_SBC2_WRITENVERIFY12, "Write & Verify(12)"},
+    {SCSI_SBC2_WRITENVERIFY16, "Write & Verify(16)"},
     {SCSI_SBC2_WRITELONG, "Write Long"},
-    {SCSI_SBC2_WRITESAME10, "Write Same (10)"},
-    {SCSI_SBC2_WRITESAME16, "Write Same (16)"},
-    {SCSI_SBC2_XDREAD10, "XdRead (10)"},
-    {SCSI_SBC2_XDREAD32, "XdRead (32)"},
-    {SCSI_SBC2_XDWRITE10, "XdWrite (10)"},
+    {SCSI_SBC2_WRITESAME10, "Write Same(10)"},
+    {SCSI_SBC2_WRITESAME16, "Write Same(16)"},
+    {SCSI_SBC2_XDREAD10, "XdRead(10)"},
+    {SCSI_SBC2_XDREAD32, "XdRead(32)"},
+    {SCSI_SBC2_XDWRITE10, "XdWrite(10)"},
     {SCSI_SBC2_XDWRITE32, "XdWrite(32)"},
-    {SCSI_SBC2_XDWRITEREAD10, "XdWriteRead (10)"},
-    {SCSI_SBC2_XDWRITEREAD32, "XdWriteRead (32)"},
-    {SCSI_SBC2_XDWRITEEXTD16, "XdWrite Extended (16)"},
-    {SCSI_SBC2_XDWRITEEXTD32, "XdWrite Extended (32)"},
-    {SCSI_SBC2_XPWRITE10, "XpWrite (10)"},
-    {SCSI_SBC2_XPWRITE32, "XpWrite (32)"},
+    {SCSI_SBC2_XDWRITEREAD10, "XdWriteRead(10)"},
+    {SCSI_SBC2_XDWRITEREAD32, "XdWriteRead(32)"},
+    {SCSI_SBC2_XDWRITEEXTD16, "XdWrite Extended(16)"},
+    {SCSI_SBC2_XDWRITEEXTD32, "XdWrite Extended(32)"},
+    {SCSI_SBC2_XPWRITE10, "XpWrite(10)"},
+    {SCSI_SBC2_XPWRITE32, "XpWrite(32)"},
     {0, NULL},
 };
 
@@ -330,12 +347,8 @@ static const value_string scsi_sbc2_val[] = {
 #define SCSI_SSC2_FORMAT_MEDIUM                 0x04
 #define SCSI_SSC2_LOAD_UNLOAD                   0x1B
 #define SCSI_SSC2_LOCATE_16                     0x92
-#define SCSI_SSC2_MOVE_MEDIUM                   0xA5
-#define SCSI_SSC2_MOVE_MEDIUM_ATTACHED          0xA7
 #define SCSI_SSC2_READ_16                       0x88
 #define SCSI_SSC2_READ_BLOCK_LIMITS             0x05
-#define SCSI_SSC2_READ_ELEMENT_STATUS           0xB8
-#define SCSI_SSC2_READ_ELEMENT_STATUS_ATTACHED  0xB4
 #define SCSI_SSC2_READ_POSITION                 0x34
 #define SCSI_SSC2_READ_REVERSE_16               0x81
 #define SCSI_SSC2_RECOVER_BUFFERED_DATA         0x14
@@ -349,11 +362,11 @@ static const value_string scsi_sbc2_val[] = {
 #define SCSI_SSC2_ERASE_6                       0x19
 #define SCSI_SSC2_LOCATE_10                     0x2B
 #define SCSI_SSC2_LOCATE_16                     0x92
-#define SCSI_SSC2_READ_6                        0x08
+#define SCSI_SSC2_READ                        0x08
 #define SCSI_SSC2_READ_REVERSE_6                0x0F
 #define SCSI_SSC2_SPACE_6                       0x11
 #define SCSI_SSC2_VERIFY_6                      0x13
-#define SCSI_SSC2_WRITE_6                       0x0A
+#define SCSI_SSC2_WRITE                       0x0A
 #define SCSI_SSC2_WRITE_FILEMARKS_6             0x10
 
 static const value_string scsi_ssc2_val[] = {
@@ -361,12 +374,8 @@ static const value_string scsi_ssc2_val[] = {
     {SCSI_SSC2_FORMAT_MEDIUM               , "Format Medium"},
     {SCSI_SSC2_LOAD_UNLOAD                 , "Load Unload"},
     {SCSI_SSC2_LOCATE_16                   , "Locate(16)"},
-    {SCSI_SSC2_MOVE_MEDIUM                 , "Move Medium"},
-    {SCSI_SSC2_MOVE_MEDIUM_ATTACHED        , "Move Medium Attached"},
     {SCSI_SSC2_READ_16                     , "Read(16)"},
     {SCSI_SSC2_READ_BLOCK_LIMITS           , "Read Block Limits"},
-    {SCSI_SSC2_READ_ELEMENT_STATUS         , "Read Element Status"},
-    {SCSI_SSC2_READ_ELEMENT_STATUS_ATTACHED, "Read Element Status Attached"},
     {SCSI_SSC2_READ_POSITION               , "Read Position"},
     {SCSI_SSC2_READ_REVERSE_16             , "Read Reverse(16)"},
     {SCSI_SSC2_RECOVER_BUFFERED_DATA       , "Recover Buffered Data"},
@@ -380,26 +389,65 @@ static const value_string scsi_ssc2_val[] = {
     {SCSI_SSC2_ERASE_6                     , "Erase(6)"},
     {SCSI_SSC2_LOCATE_10                   , "Locate(10)"},
     {SCSI_SSC2_LOCATE_16                   , "Locate(16)"},
-    {SCSI_SSC2_READ_6                      , "Read(6)"},
+    {SCSI_SSC2_READ                      , "Read(6)"},
     {SCSI_SSC2_READ_REVERSE_6              , "Read Reverse(6)"},
     {SCSI_SSC2_SPACE_6                     , "Space(6)"},
     {SCSI_SSC2_VERIFY_6                    , "Verify(6)"},
-    {SCSI_SSC2_WRITE_6                     , "Write(6)"},
+    {SCSI_SSC2_WRITE                     , "Write(6)"},
     {SCSI_SSC2_WRITE_FILEMARKS_6           , "Write Filemarks(6)"},
+    {0, NULL},
+};
+
+/* SMC2 Commands */
+#define SCSI_SMC2_EXCHANGE_MEDIUM                 0x40
+#define SCSI_SMC2_INITIALIZE_ELEMENT_STATUS       0x07
+#define SCSI_SMC2_INITIALIZE_ELEMENT_STATUS_RANGE 0x37
+#define SCSI_SMC2_MOVE_MEDIUM                     0xA5
+#define SCSI_SMC2_MOVE_MEDIUM_ATTACHED            0xA7
+#define SCSI_SMC2_POSITION_TO_ELEMENT             0x2B
+#define SCSI_SMC2_READ_ATTRIBUTE                  0x8C
+#define SCSI_SMC2_READ_ELEMENT_STATUS             0xB8
+#define SCSI_SMC2_READ_ELEMENT_STATUS_ATTACHED    0xB4
+#define SCSI_SMC2_REQUEST_VOLUME_ELEMENT_ADDRESS  0xB5
+#define SCSI_SMC2_SEND_VOLUME_TAG                 0xB6
+#define SCSI_SMC2_WRITE_ATTRIBUTE                 0x8D
+
+static const value_string scsi_smc2_val[] = {
+    {SCSI_SMC2_EXCHANGE_MEDIUM                , "Exchange Medium"},
+    {SCSI_SMC2_INITIALIZE_ELEMENT_STATUS      , "Initialize Element Status"},
+    {SCSI_SMC2_INITIALIZE_ELEMENT_STATUS_RANGE, "Initialize Element Status With Range"},
+    {SCSI_SMC2_MOVE_MEDIUM                    , "Move Medium"},
+    {SCSI_SMC2_MOVE_MEDIUM_ATTACHED           , "Move Medium Attached"},
+    {SCSI_SMC2_POSITION_TO_ELEMENT            , "Position To Element"},
+    {SCSI_SMC2_READ_ATTRIBUTE                 , "Read Attribute"},
+    {SCSI_SMC2_READ_ELEMENT_STATUS            , "Read Element Status"},
+    {SCSI_SMC2_READ_ELEMENT_STATUS_ATTACHED   , "Read Element Status Attached"},
+    {SCSI_SMC2_REQUEST_VOLUME_ELEMENT_ADDRESS , "Request Volume Element Address"},
+    {SCSI_SMC2_SEND_VOLUME_TAG                , "Send Volume Tag"},
+    {SCSI_SMC2_WRITE_ATTRIBUTE                , "Write Attribute"},
+    {0, NULL},
 };
 
+#define SCSI_EVPD_SUPPPG          0x00
+#define SCSI_EVPD_DEVSERNUM       0x80
+#define SCSI_EVPD_OPER            0x81
+#define SCSI_EVPD_ASCIIOPER       0x82
+#define SCSI_EVPD_DEVID           0x83
+
 static const value_string scsi_evpd_pagecode_val[] = {
-    {0x00, "Supported Vital Data Product Pages"},
-    {0x80, "Unit Serial Number Page"},
-    {0x82, "ASCII Implemented Operating Definition Page"},
-    {0x01, "ASCII Information Page"},
-    {0x02, "ASCII Information Page"},
-    {0x03, "ASCII Information Page"},
-    {0x04, "ASCII Information Page"},
-    {0x05, "ASCII Information Page"},
-    {0x06, "ASCII Information Page"},
-    {0x07, "ASCII Information Page"},
-    {0x83, "Device Identification Page"},
+    {SCSI_EVPD_SUPPPG,    "Supported Vital Product Data Pages"},
+    {0x01,                "ASCII Information Page"},
+    {0x02,                "ASCII Information Page"},
+    {0x03,                "ASCII Information Page"},
+    {0x04,                "ASCII Information Page"},
+    {0x05,                "ASCII Information Page"},
+    {0x06,                "ASCII Information Page"},
+    {0x07,                "ASCII Information Page"},
+    /* XXX - 0x01 through 0x7F are all ASCII information pages */
+    {SCSI_EVPD_DEVSERNUM, "Unit Serial Number Page"},
+    {SCSI_EVPD_OPER,      "Implemented Operating Definition Page"},
+    {SCSI_EVPD_ASCIIOPER, "ASCII Implemented Operating Definition Page"},
+    {SCSI_EVPD_DEVID,     "Device Identification Page"},
     {0, NULL},
 };
 
@@ -444,43 +492,79 @@ static const value_string scsi_modesns_pc_val[] = {
     {0, NULL},
 };
 
-#define SCSI_MODEPAGE_VEND          0x0
-#define SCSI_MODEPAGE_CTL           0x0A
-#define SCSI_MODEPAGE_DISCON        0x02
-#define SCSI_MODEPAGE_INFOEXCP      0x1C
-#define SCSI_MODEPAGE_PWR           0x1A
-#define SCSI_MODEPAGE_LUN           0x18
-#define SCSI_MODEPAGE_PORT          0x19
-#define SCSI_MODEPAGE_RDWRERR       0x01
-#define SCSI_MODEPAGE_FMTDEV        0x03
-#define SCSI_MODEPAGE_DISKGEOM      0x04
-#define SCSI_MODEPAGE_FLEXDISK      0x05
-#define SCSI_MODEPAGE_VERERR        0x07
-#define SCSI_MODEPAGE_CACHE         0x08
-#define SCSI_MODEPAGE_PERDEV        0x09
-#define SCSI_MODEPAGE_MEDTYPE       0x0B
-#define SCSI_MODEPAGE_NOTPART       0x0C
-#define SCSI_MODEPAGE_XORCTL        0x10
-
-static const value_string scsi_modesns_page_val[] = {
-    {0, "Vendor Specific Page"},
-    {0x0A, "Control"},
-    {0x02, "Disconnect-Reconnect"},
-    {0x1C, "Informational Exceptions Control"},
-    {0x1A, "Power Condition"},
-    {0x18, "Protocol Specific LUN"},
-    {0x19, "Protocol-Specific Port"},
-    {0x01, "Read/Write Error Recovery"},
-    {0x03, "Format Device"},
-    {0x04, "Rigid Disk Geometry"},
-    {0x05, "Flexible Disk"},
-    {0x07, "Verify Error Recovery"},
-    {0x08, "Caching"},
-    {0x09, "Peripheral Device"},
-    {0x0B, "Medium Types Supported"},
-    {0x0C, "Notch & Partition"},
-    {0x10, "XOR Control"},
-    {0x3F, "Return All Mode Pages"},
+#define SCSI_SPC2_MODEPAGE_CTL      0x0A
+#define SCSI_SPC2_MODEPAGE_DISCON   0x02
+#define SCSI_SCSI2_MODEPAGE_PERDEV  0x09  /* Obsolete in SPC-2; generic in SCSI-2 */
+#define SCSI_SPC2_MODEPAGE_INFOEXCP 0x1C
+#define SCSI_SPC2_MODEPAGE_PWR      0x1A
+#define SCSI_SPC2_MODEPAGE_LUN      0x18
+#define SCSI_SPC2_MODEPAGE_PORT     0x19
+#define SCSI_SPC2_MODEPAGE_VEND     0x00
+
+static const value_string scsi_spc2_modepage_val[] = {
+    {SCSI_SPC2_MODEPAGE_CTL,      "Control"},
+    {SCSI_SPC2_MODEPAGE_DISCON,   "Disconnect-Reconnect"},
+    {SCSI_SCSI2_MODEPAGE_PERDEV,  "Peripheral Device"},
+    {SCSI_SPC2_MODEPAGE_INFOEXCP, "Informational Exceptions Control"},
+    {SCSI_SPC2_MODEPAGE_PWR,      "Power Condition"},
+    {SCSI_SPC2_MODEPAGE_LUN,      "Protocol Specific LUN"},
+    {SCSI_SPC2_MODEPAGE_PORT,     "Protocol-Specific Port"},
+    {SCSI_SPC2_MODEPAGE_VEND,     "Vendor Specific Page"},
+    {0x3F,                        "Return All Mode Pages"},
+    {0, NULL},
+};
+
+#define SCSI_SBC2_MODEPAGE_RDWRERR  0x01
+#define SCSI_SBC2_MODEPAGE_FMTDEV   0x03
+#define SCSI_SBC2_MODEPAGE_DISKGEOM 0x04
+#define SCSI_SBC2_MODEPAGE_FLEXDISK 0x05
+#define SCSI_SBC2_MODEPAGE_VERERR   0x07
+#define SCSI_SBC2_MODEPAGE_CACHE    0x08
+#define SCSI_SBC2_MODEPAGE_MEDTYPE  0x0B
+#define SCSI_SBC2_MODEPAGE_NOTPART  0x0C
+#define SCSI_SBC2_MODEPAGE_XORCTL   0x10
+
+static const value_string scsi_sbc2_modepage_val[] = {
+    {SCSI_SBC2_MODEPAGE_RDWRERR,  "Read/Write Error Recovery"},
+    {SCSI_SBC2_MODEPAGE_FMTDEV,   "Format Device"},
+    {SCSI_SBC2_MODEPAGE_DISKGEOM, "Rigid Disk Geometry"},
+    {SCSI_SBC2_MODEPAGE_FLEXDISK, "Flexible Disk"},
+    {SCSI_SBC2_MODEPAGE_VERERR,   "Verify Error Recovery"},
+    {SCSI_SBC2_MODEPAGE_CACHE,    "Caching"},
+    {SCSI_SBC2_MODEPAGE_MEDTYPE,  "Medium Types Supported"},
+    {SCSI_SBC2_MODEPAGE_NOTPART,  "Notch & Partition"},
+    {SCSI_SBC2_MODEPAGE_XORCTL,   "XOR Control"},
+    {0x3F,                        "Return All Mode Pages"},
+    {0, NULL},
+};
+
+#define SCSI_SSC2_MODEPAGE_DATACOMP 0x0F  /* data compression */
+#define SCSI_SSC2_MODEPAGE_DEVCONF  0x10  /* device configuration */
+#define SCSI_SSC2_MODEPAGE_MEDPAR1  0x11  /* medium partition (1) */
+#define SCSI_SSC2_MODEPAGE_MEDPAR2  0x12  /* medium partition (2) */
+#define SCSI_SSC2_MODEPAGE_MEDPAR3  0x13  /* medium partition (3) */
+#define SCSI_SSC2_MODEPAGE_MEDPAR4  0x14  /* medium partition (4) */
+
+static const value_string scsi_ssc2_modepage_val[] = {
+    {SCSI_SSC2_MODEPAGE_DATACOMP, "Data Compression"},
+    {SCSI_SSC2_MODEPAGE_DEVCONF,  "Device Configuration"},
+    {SCSI_SSC2_MODEPAGE_MEDPAR1,  "Medium Partition (1)"},
+    {SCSI_SSC2_MODEPAGE_MEDPAR2,  "Medium Partition (2)"},
+    {SCSI_SSC2_MODEPAGE_MEDPAR3,  "Medium Partition (3)"},
+    {SCSI_SSC2_MODEPAGE_MEDPAR4,  "Medium Partition (4)"},
+    {0x3F,                        "Return All Mode Pages"},
+    {0, NULL},
+};
+
+#define SCSI_SMC2_MODEPAGE_EAA      0x1D  /* element address assignment */
+#define SCSI_SMC2_MODEPAGE_TRANGEOM 0x1E  /* transport geometry parameters */
+#define SCSI_SMC2_MODEPAGE_DEVCAP   0x1F  /* device capabilities */
+
+static const value_string scsi_smc2_modepage_val[] = {
+    {SCSI_SMC2_MODEPAGE_EAA,      "Element Address Assignment"},
+    {SCSI_SMC2_MODEPAGE_TRANGEOM, "Transport Geometry Parameters"},
+    {SCSI_SMC2_MODEPAGE_DEVCAP,   "Device Capabilities"},
+    {0x3F,                        "Return All Mode Pages"},
     {0, NULL},
 };
 
@@ -519,22 +603,11 @@ static const value_string scsi_persresv_type_val[] = {
     {0, NULL},
 };
 
-/* SCSI Device Types */
-#define SCSI_DEV_SBC       0x0
-#define SCSI_DEV_SSC       0x1
-#define SCSI_DEV_PRNT      0x2
-#define SCSI_DEV_PROC      0x3
-#define SCSI_DEV_WORM      0x4
-#define SCSI_DEV_CDROM     0x5
-#define SCSI_DEV_SCAN      0x6
-#define SCSI_DEV_OPTMEM    0x7
-#define SCSI_DEV_SMC       0x8
-#define SCSI_DEV_COMM      0x9
-#define SCSI_DEV_RAID      0xC
-#define SCSI_DEV_SES       0xD
-#define SCSI_DEV_RBC       0xE
-#define SCSI_DEV_OCRW      0xF
-#define SCSI_DEV_OSD       0x11
+static const value_string scsi_qualifier_val[] = {
+    {0x0, "Device type is connected to logical unit"},
+    {0x1, "Device type is supported by server but is not connected to logical unit"},
+    {0x3, "Device type is not supported by server"},
+};
 
 static const value_string scsi_devtype_val[] = {
     {SCSI_DEV_SBC   , "Direct Access Device"},
@@ -542,7 +615,7 @@ static const value_string scsi_devtype_val[] = {
     {SCSI_DEV_PRNT  , "Printer"},
     {SCSI_DEV_PROC  , "Processor"},
     {SCSI_DEV_WORM  , "WORM"},
-    {SCSI_DEV_CDROM , "CD ROM"},
+    {SCSI_DEV_CDROM , "CD-ROM"},
     {SCSI_DEV_SCAN  , "Scanner"},
     {SCSI_DEV_OPTMEM, "Optical Memory"},
     {SCSI_DEV_SMC   , "Medium Changer"},
@@ -550,8 +623,11 @@ static const value_string scsi_devtype_val[] = {
     {SCSI_DEV_RAID  , "Storage Array"},
     {SCSI_DEV_SES   , "Enclosure Services"},
     {SCSI_DEV_RBC   , "Simplified Block Device"},
-    {SCSI_DEV_OCRW  , "OCRW"},
-    {SCSI_DEV_OSD   , "OSD"},
+    {SCSI_DEV_OCRW  , "Optical Card Reader/Writer"},
+    {SCSI_DEV_OSD   , "Object-based Storage Device"},
+    {SCSI_DEV_ADC   , "Automation/Drive Interface"},
+    {0x1E           , "Well known logical unit"},
+    {SCSI_DEV_NOLUN , "Unknown or no device type"},
     {0, NULL},
 };
 
@@ -573,10 +649,21 @@ static const value_string scsi_inquiry_vers_val[] = {
     {0, NULL},
 };
 
-static const value_string scsi_modesense_medtype_val[] = {
-    {0, "Default"},
-    {1, "Flexible Disk, Single-sided"},
-    {2, "Flexible Disk, Double-sided"},
+static const value_string scsi_modesense_medtype_sbc_val[] = {
+    {0x00, "Default"},
+    {0x01, "Flexible disk, single-sided; unspecified medium"},
+    {0x02, "Flexible disk, double-sided; unspecified medium"},
+    {0x05, "Flexible disk, single-sided, single density; 200mm/8in diameter"},
+    {0x06, "Flexible disk, double-sided, single density; 200mm/8in diameter"},
+    {0x09, "Flexible disk, single-sided, double density; 200mm/8in diameter"},
+    {0x0A, "Flexible disk, double-sided, double density; 200mm/8in diameter"},
+    {0x0D, "Flexible disk, single-sided, single density; 130mm/5.25in diameter"},
+    {0x12, "Flexible disk, double-sided, single density; 130mm/5.25in diameter"},
+    {0x16, "Flexible disk, single-sided, double density; 130mm/5.25in diameter"},
+    {0x1A, "Flexible disk, double-sided, double density; 130mm/5.25in diameter"},
+    {0x1E, "Flexible disk, double-sided; 90mm/3.5in diameter"},
+    {0x40, "Direct-access magnetic tape, 12 tracks"},
+    {0x44, "Direct-access magnetic tape, 24 tracks"},
     {0, NULL},
 };
 
@@ -626,19 +713,6 @@ static const value_string scsi_verdesc_val[] = {
     {0, NULL},
 };
 
-#define SCSI_EVPD_SUPPPG          0
-#define SCSI_EVPD_ASCIIOPER       0x82
-#define SCSI_EVPD_DEVID           0x83
-#define SCSI_EVPD_DEVSERNUM       0x80
-
-static const value_string scsi_inq_evpd_val[] = {
-    {SCSI_EVPD_SUPPPG, "Supported Vital Product Data Page"},
-    {SCSI_EVPD_ASCIIOPER, "ASCII Implemented Operating Definition Page"},
-    {SCSI_EVPD_DEVID, "Device ID Page"},
-    {SCSI_EVPD_DEVSERNUM, "Unit Serial Number Page"},
-    {0x0, NULL},
-};
-
 /* Command Support Data "Support" field definitions */
 static const value_string scsi_cmdt_supp_val[] = {
     {0, "Data not currently available"},
@@ -652,11 +726,14 @@ static const value_string scsi_cmdt_supp_val[] = {
     {0, NULL},
 };
 
+#define CODESET_BINARY 1
+#define CODESET_ASCII  2
+
 static const value_string scsi_devid_codeset_val[] = {
-    {0, "Reserved"},
-    {1, "Identifier field contains binary values"},
-    {2, "Identifier field contains ASCII graphic codes"},
-    {0, NULL},
+    {0,              "Reserved"},
+    {CODESET_BINARY, "Identifier field contains binary values"},
+    {CODESET_ASCII,  "Identifier field contains ASCII graphic codes"},
+    {0,              NULL},
 };
 
 static const value_string scsi_devid_assoc_val[] = {
@@ -1091,14 +1168,38 @@ static gint scsi_def_devtype = SCSI_DEV_SBC;
  * We track SCSI requests and responses with a hash table.
  * The key is a "scsi_task_id_t" structure; the data is a
  * "scsi_task_data_t" structure.
+ *
+ * We remember:
+ *
+ *    the command code and type of command (it's not present in the
+ *        response, and we need it to dissect the response);
+ *    the type of device it's on;
+ *
+ * and we also have a field to record flags in case the interpretation
+ * of the response data depends on data from the command.
  */
 typedef struct _scsi_task_data {
     guint32 opcode;
+    scsi_cmnd_type cmd;
     scsi_device_type devtype;
-    guint8 flags;               /* used by SCSI Inquiry */
+    guint8 flags;
 } scsi_task_data_t;
 
-/* The next two data structures are used to track SCSI device type */
+/*
+ * The next two data structures are used to track SCSI device type.
+ *
+ * XXX - it might not be sufficient to use the address of the server
+ * to which SCSI CDBs are being sent to identify the device, as
+ *
+ *     1) a server might have multiple targets or logical units;
+ *
+ *     2) a server might make a different logical unit refer to
+ *        different devices for different clients;
+ *
+ * so we should really base this on the connection index for the
+ * connection and on a device identifier supplied to us by our caller,
+ * not on a network-layer address.
+ */
 typedef struct _scsi_devtype_key {
     address devid;
 } scsi_devtype_key_t;
@@ -1125,8 +1226,8 @@ static dissector_handle_t data_handle;
 static gint
 scsi_equal(gconstpointer v, gconstpointer w)
 {
-  scsi_task_id_t *v1 = (scsi_task_id_t *)v;
-  scsi_task_id_t *v2 = (scsi_task_id_t *)w;
+  const scsi_task_id_t *v1 = (const scsi_task_id_t *)v;
+  const scsi_task_id_t *v2 = (const scsi_task_id_t *)w;
 
   return (v1->conv_id == v2->conv_id && v1->task_id == v2->task_id);
 }
@@ -1134,7 +1235,7 @@ scsi_equal(gconstpointer v, gconstpointer w)
 static guint
 scsi_hash (gconstpointer v)
 {
-       scsi_task_id_t *key = (scsi_task_id_t *)v;
+       const scsi_task_id_t *key = (const scsi_task_id_t *)v;
        guint val;
 
        val = key->conv_id + key->task_id;
@@ -1145,8 +1246,8 @@ scsi_hash (gconstpointer v)
 static gint
 scsidev_equal (gconstpointer v, gconstpointer w)
 {
-    scsi_devtype_key_t *k1 = (scsi_devtype_key_t *)v;
-    scsi_devtype_key_t *k2 = (scsi_devtype_key_t *)w;
+    const scsi_devtype_key_t *k1 = (const scsi_devtype_key_t *)v;
+    const scsi_devtype_key_t *k2 = (const scsi_devtype_key_t *)w;
 
     if (ADDRESSES_EQUAL (&k1->devid, &k2->devid))
         return 1;
@@ -1157,7 +1258,7 @@ scsidev_equal (gconstpointer v, gconstpointer w)
 static guint
 scsidev_hash (gconstpointer v)
 {
-    scsi_devtype_key_t *key = (scsi_devtype_key_t *)v;
+    const scsi_devtype_key_t *key = (const scsi_devtype_key_t *)v;
     guint val;
     int i;
 
@@ -1174,7 +1275,7 @@ scsi_new_task (packet_info *pinfo)
 {
     scsi_task_data_t *cdata = NULL;
     scsi_task_id_t ckey, *req_key;
-    
+
     if ((pinfo != NULL) && (pinfo->private_data)) {
         ckey = *(scsi_task_id_t *)pinfo->private_data;
 
@@ -1183,9 +1284,9 @@ scsi_new_task (packet_info *pinfo)
         if (!cdata) {
             req_key = g_mem_chunk_alloc (scsi_req_keys);
             *req_key = *(scsi_task_id_t *)pinfo->private_data;
-            
+
             cdata = g_mem_chunk_alloc (scsi_req_vals);
-            
+
             g_hash_table_insert (scsi_req_hash, req_key, cdata);
         }
     }
@@ -1227,9 +1328,32 @@ scsi_end_task (packet_info *pinfo)
 /*
  * Protocol initialization
  */
+static void
+free_devtype_key_dev_info(gpointer key_arg, gpointer value_arg _U_,
+    gpointer user_data _U_)
+{
+       scsi_devtype_key_t *key = key_arg;
+
+       if (key->devid.data != NULL) {
+               g_free((gpointer)key->devid.data);
+               key->devid.data = NULL;
+       }
+}
+
 static void
 scsi_init_protocol(void)
 {
+       /*
+        * First, free up the data for the addresses attached to
+        * scsi_devtype_key_t structures.  Do so before we free
+        * those structures or destroy the hash table in which
+        * they're stored.
+        */
+       if (scsidev_req_hash != NULL) {
+               g_hash_table_foreach(scsidev_req_hash, free_devtype_key_dev_info,
+                   NULL);
+       }
+
        if (scsi_req_keys)
             g_mem_chunk_destroy(scsi_req_keys);
        if (scsi_req_vals)
@@ -1274,7 +1398,7 @@ dissect_scsi_evpd (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
     proto_tree *evpd_tree;
     proto_item *ti;
     guint pcode, plen, i, idlen;
-    guint8 flags;
+    guint8 codeset, flags;
     char str[256+1];
 
     if (tree) {
@@ -1284,10 +1408,9 @@ dissect_scsi_evpd (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                                   val_to_str (pcode, scsi_evpd_pagecode_val,
                                               "Unknown (0x%08x)"));
         evpd_tree = proto_item_add_subtree (ti, ett_scsi_page);
-        
-        proto_tree_add_text (evpd_tree, tvb, offset, 1,
-                             "Peripheral Qualifier: 0x%x",
-                             (tvb_get_guint8 (tvb, offset) & 0xF0)>>4);
+
+        proto_tree_add_item (evpd_tree, hf_scsi_inq_qualifier, tvb, offset,
+                             1, 0);
         proto_tree_add_item (evpd_tree, hf_scsi_inq_devtype, tvb, offset,
                              1, 0);
         proto_tree_add_text (evpd_tree, tvb, offset+1, 1,
@@ -1308,40 +1431,88 @@ dissect_scsi_evpd (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
             }
             break;
         case SCSI_EVPD_DEVID:
-            while (plen > 0) {
-                flags = tvb_get_guint8 (tvb, offset);
+            while (plen != 0) {
+                codeset = tvb_get_guint8 (tvb, offset) & 0x0F;
                 proto_tree_add_text (evpd_tree, tvb, offset, 1,
                                      "Code Set: %s",
-                                     val_to_str (plen & 0x0F,
+                                     val_to_str (codeset,
                                                  scsi_devid_codeset_val,
                                                  "Unknown (0x%02x)"));
-                flags = tvb_get_guint8 (tvb, offset+1);
-                proto_tree_add_text (evpd_tree, tvb, offset+1, 1,
+                plen -= 1;
+                offset += 1;
+
+                if (plen < 1) {
+                    proto_tree_add_text (evpd_tree, tvb, offset, 0,
+                                         "Product data goes past end of page");
+                    break;
+                }
+                flags = tvb_get_guint8 (tvb, offset);
+                proto_tree_add_text (evpd_tree, tvb, offset, 1,
                                      "Association: %s",
                                      val_to_str ((flags & 0x30) >> 4,
                                                  scsi_devid_assoc_val,
                                                  "Unknown (0x%02x)"));
-                proto_tree_add_text (evpd_tree, tvb, offset+1, 1,
-                                     "Identifier Type: %s", 
+                proto_tree_add_text (evpd_tree, tvb, offset, 1,
+                                     "Identifier Type: %s",
                                      val_to_str ((flags & 0x0F),
-                                                 scsi_devid_idtype_val, 
+                                                 scsi_devid_idtype_val,
                                                  "Unknown (0x%02x)"));
-                idlen = tvb_get_guint8 (tvb, offset+3);
-                proto_tree_add_text (evpd_tree, tvb, offset+3, 1,
+                plen -= 1;
+                offset += 1;
+
+                /* Skip reserved byte */
+                if (plen < 1) {
+                    proto_tree_add_text (evpd_tree, tvb, offset, 0,
+                                         "Product data goes past end of page");
+                    break;
+                }
+                plen -= 1;
+                offset += 1;
+
+                if (plen < 1) {
+                    proto_tree_add_text (evpd_tree, tvb, offset, 0,
+                                         "Product data goes past end of page");
+                    break;
+                }
+                idlen = tvb_get_guint8 (tvb, offset);
+                proto_tree_add_text (evpd_tree, tvb, offset, 1,
                                      "Identifier Length: %u", idlen);
-                proto_tree_add_text (evpd_tree, tvb, offset+4, idlen,
-                                         "Identifier: %s",
-                                         tvb_bytes_to_str (tvb, offset+4,
-                                                           idlen));
-                plen -= idlen;
-                offset += idlen;
+                plen -= 1;
+                offset += 1;
+
+                if (idlen != 0) {
+                    if (plen < idlen) {
+                        proto_tree_add_text (evpd_tree, tvb, offset, 0,
+                                             "Product data goes past end of page");
+                        break;
+                    }
+                    if (codeset == CODESET_ASCII) {
+                        proto_tree_add_text (evpd_tree, tvb, offset, idlen,
+                                             "Identifier: %s",
+                                             tvb_format_text (tvb, offset,
+                                                              idlen));
+                    } else {
+                        /*
+                         * XXX - decode this based on the identifier type,
+                         * if the codeset is CODESET_BINARY?
+                         */
+                        proto_tree_add_text (evpd_tree, tvb, offset, idlen,
+                                             "Identifier: %s",
+                                             tvb_bytes_to_str (tvb, offset,
+                                                               idlen));
+                    }
+                    plen -= idlen;
+                    offset += idlen;
+                }
             }
             break;
         case SCSI_EVPD_DEVSERNUM:
-            str[0] = '\0';
-            tvb_get_nstringz0 (tvb, offset, MIN(plen, sizeof(str) - 1), str);
-            proto_tree_add_text (evpd_tree, tvb, offset, plen,
-                                 "Product Serial Number: %s", str);
+            if (plen > 0) {
+                tvb_memcpy (tvb, str, offset, MIN(plen, sizeof(str) - 1));
+                str[sizeof(str) - 1] = '\0';
+                proto_tree_add_text (evpd_tree, tvb, offset, plen,
+                                     "Product Serial Number: %s", str);
+            }
             break;
         }
     }
@@ -1360,9 +1531,8 @@ dissect_scsi_cmddt (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
         ti = proto_tree_add_text (tree, tvb, offset, plen, "Command Data");
         cmdt_tree = proto_item_add_subtree (ti, ett_scsi_page);
 
-        proto_tree_add_text (cmdt_tree, tvb, offset, 1,
-                             "Peripheral Qualifier: 0x%x",
-                             (tvb_get_guint8 (tvb, offset) & 0xF0)>>4);
+        proto_tree_add_item (cmdt_tree, hf_scsi_inq_qualifier, tvb, offset,
+                             1, 0);
         proto_tree_add_item (cmdt_tree, hf_scsi_inq_devtype, tvb, offset,
                              1, 0);
         proto_tree_add_text (cmdt_tree, tvb, offset+1, 1, "Support: %s",
@@ -1382,35 +1552,56 @@ dissect_scsi_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                       guint offset, gboolean isreq, gboolean iscdb,
                       guint32 payload_len, scsi_task_data_t *cdata)
 {
-    guint8 flags, i;
+    guint8 flags, i, devtype;
     gchar str[32];
     guint tot_len;
     scsi_devtype_data_t *devdata = NULL;
     scsi_devtype_key_t dkey, *req_key;
 
-    /* Add device type to list of known devices & their types */
-    COPY_ADDRESS (&(dkey.devid), &(pinfo->src));
-    devdata = (scsi_devtype_data_t *)g_hash_table_lookup (scsidev_req_hash,
-                                                          &dkey);
-    if (!devdata) {
-        req_key = g_mem_chunk_alloc (scsidev_req_keys);
-        COPY_ADDRESS (&(req_key->devid), &(pinfo->src));
-        
-        devdata = g_mem_chunk_alloc (scsidev_req_vals);
-        devdata->devtype = tvb_get_guint8 (tvb, offset) & 0x10;
-        
-        g_hash_table_insert (scsidev_req_hash, req_key, devdata);
+    if (!isreq && (cdata == NULL || !(cdata->flags & 0x3))) {
+        /*
+         * INQUIRY response with device type information; add device type
+         * to list of known devices & their types if not already known.
+         *
+         * We don't use COPY_ADDRESS because "dkey.devid" isn't
+         * persistent, and therefore it can point to the stuff
+         * in "pinfo->src".  (Were we to use COPY_ADDRESS, we'd
+         * have to free the address data it allocated before we return.)
+         */
+        dkey.devid = pinfo->src;
+        devdata = (scsi_devtype_data_t *)g_hash_table_lookup (scsidev_req_hash,
+                                                              &dkey);
+        if (!devdata) {
+            req_key = g_mem_chunk_alloc (scsidev_req_keys);
+            COPY_ADDRESS (&(req_key->devid), &(pinfo->src));
+
+            devdata = g_mem_chunk_alloc (scsidev_req_vals);
+            devdata->devtype = tvb_get_guint8 (tvb, offset) & SCSI_DEV_BITS;
+
+            g_hash_table_insert (scsidev_req_hash, req_key, devdata);
+       }
+        else {
+            devtype = tvb_get_guint8 (tvb, offset);
+            if ((devtype & SCSI_DEV_BITS) != SCSI_DEV_NOLUN) {
+                /* Some initiators probe more than the available LUNs which
+                 * results in Inquiry data being returned indicating that a LUN
+                 * is not supported. We don't want to overwrite the device type
+                 * with such responses.
+                 */
+                devdata->devtype = (devtype & SCSI_DEV_BITS);
+            }
+        }
     }
-        
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
         if (cdata != NULL) {
             cdata->flags = flags;
         }
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_inquiry_flags, tvb, offset, 1,
                                     flags, "CMDT = %u, EVPD = %u",
                                     flags & 0x2, flags & 0x1);
@@ -1423,7 +1614,7 @@ dissect_scsi_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                  1, 0);
         }
 
-        proto_tree_add_uint (tree, hf_scsi_alloclen, tvb, offset+3, 1, 0);
+        proto_tree_add_item (tree, hf_scsi_alloclen, tvb, offset+3, 1, 0);
         flags = tvb_get_guint8 (tvb, offset+4);
         proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
                                     flags,
@@ -1440,8 +1631,8 @@ dissect_scsi_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
             return;
         }
 
-        proto_tree_add_text (tree, tvb, offset, 1, "Peripheral Qualifier: 0x%x",
-                             (tvb_get_guint8 (tvb, offset) & 0xF0)>>4);
+        proto_tree_add_item (tree, hf_scsi_inq_qualifier, tvb, offset,
+                             1, 0);
         proto_tree_add_item (tree, hf_scsi_inq_devtype, tvb, offset, 1, 0);
         proto_tree_add_item (tree, hf_scsi_inq_version, tvb, offset+2, 1, 0);
 
@@ -1463,14 +1654,17 @@ dissect_scsi_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                              "RelAdr: %u, Linked: %u, CmdQue: %u",
                              (flags & 0x80) >> 7, (flags & 0x08) >> 3,
                              (flags & 0x02) >> 1);
-        tvb_get_nstringz0 (tvb, offset+8, 8, str);
+        tvb_memcpy (tvb, str, offset+8, 8);
+        str[8] = '\0';
         proto_tree_add_text (tree, tvb, offset+8, 8, "Vendor Id: %s", str);
-        tvb_get_nstringz0 (tvb, offset+16, 16, str);
+        tvb_memcpy (tvb, str, offset+16, 16);
+        str[16] = '\0';
         proto_tree_add_text (tree, tvb, offset+16, 16, "Product ID: %s", str);
-        tvb_get_nstringz0 (tvb, offset+32, 4, str);
+        tvb_memcpy (tvb, str, offset+32, 4);
+        str[4] = '\0';
         proto_tree_add_text (tree, tvb, offset+32, 4, "Product Revision: %s",
                              str);
-        
+
         offset += 58;
         if ((tot_len > 58) && tvb_bytes_exist (tvb, offset, 16)) {
             for (i = 0; i < 8; i++) {
@@ -1487,11 +1681,11 @@ dissect_scsi_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 }
 
 static void
-dissect_scsi_extcopy (tvbuff_t *tvb _U_, packet_info *pinfo _U_, 
-                     proto_tree *tree _U_, guint offset _U_, 
+dissect_scsi_extcopy (tvbuff_t *tvb _U_, packet_info *pinfo _U_,
+                     proto_tree *tree _U_, guint offset _U_,
                      gboolean isreq _U_, gboolean iscdb _U_)
 {
-    
+
 }
 
 static void
@@ -1499,17 +1693,17 @@ dissect_scsi_logselect (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                         guint offset, gboolean isreq, gboolean iscdb)
 {
     guint8 flags;
-    
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_logsel_flags, tvb, offset, 1,
                                     flags, "PCR = %u, SP = %u", flags & 0x2,
                                     flags & 0x1);
-        proto_tree_add_uint_format (tree, hf_scsi_log_pc, tvb, offset+1, 1,
+        proto_tree_add_uint_format (tree, hf_scsi_logsel_pc, tvb, offset+1, 1,
                                     tvb_get_guint8 (tvb, offset+1),
                                     "PC: 0x%x", flags & 0xC0);
         proto_tree_add_item (tree, hf_scsi_paramlen16, tvb, offset+6, 2, 0);
@@ -1529,17 +1723,17 @@ dissect_scsi_logsense (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                        guint offset, gboolean isreq, gboolean iscdb)
 {
     guint8 flags;
-    
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_logsns_flags, tvb, offset, 1,
                                     flags, "PPC = %u, SP = %u", flags & 0x2,
                                     flags & 0x1);
-        proto_tree_add_uint_format (tree, hf_scsi_log_pc, tvb, offset+1, 1,
+        proto_tree_add_uint_format (tree, hf_scsi_logsns_pc, tvb, offset+1, 1,
                                     tvb_get_guint8 (tvb, offset+1),
                                     "PC: 0x%x", flags & 0xC0);
         proto_tree_add_item (tree, hf_scsi_logsns_pagecode, tvb, offset+1,
@@ -1558,34 +1752,157 @@ dissect_scsi_logsense (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
     }
 }
 
-static guint8
-dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_, 
-                      proto_tree *scsi_tree, guint offset)
+static gboolean
+dissect_scsi_blockdescs (tvbuff_t *tvb, packet_info *pinfo _U_,
+                        proto_tree *scsi_tree, guint offset,
+                        guint payload_len, guint desclen,
+                        scsi_device_type devtype, gboolean longlba)
 {
-    guint8 pcode, plen, flags, proto;
-    proto_tree *tree;
-    proto_item *ti;
+    while (desclen != 0) {
+        if (longlba) {
+            if (payload_len < 8)
+                return FALSE;
+            if (desclen < 8) {
+                offset += desclen;
+                payload_len -= desclen;
+                break;
+            }
+            proto_tree_add_text (scsi_tree, tvb, offset, 8, "No. of Blocks: %s",
+                                 u64toa (tvb_get_ptr (tvb, offset, 8)));
+            offset += 8;
+            payload_len -= 8;
+            desclen -= 8;
 
-    pcode = tvb_get_guint8 (tvb, offset);
-    plen = tvb_get_guint8 (tvb, offset+1);
+            if (payload_len < 1)
+                return FALSE;
+            if (desclen < 1)
+                break;
+            proto_tree_add_text (scsi_tree, tvb, offset, 1, "Density Code: 0x%02x",
+                                 tvb_get_guint8 (tvb, offset));
+            offset += 1;
+            payload_len -= 1;
+            desclen -= 1;
+
+            if (payload_len < 3)
+                return FALSE;
+            if (desclen < 3) {
+                offset += desclen;
+                payload_len -= desclen;
+                break;
+            }
+            /* 3 reserved bytes */
+            offset += 3;
+            payload_len -= 3;
+            desclen -= 3;
+
+            if (payload_len < 4)
+                return FALSE;
+            if (desclen < 4) {
+                offset += desclen;
+                payload_len -= desclen;
+                break;
+            }
+            proto_tree_add_text (scsi_tree, tvb, offset, 4, "Block Length: %u",
+                                     tvb_get_ntohl (tvb, offset));
+            offset += 4;
+            payload_len -= 4;
+            desclen -= 4;
+        } else {
+            if (devtype == SCSI_DEV_SBC) {
+                if (payload_len < 4)
+                    return FALSE;
+                if (desclen < 4) {
+                    offset += desclen;
+                    payload_len -= desclen;
+                    break;
+                }
+                proto_tree_add_text (scsi_tree, tvb, offset, 4, "No. of Blocks: %u",
+                                     tvb_get_ntohl (tvb, offset));
+                offset += 4;
+                payload_len -= 4;
+                desclen -= 4;
+
+                if (payload_len < 1)
+                    return FALSE;
+                if (desclen < 1)
+                    break;
+                proto_tree_add_text (scsi_tree, tvb, offset, 1, "Density Code: 0x%02x",
+                                     tvb_get_guint8 (tvb, offset));
+                offset += 1;
+                payload_len -= 1;
+                desclen -= 1;
+
+                if (payload_len < 3)
+                    return FALSE;
+                if (desclen < 3) {
+                    offset += desclen;
+                    payload_len -= desclen;
+                    break;
+                }
+                proto_tree_add_text (scsi_tree, tvb, offset, 3, "Block Length: %u",
+                                         tvb_get_ntoh24 (tvb, offset));
+                offset += 3;
+                payload_len -= 3;
+                desclen -= 3;
+            } else {
+                if (payload_len < 1)
+                    return FALSE;
+                if (desclen < 1)
+                    break;
+                proto_tree_add_text (scsi_tree, tvb, offset, 1, "Density Code: 0x%02x",
+                                     tvb_get_guint8 (tvb, offset));
+                offset += 1;
+                payload_len -= 1;
+                desclen -= 1;
+
+                if (payload_len < 3)
+                    return FALSE;
+                if (desclen < 3) {
+                    offset += desclen;
+                    payload_len -= desclen;
+                    break;
+                }
+                proto_tree_add_text (scsi_tree, tvb, offset, 3, "No. of Blocks: %u",
+                                     tvb_get_ntoh24 (tvb, offset));
+                offset += 3;
+                payload_len -= 3;
+                desclen -= 3;
+
+                if (payload_len < 1)
+                    return FALSE;
+                if (desclen < 1)
+                    break;
+                /* Reserved byte */
+                offset += 1;
+                payload_len -= 1;
+                desclen -= 1;
+
+                if (payload_len < 3)
+                    return FALSE;
+                if (desclen < 3) {
+                    offset += desclen;
+                    payload_len -= desclen;
+                    break;
+                }
+                proto_tree_add_text (scsi_tree, tvb, offset, 3, "Block Length: %u",
+                                         tvb_get_ntoh24 (tvb, offset));
+                offset += 3;
+                payload_len -= 3;
+                desclen -= 3;
+            }
+        }
+    }
+    return TRUE;
+}
 
-    ti = proto_tree_add_text (scsi_tree, tvb, offset, plen+2, "%s Mode Page",
-                              val_to_str (pcode & 0x3F, scsi_modesns_page_val,
-                                          "Unknown (0x%08x)"));
-    tree = proto_item_add_subtree (ti, ett_scsi_page);
-    proto_tree_add_text (tree, tvb, offset, 1, "PS: %u", (pcode & 0x80) >> 8);
-                         
-    proto_tree_add_item (tree, hf_scsi_modesns_pagecode, tvb, offset, 1, 0);
-    proto_tree_add_text (tree, tvb, offset+1, 1, "Page Length: %u",
-                         plen);
+static gboolean
+dissect_scsi_spc2_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
+                           proto_tree *tree, guint offset, guint8 pcode)
+{
+    guint8 flags, proto;
 
-    if (!tvb_bytes_exist (tvb, offset, plen)) {
-        return (plen + 2);
-    }
-    
-    pcode &= 0x3F;
     switch (pcode) {
-    case SCSI_MODEPAGE_CTL:
+    case SCSI_SPC2_MODEPAGE_CTL:
         flags = tvb_get_guint8 (tvb, offset+2);
         proto_tree_add_item (tree, hf_scsi_modesns_tst, tvb, offset+2, 1, 0);
         proto_tree_add_text (tree, tvb, offset+2, 1,
@@ -1615,7 +1932,7 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "Extended Self-Test Completion Time: %u",
                              tvb_get_ntohs (tvb, offset+10));
         break;
-    case SCSI_MODEPAGE_DISCON:
+    case SCSI_SPC2_MODEPAGE_DISCON:
         proto_tree_add_text (tree, tvb, offset+2, 1, "Buffer Full Ratio: %u",
                              tvb_get_guint8 (tvb, offset+2));
         proto_tree_add_text (tree, tvb, offset+3, 1, "Buffer Empty Ratio: %u",
@@ -1638,7 +1955,7 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "First Burst Size: %u bytes",
                              tvb_get_ntohs (tvb, offset+14)*512);
         break;
-    case SCSI_MODEPAGE_INFOEXCP:
+    case SCSI_SPC2_MODEPAGE_INFOEXCP:
         flags = tvb_get_guint8 (tvb, offset+2);
         proto_tree_add_text (tree, tvb, offset+2, 1,
                              "Perf: %u, EBF: %u, EWasc: %u, DExcpt: %u, Test: %u, LogErr: %u",
@@ -1657,7 +1974,7 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
         proto_tree_add_text (tree, tvb, offset+8, 4, "Report Count: %u",
                              tvb_get_ntohl (tvb, offset+8));
         break;
-    case SCSI_MODEPAGE_PWR:
+    case SCSI_SPC2_MODEPAGE_PWR:
         flags = tvb_get_guint8 (tvb, offset+3);
         proto_tree_add_text (tree, tvb, offset+3, 1, "Idle: %u, Standby: %u",
                              (flags & 0x2) >> 1, (flags & 0x1));
@@ -1668,9 +1985,9 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "Standby Condition Timer: %u ms",
                              tvb_get_ntohs (tvb, offset+6) * 100);
         break;
-    case SCSI_MODEPAGE_LUN:
-        break;
-    case SCSI_MODEPAGE_PORT:
+    case SCSI_SPC2_MODEPAGE_LUN:
+        return FALSE;
+    case SCSI_SPC2_MODEPAGE_PORT:
         proto = tvb_get_guint8 (tvb, offset+2) & 0x0F;
         proto_tree_add_item (tree, hf_scsi_protocol, tvb, offset+2, 1, 0);
         if (proto == SCSI_PROTO_FCP) {
@@ -1689,11 +2006,28 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                                  tvb_get_guint8 (tvb, offset+7));
         }
         else if (proto == SCSI_PROTO_iSCSI) {
+            return FALSE;
         }
         else {
+            return FALSE;
         }
         break;
-    case SCSI_MODEPAGE_FMTDEV:
+    case SCSI_SCSI2_MODEPAGE_PERDEV:
+        return FALSE;
+    default:
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static gboolean
+dissect_scsi_sbc2_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
+                           proto_tree *tree, guint offset, guint8 pcode)
+{
+    guint8 flags;
+
+    switch (pcode) {
+    case SCSI_SBC2_MODEPAGE_FMTDEV:
         proto_tree_add_text (tree, tvb, offset+2, 2, "Tracks Per Zone: %u",
                              tvb_get_ntohs (tvb, offset+2));
         proto_tree_add_text (tree, tvb, offset+4, 2,
@@ -1723,7 +2057,7 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              (flags & 0x80) >> 7, (flags & 0x40) >> 6,
                              (flags & 0x20) >> 5, (flags & 0x10) >> 4);
         break;
-    case SCSI_MODEPAGE_RDWRERR:
+    case SCSI_SBC2_MODEPAGE_RDWRERR:
         flags = tvb_get_guint8 (tvb, offset+2);
         proto_tree_add_text (tree, tvb, offset+2, 1,
                              "AWRE: %u, ARRE: %u, TB: %u, RC: %u, EER: %u, PER: %u, DTE: %u, DCR: %u",
@@ -1746,7 +2080,7 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "Recovery Time Limit: %u ms",
                              tvb_get_ntohs (tvb, offset+10));
         break;
-    case SCSI_MODEPAGE_DISKGEOM:
+   case SCSI_SBC2_MODEPAGE_DISKGEOM:
         proto_tree_add_text (tree, tvb, offset+2, 3, "Number of Cylinders: %u",
                              tvb_get_ntoh24 (tvb, offset+2));
         proto_tree_add_text (tree, tvb, offset+5, 1, "Number of Heads: %u",
@@ -1767,11 +2101,11 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "Medium Rotation Rate: %u",
                              tvb_get_ntohs (tvb, offset+20));
         break;
-    case SCSI_MODEPAGE_FLEXDISK:
-        break;
-    case SCSI_MODEPAGE_VERERR:
-        break;
-    case SCSI_MODEPAGE_CACHE:
+    case SCSI_SBC2_MODEPAGE_FLEXDISK:
+        return FALSE;
+    case SCSI_SBC2_MODEPAGE_VERERR:
+        return FALSE;
+    case SCSI_SBC2_MODEPAGE_CACHE:
         flags = tvb_get_guint8 (tvb, offset+2);
         proto_tree_add_text (tree, tvb, offset+2, 1,
                              "IC: %u, ABPF: %u, CAP %u, Disc: %u, Size: %u, WCE: %u, MF: %u, RCD: %u",
@@ -1807,18 +2141,258 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
                              "Non-Cache Segment Size: %u",
                              tvb_get_ntoh24 (tvb, offset+17));
         break;
-    case SCSI_MODEPAGE_PERDEV:
-        break;
-    case SCSI_MODEPAGE_MEDTYPE:
+    case SCSI_SBC2_MODEPAGE_MEDTYPE:
+        return FALSE;
+    case SCSI_SBC2_MODEPAGE_NOTPART:
+        return FALSE;
+    case SCSI_SBC2_MODEPAGE_XORCTL:
+        return FALSE;
+    default:
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static const value_string compression_algorithm_vals[] = {
+       {0x00, "No algorithm selected"},
+       {0x01, "Default algorithm"},
+       {0x03, "IBM ALDC with 512-byte buffer"},
+       {0x04, "IBM ALDC with 1024-byte buffer"},
+       {0x05, "IBM ALDC with 2048-byte buffer"},
+       {0x10, "IBM IDRC"},
+       {0x20, "DCLZ"},
+       {0xFF, "Unregistered algorithm"},
+       {0, NULL}
+};
+
+static gboolean
+dissect_scsi_ssc2_modepage (tvbuff_t *tvb _U_, packet_info *pinfo _U_,
+                           proto_tree *tree _U_, guint offset _U_,
+                            guint8 pcode)
+{
+    guint8 flags;
+
+    switch (pcode) {
+    case SCSI_SSC2_MODEPAGE_DATACOMP:
+        flags = tvb_get_guint8 (tvb, offset+2);
+        proto_tree_add_text (tree, tvb, offset+2, 1,
+                             "DCE: %u, DCC: %u",
+                             (flags & 0x80) >> 7, (flags & 0x40) >> 6);
+        flags = tvb_get_guint8 (tvb, offset+3);
+        proto_tree_add_text (tree, tvb, offset+3, 1,
+                             "DDE: %u, RED: %u",
+                             (flags & 0x80) >> 7, (flags & 0x60) >> 5);
+        proto_tree_add_text (tree, tvb, offset+4, 4,
+                             "Compression algorithm: %s",
+                             val_to_str (tvb_get_ntohl (tvb, offset+4),
+                                         compression_algorithm_vals,
+                                         "Unknown (0x%08x)"));
+        proto_tree_add_text (tree, tvb, offset+8, 4,
+                             "Decompression algorithm: %s",
+                             val_to_str (tvb_get_ntohl (tvb, offset+4),
+                                         compression_algorithm_vals,
+                                         "Unknown (0x%08x)"));
         break;
-    case SCSI_MODEPAGE_NOTPART:
+    case SCSI_SSC2_MODEPAGE_DEVCONF:
+        return FALSE;
+    case SCSI_SSC2_MODEPAGE_MEDPAR1:
+        return FALSE;
+    case SCSI_SSC2_MODEPAGE_MEDPAR2:
+        return FALSE;
+    case SCSI_SSC2_MODEPAGE_MEDPAR3:
+        return FALSE;
+    case SCSI_SSC2_MODEPAGE_MEDPAR4:
+        return FALSE;
+    default:
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static gboolean
+dissect_scsi_smc2_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
+                           proto_tree *tree, guint offset, guint8 pcode)
+{
+    guint8 flags;
+    guint8 param_list_len;
+
+    switch (pcode) {
+    case SCSI_SMC2_MODEPAGE_EAA:
+        param_list_len = tvb_get_guint8 (tvb, offset+2);
+        proto_tree_add_text (tree, tvb, offset+2, 1, "Parameter List Length: %u",
+                             param_list_len);
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+3, 2, "First Medium Transport Element Address: %u",
+                             tvb_get_ntohs (tvb, offset+3));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+5, 2, "Number of Medium Transport Elements: %u",
+                             tvb_get_ntohs (tvb, offset+5));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+7, 2, "First Storage Element Address: %u",
+                             tvb_get_ntohs (tvb, offset+7));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+9, 2, "Number of Storage Elements: %u",
+                             tvb_get_ntohs (tvb, offset+9));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+11, 2, "First Import/Export Element Address: %u",
+                             tvb_get_ntohs (tvb, offset+11));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+13, 2, "Number of Import/Export Elements: %u",
+                             tvb_get_ntohs (tvb, offset+13));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+15, 2, "First Data Transfer Element Address: %u",
+                             tvb_get_ntohs (tvb, offset+15));
+        param_list_len -= 2;
+        if (param_list_len < 2)
+            break;
+        proto_tree_add_text (tree, tvb, offset+17, 2, "Number of Data Transfer Elements: %u",
+                             tvb_get_ntohs (tvb, offset+17));
         break;
-    case SCSI_MODEPAGE_XORCTL:
+    case SCSI_SMC2_MODEPAGE_TRANGEOM:
+        return FALSE;
+    case SCSI_SMC2_MODEPAGE_DEVCAP:
+        flags = tvb_get_guint8 (tvb, offset+2);
+        proto_tree_add_text (tree, tvb, offset+2, 1,
+                             "STORDT: %u, STORI/E: %u, STORST: %u, STORMT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_text (tree, tvb, offset+4, 1,
+                             "MT->DT: %u, MT->I/E: %u, MT->ST: %u, MT->MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+5);
+        proto_tree_add_text (tree, tvb, offset+5, 1,
+                             "ST->DT: %u, ST->I/E: %u, ST->ST: %u, ST->MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+6);
+        proto_tree_add_text (tree, tvb, offset+6, 1,
+                             "I/E->DT: %u, I/E->I/E: %u, I/E->ST: %u, I/E->MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+7);
+        proto_tree_add_text (tree, tvb, offset+7, 1,
+                             "DT->DT: %u, DT->I/E: %u, DT->ST: %u, DT->MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+12);
+        proto_tree_add_text (tree, tvb, offset+12, 1,
+                             "MT<>DT: %u, MT<>I/E: %u, MT<>ST: %u, MT<>MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+13);
+        proto_tree_add_text (tree, tvb, offset+13, 1,
+                             "ST<>DT: %u, ST<>I/E: %u, ST<>ST: %u, ST<>MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+14);
+        proto_tree_add_text (tree, tvb, offset+14, 1,
+                             "I/E<>DT: %u, I/E<>I/E: %u, I/E<>ST: %u, I/E<>MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+15);
+        proto_tree_add_text (tree, tvb, offset+15, 1,
+                             "DT<>DT: %u, DT<>I/E: %u, DT<>ST: %u, DT<>MT: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
         break;
     default:
-        proto_tree_add_text (tree, tvb, offset, plen,
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static guint
+dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo,
+                      proto_tree *scsi_tree, guint offset,
+                       scsi_device_type devtype)
+{
+    guint8 pcode, plen;
+    proto_tree *tree;
+    proto_item *ti;
+    const value_string *modepage_val;
+    int hf_pagecode;
+    gboolean (*dissect_modepage)(tvbuff_t *, packet_info *, proto_tree *,
+                                 guint, guint8);
+
+    pcode = tvb_get_guint8 (tvb, offset);
+    plen = tvb_get_guint8 (tvb, offset+1);
+
+    if (match_strval (pcode & SCSI_MS_PCODE_BITS,
+                      scsi_spc2_modepage_val) == NULL) {
+        /*
+         * This isn't a generic mode page that applies to all SCSI
+         * device types; try to interpret it based on what we deduced,
+         * or were told, the device type is.
+         */
+        switch (devtype) {
+        case SCSI_DEV_SBC:
+            modepage_val = scsi_sbc2_modepage_val;
+            hf_pagecode = hf_scsi_sbcpagecode;
+            dissect_modepage = dissect_scsi_sbc2_modepage;
+            break;
+
+        case SCSI_DEV_SSC:
+            modepage_val = scsi_ssc2_modepage_val;
+            hf_pagecode = hf_scsi_sscpagecode;
+            dissect_modepage = dissect_scsi_ssc2_modepage;
+            break;
+
+        case SCSI_DEV_SMC:
+            modepage_val = scsi_smc2_modepage_val;
+            hf_pagecode = hf_scsi_smcpagecode;
+            dissect_modepage = dissect_scsi_smc2_modepage;
+            break;
+
+        default:
+            /*
+             * The "val_to_str()" lookup will fail in this table
+             * (it failed in "match_strval()"), so it'll return
+             * "Unknown (XXX)", which is what we want.
+             */
+            modepage_val = scsi_spc2_modepage_val;
+            hf_pagecode = hf_scsi_spcpagecode;
+            dissect_modepage = dissect_scsi_spc2_modepage;
+            break;
+       }
+    } else {
+        modepage_val = scsi_spc2_modepage_val;
+        hf_pagecode = hf_scsi_spcpagecode;
+        dissect_modepage = dissect_scsi_spc2_modepage;
+    }
+    ti = proto_tree_add_text (scsi_tree, tvb, offset, plen+2, "%s Mode Page",
+                              val_to_str (pcode & SCSI_MS_PCODE_BITS,
+                                          modepage_val, "Unknown (0x%08x)"));
+    tree = proto_item_add_subtree (ti, ett_scsi_page);
+    proto_tree_add_text (tree, tvb, offset, 1, "PS: %u", (pcode & 0x80) >> 7);
+
+    proto_tree_add_item (tree, hf_pagecode, tvb, offset, 1, 0);
+    proto_tree_add_text (tree, tvb, offset+1, 1, "Page Length: %u",
+                         plen);
+
+    if (!tvb_bytes_exist (tvb, offset, plen)) {
+       /* XXX - why not just drive on and throw an exception? */
+        return (plen + 2);
+    }
+
+    if (!(*dissect_modepage)(tvb, pinfo, tree, offset,
+                             pcode & SCSI_MS_PCODE_BITS)) {
+        proto_tree_add_text (tree, tvb, offset+2, plen,
                              "Unknown Page");
-        break;
     }
     return (plen+2);
 }
@@ -1826,17 +2400,17 @@ dissect_scsi_modepage (tvbuff_t *tvb, packet_info *pinfo _U_,
 static void
 dissect_scsi_modeselect6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                           guint offset, gboolean isreq, gboolean iscdb,
-                          guint payload_len _U_)
+                          scsi_device_type devtype, guint payload_len)
 {
     guint8 flags;
     guint tot_len, desclen, plen;
-    
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_modesel_flags, tvb, offset, 1,
                                     flags, "PF = %u, SP = %u", flags & 0x10,
                                     flags & 0x1);
@@ -1858,33 +2432,62 @@ dissect_scsi_modeselect6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
          * Page (s)
          *    - Page code, Page length, Page Parameters
          */
+        if (payload_len < 1)
+            return;
         tot_len = tvb_get_guint8 (tvb, offset);
         proto_tree_add_text (tree, tvb, offset, 1, "Mode Data Length: %u",
                              tot_len);
-        proto_tree_add_text (tree, tvb, offset+1, 1, "Medium Type: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+1));
-        proto_tree_add_text (tree, tvb, offset+2, 1,
+        offset += 1;
+        payload_len -= 1;
+        /* The mode data length is reserved for MODE SELECT, so we just
+           use the payload length. */
+
+        if (payload_len < 1)
+            return;
+        switch (devtype) {
+
+        case SCSI_DEV_SBC:
+            proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: %s",
+                                 val_to_str(tvb_get_guint8 (tvb, offset),
+                                            scsi_modesense_medtype_sbc_val,
+                                            "Unknown (0x%02x)"));
+            break;
+
+        default:
+            proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: 0x%02x",
+                                 tvb_get_guint8 (tvb, offset));
+            break;
+        }
+        offset += 1;
+        payload_len -= 1;
+
+        if (payload_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1,
                              "Device-Specific Parameter: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+2));
-        desclen = tvb_get_guint8 (tvb, offset+3);
-        proto_tree_add_text (tree, tvb, offset+3, 1,
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        payload_len -= 1;
+
+        if (payload_len < 1)
+            return;
+        desclen = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
                              "Block Descriptor Length: %u", desclen);
-        offset = 4;
-        tot_len -= 3;           /* tot_len does not include the len field */
-        if (desclen) {
-            proto_tree_add_text (tree, tvb, offset, 4, "No. of Blocks: %u",
-                                 tvb_get_ntohl (tvb, offset));
-            proto_tree_add_text (tree, tvb, offset+4, 1, "Density Code: 0x%02x",
-                                 tvb_get_guint8 (tvb, offset+4));
-            proto_tree_add_text (tree, tvb, offset+5, 3, "Block Length: %u",
-                                 tvb_get_ntoh24 (tvb, offset+5));
-            offset += 8;        /* increment the offset by 8 */
-            tot_len -= 8;       /* subtract by the block desc len */
-        }
+        offset += 1;
+        payload_len -= 1;
+
+        if (!dissect_scsi_blockdescs (tvb, pinfo, tree, offset, payload_len,
+                                     desclen, devtype, FALSE))
+            return;
+        offset += desclen;
+        payload_len -= desclen;
+
         /* offset points to the start of the mode page */
-        while ((tot_len > offset) && tvb_bytes_exist (tvb, offset, 2)) {
-            plen = dissect_scsi_modepage (tvb, pinfo, tree, offset);
+        while ((payload_len > 0) && tvb_bytes_exist (tvb, offset, 2)) {
+            plen = dissect_scsi_modepage (tvb, pinfo, tree, offset, devtype);
             offset += plen;
+            payload_len -= plen;
         }
     }
 }
@@ -1892,18 +2495,18 @@ dissect_scsi_modeselect6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static void
 dissect_scsi_modeselect10 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                            guint offset, gboolean isreq, gboolean iscdb,
-                           guint payload_len _U_)
+                           scsi_device_type devtype, guint payload_len)
 {
     guint8 flags;
     gboolean longlba;
-    guint tot_len, desclen;
-    
+    guint tot_len, desclen, plen;
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_modesel_flags, tvb, offset, 1,
                                     flags, "PF = %u, SP = %u", flags & 0x10,
                                     flags & 0x1);
@@ -1925,58 +2528,131 @@ dissect_scsi_modeselect10 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
          * Page (s)
          *    - Page code, Page length, Page Parameters
          */
+        if (payload_len < 1)
+            return;
         tot_len = tvb_get_ntohs (tvb, offset);
         proto_tree_add_text (tree, tvb, offset, 2, "Mode Data Length: %u",
                              tot_len);
-        proto_tree_add_text (tree, tvb, offset+2, 1, "Medium Type: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+2));
-        proto_tree_add_text (tree, tvb, offset+3, 1,
-                             "Device-Specific Parameter: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+3));
-        longlba = tvb_get_guint8 (tvb, offset+4) & 0x1;
-        proto_tree_add_text (tree, tvb, offset+4, 1, "LongLBA: %u", longlba);
-        desclen = tvb_get_guint8 (tvb, offset+6);
-        proto_tree_add_text (tree, tvb, offset+6, 1,
-                             "Block Descriptor Length: %u", desclen);
-        offset = 8;
-        tot_len -= 6;           /* tot_len does not include the len field */
-        if (desclen) {
-            proto_tree_add_text (tree, tvb, offset, 8, "No. of Blocks: %s",
-                                 bytes_to_str (tvb_get_ptr (tvb, offset, 8),
-                                               8));
-            proto_tree_add_text (tree, tvb, offset+8, 1, "Density Code: 0x%02x",
-                                 tvb_get_guint8 (tvb, offset+4));
-            proto_tree_add_text (tree, tvb, offset+12, 4, "Block Length: %u",
-                                 tvb_get_ntohl (tvb, offset+12));
-            offset += 16;        /* increment the offset by 8 */
-            tot_len -= 16;       /* subtract by the block desc len */
+        offset += 2;
+        payload_len -= 2;
+        /* The mode data length is reserved for MODE SELECT, so we just
+           use the payload length. */
+
+        if (payload_len < 1)
+            return;
+        switch (devtype) {
+
+        case SCSI_DEV_SBC:
+            proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: %s",
+                                 val_to_str(tvb_get_guint8 (tvb, offset),
+                                            scsi_modesense_medtype_sbc_val,
+                                            "Unknown (0x%02x)"));
+            break;
+
+        default:
+            proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: 0x%02x",
+                                 tvb_get_guint8 (tvb, offset));
+            break;
         }
+        offset += 1;
+        payload_len -= 1;
+
+        if (payload_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Device-Specific Parameter: 0x%02x",
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        payload_len -= 1;
+
+        if (payload_len < 1)
+            return;
+        longlba = tvb_get_guint8 (tvb, offset) & 0x1;
+        proto_tree_add_text (tree, tvb, offset, 1, "LongLBA: %u", longlba);
+        offset += 2;   /* skip LongLBA byte and reserved byte */
+        payload_len -= 2;
+
+        if (payload_len < 1)
+            return;
+        desclen = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Block Descriptor Length: %u", desclen);
+        offset += 1;
+        payload_len -= 1;
+
+        if (!dissect_scsi_blockdescs (tvb, pinfo, tree, offset, payload_len,
+                                     desclen, devtype, longlba))
+            return;
+        offset += desclen;
+        payload_len -= desclen;
+
         /* offset points to the start of the mode page */
-        while ((tot_len > offset) && tvb_bytes_exist (tvb, offset, 2)) {
-            offset += dissect_scsi_modepage (tvb, pinfo, tree, offset);
+        while ((payload_len > 0) && tvb_bytes_exist (tvb, offset, 2)) {
+            plen = dissect_scsi_modepage (tvb, pinfo, tree, offset, devtype);
+            offset += plen;
+            payload_len -= plen;
         }
     }
 }
 
+static void
+dissect_scsi_pagecode (tvbuff_t *tvb, packet_info *pinfo _U_,
+                       proto_tree *tree, guint offset,
+                       scsi_device_type devtype)
+{
+    guint8 pcode;
+    gchar *valstr;
+    int hf_pagecode;
+
+    pcode = tvb_get_guint8 (tvb, offset);
+    if ((valstr = match_strval (pcode & SCSI_MS_PCODE_BITS,
+                                scsi_spc2_modepage_val)) == NULL) {
+        /*
+         * This isn't a generic mode page that applies to all SCSI
+         * device types; try to interpret it based on what we deduced,
+         * or were told, the device type is.
+         */
+        switch (devtype) {
+        case SCSI_DEV_SBC:
+            hf_pagecode = hf_scsi_sbcpagecode;
+            break;
+
+        case SCSI_DEV_SSC:
+            hf_pagecode = hf_scsi_sscpagecode;
+            break;
+
+        case SCSI_DEV_SMC:
+            hf_pagecode = hf_scsi_smcpagecode;
+            break;
+
+        default:
+            hf_pagecode = hf_scsi_spcpagecode;
+            break;
+       }
+    } else {
+        hf_pagecode = hf_scsi_spcpagecode;
+    }
+    proto_tree_add_uint (tree, hf_pagecode, tvb, offset, 1, pcode);
+}
+
 static void
 dissect_scsi_modesense6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                          guint offset, gboolean isreq, gboolean iscdb,
-                         guint payload_len)
+                         scsi_device_type devtype, guint payload_len)
 {
     guint8 flags;
-    guint tot_len, desclen;
-    
+    guint tot_len, desclen, plen;
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_modesns_flags, tvb, offset, 1,
                                     flags, "DBD = %u", flags & 0x8);
         proto_tree_add_item (tree, hf_scsi_modesns_pc, tvb, offset+1, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_modesns_pagecode, tvb, offset+1, 1,
-                             0);
+        dissect_scsi_pagecode (tvb, pinfo, tree, offset+1, devtype);
         proto_tree_add_item (tree, hf_scsi_alloclen, tvb, offset+3, 1, 0);
 
         flags = tvb_get_guint8 (tvb, offset+4);
@@ -1998,32 +2674,52 @@ dissect_scsi_modesense6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
         tot_len = tvb_get_guint8 (tvb, offset);
         proto_tree_add_text (tree, tvb, offset, 1, "Mode Data Length: %u",
                              tot_len);
-        proto_tree_add_text (tree, tvb, offset+1, 1, "Medium Type: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+1));
-        proto_tree_add_text (tree, tvb, offset+2, 1,
-                             "Device-Specific Parameter: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+2));
-        desclen = tvb_get_guint8 (tvb, offset+3);
-        proto_tree_add_text (tree, tvb, offset+3, 1,
-                             "Block Descriptor Length: %u", desclen);
-        offset = 4;
+        offset += 1;
+
         /* The actual payload is the min of the length in the response & the
          * space allocated by the initiator as specified in the request.
+         *
+         * XXX - the payload length includes the length field, so we
+         * really should subtract the length of the length field from
+         * the payload length - but can it really be zero here?
          */
         if (payload_len && (tot_len > payload_len))
             tot_len = payload_len;
-        if (desclen) {
-            proto_tree_add_text (tree, tvb, offset, 4, "No. of Blocks: %u",
-                                 tvb_get_ntohl (tvb, offset));
-            proto_tree_add_text (tree, tvb, offset+4, 1, "Density Code: 0x%02x",
-                                 tvb_get_guint8 (tvb, offset+4));
-            proto_tree_add_text (tree, tvb, offset+5, 3, "Block Length: %u",
-                                 tvb_get_ntoh24 (tvb, offset+5));
-            offset += 8;        /* increment the offset by 8 */
-        }
+
+        if (tot_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: 0x%02x",
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        tot_len -= 1;
+
+        if (tot_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Device-Specific Parameter: 0x%02x",
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        tot_len -= 1;
+
+        if (tot_len < 1)
+            return;
+        desclen = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Block Descriptor Length: %u", desclen);
+        offset += 1;
+        tot_len -= 1;
+
+        if (!dissect_scsi_blockdescs (tvb, pinfo, tree, offset, tot_len,
+                                     desclen, devtype, FALSE))
+            return;
+        offset += desclen;
+        tot_len -= desclen;
+
         /* offset points to the start of the mode page */
-        while ((tot_len > offset) && tvb_bytes_exist (tvb, offset, 2)) {
-            offset += dissect_scsi_modepage (tvb, pinfo, tree, offset);
+        while ((tot_len > 0) && tvb_bytes_exist (tvb, offset, 2)) {
+            plen = dissect_scsi_modepage (tvb, pinfo, tree, offset, devtype);
+            offset += plen;
+            tot_len -= plen;
         }
     }
 }
@@ -2031,24 +2727,23 @@ dissect_scsi_modesense6 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 static void
 dissect_scsi_modesense10 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                           guint offset, gboolean isreq, gboolean iscdb,
-                          guint payload_len)
+                          scsi_device_type devtype, guint payload_len)
 {
     guint8 flags;
     gboolean longlba;
-    guint tot_len, desclen;
+    guint tot_len, desclen, plen;
+
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-        
+
         proto_tree_add_uint_format (tree, hf_scsi_modesns_flags, tvb, offset, 1,
                                     flags, "LLBAA = %u, DBD = %u", flags & 0x10,
                                     flags & 0x8);
         proto_tree_add_item (tree, hf_scsi_modesns_pc, tvb, offset+1, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_modesns_pagecode, tvb, offset+1, 1,
-                             0);
+        dissect_scsi_pagecode (tvb, pinfo, tree, offset+1, devtype);
         proto_tree_add_item (tree, hf_scsi_alloclen16, tvb, offset+6, 2, 0);
 
         flags = tvb_get_guint8 (tvb, offset+8);
@@ -2070,35 +2765,58 @@ dissect_scsi_modesense10 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
         tot_len = tvb_get_ntohs (tvb, offset);
         proto_tree_add_text (tree, tvb, offset, 2, "Mode Data Length: %u",
                              tot_len);
-        proto_tree_add_text (tree, tvb, offset+2, 1, "Medium Type: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+2));
-        proto_tree_add_text (tree, tvb, offset+3, 1,
+        offset += 2;
+        /* The actual payload is the min of the length in the response & the
+         * space allocated by the initiator as specified in the request.
+         *
+         * XXX - the payload length includes the length field, so we
+         * really should subtract the length of the length field from
+         * the payload length - but can it really be zero here?
+         */
+        if (payload_len && (tot_len > payload_len))
+            tot_len = payload_len;
+
+        if (tot_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1, "Medium Type: 0x%02x",
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        tot_len -= 1;
+
+        if (tot_len < 1)
+            return;
+        proto_tree_add_text (tree, tvb, offset, 1,
                              "Device-Specific Parameter: 0x%02x",
-                             tvb_get_guint8 (tvb, offset+3));
-        longlba = tvb_get_guint8 (tvb, offset+4) & 0x1;
-        proto_tree_add_text (tree, tvb, offset+4, 1, "LongLBA: %u", longlba);
-        desclen = tvb_get_guint8 (tvb, offset+6);
-        proto_tree_add_text (tree, tvb, offset+6, 1,
+                             tvb_get_guint8 (tvb, offset));
+        offset += 1;
+        tot_len -= 1;
+
+        if (tot_len < 1)
+            return;
+        longlba = tvb_get_guint8 (tvb, offset) & 0x1;
+        proto_tree_add_text (tree, tvb, offset, 1, "LongLBA: %u", longlba);
+        offset += 2;   /* skip LongLBA byte and reserved byte */
+        tot_len -= 2;
+
+        if (tot_len < 1)
+            return;
+        desclen = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
                              "Block Descriptor Length: %u", desclen);
-        offset = 8;
+        offset += 1;
+        tot_len -= 1;
 
-        if (payload_len && (tot_len > payload_len))
-            tot_len = payload_len;
+        if (!dissect_scsi_blockdescs (tvb, pinfo, tree, offset, tot_len,
+                                     desclen, devtype, longlba))
+            return;
+        offset += desclen;
+        tot_len -= desclen;
 
-        if (desclen) {
-            proto_tree_add_text (tree, tvb, offset, 8, "No. of Blocks: %s",
-                                 bytes_to_str (tvb_get_ptr (tvb, offset, 8),
-                                               8));
-            proto_tree_add_text (tree, tvb, offset+8, 1, "Density Code: 0x%02x",
-                                 tvb_get_guint8 (tvb, offset+4));
-            proto_tree_add_text (tree, tvb, offset+12, 4, "Block Length: %u",
-                                 tvb_get_ntohl (tvb, offset+12));
-            offset += 16;        /* increment the offset by 8 */
-            tot_len -= 16;       /* subtract by the block desc len */
-        }
         /* offset points to the start of the mode page */
-        while ((tot_len > offset) && tvb_bytes_exist (tvb, offset, 2)) {
-            offset += dissect_scsi_modepage (tvb, pinfo, tree, offset);
+        while ((tot_len > 0) && tvb_bytes_exist (tvb, offset, 2)) {
+            plen = dissect_scsi_modepage (tvb, pinfo, tree, offset, devtype);
+            offset += plen;
+            tot_len -= plen;
         }
     }
 }
@@ -2115,7 +2833,7 @@ dissect_scsi_persresvin (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         proto_tree_add_item (tree, hf_scsi_persresvin_svcaction, tvb, offset+1,
                              1, 0);
@@ -2142,13 +2860,13 @@ dissect_scsi_persresvin (tvbuff_t *tvb, packet_info *pinfo _U_,
         proto_tree_add_text (tree, tvb, offset, 4, "Additional Length: %u",
                              len);
         len = (payload_len > len) ? len : payload_len;
-        
+
         if ((flags & 0x1F) == SCSI_SPC2_RESVIN_SVCA_RDKEYS) {
            /* XXX - what if len is < 8?  That may be illegal, but
               that doesn't make it impossible.... */
             numrec = (len - 8)/8;
             offset += 8;
-            
+
             for (i = 0; i < numrec; i++) {
                 proto_tree_add_item (tree, hf_scsi_persresv_key, tvb, offset,
                                      8, 0);
@@ -2178,7 +2896,7 @@ dissect_scsi_persresvout (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         proto_tree_add_item (tree, hf_scsi_persresvin_svcaction, tvb, offset,
                              1, 0);
@@ -2205,7 +2923,7 @@ dissect_scsi_release6 (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset+4);
         proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
@@ -2216,14 +2934,14 @@ dissect_scsi_release6 (tvbuff_t *tvb, packet_info *pinfo _U_,
 }
 
 static void
-dissect_scsi_release10 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, 
+dissect_scsi_release10 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                         guint offset, gboolean isreq, gboolean iscdb)
 {
     guint8 flags;
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
 
@@ -2250,20 +2968,20 @@ dissect_scsi_reportdeviceid (tvbuff_t *tvb _U_, packet_info *pinfo _U_,
                              proto_tree *tree _U_, guint offset _U_,
                              gboolean isreq _U_, gboolean iscdb _U_)
 {
-    
+
 }
 
 static void
 dissect_scsi_reportluns (tvbuff_t *tvb, packet_info *pinfo _U_,
                          proto_tree *tree, guint offset, gboolean isreq,
-                         gboolean iscdb)
+                         gboolean iscdb, guint payload_len)
 {
     guint8 flags;
-    guint numelem, i;
+    guint listlen, i;
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         proto_tree_add_item (tree, hf_scsi_alloclen32, tvb, offset+5, 4, 0);
 
@@ -2274,11 +2992,16 @@ dissect_scsi_reportluns (tvbuff_t *tvb, packet_info *pinfo _U_,
                                     flags & 0xC0, flags & 0x4, flags & 0x1);
     }
     else if (!isreq) {
-        numelem = tvb_get_ntohl (tvb, offset);
+        listlen = tvb_get_ntohl (tvb, offset);
         proto_tree_add_text (tree, tvb, offset, 4, "LUN List Length: %u",
-                             numelem);
+                             listlen);
         offset += 8;
-        for (i = 0; i < numelem/8; i++) {
+        payload_len -= 8;
+        if (payload_len != 0) {
+            listlen = (listlen < payload_len) ? listlen : payload_len;
+        }
+        
+        for (i = 0; i < listlen/8; i++) {
             if (!tvb_get_guint8 (tvb, offset))
                 proto_tree_add_item (tree, hf_scsi_rluns_lun, tvb, offset+1, 1,
                                      0);
@@ -2298,7 +3021,7 @@ dissect_scsi_reqsense (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         proto_tree_add_item (tree, hf_scsi_alloclen, tvb, offset+3, 1, 0);
 
@@ -2318,7 +3041,7 @@ dissect_scsi_reserve6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset+4);
         proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
@@ -2336,7 +3059,7 @@ dissect_scsi_reserve10 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
 
@@ -2367,7 +3090,7 @@ dissect_scsi_testunitrdy (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset+4);
         proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
@@ -2386,7 +3109,7 @@ dissect_scsi_formatunit (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
         proto_tree_add_uint_format (tree, hf_scsi_formatunit_flags, tvb, offset,
@@ -2407,7 +3130,7 @@ dissect_scsi_formatunit (tvbuff_t *tvb, packet_info *pinfo _U_,
 }
 
 static void
-dissect_scsi_rdwr6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+dissect_scsi_sbc2_rdwr6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                     guint offset, gboolean isreq, gboolean iscdb)
 {
     guint8 flags;
@@ -2418,7 +3141,7 @@ dissect_scsi_rdwr6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
                              tvb_get_ntoh24 (tvb, offset),
                              tvb_get_guint8 (tvb, offset+3));
     }
-    
+
     if (tree && isreq && iscdb) {
         proto_tree_add_item (tree, hf_scsi_rdwr6_lba, tvb, offset, 3, 0);
         proto_tree_add_item (tree, hf_scsi_rdwr6_xferlen, tvb, offset+3, 1, 0);
@@ -2523,13 +3246,13 @@ dissect_scsi_readcapacity (tvbuff_t *tvb, packet_info *pinfo _U_,
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
 
         proto_tree_add_uint_format (tree, hf_scsi_readcapacity_flags, tvb,
                                     offset, 1, flags,
-                                    "LongLBA = %u, RelAddr = %u", 
+                                    "LongLBA = %u, RelAddr = %u",
                                     flags & 0x2, flags & 0x1);
         proto_tree_add_item (tree, hf_scsi_readcapacity_lba, tvb, offset+1,
                              4, 0);
@@ -2549,97 +3272,847 @@ dissect_scsi_readcapacity (tvbuff_t *tvb, packet_info *pinfo _U_,
         proto_tree_add_text (tree, tvb, offset+4, 4, "Block Length: %u bytes",
                              tvb_get_ntohl (tvb, offset+4));
     }
-}
+}
+
+static void
+dissect_scsi_readdefdata10 (tvbuff_t *tvb, packet_info *pinfo _U_,
+                            proto_tree *tree, guint offset, gboolean isreq,
+                            gboolean iscdb)
+{
+    guint8 flags;
+
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+
+        proto_tree_add_uint_format (tree, hf_scsi_readdefdata_flags, tvb,
+                                    offset, 1, flags, "PLIST = %u, GLIST = %u",
+                                    flags & 0x10, flags & 0x8);
+        proto_tree_add_item (tree, hf_scsi_cdb_defectfmt, tvb, offset, 1, 0);
+        proto_tree_add_item (tree, hf_scsi_alloclen16, tvb, offset+6, 2, 0);
+        flags = tvb_get_guint8 (tvb, offset+8);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+8, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_readdefdata12 (tvbuff_t *tvb, packet_info *pinfo _U_,
+                            proto_tree *tree, guint offset, gboolean isreq,
+                            gboolean iscdb)
+{
+    guint8 flags;
+
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+
+        proto_tree_add_uint_format (tree, hf_scsi_readdefdata_flags, tvb,
+                                    offset, 1, flags, "PLIST = %u, GLIST = %u",
+                                    flags & 0x10, flags & 0x8);
+        proto_tree_add_item (tree, hf_scsi_cdb_defectfmt, tvb, offset, 1, 0);
+        proto_tree_add_item (tree, hf_scsi_alloclen32, tvb, offset+5, 4, 0);
+        flags = tvb_get_guint8 (tvb, offset+10);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+10, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_reassignblks (tvbuff_t *tvb, packet_info *pinfo _U_,
+                           proto_tree *tree, guint offset, gboolean isreq,
+                           gboolean iscdb)
+{
+    guint8 flags;
+
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+
+        proto_tree_add_uint_format (tree, hf_scsi_reassignblks_flags, tvb,
+                                    offset, 1, flags,
+                                    "LongLBA = %u, LongList = %u",
+                                    flags & 0x2, flags & 0x1);
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_varlencdb (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                        guint offset, gboolean isreq, gboolean iscdb)
+{
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        proto_tree_add_item (tree, hf_scsi_control, tvb, offset, 1, 0);
+        proto_tree_add_item (tree, hf_scsi_add_cdblen, tvb, offset+6, 1, 0);
+        proto_tree_add_item (tree, hf_scsi_svcaction, tvb, offset+7, 2, 0);
+
+    }
+}
+
+static void
+dissect_scsi_ssc2_read6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (isreq) {
+        if (check_col (pinfo->cinfo, COL_INFO))
+            col_append_fstr (pinfo->cinfo, COL_INFO, "(Len: %u)",
+                             tvb_get_ntoh24 (tvb, offset+1));
+    }
+
+    if (tree && isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "SILI: %u, FIXED: %u",
+                             (flags & 0x02) >> 1, flags & 0x01);
+        proto_tree_add_item (tree, hf_scsi_rdwr6_xferlen, tvb, offset+1, 3, 0);
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_ssc2_write6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (isreq) {
+        if (check_col (pinfo->cinfo, COL_INFO))
+            col_append_fstr (pinfo->cinfo, COL_INFO, "(Len: %u)",
+                             tvb_get_ntoh24 (tvb, offset+1));
+    }
+
+    if (tree && isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "FIXED: %u", flags & 0x01);
+        proto_tree_add_item (tree, hf_scsi_rdwr6_xferlen, tvb, offset+1, 3,
+                             FALSE);
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_ssc2_writefilemarks6 (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (isreq) {
+        if (check_col (pinfo->cinfo, COL_INFO))
+            col_append_fstr (pinfo->cinfo, COL_INFO, "(Len: %u)",
+                             tvb_get_ntoh24 (tvb, offset+1));
+    }
+
+    if (tree && isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "WSMK: %u, IMMED: %u",
+                             (flags & 0x02) >> 1, flags & 0x01);
+        proto_tree_add_item (tree, hf_scsi_rdwr6_xferlen, tvb, offset+1, 3,
+                             FALSE);
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_ssc2_loadunload (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (isreq && iscdb) {
+        if (check_col (pinfo->cinfo, COL_INFO))
+            col_append_fstr (pinfo->cinfo, COL_INFO, "(Immed: %u)",
+                             tvb_get_guint8 (tvb, offset) & 0x01);
+
+        if (!tree)
+            return;
+
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Immed: %u", tvb_get_guint8 (tvb, offset) & 0x01);
+        flags = tvb_get_guint8 (tvb, offset+3);
+        proto_tree_add_text (tree, tvb, offset+3, 1,
+                             "Hold: %u, EOT: %u, Reten: %u, Load: %u",
+                             (flags & 0x08) >> 3, (flags & 0x04) >> 2,
+                             (flags & 0x02) >> 1, (flags & 0x01));
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_ssc2_readblocklimits (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags, granularity;
+
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+    else if (!iscdb) {
+       granularity = tvb_get_guint8 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 1, "Granularity: %u (%u %s)",
+                             granularity, 1 << granularity,
+                             plurality(1 << granularity, "byte", "bytes"));
+        proto_tree_add_text (tree, tvb, offset+1, 3, "Maximum Block Length Limit: %u bytes",
+                             tvb_get_ntoh24 (tvb, offset+1));
+        proto_tree_add_text (tree, tvb, offset+4, 2, "Minimum Block Length Limit: %u bytes",
+                             tvb_get_ntohs (tvb, offset+4));
+    }
+}
+
+#define SHORT_FORM_BLOCK_ID        0x00
+#define SHORT_FORM_VENDOR_SPECIFIC 0x01
+#define LONG_FORM                  0x06
+#define EXTENDED_FORM              0x08
+
+static const value_string service_action_vals[] = {
+       {SHORT_FORM_BLOCK_ID,        "Short Form - Block ID"},
+       {SHORT_FORM_VENDOR_SPECIFIC, "Short Form - Vendor-Specific"},
+       {LONG_FORM,                  "Long Form"},
+       {EXTENDED_FORM,              "Extended Form"},
+       {0, NULL}
+};
+
+#define BCU  0x20
+#define BYCU 0x10
+#define MPU  0x08
+#define BPU  0x04
+
+static void
+dissect_scsi_ssc2_readposition (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb,
+                    scsi_task_data_t *cdata)
+{
+    gint service_action;
+    guint8 flags;
+
+    if (!tree)
+        return;
+
+    if (isreq && iscdb) {
+        service_action = tvb_get_guint8 (tvb, offset) & 0x1F;
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Service Action: %s",
+                             val_to_str (service_action,
+                                         service_action_vals,
+                                         "Unknown (0x%02x)"));
+        /* Remember the service action so we can decode the reply */
+        if (cdata != NULL) {
+            cdata->flags = service_action;
+        }
+        proto_tree_add_text (tree, tvb, offset+6, 2,
+                             "Parameter Len: %u",
+                             tvb_get_ntohs (tvb, offset+6));
+        flags = tvb_get_guint8 (tvb, offset+8);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+8, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+    else if (!isreq) {
+        if (cdata)
+            service_action = cdata->flags;
+        else
+            service_action = -1; /* unknown */
+        switch (service_action) {
+        case SHORT_FORM_BLOCK_ID:
+        case SHORT_FORM_VENDOR_SPECIFIC:
+            flags = tvb_get_guint8 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 1,
+                             "BOP: %u, EOP: %u, BCU: %u, BYCU: %u, BPU: %u, PERR: %u",
+                             (flags & 0x80) >> 7, (flags & 0x40) >> 6,
+                             (flags & BCU) >> 5, (flags & BYCU) >> 4,
+                             (flags & BPU) >> 2, (flags & 0x02) >> 1);
+            offset += 1;
+
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "Partition Number: %u",
+                                 tvb_get_guint8 (tvb, offset));
+            offset += 1;
+
+            offset += 2; /* reserved */
+
+            if (!(flags & BPU)) {
+                proto_tree_add_text (tree, tvb, offset, 4,
+                                     "First Block Location: %u",
+                                     tvb_get_ntohl (tvb, offset));
+                offset += 4;
+
+                proto_tree_add_text (tree, tvb, offset, 4,
+                                     "Last Block Location: %u",
+                                     tvb_get_ntohl (tvb, offset));
+                offset += 4;
+            } else
+                offset += 8;
+
+            offset += 1; /* reserved */
+
+            if (!(flags & BCU)) {
+                proto_tree_add_text (tree, tvb, offset, 3,
+                                     "Number of Blocks in Buffer: %u",
+                                     tvb_get_ntoh24 (tvb, offset));
+            }
+            offset += 3;
+
+            if (!(flags & BYCU)) {
+                proto_tree_add_text (tree, tvb, offset, 4,
+                                     "Number of Bytes in Buffer: %u",
+                                     tvb_get_ntohl (tvb, offset));
+            }
+            offset += 4;
+            break;
+
+        case LONG_FORM:
+            flags = tvb_get_guint8 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 1,
+                             "BOP: %u, EOP: %u, MPU: %u, BPU: %u",
+                             (flags & 0x80) >> 7, (flags & 0x40) >> 6,
+                             (flags & MPU) >> 3, (flags & BPU) >> 2);
+            offset += 1;
+
+            offset += 3; /* reserved */
+
+            if (!(flags & BPU)) {
+                proto_tree_add_text (tree, tvb, offset, 4,
+                                     "Partition Number: %u",
+                                     tvb_get_ntohl (tvb, offset));
+                offset += 4;
+
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "Block Number: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+                 offset += 8;
+            } else
+                offset += 12;
+
+            if (!(flags & MPU)) {
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "File Number: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+                offset += 8;
+
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "Set Number: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+                offset += 8;
+            } else
+                offset += 16;
+            break;
+
+        case EXTENDED_FORM:
+            flags = tvb_get_guint8 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 1,
+                             "BOP: %u, EOP: %u, BCU: %u, BYCU: %u, MPU: %u, BPU: %u, PERR: %u",
+                             (flags & 0x80) >> 7, (flags & 0x40) >> 6,
+                             (flags & BCU) >> 5, (flags & BYCU) >> 4,
+                             (flags & MPU) >> 3, (flags & BPU) >> 2,
+                             (flags & 0x02) >> 1);
+            offset += 1;
+
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "Partition Number: %u",
+                                 tvb_get_guint8 (tvb, offset));
+            offset += 1;
+
+            proto_tree_add_text (tree, tvb, offset, 2,
+                                 "Additional Length: %u",
+                                 tvb_get_ntohs (tvb, offset));
+            offset += 2;
+
+            offset += 1; /* reserved */
+
+            if (!(flags & BCU)) {
+                proto_tree_add_text (tree, tvb, offset, 3,
+                                     "Number of Blocks in Buffer: %u",
+                                     tvb_get_ntoh24 (tvb, offset));
+            }
+            offset += 3;
+
+            if (!(flags & BPU)) {
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "First Block Location: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+                offset += 8;
+
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "Last Block Location: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+                offset += 8;
+            } else
+                offset += 16;
+
+            offset += 1; /* reserved */
+
+            if (!(flags & BYCU)) {
+                proto_tree_add_text (tree, tvb, offset, 8,
+                                     "Number of Bytes in Buffer: %s",
+                                     u64toa (tvb_get_ptr (tvb, offset, 8)));
+            }
+            offset += 8;
+            break;
+
+        default:
+            break;
+        }
+    }
+}
+
+static void
+dissect_scsi_ssc2_rewind (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (isreq && iscdb) {
+        if (check_col (pinfo->cinfo, COL_INFO))
+            col_append_fstr (pinfo->cinfo, COL_INFO, "(Immed: %u)",
+                             tvb_get_guint8 (tvb, offset) & 0x01);
+
+        if (!tree)
+            return;
+
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "Immed: %u", tvb_get_guint8 (tvb, offset) & 0x01);
+        flags = tvb_get_guint8 (tvb, offset+4);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+static void
+dissect_scsi_smc2_movemedium (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
+                    guint offset, gboolean isreq, gboolean iscdb)
+{
+    guint8 flags;
+
+    if (tree && isreq && iscdb) {
+        proto_tree_add_text (tree, tvb, offset+1, 2,
+                             "Medium Transport Address: %u",
+                             tvb_get_ntohs (tvb, offset+1));
+        proto_tree_add_text (tree, tvb, offset+3, 2,
+                             "Source Address: %u",
+                             tvb_get_ntohs (tvb, offset+3));
+        proto_tree_add_text (tree, tvb, offset+5, 2,
+                             "Destination Address: %u",
+                             tvb_get_ntohs (tvb, offset+5));
+        flags = tvb_get_guint8 (tvb, offset+9);
+        proto_tree_add_text (tree, tvb, offset+9, 1,
+                             "INV: %u", flags & 0x01);
+        flags = tvb_get_guint8 (tvb, offset+10);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+10, 1,
+                                    flags,
+                                    "Vendor Unique = %u, NACA = %u, Link = %u",
+                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    }
+}
+
+#define MT_ELEM  0x1
+#define ST_ELEM  0x2
+#define I_E_ELEM 0x3
+#define DT_ELEM  0x4
+
+static const value_string element_type_code_vals[] = {
+    {0x0,      "All element types"},
+    {MT_ELEM,  "Medium transport element"},
+    {ST_ELEM,  "Storage element"},
+    {I_E_ELEM, "Import/export element"},
+    {DT_ELEM,  "Data transfer element"},
+    {0, NULL}
+};
+
+#define PVOLTAG 0x80
+#define AVOLTAG 0x40
+
+#define EXCEPT 0x04
+
+#define ID_VALID 0x20
+#define LU_VALID 0x10
+
+#define SVALID 0x80
+
+static void
+dissect_scsi_smc2_volume_tag (tvbuff_t *tvb, packet_info *pinfo _U_,
+                              proto_tree *tree, guint offset,
+                              const char *name)
+{
+    char volid[32+1];
+    char *p;
+
+    tvb_memcpy (tvb, (guint8 *)volid, offset, 32);
+    p = &volid[32];
+    for (;;) {
+       *p = '\0';
+        if (p == volid)
+            break;
+        if (*(p - 1) != ' ')
+            break;
+        p--;
+    }
+    proto_tree_add_text (tree, tvb, offset, 36,
+                         "%s: Volume Identification = \"%s\", Volume Sequence Number = %u",
+                        name, volid, tvb_get_ntohs (tvb, offset+34));
+}
+
+static void
+dissect_scsi_smc2_element (tvbuff_t *tvb, packet_info *pinfo _U_,
+                         proto_tree *tree, guint offset,
+                         guint elem_bytecnt, guint8 elem_type,
+                         guint8 voltag_flags)
+{
+    guint8 flags;
+    guint8 ident_len;
+
+    if (elem_bytecnt < 2)
+        return;
+    proto_tree_add_text (tree, tvb, offset, 2,
+                         "Element Address: %u",
+                         tvb_get_ntohs (tvb, offset));
+    offset += 2;
+    elem_bytecnt -= 2;
+
+    if (elem_bytecnt < 1)
+        return;
+    flags = tvb_get_guint8 (tvb, offset);
+    switch (elem_type) {
+
+    case MT_ELEM:
+        proto_tree_add_text (tree, tvb, offset, 1,
+                            "EXCEPT: %u, FULL: %u",
+                             (flags & EXCEPT) >> 2, flags & 0x01);
+        break;
+
+    case ST_ELEM:
+    case DT_ELEM:
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "ACCESS: %u, EXCEPT: %u, FULL: %u",
+                             (flags & 0x08) >> 3,
+                             (flags & EXCEPT) >> 2, flags & 0x01);
+        break;
+
+    case I_E_ELEM:
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "cmc: %u, INENAB: %u, EXENAB: %u, ACCESS: %u, EXCEPT: %u, IMPEXP: %u, FULL: %u",
+                             (flags & 0x40) >> 6,
+                             (flags & 0x20) >> 5,
+                             (flags & 0x10) >> 4,
+                             (flags & 0x08) >> 3,
+                             (flags & EXCEPT) >> 2,
+                             (flags & 0x02) >> 1,
+                             flags & 0x01);
+        break;
+    }
+    offset += 1;
+    elem_bytecnt -= 1;
+
+    if (elem_bytecnt < 1)
+        return;
+    offset += 1; /* reserved */
+    elem_bytecnt -= 1;
+
+    if (elem_bytecnt < 2)
+        return;
+    if (flags & EXCEPT) {
+        proto_tree_add_text (tree, tvb, offset, 2,
+                             "Additional Sense Code+Qualifier: %s",
+                             val_to_str (tvb_get_ntohs (tvb, offset),
+                                         scsi_asc_val, "Unknown (0x%04x)"));
+    }
+    offset += 2;
+    elem_bytecnt -= 2;
+
+    if (elem_bytecnt < 3)
+        return;
+    switch (elem_type) {
+
+    case DT_ELEM:
+        flags = tvb_get_guint8 (tvb, offset);
+        if (flags & LU_VALID) {
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "NOT BUS: %u, ID VALID: %u, LU VALID: 1, LUN: %u",
+                                 (flags & 0x80) >> 7,
+                                 (flags & ID_VALID) >> 5,
+                                 flags & 0x07);
+        } else if (flags & ID_VALID) {
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "ID VALID: 1, LU VALID: 0");
+        } else {
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "ID VALID: 0, LU VALID: 0");
+        }
+        offset += 1;
+        if (flags & ID_VALID) {
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "SCSI Bus Address: %u",
+                                 tvb_get_guint8 (tvb, offset));
+        }
+        offset += 1;
+        offset += 1; /* reserved */
+        break;
+
+    default:
+        offset += 3; /* reserved */
+        break;
+    }
+    elem_bytecnt -= 3;
 
-static void
-dissect_scsi_readdefdata10 (tvbuff_t *tvb, packet_info *pinfo _U_,
-                            proto_tree *tree, guint offset, gboolean isreq,
-                            gboolean iscdb)
-{
-    guint8 flags;
+    if (elem_bytecnt < 3)
+        return;
+    flags = tvb_get_guint8 (tvb, offset);
+    if (flags & SVALID) {
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "SVALID: 1, INVERT: %u",
+                             (flags & 0x40) >> 6);
+        offset += 1;
+        proto_tree_add_text (tree, tvb, offset, 2,
+                             "Source Storage Element Address: %u",
+                             tvb_get_ntohs (tvb, offset));
+        offset += 2;
+    } else {
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "SVALID: 0");
+        offset += 3;
+    }
+    elem_bytecnt -= 3;
 
-    if (!tree)
+    if (voltag_flags & PVOLTAG) {
+        if (elem_bytecnt < 36)
+            return;
+        dissect_scsi_smc2_volume_tag (tvb, pinfo, tree, offset,
+                                      "Primary Volume Tag Information");
+        offset += 36;
+        elem_bytecnt -= 36;
+    }
+
+    if (voltag_flags & AVOLTAG) {
+        if (elem_bytecnt < 36)
+            return;
+        dissect_scsi_smc2_volume_tag (tvb, pinfo, tree, offset,
+                                      "Alternate Volume Tag Information");
+        offset += 36;
+        elem_bytecnt -= 36;
+    }
+
+    if (elem_bytecnt < 1)
         return;
-    
-    if (isreq && iscdb) {
-        flags = tvb_get_guint8 (tvb, offset);
+    flags = tvb_get_guint8 (tvb, offset);
+    proto_tree_add_text (tree, tvb, offset, 1,
+                         "Code Set: %s",
+                         val_to_str (flags & 0x0F,
+                                     scsi_devid_codeset_val,
+                                     "Unknown (0x%02x)"));
+    offset += 1;
+    elem_bytecnt -= 1;
+
+    if (elem_bytecnt < 1)
+        return;
+    flags = tvb_get_guint8 (tvb, offset);
+    proto_tree_add_text (tree, tvb, offset, 1,
+                         "Identifier Type: %s",
+                         val_to_str ((flags & 0x0F),
+                                     scsi_devid_idtype_val,
+                                     "Unknown (0x%02x)"));
+    offset += 1;
+    elem_bytecnt -= 1;
+
+    if (elem_bytecnt < 1)
+        return;
+    offset += 1; /* reserved */
+    elem_bytecnt -= 1;
 
-        proto_tree_add_uint_format (tree, hf_scsi_readdefdata_flags, tvb,
-                                    offset, 1, flags, "PLIST = %u, GLIST = %u",
-                                    flags & 0x10, flags & 0x8);
-        proto_tree_add_item (tree, hf_scsi_cdb_defectfmt, tvb, offset, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_alloclen16, tvb, offset+6, 2, 0);
-        flags = tvb_get_guint8 (tvb, offset+8);
-        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+8, 1,
-                                    flags,
-                                    "Vendor Unique = %u, NACA = %u, Link = %u",
-                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    if (elem_bytecnt < 1)
+        return;
+    ident_len = tvb_get_guint8 (tvb, offset);
+    proto_tree_add_text (tree, tvb, offset, 1,
+                         "Identifier Length: %u",
+                         ident_len);
+    offset += 1;
+    elem_bytecnt -= 1;
+
+    if (ident_len != 0) {
+        if (elem_bytecnt < ident_len)
+            return;
+        proto_tree_add_text (tree, tvb, offset, ident_len,
+                             "Identifier: %s",
+                             tvb_bytes_to_str (tvb, offset, ident_len));
+        offset += ident_len;
+        elem_bytecnt -= ident_len;
+    }
+    if (elem_bytecnt != 0) {
+        proto_tree_add_text (tree, tvb, offset, elem_bytecnt,
+                             "Vendor-specific Data: %s",
+                             tvb_bytes_to_str (tvb, offset, elem_bytecnt));
     }
 }
 
 static void
-dissect_scsi_readdefdata12 (tvbuff_t *tvb, packet_info *pinfo _U_,
-                            proto_tree *tree, guint offset, gboolean isreq,
-                            gboolean iscdb)
+dissect_scsi_smc2_elements (tvbuff_t *tvb, packet_info *pinfo,
+                            proto_tree *tree, guint offset,
+                            guint desc_bytecnt, guint8 elem_type,
+                            guint8 voltag_flags, guint16 elem_desc_len)
 {
-    guint8 flags;
-
-    if (!tree)
-        return;
-    
-    if (isreq && iscdb) {
-        flags = tvb_get_guint8 (tvb, offset);
-
-        proto_tree_add_uint_format (tree, hf_scsi_readdefdata_flags, tvb,
-                                    offset, 1, flags, "PLIST = %u, GLIST = %u",
-                                    flags & 0x10, flags & 0x8);
-        proto_tree_add_item (tree, hf_scsi_cdb_defectfmt, tvb, offset, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_alloclen32, tvb, offset+5, 4, 0);
-        flags = tvb_get_guint8 (tvb, offset+10);
-        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+10, 1,
-                                    flags,
-                                    "Vendor Unique = %u, NACA = %u, Link = %u",
-                                    flags & 0xC0, flags & 0x4, flags & 0x1);
+    guint elem_bytecnt;
+
+    while (desc_bytecnt != 0) {
+        elem_bytecnt = elem_desc_len;
+        if (elem_bytecnt > desc_bytecnt)
+            elem_bytecnt = desc_bytecnt;
+        dissect_scsi_smc2_element (tvb, pinfo, tree, offset, elem_bytecnt,
+                                   elem_type, voltag_flags);
+        offset += elem_bytecnt;
+        desc_bytecnt -= elem_bytecnt;
     }
 }
 
 static void
-dissect_scsi_reassignblks (tvbuff_t *tvb, packet_info *pinfo _U_,
-                           proto_tree *tree, guint offset, gboolean isreq,
-                           gboolean iscdb)
+dissect_scsi_smc2_readelementstatus (tvbuff_t *tvb, packet_info *pinfo,
+                         proto_tree *tree, guint offset, gboolean isreq,
+                         gboolean iscdb)
 {
     guint8 flags;
+    guint numelem, bytecnt, desc_bytecnt;
+    guint8 elem_type;
+    guint8 voltag_flags;
+    guint16 elem_desc_len;
 
     if (!tree)
         return;
-    
+
     if (isreq && iscdb) {
         flags = tvb_get_guint8 (tvb, offset);
-
-        proto_tree_add_uint_format (tree, hf_scsi_reassignblks_flags, tvb,
-                                    offset, 1, flags,
-                                    "LongLBA = %u, LongList = %u",
-                                    flags & 0x2, flags & 0x1);
+        proto_tree_add_text (tree, tvb, offset, 1,
+                             "VOLTAG: %u, Element Type Code: %s",
+                             (flags & 0x10) >> 4,
+                             val_to_str (flags & 0xF, element_type_code_vals,
+                                         "Unknown (0x%x)"));
+        proto_tree_add_text (tree, tvb, offset+1, 2,
+                             "Starting Element Address: %u",
+                             tvb_get_ntohs (tvb, offset+1));
+        proto_tree_add_text (tree, tvb, offset+3, 2,
+                             "Number of Elements: %u",
+                             tvb_get_ntohs (tvb, offset+3));
         flags = tvb_get_guint8 (tvb, offset+4);
-        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+4, 1,
+        proto_tree_add_text (tree, tvb, offset+4, 1,
+                             "CURDATA: %u, DVCID: %u",
+                             (flags & 0x02) >> 1, flags & 0x01);
+        proto_tree_add_text (tree, tvb, offset+5, 3,
+                             "Allocation Length: %u",
+                             tvb_get_ntoh24 (tvb, offset+5));
+        flags = tvb_get_guint8 (tvb, offset+10);
+        proto_tree_add_uint_format (tree, hf_scsi_control, tvb, offset+10, 1,
                                     flags,
                                     "Vendor Unique = %u, NACA = %u, Link = %u",
                                     flags & 0xC0, flags & 0x4, flags & 0x1);
     }
-}
-
-static void
-dissect_scsi_varlencdb (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
-                        guint offset, gboolean isreq, gboolean iscdb)
-{
-    if (!tree)
-        return;
-    
-    if (isreq && iscdb) {
-        proto_tree_add_item (tree, hf_scsi_control, tvb, offset, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_add_cdblen, tvb, offset+6, 1, 0);
-        proto_tree_add_item (tree, hf_scsi_svcaction, tvb, offset+7, 2, 0);
+    else if (!isreq) {
+        proto_tree_add_text (tree, tvb, offset, 2,
+                             "First Element Address Reported: %u",
+                             tvb_get_ntohs (tvb, offset));
+        offset += 2;
+        numelem = tvb_get_ntohs (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 2,
+                             "Number of Elements Available: %u", numelem);
+        offset += 2;
+        offset += 1; /* reserved */
+        bytecnt = tvb_get_ntoh24 (tvb, offset);
+        proto_tree_add_text (tree, tvb, offset, 3,
+                             "Byte Count of Report Available: %u", bytecnt);
+        offset += 3;
+        while (bytecnt != 0) {
+            if (bytecnt < 1)
+                break;
+            elem_type = tvb_get_guint8 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "Element Type Code: %s",
+                                 val_to_str (elem_type, element_type_code_vals,
+                                             "Unknown (0x%x)"));
+            offset += 1;
+            bytecnt -= 1;
+
+            if (bytecnt < 1)
+                break;
+            voltag_flags = tvb_get_guint8 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 1,
+                                 "PVOLTAG: %u, AVOLTAG: %u",
+                                 (voltag_flags & PVOLTAG) >> 7,
+                                 (voltag_flags & AVOLTAG) >> 6);
+            offset += 1;
+            bytecnt -= 1;
+
+            if (bytecnt < 2)
+                break;
+            elem_desc_len = tvb_get_ntohs (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 2,
+                                 "Element Descriptor Length: %u",
+                                 elem_desc_len);
+            offset += 2;
+            bytecnt -= 2;
+
+            if (bytecnt < 1)
+                break;
+            offset += 1; /* reserved */
+            bytecnt -= 1;
 
+            if (bytecnt < 3)
+                break;
+            desc_bytecnt = tvb_get_ntoh24 (tvb, offset);
+            proto_tree_add_text (tree, tvb, offset, 3,
+                                 "Byte Count Of Descriptor Data Available: %u",
+                                 desc_bytecnt);
+            offset += 3;
+            bytecnt -= 3;
+
+            if (desc_bytecnt > bytecnt)
+                desc_bytecnt = bytecnt;
+            dissect_scsi_smc2_elements (tvb, pinfo, tree, offset,
+                                        desc_bytecnt, elem_type,
+                                        voltag_flags, elem_desc_len);
+            offset += desc_bytecnt;
+            bytecnt -= desc_bytecnt;
+        }
     }
 }
 
@@ -2663,7 +4136,7 @@ dissect_scsi_snsinfo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     proto_tree *sns_tree;
 
     scsi_end_task (pinfo);
-    
+
     if (tree) {
         ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
                                              snslen, "SCSI: SNS Info");
@@ -2698,51 +4171,79 @@ dissect_scsi_snsinfo (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
 void
 dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
-                  guint start, guint cdblen)
+                  guint start, guint cdblen, gint devtype_arg)
 {
     int offset = start;
     proto_item *ti;
     proto_tree *scsi_tree = NULL;
     guint8 opcode;
+    scsi_device_type devtype;
     scsi_cmnd_type cmd = 0;     /* 0 is undefined type */
-    scsi_device_type devtype = 0;
     gchar *valstr;
     scsi_task_data_t *cdata;
     scsi_devtype_key_t dkey;
     scsi_devtype_data_t *devdata;
-    
-    opcode = tvb_get_guint8 (tvb, offset);
 
-    /* Identify target if possible */
-    COPY_ADDRESS (&(dkey.devid), &pinfo->dst);
+    opcode = tvb_get_guint8 (tvb, offset);
 
-    devdata = (scsi_devtype_data_t *)g_hash_table_lookup (scsidev_req_hash,
-                                                          &dkey);
-    if (devdata != NULL) {
-        devtype = devdata->devtype;
-    }
+    if (devtype_arg != SCSI_DEV_UNKNOWN)
+        devtype = devtype_arg;
     else {
-        devtype = (scsi_device_type)scsi_def_devtype;
+        /*
+         * Try to look up the device data for this device.
+         *
+         * We don't use COPY_ADDRESS because "dkey.devid" isn't
+         * persistent, and therefore it can point to the stuff
+         * in "pinfo->src".  (Were we to use COPY_ADDRESS, we'd
+         * have to free the address data it allocated before we return.)
+         */
+        dkey.devid = pinfo->dst;
+
+        devdata = (scsi_devtype_data_t *)g_hash_table_lookup (scsidev_req_hash,
+                                                              &dkey);
+        if (devdata != NULL) {
+            devtype = devdata->devtype;
+        }
+        else {
+            devtype = (scsi_device_type)scsi_def_devtype;
+        }
     }
 
     if ((valstr = match_strval (opcode, scsi_spc2_val)) == NULL) {
-        if (devtype == SCSI_DEV_SBC) {
+        /*
+         * This isn't a generic command that applies to all SCSI
+         * device types; try to interpret it based on what we deduced,
+         * or were told, the device type is.
+         *
+         * Right now, the only choices are SBC or SSC. If we ever expand
+         * this to decode other device types, this piece of code needs to
+         * be modified.
+         */
+        switch (devtype) {
+        case SCSI_DEV_SBC:
             valstr = match_strval (opcode, scsi_sbc2_val);
             cmd = SCSI_CMND_SBC2;
-        }
-        else {
-            /* Right now, the only choices are SBC or SSC. If we ever expand
-             * this to decode other device types, this piece of code needs to
-             * be modified.
-             */
+            break;
+
+        case SCSI_DEV_SSC:
             valstr = match_strval (opcode, scsi_ssc2_val);
             cmd = SCSI_CMND_SSC2;
+            break;
+
+        case SCSI_DEV_SMC:
+            valstr = match_strval (opcode, scsi_smc2_val);
+            cmd = SCSI_CMND_SMC2;
+            break;
+
+        default:
+            cmd = SCSI_CMND_SPC2;
+            break;
         }
     }
     else {
         cmd = SCSI_CMND_SPC2;
     }
-    
+
     if (valstr != NULL) {
         if (check_col (pinfo->cinfo, COL_INFO)) {
             col_add_fstr (pinfo->cinfo, COL_INFO, "SCSI: %s", valstr);
@@ -2758,9 +4259,10 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
     if (cdata) {
         cdata->opcode = opcode;
-        cdata->devtype = cmd;
+        cdata->cmd = cmd;
+        cdata->devtype = devtype;
     }
-    
+
     if (tree) {
         ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, start,
                                              cdblen, "SCSI CDB");
@@ -2781,20 +4283,32 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                             "Opcode: %s (0x%02x)", valstr,
                                             opcode);
             }
+            else if (cmd == SCSI_CMND_SSC2) {
+                proto_tree_add_uint_format (scsi_tree, hf_scsi_sscopcode, tvb,
+                                            offset, 1,
+                                            tvb_get_guint8 (tvb, offset),
+                                            "Opcode: %s (0x%02x)", valstr,
+                                            opcode);
+            }
+            else if (cmd == SCSI_CMND_SMC2) {
+                proto_tree_add_uint_format (scsi_tree, hf_scsi_smcopcode, tvb,
+                                            offset, 1,
+                                            tvb_get_guint8 (tvb, offset),
+                                            "Opcode: %s (0x%02x)", valstr,
+                                            opcode);
+            }
             else {
-                 proto_tree_add_uint_format (scsi_tree, hf_scsi_sscopcode, tvb,
-                                             offset, 1,
-                                             tvb_get_guint8 (tvb, offset),
-                                             "Opcode: %s (0x%02x)", valstr,
-                                             opcode);
+                /* "Can't happen" */
+                g_assert_not_reached();
             }
         }
         else {
-            proto_tree_add_item (scsi_tree, hf_scsi_sbcopcode, tvb, offset, 1, 0);
+            proto_tree_add_item (scsi_tree, hf_scsi_spcopcode, tvb, offset, 1, 0);
         }
     }
-        
-    if (cmd == SCSI_CMND_SPC2) {
+
+    switch (cmd) {
+    case SCSI_CMND_SPC2:
         switch (opcode) {
         case SCSI_SPC2_INQUIRY:
             dissect_scsi_inquiry (tvb, pinfo, scsi_tree, offset+1, TRUE,
@@ -2818,22 +4332,22 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
         case SCSI_SPC2_MODESELECT6:
             dissect_scsi_modeselect6 (tvb, pinfo, scsi_tree, offset+1,
-                                      TRUE, TRUE, 0);
+                                      TRUE, TRUE, devtype, 0);
             break;
 
         case SCSI_SPC2_MODESELECT10:
             dissect_scsi_modeselect10 (tvb, pinfo, scsi_tree, offset+1,
-                                       TRUE, TRUE, 0);
+                                       TRUE, TRUE, devtype, 0);
             break;
 
         case SCSI_SPC2_MODESENSE6:
             dissect_scsi_modesense6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
-                                     TRUE, 0);
+                                     TRUE, devtype, 0);
             break;
 
         case SCSI_SPC2_MODESENSE10:
             dissect_scsi_modesense10 (tvb, pinfo, scsi_tree, offset+1,
-                                      TRUE, TRUE, 0);
+                                      TRUE, TRUE, devtype, 0);
             break;
 
         case SCSI_SPC2_PERSRESVIN:
@@ -2863,7 +4377,7 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
         case SCSI_SPC2_REPORTLUNS:
             dissect_scsi_reportluns (tvb, pinfo, scsi_tree, offset+1, TRUE,
-                                     TRUE);
+                                     TRUE, 0);
             break;
 
         case SCSI_SPC2_REQSENSE:
@@ -2895,8 +4409,9 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
             call_dissector (data_handle, tvb, pinfo, scsi_tree);
             break;
         }
-    }
-    else if (cmd == SCSI_CMND_SBC2) {
+        break;
+
+    case SCSI_CMND_SBC2:
         switch (opcode) {
 
         case SCSI_SBC2_FORMATUNIT:
@@ -2905,7 +4420,7 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
             break;
 
         case SCSI_SBC2_READ6:
-            dissect_scsi_rdwr6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
+            dissect_scsi_sbc2_rdwr6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
                                 TRUE);
             break;
 
@@ -2945,7 +4460,7 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
             break;
 
         case SCSI_SBC2_WRITE6:
-            dissect_scsi_rdwr6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
+            dissect_scsi_sbc2_rdwr6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
                                 TRUE);
             break;
 
@@ -2968,29 +4483,92 @@ dissect_scsi_cdb (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
             call_dissector (data_handle, tvb, pinfo, scsi_tree);
             break;
         }
-    }
-    else if (cmd == SCSI_CMND_SSC2) {
+        break;
+
+    case SCSI_CMND_SSC2:
+        switch (opcode) {
+
+        case SCSI_SSC2_READ6:
+            dissect_scsi_ssc2_read6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                                TRUE);
+            break;
+
+        case SCSI_SSC2_WRITE6:
+            dissect_scsi_ssc2_write6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                                TRUE);
+            break;
+
+        case SCSI_SSC2_WRITE_FILEMARKS_6:
+            dissect_scsi_ssc2_writefilemarks6 (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                                TRUE);
+            break;
+
+        case SCSI_SSC2_LOAD_UNLOAD:
+            dissect_scsi_ssc2_loadunload (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE);
+            break;
+
+        case SCSI_SSC2_READ_BLOCK_LIMITS:
+            dissect_scsi_ssc2_readblocklimits (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE);
+            break;
+
+        case SCSI_SSC2_READ_POSITION:
+            dissect_scsi_ssc2_readposition (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE, cdata);
+            break;
+
+        case SCSI_SSC2_REWIND:
+            dissect_scsi_ssc2_rewind (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE);
+            break;
+
+        default:
+            call_dissector (data_handle, tvb, pinfo, scsi_tree);
+            break;
+        }
+        break;
+
+    case SCSI_CMND_SMC2:
+        switch (opcode) {
+
+        case SCSI_SMC2_MOVE_MEDIUM:
+        case SCSI_SMC2_MOVE_MEDIUM_ATTACHED:
+            dissect_scsi_smc2_movemedium (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE);
+            break;
+
+        case SCSI_SMC2_READ_ELEMENT_STATUS:
+        case SCSI_SMC2_READ_ELEMENT_STATUS_ATTACHED:
+            dissect_scsi_smc2_readelementstatus (tvb, pinfo, scsi_tree, offset+1, TRUE,
+                            TRUE);
+            break;
+
+        default:
+            call_dissector (data_handle, tvb, pinfo, scsi_tree);
+            break;
+        }
+        break;
+
+    default:
         call_dissector (data_handle, tvb, pinfo, scsi_tree);
+        break;
     }
 }
 
-static void
-dissect_scsi (tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_)
-{
-}
-
 void
 dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                       guint offset, gboolean isreq, guint32 payload_len)
 {
     proto_item *ti;
-    proto_tree *scsi_tree;
+    proto_tree *scsi_tree = NULL;
     guint8 opcode = 0xFF;
     scsi_cmnd_type cmd = 0;     /* 0 is undefined type */
+    scsi_device_type devtype;
     scsi_task_data_t *cdata = NULL;
-    
+
     cdata = scsi_find_task (pinfo);
-    
+
     if (!cdata) {
         /* we have no record of this exchange and so we can't dissect the
          * payload
@@ -2999,10 +4577,12 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     }
 
     opcode = cdata->opcode;
-    cmd = cdata->devtype;
-    
+    cmd = cdata->cmd;
+    devtype = cdata->devtype;
+
     if (tree) {
-        if (cmd == SCSI_CMND_SPC2) {
+        switch (cmd) {
+        case SCSI_CMND_SPC2:
             ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
                                                  payload_len,
                                                  "SCSI Payload (%s %s)",
@@ -3010,8 +4590,9 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                                              scsi_spc2_val,
                                                              "0x%02x"),
                                                  isreq ? "Request" : "Response");
-        }
-        else if (cmd == SCSI_CMND_SBC2) {
+            break;
+
+        case SCSI_CMND_SBC2:
             ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
                                                  payload_len,
                                                  "SCSI Payload (%s %s)",
@@ -3019,18 +4600,55 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                                                              scsi_sbc2_val,
                                                              "0x%02x"),
                                                  isreq ? "Request" : "Response");
-        }
-        else {
+            break;
+
+        case SCSI_CMND_SSC2:
+            ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
+                                                 payload_len,
+                                                 "SCSI Payload (%s %s)",
+                                                 val_to_str (opcode,
+                                                             scsi_ssc2_val,
+                                                             "0x%02x"),
+                                                 isreq ? "Request" : "Response");
+            break;
+
+        case SCSI_CMND_SMC2:
+            ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
+                                                 payload_len,
+                                                 "SCSI Payload (%s %s)",
+                                                 val_to_str (opcode,
+                                                             scsi_smc2_val,
+                                                             "0x%02x"),
+                                                 isreq ? "Request" : "Response");
+            break;
+
+        default:
             ti = proto_tree_add_protocol_format (tree, proto_scsi, tvb, offset,
                                                  payload_len,
                                                  "SCSI Payload (0x%02x %s)",
                                                  opcode,
                                                  isreq ? "Request" : "Response");
+            break;
         }
 
         scsi_tree = proto_item_add_subtree (ti, ett_scsi);
+    }
 
-        if (cmd == SCSI_CMND_SPC2) {
+    if (tree == NULL) {
+        /*
+         * We have to dissect INQUIRY responses, in order to determine the
+         * types of devices.
+         *
+         * We don't bother dissecting other payload if we're not buildng
+         * a protocol tree.
+         */
+        if (cmd == SCSI_CMND_SPC2 && opcode == SCSI_SPC2_INQUIRY) {
+            dissect_scsi_inquiry (tvb, pinfo, scsi_tree, offset, isreq,
+                                  FALSE, payload_len, cdata);
+        }
+      } else {
+        switch (cmd) {
+        case SCSI_CMND_SPC2:
             switch (opcode) {
             case SCSI_SPC2_INQUIRY:
                 dissect_scsi_inquiry (tvb, pinfo, scsi_tree, offset, isreq,
@@ -3054,22 +4672,22 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
             case SCSI_SPC2_MODESELECT6:
                 dissect_scsi_modeselect6 (tvb, pinfo, scsi_tree, offset,
-                                          isreq, FALSE, payload_len);
+                                          isreq, FALSE, devtype, payload_len);
                 break;
 
             case SCSI_SPC2_MODESELECT10:
                 dissect_scsi_modeselect10 (tvb, pinfo, scsi_tree, offset,
-                                           isreq, FALSE, payload_len);
+                                           isreq, FALSE, devtype, payload_len);
                 break;
 
             case SCSI_SPC2_MODESENSE6:
                 dissect_scsi_modesense6 (tvb, pinfo, scsi_tree, offset, isreq,
-                                         FALSE, payload_len);
+                                         FALSE, devtype, payload_len);
                 break;
 
             case SCSI_SPC2_MODESENSE10:
                 dissect_scsi_modesense10 (tvb, pinfo, scsi_tree, offset,
-                                          isreq, FALSE, payload_len);
+                                          isreq, FALSE, devtype, payload_len);
                 break;
 
             case SCSI_SPC2_PERSRESVIN:
@@ -3099,7 +4717,7 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
             case SCSI_SPC2_REPORTLUNS:
                 dissect_scsi_reportluns (tvb, pinfo, scsi_tree, offset, isreq,
-                                         FALSE);
+                                         FALSE, payload_len);
                 break;
 
             case SCSI_SPC2_REQSENSE:
@@ -3126,8 +4744,9 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 call_dissector (data_handle, tvb, pinfo, scsi_tree);
                 break;
             }
-        }
-        else if (cmd == SCSI_CMND_SBC2) {
+            break;
+
+        case SCSI_CMND_SBC2:
             switch (opcode) {
 
             case SCSI_SBC2_FORMATUNIT:
@@ -3136,7 +4755,7 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 break;
 
             case SCSI_SBC2_READ6:
-                dissect_scsi_rdwr6 (tvb, pinfo, scsi_tree, offset, isreq,
+                dissect_scsi_sbc2_rdwr6 (tvb, pinfo, scsi_tree, offset, isreq,
                                     FALSE);
                 break;
 
@@ -3176,7 +4795,7 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 break;
 
             case SCSI_SBC2_WRITE6:
-                dissect_scsi_rdwr6 (tvb, pinfo, scsi_tree, offset, isreq,
+                dissect_scsi_sbc2_rdwr6 (tvb, pinfo, scsi_tree, offset, isreq,
                                     FALSE);
                 break;
 
@@ -3199,9 +4818,76 @@ dissect_scsi_payload (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                 call_dissector (data_handle, tvb, pinfo, scsi_tree);
                 break;
             }
-        }
-        else {
+            break;
+
+        case SCSI_CMND_SSC2:
+            switch (opcode) {
+
+            case SCSI_SSC2_READ6:
+                dissect_scsi_ssc2_read6 (tvb, pinfo, scsi_tree, offset, isreq,
+                                    FALSE);
+                break;
+
+            case SCSI_SSC2_WRITE6:
+                dissect_scsi_ssc2_write6 (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            case SCSI_SSC2_WRITE_FILEMARKS_6:
+                dissect_scsi_ssc2_writefilemarks6 (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            case SCSI_SSC2_LOAD_UNLOAD:
+                dissect_scsi_ssc2_loadunload (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            case SCSI_SSC2_READ_BLOCK_LIMITS:
+                dissect_scsi_ssc2_readblocklimits (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            case SCSI_SSC2_READ_POSITION:
+                dissect_scsi_ssc2_readposition (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE, cdata);
+                break;
+
+            case SCSI_SSC2_REWIND:
+                dissect_scsi_ssc2_rewind (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            default:
+                call_dissector (data_handle, tvb, pinfo, scsi_tree);
+                break;
+            }
+            break;
+
+        case SCSI_CMND_SMC2:
+            switch (opcode) {
+
+            case SCSI_SMC2_MOVE_MEDIUM:
+            case SCSI_SMC2_MOVE_MEDIUM_ATTACHED:
+                dissect_scsi_smc2_movemedium (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            case SCSI_SMC2_READ_ELEMENT_STATUS:
+            case SCSI_SMC2_READ_ELEMENT_STATUS_ATTACHED:
+                dissect_scsi_smc2_readelementstatus (tvb, pinfo, scsi_tree, offset, isreq,
+                                FALSE);
+                break;
+
+            default:
+                call_dissector (data_handle, tvb, pinfo, scsi_tree);
+                break;
+            }
+            break;
+
+        default:
             call_dissector (data_handle, tvb, pinfo, scsi_tree);
+            break;
         }
     }
 }
@@ -3220,11 +4906,14 @@ proto_register_scsi (void)
         { &hf_scsi_sscopcode,
           {"SSC-2 Opcode", "scsi.ssc.opcode", FT_UINT8, BASE_HEX,
            VALS (scsi_ssc2_val), 0x0, "", HFILL}},
+        { &hf_scsi_smcopcode,
+          {"SMC-2 Opcode", "scsi.smc.opcode", FT_UINT8, BASE_HEX,
+           VALS (scsi_smc2_val), 0x0, "", HFILL}},
         { &hf_scsi_control,
           {"Control", "scsi.cdb.control", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
         { &hf_scsi_inquiry_flags,
-          {"Flags", "scsi.inquiry.flags", FT_UINT8, BASE_BIN, NULL, 0x0, "",
+          {"Flags", "scsi.inquiry.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
         { &hf_scsi_inquiry_evpd_page,
           {"EVPD Page Code", "scsi.inquiry.evpd.pagecode", FT_UINT8, BASE_HEX,
@@ -3236,17 +4925,20 @@ proto_register_scsi (void)
           {"Allocation Length", "scsi.cdb.alloclen", FT_UINT8, BASE_DEC, NULL,
            0x0, "", HFILL}},
         { &hf_scsi_logsel_flags,
-          {"Flags", "scsi.logsel.flags", FT_UINT8, BASE_BIN, NULL, 0x0, "",
+          {"Flags", "scsi.logsel.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
-        { &hf_scsi_log_pc,
-          {"Page Control", "scsi.log.pc", FT_UINT8, BASE_BIN,
+        { &hf_scsi_logsel_pc,
+          {"Page Control", "scsi.logsel.pc", FT_UINT8, BASE_DEC,
            VALS (scsi_logsel_pc_val), 0xC0, "", HFILL}},
         { &hf_scsi_paramlen,
           {"Parameter Length", "scsi.cdb.paramlen", FT_UINT8, BASE_DEC, NULL,
            0x0, "", HFILL}},
         { &hf_scsi_logsns_flags,
-          {"Flags", "scsi.logsns.flags", FT_UINT16, BASE_BIN, NULL, 0x0, "",
+          {"Flags", "scsi.logsns.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "",
            HFILL}},
+        { &hf_scsi_logsns_pc,
+          {"Page Control", "scsi.logsns.pc", FT_UINT8, BASE_DEC,
+           VALS (scsi_logsns_pc_val), 0xC0, "", HFILL}},
         { &hf_scsi_logsns_pagecode,
           {"Page Code", "scsi.logsns.pagecode", FT_UINT8, BASE_HEX,
            VALS (scsi_logsns_page_val), 0x3F0, "", HFILL}},
@@ -3254,17 +4946,26 @@ proto_register_scsi (void)
           {"Parameter Length", "scsi.cdb.paramlen16", FT_UINT16, BASE_DEC, NULL,
            0x0, "", HFILL}},
         { &hf_scsi_modesel_flags,
-          {"Mode Sense/Select Flags", "scsi.cdb.mode.flags", FT_UINT8, BASE_BIN,
+          {"Mode Sense/Select Flags", "scsi.cdb.mode.flags", FT_UINT8, BASE_HEX,
            NULL, 0x0, "", HFILL}},
         { &hf_scsi_alloclen16,
           {"Allocation Length", "scsi.cdb.alloclen16", FT_UINT16, BASE_DEC,
            NULL, 0x0, "", HFILL}},
         { &hf_scsi_modesns_pc,
-          {"Page Control", "scsi.mode.pc", FT_UINT8, BASE_BIN,
+          {"Page Control", "scsi.mode.pc", FT_UINT8, BASE_DEC,
            VALS (scsi_modesns_pc_val), 0xC0, "", HFILL}},
-        { &hf_scsi_modesns_pagecode,
-          {"Page Code", "scsi.mode.pagecode", FT_UINT8, BASE_HEX,
-           VALS (scsi_modesns_page_val), 0x3F, "", HFILL}},
+        { &hf_scsi_spcpagecode,
+          {"SPC-2 Page Code", "scsi.mode.spc.pagecode", FT_UINT8, BASE_HEX,
+           VALS (scsi_spc2_modepage_val), 0x3F, "", HFILL}},
+        { &hf_scsi_sbcpagecode,
+          {"SBC-2 Page Code", "scsi.mode.sbc.pagecode", FT_UINT8, BASE_HEX,
+           VALS (scsi_sbc2_modepage_val), 0x3F, "", HFILL}},
+        { &hf_scsi_sscpagecode,
+          {"SSC-2 Page Code", "scsi.mode.ssc.pagecode", FT_UINT8, BASE_HEX,
+           VALS (scsi_ssc2_modepage_val), 0x3F, "", HFILL}},
+        { &hf_scsi_smcpagecode,
+          {"SMC-2 Page Code", "scsi.mode.smc.pagecode", FT_UINT8, BASE_HEX,
+           VALS (scsi_smc2_modepage_val), 0x3F, "", HFILL}},
         { &hf_scsi_modesns_flags,
           {"Flags", "scsi.mode.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
@@ -3281,7 +4982,7 @@ proto_register_scsi (void)
           {"Reservation Type", "scsi.persresv.type", FT_UINT8, BASE_HEX,
            VALS (scsi_persresv_type_val), 0x0F, "", HFILL}},
         { &hf_scsi_release_flags,
-          {"Release Flags", "scsi.release.flags", FT_UINT8, BASE_BIN, NULL,
+          {"Release Flags", "scsi.release.flags", FT_UINT8, BASE_HEX, NULL,
            0x0, "", HFILL}},
         { &hf_scsi_release_thirdpartyid,
           {"Third-Party ID", "scsi.release.thirdpartyid", FT_BYTES, BASE_HEX,
@@ -3290,10 +4991,10 @@ proto_register_scsi (void)
           {"Allocation Length", "scsi.cdb.alloclen32", FT_UINT32, BASE_DEC,
            NULL, 0x0, "", HFILL}},
         { &hf_scsi_formatunit_flags,
-          {"Flags", "scsi.formatunit.flags", FT_UINT8, BASE_BIN, NULL, 0xF8,
+          {"Flags", "scsi.formatunit.flags", FT_UINT8, BASE_HEX, NULL, 0xF8,
            "", HFILL}},
         { &hf_scsi_cdb_defectfmt,
-          {"Defect List Format", "scsi.cdb.defectfmt", FT_UINT8, BASE_BIN,
+          {"Defect List Format", "scsi.cdb.defectfmt", FT_UINT8, BASE_DEC,
            NULL, 0x7, "", HFILL}},
         { &hf_scsi_formatunit_interleave,
           {"Interleave", "scsi.formatunit.interleave", FT_UINT16, BASE_HEX,
@@ -3305,7 +5006,7 @@ proto_register_scsi (void)
           {"Logical Block Address (LBA)", "scsi.rdwr6.lba", FT_UINT24, BASE_DEC,
            NULL, 0x0FFFFF, "", HFILL}},
         { &hf_scsi_rdwr6_xferlen,
-          {"Transfer Length", "scsi.rdwr6.xferlen", FT_UINT8, BASE_DEC, NULL, 0x0,
+          {"Transfer Length", "scsi.rdwr6.xferlen", FT_UINT24, BASE_DEC, NULL, 0x0,
            "", HFILL}},
         { &hf_scsi_rdwr10_lba,
           {"Logical Block Address (LBA)", "scsi.rdwr10.lba", FT_UINT32, BASE_DEC,
@@ -3323,23 +5024,26 @@ proto_register_scsi (void)
           {"Logical Block Address (LBA)", "scsi.rdwr16.lba", FT_BYTES, BASE_DEC,
            NULL, 0x0, "", HFILL}},
         { &hf_scsi_readcapacity_flags,
-          {"Flags", "scsi.readcapacity.flags", FT_UINT8, BASE_BIN, NULL, 0x0,
+          {"Flags", "scsi.readcapacity.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
            "", HFILL}},
         { &hf_scsi_readcapacity_lba,
           {"Logical Block Address", "scsi.readcapacity.lba", FT_UINT32, BASE_DEC,
            NULL, 0x0, "", HFILL}},
         { &hf_scsi_readcapacity_pmi,
-          {"PMI", "scsi.readcapacity.pmi", FT_UINT8, BASE_BIN, NULL, 0x1, "",
+          {"PMI", "scsi.readcapacity.pmi", FT_UINT8, BASE_DEC, NULL, 0x1, "",
            HFILL}},
         { &hf_scsi_readdefdata_flags,
-          {"Flags", "scsi.readdefdata.flags", FT_UINT8, BASE_BIN, NULL, 0x0, "",
+          {"Flags", "scsi.readdefdata.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
         { &hf_scsi_reassignblks_flags,
-          {"Flags", "scsi.reassignblks.flags", FT_UINT8, BASE_BIN, NULL, 0x0, "",
+          {"Flags", "scsi.reassignblks.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "",
            HFILL}},
+        { &hf_scsi_inq_qualifier,
+          {"Peripheral Qualifier", "scsi.inquiry.qualifier", FT_UINT8, BASE_HEX,
+           VALS (scsi_qualifier_val), 0xE0, "", HFILL}},
         { &hf_scsi_inq_devtype,
-          {"Device Type", "scsi.inquiry.devtype", FT_UINT8, BASE_HEX,
-           VALS (scsi_devtype_val), 0x0F, "", HFILL}},
+          {"Peripheral Device Type", "scsi.inquiry.devtype", FT_UINT8, BASE_HEX,
+           VALS (scsi_devtype_val), SCSI_DEV_BITS, "", HFILL}},
         { & hf_scsi_inq_version,
           {"Version", "scsi.inquiry.version", FT_UINT8, BASE_HEX,
            VALS (scsi_inquiry_vers_val), 0x0, "", HFILL}},
@@ -3356,7 +5060,7 @@ proto_register_scsi (void)
           {"MRIE", "scsi.mode.mrie", FT_UINT8, BASE_HEX,
            VALS (scsi_modesns_mrie_val), 0x0F, "", HFILL}},
         { &hf_scsi_modesns_tst,
-          {"Task Set Type", "scsi.mode.tst", FT_UINT8, BASE_BIN,
+          {"Task Set Type", "scsi.mode.tst", FT_UINT8, BASE_DEC,
            VALS (scsi_modesns_tst_val), 0xE0, "", HFILL}},
         { &hf_scsi_modesns_qmod,
           {"Queue Algorithm Modifier", "scsi.mode.qmod", FT_UINT8, BASE_HEX,
@@ -3420,7 +5124,7 @@ proto_register_scsi (void)
         &ett_scsi_page,
     };
     module_t *scsi_module;
-    
+
     /* Register the protocol name and description */
     proto_scsi = proto_register_protocol("SCSI", "SCSI", "scsi");
 
@@ -3428,7 +5132,6 @@ proto_register_scsi (void)
     proto_register_field_array(proto_scsi, hf, array_length(hf));
     proto_register_subtree_array(ett, array_length(ett));
     register_init_routine (&scsi_init_protocol);
-    register_dissector ("SCSI", dissect_scsi, proto_scsi);
     data_handle = find_dissector ("data");
 
     /* add preferences to decode SCSI message */