VirtualBox

Changeset 38680 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Sep 8, 2011 7:52:08 AM (13 years ago)
Author:
vboxsync
Message:

VSCSI+DrvSCSI: Add support for the UNMAP command if discarding is enabled

Location:
trunk/src/VBox/Devices
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Makefile.kmk

    r38679 r38680  
    7373        Storage/VSCSI/VSCSISense.cpp \
    7474        Storage/VSCSI/VSCSIIoReq.cpp \
     75        Storage/VSCSI/VSCSIVpdPagePool.cpp \
    7576        build/VBoxDDUDeps.cpp
    7677 ifdef VBOX_WITH_USB
  • trunk/src/VBox/Devices/Storage/DrvSCSI.cpp

    r35353 r38680  
    105105    /** Errors printed in the release log. */
    106106    unsigned                cErrors;
     107    /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
     108    bool                    fNonRotational;
    107109} DRVSCSI, *PDRVSCSI;
    108110
     
    188190            break;
    189191        }
     192        case VSCSIIOREQTXDIR_UNMAP:
     193        {
     194            PVSCSIRANGE paRanges;
     195            unsigned cRanges;
     196
     197            rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges);
     198            AssertRC(rc);
     199
     200            pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
     201            rc = pThis->pDrvBlock->pfnDiscard(pThis->pDrvBlock, (PPDMRANGE)paRanges, cRanges);
     202            pThis->pLed->Actual.s.fWriting = 0;
     203            break;
     204        }
    190205        default:
    191206            AssertMsgFailed(("Invalid transfer direction %d\n", enmTxDir));
     
    200215}
    201216
    202 static int drvscsiGetSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pcbSize)
     217static DECLCALLBACK(int) drvscsiGetSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pcbSize)
    203218{
    204219    PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
     
    259274}
    260275
    261 static int drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun,
    262                                      void *pvScsiLunUser,
    263                                      VSCSIIOREQ hVScsiIoReq)
     276static DECLCALLBACK(int) drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun,
     277                                                   void *pvScsiLunUser,
     278                                                   VSCSIIOREQ hVScsiIoReq)
    264279{
    265280    int rc = VINF_SUCCESS;
     
    372387}
    373388
     389static DECLCALLBACK(int) drvscsiGetFeatureFlags(VSCSILUN hVScsiLun,
     390                                                void *pvScsiLunUser,
     391                                                uint64_t *pfFeatures)
     392{
     393    int rc = VINF_SUCCESS;
     394    PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
     395
     396    *pfFeatures = 0;
     397
     398    if (pThis->pDrvBlock->pfnDiscard)
     399        *pfFeatures |= VSCSI_LUN_FEATURE_UNMAP;
     400
     401    if (pThis->fNonRotational)
     402        *pfFeatures |= VSCSI_LUN_FEATURE_NON_ROTATIONAL;
     403
     404    return VINF_SUCCESS;
     405}
     406
    374407static void drvscsiVScsiReqCompleted(VSCSIDEVICE hVScsiDevice, void *pVScsiDeviceUser,
    375408                                     void *pVScsiReqUser, int rcScsiCode, bool fRedoPossible,
     
    741774
    742775    /*
     776     * Validate and read configuration.
     777     */
     778    if (!CFGMR3AreValuesValid(pCfg, "NonRotationalMedium\0"))
     779        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
     780                                N_("SCSI configuration error: unknown option specified"));
     781
     782    rc = CFGMR3QueryBoolDef(pCfg, "NonRotationalMedium", &pThis->fNonRotational, false);
     783    if (RT_FAILURE(rc))
     784        return PDMDRV_SET_ERROR(pDrvIns, rc,
     785                    N_("SCSI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
     786
     787    /*
    743788     * Initialize the instance data.
    744789     */
     
    803848    pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize      = drvscsiGetSize;
    804849    pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue;
     850    pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags    = drvscsiGetFeatureFlags;
    805851
    806852    rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis);
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp

    r38678 r38680  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
     17/*******************************************************************************
     18*   Header Files                                                               *
     19*******************************************************************************/
    1720#define LOG_GROUP LOG_GROUP_VSCSI
    1821#include <VBox/log.h>
     
    8184             */
    8285            if (vscsiBE2HU32(&pVScsiReq->pbCDB[6]) < 16)
    83                 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     86                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    8487            else
    8588            {
     
    9194                cbData = RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
    9295                if (cbData < 16)
    93                     *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     96                    *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    9497                else
    9598                    *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
     
    106109            /* Descriptor format sense data is not supported and results in an error. */
    107110            if ((pVScsiReq->pbCDB[1] & 0x1) != 0)
    108                 *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     111                *prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    109112            else
    110113                *prcReq = vscsiReqSenseCmd(&pVScsiDevice->VScsiSense, pVScsiReq);
     
    293296            vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq,
    294297                                  SCSI_SENSE_ILLEGAL_REQUEST,
    295                                   SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION);
     298                                  SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION,
     299                                  0x00);
    296300
    297301            vscsiDeviceReqComplete(pVScsiDevice, pVScsiReq,
     
    333337    pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;
    334338
    335     RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);
     339    if (cSGListEntries)
     340        RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);
    336341
    337342    *phVScsiReq = pVScsiReq;
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h

    r38678 r38680  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222#include <iprt/memcache.h>
    2323#include <iprt/sg.h>
     24#include <iprt/list.h>
    2425
    2526#include "VSCSIInline.h"
     27#include "VSCSIVpdPages.h"
    2628
    2729/** Pointer to an internal virtual SCSI device. */
     
    8486    /** Pointer to the LUN type descriptor. */
    8587    PVSCSILUNDESC        pVScsiLunDesc;
     88    /** Flags of supported features. */
     89    uint64_t             fFeatures;
    8690    /** I/O request processing data */
    8791    struct
     
    119123{
    120124    /** The associated request. */
    121     PVSCSIREQINT        pVScsiReq;
     125    PVSCSIREQINT           pVScsiReq;
    122126    /** Lun for this I/O request. */
    123     PVSCSILUNINT        pVScsiLun;
     127    PVSCSILUNINT           pVScsiLun;
    124128    /** Transfer direction */
    125     VSCSIIOREQTXDIR     enmTxDir;
    126     /** Start offset */
    127     uint64_t            uOffset;
    128     /** Number of bytes to transfer */
    129     size_t              cbTransfer;
    130     /** Number of bytes the S/G list holds */
    131     size_t              cbSeg;
    132     /** Number of segments. */
    133     unsigned            cSeg;
    134     /** Segment array. */
    135     PCRTSGSEG           paSeg;
     129    VSCSIIOREQTXDIR        enmTxDir;
     130    /** Direction dependent data. */
     131    union
     132    {
     133        /** Read/Write request. */
     134        struct
     135        {
     136            /** Start offset */
     137            uint64_t       uOffset;
     138            /** Number of bytes to transfer */
     139            size_t         cbTransfer;
     140            /** Number of bytes the S/G list holds */
     141            size_t         cbSeg;
     142            /** Number of segments. */
     143            unsigned       cSeg;
     144            /** Segment array. */
     145            PCRTSGSEG      paSeg;
     146        } Io;
     147        /** Unmape request. */
     148        struct
     149        {
     150            /** Array of ranges to unmap. */
     151            PVSCSIRANGE    paRanges;
     152            /** Number of ranges. */
     153            unsigned       cRanges;
     154        } Unmap;
     155    } u;
    136156} VSCSIIOREQINT;
     157
     158/**
     159 * VPD page pool.
     160 */
     161typedef struct VSCSIVPDPOOL
     162{
     163    /** List of registered pages. */
     164    RTLISTNODE    ListPages;
     165} VSCSIVPDPOOL;
     166/** Pointer to the VSCSI VPD page pool. */
     167typedef VSCSIVPDPOOL *PVSCSIVPDPOOL;
    137168
    138169/**
     
    217248 * @param   uSCSISenseKey The SCSI sense key to set.
    218249 * @param   uSCSIASC      The ASC value.
    219  */
    220 int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC);
     250 * @param   uSCSIASC      The ASCQ value.
     251 */
     252int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey,
     253                          uint8_t uSCSIASC, uint8_t uSCSIASCQ);
    221254
    222255/**
     
    228261 */
    229262int vscsiReqSenseCmd(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq);
     263
     264/**
     265 * Inits the VPD page pool.
     266 *
     267 * @returns VBox status code.
     268 * @param   pVScsiVpdPool    The VPD page pool to initialize.
     269 */
     270int vscsiVpdPagePoolInit(PVSCSIVPDPOOL pVScsiVpdPool);
     271
     272/**
     273 * Destroys the given VPD page pool freeing all pages in it.
     274 *
     275 * @returns nothing.
     276 * @param   pVScsiVpdPool    The VPD page pool to destroy.
     277 */
     278void vscsiVpdPagePoolDestroy(PVSCSIVPDPOOL pVScsiVpdPool);
     279
     280/**
     281 * Allocates a new page in the VPD page pool with the given number.
     282 *
     283 * @returns VBox status code.
     284 * @retval  VERR_ALREADY_EXIST if the page number is in use.
     285 * @param   pVScsiVpdPool    The VPD page pool the page will belong to.
     286 * @param   uPage            The page number, must be unique.
     287 * @param   cbPage           Size of the page in bytes.
     288 * @param   ppbPage          Where to store the pointer to the raw page data on success.
     289 */
     290int vscsiVpdPagePoolAllocNewPage(PVSCSIVPDPOOL pVScsiVpdPool, uint8_t uPage, size_t cbPage, uint8_t **ppbPage);
     291
     292/**
     293 * Queries the given page from the pool and cpies it to the buffer given
     294 * by the SCSI request.
     295 *
     296 * @returns VBox status code.
     297 * @retval  VERR_NOT_FOUND if the page is not in the pool.
     298 * @param   pVScsiVpdPool    The VPD page pool to use.
     299 * @param   pVScsiReq        The SCSI request.
     300 * @param   uPage            Page to query.
     301 */
     302int vscsiVpdPagePoolQueryPage(PVSCSIVPDPOOL pVScsiVpdPool, PVSCSIREQINT pVScsiReq, uint8_t uPage);
    230303
    231304/**
     
    253326
    254327/**
     328 * Enqueue a new unmap request.
     329 *
     330 * @returns VBox status code.
     331 * @param   pVScsiLun   The LUN instance which issued the request.
     332 * @param   pVScsiReq   The virtual SCSI request associated with the transfer.
     333 * @param   paRanges    The array of ranges to unmap.
     334 * @param   cRanges     Number of ranges in the array.
     335 */
     336int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
     337                           PVSCSIRANGE paRanges, unsigned cRanges);
     338
     339/**
    255340 * Returns the current number of outstanding tasks on the given LUN.
    256341 *
     
    289374
    290375/**
     376 * Wrapper for the get feature flags I/O callback.
     377 *
     378 * @returns VBox status code.
     379 * @param   pVScsiLun   The LUN.
     380 * @param   pVScsiIoReq The I/O request to enqueue.
     381 */
     382DECLINLINE(int) vscsiLunGetFeatureFlags(PVSCSILUNINT pVScsiLun, uint64_t *pfFeatures)
     383{
     384    return pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunGetFeatureFlags(pVScsiLun,
     385                                                                       pVScsiLun->pvVScsiLunUser,
     386                                                                       pfFeatures);
     387}
     388
     389/**
    291390 * Wrapper around vscsiReqSenseOkSet()
    292391 */
     
    299398 * Wrapper around vscsiReqSenseErrorSet()
    300399 */
    301 DECLINLINE(int) vscsiLunReqSenseErrorSet(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
    302 {
    303     return vscsiReqSenseErrorSet(&pVScsiLun->pVScsiDevice->VScsiSense, pVScsiReq, uSCSISenseKey, uSCSIASC);
     400DECLINLINE(int) vscsiLunReqSenseErrorSet(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC, uint8_t uSCSIASCQ)
     401{
     402    return vscsiReqSenseErrorSet(&pVScsiLun->pVScsiDevice->VScsiSense, pVScsiReq, uSCSISenseKey, uSCSIASC, uSCSIASCQ);
    304403}
    305404
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp

    r38678 r38680  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    6666        return VERR_NO_MEMORY;
    6767
    68     pVScsiIoReq->pVScsiReq  = pVScsiReq;
    69     pVScsiIoReq->pVScsiLun  = pVScsiLun;
    70     pVScsiIoReq->enmTxDir   = enmTxDir;
    71     pVScsiIoReq->uOffset    = uOffset;
    72     pVScsiIoReq->cbTransfer = cbTransfer;
    73     pVScsiIoReq->paSeg      = pVScsiReq->SgBuf.paSegs;
    74     pVScsiIoReq->cSeg       = pVScsiReq->SgBuf.cSegs;
     68    pVScsiIoReq->pVScsiReq       = pVScsiReq;
     69    pVScsiIoReq->pVScsiLun       = pVScsiLun;
     70    pVScsiIoReq->enmTxDir        = enmTxDir;
     71    pVScsiIoReq->u.Io.uOffset    = uOffset;
     72    pVScsiIoReq->u.Io.cbTransfer = cbTransfer;
     73    pVScsiIoReq->u.Io.paSeg      = pVScsiReq->SgBuf.paSegs;
     74    pVScsiIoReq->u.Io.cSeg       = pVScsiReq->SgBuf.cSegs;
     75
     76    ASMAtomicIncU32(&pVScsiLun->IoReq.cReqOutstanding);
     77
     78    rc = vscsiLunReqTransferEnqueue(pVScsiLun, pVScsiIoReq);
     79    if (RT_FAILURE(rc))
     80    {
     81        ASMAtomicDecU32(&pVScsiLun->IoReq.cReqOutstanding);
     82        RTMemFree(pVScsiIoReq);
     83    }
     84
     85    return rc;
     86}
     87
     88
     89int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
     90                           PVSCSIRANGE paRanges, unsigned cRanges)
     91{
     92    int rc = VINF_SUCCESS;
     93    PVSCSIIOREQINT pVScsiIoReq = NULL;
     94
     95    LogFlowFunc(("pVScsiLun=%#p pVScsiReq=%#p paRanges=%#p cRanges=%u\n",
     96                 pVScsiLun, pVScsiReq, paRanges, cRanges));
     97
     98    pVScsiIoReq = (PVSCSIIOREQINT)RTMemAllocZ(sizeof(VSCSIIOREQINT));
     99    if (!pVScsiIoReq)
     100        return VERR_NO_MEMORY;
     101
     102    pVScsiIoReq->pVScsiReq        = pVScsiReq;
     103    pVScsiIoReq->pVScsiLun        = pVScsiLun;
     104    pVScsiIoReq->enmTxDir         = VSCSIIOREQTXDIR_UNMAP;
     105    pVScsiIoReq->u.Unmap.paRanges = paRanges;
     106    pVScsiIoReq->u.Unmap.cRanges  = cRanges;
    75107
    76108    ASMAtomicIncU32(&pVScsiLun->IoReq.cReqOutstanding);
     
    112144    ASMAtomicDecU32(&pVScsiLun->IoReq.cReqOutstanding);
    113145
    114     /** @todo error reporting */
    115146    if (RT_SUCCESS(rcIoReq))
    116147        rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     
    122153                                         pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_READ
    123154                                         ? SCSI_ASC_READ_ERROR
    124                                          : SCSI_ASC_WRITE_ERROR);
     155                                         : SCSI_ASC_WRITE_ERROR,
     156                                         0x00);
    125157    }
    126158    else
    127159        rcReq = SCSI_STATUS_CHECK_CONDITION;
     160
     161    if (pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_UNMAP)
     162        RTMemFree(pVScsiIoReq->u.Unmap.paRanges);
    128163
    129164    /* Free the I/O request */
     
    154189
    155190    AssertPtrReturn(pVScsiIoReq, VERR_INVALID_HANDLE);
    156     AssertReturn(pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_FLUSH, VERR_NOT_SUPPORTED);
    157 
    158     *puOffset    = pVScsiIoReq->uOffset;
    159     *pcbTransfer = pVScsiIoReq->cbTransfer;
    160     *pcSeg       = pVScsiIoReq->cSeg;
    161     *pcbSeg      = pVScsiIoReq->cbSeg;
    162     *ppaSeg      = pVScsiIoReq->paSeg;
     191    AssertReturn(   pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_FLUSH
     192                 && pVScsiIoReq->enmTxDir != VSCSIIOREQTXDIR_UNMAP,
     193                 VERR_NOT_SUPPORTED);
     194
     195    *puOffset    = pVScsiIoReq->u.Io.uOffset;
     196    *pcbTransfer = pVScsiIoReq->u.Io.cbTransfer;
     197    *pcSeg       = pVScsiIoReq->u.Io.cSeg;
     198    *pcbSeg      = pVScsiIoReq->u.Io.cbSeg;
     199    *ppaSeg      = pVScsiIoReq->u.Io.paSeg;
    163200
    164201    return VINF_SUCCESS;
    165202}
    166203
     204VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PVSCSIRANGE *ppaRanges,
     205                                           unsigned *pcRanges)
     206{
     207    PVSCSIIOREQINT pVScsiIoReq = hVScsiIoReq;
     208
     209    AssertPtrReturn(pVScsiIoReq, VERR_INVALID_HANDLE);
     210    AssertReturn(pVScsiIoReq->enmTxDir == VSCSIIOREQTXDIR_UNMAP, VERR_NOT_SUPPORTED);
     211
     212    *ppaRanges = pVScsiIoReq->u.Unmap.paRanges;
     213    *pcRanges  = pVScsiIoReq->u.Unmap.cRanges;
     214
     215    return VINF_SUCCESS;
     216}
     217
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp

    r33540 r38680  
    7171    pVScsiLun->pVScsiLunDesc        = pVScsiLunDesc;
    7272
    73     int rc = pVScsiLunDesc->pfnVScsiLunInit(pVScsiLun);
     73    int rc = vscsiLunGetFeatureFlags(pVScsiLun, &pVScsiLun->fFeatures);
    7474    if (RT_SUCCESS(rc))
    7575    {
    76         /** @todo Init other stuff */
    77         *phVScsiLun = pVScsiLun;
    78         return VINF_SUCCESS;
     76        rc = pVScsiLunDesc->pfnVScsiLunInit(pVScsiLun);
     77        if (RT_SUCCESS(rc))
     78        {
     79            *phVScsiLun = pVScsiLun;
     80            return VINF_SUCCESS;
     81        }
    7982    }
    8083
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp

    r38678 r38680  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2424#include <VBox/types.h>
    2525#include <VBox/vscsi.h>
     26#include <iprt/cdefs.h>
     27#include <iprt/asm.h>
    2628#include <iprt/assert.h>
    2729#include <iprt/mem.h>
     
    2931
    3032#include "VSCSIInternal.h"
     33
     34/** Maximum of amount of LBAs to unmap with one command. */
     35#define VSCSI_UNMAP_LBAS_MAX ((10*_1M) / 512)
    3136
    3237/**
     
    3944    /** Size of the virtual disk. */
    4045    uint64_t       cSectors;
     46    /** VPD page pool. */
     47    VSCSIVPDPOOL   VpdPagePool;
    4148} VSCSILUNSBC;
    4249/** Pointer to a SBC LUN instance */
     
    4855    uint64_t cbDisk = 0;
    4956    int rc = VINF_SUCCESS;
     57    int cVpdPages = 0;
    5058
    5159    rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
     
    5361        pVScsiLunSbc->cSectors = cbDisk / 512; /* Fixed sector size */
    5462
     63    if (RT_SUCCESS(rc))
     64        rc = vscsiVpdPagePoolInit(&pVScsiLunSbc->VpdPagePool);
     65
     66    if (   RT_SUCCESS(rc)
     67        && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP))
     68    {
     69        PVSCSIVPDPAGEBLOCKLIMITS pBlkPage;
     70        PVSCSIVPDPAGEBLOCKPROV   pBlkProvPage;
     71
     72        /* Create the page and fill it. */
     73        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_LIMITS_NUMBER,
     74                                          VSCSI_VPD_BLOCK_LIMITS_SIZE, (uint8_t **)&pBlkPage);
     75        if (RT_SUCCESS(rc))
     76        {
     77                pBlkPage->u5PeripheralDeviceType       = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
     78                pBlkPage->u3PeripheralQualifier        = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     79                pBlkPage->u16PageLength                = RT_H2BE_U16(0x3c);
     80                pBlkPage->u8MaxCmpWriteLength          = 0;
     81                pBlkPage->u16OptTrfLengthGran          = 0;
     82                pBlkPage->u32MaxTrfLength              = 0;
     83                pBlkPage->u32OptTrfLength              = 0;
     84                pBlkPage->u32MaxPreXdTrfLength         = 0;
     85                pBlkPage->u32MaxUnmapLbaCount          = RT_H2BE_U32(VSCSI_UNMAP_LBAS_MAX);
     86                pBlkPage->u32MaxUnmapBlkDescCount      = UINT32_C(0xffffffff);
     87                pBlkPage->u32OptUnmapGranularity       = 0;
     88                pBlkPage->u32UnmapGranularityAlignment = 0;
     89                cVpdPages++;
     90        }
     91
     92        if (RT_SUCCESS(rc))
     93        {
     94            rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_PROV_NUMBER,
     95                                              VSCSI_VPD_BLOCK_PROV_SIZE, (uint8_t **)&pBlkProvPage);
     96            if (RT_SUCCESS(rc))
     97            {
     98                pBlkProvPage->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
     99                pBlkProvPage->u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     100                pBlkProvPage->u16PageLength          = RT_H2BE_U16(0x4);
     101                pBlkProvPage->u8ThresholdExponent    = 1;
     102                pBlkProvPage->fLBPU                  = true;
     103                cVpdPages++;
     104            }
     105        }
     106    }
     107
     108    if (   RT_SUCCESS(rc)
     109        && (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL))
     110    {
     111        PVSCSIVPDPAGEBLOCKCHARACTERISTICS pBlkPage;
     112
     113        /* Create the page and fill it. */
     114        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER,
     115                                          VSCSI_VPD_BLOCK_CHARACTERISTICS_SIZE, (uint8_t **)&pBlkPage);
     116        if (RT_SUCCESS(rc))
     117        {
     118                pBlkPage->u5PeripheralDeviceType       = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
     119                pBlkPage->u3PeripheralQualifier        = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     120                pBlkPage->u16PageLength                = RT_H2BE_U16(0x3c);
     121                pBlkPage->u16MediumRotationRate        = RT_H2BE_U16(VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NON_ROTATING);
     122                cVpdPages++;
     123        }
     124    }
     125
     126    if (   RT_SUCCESS(rc)
     127        && cVpdPages)
     128    {
     129        PVSCSIVPDPAGESUPPORTEDPAGES pVpdPages;
     130
     131        rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_SUPPORTED_PAGES_NUMBER,
     132                                          VSCSI_VPD_SUPPORTED_PAGES_SIZE + cVpdPages - 1, (uint8_t **)&pVpdPages);
     133        if (RT_SUCCESS(rc))
     134        {
     135            unsigned idxVpdPage = 0;
     136            pVpdPages->u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
     137            pVpdPages->u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     138            pVpdPages->u16PageLength          = RT_H2BE_U16(cVpdPages);
     139
     140            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
     141            {
     142                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_LIMITS_NUMBER;
     143                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_PROV_NUMBER;
     144            }
     145
     146            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_NON_ROTATIONAL)
     147                pVpdPages->abVpdPages[idxVpdPage++] = VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER;
     148        }
     149    }
     150
    55151    return rc;
    56152}
     
    59155{
    60156    PVSCSILUNSBC pVScsiLunSbc = (PVSCSILUNSBC)pVScsiLun;
     157
     158    vscsiVpdPagePoolDestroy(&pVScsiLunSbc->VpdPagePool);
    61159
    62160    return VINF_SUCCESS;
     
    76174        case SCSI_INQUIRY:
    77175        {
    78             SCSIINQUIRYDATA ScsiInquiryReply;
    79 
    80             memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
    81 
    82             ScsiInquiryReply.cbAdditional           = 31;
    83             ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
    84             ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
    85             ScsiInquiryReply.u3AnsiVersion          = 0x05; /* SPC-4 compliant */
    86             ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
    87             ScsiInquiryReply.fWBus16                = 1;
    88             vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
    89             vscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
    90             vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
    91 
    92             RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
    93             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     176            /* Check for EVPD bit. */
     177            if (pVScsiReq->pbCDB[1] & 0x1)
     178            {
     179                rc = vscsiVpdPagePoolQueryPage(&pVScsiLunSbc->VpdPagePool, pVScsiReq, pVScsiReq->pbCDB[2]);
     180                if (RT_UNLIKELY(rc == VERR_NOT_FOUND))
     181                {
     182                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     183                                                     SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     184                    rc = VINF_SUCCESS;
     185                }
     186                else
     187                    rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     188            }
     189            else if (pVScsiReq->pbCDB[2] != 0) /* A non zero page code is an error. */
     190                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     191                                                 SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     192            else
     193            {
     194                SCSIINQUIRYDATA ScsiInquiryReply;
     195
     196                memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
     197
     198                ScsiInquiryReply.cbAdditional           = 31;
     199                ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
     200                ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     201                ScsiInquiryReply.u3AnsiVersion          = 0x05; /* SPC-4 compliant */
     202                ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
     203                ScsiInquiryReply.fWBus16                = 1;
     204                vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
     205                vscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
     206                vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
     207
     208                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
     209                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     210            }
    94211            break;
    95212        }
     
    263380                }
    264381                default:
    265                     rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     382                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    266383            }
    267384            break;
     
    278395                    vscsiH2BEU64(aReply, pVScsiLunSbc->cSectors - 1);
    279396                    vscsiH2BEU32(&aReply[8], 512);
     397                    if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
     398                        aReply[14] = 0x80; /* LPME enabled */
    280399                    /* Leave the rest 0 */
    281400
     
    285404                }
    286405                default:
    287                     rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); /* Don't know if this is correct */
    288             }
     406                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
     407            }
     408            break;
     409        }
     410        case SCSI_UNMAP:
     411        {
     412            if (pVScsiLun->fFeatures & VSCSI_LUN_FEATURE_UNMAP)
     413            {
     414                uint8_t abHdr[8];
     415                size_t cbCopied;
     416                size_t cbList = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     417
     418                /* Copy the header. */
     419                cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abHdr[0], sizeof(abHdr));
     420
     421                /* Using the anchor bit is not supported. */
     422                if (   !(pVScsiReq->pbCDB[1] & 0x01)
     423                    && cbCopied == sizeof(abHdr)
     424                    && cbList >= 8)
     425                {
     426                    size_t cBlkDesc = vscsiBE2HU16(&abHdr[2]) / 16;
     427
     428                    if (cBlkDesc)
     429                    {
     430                        PVSCSIRANGE paRanges;
     431
     432                        paRanges = (PVSCSIRANGE)RTMemAllocZ(cBlkDesc * sizeof(PVSCSIRANGE));
     433                        if (paRanges)
     434                        {
     435                            for (unsigned i = 0; i < cBlkDesc; i++)
     436                            {
     437                                uint8_t abBlkDesc[16];
     438
     439                                cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abBlkDesc[0], sizeof(abBlkDesc));
     440                                if (RT_UNLIKELY(cbCopied != sizeof(abBlkDesc)))
     441                                {
     442                                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     443                                    break;
     444                                }
     445
     446                                paRanges[i].offStart = vscsiBE2HU64(&abBlkDesc[0]) * 512;
     447                                paRanges[i].cbRange = vscsiBE2HU32(&abBlkDesc[8]) * 512;
     448                            }
     449
     450                            if (rcReq == SCSI_STATUS_OK)
     451                                rc = vscsiIoReqUnmapEnqueue(pVScsiLun, pVScsiReq, paRanges, cBlkDesc);
     452                        }
     453                        else /* Out of memory. */
     454                            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_SYSTEM_RESOURCE_FAILURE,
     455                                                             SCSI_ASCQ_SYSTEM_BUFFER_FULL);
     456                    }
     457                    else /* No block descriptors is not an error condition. */
     458                        rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     459                }
     460                else /* Invalid CDB. */
     461                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     462            }
     463            else
     464                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
     465
    289466            break;
    290467        }
    291468        default:
    292469            //AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
    293             rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     470            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
    294471    }
    295472
     
    301478        if (RT_UNLIKELY(uLbaStart + cSectorTransfer > pVScsiLunSbc->cSectors))
    302479        {
    303             rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
     480            rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
    304481            vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
    305482        }
     
    316493        rc = vscsiIoReqFlushEnqueue(pVScsiLun, pVScsiReq);
    317494    }
    318     else /* Request completed */
     495    else if (pVScsiReq->pbCDB[0] !=  SCSI_UNMAP) /* Request completed */
    319496        vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
    320497
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp

    r38678 r38680  
    55
    66/*
    7  * Copyright (C) 2006-2010 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4343}
    4444
    45 int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
     45int vscsiReqSenseErrorSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq, uint8_t uSCSISenseKey, uint8_t uSCSIASC, uint8_t uSCSIASCQ)
    4646{
    4747    memset(pVScsiSense->abSenseBuf, 0, sizeof(pVScsiSense->abSenseBuf));
     
    5050    pVScsiSense->abSenseBuf[7]  = 10;
    5151    pVScsiSense->abSenseBuf[12] = uSCSIASC;
    52     pVScsiSense->abSenseBuf[13] = 0x00; /** @todo: Provide more info. */
     52    pVScsiSense->abSenseBuf[13] = uSCSIASCQ;
    5353
    5454    if (pVScsiReq->pbSense && pVScsiReq->cbSense)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette