~ubuntu-branches/ubuntu/natty/virtualbox-ose/natty-updates

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Storage/DevAHCI.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2010-05-25 22:51:39 UTC
  • mfrom: (0.3.6 upstream) (0.4.12 sid)
  • Revision ID: james.westby@ubuntu.com-20100525225139-hpo777g413iyfvzu
Tags: 3.2.0-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Set x11 backport switch to "lucid".
  - VirtualBox should go in Accessories, not in System tools. (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop u03-fix-cpu-lockup.dpatch, fixed upstream.
* Remove Launchpad integration as (non-packaging) bugs should be reported
  upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: DevAHCI.cpp $ */
 
1
/* $Id: DevAHCI.cpp 29504 2010-05-16 13:43:18Z vboxsync $ */
2
2
/** @file
3
3
 * VBox storage devices: AHCI controller device (disk and cdrom).
4
4
 *                       Implements the AHCI standard 1.1
5
5
 */
6
6
 
7
7
/*
8
 
 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
 
8
 * Copyright (C) 2006-2009 Oracle Corporation
9
9
 *
10
10
 * This file is part of VirtualBox Open Source Edition (OSE), as
11
11
 * available from http://www.virtualbox.org. This file is free software;
14
14
 * Foundation, in version 2 as it comes in the "COPYING" file of the
15
15
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16
16
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17
 
 *
18
 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19
 
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20
 
 * additional information or have any questions.
21
17
 */
22
18
 
23
19
/** @page pg_dev_ahci   AHCI - Advanced Host Controller Interface Emulation.
225
221
typedef FNAHCIPOSTPROCESS *PFNAHCIPOSTPROCESS;
226
222
 
227
223
/**
 
224
 * Transfer type.
 
225
 */
 
226
typedef enum AHCITXDIR
 
227
{
 
228
    /** Invalid */
 
229
    AHCITXDIR_INVALID = 0,
 
230
    /** None */
 
231
    AHCITXDIR_NONE,
 
232
    /** Read */
 
233
    AHCITXDIR_READ,
 
234
    /** Write */
 
235
    AHCITXDIR_WRITE,
 
236
    /** Flush */
 
237
    AHCITXDIR_FLUSH
 
238
} AHCITXDIR;
 
239
 
 
240
/**
228
241
 * A task state.
229
242
 */
230
243
typedef struct AHCIPORTTASKSTATE
242
255
    /** Physical address of the command header. - GC */
243
256
    RTGCPHYS                   GCPhysCmdHdrAddr;
244
257
    /** Data direction. */
245
 
    uint8_t                    uTxDir;
 
258
    AHCITXDIR                  enmTxDir;
246
259
    /** Start offset. */
247
260
    uint64_t                   uOffset;
248
261
    /** Number of bytes to transfer. */
256
269
    /** Number of used SG list entries. */
257
270
    uint32_t                   cSGListUsed;
258
271
    /** Pointer to the first entry of the scatter gather list. */
259
 
    PPDMDATASEG                pSGListHead;
 
272
    PRTSGSEG                   pSGListHead;
260
273
    /** Number of scatter gather list entries. */
261
274
    uint32_t                   cSGEntries;
262
275
    /** Total number of bytes the guest reserved for this request.
274
287
     * If this is set we will use a buffer for the data
275
288
     * and the callback copies the data to the destination. */
276
289
    PFNAHCIPOSTPROCESS         pfnPostProcess;
 
290
#ifdef RT_STRICT
 
291
    /** Flag whether the task state is currently active - used for debugging */
 
292
    volatile bool              fActive;
 
293
#endif
277
294
} AHCIPORTTASKSTATE;
278
295
 
279
296
/**
291
308
    uint8_t             fQueued;
292
309
} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
293
310
 
 
311
 
 
312
/**
 
313
 * @implements PDMIBASE
 
314
 * @implements PDMIBLOCKPORT
 
315
 * @implements PDMIBLOCKASYNCPORT
 
316
 * @implements PDMIMOUNTNOTIFY
 
317
 */
294
318
typedef struct AHCIPort
295
319
{
296
320
    /** Pointer to the device instance - HC ptr */
438
462
     * Only used with the async interface.
439
463
     */
440
464
    R3PTRTYPE(PAHCIPORTTASKSTATE)   aCachedTasks[AHCI_NR_COMMAND_SLOTS];
 
465
    /** First task throwing an error. */
 
466
    R3PTRTYPE(volatile PAHCIPORTTASKSTATE) pTaskErr;
441
467
 
442
468
    uint32_t                        u32Alignment5[4];
443
469
 
444
 
#if HC_ARCH_BITS == 32
 
470
#if 0 /*HC_ARCH_BITS == 32*/
445
471
    uint32_t                        u32Alignment6;
446
472
#endif
447
473
 
482
508
    char                            szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
483
509
    /** The revision string for SCSI INQUIRY commands. */
484
510
    char                            szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
485
 
 
486
 
    uint32_t                        Alignment7;
487
 
 
488
 
} AHCIPort, *PAHCIPort;
489
 
 
490
 
/*
 
511
    /** Error counter */
 
512
    uint32_t                        cErrors;
 
513
 
 
514
} AHCIPort;
 
515
/** Pointer to the state of an AHCI port. */
 
516
typedef AHCIPort *PAHCIPort;
 
517
 
 
518
/**
491
519
 * Main AHCI device state.
 
520
 *
 
521
 * @implements  PDMILEDPORTS
492
522
 */
493
523
typedef struct AHCI
494
524
{
505
535
    uint32_t                        Alignment0;
506
536
#endif
507
537
 
508
 
    /** The base interface */
 
538
    /** Status LUN: The base interface. */
509
539
    PDMIBASE                        IBase;
510
 
    /** Status Port - Leds interface. */
 
540
    /** Status LUN: Leds interface. */
511
541
    PDMILEDPORTS                    ILeds;
512
 
    /** Partner of ILeds. */
 
542
    /** Status LUN: Partner of ILeds. */
513
543
    R3PTRTYPE(PPDMILEDCONNECTORS)   pLedsConnector;
514
544
 
515
545
#if HC_ARCH_BITS == 64
617
647
    /** How many milliseconds to sleep. */
618
648
    uint32_t                        cMillisToSleep;
619
649
 
620
 
} AHCI, *PAHCI;
 
650
} AHCI;
 
651
/** Pointer to the state of an AHCI device. */
 
652
typedef AHCI *PAHCI;
621
653
 
622
 
/* Scatter gather list entry. */
 
654
/**
 
655
 * Scatter gather list entry.
 
656
 */
623
657
typedef struct
624
658
{
625
659
    /** Data Base Address. */
2299
2333
 
2300
2334
    if (pThis->fGCEnabled)
2301
2335
    {
2302
 
        rc = PDMDevHlpMMIORegisterGC(pDevIns, GCPhysAddress, cb, 0,
 
2336
        rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, 0,
2303
2337
                                     "ahciMMIOWrite", "ahciMMIORead", NULL);
2304
2338
        if (RT_FAILURE(rc))
2305
2339
            return rc;
2338
2372
 
2339
2373
    if (pThis->fGCEnabled)
2340
2374
    {
2341
 
        rc = PDMDevHlpIOPortRegisterGC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
 
2375
        rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2342
2376
                                       "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2343
2377
        if (RT_FAILURE(rc))
2344
2378
            return rc;
2370
2404
}
2371
2405
 
2372
2406
/**
2373
 
 * Queries an interface to the driver.
2374
 
 *
2375
 
 * @returns Pointer to interface.
2376
 
 * @returns NULL if the interface was not supported by the device.
2377
 
 * @param   pInterface          Pointer to ATADevState::IBase.
2378
 
 * @param   enmInterface        The requested interface identification.
 
2407
 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2379
2408
 */
2380
 
static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 
2409
static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2381
2410
{
2382
 
    PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
2383
 
    switch (enmInterface)
2384
 
    {
2385
 
        case PDMINTERFACE_BASE:
2386
 
            return &pAhci->IBase;
2387
 
        case PDMINTERFACE_LED_PORTS:
2388
 
            return &pAhci->ILeds;
2389
 
        default:
2390
 
            return NULL;
2391
 
    }
 
2411
    PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
 
2412
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
 
2413
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
 
2414
    return NULL;
2392
2415
}
2393
2416
 
2394
2417
/**
2395
 
 * Query interface method for the AHCI port.
 
2418
 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2396
2419
 */
2397
 
static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 
2420
static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2398
2421
{
2399
2422
    PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2400
 
    switch (enmInterface)
2401
 
    {
2402
 
        case PDMINTERFACE_BASE:
2403
 
            return &pAhciPort->IBase;
2404
 
        case PDMINTERFACE_BLOCK_PORT:
2405
 
            return &pAhciPort->IPort;
2406
 
        case PDMINTERFACE_BLOCK_ASYNC_PORT:
2407
 
            return &pAhciPort->IPortAsync;
2408
 
        case PDMINTERFACE_MOUNT_NOTIFY:
2409
 
            return &pAhciPort->IMountNotify;
2410
 
        default:
2411
 
            return NULL;
2412
 
    }
 
2423
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
 
2424
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKPORT, &pAhciPort->IPort);
 
2425
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNCPORT, &pAhciPort->IPortAsync);
 
2426
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
 
2427
    return NULL;
2413
2428
}
2414
2429
 
2415
2430
#ifdef DEBUG
2699
2714
    pAhciPortTaskState->uATARegError = 0;
2700
2715
    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2701
2716
    pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2702
 
        | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
 
2717
        | ((pAhciPortTaskState->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
2703
2718
        | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2704
2719
    pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
2705
2720
    pAhciPort->uATAPIASC = SCSI_ASC_NONE;
2878
2893
static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2879
2894
{
2880
2895
    uint16_t p[256];
2881
 
    RTUUID Uuid;
2882
 
    int rc;
2883
2896
 
2884
2897
    memset(p, 0, 512);
2885
2898
    /* Removable CDROM, 50us response, 12 byte packets */
3438
3451
 
3439
3452
static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3440
3453
{
3441
 
    int rc = PDMBLOCKTXDIR_NONE;
 
3454
    int iTxDir = PDMBLOCKTXDIR_NONE;
3442
3455
    const uint8_t *pbPacket;
3443
3456
    uint32_t cbMax;
3444
3457
 
3551
3564
                    break;
3552
3565
                }
3553
3566
                atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3554
 
                rc = PDMBLOCKTXDIR_FROM_DEVICE;
 
3567
                iTxDir = AHCITXDIR_READ;
3555
3568
            }
3556
3569
            break;
3557
3570
        case SCSI_READ_CD:
3600
3613
                    case 0x10:
3601
3614
                        /* normal read */
3602
3615
                        atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3603
 
                        rc = PDMBLOCKTXDIR_FROM_DEVICE;
 
3616
                        iTxDir = AHCITXDIR_READ;
3604
3617
                        break;
3605
3618
                    case 0xf8:
3606
3619
                        /* read all data */
3607
3620
                        atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
3608
 
                        rc = PDMBLOCKTXDIR_FROM_DEVICE;
 
3621
                        iTxDir = AHCITXDIR_READ;
3609
3622
                        break;
3610
3623
                    default:
3611
3624
                        LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
3779
3792
            break;
3780
3793
    }
3781
3794
 
3782
 
    return rc;
 
3795
    return iTxDir;
3783
3796
}
3784
3797
 
3785
3798
/**
3871
3884
 * @returns Nothing
3872
3885
 * @param   pAhciPort           The port for which the SDB Fis is send.
3873
3886
 * @param   uFinishedTasks      Bitmask of finished tasks.
3874
 
 * @param   pAhciPortTaskState  The state of the last task.
3875
3887
 * @param   fInterrupt          If an interrupt should be asserted.
3876
3888
 */
3877
 
static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
 
3889
static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
3878
3890
{
3879
3891
    uint32_t sdbFis[2];
3880
3892
    bool fAssertIntr = false;
3881
3893
    PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
 
3894
    PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr);
3882
3895
 
3883
3896
    ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3884
3897
 
3887
3900
        memset(&sdbFis[0], 0, sizeof(sdbFis));
3888
3901
        sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3889
3902
        sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3890
 
        sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3891
 
        sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3892
 
        sdbFis[1] = uFinishedTasks;
3893
 
 
3894
 
        ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3895
 
 
3896
 
        if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
 
3903
        if (RT_UNLIKELY(pTaskErr))
 
3904
        {
 
3905
            sdbFis[0]  = pTaskErr->uATARegError;
 
3906
            sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
 
3907
 
 
3908
            /* Update registers. */
 
3909
            pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
 
3910
        }
 
3911
        else
 
3912
        {
 
3913
            sdbFis[0]  = 0;
 
3914
            sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
 
3915
            pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
 
3916
        }
 
3917
 
 
3918
        sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
 
3919
 
 
3920
         ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
 
3921
 
 
3922
        if (RT_UNLIKELY(pTaskErr))
3897
3923
        {
3898
3924
            /* Error bit is set. */
3899
3925
            ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3909
3935
                fAssertIntr = true;
3910
3936
        }
3911
3937
 
3912
 
        /* Update registers. */
3913
 
        pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3914
 
 
3915
3938
        ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3916
3939
 
3917
3940
        if (fAssertIntr)
4047
4070
        }
4048
4071
 
4049
4072
        /* Allocate R3 scatter gather list. */
4050
 
        pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
 
4073
        pAhciPortTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(cSGList * sizeof(RTSGSEG));
4051
4074
        if (!pAhciPortTaskState->pSGListHead)
4052
4075
            return VERR_NO_MEMORY;
4053
4076
 
4083
4106
    if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4084
4107
    {
4085
4108
        if (pAhciPortTaskState->pvBufferUnaligned)
4086
 
            RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4109
            RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4087
4110
 
4088
4111
        Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4089
4112
 
4090
 
        pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
 
4113
        pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(cbUnaligned);
4091
4114
        if (!pAhciPortTaskState->pvBufferUnaligned)
4092
4115
            return VERR_NO_MEMORY;
4093
4116
 
4096
4119
 
4097
4120
    /* Make debugging easier. */
4098
4121
#ifdef DEBUG
4099
 
    memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
 
4122
    memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(RTSGSEG));
4100
4123
    memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4101
4124
    if (pAhciPortTaskState->pvBufferUnaligned)
4102
4125
        memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4144
4167
 
4145
4168
    if (pAhciPortTaskState->pvBufferUnaligned)
4146
4169
    {
4147
 
        RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4170
        RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4148
4171
        pAhciPortTaskState->pvBufferUnaligned = NULL;
4149
4172
    }
4150
4173
    if (pAhciPortTaskState->pSGListHead)
4164
4187
    pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbSGBuffers;
4165
4188
 
4166
4189
    /* Allocate new buffers and SG lists. */
4167
 
    pAhciPortTaskState->pvBufferUnaligned = RTMemAlloc(pAhciPortTaskState->cbSGBuffers);
 
4190
    pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(pAhciPortTaskState->cbSGBuffers);
4168
4191
    if (!pAhciPortTaskState->pvBufferUnaligned)
4169
4192
        return VERR_NO_MEMORY;
4170
4193
 
4171
 
    pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(1 * sizeof(PDMDATASEG));
 
4194
    pAhciPortTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(1 * sizeof(RTSGSEG));
4172
4195
    if (!pAhciPortTaskState->pSGListHead)
4173
4196
    {
4174
 
        RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4197
        RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4175
4198
        return VERR_NO_MEMORY;
4176
4199
    }
4177
4200
 
4178
4201
    pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
4179
4202
    if (!pAhciPortTaskState->paSGEntries)
4180
4203
    {
4181
 
        RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4204
        RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4182
4205
        RTMemFree(pAhciPortTaskState->pSGListHead);
4183
4206
        return VERR_NO_MEMORY;
4184
4207
    }
4195
4218
            if (!pAhciPortTaskState->pSGListHead[0].pvSeg)
4196
4219
            {
4197
4220
                RTMemFree(pAhciPortTaskState->paSGEntries);
4198
 
                RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4221
                RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4199
4222
                RTMemFree(pAhciPortTaskState->pSGListHead);
4200
4223
                return VERR_NO_MEMORY;
4201
4224
            }
4214
4237
    pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4215
4238
    pAhciPortTaskState->paSGEntries[0].u.temp.pvBuf = pAhciPortTaskState->pvBufferUnaligned;
4216
4239
 
4217
 
    if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
 
4240
    if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
4218
4241
        ahciCopyFromSGListIntoBuffer(pDevIns, &pAhciPortTaskState->paSGEntries[0]);
4219
4242
 
4220
4243
    return VINF_SUCCESS;
4250
4273
    RTGCPHYS   GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
4251
4274
    PAHCIPORTTASKSTATESGENTRY  pSGInfoCurr  = NULL;
4252
4275
    PAHCIPORTTASKSTATESGENTRY  pSGInfoPrev  = NULL;
4253
 
    PPDMDATASEG                pSGEntryCurr = NULL;
4254
 
    PPDMDATASEG                pSGEntryPrev = NULL;
 
4276
    PRTSGSEG                   pSGEntryCurr = NULL;
 
4277
    PRTSGSEG                   pSGEntryPrev = NULL;
4255
4278
    RTGCPHYS                   GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4256
4279
    uint8_t                   *pu8BufferUnalignedPos = NULL;
4257
4280
    uint32_t                   cbUnalignedComplete = 0;
4262
4285
 
4263
4286
    /*
4264
4287
     * Create a safe mapping when doing post processing because the size of the
4265
 
     * data to transfer and the amount of guest memory reserved can differ
 
4288
     * data to transfer and the amount of guest memory reserved can differ.
 
4289
     *
 
4290
     * @fixme: Read performance is really bad on OS X hosts because there is no
 
4291
     *         S/G support and the I/O manager has to create a newrequest
 
4292
     *         for every segment. The default limit of active requests is 16 on OS X
 
4293
     *         which causes a the bad read performance (writes are not affected
 
4294
     *         because of the writeback cache).
 
4295
     *         For now we will always use an intermediate buffer until
 
4296
     *         there is support for host S/G operations.
4266
4297
     */
4267
 
    if (pAhciPortTaskState->pfnPostProcess)
 
4298
    if (pAhciPortTaskState->pfnPostProcess || true)
4268
4299
    {
4269
 
        ahciLog(("%s: Request with post processing.\n"));
 
4300
        ahciLog(("%s: Request with post processing.\n", __FUNCTION__));
4270
4301
 
4271
4302
        ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
4272
4303
 
4384
4415
                                 * If the transfer is to the device we need to copy the content of the not mapped guest
4385
4416
                                 * segments into the temporary buffer.
4386
4417
                                 */
4387
 
                                if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
 
4418
                                if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
4388
4419
                                    ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4389
4420
 
4390
4421
                                /* Advance to next entry saving the pointers to the current ones. */
4630
4661
         * If the transfer is to the device we need to copy the content of the not mapped guest
4631
4662
         * segments into the temporary buffer.
4632
4663
         */
4633
 
        if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
 
4664
        if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
4634
4665
            ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4635
4666
    }
4636
4667
 
4672
4703
            /* Release the lock. */
4673
4704
            PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4674
4705
        }
4675
 
        else if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
 
4706
        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
4676
4707
        {
4677
4708
            /* Copy the data into the guest segments now. */
4678
4709
            ahciCopyFromBufferIntoSGList(pDevIns, pSGInfoCurr);
4688
4719
        RTMemFree(pAhciPortTaskState->pSGListHead);
4689
4720
        RTMemFree(pAhciPortTaskState->paSGEntries);
4690
4721
        if (pAhciPortTaskState->pvBufferUnaligned)
4691
 
            RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
4722
            RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4692
4723
        pAhciPortTaskState->cSGListSize = 0;
4693
4724
        pAhciPortTaskState->cSGListTooBig = 0;
4694
4725
        pAhciPortTaskState->pSGListHead = NULL;
4798
4829
{
4799
4830
    unsigned cSGEntry = 0;
4800
4831
    int cbCopied = 0;
4801
 
    PPDMDATASEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
 
4832
    PRTSGSEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
4802
4833
    uint8_t *pu8Buf = (uint8_t *)pvBuf;
4803
4834
 
4804
4835
    while (cSGEntry < pAhciPortTaskState->cSGEntries)
4839
4870
 *
4840
4871
 * @param pAhciPort             Pointer to the port where to request completed.
4841
4872
 * @param pAhciPortTaskState    Pointer to the task which finished.
 
4873
 * @param rcReq                 IPRT status code of the completed request.
4842
4874
 */
4843
 
static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
 
4875
static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
4844
4876
{
4845
4877
    /* Free system resources occupied by the scatter gather list. */
4846
 
    ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4847
 
 
4848
 
    pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4849
 
 
4850
 
    pAhciPortTaskState->uATARegError = 0;
4851
 
    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4852
 
    /* Write updated command header into memory of the guest. */
4853
 
    PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4854
 
                       &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4855
 
 
4856
 
    if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
 
4878
    if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
 
4879
        ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
 
4880
 
 
4881
    if (RT_FAILURE(rcReq))
 
4882
    {
 
4883
        pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
 
4884
        pAhciPortTaskState->uATARegError = ID_ERR;
 
4885
        pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
 
4886
 
 
4887
        /* Log the error. */
 
4888
        if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
 
4889
        {
 
4890
            if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
 
4891
                LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
 
4892
                        pAhciPort->iLUN, rcReq));
 
4893
            else
 
4894
                LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
 
4895
                        pAhciPort->iLUN,
 
4896
                        pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
 
4897
                        ? "Read"
 
4898
                        : "Write",
 
4899
                        pAhciPortTaskState->uOffset,
 
4900
                        pAhciPortTaskState->cbTransfer, rcReq));
 
4901
        }
 
4902
        ASMAtomicCmpXchgPtr((void * volatile *)&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
 
4903
    }
 
4904
    else
 
4905
    {
 
4906
        pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
 
4907
 
 
4908
        pAhciPortTaskState->uATARegError = 0;
 
4909
        pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
4910
 
 
4911
        /* Write updated command header into memory of the guest. */
 
4912
        PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
 
4913
                           &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
 
4914
    }
 
4915
 
 
4916
    if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
4857
4917
    {
4858
4918
        STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
4859
4919
        pAhciPort->Led.Actual.s.fReading = 0;
4860
4920
    }
4861
 
    else
 
4921
    else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
4862
4922
    {
4863
4923
        STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
4864
4924
        pAhciPort->Led.Actual.s.fWriting = 0;
4871
4931
        ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
4872
4932
        cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
4873
4933
        ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
4874
 
        ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
 
4934
        if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr))
 
4935
            ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
 
4936
 
 
4937
#ifdef RT_STRICT
 
4938
        bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
 
4939
        AssertMsg(fXchg, ("Task is not active\n"));
 
4940
#endif
4875
4941
 
4876
4942
        if (!cOutstandingTasks)
4877
 
            ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
 
4943
            ahciSendSDBFis(pAhciPort, 0, true);
4878
4944
    }
4879
4945
    else
 
4946
    {
 
4947
#ifdef RT_STRICT
 
4948
        bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
 
4949
        AssertMsg(fXchg, ("Task is not active\n"));
 
4950
#endif
 
4951
 
4880
4952
        ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
 
4953
    }
4881
4954
 
4882
4955
    /* Add the task to the cache. */
4883
4956
    pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
4891
4964
 * @returns VBox status code.
4892
4965
 * @param   pInterface   Pointer to the interface.
4893
4966
 * @param   pvUser       User data.
 
4967
 * @param   rcReq        IPRT Status code of the completed request.
4894
4968
 */
4895
 
static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
 
4969
static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
4896
4970
{
4897
4971
    PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
4898
4972
    PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
4900
4974
    ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
4901
4975
             __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
4902
4976
 
4903
 
    int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
 
4977
    int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
4904
4978
 
4905
4979
    if (pAhciPort->uActTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
4906
4980
        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
4913
4987
 * @returns The direction of the data transfer
4914
4988
 * @param   pCmdHdr Pointer to the command header.
4915
4989
 */
4916
 
static int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
 
4990
static AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
4917
4991
{
4918
 
    int rc = PDMBLOCKTXDIR_NONE;
 
4992
    AHCITXDIR rc = AHCITXDIR_NONE;
4919
4993
    bool fLBA48 = false;
4920
4994
    CmdHdr   *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4921
4995
 
4929
5003
            {
4930
5004
                if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
4931
5005
                {
 
5006
                    int rc2;
4932
5007
                    uint16_t u16Temp[256];
4933
5008
 
4934
5009
                    /* Fill the buffer. */
4935
5010
                    ahciIdentifySS(pAhciPort, u16Temp);
4936
5011
 
4937
5012
                    /* Create scatter gather list. */
4938
 
                    rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
4939
 
                    if (RT_FAILURE(rc))
4940
 
                        AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
 
5013
                    rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
 
5014
                    if (RT_FAILURE(rc2))
 
5015
                        AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
4941
5016
 
4942
5017
                    /* Copy the buffer. */
4943
5018
                    pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
4944
5019
 
4945
5020
                    /* Destroy list. */
4946
 
                    rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4947
 
                    if (RT_FAILURE(rc))
4948
 
                        AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
 
5021
                    rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
 
5022
                    if (RT_FAILURE(rc2))
 
5023
                        AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
4949
5024
 
4950
5025
                    pAhciPortTaskState->uATARegError = 0;
4951
5026
                    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4976
5051
                    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4977
5052
                    break;
4978
5053
                case 0x82: /* write cache disable */
4979
 
                    rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4980
 
                    pAhciPortTaskState->uATARegError = 0;
4981
 
                    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5054
                    rc = AHCITXDIR_FLUSH;
4982
5055
                    break;
4983
5056
                case 0x03:
4984
5057
                { /* set transfer mode */
5005
5078
        }
5006
5079
        case ATA_FLUSH_CACHE_EXT:
5007
5080
        case ATA_FLUSH_CACHE:
5008
 
            rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
5009
 
            pAhciPortTaskState->uATARegError = 0;
5010
 
            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5081
            rc = AHCITXDIR_FLUSH;
5011
5082
            break;
5012
5083
        case ATA_PACKET:
5013
5084
            if (!pAhciPort->fATAPI)
5017
5088
            }
5018
5089
            else
5019
5090
            {
5020
 
                rc = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
 
5091
                int rc2 = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
5021
5092
            }
5022
5093
            break;
5023
5094
        case ATA_IDENTIFY_PACKET_DEVICE:
5062
5133
        case ATA_READ_VERIFY_SECTORS_EXT:
5063
5134
        case ATA_READ_VERIFY_SECTORS:
5064
5135
        case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
 
5136
        case ATA_SLEEP:
5065
5137
            pAhciPortTaskState->uATARegError = 0;
5066
5138
            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5067
5139
            break;
5071
5143
        {
5072
5144
            pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5073
5145
            pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5074
 
            rc = PDMBLOCKTXDIR_FROM_DEVICE;
 
5146
            rc = AHCITXDIR_READ;
5075
5147
            break;
5076
5148
        }
5077
5149
        case ATA_WRITE_DMA_EXT:
5080
5152
        {
5081
5153
            pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5082
5154
            pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5083
 
            rc = PDMBLOCKTXDIR_TO_DEVICE;
 
5155
            rc = AHCITXDIR_WRITE;
5084
5156
            break;
5085
5157
        }
5086
5158
        case ATA_READ_FPDMA_QUEUED:
5087
5159
        {
5088
5160
            pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5089
5161
            pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5090
 
            rc = PDMBLOCKTXDIR_FROM_DEVICE;
 
5162
            rc = AHCITXDIR_READ;
5091
5163
            break;
5092
5164
        }
5093
5165
        case ATA_WRITE_FPDMA_QUEUED:
5094
5166
        {
5095
5167
            pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5096
5168
            pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5097
 
            rc = PDMBLOCKTXDIR_TO_DEVICE;
 
5169
            rc = AHCITXDIR_WRITE;
 
5170
            break;
 
5171
        }
 
5172
        case ATA_READ_LOG_EXT:
 
5173
        {
 
5174
            size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
 
5175
            unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
 
5176
            unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
 
5177
 
 
5178
            LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
 
5179
 
 
5180
            uint8_t aBuf[512];
 
5181
 
 
5182
            memset(aBuf, 0, sizeof(aBuf));
 
5183
 
 
5184
            if (offLogRead + cbLogRead <= sizeof(aBuf))
 
5185
            {
 
5186
                switch (iPage)
 
5187
                {
 
5188
                    case 0x10:
 
5189
                    {
 
5190
                        LogFlow(("Reading error page\n"));
 
5191
                        PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->pTaskErr, NULL);
 
5192
                        if (pTaskErr)
 
5193
                        {
 
5194
                            aBuf[0] = pTaskErr->fQueued ? pTaskErr->uTag : (1 << 7);
 
5195
                            aBuf[2] = pTaskErr->uATARegStatus;
 
5196
                            aBuf[3] = pTaskErr->uATARegError;
 
5197
                            aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
 
5198
                            aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
 
5199
                            aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
 
5200
                            aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
 
5201
                            aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
 
5202
                            aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
 
5203
                            aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
 
5204
                            aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
 
5205
                            aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
 
5206
 
 
5207
                            /* Calculate checksum */
 
5208
                            uint8_t uChkSum = 0;
 
5209
                            for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
 
5210
                                uChkSum += aBuf[i];
 
5211
 
 
5212
                            aBuf[511] = (uint8_t)-(int8_t)uChkSum;
 
5213
 
 
5214
                            /*
 
5215
                             * Reading this log page results in an abort of all outstanding commands
 
5216
                             * and clearing the SActive register and TaskFile register.
 
5217
                             */
 
5218
                            ahciSendSDBFis(pAhciPort, 0xffffffff, true);
 
5219
                        }
 
5220
                        break;
 
5221
                    }
 
5222
                }
 
5223
 
 
5224
                /* Create scatter gather list. */
 
5225
                int rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
 
5226
                if (RT_FAILURE(rc2))
 
5227
                    AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
 
5228
 
 
5229
                /* Copy the buffer. */
 
5230
                pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &aBuf[offLogRead], cbLogRead);
 
5231
 
 
5232
                /* Destroy list. */
 
5233
                rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
 
5234
                if (RT_FAILURE(rc2))
 
5235
                    AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
 
5236
 
 
5237
                pAhciPortTaskState->uATARegError = 0;
 
5238
                pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5239
 
 
5240
                /* Write updated command header into memory of the guest. */
 
5241
                PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
 
5242
            }
 
5243
 
5098
5244
            break;
5099
5245
        }
5100
5246
        /* All not implemented commands go below. */
5101
5247
        case ATA_SECURITY_FREEZE_LOCK:
5102
5248
        case ATA_SMART:
5103
5249
        case ATA_NV_CACHE:
5104
 
        case ATA_SLEEP: /* Powermanagement not supported. */
5105
5250
            pAhciPortTaskState->uATARegError = ABRT_ERR;
5106
5251
            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5107
5252
            break;
5151
5296
    PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
5152
5297
 
5153
5298
    /* Set transfer direction. */
5154
 
    pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
 
5299
    pAhciPortTaskState->enmTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
5155
5300
 
5156
5301
    /* If this is an ATAPI command read the atapi command. */
5157
5302
    if (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
5220
5365
    }
5221
5366
    else
5222
5367
    {
5223
 
        int                iTxDir;
 
5368
        AHCITXDIR          enmTxDir;
5224
5369
        PAHCIPORTTASKSTATE pAhciPortTaskState;
5225
5370
 
5226
5371
        ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
5227
5372
 
5228
 
        /* Check if there is already an allocated task struct in the cache.
 
5373
        /*
 
5374
         * Check if there is already an allocated task struct in the cache.
5229
5375
         * Allocate a new task otherwise.
5230
5376
         */
5231
5377
        if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
5238
5384
            pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
5239
5385
        }
5240
5386
 
 
5387
#ifdef RT_STRICT
 
5388
        bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, true, false);
 
5389
        AssertMsg(fXchg, ("Task is already active\n"));
 
5390
#endif
 
5391
 
5241
5392
        /** Set current command slot */
5242
5393
        pAhciPortTaskState->uTag = pNotifierItem->iTask;
5243
5394
        pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5262
5413
                pAhciPort->fResetDevice = true;
5263
5414
                ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
5264
5415
                pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
 
5416
#ifdef RT_STRICT
 
5417
                fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
 
5418
                AssertMsg(fXchg, ("Task is not active\n"));
 
5419
#endif
5265
5420
                return true;
5266
5421
            }
5267
5422
            else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5268
5423
            {
5269
5424
                ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5270
5425
                pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
 
5426
#ifdef RT_STRICT
 
5427
                fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
 
5428
                AssertMsg(fXchg, ("Task is not active\n"));
 
5429
#endif
5271
5430
                return true;
5272
5431
            }
5273
5432
            else /* We are not in a reset state update the control registers. */
5276
5435
            }
5277
5436
        }
5278
5437
 
5279
 
        iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
 
5438
        enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5280
5439
 
5281
 
        if (iTxDir != PDMBLOCKTXDIR_NONE)
 
5440
        if (enmTxDir != AHCITXDIR_NONE)
5282
5441
        {
 
5442
            pAhciPortTaskState->enmTxDir = enmTxDir;
 
5443
 
5283
5444
            if (pAhciPortTaskState->fQueued)
5284
5445
            {
5285
5446
                ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5287
5448
                ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5288
5449
            }
5289
5450
 
5290
 
            STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5291
 
 
5292
 
            rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5293
 
            if (RT_FAILURE(rc))
5294
 
                AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5295
 
 
5296
 
            if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
 
5451
            if (enmTxDir != AHCITXDIR_FLUSH)
 
5452
            {
 
5453
                STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
 
5454
 
 
5455
                rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
 
5456
                if (RT_FAILURE(rc))
 
5457
                    AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
 
5458
            }
 
5459
 
 
5460
            if (enmTxDir == AHCITXDIR_FLUSH)
 
5461
            {
 
5462
                rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
 
5463
                                                              pAhciPortTaskState);
 
5464
            }
 
5465
            else if (enmTxDir == AHCITXDIR_READ)
5297
5466
            {
5298
5467
                pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5299
5468
                rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5310
5479
                                                              pAhciPortTaskState);
5311
5480
            }
5312
5481
            if (rc == VINF_VD_ASYNC_IO_FINISHED)
5313
 
                rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
 
5482
                rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, VINF_SUCCESS);
5314
5483
 
5315
 
            if (RT_FAILURE(rc))
5316
 
                AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
 
5484
            if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
 
5485
                rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rc);
5317
5486
        }
5318
5487
        else
5319
5488
        {
 
5489
#ifdef RT_STRICT
 
5490
            fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
 
5491
            AssertMsg(fXchg, ("Task is not active\n"));
 
5492
#endif
 
5493
 
5320
5494
            /* There is nothing left to do. Notify the guest. */
5321
5495
            ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5322
5496
            /* Add the task to the cache. */
5441
5615
        while (   (cTasksToProcess > 0)
5442
5616
               && RT_LIKELY(!pAhciPort->fPortReset))
5443
5617
        {
5444
 
            int       iTxDir;
 
5618
            AHCITXDIR enmTxDir;
5445
5619
            uint8_t   uActTag;
5446
5620
 
5447
5621
            STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
5491
5665
            }
5492
5666
            else
5493
5667
            {
5494
 
                iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5495
 
 
5496
 
                if (iTxDir != PDMBLOCKTXDIR_NONE)
 
5668
                enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
 
5669
 
 
5670
                if (enmTxDir == AHCITXDIR_FLUSH)
 
5671
                {
 
5672
                    rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
 
5673
 
 
5674
                    /* Log the error. */
 
5675
                    if (   RT_FAILURE(rc)
 
5676
                        && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
 
5677
                    {
 
5678
                        LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
 
5679
                                pAhciPort->iLUN, rc));
 
5680
                    }
 
5681
 
 
5682
                    if (RT_FAILURE(rc))
 
5683
                    {
 
5684
                        pAhciPortTaskState->uATARegError = ID_ERR;
 
5685
                        pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
 
5686
                    }
 
5687
                    else
 
5688
                    {
 
5689
                        pAhciPortTaskState->uATARegError = 0;
 
5690
                        pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5691
                    }
 
5692
 
 
5693
                    if (pAhciPortTaskState->fQueued)
 
5694
                        uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
 
5695
                    else
 
5696
                    {
 
5697
                        /* Task is not queued send D2H FIS */
 
5698
                        ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
 
5699
                    }
 
5700
                }
 
5701
                else if (enmTxDir != AHCITXDIR_NONE)
5497
5702
                {
5498
5703
                    uint64_t uOffset;
5499
5704
                    size_t cbTransfer;
5500
 
                    PPDMDATASEG pSegCurr;
 
5705
                    PRTSGSEG pSegCurr;
5501
5706
                    PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
5502
5707
 
5503
 
                    rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
 
5708
                    rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
5504
5709
                    if (RT_FAILURE(rc))
5505
5710
                        AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
5506
5711
 
5512
5717
                    pSegCurr    = &pAhciPortTaskState->pSGListHead[0];
5513
5718
                    pSGInfoCurr = pAhciPortTaskState->paSGEntries;
5514
5719
 
5515
 
                    STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, a);
 
5720
                    STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, b);
5516
5721
 
5517
5722
                    while (cbTransfer)
5518
5723
                    {
5522
5727
                        AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
5523
5728
                        AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
5524
5729
 
5525
 
                        if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
 
5730
                        if (enmTxDir == AHCITXDIR_READ)
5526
5731
                        {
5527
5732
                            pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5528
5733
                            rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
5529
5734
                                                               pSegCurr->pvSeg, cbProcess);
5530
5735
                            pAhciPort->Led.Actual.s.fReading = 0;
5531
5736
                            if (RT_FAILURE(rc))
5532
 
                                AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
 
5737
                                break;
5533
5738
 
5534
5739
                            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
5535
5740
                        }
5540
5745
                                                                pSegCurr->pvSeg, cbProcess);
5541
5746
                            pAhciPort->Led.Actual.s.fWriting = 0;
5542
5747
                            if (RT_FAILURE(rc))
5543
 
                                AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
 
5748
                                break;
5544
5749
 
5545
5750
                            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbProcess);
5546
5751
                        }
5552
5757
                        pSGInfoCurr++;
5553
5758
                    }
5554
5759
 
5555
 
                    STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
 
5760
                    STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, b);
 
5761
 
 
5762
                    /* Log the error. */
 
5763
                    if (   RT_FAILURE(rc)
 
5764
                        && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
 
5765
                    {
 
5766
                        LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
 
5767
                                pAhciPort->iLUN,
 
5768
                                enmTxDir == AHCITXDIR_READ
 
5769
                                ? "Read"
 
5770
                                : "Write",
 
5771
                                uOffset, cbTransfer, rc));
 
5772
                    }
5556
5773
 
5557
5774
                    /* Cleanup. */
5558
 
                    rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5559
 
                    if (RT_FAILURE(rc))
 
5775
                    int rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
 
5776
                    if (RT_FAILURE(rc2))
5560
5777
                        AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
5561
5778
 
5562
5779
                    if (RT_LIKELY(!pAhciPort->fPortReset))
5563
5780
                    {
5564
 
                        pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
5565
 
                        pAhciPortTaskState->uATARegError = 0;
5566
 
                        pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5781
                        pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer - cbTransfer;
 
5782
                        if (RT_FAILURE(rc))
 
5783
                        {
 
5784
                            pAhciPortTaskState->uATARegError = ID_ERR;
 
5785
                            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
 
5786
                        }
 
5787
                        else
 
5788
                        {
 
5789
                            pAhciPortTaskState->uATARegError = 0;
 
5790
                            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
 
5791
                        }
5567
5792
                        /* Write updated command header into memory of the guest. */
5568
5793
                        PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
5569
5794
                                           &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5603
5828
            pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
5604
5829
            ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5605
5830
            cTasksToProcess--;
5606
 
            if (!cTasksToProcess)
 
5831
 
 
5832
            /* If we encountered an error notify the guest and continue with the next task. */
 
5833
            if (RT_FAILURE(rc))
 
5834
            {
 
5835
                if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
 
5836
                    ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
 
5837
 
 
5838
                uQueuedTasksFinished = 0;
 
5839
            }
 
5840
            else if (!cTasksToProcess)
5607
5841
                cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5608
5842
        }
5609
5843
 
5610
5844
        if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5611
 
            ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, true);
 
5845
            ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
5612
5846
 
5613
5847
        uQueuedTasksFinished = 0;
5614
5848
 
5624
5858
            /* For the release statistics. There is no macro to set the counter to a specific value. */
5625
5859
            pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
5626
5860
        }
5627
 
    }
 
5861
    } /* While running */
5628
5862
 
5629
5863
    if (pAhci->fSignalIdle)
5630
5864
        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
5635
5869
    if (pAhciPortTaskState->paSGEntries)
5636
5870
        RTMemFree(pAhciPortTaskState->paSGEntries);
5637
5871
    if (pAhciPortTaskState->pvBufferUnaligned)
5638
 
        RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
 
5872
        RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
5639
5873
    RTMemFree(pAhciPortTaskState);
5640
5874
 
5641
5875
    ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
5781
6015
    for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
5782
6016
    {
5783
6017
        uint32_t iPort;
5784
 
        int rc = CFGMR3QueryU32Def(pDevIns->pCfgHandle, s_apszIdeEmuPortNames[i], &iPort, i);
 
6018
        int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
5785
6019
        AssertRCReturn(rc, rc);
5786
6020
        SSMR3PutU32(pSSM, iPort);
5787
6021
    }
5883
6117
{
5884
6118
    PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
5885
6119
    uint32_t u32;
5886
 
    uint32_t i;
5887
6120
    int rc;
5888
6121
 
5889
6122
    if (    uVersion != AHCI_SAVED_STATE_VERSION
5940
6173
        for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
5941
6174
        {
5942
6175
            uint32_t iPort;
5943
 
            rc = CFGMR3QueryU32Def(pDevIns->pCfgHandle, s_apszIdeEmuPortNames[i], &iPort, i);
 
6176
            rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
5944
6177
            AssertRCReturn(rc, rc);
5945
6178
 
5946
6179
            uint32_t iPortSaved;
5977
6210
        SSMR3GetBool(pSSM, &pThis->fGCEnabled);
5978
6211
 
5979
6212
        /* Now every port. */
5980
 
        for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
 
6213
        for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5981
6214
        {
5982
6215
            SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
5983
6216
            SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
6015
6248
        }
6016
6249
 
6017
6250
        /* Now the emulated ata controllers. */
6018
 
        for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
 
6251
        for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6019
6252
        {
6020
6253
            rc = ataControllerLoadExec(&pThis->aCts[i], pSSM);
6021
6254
            if (RT_FAILURE(rc))
6065
6298
 */
6066
6299
static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
6067
6300
{
6068
 
    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6069
 
    int rc = VINF_SUCCESS;
6070
 
    unsigned iActPort = 0;
 
6301
    PAHCI       pAhci    = PDMINS_2_DATA(pDevIns, PAHCI);
 
6302
    int         rc       = VINF_SUCCESS;
 
6303
    unsigned    iActPort = 0;
 
6304
    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
6071
6305
 
6072
6306
    /*
6073
6307
     * At this point the async I/O thread is suspended and will not enter
6135
6369
    /*
6136
6370
     * Query the block and blockbios interfaces.
6137
6371
     */
6138
 
    pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
 
6372
    pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
6139
6373
    if (!pAhciPort->pDrvBlock)
6140
6374
    {
6141
6375
        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
6142
6376
        return VERR_PDM_MISSING_INTERFACE;
6143
6377
    }
6144
 
    pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
 
6378
    pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
6145
6379
    if (!pAhciPort->pDrvBlockBios)
6146
6380
    {
6147
6381
        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
6148
6382
        return VERR_PDM_MISSING_INTERFACE;
6149
6383
    }
6150
6384
 
6151
 
    pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
 
6385
    pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
6152
6386
 
6153
6387
    /* Try to get the optional async block interface. */
6154
 
    pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
 
6388
    pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
6155
6389
 
6156
6390
    /*
6157
6391
     * Validate type.
6305
6539
        if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
6306
6540
            AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
6307
6541
 
 
6542
        pAhciPort->pAsyncIOThread = NULL;
 
6543
 
6308
6544
        rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
6309
6545
        if (RT_FAILURE(rc))
6310
6546
            AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
6382
6618
            }
6383
6619
 
6384
6620
            /* Create the async IO thread. */
6385
 
            rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6386
 
                                          RTTHREADTYPE_IO, szName);
 
6621
            rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
 
6622
                                       RTTHREADTYPE_IO, szName);
6387
6623
            if (RT_FAILURE(rc))
6388
6624
            {
6389
6625
                AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
6464
6700
}
6465
6701
 
6466
6702
/**
6467
 
 * Construct a device instance for a VM.
6468
 
 *
6469
 
 * @returns VBox status.
6470
 
 * @param   pDevIns     The device instance data.
6471
 
 *                      If the registration structure is needed, pDevIns->pDevReg points to it.
6472
 
 * @param   iInstance   Instance number. Use this to figure out which registers and such to use.
6473
 
 *                      The device number is also found in pDevIns->iInstance, but since it's
6474
 
 *                      likely to be freqently used PDM passes it as parameter.
6475
 
 * @param   pCfgHandle  Configuration node handle for the device. Use this to obtain the configuration
6476
 
 *                      of the device instance. It's also found in pDevIns->pCfgHandle, but like
6477
 
 *                      iInstance it's expected to be used a bit in this function.
 
6703
 * @interface_method_impl{PDMDEVREG,pfnConstruct}
6478
6704
 */
6479
 
static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
 
6705
static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
6480
6706
{
6481
6707
    PAHCI      pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6482
6708
    PPDMIBASE  pBase;
6485
6711
    bool       fGCEnabled = false;
6486
6712
    bool       fR0Enabled = false;
6487
6713
    uint32_t   cbTotalBufferSize = 0;
 
6714
    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
6488
6715
 
6489
6716
    /*
6490
6717
     * Validate and read configuration.
6491
6718
     */
6492
 
    if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0"
 
6719
    if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
6493
6720
                                          "R0Enabled\0"
6494
6721
                                          "PrimaryMaster\0"
6495
6722
                                          "PrimarySlave\0"
6502
6729
        return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6503
6730
                                N_("AHCI configuration error: unknown option specified"));
6504
6731
 
6505
 
    rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
 
6732
    rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
6506
6733
    if (RT_FAILURE(rc))
6507
6734
        return PDMDEV_SET_ERROR(pDevIns, rc,
6508
6735
                                N_("AHCI configuration error: failed to read GCEnabled as boolean"));
6509
6736
    Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
6510
6737
 
6511
 
    rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
 
6738
    rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
6512
6739
    if (RT_FAILURE(rc))
6513
6740
        return PDMDEV_SET_ERROR(pDevIns, rc,
6514
6741
                                N_("AHCI configuration error: failed to read R0Enabled as boolean"));
6515
6742
    Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
6516
6743
 
6517
 
    rc = CFGMR3QueryU32Def(pCfgHandle, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
 
6744
    rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6518
6745
    if (RT_FAILURE(rc))
6519
6746
        return PDMDEV_SET_ERROR(pDevIns, rc,
6520
6747
                                N_("AHCI configuration error: failed to read PortCount as integer"));
6528
6755
                                   N_("AHCI configuration error: PortCount=%u should be at least 1"),
6529
6756
                                   pThis->cPortsImpl);
6530
6757
 
6531
 
    rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
 
6758
    rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6532
6759
    if (RT_FAILURE(rc))
6533
6760
        return PDMDEV_SET_ERROR(pDevIns, rc,
6534
6761
                                N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6535
 
    rc = CFGMR3QueryU32Def(pCfgHandle, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
 
6762
    rc = CFGMR3QueryU32Def(pCfg, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6536
6763
    if (RT_FAILURE(rc))
6537
6764
        return PDMDEV_SET_ERROR(pDevIns, rc,
6538
6765
                                N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
6539
 
    rc = CFGMR3QueryU32Def(pCfgHandle, "MillisToSleep", &pThis->cMillisToSleep, 0);
 
6766
    rc = CFGMR3QueryU32Def(pCfg, "MillisToSleep", &pThis->cMillisToSleep, 0);
6540
6767
    if (RT_FAILURE(rc))
6541
6768
        return PDMDEV_SET_ERROR(pDevIns, rc,
6542
6769
                                N_("AHCI configuration error: failed to read MillisToSleep as integer"));
6620
6847
        return PDMDEV_SET_ERROR(pDevIns, rc,
6621
6848
                                N_("AHCI cannot register PCI memory region for registers"));
6622
6849
 
6623
 
    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, "AHCI");
 
6850
    rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI");
6624
6851
    if (RT_FAILURE(rc))
6625
6852
    {
6626
6853
        Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6645
6872
    /*
6646
6873
     * Create the transmit queue.
6647
6874
     */
6648
 
    rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6649
 
                                 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
 
6875
    rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
 
6876
                              ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6650
6877
    if (RT_FAILURE(rc))
6651
6878
        return rc;
6652
6879
    pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
6746
6973
                RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
6747
6974
 
6748
6975
            /* Get user config if present using defaults otherwise. */
6749
 
            PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, szName);
 
6976
            PCFGMNODE pCfgNode = CFGMR3GetChild(pCfg, szName);
6750
6977
            rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
6751
6978
                                      szSerial);
6752
6979
            if (RT_FAILURE(rc))
6836
7063
                AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
6837
7064
 
6838
7065
 
6839
 
                rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6840
 
                                              RTTHREADTYPE_IO, szName);
 
7066
                rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
 
7067
                                           RTTHREADTYPE_IO, szName);
6841
7068
                AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
6842
7069
            }
6843
7070
        }
6852
7079
                                       N_("AHCI: Failed to attach drive to %s"), szName);
6853
7080
 
6854
7081
#ifdef DEBUG
6855
 
        for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
6856
 
            pAhciPort->ahciIOTasks[i] = 0xff;
 
7082
        for (uint32_t j = 0; j < AHCI_NR_COMMAND_SLOTS; j++)
 
7083
            pAhciPort->ahciIOTasks[j] = 0xff;
6857
7084
#endif
6858
7085
    }
6859
7086
 
6862
7089
     */
6863
7090
    rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
6864
7091
    if (RT_SUCCESS(rc))
6865
 
        pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
 
7092
        pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
6866
7093
    else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
6867
7094
    {
6868
7095
        AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
6889
7116
    pThis->aCts[1].IOPortBase1  = 0x168;
6890
7117
    pThis->aCts[1].IOPortBase2  = 0x366;
6891
7118
 
6892
 
    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
 
7119
    for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6893
7120
    {
6894
7121
        PAHCIATACONTROLLER pCtl = &pThis->aCts[i];
6895
7122
        uint32_t iPortMaster, iPortSlave;
6900
7127
            { "SecondaryMaster", "SecondarySlave" }
6901
7128
        };
6902
7129
 
6903
 
        rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][0], &iPortMaster, 2 * i);
 
7130
        rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][0], &iPortMaster, 2 * i);
6904
7131
        if (RT_FAILURE(rc))
6905
7132
            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6906
7133
                                       N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
6907
7134
 
6908
 
        rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
 
7135
        rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
6909
7136
        if (RT_FAILURE(rc))
6910
7137
            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6911
7138
                                       N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);
6935
7162
 
6936
7163
        if (pThis->fGCEnabled)
6937
7164
        {
6938
 
            rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
 
7165
            rc = PDMDevHlpIOPortRegisterRC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
6939
7166
                                            "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI GC");
6940
7167
            if (RT_FAILURE(rc))
6941
7168
                return rc;
6956
7183
 
6957
7184
        if (pThis->fGCEnabled)
6958
7185
        {
6959
 
            rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
 
7186
            rc = PDMDevHlpIOPortRegisterRC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
6960
7187
                                            "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI GC");
6961
7188
            if (RT_FAILURE(rc))
6962
7189
                return rc;
6980
7207
{
6981
7208
    /* u32Version */
6982
7209
    PDM_DEVREG_VERSION,
6983
 
    /* szDeviceName */
 
7210
    /* szName */
6984
7211
    "ahci",
6985
7212
    /* szRCMod */
6986
7213
    "VBoxDDGC.gc",