Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp	(revision 38680)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -15,4 +15,7 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  */
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
 #define LOG_GROUP LOG_GROUP_VSCSI
 #include <VBox/log.h>
@@ -81,5 +84,5 @@
              */
             if (vscsiBE2HU32(&pVScsiReq->pbCDB[6]) < 16)
-                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
+                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
             else
             {
@@ -91,5 +94,5 @@
                 cbData = RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
                 if (cbData < 16)
-                    *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
+                    *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
                 else
                     *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
@@ -106,5 +109,5 @@
             /* Descriptor format sense data is not supported and results in an error. */
             if ((pVScsiReq->pbCDB[1] & 0x1) != 0)
-                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
+                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
             else
                 *prcReq = vscsiReqSenseCmd(&pVScsiDevice->VScsiSense, pVScsiReq);
@@ -293,5 +296,6 @@
             vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq,
                                   SCSI_SENSE_ILLEGAL_REQUEST,
-                                  SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION);
+                                  SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION,
+                                  0x00);
 
             vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
@@ -333,5 +337,6 @@
     pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;
 
-    RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);
+    if (cSGListEntries)
+        RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);
 
     *phVScsiReq = pVScsiReq;
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h	(revision 38680)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -22,6 +22,8 @@
 #include <iprt/memcache.h>
 #include <iprt/sg.h>
+#include <iprt/list.h>
 
 #include "VSCSIInline.h"
+#include "VSCSIVpdPages.h"
 
 /** Pointer to an internal virtual SCSI device. */
@@ -84,4 +86,6 @@
     /** Pointer to the LUN type descriptor. */
     PVSCSILUNDESC        pVScsiLunDesc;
+    /** Flags of supported features. */
+    uint64_t             fFeatures;
     /** I/O request processing data */
     struct
@@ -119,20 +123,47 @@
 {
     /** The associated request. */
-    PVSCSIREQINT        pVScsiReq;
+    PVSCSIREQINT           pVScsiReq;
     /** Lun for this I/O request. */
-    PVSCSILUNINT        pVScsiLun;
+    PVSCSILUNINT           pVScsiLun;
     /** Transfer direction */
-    VSCSIIOREQTXDIR     enmTxDir;
-    /** Start offset */
-    uint64_t            uOffset;
-    /** Number of bytes to transfer */
-    size_t              cbTransfer;
-    /** Number of bytes the S/G list holds */
-    size_t              cbSeg;
-    /** Number of segments. */
-    unsigned            cSeg;
-    /** Segment array. */
-    PCRTSGSEG           paSeg;
+    VSCSIIOREQTXDIR        enmTxDir;
+    /** Direction dependent data. */
+    union
+    {
+        /** Read/Write request. */
+        struct
+        {
+            /** Start offset */
+            uint64_t       uOffset;
+            /** Number of bytes to transfer */
+            size_t         cbTransfer;
+            /** Number of bytes the S/G list holds */
+            size_t         cbSeg;
+            /** Number of segments. */
+            unsigned       cSeg;
+            /** Segment array. */
+            PCRTSGSEG      paSeg;
+        } Io;
+        /** Unmape request. */
+        struct
+        {
+            /** Array of ranges to unmap. */
+            PVSCSIRANGE    paRanges;
+            /** Number of ranges. */
+            unsigned       cRanges;
+        } Unmap;
+    } u;
 } VSCSIIOREQINT;
+
+/**
+ * VPD page pool.
+ */
+typedef struct VSCSIVPDPOOL
+{
+    /** List of registered pages. */
+    RTLISTNODE    ListPages;
+} VSCSIVPDPOOL;
+/** Pointer to the VSCSI VPD page pool. */
+typedef VSCSIVPDPOOL *PVSCSIVPDPOOL;
 
 /**
@@ -217,6 +248,8 @@
  * @param   uSCSISenseKey The SCSI sense key to set.
  * @param   uSCSIASC      The ASC value.
- */
-int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC);
+ * @param   uSCSIASC      The ASCQ value.
+ */
+int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey,
+                          uint8_t uSCSIASC, uint8_t uSCSIASCQ);
 
 /**
@@ -228,4 +261,44 @@
  */
 int vscsiReqSenseCmd(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq);
+
+/**
+ * Inits the VPD page pool.
+ *
+ * @returns VBox status code.
+ * @param   pVScsiVpdPool    The VPD page pool to initialize.
+ */
+int vscsiVpdPagePoolInit(PVSCSIVPDPOOL pVScsiVpdPool);
+
+/**
+ * Destroys the given VPD page pool freeing all pages in it.
+ *
+ * @returns nothing.
+ * @param   pVScsiVpdPool    The VPD page pool to destroy.
+ */
+void vscsiVpdPagePoolDestroy(PVSCSIVPDPOOL pVScsiVpdPool);
+
+/**
+ * Allocates a new page in the VPD page pool with the given number.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_ALREADY_EXIST if the page number is in use.
+ * @param   pVScsiVpdPool    The VPD page pool the page will belong to.
+ * @param   uPage            The page number, must be unique.
+ * @param   cbPage           Size of the page in bytes.
+ * @param   ppbPage          Where to store the pointer to the raw page data on success.
+ */
+int vscsiVpdPagePoolAllocNewPage(PVSCSIVPDPOOL pVScsiVpdPool, uint8_t uPage, size_t cbPage, uint8_t **ppbPage);
+
+/**
+ * Queries the given page from the pool and cpies it to the buffer given
+ * by the SCSI request.
+ *
+ * @returns VBox status code.
+ * @retval  VERR_NOT_FOUND if the page is not in the pool.
+ * @param   pVScsiVpdPool    The VPD page pool to use.
+ * @param   pVScsiReq        The SCSI request.
+ * @param   uPage            Page to query.
+ */
+int vscsiVpdPagePoolQueryPage(PVSCSIVPDPOOL pVScsiVpdPool, PVSCSIREQINT pVScsiReq, uint8_t uPage);
 
 /**
@@ -253,4 +326,16 @@
 
 /**
+ * Enqueue a new unmap request.
+ *
+ * @returns VBox status code.
+ * @param   pVScsiLun   The LUN instance which issued the request.
+ * @param   pVScsiReq   The virtual SCSI request associated with the transfer.
+ * @param   paRanges    The array of ranges to unmap.
+ * @param   cRanges     Number of ranges in the array.
+ */
+int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
+                           PVSCSIRANGE paRanges, unsigned cRanges);
+
+/**
  * Returns the current number of outstanding tasks on the given LUN.
  *
@@ -289,4 +374,18 @@
 
 /**
+ * Wrapper for the get feature flags I/O callback.
+ *
+ * @returns VBox status code.
+ * @param   pVScsiLun   The LUN.
+ * @param   pVScsiIoReq The I/O request to enqueue.
+ */
+DECLINLINE(int) vscsiLunGetFeatureFlags(PVSCSILUNINT pVScsiLun, uint64_t *pfFeatures)
+{
+    return pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunGetFeatureFlags(pVScsiLun,
+                                                                       pVScsiLun->pvVScsiLunUser,
+                                                                       pfFeatures);
+}
+
+/**
  * Wrapper around vscsiReqSenseOkSet()
  */
@@ -299,7 +398,7 @@
  * Wrapper around vscsiReqSenseErrorSet()
  */
-DECLINLINE(int) vscsiLunReqSenseErrorSet(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
-{
-    return vscsiReqSenseErrorSet(&pVScsiLun->pVScsiDevice->VScsiSense, pVScsiReq, uSCSISenseKey, uSCSIASC);
+DECLINLINE(int) vscsiLunReqSenseErrorSet(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC, uint8_t uSCSIASCQ)
+{
+    return vscsiReqSenseErrorSet(&pVScsiLun->pVScsiDevice->VScsiSense, pVScsiReq, uSCSISenseKey, uSCSIASC, uSCSIASCQ);
 }
 
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp	(revision 38680)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -66,11 +66,43 @@
         return VERR_NO_MEMORY;
 
-    pVScsiIoReq->pVScsiReq  = pVScsiReq;
-    pVScsiIoReq->pVScsiLun  = pVScsiLun;
-    pVScsiIoReq->enmTxDir   = enmTxDir;
-    pVScsiIoReq->uOffset    = uOffset;
-    pVScsiIoReq->cbTransfer = cbTransfer;
-    pVScsiIoReq->paSeg      = pVScsiReq->SgBuf.paSegs;
-    pVScsiIoReq->cSeg       = pVScsiReq->SgBuf.cSegs;
+    pVScsiIoReq->pVScsiReq       = pVScsiReq;
+    pVScsiIoReq->pVScsiLun       = pVScsiLun;
+    pVScsiIoReq->enmTxDir        = enmTxDir;
+    pVScsiIoReq->u.Io.uOffset    = uOffset;
+    pVScsiIoReq->u.Io.cbTransfer = cbTransfer;
+    pVScsiIoReq->u.Io.paSeg      = pVScsiReq->SgBuf.paSegs;
+    pVScsiIoReq->u.Io.cSeg       = pVScsiReq->SgBuf.cSegs;
+
+    ASMAtomicIncU32(&pVScsiLun->IoReq.cReqOutstanding);
+
+    rc = vscsiLunReqTransferEnqueue(pVScsiLun, pVScsiIoReq);
+    if (RT_FAILURE(rc))
+    {
+        ASMAtomicDecU32(&pVScsiLun->IoReq.cReqOutstanding);
+        RTMemFree(pVScsiIoReq);
+    }
+
+    return rc;
+}
+
+
+int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
+                           PVSCSIRANGE paRanges, unsigned cRanges)
+{
+    int rc = VINF_SUCCESS;
+    PVSCSIIOREQINT pVScsiIoReq = NULL;
+
+    LogFlowFunc(("pVScsiLun=%#p pVScsiReq=%#p paRanges=%#p cRanges=%u\n",
+                 pVScsiLun, pVScsiReq, paRanges, cRanges));
+
+    pVScsiIoReq = (PVSCSIIOREQINT)RTMemAllocZ(sizeof(VSCSIIOREQINT));
+    if (!pVScsiIoReq)
+        return VERR_NO_MEMORY;
+
+    pVScsiIoReq->pVScsiReq        = pVScsiReq;
+    pVScsiIoReq->pVScsiLun        = pVScsiLun;
+    pVScsiIoReq->enmTxDir         = VSCSIIOREQTXDIR_UNMAP;
+    pVScsiIoReq->u.Unmap.paRanges = paRanges;
+    pVScsiIoReq->u.Unmap.cRanges  = cRanges;
 
     ASMAtomicIncU32(&pVScsiLun->IoReq.cReqOutstanding);
@@ -112,5 +144,4 @@
     ASMAtomicDecU32(&pVScsiLun->IoReq.cReqOutstanding);
 
-    /** @todo error reporting */
     if (RT_SUCCESS(rcIoReq))
         rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
@@ -122,8 +153,12 @@
                                          pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_READ
                                          ? SCSI_ASC_READ_ERROR
-                                         : SCSI_ASC_WRITE_ERROR);
+                                         : SCSI_ASC_WRITE_ERROR,
+                                         0x00);
     }
     else
         rcReq = SCSI_STATUS_CHECK_CONDITION;
+
+    if (pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_UNMAP)
+        RTMemFree(pVScsiIoReq->u.Unmap.paRanges);
 
     /* Free the I/O request */
@@ -154,13 +189,29 @@
 
     AssertPtrReturn(pVScsiIoReq, VERR_INVALID_HANDLE);
-    AssertReturn(pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_FLUSH, VERR_NOT_SUPPORTED);
-
-    *puOffset    = pVScsiIoReq->uOffset;
-    *pcbTransfer = pVScsiIoReq->cbTransfer;
-    *pcSeg       = pVScsiIoReq->cSeg;
-    *pcbSeg      = pVScsiIoReq->cbSeg;
-    *ppaSeg      = pVScsiIoReq->paSeg;
+    AssertReturn(   pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_FLUSH
+                 && pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_UNMAP,
+                 VERR_NOT_SUPPORTED);
+
+    *puOffset    = pVScsiIoReq->u.Io.uOffset;
+    *pcbTransfer = pVScsiIoReq->u.Io.cbTransfer;
+    *pcSeg       = pVScsiIoReq->u.Io.cSeg;
+    *pcbSeg      = pVScsiIoReq->u.Io.cbSeg;
+    *ppaSeg      = pVScsiIoReq->u.Io.paSeg;
 
     return VINF_SUCCESS;
 }
 
+VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PVSCSIRANGE *ppaRanges,
+                                           unsigned *pcRanges)
+{
+    PVSCSIIOREQINT pVScsiIoReq = hVScsiIoReq;
+
+    AssertPtrReturn(pVScsiIoReq, VERR_INVALID_HANDLE);
+    AssertReturn(pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_UNMAP, VERR_NOT_SUPPORTED);
+
+    *ppaRanges = pVScsiIoReq->u.Unmap.paRanges;
+    *pcRanges  = pVScsiIoReq->u.Unmap.cRanges;
+
+    return VINF_SUCCESS;
+}
+
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp	(revision 38680)
@@ -71,10 +71,13 @@
     pVScsiLun->pVScsiLunDesc        = pVScsiLunDesc;
 
-    int rc = pVScsiLunDesc->pfnVScsiLunInit(pVScsiLun);
+    int rc = vscsiLunGetFeatureFlags(pVScsiLun, &pVScsiLun->fFeatures);
     if (RT_SUCCESS(rc))
     {
-        /** @todo Init other stuff */
-        *phVScsiLun = pVScsiLun;
-        return VINF_SUCCESS;
+        rc = pVScsiLunDesc->pfnVScsiLunInit(pVScsiLun);
+        if (RT_SUCCESS(rc))
+        {
+            *phVScsiLun = pVScsiLun;
+            return VINF_SUCCESS;
+        }
     }
 
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp	(revision 38680)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -24,4 +24,6 @@
 #include <VBox/types.h>
 #include <VBox/vscsi.h>
+#include <iprt/cdefs.h>
+#include <iprt/asm.h>
 #include <iprt/assert.h>
 #include <iprt/mem.h>
@@ -29,4 +31,7 @@
 
 #include "VSCSIInternal.h"
+
+/** Maximum of amount of LBAs to unmap with one command. */
+#define VSCSI_UNMAP_LBAS_MAX ((10*_1M) / 512)
 
 /**
@@ -39,4 +44,6 @@
     /** Size of the virtual disk. */
     uint64_t       cSectors;
+    /** VPD page pool. */
+    VSCSIVPDPOOL   VpdPagePool;
 } VSCSILUNSBC;
 /** Pointer to a SBC LUN instance */
@@ -48,4 +55,5 @@
     uint64_t cbDisk = 0;
     int rc = VINF_SUCCESS;
+    int cVpdPages = 0;
 
     rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
@@ -53,4 +61,92 @@
         pVScsiLunSbc->cSectors = cbDisk / 512; /* Fixed sector size */
 
+    if (RT_SUCCESS(rc))
+        rc = vscsiVpdPagePoolInit(&pVScsiLunSbc->VpdPagePool);
+
+    if (   RT_SUCCESS(rc)
+        && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP))
+    {
+        PVSCSIVPDPAGEBLOCKLIMITS pBlkPage;
+        PVSCSIVPDPAGEBLOCKPROV   pBlkProvPage;
+
+        /* Create the page and fill it. */
+        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_LIMITS_NUMBER,
+                                          VSCSI_VPD_BLOCK_LIMITS_SIZE, (uint8_t **)&pBlkPage);
+        if (RT_SUCCESS(rc))
+        {
+                pBlkPage->u5PeripheralDeviceType       = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
+                pBlkPage->u3PeripheralQualifier        = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
+                pBlkPage->u16PageLength                = RT_H2BE_U16(0x3c);
+                pBlkPage->u8MaxCmpWriteLength          = 0;
+                pBlkPage->u16OptTrfLengthGran          = 0;
+                pBlkPage->u32MaxTrfLength              = 0;
+                pBlkPage->u32OptTrfLength              = 0;
+                pBlkPage->u32MaxPreXdTrfLength         = 0;
+                pBlkPage->u32MaxUnmapLbaCount          = RT_H2BE_U32(VSCSI_UNMAP_LBAS_MAX);
+                pBlkPage->u32MaxUnmapBlkDescCount      = UINT32_C(0xffffffff);
+                pBlkPage->u32OptUnmapGranularity       = 0;
+                pBlkPage->u32UnmapGranularityAlignment = 0;
+                cVpdPages++;
+        }
+
+        if (RT_SUCCESS(rc))
+        {
+            rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_PROV_NUMBER,
+                                              VSCSI_VPD_BLOCK_PROV_SIZE, (uint8_t **)&pBlkProvPage);
+            if (RT_SUCCESS(rc))
+            {
+                pBlkProvPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
+                pBlkProvPage->u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
+                pBlkProvPage->u16PageLength          = RT_H2BE_U16(0x4);
+                pBlkProvPage->u8ThresholdExponent    = 1;
+                pBlkProvPage->fLBPU                  = true;
+                cVpdPages++;
+            }
+        }
+    }
+
+    if (   RT_SUCCESS(rc)
+        && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL))
+    {
+        PVSCSIVPDPAGEBLOCKCHARACTERISTICS pBlkPage;
+
+        /* Create the page and fill it. */
+        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER,
+                                          VSCSI_VPD_BLOCK_CHARACTERISTICS_SIZE, (uint8_t **)&pBlkPage);
+        if (RT_SUCCESS(rc))
+        {
+                pBlkPage->u5PeripheralDeviceType       = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
+                pBlkPage->u3PeripheralQualifier        = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
+                pBlkPage->u16PageLength                = RT_H2BE_U16(0x3c);
+                pBlkPage->u16MediumRotationRate        = RT_H2BE_U16(VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NON_ROTATING);
+                cVpdPages++;
+        }
+    }
+
+    if (   RT_SUCCESS(rc)
+        && cVpdPages)
+    {
+        PVSCSIVPDPAGESUPPORTEDPAGES pVpdPages;
+
+        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_SUPPORTED_PAGES_NUMBER,
+                                          VSCSI_VPD_SUPPORTED_PAGES_SIZE + cVpdPages - 1, (uint8_t **)&pVpdPages);
+        if (RT_SUCCESS(rc))
+        {
+            unsigned idxVpdPage = 0;
+            pVpdPages->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
+            pVpdPages->u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
+            pVpdPages->u16PageLength          = RT_H2BE_U16(cVpdPages);
+
+            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
+            {
+                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_LIMITS_NUMBER;
+                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_PROV_NUMBER;
+            }
+
+            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL)
+                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER;
+        }
+    }
+
     return rc;
 }
@@ -59,4 +155,6 @@
 {
     PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
+
+    vscsiVpdPagePoolDestroy(&pVScsiLunSbc->VpdPagePool);
 
     return VINF_SUCCESS;
@@ -76,20 +174,39 @@
         case SCSI_INQUIRY:
         {
-            SCSIINQUIRYDATA ScsiInquiryReply;
-
-            memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
-
-            ScsiInquiryReply.cbAdditional           = 31;
-            ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
-            ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
-            ScsiInquiryReply.u3AnsiVersion          = 0x05; /* SPC-4 compliant */
-            ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
-            ScsiInquiryReply.fWBus16                = 1;
-            vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
-            vscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
-            vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
-
-            RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
-            rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+            /* Check for EVPD bit. */
+            if (pVScsiReq->pbCDB[1] & 0x1)
+            {
+                rc = vscsiVpdPagePoolQueryPage(&pVScsiLunSbc->VpdPagePool, pVScsiReq, pVScsiReq->pbCDB[2]);
+                if (RT_UNLIKELY(rc == VERR_NOT_FOUND))
+                {
+                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
+                                                     SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+                    rc = VINF_SUCCESS;
+                }
+                else
+                    rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+            }
+            else if (pVScsiReq->pbCDB[2] != 0) /* A non zero page code is an error. */
+                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
+                                                 SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+            else
+            {
+                SCSIINQUIRYDATA ScsiInquiryReply;
+
+                memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
+
+                ScsiInquiryReply.cbAdditional           = 31;
+                ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
+                ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
+                ScsiInquiryReply.u3AnsiVersion          = 0x05; /* SPC-4 compliant */
+                ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
+                ScsiInquiryReply.fWBus16                = 1;
+                vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
+                vscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
+                vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
+
+                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
+                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+            }
             break;
         }
@@ -263,5 +380,5 @@
                 }
                 default:
-                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
+                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
             }
             break;
@@ -278,4 +395,6 @@
                     vscsiH2BEU64(aReply, pVScsiLunSbc->cSectors - 1);
                     vscsiH2BEU32(&aReply[8], 512);
+                    if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
+                        aReply[14] = 0x80; /* LPME enabled */
                     /* Leave the rest 0 */
 
@@ -285,11 +404,69 @@
                 }
                 default:
-                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); /* Don't know if this is correct */
-            }
+                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
+            }
+            break;
+        }
+        case SCSI_UNMAP:
+        {
+            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
+            {
+                uint8_t abHdr[8];
+                size_t cbCopied;
+                size_t cbList = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
+
+                /* Copy the header. */
+                cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abHdr[0], sizeof(abHdr));
+
+                /* Using the anchor bit is not supported. */
+                if (   !(pVScsiReq->pbCDB[1] & 0x01)
+                    && cbCopied == sizeof(abHdr)
+                    && cbList >= 8)
+                {
+                    size_t cBlkDesc = vscsiBE2HU16(&abHdr[2]) / 16;
+
+                    if (cBlkDesc)
+                    {
+                        PVSCSIRANGE paRanges;
+
+                        paRanges = (PVSCSIRANGE)RTMemAllocZ(cBlkDesc * sizeof(PVSCSIRANGE));
+                        if (paRanges)
+                        {
+                            for (unsigned i = 0; i < cBlkDesc; i++)
+                            {
+                                uint8_t abBlkDesc[16];
+
+                                cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abBlkDesc[0], sizeof(abBlkDesc));
+                                if (RT_UNLIKELY(cbCopied != sizeof(abBlkDesc)))
+                                {
+                                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+                                    break;
+                                }
+
+                                paRanges[i].offStart = vscsiBE2HU64(&abBlkDesc[0]) * 512;
+                                paRanges[i].cbRange = vscsiBE2HU32(&abBlkDesc[8]) * 512;
+                            }
+
+                            if (rcReq == SCSI_STATUS_OK)
+                                rc = vscsiIoReqUnmapEnqueue(pVScsiLun, pVScsiReq, paRanges, cBlkDesc);
+                        }
+                        else /* Out of memory. */
+                            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_SYSTEM_RESOURCE_FAILURE,
+                                                             SCSI_ASCQ_SYSTEM_BUFFER_FULL);
+                    }
+                    else /* No block descriptors is not an error condition. */
+                        rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+                }
+                else /* Invalid CDB. */
+                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+            }
+            else
+                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
+
             break;
         }
         default:
             //AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
-            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
+            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
     }
 
@@ -301,5 +478,5 @@
         if (RT_UNLIKELY(uLbaStart + cSectorTransfer > pVScsiLunSbc->cSectors))
         {
-            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
+            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
             vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
         }
@@ -316,5 +493,5 @@
         rc = vscsiIoReqFlushEnqueue(pVScsiLun, pVScsiReq);
     }
-    else /* Request completed */
+    else if (pVScsiReq->pbCDB[0] !=  SCSI_UNMAP) /* Request completed */
         vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
 
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp	(revision 38678)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp	(revision 38680)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -43,5 +43,5 @@
 }
 
-int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
+int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC, uint8_t uSCSIASCQ)
 {
     memset(pVScsiSense->abSenseBuf, 0, sizeof(pVScsiSense->abSenseBuf));
@@ -50,5 +50,5 @@
     pVScsiSense->abSenseBuf[7]  = 10;
     pVScsiSense->abSenseBuf[12] = uSCSIASC;
-    pVScsiSense->abSenseBuf[13] = 0x00; /** @todo: Provide more info. */
+    pVScsiSense->abSenseBuf[13] = uSCSIASCQ;
 
     if (pVScsiReq->pbSense && pVScsiReq->cbSense)
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPagePool.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPagePool.cpp	(revision 38680)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPagePool.cpp	(revision 38680)
@@ -0,0 +1,114 @@
+/* $Id$ */
+/** @file
+ * Virtual SCSI driver: VPD page pool
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_VSCSI
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <iprt/mem.h>
+#include <iprt/assert.h>
+
+#include "VSCSIInternal.h"
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+
+/**
+ * A VSCSI VPD page.
+ */
+typedef struct VSCSIVPDPAGE
+{
+    /** List node. */
+    RTLISTNODE    NodePages;
+    /** Page size. */
+    size_t        cbPage;
+    /** Page data - variable size. */
+    uint8_t       abPage[1];
+} VSCSIVPDPAGE;
+/** Pointer to a VPD page. */
+typedef VSCSIVPDPAGE *PVSCSIVPDPAGE;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+
+int vscsiVpdPagePoolInit(PVSCSIVPDPOOL pVScsiVpdPool)
+{
+    RTListInit(&pVScsiVpdPool->ListPages);
+    return VINF_SUCCESS;
+}
+
+
+void vscsiVpdPagePoolDestroy(PVSCSIVPDPOOL pVScsiVpdPool)
+{
+    PVSCSIVPDPAGE pIt, pItNext;
+
+    RTListForEachSafe(&pVScsiVpdPool->ListPages, pIt, pItNext, VSCSIVPDPAGE, NodePages)
+    {
+        RTListNodeRemove(&pIt->NodePages);
+        RTMemFree(pIt);
+    }
+}
+
+
+int vscsiVpdPagePoolAllocNewPage(PVSCSIVPDPOOL pVScsiVpdPool, uint8_t uPage, size_t cbPage, uint8_t **ppbPage)
+{
+    int rc = VINF_SUCCESS;
+    PVSCSIVPDPAGE pPage;
+
+    /* Check that the page doesn't exist already. */
+    RTListForEach(&pVScsiVpdPool->ListPages, pPage, VSCSIVPDPAGE, NodePages)
+    {
+        if (pPage->abPage[1] == uPage)
+            return VERR_ALREADY_EXISTS;
+    }
+
+    pPage = (PVSCSIVPDPAGE)RTMemAllocZ(RT_OFFSETOF(VSCSIVPDPAGE, abPage[cbPage]));
+    if (pPage)
+    {
+        pPage->cbPage    = cbPage;
+        pPage->abPage[1] = uPage;
+        RTListAppend(&pVScsiVpdPool->ListPages, &pPage->NodePages);
+        *ppbPage = &pPage->abPage[0];
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+
+int vscsiVpdPagePoolQueryPage(PVSCSIVPDPOOL pVScsiVpdPool, PVSCSIREQINT pVScsiReq, uint8_t uPage)
+{
+    PVSCSIVPDPAGE pPage;
+
+    /* Check that the page doesn't exist already. */
+    RTListForEach(&pVScsiVpdPool->ListPages, pPage, VSCSIVPDPAGE, NodePages)
+    {
+        if (pPage->abPage[1] == uPage)
+        {
+            RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, &pPage->abPage[0], pPage->cbPage);
+            return VINF_SUCCESS;
+        }
+    }
+
+    return VERR_NOT_FOUND;
+}
+
Index: trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPages.h
===================================================================
--- trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPages.h	(revision 38680)
+++ trunk/src/VBox/Devices/Storage/VSCSI/VSCSIVpdPages.h	(revision 38680)
@@ -0,0 +1,174 @@
+/* $Id$ */
+/** @file
+ * Virtual SCSI driver: Definitions for VPD pages.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#ifndef ___VSCSIVpdPages_h
+#define ___VSCSIVpdPages_h
+
+#include <iprt/stdint.h>
+
+/** VPD supported VPD pages page number. */
+#define VSCSI_VPD_SUPPORTED_PAGES_NUMBER 0x00
+/** VPD supported VPD pages size. */
+#define VSCSI_VPD_SUPPORTED_PAGES_SIZE   4
+/**
+ * Block limits VPD page data.
+ */
+#pragma pack(1)
+typedef struct VSCSIVPDPAGESUPPORTEDPAGES
+{
+    /** Device type. */
+    unsigned u5PeripheralDeviceType : 5;    /**< 0x00 / 00 */
+    /** Qualifier. */
+    unsigned u3PeripheralQualifier  : 3;
+    /** Page number. */
+    uint8_t  u8PageCode;
+    /** Page size (Big endian) */
+    uint16_t u16PageLength;
+    /** Supported pages array - variable. */
+    uint8_t  abVpdPages[1];
+} VSCSIVPDPAGESUPPORTEDPAGES;
+#pragma pack()
+AssertCompileSize(VSCSIVPDPAGESUPPORTEDPAGES, VSCSI_VPD_SUPPORTED_PAGES_SIZE+1);
+typedef VSCSIVPDPAGESUPPORTEDPAGES *PVSCSIVPDPAGESUPPORTEDPAGES;
+typedef const VSCSIVPDPAGESUPPORTEDPAGES *PCVSCSIVPDPAGESUPPORTEDPAGES;
+
+/** VPD block characteristics page number. */
+#define VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER 0xb1
+/** VPD block characteristics size. */
+#define VSCSI_VPD_BLOCK_CHARACTERISTICS_SIZE   64
+/**
+ * Block limits VPD page data.
+ */
+#pragma pack(1)
+typedef struct VSCSIVPDPAGEBLOCKCHARACTERISTICS
+{
+    /** Device type. */
+    unsigned u5PeripheralDeviceType : 5;    /**< 0x00 / 00 */
+    /** Qualifier. */
+    unsigned u3PeripheralQualifier  : 3;
+    /** Page number. */
+    uint8_t  u8PageCode;
+    /** Page size (Big endian) */
+    uint16_t u16PageLength;
+    /** Medium rotation rate. */
+    uint16_t u16MediumRotationRate;
+    /** Reserved. */
+    uint8_t  u8Reserved;
+    /** Nominal form factor. */
+    unsigned u4NominalFormFactor    : 4;
+    /** Reserved */
+    unsigned u4Reserved             : 4;
+    /** Reserved. */
+    uint8_t  abReserved[56];
+} VSCSIVPDPAGEBLOCKCHARACTERISTICS;
+#pragma pack()
+AssertCompileSize(VSCSIVPDPAGEBLOCKCHARACTERISTICS, VSCSI_VPD_BLOCK_CHARACTERISTICS_SIZE);
+typedef VSCSIVPDPAGEBLOCKCHARACTERISTICS *PVSCSIVPDPAGEBLOCKCHARACTERISTICS;
+typedef const VSCSIVPDPAGEBLOCKCHARACTERISTICS *PCVSCSIVPDPAGEBLOCKCHARACTERISTICS;
+
+#define VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NOT_REPORTED UINT16_C(0x0000)
+#define VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NON_ROTATING UINT16_C(0x0001)
+
+/** VPD block limits page number. */
+#define VSCSI_VPD_BLOCK_LIMITS_NUMBER 0xb0
+/** VPD block limits size. */
+#define VSCSI_VPD_BLOCK_LIMITS_SIZE   64
+/**
+ * Block limits VPD page data.
+ */
+#pragma pack(1)
+typedef struct VSCSIVPDPAGEBLOCKLIMITS
+{
+    /** Device type. */
+    unsigned u5PeripheralDeviceType : 5;    /**< 0x00 / 00 */
+    /** Qualifier. */
+    unsigned u3PeripheralQualifier  : 3;
+    /** Page number. */
+    uint8_t  u8PageCode;
+    /** Page size (Big endian) */
+    uint16_t u16PageLength;
+    /** Reserved. */
+    uint8_t  u8Reserved;
+    /** Maximum compare and write length. */
+    uint8_t  u8MaxCmpWriteLength;
+    /** Optimal transfer length granularity. */
+    uint16_t u16OptTrfLengthGran;
+    /** Maximum transfer length. */
+    uint32_t u32MaxTrfLength;
+    /** Optimal transfer length. */
+    uint32_t u32OptTrfLength;
+    /** Maximum PREFETCH, XDREAD and XDWRITE transfer length. */
+    uint32_t u32MaxPreXdTrfLength;
+    /** Maximum UNMAP LBA count. */
+    uint32_t u32MaxUnmapLbaCount;
+    /** Maximum UNMAP block descriptor count. */
+    uint32_t u32MaxUnmapBlkDescCount;
+    /** Optimal UNMAP granularity. */
+    uint32_t u32OptUnmapGranularity;
+    /** UNMAP granularity alignment. */
+    uint32_t u32UnmapGranularityAlignment;
+    /** Reserved. */
+    uint8_t  abReserved[28];
+} VSCSIVPDPAGEBLOCKLIMITS;
+#pragma pack()
+AssertCompileSize(VSCSIVPDPAGEBLOCKLIMITS, VSCSI_VPD_BLOCK_LIMITS_SIZE);
+typedef VSCSIVPDPAGEBLOCKLIMITS *PVSCSIVPDPAGEBLOCKLIMITS;
+typedef const VSCSIVPDPAGEBLOCKLIMITS *PCVSCSIVPDPAGEBLOCKLIMITS;
+
+/** VPD block provisioning page number. */
+#define VSCSI_VPD_BLOCK_PROV_NUMBER 0xb2
+/** VPD block provisioning size. */
+#define VSCSI_VPD_BLOCK_PROV_SIZE   8
+/**
+ * Block provisioning VPD page data.
+ */
+#pragma pack(1)
+typedef struct VSCSIVPDPAGEBLOCKPROV
+{
+    /** Device type. */
+    unsigned u5PeripheralDeviceType : 5;    /**< 0x00 / 00 */
+    /** Qualifier. */
+    unsigned u3PeripheralQualifier  : 3;
+    /** Page number. */
+    uint8_t  u8PageCode;
+    /** Page size (Big endian) */
+    uint16_t u16PageLength;
+    /** Threshold exponent. */
+    uint8_t  u8ThresholdExponent;
+    /** Descriptor present. */
+    bool     fDP                    : 1;
+    /** Anchored LBAs supported. */
+    bool     fAncSup                : 1;
+    /** Reserved. */
+    unsigned u4Reserved             : 4;
+    /** WRITE SAME command supported. */
+    bool     fLBPWS                 : 1;
+    /** UNMAP command supported. */
+    bool     fLBPU                  : 1;
+    /** Provisioning type. */
+    unsigned u3ProvType             : 3;
+    /** Reserved. */
+    unsigned u5Reserved             : 5;
+    /** Reserved. */
+    uint8_t  u8Reserved;
+} VSCSIVPDPAGEBLOCKPROV;
+#pragma pack()
+AssertCompileSize(VSCSIVPDPAGEBLOCKPROV, VSCSI_VPD_BLOCK_PROV_SIZE);
+typedef VSCSIVPDPAGEBLOCKPROV *PVSCSIVPDPAGEBLOCKPROV;
+typedef const VSCSIVPDPAGEBLOCKPROV *PCVSCSIVPDPAGEBLOCKPROVS;
+
+#endif /* ___VSCSIVpdPages_h */
+
