VirtualBox

Changeset 64064 in vbox


Ignore:
Timestamp:
Sep 28, 2016 8:51:22 AM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
110992
Message:

VSCSI: Port missing commands over from the AHCI controller

Location:
trunk/src/VBox/Devices/Storage/VSCSI
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h

    r63992 r64064  
    208208    DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqProcess, (PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq));
    209209
     210    /**
     211     * Informs about a medium being inserted - optional.
     212     *
     213     * @returns VBox status code.
     214     * @param   pVScsiLun    The SCSI LUN instance.
     215     */
     216    DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumInserted, (PVSCSILUNINT pVScsiLun));
     217
     218    /**
     219     * Informs about a medium being removed - optional.
     220     *
     221     * @returns VBox status code.
     222     * @param   pVScsiLun    The SCSI LUN instance.
     223     */
     224    DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumRemoved, (PVSCSILUNINT pVScsiLun));
     225
    210226} VSCSILUNDESC;
    211227
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp

    r63992 r64064  
    129129VBOXDDU_DECL(int) VSCSILunMountNotify(VSCSILUN hVScsiLun)
    130130{
     131    int rc = VINF_SUCCESS;
    131132    PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
    132133
     
    138139    pVScsiLun->fReady        = false;
    139140    pVScsiLun->fMediaPresent = true;
     141    if (pVScsiLun->pVScsiLunDesc->pfnVScsiLunMediumInserted)
     142        rc = pVScsiLun->pVScsiLunDesc->pfnVScsiLunMediumInserted(pVScsiLun);
    140143
    141     return VINF_SUCCESS;
     144    return rc;
    142145}
    143146
     
    151154VBOXDDU_DECL(int) VSCSILunUnmountNotify(VSCSILUN hVScsiLun)
    152155{
     156    int rc = VINF_SUCCESS;
    153157    PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
    154158
     
    159163    pVScsiLun->fReady        = false;
    160164    pVScsiLun->fMediaPresent = false;
     165    if (pVScsiLun->pVScsiLunDesc->pfnVScsiLunMediumRemoved)
     166        rc = pVScsiLun->pVScsiLunDesc->pfnVScsiLunMediumRemoved(pVScsiLun);
    161167
    162     return VINF_SUCCESS;
     168    return rc;
    163169}
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp

    r63562 r64064  
    2525#include <VBox/types.h>
    2626#include <VBox/vscsi.h>
     27#include <iprt/asm.h>
    2728#include <iprt/assert.h>
    2829#include <iprt/mem.h>
     
    3031
    3132#include "VSCSIInternal.h"
     33
     34/**
     35 * Different event status types.
     36 */
     37typedef enum MMCEVENTSTATUSTYPE
     38{
     39    /** Medium event status not changed. */
     40    MMCEVENTSTATUSTYPE_UNCHANGED = 0,
     41    /** New medium inserted. */
     42    MMCEVENTSTATUSTYPE_MEDIA_NEW,
     43    /** Medium removed. */
     44    MMCEVENTSTATUSTYPE_MEDIA_REMOVED,
     45    /** Medium was removed + new medium was inserted. */
     46    MMCEVENTSTATUSTYPE_MEDIA_CHANGED,
     47    /** Medium eject requested (eject button pressed). */
     48    MMCEVENTSTATUSTYPE_MEDIA_EJECT_REQUESTED,
     49    /** 32bit hack. */
     50    MMCEVENTSTATUSTYPE_32BIT_HACK = 0x7fffffff
     51} MMCEVENTSTATUSTYPE;
     52
     53/** @name Media track types.
     54 * @{ */
     55/** Unknown media type. */
     56#define MMC_MEDIA_TYPE_UNKNOWN          0
     57/** Door closed, no media. */
     58#define MMC_MEDIA_TYPE_NO_DISC       0x70
     59/** @} */
     60
    3261
    3362/**
     
    3766{
    3867    /** Core LUN structure */
    39     VSCSILUNINT     Core;
     68    VSCSILUNINT                 Core;
    4069    /** Size of the virtual disk. */
    41     uint64_t        cSectors;
     70    uint64_t                    cSectors;
    4271    /** Sector size. */
    43     uint32_t        cbSector;
     72    uint32_t                    cbSector;
    4473    /** Medium locked indicator. */
    45     bool            fLocked;
     74    bool                        fLocked;
     75    /** Media event status. */
     76    volatile MMCEVENTSTATUSTYPE MediaEventStatus;
     77    /** Media track type. */
     78    volatile uint32_t           u32MediaTrackType;
    4679} VSCSILUNMMC, *PVSCSILUNMMC;
    4780
     
    158191}
    159192
     193/**
     194 * Create raw TOC data information.
     195 *
     196 * @returns SCSI status code.
     197 * @param   pVScsiLun     The LUN instance.
     198 * @param   pVScsiReq     The VSCSI request.
     199 * @param   cbMaxTransfer The maximum transfer size.
     200 * @param   fMSF          Flag whether to use MSF format to encode sector numbers.
     201 */
     202static int mmcReadTOCRaw(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
     203{
     204    PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
     205    uint8_t aReply[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
     206    uint32_t cbSize;
     207    uint8_t *pbBuf = &aReply[0] + 2;
     208
     209    *pbBuf++ = 1; /* first session */
     210    *pbBuf++ = 1; /* last session */
     211
     212    *pbBuf++ = 1; /* session number */
     213    *pbBuf++ = 0x14; /* data track */
     214    *pbBuf++ = 0; /* track number */
     215    *pbBuf++ = 0xa0; /* first track in program area */
     216    *pbBuf++ = 0; /* min */
     217    *pbBuf++ = 0; /* sec */
     218    *pbBuf++ = 0; /* frame */
     219    *pbBuf++ = 0;
     220    *pbBuf++ = 1; /* first track */
     221    *pbBuf++ = 0x00; /* disk type CD-DA or CD data */
     222    *pbBuf++ = 0;
     223
     224    *pbBuf++ = 1; /* session number */
     225    *pbBuf++ = 0x14; /* data track */
     226    *pbBuf++ = 0; /* track number */
     227    *pbBuf++ = 0xa1; /* last track in program area */
     228    *pbBuf++ = 0; /* min */
     229    *pbBuf++ = 0; /* sec */
     230    *pbBuf++ = 0; /* frame */
     231    *pbBuf++ = 0;
     232    *pbBuf++ = 1; /* last track */
     233    *pbBuf++ = 0;
     234    *pbBuf++ = 0;
     235
     236    *pbBuf++ = 1; /* session number */
     237    *pbBuf++ = 0x14; /* data track */
     238    *pbBuf++ = 0; /* track number */
     239    *pbBuf++ = 0xa2; /* lead-out */
     240    *pbBuf++ = 0; /* min */
     241    *pbBuf++ = 0; /* sec */
     242    *pbBuf++ = 0; /* frame */
     243    if (fMSF)
     244    {
     245        *pbBuf++ = 0; /* reserved */
     246        mmcLBA2MSF(pbBuf, pVScsiLunMmc->cSectors);
     247        pbBuf += 3;
     248    }
     249    else
     250    {
     251        vscsiH2BEU32(pbBuf, pVScsiLunMmc->cSectors);
     252        pbBuf += 4;
     253    }
     254
     255    *pbBuf++ = 1; /* session number */
     256    *pbBuf++ = 0x14; /* ADR, control */
     257    *pbBuf++ = 0;    /* track number */
     258    *pbBuf++ = 1;    /* point */
     259    *pbBuf++ = 0; /* min */
     260    *pbBuf++ = 0; /* sec */
     261    *pbBuf++ = 0; /* frame */
     262    if (fMSF)
     263    {
     264        *pbBuf++ = 0; /* reserved */
     265        mmcLBA2MSF(pbBuf, 0);
     266        pbBuf += 3;
     267    }
     268    else
     269    {
     270        /* sector 0 */
     271        vscsiH2BEU32(pbBuf, 0);
     272        pbBuf += 4;
     273    }
     274
     275    cbSize = pbBuf - aReply;
     276    vscsiH2BEU16(&aReply[0], cbSize - 2);
     277
     278    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, cbSize));
     279    return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     280}
     281
     282static size_t vscsiLunMmcGetConfigurationFillFeatureListProfiles(uint8_t *pbBuf, size_t cbBuf)
     283{
     284    if (cbBuf < 3*4)
     285        return 0;
     286
     287    vscsiH2BEU16(pbBuf, 0x0); /* feature 0: list of profiles supported */
     288    pbBuf[2] = (0 << 2) | (1 << 1) | (1 << 0); /* version 0, persistent, current */
     289    pbBuf[3] = 8; /* additional bytes for profiles */
     290    /* The MMC-3 spec says that DVD-ROM read capability should be reported
     291     * before CD-ROM read capability. */
     292    vscsiH2BEU16(pbBuf + 4, 0x10); /* profile: read-only DVD */
     293    pbBuf[6] = (0 << 0); /* NOT current profile */
     294    vscsiH2BEU16(pbBuf + 8, 0x08); /* profile: read only CD */
     295    pbBuf[10] = (1 << 0); /* current profile */
     296
     297    return 3*4; /* Header + 2 profiles entries */
     298}
     299
     300static size_t vscsiLunMmcGetConfigurationFillFeatureCore(uint8_t *pbBuf, size_t cbBuf)
     301{
     302    if (cbBuf < 12)
     303        return 0;
     304
     305    vscsiH2BEU16(pbBuf, 0x1); /* feature 0001h: Core Feature */
     306    pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     307    pbBuf[3] = 8; /* Additional length */
     308    vscsiH2BEU16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
     309    pbBuf[8] = RT_BIT(0); /* DBE */
     310    /* Rest is reserved. */
     311
     312    return 12;
     313}
     314
     315static size_t vscsiLunMmcGetConfigurationFillFeatureMorphing(uint8_t *pbBuf, size_t cbBuf)
     316{
     317    if (cbBuf < 8)
     318        return 0;
     319
     320    vscsiH2BEU16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
     321    pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     322    pbBuf[3] = 4; /* Additional length */
     323    pbBuf[4] = RT_BIT(1) | 0x0; /* OCEvent | !ASYNC */
     324    /* Rest is reserved. */
     325
     326    return 8;
     327}
     328
     329static size_t vscsiLunMmcGetConfigurationFillFeatureRemovableMedium(uint8_t *pbBuf, size_t cbBuf)
     330{
     331    if (cbBuf < 8)
     332        return 0;
     333
     334    vscsiH2BEU16(pbBuf, 0x3); /* feature 0003h: Removable Medium Feature */
     335    pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     336    pbBuf[3] = 4; /* Additional length */
     337    /* Tray type loading | Load | Eject | !Pvnt Jmpr | !DBML | Lock */
     338    pbBuf[4] = (0x2 << 5) | RT_BIT(4) | RT_BIT(3) | (0x0 << 2) | (0x0 << 1) | RT_BIT(0);
     339    /* Rest is reserved. */
     340
     341    return 8;
     342}
     343
     344static size_t vscsiLunMmcGetConfigurationFillFeatureRandomReadable(uint8_t *pbBuf, size_t cbBuf)
     345{
     346    if (cbBuf < 12)
     347        return 0;
     348
     349    vscsiH2BEU16(pbBuf, 0x10); /* feature 0010h: Random Readable Feature */
     350    pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     351    pbBuf[3] = 8; /* Additional length */
     352    vscsiH2BEU32(pbBuf + 4, 2048); /* Logical block size. */
     353    vscsiH2BEU16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
     354    pbBuf[10] = 0; /* PP not present */
     355    /* Rest is reserved. */
     356
     357    return 12;
     358}
     359
     360static size_t vscsiLunMmcGetConfigurationFillFeatureCDRead(uint8_t *pbBuf, size_t cbBuf)
     361{
     362    if (cbBuf < 8)
     363        return 0;
     364
     365    vscsiH2BEU16(pbBuf, 0x1e); /* feature 001Eh: CD Read Feature */
     366    pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     367    pbBuf[3] = 0; /* Additional length */
     368    pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
     369    /* Rest is reserved. */
     370
     371    return 8;
     372}
     373
     374static size_t vscsiLunMmcGetConfigurationFillFeaturePowerManagement(uint8_t *pbBuf, size_t cbBuf)
     375{
     376    if (cbBuf < 4)
     377        return 0;
     378
     379    vscsiH2BEU16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
     380    pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     381    pbBuf[3] = 0; /* Additional length */
     382
     383    return 4;
     384}
     385
     386static size_t vscsiLunMmcGetConfigurationFillFeatureTimeout(uint8_t *pbBuf, size_t cbBuf)
     387{
     388    if (cbBuf < 8)
     389        return 0;
     390
     391    vscsiH2BEU16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
     392    pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
     393    pbBuf[3] = 4; /* Additional length */
     394    pbBuf[4] = 0x0; /* !Group3 */
     395
     396    return 8;
     397}
     398
     399/**
     400 * Processes the GET CONFIGURATION SCSI request.
     401 *
     402 * @returns SCSI status code.
     403 * @param   pVScsiLunMmc  The MMC LUN instance.
     404 * @param   pVScsiReq     The VSCSI request.
     405 * @param   cbMaxTransfer The maximum transfer size.
     406 */
     407static int vscsiLunMmcGetConfiguration(PVSCSILUNMMC pVScsiLunMmc, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer)
     408{
     409    uint8_t aReply[80];
     410    uint8_t *pbBuf = &aReply[0];
     411    size_t cbBuf = sizeof(aReply);
     412    size_t cbCopied = 0;
     413
     414    /* Accept valid request types only, and only starting feature 0. */
     415    if ((pVScsiReq->pbCDB[1] & 0x03) == 3 || vscsiBE2HU16(&pVScsiReq->pbCDB[2]) != 0)
     416        return vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     417                                        SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     418
     419    /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
     420     * way to differentiate them right now is based on the image size). */
     421    if (pVScsiLunMmc->cSectors)
     422        vscsiH2BEU16(pbBuf + 6, 0x08); /* current profile: read-only CD */
     423    else
     424        vscsiH2BEU16(pbBuf + 6, 0x00); /* current profile: none -> no media */
     425    cbBuf    -= 8;
     426    pbBuf    += 8;
     427
     428    cbCopied = vscsiLunMmcGetConfigurationFillFeatureListProfiles(pbBuf, cbBuf);
     429    cbBuf -= cbCopied;
     430    pbBuf += cbCopied;
     431
     432    cbCopied = vscsiLunMmcGetConfigurationFillFeatureCore(pbBuf, cbBuf);
     433    cbBuf -= cbCopied;
     434    pbBuf += cbCopied;
     435
     436    cbCopied = vscsiLunMmcGetConfigurationFillFeatureMorphing(pbBuf, cbBuf);
     437    cbBuf -= cbCopied;
     438    pbBuf += cbCopied;
     439
     440    cbCopied = vscsiLunMmcGetConfigurationFillFeatureRemovableMedium(pbBuf, cbBuf);
     441    cbBuf -= cbCopied;
     442    pbBuf += cbCopied;
     443
     444    cbCopied = vscsiLunMmcGetConfigurationFillFeatureRandomReadable(pbBuf, cbBuf);
     445    cbBuf -= cbCopied;
     446    pbBuf += cbCopied;
     447
     448    cbCopied = vscsiLunMmcGetConfigurationFillFeatureCDRead(pbBuf, cbBuf);
     449    cbBuf -= cbCopied;
     450    pbBuf += cbCopied;
     451
     452    cbCopied = vscsiLunMmcGetConfigurationFillFeaturePowerManagement(pbBuf, cbBuf);
     453    cbBuf -= cbCopied;
     454    pbBuf += cbCopied;
     455
     456    cbCopied = vscsiLunMmcGetConfigurationFillFeatureTimeout(pbBuf, cbBuf);
     457    cbBuf -= cbCopied;
     458    pbBuf += cbCopied;
     459
     460    /* Set data length now. */
     461    vscsiH2BEU32(&aReply[0], (uint32_t)(sizeof(aReply) - cbBuf));
     462
     463    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, sizeof(aReply) - cbBuf));
     464    return vscsiLunReqSenseOkSet(&pVScsiLunMmc->Core, pVScsiReq);
     465}
     466
     467/**
     468 * Processes the READ DVD STRUCTURE SCSI request.
     469 *
     470 * @returns SCSI status code.
     471 * @param   pVScsiLunMmc  The MMC LUN instance.
     472 * @param   pVScsiReq     The VSCSI request.
     473 * @param   cbMaxTransfer The maximum transfer size.
     474 */
     475static int vscsiLunMmcReadDvdStructure(PVSCSILUNMMC pVScsiLunMmc, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer)
     476{
     477    uint8_t aReply[25]; /* Counted a maximum of 20 bytes but better be on the safe side. */
     478
     479    RT_ZERO(aReply);
     480
     481    /* Act according to the indicated format. */
     482    switch (pVScsiReq->pbCDB[7])
     483    {
     484        case 0x00:
     485        case 0x01:
     486        case 0x02:
     487        case 0x03:
     488        case 0x04:
     489        case 0x05:
     490        case 0x06:
     491        case 0x07:
     492        case 0x08:
     493        case 0x09:
     494        case 0x0a:
     495        case 0x0b:
     496        case 0x0c:
     497        case 0x0d:
     498        case 0x0e:
     499        case 0x0f:
     500        case 0x10:
     501        case 0x11:
     502        case 0x30:
     503        case 0x31:
     504        case 0xff:
     505            if (pVScsiReq->pbCDB[1] == 0)
     506            {
     507                int uASC = SCSI_ASC_NONE;
     508
     509                switch (pVScsiReq->pbCDB[7])
     510                {
     511                    case 0x0: /* Physical format information */
     512                    {
     513                        uint8_t uLayer = pVScsiReq->pbCDB[6];
     514                        uint64_t cTotalSectors;
     515
     516                        if (uLayer != 0)
     517                        {
     518                            uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
     519                            break;
     520                        }
     521
     522                        cTotalSectors = pVScsiLunMmc->cSectors;
     523                        cTotalSectors >>= 2;
     524                        if (cTotalSectors == 0)
     525                        {
     526                            uASC = -SCSI_ASC_MEDIUM_NOT_PRESENT;
     527                            break;
     528                        }
     529
     530                        aReply[4] = 1;   /* DVD-ROM, part version 1 */
     531                        aReply[5] = 0xf; /* 120mm disc, minimum rate unspecified */
     532                        aReply[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
     533                        aReply[7] = 0;   /* default densities */
     534
     535                        /* FIXME: 0x30000 per spec? */
     536                        vscsiH2BEU32(&aReply[8], 0); /* start sector */
     537                        vscsiH2BEU32(&aReply[12], cTotalSectors - 1); /* end sector */
     538                        vscsiH2BEU32(&aReply[16], cTotalSectors - 1); /* l0 end sector */
     539
     540                        /* Size of buffer, not including 2 byte size field */
     541                        vscsiH2BEU32(&aReply[0], 2048 + 2);
     542
     543                        /* 2k data + 4 byte header */
     544                        uASC = (2048 + 4);
     545                        break;
     546                    }
     547                    case 0x01: /* DVD copyright information */
     548                        aReply[4] = 0; /* no copyright data */
     549                        aReply[5] = 0; /* no region restrictions */
     550
     551                        /* Size of buffer, not including 2 byte size field */
     552                        vscsiH2BEU16(&aReply[0], 4 + 2);
     553
     554                        /* 4 byte header + 4 byte data */
     555                        uASC = (4 + 4);
     556                        break;
     557
     558                    case 0x03: /* BCA information - invalid field for no BCA info */
     559                        uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
     560                        break;
     561
     562                    case 0x04: /* DVD disc manufacturing information */
     563                        /* Size of buffer, not including 2 byte size field */
     564                        vscsiH2BEU16(&aReply[0], 2048 + 2);
     565
     566                        /* 2k data + 4 byte header */
     567                        uASC = (2048 + 4);
     568                        break;
     569                    case 0xff:
     570                        /*
     571                         * This lists all the command capabilities above.  Add new ones
     572                         * in order and update the length and buffer return values.
     573                         */
     574
     575                        aReply[4] = 0x00; /* Physical format */
     576                        aReply[5] = 0x40; /* Not writable, is readable */
     577                        vscsiH2BEU16(&aReply[6], 2048 + 4);
     578
     579                        aReply[8] = 0x01; /* Copyright info */
     580                        aReply[9] = 0x40; /* Not writable, is readable */
     581                        vscsiH2BEU16(&aReply[10], 4 + 4);
     582
     583                        aReply[12] = 0x03; /* BCA info */
     584                        aReply[13] = 0x40; /* Not writable, is readable */
     585                        vscsiH2BEU16(&aReply[14], 188 + 4);
     586
     587                        aReply[16] = 0x04; /* Manufacturing info */
     588                        aReply[17] = 0x40; /* Not writable, is readable */
     589                        vscsiH2BEU16(&aReply[18], 2048 + 4);
     590
     591                        /* Size of buffer, not including 2 byte size field */
     592                        vscsiH2BEU16(&aReply[0], 16 + 2);
     593
     594                        /* data written + 4 byte header */
     595                        uASC = (16 + 4);
     596                        break;
     597                    default: /** @todo formats beyond DVD-ROM requires */
     598                        uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
     599                }
     600
     601                if (uASC < 0)
     602                    return vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     603                                                    -uASC, 0x00);
     604                break;
     605            }
     606            /** @todo BD support, fall through for now */
     607
     608        /* Generic disk structures */
     609        case 0x80: /** @todo AACS volume identifier */
     610        case 0x81: /** @todo AACS media serial number */
     611        case 0x82: /** @todo AACS media identifier */
     612        case 0x83: /** @todo AACS media key block */
     613        case 0x90: /** @todo List of recognized format layers */
     614        case 0xc0: /** @todo Write protection status */
     615        default:
     616            return vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     617                                            SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     618    }
     619
     620    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, sizeof(aReply)));
     621    return vscsiLunReqSenseOkSet(&pVScsiLunMmc->Core, pVScsiReq);
     622}
     623
     624/**
     625 * Processes the MODE SENSE 10 SCSI request.
     626 *
     627 * @returns SCSI status code.
     628 * @param   pVScsiLunMmc  The MMC LUN instance.
     629 * @param   pVScsiReq     The VSCSI request.
     630 * @param   cbMaxTransfer The maximum transfer size.
     631 */
     632static int vscsiLunMmcModeSense10(PVSCSILUNMMC pVScsiLunMmc, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer)
     633{
     634    int rcReq;
     635    uint8_t uPageControl = pVScsiReq->pbCDB[2] >> 6;
     636    uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
     637
     638    switch (uPageControl)
     639    {
     640        case SCSI_PAGECONTROL_CURRENT:
     641            switch (uPageCode)
     642            {
     643                case SCSI_MODEPAGE_ERROR_RECOVERY:
     644                {
     645                    uint8_t aReply[16];
     646
     647                    vscsiH2BEU16(&aReply[0], 16 + 6);
     648                    aReply[2] = (uint8_t)pVScsiLunMmc->u32MediaTrackType;
     649                    aReply[3] = 0;
     650                    aReply[4] = 0;
     651                    aReply[5] = 0;
     652                    aReply[6] = 0;
     653                    aReply[7] = 0;
     654
     655                    aReply[8] = 0x01;
     656                    aReply[9] = 0x06;
     657                    aReply[10] = 0x00;
     658                    aReply[11] = 0x05;
     659                    aReply[12] = 0x00;
     660                    aReply[13] = 0x00;
     661                    aReply[14] = 0x00;
     662                    aReply[15] = 0x00;
     663                    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, sizeof(aReply)));
     664                    rcReq = vscsiLunReqSenseOkSet(&pVScsiLunMmc->Core, pVScsiReq);
     665                    break;
     666                }
     667                case SCSI_MODEPAGE_CD_STATUS:
     668                {
     669                    uint8_t aReply[40];
     670
     671                    vscsiH2BEU16(&aReply[0], 38);
     672                    aReply[2] = (uint8_t)pVScsiLunMmc->u32MediaTrackType;
     673                    aReply[3] = 0;
     674                    aReply[4] = 0;
     675                    aReply[5] = 0;
     676                    aReply[6] = 0;
     677                    aReply[7] = 0;
     678
     679                    aReply[8] = 0x2a;
     680                    aReply[9] = 30; /* page length */
     681                    aReply[10] = 0x08; /* DVD-ROM read support */
     682                    aReply[11] = 0x00; /* no write support */
     683                    /* The following claims we support audio play. This is obviously false,
     684                     * but the Linux generic CDROM support makes many features depend on this
     685                     * capability. If it's not set, this causes many things to be disabled. */
     686                    aReply[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
     687                    aReply[13] = 0x00; /* no subchannel reads supported */
     688                    aReply[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
     689                    if (pVScsiLunMmc->fLocked)
     690                        aReply[14] |= 1 << 1; /* report lock state */
     691                    aReply[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
     692                    vscsiH2BEU16(&aReply[16], 5632); /* (obsolete) claim 32x speed support */
     693                    vscsiH2BEU16(&aReply[18], 2); /* number of audio volume levels */
     694                    vscsiH2BEU16(&aReply[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
     695                                                       Just write some dummy value. */
     696                    vscsiH2BEU16(&aReply[22], 5632); /* (obsolete) current read speed 32x */
     697                    aReply[24] = 0; /* reserved */
     698                    aReply[25] = 0; /* reserved for digital audio (see idx 15) */
     699                    vscsiH2BEU16(&aReply[26], 0); /* (obsolete) maximum write speed */
     700                    vscsiH2BEU16(&aReply[28], 0); /* (obsolete) current write speed */
     701                    vscsiH2BEU16(&aReply[30], 0); /* copy management revision supported 0=no CSS */
     702                    aReply[32] = 0; /* reserved */
     703                    aReply[33] = 0; /* reserved */
     704                    aReply[34] = 0; /* reserved */
     705                    aReply[35] = 1; /* rotation control CAV */
     706                    vscsiH2BEU16(&aReply[36], 0); /* current write speed */
     707                    vscsiH2BEU16(&aReply[38], 0); /* number of write speed performance descriptors */
     708                    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, sizeof(aReply)));
     709                    rcReq = vscsiLunReqSenseOkSet(&pVScsiLunMmc->Core, pVScsiReq);
     710                    break;
     711                }
     712                default:
     713                    rcReq = vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     714                                                     SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     715                    break;
     716            }
     717            break;
     718        case SCSI_PAGECONTROL_CHANGEABLE:
     719        case SCSI_PAGECONTROL_DEFAULT:
     720            rcReq = vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     721                                             SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     722            break;
     723        default:
     724        case SCSI_PAGECONTROL_SAVED:
     725            rcReq = vscsiLunReqSenseErrorSet(&pVScsiLunMmc->Core, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     726                                             SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED, 0x00);
     727            break;
     728    }
     729
     730    return rcReq;
     731}
     732
     733/**
     734 * Processes the GET EVENT STATUS NOTIFICATION SCSI request.
     735 *
     736 * @returns SCSI status code.
     737 * @param   pVScsiLunMmc  The MMC LUN instance.
     738 * @param   pVScsiReq     The VSCSI request.
     739 * @param   cbMaxTransfer The maximum transfer size.
     740 */
     741static int vscsiLunMmcGetEventStatusNotification(PVSCSILUNMMC pVScsiLunMmc, PVSCSIREQINT pVScsiReq,
     742                                                 uint16_t cbMaxTransfer)
     743{
     744    uint32_t OldStatus;
     745    uint32_t NewStatus;
     746    uint8_t aReply[8];
     747    RT_ZERO(aReply);
     748
     749    do
     750    {
     751        OldStatus = ASMAtomicReadU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus);
     752        NewStatus = MMCEVENTSTATUSTYPE_UNCHANGED;
     753
     754        switch (OldStatus)
     755        {
     756            case MMCEVENTSTATUSTYPE_MEDIA_NEW:
     757                /* mount */
     758                vscsiH2BEU16(&aReply[0], 6);
     759                aReply[2] = 0x04; /* media */
     760                aReply[3] = 0x5e; /* supported = busy|media|external|power|operational */
     761                aReply[4] = 0x02; /* new medium */
     762                aReply[5] = 0x02; /* medium present / door closed */
     763                aReply[6] = 0x00;
     764                aReply[7] = 0x00;
     765                break;
     766
     767            case MMCEVENTSTATUSTYPE_MEDIA_CHANGED:
     768            case MMCEVENTSTATUSTYPE_MEDIA_REMOVED:
     769                /* umount */
     770                vscsiH2BEU16(&aReply[0], 6);
     771                aReply[2] = 0x04; /* media */
     772                aReply[3] = 0x5e; /* supported = busy|media|external|power|operational */
     773                aReply[4] = 0x03; /* media removal */
     774                aReply[5] = 0x00; /* medium absent / door closed */
     775                aReply[6] = 0x00;
     776                aReply[7] = 0x00;
     777                if (OldStatus == MMCEVENTSTATUSTYPE_MEDIA_CHANGED)
     778                    NewStatus = MMCEVENTSTATUSTYPE_MEDIA_NEW;
     779                break;
     780
     781            case MMCEVENTSTATUSTYPE_MEDIA_EJECT_REQUESTED: /* currently unused */
     782                vscsiH2BEU16(&aReply[0], 6);
     783                aReply[2] = 0x04; /* media */
     784                aReply[3] = 0x5e; /* supported = busy|media|external|power|operational */
     785                aReply[4] = 0x01; /* eject requested (eject button pressed) */
     786                aReply[5] = 0x02; /* medium present / door closed */
     787                aReply[6] = 0x00;
     788                aReply[7] = 0x00;
     789                break;
     790
     791            case MMCEVENTSTATUSTYPE_UNCHANGED:
     792            default:
     793                vscsiH2BEU16(&aReply[0], 6);
     794                aReply[2] = 0x01; /* operational change request / notification */
     795                aReply[3] = 0x5e; /* supported = busy|media|external|power|operational */
     796                aReply[4] = 0x00;
     797                aReply[5] = 0x00;
     798                aReply[6] = 0x00;
     799                aReply[7] = 0x00;
     800                break;
     801        }
     802    } while (!ASMAtomicCmpXchgU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus, NewStatus, OldStatus));
     803
     804    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(cbMaxTransfer, sizeof(aReply)));
     805    return vscsiLunReqSenseOkSet(&pVScsiLunMmc->Core, pVScsiReq);
     806}
     807
    160808static DECLCALLBACK(int) vscsiLunMmcInit(PVSCSILUNINT pVScsiLun)
    161809{
     
    164812    int             rc = VINF_SUCCESS;
    165813
    166     pVScsiLunMmc->cbSector = 2048;  /* Default to 2K sectors. */
     814    ASMAtomicWriteU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus, MMCEVENTSTATUSTYPE_UNCHANGED);
     815    pVScsiLunMmc->u32MediaTrackType = MMC_MEDIA_TYPE_UNKNOWN;
     816    pVScsiLunMmc->cbSector          = 2048;  /* Default to 2K sectors. */
    167817    rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
    168818    if (RT_SUCCESS(rc))
     
    215865        switch (uCmd)
    216866        {
    217         case SCSI_TEST_UNIT_READY:
    218             Assert(!pVScsiLunMmc->Core.fReady); /* Only should get here if LUN isn't ready. */
    219             rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
    220             break;
    221 
    222         case SCSI_INQUIRY:
    223         {
    224             SCSIINQUIRYDATA ScsiInquiryReply;
    225 
    226             memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
    227 
    228             ScsiInquiryReply.cbAdditional           = 31;
    229             ScsiInquiryReply.fRMB                   = 1;    /* Removable. */
    230             ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_CD_DVD;
    231             ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
    232             ScsiInquiryReply.u3AnsiVersion          = 0x05; /* MMC-?? compliant */
    233             ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
    234             ScsiInquiryReply.fWBus16                = 1;
    235             vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
    236             vscsiPadStr(ScsiInquiryReply.achProductId, "CD-ROM", 16);
    237             vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
    238 
    239             RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
    240             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    241             break;
    242         }
    243         case SCSI_READ_CAPACITY:
    244         {
    245             uint8_t aReply[8];
    246             memset(aReply, 0, sizeof(aReply));
    247 
    248             /*
    249              * If sector size exceeds the maximum value that is
    250              * able to be stored in 4 bytes return 0xffffffff in this field
    251              */
    252             if (pVScsiLunMmc->cSectors > UINT32_C(0xffffffff))
    253                 vscsiH2BEU32(aReply, UINT32_C(0xffffffff));
    254             else
    255                 vscsiH2BEU32(aReply, pVScsiLunMmc->cSectors - 1);
    256             vscsiH2BEU32(&aReply[4], pVScsiLunMmc->cbSector);
    257             RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
    258             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    259             break;
    260         }
    261         case SCSI_MODE_SENSE_6:
    262         {
    263             uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
    264             uint8_t aReply[24];
    265             uint8_t *pu8ReplyPos;
    266             bool    fValid = false;
    267 
    268             memset(aReply, 0, sizeof(aReply));
    269             aReply[0] = 4; /* Reply length 4. */
    270             aReply[1] = 0; /* Default media type. */
    271             aReply[2] = RT_BIT(4); /* Caching supported. */
    272             aReply[3] = 0; /* Block descriptor length. */
    273 
    274             pu8ReplyPos = aReply + 4;
    275 
    276             if ((uModePage == 0x08) || (uModePage == 0x3f))
    277             {
    278                 memset(pu8ReplyPos, 0, 20);
    279                 *pu8ReplyPos++ = 0x08; /* Page code. */
    280                 *pu8ReplyPos++ = 0x12; /* Size of the page. */
    281                 *pu8ReplyPos++ = 0x4;  /* Write cache enabled. */
    282                 fValid = true;
    283             } else if (uModePage == 0) {
    284                 fValid = true;
    285             }
    286 
    287             /* Querying unknown pages must fail. */
    288             if (fValid) {
     867            case SCSI_TEST_UNIT_READY:
     868                Assert(!pVScsiLunMmc->Core.fReady); /* Only should get here if LUN isn't ready. */
     869                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
     870                break;
     871
     872            case SCSI_INQUIRY:
     873            {
     874                SCSIINQUIRYDATA ScsiInquiryReply;
     875
     876                memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
     877
     878                ScsiInquiryReply.cbAdditional           = 31;
     879                ScsiInquiryReply.fRMB                   = 1;    /* Removable. */
     880                ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_CD_DVD;
     881                ScsiInquiryReply.u3PeripheralQualifier  = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
     882                ScsiInquiryReply.u3AnsiVersion          = 0x05; /* MMC-?? compliant */
     883                ScsiInquiryReply.fCmdQue                = 1;    /* Command queuing supported. */
     884                ScsiInquiryReply.fWBus16                = 1;
     885                vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
     886                vscsiPadStr(ScsiInquiryReply.achProductId, "CD-ROM", 16);
     887                vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
     888
     889                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
     890                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     891                break;
     892            }
     893            case SCSI_READ_CAPACITY:
     894            {
     895                uint8_t aReply[8];
     896                memset(aReply, 0, sizeof(aReply));
     897
     898                /*
     899                 * If sector size exceeds the maximum value that is
     900                 * able to be stored in 4 bytes return 0xffffffff in this field
     901                 */
     902                if (pVScsiLunMmc->cSectors > UINT32_C(0xffffffff))
     903                    vscsiH2BEU32(aReply, UINT32_C(0xffffffff));
     904                else
     905                    vscsiH2BEU32(aReply, pVScsiLunMmc->cSectors - 1);
     906                vscsiH2BEU32(&aReply[4], pVScsiLunMmc->cbSector);
    289907                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
    290908                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    291             } else {
    292                 rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    293             }
    294             break;
    295         }
    296         case SCSI_MODE_SELECT_6:
    297         {
    298             /** @todo implement!! */
    299             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    300             break;
    301         }
    302         case SCSI_READ_6:
    303         {
    304             enmTxDir       = VSCSIIOREQTXDIR_READ;
    305             uLbaStart      = ((uint64_t)    pVScsiReq->pbCDB[3]
    306                                         |  (pVScsiReq->pbCDB[2] <<  8)
    307                                         | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
    308             cSectorTransfer = pVScsiReq->pbCDB[4];
    309             break;
    310         }
    311         case SCSI_READ_10:
    312         {
    313             enmTxDir        = VSCSIIOREQTXDIR_READ;
    314             uLbaStart       = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
    315             cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
    316             break;
    317         }
    318         case SCSI_READ_12:
    319         {
    320             enmTxDir        = VSCSIIOREQTXDIR_READ;
    321             uLbaStart       = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
    322             cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
    323             break;
    324         }
    325         case SCSI_READ_16:
    326         {
    327             enmTxDir        = VSCSIIOREQTXDIR_READ;
    328             uLbaStart       = vscsiBE2HU64(&pVScsiReq->pbCDB[2]);
    329             cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
    330             break;
    331         }
    332         case SCSI_READ_BUFFER:
    333         {
    334             uint8_t uDataMode = pVScsiReq->pbCDB[1] & 0x1f;
    335 
    336             switch (uDataMode)
    337             {
    338                 case 0x00:
    339                 case 0x01:
    340                 case 0x02:
    341                 case 0x03:
    342                 case 0x0a:
    343                     break;
    344                 case 0x0b:
     909                break;
     910            }
     911            case SCSI_MODE_SENSE_6:
     912            {
     913                uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
     914                uint8_t aReply[24];
     915                uint8_t *pu8ReplyPos;
     916                bool    fValid = false;
     917
     918                memset(aReply, 0, sizeof(aReply));
     919                aReply[0] = 4; /* Reply length 4. */
     920                aReply[1] = 0; /* Default media type. */
     921                aReply[2] = RT_BIT(4); /* Caching supported. */
     922                aReply[3] = 0; /* Block descriptor length. */
     923
     924                pu8ReplyPos = aReply + 4;
     925
     926                if ((uModePage == 0x08) || (uModePage == 0x3f))
    345927                {
    346                     uint8_t aReply[4];
    347 
    348                     /* We do not implement an echo buffer. */
    349                     memset(aReply, 0, sizeof(aReply));
    350 
     928                    memset(pu8ReplyPos, 0, 20);
     929                    *pu8ReplyPos++ = 0x08; /* Page code. */
     930                    *pu8ReplyPos++ = 0x12; /* Size of the page. */
     931                    *pu8ReplyPos++ = 0x4;  /* Write cache enabled. */
     932                    fValid = true;
     933                } else if (uModePage == 0) {
     934                    fValid = true;
     935                }
     936
     937                /* Querying unknown pages must fail. */
     938                if (fValid) {
    351939                    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
    352940                    rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    353                     break;
     941                } else {
     942                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    354943                }
    355                 case 0x1a:
    356                 case 0x1c:
    357                     break;
    358                 default:
    359                     AssertMsgFailed(("Invalid data mode\n"));
    360             }
    361             break;
    362         }
    363         case SCSI_VERIFY_10:
    364         case SCSI_START_STOP_UNIT:
    365         {
    366             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    367             break;
    368         }
    369         case SCSI_LOG_SENSE:
    370         {
    371             uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
    372             uint8_t uSubPageCode = pVScsiReq->pbCDB[3];
    373 
    374             switch (uPageCode)
    375             {
    376                 case 0x00:
     944                break;
     945            }
     946            case SCSI_MODE_SENSE_10:
     947            {
     948                size_t cbMax = vscsiBE2HU32(&pVScsiReq->pbCDB[7]);
     949                rcReq = vscsiLunMmcModeSense10(pVScsiLunMmc, pVScsiReq, cbMax);
     950                break;
     951            }
     952            case SCSI_SEEK_10:
     953            {
     954                uint32_t uLba = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
     955                if (uLba > pVScsiLunMmc->cSectors)
     956                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     957                                                     SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
     958                else
     959                    rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     960                break;
     961            }
     962            case SCSI_MODE_SELECT_6:
     963            {
     964                /** @todo implement!! */
     965                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     966                break;
     967            }
     968            case SCSI_READ_6:
     969            {
     970                enmTxDir       = VSCSIIOREQTXDIR_READ;
     971                uLbaStart      = ((uint64_t)    pVScsiReq->pbCDB[3]
     972                                            |  (pVScsiReq->pbCDB[2] <<  8)
     973                                            | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
     974                cSectorTransfer = pVScsiReq->pbCDB[4];
     975                break;
     976            }
     977            case SCSI_READ_10:
     978            {
     979                enmTxDir        = VSCSIIOREQTXDIR_READ;
     980                uLbaStart       = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
     981                cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     982                break;
     983            }
     984            case SCSI_READ_12:
     985            {
     986                enmTxDir        = VSCSIIOREQTXDIR_READ;
     987                uLbaStart       = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
     988                cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
     989                break;
     990            }
     991            case SCSI_READ_16:
     992            {
     993                enmTxDir        = VSCSIIOREQTXDIR_READ;
     994                uLbaStart       = vscsiBE2HU64(&pVScsiReq->pbCDB[2]);
     995                cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
     996                break;
     997            }
     998            case SCSI_READ_BUFFER:
     999            {
     1000                uint8_t uDataMode = pVScsiReq->pbCDB[1] & 0x1f;
     1001
     1002                switch (uDataMode)
    3771003                {
    378                     if (uSubPageCode == 0)
     1004                    case 0x00:
     1005                    case 0x01:
     1006                    case 0x02:
     1007                    case 0x03:
     1008                    case 0x0a:
     1009                        break;
     1010                    case 0x0b:
    3791011                    {
    3801012                        uint8_t aReply[4];
    381 
    382                         aReply[0] = 0;
    383                         aReply[1] = 0;
    384                         aReply[2] = 0;
    385                         aReply[3] = 0;
     1013                        RT_ZERO(aReply);
    3861014
    3871015                        RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
     
    3891017                        break;
    3901018                    }
     1019                    case 0x1a:
     1020                    case 0x1c:
     1021                        break;
     1022                    default:
     1023                        AssertMsgFailed(("Invalid data mode\n"));
    3911024                }
    392                 default:
     1025                break;
     1026            }
     1027            case SCSI_VERIFY_10:
     1028            case SCSI_START_STOP_UNIT:
     1029            {
     1030                /** @todo: Improve START STOP UNIT */
     1031                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1032                break;
     1033            }
     1034            case SCSI_LOG_SENSE:
     1035            {
     1036                uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
     1037                uint8_t uSubPageCode = pVScsiReq->pbCDB[3];
     1038
     1039                switch (uPageCode)
     1040                {
     1041                    case 0x00:
     1042                    {
     1043                        if (uSubPageCode == 0)
     1044                        {
     1045                            uint8_t aReply[4];
     1046
     1047                            aReply[0] = 0;
     1048                            aReply[1] = 0;
     1049                            aReply[2] = 0;
     1050                            aReply[3] = 0;
     1051
     1052                            RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
     1053                            rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1054                            break;
     1055                        }
     1056                    }
     1057                    default:
     1058                        rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     1059                }
     1060                break;
     1061            }
     1062            case SCSI_SERVICE_ACTION_IN_16:
     1063            {
     1064                switch (pVScsiReq->pbCDB[1] & 0x1f)
     1065                {
     1066                    case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
     1067                    {
     1068                        uint8_t aReply[32];
     1069
     1070                        memset(aReply, 0, sizeof(aReply));
     1071                        vscsiH2BEU64(aReply, pVScsiLunMmc->cSectors - 1);
     1072                        vscsiH2BEU32(&aReply[8], pVScsiLunMmc->cbSector);
     1073                        /* Leave the rest 0 */
     1074                        RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
     1075                        rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1076                        break;
     1077                    }
     1078                    default:
     1079                        rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     1080                                                         SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
     1081                }
     1082                break;
     1083            }
     1084            case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
     1085            {
     1086                pVScsiLunMmc->fLocked = pVScsiReq->pbCDB[4] & 1;
     1087                vscsiLunMediumSetLock(pVScsiLun, pVScsiLunMmc->fLocked);
     1088                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1089                break;
     1090            }
     1091            case SCSI_READ_TOC_PMA_ATIP:
     1092            {
     1093                uint8_t     format;
     1094                uint16_t    cbMax;
     1095                bool        fMSF;
     1096
     1097                format = pVScsiReq->pbCDB[2] & 0x0f;
     1098                cbMax  = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     1099                fMSF   = (pVScsiReq->pbCDB[1] >> 1) & 1;
     1100                switch (format)
     1101                {
     1102                    case 0x00:
     1103                        rcReq = mmcReadTOCNormal(pVScsiLun, pVScsiReq, cbMax, fMSF);
     1104                        break;
     1105                    case 0x01:
     1106                        rcReq = mmcReadTOCMulti(pVScsiLun, pVScsiReq, cbMax, fMSF);
     1107                        break;
     1108                    case 0x02:
     1109                        rcReq = mmcReadTOCRaw(pVScsiLun, pVScsiReq, cbMax, fMSF);
     1110                        break;
     1111                    default:
     1112                        rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     1113                }
     1114                break;
     1115            }
     1116            case SCSI_GET_EVENT_STATUS_NOTIFICATION:
     1117            {
     1118                /* Only supporting polled mode at the moment. */
     1119                if (pVScsiReq->pbCDB[1] & 0x1)
     1120                {
     1121                    size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     1122                    rcReq = vscsiLunMmcGetEventStatusNotification(pVScsiLunMmc, pVScsiReq, cbMax);
     1123                }
     1124                else
    3931125                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    394             }
    395             break;
    396         }
    397         case SCSI_SERVICE_ACTION_IN_16:
    398         {
    399             switch (pVScsiReq->pbCDB[1] & 0x1f)
    400             {
    401                 case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
     1126                break;
     1127            }
     1128            case SCSI_MECHANISM_STATUS:
     1129            {
     1130                size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[8]);
     1131                uint8_t aReply[8];
     1132
     1133                vscsiH2BEU16(&aReply[0], 0);
     1134                /* no current LBA */
     1135                aReply[2] = 0;
     1136                aReply[3] = 0;
     1137                aReply[4] = 0;
     1138                aReply[5] = 1;
     1139                vscsiH2BEU16(&aReply[6], 0);
     1140                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(sizeof(aReply), cbMax));
     1141                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1142                break;
     1143            }
     1144            case SCSI_READ_DISC_INFORMATION:
     1145            {
     1146                uint8_t aReply[34];
     1147                size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     1148
     1149                memset(aReply, '\0', sizeof(aReply));
     1150                vscsiH2BEU16(&aReply[0], 32);
     1151                aReply[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
     1152                aReply[3] = 1; /* number of first track */
     1153                aReply[4] = 1; /* number of sessions (LSB) */
     1154                aReply[5] = 1; /* first track number in last session (LSB) */
     1155                aReply[6] = 1; /* last track number in last session (LSB) */
     1156                aReply[7] = (0 << 7) | (0 << 6) | (1 << 5) | (0 << 2) | (0 << 0); /* disc id not valid, disc bar code not valid, unrestricted use, not dirty, not RW medium */
     1157                aReply[8] = 0; /* disc type = CD-ROM */
     1158                aReply[9] = 0; /* number of sessions (MSB) */
     1159                aReply[10] = 0; /* number of sessions (MSB) */
     1160                aReply[11] = 0; /* number of sessions (MSB) */
     1161                vscsiH2BEU32(&aReply[16], 0x00ffffff); /* last session lead-in start time is not available */
     1162                vscsiH2BEU32(&aReply[20], 0x00ffffff); /* last possible start time for lead-out is not available */
     1163                RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(sizeof(aReply), cbMax));
     1164                rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
     1165                break;
     1166            }
     1167            case SCSI_READ_TRACK_INFORMATION:
     1168            {
     1169                /* Accept address/number type of 1 only, and only track 1 exists. */
     1170                if ((pVScsiReq->pbCDB[1] & 0x03) != 1 || vscsiBE2HU32(&pVScsiReq->pbCDB[2]) != 1)
     1171                    rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST,
     1172                                                     SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
     1173                else
    4021174                {
    403                     uint8_t aReply[32];
    404 
    405                     memset(aReply, 0, sizeof(aReply));
    406                     vscsiH2BEU64(aReply, pVScsiLunMmc->cSectors - 1);
    407                     vscsiH2BEU32(&aReply[8], pVScsiLunMmc->cbSector);
    408                     /* Leave the rest 0 */
    409                     RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
     1175                    size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     1176                    uint8_t aReply[36];
     1177                    RT_ZERO(aReply);
     1178
     1179                    vscsiH2BEU16(&aReply[0], 34);
     1180                    aReply[2] = 1; /* track number (LSB) */
     1181                    aReply[3] = 1; /* session number (LSB) */
     1182                    aReply[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
     1183                    aReply[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
     1184                    aReply[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
     1185                    vscsiH2BEU32(&aReply[8], 0); /* track start address is 0 */
     1186                    vscsiH2BEU32(&aReply[24], pVScsiLunMmc->cSectors); /* track size */
     1187                    aReply[32] = 0; /* track number (MSB) */
     1188                    aReply[33] = 0; /* session number (MSB) */
     1189
     1190                    RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, RT_MIN(sizeof(aReply), cbMax));
    4101191                    rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    411                     break;
    4121192                }
    413                 default:
    414                     rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
    415             }
    416             break;
    417         }
    418         case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
    419         {
    420             pVScsiLunMmc->fLocked = pVScsiReq->pbCDB[4] & 1;
    421             vscsiLunMediumSetLock(pVScsiLun, pVScsiLunMmc->fLocked);
    422             rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
    423             break;
    424         }
    425         case SCSI_READ_TOC_PMA_ATIP:
    426         {
    427             uint8_t     format;
    428             uint16_t    cbMax;
    429             bool        fMSF;
    430 
    431             format = pVScsiReq->pbCDB[2] & 0x0f;
    432             cbMax  = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
    433             fMSF   = (pVScsiReq->pbCDB[1] >> 1) & 1;
    434             switch (format)
    435             {
    436                 case 0x00:
    437                     mmcReadTOCNormal(pVScsiLun, pVScsiReq, cbMax, fMSF);
    438                     break;
    439                 case 0x01:
    440                     mmcReadTOCMulti(pVScsiLun, pVScsiReq, cbMax, fMSF);
    441                     break;
    442                 default:
    443                     rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
    444             }
    445             break;
    446         }
    447 
    448         default:
    449             //AssertMsgFailed(("Command %#x [%s] not implemented\n", pVScsiReq->pbCDB[0], SCSICmdText(pVScsiReq->pbCDB[0])));
    450             rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
     1193                break;
     1194            }
     1195            case SCSI_GET_CONFIGURATION:
     1196            {
     1197                size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
     1198                rcReq = vscsiLunMmcGetConfiguration(pVScsiLunMmc, pVScsiReq, cbMax);
     1199                break;
     1200            }
     1201            case SCSI_READ_DVD_STRUCTURE:
     1202            {
     1203                size_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[8]);
     1204                rcReq = vscsiLunMmcReadDvdStructure(pVScsiLunMmc, pVScsiReq, cbMax);
     1205                break;
     1206            }
     1207            default:
     1208                //AssertMsgFailed(("Command %#x [%s] not implemented\n", pVScsiReq->pbCDB[0], SCSICmdText(pVScsiReq->pbCDB[0])));
     1209                rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
    4511210        }
    4521211    }
     
    4821241}
    4831242
     1243/** @interface_method_impl{VSCSILUNDESC,pfnVScsiLunMediumInserted} */
     1244static DECLCALLBACK(int) vscsiLunMmcMediumInserted(PVSCSILUNINT pVScsiLun)
     1245{
     1246    PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
     1247
     1248    uint32_t OldStatus, NewStatus;
     1249    do
     1250    {
     1251        OldStatus = ASMAtomicReadU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus);
     1252        switch (OldStatus)
     1253        {
     1254            case MMCEVENTSTATUSTYPE_MEDIA_CHANGED:
     1255            case MMCEVENTSTATUSTYPE_MEDIA_REMOVED:
     1256                /* no change, we will send "medium removed" + "medium inserted" */
     1257                NewStatus = MMCEVENTSTATUSTYPE_MEDIA_CHANGED;
     1258                break;
     1259            default:
     1260                NewStatus = MMCEVENTSTATUSTYPE_MEDIA_NEW;
     1261                break;
     1262        }
     1263    } while (!ASMAtomicCmpXchgU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus,
     1264                                  NewStatus, OldStatus));
     1265
     1266    ASMAtomicXchgU32(&pVScsiLunMmc->u32MediaTrackType, MMC_MEDIA_TYPE_UNKNOWN);
     1267    return VINF_SUCCESS;
     1268}
     1269
     1270/** @interface_method_impl{VSCSILUNDESC,pfnVScsiLunMediumRemoved} */
     1271static DECLCALLBACK(int) vscsiLunMmcMediumRemoved(PVSCSILUNINT pVScsiLun)
     1272{
     1273    PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
     1274
     1275    ASMAtomicWriteU32((volatile uint32_t *)&pVScsiLunMmc->MediaEventStatus, MMCEVENTSTATUSTYPE_MEDIA_REMOVED);
     1276    ASMAtomicXchgU32(&pVScsiLunMmc->u32MediaTrackType, MMC_MEDIA_TYPE_NO_DISC);
     1277    return VINF_SUCCESS;
     1278}
     1279
     1280
    4841281VSCSILUNDESC g_VScsiLunTypeMmc =
    4851282{
     
    4951292    vscsiLunMmcDestroy,
    4961293    /** pfnVScsiLunReqProcess */
    497     vscsiLunMmcReqProcess
     1294    vscsiLunMmcReqProcess,
     1295    /** pfnVScsiLunMediumInserted */
     1296    vscsiLunMmcMediumInserted,
     1297    /** pfnVScsiLunMediumRemoved */
     1298    vscsiLunMmcMediumRemoved
    4981299};
  • trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp

    r63562 r64064  
    593593    vscsiLunSbcDestroy,
    594594    /** pfnVScsiLunReqProcess */
    595     vscsiLunSbcReqProcess
     595    vscsiLunSbcReqProcess,
     596    /** pfnVScsiLunMediumInserted */
     597    NULL,
     598    /** pfnVScsiLunMediumRemoved */
     599    NULL
    596600};
    597601
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