VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DevAHCI.cpp@ 92116

Last change on this file since 92116 was 92116, checked in by vboxsync, 3 years ago

DevAHCI: Some useful logging. bugref:10122

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 242.4 KB
Line 
1/* $Id: DevAHCI.cpp 92116 2021-10-28 00:23:05Z vboxsync $ */
2/** @file
3 * DevAHCI - AHCI controller device (disk and cdrom).
4 *
5 * Implements the AHCI standard 1.1
6 */
7
8/*
9 * Copyright (C) 2006-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
21 *
22 * This component implements an AHCI serial ATA controller. The device is split
23 * into two parts. The first part implements the register interface for the
24 * guest and the second one does the data transfer.
25 *
26 * The guest can access the controller in two ways. The first one is the native
27 * way implementing the registers described in the AHCI specification and is
28 * the preferred one. The second implements the I/O ports used for booting from
29 * the hard disk and for guests which don't have an AHCI SATA driver.
30 *
31 * The data is transfered using the extended media interface, asynchronously if
32 * it is supported by the driver below otherwise it weill be done synchronous.
33 * Either way a thread is used to process new requests from the guest.
34 */
35
36
37/*********************************************************************************************************************************
38* Header Files *
39*********************************************************************************************************************************/
40#define LOG_GROUP LOG_GROUP_DEV_AHCI
41#include <VBox/vmm/pdmdev.h>
42#include <VBox/vmm/pdmstorageifs.h>
43#include <VBox/vmm/pdmqueue.h>
44#include <VBox/vmm/pdmthread.h>
45#include <VBox/vmm/pdmcritsect.h>
46#include <VBox/sup.h>
47#include <VBox/scsi.h>
48#include <VBox/ata.h>
49#include <VBox/AssertGuest.h>
50#include <iprt/assert.h>
51#include <iprt/asm.h>
52#include <iprt/string.h>
53#include <iprt/list.h>
54#ifdef IN_RING3
55# include <iprt/param.h>
56# include <iprt/thread.h>
57# include <iprt/semaphore.h>
58# include <iprt/alloc.h>
59# include <iprt/uuid.h>
60# include <iprt/time.h>
61#endif
62#include "VBoxDD.h"
63
64#if defined(VBOX_WITH_DTRACE) \
65 && defined(IN_RING3) \
66 && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
67# include "dtrace/VBoxDD.h"
68#else
69# define VBOXDD_AHCI_REQ_SUBMIT(a,b,c,d) do { } while (0)
70# define VBOXDD_AHCI_REQ_COMPLETED(a,b,c,d) do { } while (0)
71#endif
72
73/** Maximum number of ports available.
74 * Spec defines 32 but we have one allocated for command completion coalescing
75 * and another for a reserved future feature.
76 */
77#define AHCI_MAX_NR_PORTS_IMPL 30
78/** Maximum number of command slots available. */
79#define AHCI_NR_COMMAND_SLOTS 32
80
81/** The current saved state version. */
82#define AHCI_SAVED_STATE_VERSION 9
83/** The saved state version before the ATAPI emulation was removed and the generic SCSI driver was used. */
84#define AHCI_SAVED_STATE_VERSION_PRE_ATAPI_REMOVE 8
85/** The saved state version before changing the port reset logic in an incompatible way. */
86#define AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES 7
87/** Saved state version before the per port hotplug port was added. */
88#define AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG 6
89/** Saved state version before legacy ATA emulation was dropped. */
90#define AHCI_SAVED_STATE_VERSION_IDE_EMULATION 5
91/** Saved state version before ATAPI support was added. */
92#define AHCI_SAVED_STATE_VERSION_PRE_ATAPI 3
93/** The saved state version use in VirtualBox 3.0 and earlier.
94 * This was before the config was added and ahciIOTasks was dropped. */
95#define AHCI_SAVED_STATE_VERSION_VBOX_30 2
96/* for Older ATA state Read handling */
97#define ATA_CTL_SAVED_STATE_VERSION 3
98#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
99#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
100
101/** The maximum number of release log entries per device. */
102#define MAX_LOG_REL_ERRORS 1024
103
104/**
105 * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
106 * Set to 1 to disable multi-sector read support. According to the ATA
107 * specification this must be a power of 2 and it must fit in an 8 bit
108 * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
109 */
110#define ATA_MAX_MULT_SECTORS 128
111
112/**
113 * Fastest PIO mode supported by the drive.
114 */
115#define ATA_PIO_MODE_MAX 4
116/**
117 * Fastest MDMA mode supported by the drive.
118 */
119#define ATA_MDMA_MODE_MAX 2
120/**
121 * Fastest UDMA mode supported by the drive.
122 */
123#define ATA_UDMA_MODE_MAX 6
124
125/**
126 * Length of the configurable VPD data (without termination)
127 */
128#define AHCI_SERIAL_NUMBER_LENGTH 20
129#define AHCI_FIRMWARE_REVISION_LENGTH 8
130#define AHCI_MODEL_NUMBER_LENGTH 40
131#define AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH 8
132#define AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH 16
133#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH 4
134
135/** ATAPI sense info size. */
136#define ATAPI_SENSE_SIZE 64
137
138/**
139 * Command Header.
140 */
141typedef struct
142{
143 /** Description Information. */
144 uint32_t u32DescInf;
145 /** Command status. */
146 uint32_t u32PRDBC;
147 /** Command Table Base Address. */
148 uint32_t u32CmdTblAddr;
149 /** Command Table Base Address - upper 32-bits. */
150 uint32_t u32CmdTblAddrUp;
151 /** Reserved */
152 uint32_t u32Reserved[4];
153} CmdHdr;
154AssertCompileSize(CmdHdr, 32);
155
156/* Defines for the command header. */
157#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
158#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
159#define AHCI_CMDHDR_C RT_BIT(10)
160#define AHCI_CMDHDR_B RT_BIT(9)
161#define AHCI_CMDHDR_R RT_BIT(8)
162#define AHCI_CMDHDR_P RT_BIT(7)
163#define AHCI_CMDHDR_W RT_BIT(6)
164#define AHCI_CMDHDR_A RT_BIT(5)
165#define AHCI_CMDHDR_CFL_MASK 0x1f
166
167#define AHCI_CMDHDR_PRDT_OFFSET 0x80
168#define AHCI_CMDHDR_ACMD_OFFSET 0x40
169
170/* Defines for the command FIS. */
171/* Defines that are used in the first double word. */
172#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
173# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
174# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
175# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
176# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
177# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
178# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
179# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
180# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
181# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
182# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
183# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
184# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
185# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
186
187#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
188#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
189#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
190#define AHCI_CMDFIS_D RT_BIT(5)
191
192#define AHCI_CMDFIS_CMD 2
193#define AHCI_CMDFIS_FET 3
194
195#define AHCI_CMDFIS_SECTN 4
196#define AHCI_CMDFIS_CYLL 5
197#define AHCI_CMDFIS_CYLH 6
198#define AHCI_CMDFIS_HEAD 7
199
200#define AHCI_CMDFIS_SECTNEXP 8
201#define AHCI_CMDFIS_CYLLEXP 9
202#define AHCI_CMDFIS_CYLHEXP 10
203#define AHCI_CMDFIS_FETEXP 11
204
205#define AHCI_CMDFIS_SECTC 12
206#define AHCI_CMDFIS_SECTCEXP 13
207#define AHCI_CMDFIS_CTL 15
208# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
209# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
210
211/* For D2H FIS */
212#define AHCI_CMDFIS_STS 2
213#define AHCI_CMDFIS_ERR 3
214
215/** Pointer to a task state. */
216typedef struct AHCIREQ *PAHCIREQ;
217
218/** Task encountered a buffer overflow. */
219#define AHCI_REQ_OVERFLOW RT_BIT_32(0)
220/** Request is a PIO data command, if this flag is not set it either is
221 * a command which does not transfer data or a DMA command based on the transfer size. */
222#define AHCI_REQ_PIO_DATA RT_BIT_32(1)
223/** The request has the SACT register set. */
224#define AHCI_REQ_CLEAR_SACT RT_BIT_32(2)
225/** Flag whether the request is queued. */
226#define AHCI_REQ_IS_QUEUED RT_BIT_32(3)
227/** Flag whether the request is stored on the stack. */
228#define AHCI_REQ_IS_ON_STACK RT_BIT_32(4)
229/** Flag whether this request transfers data from the device to the HBA or
230 * the other way around .*/
231#define AHCI_REQ_XFER_2_HOST RT_BIT_32(5)
232
233/**
234 * A task state.
235 */
236typedef struct AHCIREQ
237{
238 /** The I/O request handle from the driver below associated with this request. */
239 PDMMEDIAEXIOREQ hIoReq;
240 /** Tag of the task. */
241 uint32_t uTag;
242 /** The command Fis for this task. */
243 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
244 /** The ATAPI command data. */
245 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
246 /** Physical address of the command header. - GC */
247 RTGCPHYS GCPhysCmdHdrAddr;
248 /** Physical address of the PRDT */
249 RTGCPHYS GCPhysPrdtl;
250 /** Number of entries in the PRDTL. */
251 unsigned cPrdtlEntries;
252 /** Data direction. */
253 PDMMEDIAEXIOREQTYPE enmType;
254 /** Start offset. */
255 uint64_t uOffset;
256 /** Number of bytes to transfer. */
257 size_t cbTransfer;
258 /** Flags for this task. */
259 uint32_t fFlags;
260 /** SCSI status code. */
261 uint8_t u8ScsiSts;
262 /** Flag when the buffer is mapped. */
263 bool fMapped;
264 /** Page lock when the buffer is mapped. */
265 PGMPAGEMAPLOCK PgLck;
266} AHCIREQ;
267
268/**
269 * Notifier queue item.
270 */
271typedef struct DEVPORTNOTIFIERQUEUEITEM
272{
273 /** The core part owned by the queue manager. */
274 PDMQUEUEITEMCORE Core;
275 /** The port to process. */
276 uint8_t iPort;
277} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
278
279
280/**
281 * The shared state of an AHCI port.
282 */
283typedef struct AHCIPORT
284{
285 /** Command List Base Address. */
286 uint32_t regCLB;
287 /** Command List Base Address upper bits. */
288 uint32_t regCLBU;
289 /** FIS Base Address. */
290 uint32_t regFB;
291 /** FIS Base Address upper bits. */
292 uint32_t regFBU;
293 /** Interrupt Status. */
294 volatile uint32_t regIS;
295 /** Interrupt Enable. */
296 uint32_t regIE;
297 /** Command. */
298 uint32_t regCMD;
299 /** Task File Data. */
300 uint32_t regTFD;
301 /** Signature */
302 uint32_t regSIG;
303 /** Serial ATA Status. */
304 uint32_t regSSTS;
305 /** Serial ATA Control. */
306 uint32_t regSCTL;
307 /** Serial ATA Error. */
308 uint32_t regSERR;
309 /** Serial ATA Active. */
310 volatile uint32_t regSACT;
311 /** Command Issue. */
312 uint32_t regCI;
313
314 /** Current number of active tasks. */
315 volatile uint32_t cTasksActive;
316 uint32_t u32Alignment1;
317 /** Command List Base Address */
318 volatile RTGCPHYS GCPhysAddrClb;
319 /** FIS Base Address */
320 volatile RTGCPHYS GCPhysAddrFb;
321
322 /** Device is powered on. */
323 bool fPoweredOn;
324 /** Device has spun up. */
325 bool fSpunUp;
326 /** First D2H FIS was sent. */
327 bool fFirstD2HFisSent;
328 /** Attached device is a CD/DVD drive. */
329 bool fATAPI;
330 /** Flag whether this port is in a reset state. */
331 volatile bool fPortReset;
332 /** Flag whether TRIM is supported. */
333 bool fTrimEnabled;
334 /** Flag if we are in a device reset. */
335 bool fResetDevice;
336 /** Flag whether this port is hot plug capable. */
337 bool fHotpluggable;
338 /** Flag whether the port is in redo task mode. */
339 volatile bool fRedo;
340 /** Flag whether the worker thread is sleeping. */
341 volatile bool fWrkThreadSleeping;
342
343 bool afAlignment1[2];
344
345 /** Number of total sectors. */
346 uint64_t cTotalSectors;
347 /** Size of one sector. */
348 uint32_t cbSector;
349 /** Currently configured number of sectors in a multi-sector transfer. */
350 uint32_t cMultSectors;
351 /** The LUN (same as port number). */
352 uint32_t iLUN;
353 /** Set if there is a device present at the port. */
354 bool fPresent;
355 /** Currently active transfer mode (MDMA/UDMA) and speed. */
356 uint8_t uATATransferMode;
357 /** Exponent of logical sectors in a physical sector, number of logical sectors is 2^exp. */
358 uint8_t cLogSectorsPerPhysicalExp;
359 uint8_t bAlignment2;
360 /** ATAPI sense data. */
361 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
362
363 /** Bitmap for finished tasks (R3 -> Guest). */
364 volatile uint32_t u32TasksFinished;
365 /** Bitmap for finished queued tasks (R3 -> Guest). */
366 volatile uint32_t u32QueuedTasksFinished;
367 /** Bitmap for new queued tasks (Guest -> R3). */
368 volatile uint32_t u32TasksNew;
369 /** Bitmap of tasks which must be redone because of a non fatal error. */
370 volatile uint32_t u32TasksRedo;
371
372 /** Current command slot processed.
373 * Accessed by the guest by reading the CMD register.
374 * Holds the command slot of the command processed at the moment. */
375 volatile uint32_t u32CurrentCommandSlot;
376
377 /** Physical geometry of this image. */
378 PDMMEDIAGEOMETRY PCHSGeometry;
379
380 /** The status LED state for this drive. */
381 PDMLED Led;
382
383 /** The event semaphore the processing thread waits on. */
384 SUPSEMEVENT hEvtProcess;
385
386 /** The serial numnber to use for IDENTIFY DEVICE commands. */
387 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
388 /** The firmware revision to use for IDENTIFY DEVICE commands. */
389 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
390 /** The model number to use for IDENTIFY DEVICE commands. */
391 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
392 /** The vendor identification string for SCSI INQUIRY commands. */
393 char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
394 /** The product identification string for SCSI INQUIRY commands. */
395 char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
396 /** The revision string for SCSI INQUIRY commands. */
397 char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
398 /** Error counter */
399 uint32_t cErrors;
400
401 uint32_t u32Alignment5;
402} AHCIPORT;
403AssertCompileSizeAlignment(AHCIPORT, 8);
404/** Pointer to the shared state of an AHCI port. */
405typedef AHCIPORT *PAHCIPORT;
406
407
408/**
409 * The ring-3 state of an AHCI port.
410 *
411 * @implements PDMIBASE
412 * @implements PDMIMEDIAPORT
413 * @implements PDMIMEDIAEXPORT
414 */
415typedef struct AHCIPORTR3
416{
417 /** Pointer to the device instance - only to get our bearings in an interface
418 * method, nothing else. */
419 PPDMDEVINSR3 pDevIns;
420
421 /** The LUN (same as port number). */
422 uint32_t iLUN;
423
424 /** Device specific settings (R3 only stuff). */
425 /** Pointer to the attached driver's base interface. */
426 R3PTRTYPE(PPDMIBASE) pDrvBase;
427 /** Pointer to the attached driver's block interface. */
428 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
429 /** Pointer to the attached driver's extended interface. */
430 R3PTRTYPE(PPDMIMEDIAEX) pDrvMediaEx;
431 /** Port description. */
432 char szDesc[8];
433 /** The base interface. */
434 PDMIBASE IBase;
435 /** The block port interface. */
436 PDMIMEDIAPORT IPort;
437 /** The extended media port interface. */
438 PDMIMEDIAEXPORT IMediaExPort;
439
440 /** Async IO Thread. */
441 R3PTRTYPE(PPDMTHREAD) pAsyncIOThread;
442 /** First task throwing an error. */
443 R3PTRTYPE(volatile PAHCIREQ) pTaskErr;
444
445} AHCIPORTR3;
446AssertCompileSizeAlignment(AHCIPORTR3, 8);
447/** Pointer to the ring-3 state of an AHCI port. */
448typedef AHCIPORTR3 *PAHCIPORTR3;
449
450
451/**
452 * Main AHCI device state.
453 *
454 * @implements PDMILEDPORTS
455 */
456typedef struct AHCI
457{
458 /** Global Host Control register of the HBA
459 * @todo r=bird: Make this a 'name' doxygen comment with { and add a
460 * corrsponding at-} where appropriate. I cannot tell where to put the
461 * latter. */
462
463 /** HBA Capabilities - Readonly */
464 uint32_t regHbaCap;
465 /** HBA Control */
466 uint32_t regHbaCtrl;
467 /** Interrupt Status */
468 uint32_t regHbaIs;
469 /** Ports Implemented - Readonly */
470 uint32_t regHbaPi;
471 /** AHCI Version - Readonly */
472 uint32_t regHbaVs;
473 /** Command completion coalescing control */
474 uint32_t regHbaCccCtl;
475 /** Command completion coalescing ports */
476 uint32_t regHbaCccPorts;
477
478 /** Index register for BIOS access. */
479 uint32_t regIdx;
480
481 /** Countdown timer for command completion coalescing. */
482 TMTIMERHANDLE hHbaCccTimer;
483
484 /** Which port number is used to mark an CCC interrupt */
485 uint8_t uCccPortNr;
486 uint8_t abAlignment1[7];
487
488 /** Timeout value */
489 uint64_t uCccTimeout;
490 /** Number of completions used to assert an interrupt */
491 uint32_t uCccNr;
492 /** Current number of completed commands */
493 uint32_t uCccCurrentNr;
494
495 /** Register structure per port */
496 AHCIPORT aPorts[AHCI_MAX_NR_PORTS_IMPL];
497
498 /** The critical section. */
499 PDMCRITSECT lock;
500
501 /** Bitmask of ports which asserted an interrupt. */
502 volatile uint32_t u32PortsInterrupted;
503 /** Number of I/O threads currently active - used for async controller reset handling. */
504 volatile uint32_t cThreadsActive;
505
506 /** Flag whether the legacy port reset method should be used to make it work with saved states. */
507 bool fLegacyPortResetMethod;
508 /** Enable tiger (10.4.x) SSTS hack or not. */
509 bool fTigerHack;
510 /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
511 volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
512
513 /** Device is in a reset state.
514 * @todo r=bird: This isn't actually being modified by anyone... */
515 bool fReset;
516 /** Supports 64bit addressing
517 * @todo r=bird: This isn't really being modified by anyone (always false). */
518 bool f64BitAddr;
519 /** Flag whether the controller has BIOS access enabled.
520 * @todo r=bird: Not used, just queried from CFGM. */
521 bool fBootable;
522
523 bool afAlignment2[2];
524
525 /** Number of usable ports on this controller. */
526 uint32_t cPortsImpl;
527 /** Number of usable command slots for each port. */
528 uint32_t cCmdSlotsAvail;
529
530 /** PCI region \#0: Legacy IDE fake, 8 ports. */
531 IOMIOPORTHANDLE hIoPortsLegacyFake0;
532 /** PCI region \#1: Legacy IDE fake, 1 port. */
533 IOMIOPORTHANDLE hIoPortsLegacyFake1;
534 /** PCI region \#2: Legacy IDE fake, 8 ports. */
535 IOMIOPORTHANDLE hIoPortsLegacyFake2;
536 /** PCI region \#3: Legacy IDE fake, 1 port. */
537 IOMIOPORTHANDLE hIoPortsLegacyFake3;
538 /** PCI region \#4: BMDMA I/O port range, 16 ports, used for the Index/Data
539 * pair register access. */
540 IOMIOPORTHANDLE hIoPortIdxData;
541 /** PCI region \#5: MMIO registers. */
542 IOMMMIOHANDLE hMmio;
543} AHCI;
544AssertCompileMemberAlignment(AHCI, aPorts, 8);
545/** Pointer to the state of an AHCI device. */
546typedef AHCI *PAHCI;
547
548
549/**
550 * Main AHCI device ring-3 state.
551 *
552 * @implements PDMILEDPORTS
553 */
554typedef struct AHCIR3
555{
556 /** Pointer to the device instance - only for getting our bearings in
557 * interface methods. */
558 PPDMDEVINSR3 pDevIns;
559
560 /** Status LUN: The base interface. */
561 PDMIBASE IBase;
562 /** Status LUN: Leds interface. */
563 PDMILEDPORTS ILeds;
564 /** Status LUN: Partner of ILeds. */
565 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
566 /** Status LUN: Media Notifys. */
567 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
568
569 /** Register structure per port */
570 AHCIPORTR3 aPorts[AHCI_MAX_NR_PORTS_IMPL];
571
572 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
573 * a port is entering the idle state. */
574 bool volatile fSignalIdle;
575 bool afAlignment7[2+4];
576} AHCIR3;
577/** Pointer to the ring-3 state of an AHCI device. */
578typedef AHCIR3 *PAHCIR3;
579
580
581/**
582 * Main AHCI device ring-0 state.
583 */
584typedef struct AHCIR0
585{
586 uint64_t uUnused;
587} AHCIR0;
588/** Pointer to the ring-0 state of an AHCI device. */
589typedef AHCIR0 *PAHCIR0;
590
591
592/**
593 * Main AHCI device raw-mode state.
594 */
595typedef struct AHCIRC
596{
597 uint64_t uUnused;
598} AHCIRC;
599/** Pointer to the raw-mode state of an AHCI device. */
600typedef AHCIRC *PAHCIRC;
601
602
603/** Main AHCI device current context state. */
604typedef CTX_SUFF(AHCI) AHCICC;
605/** Pointer to the current context state of an AHCI device. */
606typedef CTX_SUFF(PAHCI) PAHCICC;
607
608
609/**
610 * Scatter gather list entry.
611 */
612typedef struct
613{
614 /** Data Base Address. */
615 uint32_t u32DBA;
616 /** Data Base Address - Upper 32-bits. */
617 uint32_t u32DBAUp;
618 /** Reserved */
619 uint32_t u32Reserved;
620 /** Description information. */
621 uint32_t u32DescInf;
622} SGLEntry;
623AssertCompileSize(SGLEntry, 16);
624
625#ifdef IN_RING3
626/**
627 * Memory buffer callback.
628 *
629 * @returns nothing.
630 * @param pDevIns The device instance.
631 * @param GCPhys The guest physical address of the memory buffer.
632 * @param pSgBuf The pointer to the host R3 S/G buffer.
633 * @param cbCopy How many bytes to copy between the two buffers.
634 * @param pcbSkip Initially contains the amount of bytes to skip
635 * starting from the guest physical address before
636 * accessing the S/G buffer and start copying data.
637 * On return this contains the remaining amount if
638 * cbCopy < *pcbSkip or 0 otherwise.
639 */
640typedef DECLCALLBACKTYPE(void, FNAHCIR3MEMCOPYCALLBACK,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
641 PRTSGBUF pSgBuf, size_t cbCopy, size_t *pcbSkip));
642/** Pointer to a memory copy buffer callback. */
643typedef FNAHCIR3MEMCOPYCALLBACK *PFNAHCIR3MEMCOPYCALLBACK;
644#endif
645
646/** Defines for a scatter gather list entry. */
647#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
648#define SGLENTRY_DESCINF_I RT_BIT(31)
649#define SGLENTRY_DESCINF_DBC 0x3fffff
650#define SGLENTRY_DESCINF_READONLY 0x803fffff
651
652/* Defines for the global host control registers for the HBA. */
653
654#define AHCI_HBA_GLOBAL_SIZE 0x100
655
656/* Defines for the HBA Capabilities - Readonly */
657#define AHCI_HBA_CAP_S64A RT_BIT(31)
658#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
659#define AHCI_HBA_CAP_SIS RT_BIT(28)
660#define AHCI_HBA_CAP_SSS RT_BIT(27)
661#define AHCI_HBA_CAP_SALP RT_BIT(26)
662#define AHCI_HBA_CAP_SAL RT_BIT(25)
663#define AHCI_HBA_CAP_SCLO RT_BIT(24)
664#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
665# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
666# define AHCI_HBA_CAP_ISS_GEN1 RT_BIT(0)
667# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
668#define AHCI_HBA_CAP_SNZO RT_BIT(19)
669#define AHCI_HBA_CAP_SAM RT_BIT(18)
670#define AHCI_HBA_CAP_SPM RT_BIT(17)
671#define AHCI_HBA_CAP_PMD RT_BIT(15)
672#define AHCI_HBA_CAP_SSC RT_BIT(14)
673#define AHCI_HBA_CAP_PSC RT_BIT(13)
674#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
675#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
676#define AHCI_HBA_CAP_CCCS RT_BIT(7)
677#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
678#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
679
680/* Defines for the HBA Control register - Read/Write */
681#define AHCI_HBA_CTRL_AE RT_BIT(31)
682#define AHCI_HBA_CTRL_IE RT_BIT(1)
683#define AHCI_HBA_CTRL_HR RT_BIT(0)
684#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
685
686/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
687#define AHCI_HBA_VS_MJR (1 << 16)
688#define AHCI_HBA_VS_MNR 0x100
689
690/* Defines for the command completion coalescing control register */
691#define AHCI_HBA_CCC_CTL_TV 0xffff0000
692#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
693#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
694
695#define AHCI_HBA_CCC_CTL_CC 0xff00
696#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
697#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
698
699#define AHCI_HBA_CCC_CTL_INT 0xf8
700#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
701#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
702
703#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
704
705/* Defines for the port registers. */
706
707#define AHCI_PORT_REGISTER_SIZE 0x80
708
709#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
710
711#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
712
713#define AHCI_PORT_IS_CPDS RT_BIT(31)
714#define AHCI_PORT_IS_TFES RT_BIT(30)
715#define AHCI_PORT_IS_HBFS RT_BIT(29)
716#define AHCI_PORT_IS_HBDS RT_BIT(28)
717#define AHCI_PORT_IS_IFS RT_BIT(27)
718#define AHCI_PORT_IS_INFS RT_BIT(26)
719#define AHCI_PORT_IS_OFS RT_BIT(24)
720#define AHCI_PORT_IS_IPMS RT_BIT(23)
721#define AHCI_PORT_IS_PRCS RT_BIT(22)
722#define AHCI_PORT_IS_DIS RT_BIT(7)
723#define AHCI_PORT_IS_PCS RT_BIT(6)
724#define AHCI_PORT_IS_DPS RT_BIT(5)
725#define AHCI_PORT_IS_UFS RT_BIT(4)
726#define AHCI_PORT_IS_SDBS RT_BIT(3)
727#define AHCI_PORT_IS_DSS RT_BIT(2)
728#define AHCI_PORT_IS_PSS RT_BIT(1)
729#define AHCI_PORT_IS_DHRS RT_BIT(0)
730#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
731
732#define AHCI_PORT_IE_CPDE RT_BIT(31)
733#define AHCI_PORT_IE_TFEE RT_BIT(30)
734#define AHCI_PORT_IE_HBFE RT_BIT(29)
735#define AHCI_PORT_IE_HBDE RT_BIT(28)
736#define AHCI_PORT_IE_IFE RT_BIT(27)
737#define AHCI_PORT_IE_INFE RT_BIT(26)
738#define AHCI_PORT_IE_OFE RT_BIT(24)
739#define AHCI_PORT_IE_IPME RT_BIT(23)
740#define AHCI_PORT_IE_PRCE RT_BIT(22)
741#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
742#define AHCI_PORT_IE_PCE RT_BIT(6)
743#define AHCI_PORT_IE_DPE RT_BIT(5)
744#define AHCI_PORT_IE_UFE RT_BIT(4)
745#define AHCI_PORT_IE_SDBE RT_BIT(3)
746#define AHCI_PORT_IE_DSE RT_BIT(2)
747#define AHCI_PORT_IE_PSE RT_BIT(1)
748#define AHCI_PORT_IE_DHRE RT_BIT(0)
749#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
750
751#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
752#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
753# define AHCI_PORT_CMD_ICC_IDLE 0x0
754# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
755# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
756# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
757#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
758#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
759#define AHCI_PORT_CMD_DLAE RT_BIT(25)
760#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
761#define AHCI_PORT_CMD_CPD RT_BIT(20)
762#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
763#define AHCI_PORT_CMD_HPCP RT_BIT(18)
764#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
765#define AHCI_PORT_CMD_CPS RT_BIT(16)
766#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
767#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
768#define AHCI_PORT_CMD_ISS RT_BIT(13) /* Readonly */
769#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
770#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
771#define AHCI_PORT_CMD_FRE RT_BIT(4)
772#define AHCI_PORT_CMD_CLO RT_BIT(3)
773#define AHCI_PORT_CMD_POD RT_BIT(2)
774#define AHCI_PORT_CMD_SUD RT_BIT(1)
775#define AHCI_PORT_CMD_ST RT_BIT(0)
776#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
777
778#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
779#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
780#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
781#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
782#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
783#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
784#define AHCI_PORT_SCTL_DET_NINIT 0
785#define AHCI_PORT_SCTL_DET_INIT 1
786#define AHCI_PORT_SCTL_DET_OFFLINE 4
787#define AHCI_PORT_SCTL_READONLY 0xfff
788
789#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
790#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
791#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
792#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
793#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
794#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
795
796#define AHCI_PORT_TFD_BSY RT_BIT(7)
797#define AHCI_PORT_TFD_DRQ RT_BIT(3)
798#define AHCI_PORT_TFD_ERR RT_BIT(0)
799
800#define AHCI_PORT_SERR_X RT_BIT(26)
801#define AHCI_PORT_SERR_W RT_BIT(18)
802#define AHCI_PORT_SERR_N RT_BIT(16)
803
804/* Signatures for attached storage devices. */
805#define AHCI_PORT_SIG_DISK 0x00000101
806#define AHCI_PORT_SIG_ATAPI 0xeb140101
807
808/*
809 * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
810 * regFB points to the base of this area.
811 * Every FIS type has an offset where it is posted in this area.
812 */
813#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
814#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
815#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
816#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
817#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
818
819/** Mask to get the LBA value from a LBA range. */
820#define AHCI_RANGE_LBA_MASK UINT64_C(0xffffffffffff)
821/** Mas to get the length value from a LBA range. */
822#define AHCI_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
823/** Returns the length of the range in sectors. */
824#define AHCI_RANGE_LENGTH_GET(val) (((val) & AHCI_RANGE_LENGTH_MASK) >> 48)
825
826/**
827 * AHCI register operator.
828 */
829typedef struct ahci_opreg
830{
831 const char *pszName;
832 VBOXSTRICTRC (*pfnRead )(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value);
833 VBOXSTRICTRC (*pfnWrite)(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value);
834} AHCIOPREG;
835
836/**
837 * AHCI port register operator.
838 */
839typedef struct pAhciPort_opreg
840{
841 const char *pszName;
842 VBOXSTRICTRC (*pfnRead )(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value);
843 VBOXSTRICTRC (*pfnWrite)(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value);
844} AHCIPORTOPREG;
845
846
847/*********************************************************************************************************************************
848* Internal Functions *
849*********************************************************************************************************************************/
850#ifndef VBOX_DEVICE_STRUCT_TESTCASE
851RT_C_DECLS_BEGIN
852#ifdef IN_RING3
853static void ahciR3HBAReset(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIR3 pThisCC);
854static int ahciPostFisIntoMemory(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort, unsigned uFisType, uint8_t *pCmdFis);
855static void ahciPostFirstD2HFisIntoMemory(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort);
856static size_t ahciR3CopyBufferToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, const void *pvSrc, size_t cbSrc, size_t cbSkip);
857static bool ahciR3CancelActiveTasks(PAHCIPORTR3 pAhciPortR3);
858#endif
859RT_C_DECLS_END
860
861
862/*********************************************************************************************************************************
863* Defined Constants And Macros *
864*********************************************************************************************************************************/
865#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
866
867#ifdef IN_RING3
868
869# ifdef LOG_USE_C99
870# define ahciLog(a) \
871 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
872# else
873# define ahciLog(a) \
874 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
875# endif
876
877#elif defined(IN_RING0)
878
879# ifdef LOG_USE_C99
880# define ahciLog(a) \
881 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
882# else
883# define ahciLog(a) \
884 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
885# endif
886
887#elif defined(IN_RC)
888
889# ifdef LOG_USE_C99
890# define ahciLog(a) \
891 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
892# else
893# define ahciLog(a) \
894 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
895# endif
896
897#endif
898
899
900
901/**
902 * Update PCI IRQ levels
903 */
904static void ahciHbaClearInterrupt(PPDMDEVINS pDevIns)
905{
906 Log(("%s: Clearing interrupt\n", __FUNCTION__));
907 PDMDevHlpPCISetIrq(pDevIns, 0, 0);
908}
909
910/**
911 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
912 */
913static int ahciHbaSetInterrupt(PPDMDEVINS pDevIns, PAHCI pThis, uint8_t iPort, int rcBusy)
914{
915 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
916
917 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->lock, rcBusy);
918 if (rc != VINF_SUCCESS)
919 return rc;
920
921 if (pThis->regHbaCtrl & AHCI_HBA_CTRL_IE)
922 {
923 if ((pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pThis->regHbaCccPorts & (1 << iPort)))
924 {
925 pThis->uCccCurrentNr++;
926 if (pThis->uCccCurrentNr >= pThis->uCccNr)
927 {
928 /* Reset command completion coalescing state. */
929 PDMDevHlpTimerSetMillies(pDevIns, pThis->hHbaCccTimer, pThis->uCccTimeout);
930 pThis->uCccCurrentNr = 0;
931
932 pThis->u32PortsInterrupted |= (1 << pThis->uCccPortNr);
933 if (!(pThis->u32PortsInterrupted & ~(1 << pThis->uCccPortNr)))
934 {
935 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
936 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
937 }
938 }
939 }
940 else
941 {
942 /* If only the bit of the actual port is set assert an interrupt
943 * because the interrupt status register was already read by the guest
944 * and we need to send a new notification.
945 * Otherwise an interrupt is still pending.
946 */
947 ASMAtomicOrU32((volatile uint32_t *)&pThis->u32PortsInterrupted, (1 << iPort));
948 if (!(pThis->u32PortsInterrupted & ~(1 << iPort)))
949 {
950 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
951 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
952 }
953 }
954 }
955
956 PDMDevHlpCritSectLeave(pDevIns, &pThis->lock);
957 return VINF_SUCCESS;
958}
959
960#ifdef IN_RING3
961
962/**
963 * @callback_method_impl{FNTMTIMERDEV, Assert irq when an CCC timeout occurs.}
964 */
965static DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
966{
967 RT_NOREF(pDevIns, hTimer);
968 PAHCI pThis = (PAHCI)pvUser;
969
970 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pThis->uCccPortNr, VERR_IGNORED);
971 AssertRC(rc);
972}
973
974/**
975 * Finishes the port reset of the given port.
976 *
977 * @returns nothing.
978 * @param pDevIns The device instance.
979 * @param pThis The shared AHCI state.
980 * @param pAhciPort The port to finish the reset on, shared bits.
981 * @param pAhciPortR3 The port to finish the reset on, ring-3 bits.
982 */
983static void ahciPortResetFinish(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3)
984{
985 ahciLog(("%s: Initiated.\n", __FUNCTION__));
986
987 /* Cancel all tasks first. */
988 bool fAllTasksCanceled = ahciR3CancelActiveTasks(pAhciPortR3);
989 Assert(fAllTasksCanceled); NOREF(fAllTasksCanceled);
990
991 /* Signature for SATA device. */
992 if (pAhciPort->fATAPI)
993 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
994 else
995 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
996
997 /* We received a COMINIT from the device. Tell the guest. */
998 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
999 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1000 pAhciPort->regTFD |= ATA_STAT_BUSY;
1001
1002 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSent))
1003 {
1004 ahciPostFirstD2HFisIntoMemory(pDevIns, pAhciPort);
1005 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1006
1007 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1008 {
1009 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
1010 AssertRC(rc);
1011 }
1012 }
1013
1014 pAhciPort->regSSTS = (0x01 << 8) /* Interface is active. */
1015 | (0x03 << 0); /* Device detected and communication established. */
1016
1017 /*
1018 * Use the maximum allowed speed.
1019 * (Not that it changes anything really)
1020 */
1021 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1022 {
1023 case 0x01:
1024 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1025 break;
1026 case 0x02:
1027 case 0x00:
1028 default:
1029 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1030 break;
1031 }
1032
1033 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1034}
1035
1036#endif /* IN_RING3 */
1037
1038/**
1039 * Kicks the I/O thread from RC or R0.
1040 *
1041 * @returns nothing.
1042 * @param pDevIns The device instance.
1043 * @param pAhciPort The port to kick, shared bits.
1044 */
1045static void ahciIoThreadKick(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort)
1046{
1047 LogFlowFunc(("Signal event semaphore\n"));
1048 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pAhciPort->hEvtProcess);
1049 AssertRC(rc);
1050}
1051
1052static VBOXSTRICTRC PortCmdIssue_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1053{
1054 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1055 RT_NOREF(pThis, iReg);
1056
1057 /* Update the CI register first. */
1058 uint32_t uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1059 pAhciPort->regCI &= ~uCIValue;
1060
1061 if ( (pAhciPort->regCMD & AHCI_PORT_CMD_CR)
1062 && u32Value > 0)
1063 {
1064 /*
1065 * Clear all tasks which are already marked as busy. The guest
1066 * shouldn't write already busy tasks actually.
1067 */
1068 u32Value &= ~pAhciPort->regCI;
1069
1070 ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
1071
1072 /* Send a notification to R3 if u32TasksNew was 0 before our write. */
1073 if (ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1074 ahciIoThreadKick(pDevIns, pAhciPort);
1075 else
1076 ahciLog(("%s: Worker thread busy, no need to kick.\n", __FUNCTION__));
1077 }
1078 else
1079 ahciLog(("%s: Nothing to do (CMD=%08x).\n", __FUNCTION__, pAhciPort->regCMD));
1080
1081 pAhciPort->regCI |= u32Value;
1082
1083 return VINF_SUCCESS;
1084}
1085
1086static VBOXSTRICTRC PortCmdIssue_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1087{
1088 RT_NOREF(pDevIns, pThis, iReg);
1089
1090 uint32_t uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1091 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
1092
1093 pAhciPort->regCI &= ~uCIValue;
1094 *pu32Value = pAhciPort->regCI;
1095
1096 return VINF_SUCCESS;
1097}
1098
1099static VBOXSTRICTRC PortSActive_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1100{
1101 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1102 RT_NOREF(pDevIns, pThis, iReg);
1103
1104 pAhciPort->regSACT |= u32Value;
1105
1106 return VINF_SUCCESS;
1107}
1108
1109static VBOXSTRICTRC PortSActive_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1110{
1111 RT_NOREF(pDevIns, pThis, iReg);
1112
1113 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1114 pAhciPort->regSACT &= ~u32TasksFinished;
1115
1116 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1117 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1118
1119 *pu32Value = pAhciPort->regSACT;
1120
1121 return VINF_SUCCESS;
1122}
1123
1124static VBOXSTRICTRC PortSError_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1125{
1126 RT_NOREF(pDevIns, pThis, iReg);
1127 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1128
1129 if ( (u32Value & AHCI_PORT_SERR_X)
1130 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1131 {
1132 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1133 pAhciPort->regTFD |= ATA_STAT_ERR;
1134 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1135 }
1136
1137 if ( (u32Value & AHCI_PORT_SERR_N)
1138 && (pAhciPort->regSERR & AHCI_PORT_SERR_N))
1139 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
1140
1141 pAhciPort->regSERR &= ~u32Value;
1142
1143 return VINF_SUCCESS;
1144}
1145
1146static VBOXSTRICTRC PortSError_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1147{
1148 RT_NOREF(pDevIns, pThis, iReg);
1149 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1150 *pu32Value = pAhciPort->regSERR;
1151 return VINF_SUCCESS;
1152}
1153
1154static VBOXSTRICTRC PortSControl_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1155{
1156 RT_NOREF(pThis, iReg);
1157 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1158 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1159 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1160
1161#ifndef IN_RING3
1162 RT_NOREF(pDevIns, pAhciPort, u32Value);
1163 return VINF_IOM_R3_MMIO_WRITE;
1164#else
1165 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1166 {
1167 if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
1168 LogRel(("AHCI#%u: Port %d reset\n", pDevIns->iInstance,
1169 pAhciPort->iLUN));
1170
1171 pAhciPort->regSSTS = 0;
1172 pAhciPort->regSIG = UINT32_MAX;
1173 pAhciPort->regTFD = 0x7f;
1174 pAhciPort->fFirstD2HFisSent = false;
1175 pAhciPort->regSCTL = u32Value;
1176 }
1177 else if ( (u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT
1178 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT
1179 && pAhciPort->fPresent)
1180 {
1181 /* Do the port reset here, so the guest sees the new status immediately. */
1182 if (pThis->fLegacyPortResetMethod)
1183 {
1184 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
1185 PAHCIPORTR3 pAhciPortR3 = &RT_SAFE_SUBSCRIPT(pThisCC->aPorts, pAhciPort->iLUN);
1186 ahciPortResetFinish(pDevIns, pThis, pAhciPort, pAhciPortR3);
1187 pAhciPort->regSCTL = u32Value; /* Update after finishing the reset, so the I/O thread doesn't get a chance to do the reset. */
1188 }
1189 else
1190 {
1191 if (!pThis->fTigerHack)
1192 pAhciPort->regSSTS = 0x1; /* Indicate device presence detected but communication not established. */
1193 else
1194 pAhciPort->regSSTS = 0x0; /* Indicate no device detected after COMRESET. [tiger hack] */
1195 pAhciPort->regSCTL = u32Value; /* Update before kicking the I/O thread. */
1196
1197 /* Kick the thread to finish the reset. */
1198 ahciIoThreadKick(pDevIns, pAhciPort);
1199 }
1200 }
1201 else /* Just update the value if there is no device attached. */
1202 pAhciPort->regSCTL = u32Value;
1203
1204 return VINF_SUCCESS;
1205#endif
1206}
1207
1208static VBOXSTRICTRC PortSControl_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1209{
1210 RT_NOREF(pDevIns, pThis, iReg);
1211 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1212 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1213 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1214 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1215
1216 *pu32Value = pAhciPort->regSCTL;
1217 return VINF_SUCCESS;
1218}
1219
1220static VBOXSTRICTRC PortSStatus_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1221{
1222 RT_NOREF(pDevIns, pThis, iReg);
1223 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1224 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1225 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1226 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1227
1228 *pu32Value = pAhciPort->regSSTS;
1229 return VINF_SUCCESS;
1230}
1231
1232static VBOXSTRICTRC PortSignature_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1233{
1234 RT_NOREF(pDevIns, pThis, iReg);
1235 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1236 *pu32Value = pAhciPort->regSIG;
1237 return VINF_SUCCESS;
1238}
1239
1240static VBOXSTRICTRC PortTaskFileData_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1241{
1242 RT_NOREF(pDevIns, pThis, iReg);
1243 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1244 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1245 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1246 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1247 *pu32Value = pAhciPort->regTFD;
1248 return VINF_SUCCESS;
1249}
1250
1251/**
1252 * Read from the port command register.
1253 */
1254static VBOXSTRICTRC PortCmd_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1255{
1256 RT_NOREF(pDevIns, pThis, iReg);
1257 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot)));
1258 ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
1259 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1260 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1261 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1262 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1263 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1264 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1265 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
1266 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1267 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1268 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1269 *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
1270 return VINF_SUCCESS;
1271}
1272
1273/**
1274 * Write to the port command register.
1275 * This is the register where all the data transfer is started
1276 */
1277static VBOXSTRICTRC PortCmd_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1278{
1279 RT_NOREF(pDevIns, pThis, iReg);
1280 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1281 ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
1282 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1283 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1284 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1285 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1286 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1287 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1288 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1289 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1290 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1291 (u32Value & AHCI_PORT_CMD_ST)));
1292
1293 /* The PxCMD.CCS bits are R/O and maintained separately. */
1294 u32Value &= ~AHCI_PORT_CMD_CCS;
1295
1296 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1297 {
1298 if (u32Value & AHCI_PORT_CMD_CLO)
1299 {
1300 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1301 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1302 /* Clear the CLO bit. */
1303 u32Value &= ~(AHCI_PORT_CMD_CLO);
1304 }
1305
1306 if (u32Value & AHCI_PORT_CMD_ST)
1307 {
1308 /*
1309 * Set engine state to running if there is a device attached and
1310 * IS.PCS is clear.
1311 */
1312 if ( pAhciPort->fPresent
1313 && !(pAhciPort->regIS & AHCI_PORT_IS_PCS))
1314 {
1315 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1316 u32Value |= AHCI_PORT_CMD_CR;
1317
1318 /* If there is something in CI, kick the I/O thread. */
1319 if ( pAhciPort->regCI > 0
1320 && ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1321 {
1322 ASMAtomicOrU32(&pAhciPort->u32TasksNew, pAhciPort->regCI);
1323 LogFlowFunc(("Signal event semaphore\n"));
1324 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pAhciPort->hEvtProcess);
1325 AssertRC(rc);
1326 }
1327 }
1328 else
1329 {
1330 if (!pAhciPort->fPresent)
1331 ahciLog(("%s: No pDrvBase, clearing PxCMD.CR!\n", __FUNCTION__));
1332 else
1333 ahciLog(("%s: PxIS.PCS set (PxIS=%#010x), clearing PxCMD.CR!\n", __FUNCTION__, pAhciPort->regIS));
1334
1335 u32Value &= ~AHCI_PORT_CMD_CR;
1336 }
1337 }
1338 else
1339 {
1340 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1341 /* Clear command issue register. */
1342 pAhciPort->regCI = 0;
1343 pAhciPort->regSACT = 0;
1344 /* Clear current command slot. */
1345 pAhciPort->u32CurrentCommandSlot = 0;
1346 u32Value &= ~AHCI_PORT_CMD_CR;
1347 }
1348 }
1349 else if (pAhciPort->fPresent)
1350 {
1351 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1352 {
1353 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1354 pAhciPort->fPoweredOn = true;
1355
1356 /*
1357 * Set states in the Port Signature and SStatus registers.
1358 */
1359 if (pAhciPort->fATAPI)
1360 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1361 else
1362 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1363 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1364 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1365 (0x03 << 0); /* Device detected and communication established. */
1366
1367 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1368 {
1369#ifndef IN_RING3
1370 return VINF_IOM_R3_MMIO_WRITE;
1371#else
1372 ahciPostFirstD2HFisIntoMemory(pDevIns, pAhciPort);
1373 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1374
1375 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1376 {
1377 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
1378 AssertRC(rc);
1379 }
1380#endif
1381 }
1382 }
1383
1384 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1385 {
1386 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1387 pAhciPort->fSpunUp = true;
1388 }
1389 }
1390 else
1391 ahciLog(("%s: No pDrvBase, no fPoweredOn + fSpunUp, doing nothing!\n", __FUNCTION__));
1392
1393 if (u32Value & AHCI_PORT_CMD_FRE)
1394 {
1395 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1396
1397 u32Value |= AHCI_PORT_CMD_FR;
1398
1399 /* Send the first D2H FIS only if it wasn't already sent. */
1400 if ( !pAhciPort->fFirstD2HFisSent
1401 && pAhciPort->fPresent)
1402 {
1403#ifndef IN_RING3
1404 return VINF_IOM_R3_MMIO_WRITE;
1405#else
1406 ahciPostFirstD2HFisIntoMemory(pDevIns, pAhciPort);
1407 pAhciPort->fFirstD2HFisSent = true;
1408#endif
1409 }
1410 }
1411 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1412 {
1413 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1414 u32Value &= ~AHCI_PORT_CMD_FR;
1415 }
1416
1417 pAhciPort->regCMD = u32Value;
1418
1419 return VINF_SUCCESS;
1420}
1421
1422/**
1423 * Read from the port interrupt enable register.
1424 */
1425static VBOXSTRICTRC PortIntrEnable_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1426{
1427 RT_NOREF(pDevIns, pThis, iReg);
1428 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1429 ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
1430 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1431 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1432 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1433 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1434 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1435 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1436 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1437 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1438 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1439 *pu32Value = pAhciPort->regIE;
1440 return VINF_SUCCESS;
1441}
1442
1443/**
1444 * Write to the port interrupt enable register.
1445 */
1446static VBOXSTRICTRC PortIntrEnable_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1447{
1448 RT_NOREF(iReg);
1449 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1450 ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
1451 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1452 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1453 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1454 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1455 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1456 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1457 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1458 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1459 (u32Value & AHCI_PORT_IE_DHRE)));
1460
1461 u32Value &= AHCI_PORT_IE_READONLY;
1462
1463 /* Check if some a interrupt status bit changed*/
1464 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1465
1466 int rc = VINF_SUCCESS;
1467 if (u32Value & u32IntrStatus)
1468 rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
1469
1470 if (rc == VINF_SUCCESS)
1471 pAhciPort->regIE = u32Value;
1472
1473 return rc;
1474}
1475
1476/**
1477 * Read from the port interrupt status register.
1478 */
1479static VBOXSTRICTRC PortIntrSts_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1480{
1481 RT_NOREF(pDevIns, pThis, iReg);
1482 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1483 ahciLog(("%s: CPDS=%d TFES=%d HBFS=%d HBDS=%d IFS=%d INFS=%d OFS=%d IPMS=%d PRCS=%d DIS=%d PCS=%d DPS=%d UFS=%d SDBS=%d DSS=%d PSS=%d DHRS=%d\n",
1484 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1485 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1486 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1487 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1488 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1489 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1490 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1491 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1492 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1493 *pu32Value = pAhciPort->regIS;
1494 return VINF_SUCCESS;
1495}
1496
1497/**
1498 * Write to the port interrupt status register.
1499 */
1500static VBOXSTRICTRC PortIntrSts_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1501{
1502 RT_NOREF(pDevIns, pThis, iReg);
1503 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1504 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1505
1506 return VINF_SUCCESS;
1507}
1508
1509/**
1510 * Read from the port FIS base address upper 32bit register.
1511 */
1512static VBOXSTRICTRC PortFisAddrUp_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1513{
1514 RT_NOREF(pDevIns, pThis, iReg);
1515 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1516 *pu32Value = pAhciPort->regFBU;
1517 return VINF_SUCCESS;
1518}
1519
1520/**
1521 * Write to the port FIS base address upper 32bit register.
1522 */
1523static VBOXSTRICTRC PortFisAddrUp_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1524{
1525 RT_NOREF(pDevIns, pThis, iReg);
1526 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1527
1528 pAhciPort->regFBU = u32Value;
1529 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1530
1531 return VINF_SUCCESS;
1532}
1533
1534/**
1535 * Read from the port FIS base address register.
1536 */
1537static VBOXSTRICTRC PortFisAddr_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1538{
1539 RT_NOREF(pDevIns, pThis, iReg);
1540 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1541 *pu32Value = pAhciPort->regFB;
1542 return VINF_SUCCESS;
1543}
1544
1545/**
1546 * Write to the port FIS base address register.
1547 */
1548static VBOXSTRICTRC PortFisAddr_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1549{
1550 RT_NOREF(pDevIns, pThis, iReg);
1551 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1552
1553 Assert(!(u32Value & ~AHCI_PORT_FB_RESERVED));
1554
1555 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1556 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1557
1558 return VINF_SUCCESS;
1559}
1560
1561/**
1562 * Write to the port command list base address upper 32bit register.
1563 */
1564static VBOXSTRICTRC PortCmdLstAddrUp_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1565{
1566 RT_NOREF(pDevIns, pThis, iReg);
1567 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1568
1569 pAhciPort->regCLBU = u32Value;
1570 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1571
1572 return VINF_SUCCESS;
1573}
1574
1575/**
1576 * Read from the port command list base address upper 32bit register.
1577 */
1578static VBOXSTRICTRC PortCmdLstAddrUp_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1579{
1580 RT_NOREF(pDevIns, pThis, iReg);
1581 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1582 *pu32Value = pAhciPort->regCLBU;
1583 return VINF_SUCCESS;
1584}
1585
1586/**
1587 * Read from the port command list base address register.
1588 */
1589static VBOXSTRICTRC PortCmdLstAddr_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1590{
1591 RT_NOREF(pDevIns, pThis, iReg);
1592 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1593 *pu32Value = pAhciPort->regCLB;
1594 return VINF_SUCCESS;
1595}
1596
1597/**
1598 * Write to the port command list base address register.
1599 */
1600static VBOXSTRICTRC PortCmdLstAddr_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1601{
1602 RT_NOREF(pDevIns, pThis, iReg);
1603 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1604
1605 Assert(!(u32Value & ~AHCI_PORT_CLB_RESERVED));
1606
1607 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1608 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1609
1610 return VINF_SUCCESS;
1611}
1612
1613/**
1614 * Read from the global Version register.
1615 */
1616static VBOXSTRICTRC HbaVersion_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1617{
1618 RT_NOREF(pDevIns, iReg);
1619 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, pThis->regHbaVs));
1620 *pu32Value = pThis->regHbaVs;
1621 return VINF_SUCCESS;
1622}
1623
1624/**
1625 * Read from the global Ports implemented register.
1626 */
1627static VBOXSTRICTRC HbaPortsImplemented_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1628{
1629 RT_NOREF(pDevIns, iReg);
1630 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, pThis->regHbaPi));
1631 *pu32Value = pThis->regHbaPi;
1632 return VINF_SUCCESS;
1633}
1634
1635/**
1636 * Write to the global interrupt status register.
1637 */
1638static VBOXSTRICTRC HbaInterruptStatus_w(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value)
1639{
1640 RT_NOREF(iReg);
1641 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1642
1643 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->lock, VINF_IOM_R3_MMIO_WRITE);
1644 if (rc != VINF_SUCCESS)
1645 return rc;
1646
1647 pThis->regHbaIs &= ~(u32Value);
1648
1649 /*
1650 * Update interrupt status register and check for ports who
1651 * set the interrupt inbetween.
1652 */
1653 bool fClear = true;
1654 pThis->regHbaIs |= ASMAtomicXchgU32(&pThis->u32PortsInterrupted, 0);
1655 if (!pThis->regHbaIs)
1656 {
1657 unsigned i = 0;
1658
1659 /* Check if the cleared ports have a interrupt status bit set. */
1660 while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
1661 {
1662 if (u32Value & 0x01)
1663 {
1664 PAHCIPORT pAhciPort = &pThis->aPorts[i];
1665
1666 if (pAhciPort->regIE & pAhciPort->regIS)
1667 {
1668 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1669 ASMAtomicOrU32(&pThis->u32PortsInterrupted, 1 << i);
1670 fClear = false;
1671 break;
1672 }
1673 }
1674 u32Value >>= 1;
1675 i++;
1676 }
1677 }
1678 else
1679 fClear = false;
1680
1681 if (fClear)
1682 ahciHbaClearInterrupt(pDevIns);
1683 else
1684 {
1685 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, pThis->u32PortsInterrupted));
1686 /*
1687 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1688 * line is still high.
1689 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1690 */
1691 PDMDevHlpPCISetIrq(pDevIns, 0, 0);
1692 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
1693 }
1694
1695 PDMDevHlpCritSectLeave(pDevIns, &pThis->lock);
1696 return VINF_SUCCESS;
1697}
1698
1699/**
1700 * Read from the global interrupt status register.
1701 */
1702static VBOXSTRICTRC HbaInterruptStatus_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1703{
1704 RT_NOREF(iReg);
1705
1706 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->lock, VINF_IOM_R3_MMIO_READ);
1707 if (rc != VINF_SUCCESS)
1708 return rc;
1709
1710 uint32_t u32PortsInterrupted = ASMAtomicXchgU32(&pThis->u32PortsInterrupted, 0);
1711
1712 PDMDevHlpCritSectLeave(pDevIns, &pThis->lock);
1713 Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, pThis->regHbaIs, u32PortsInterrupted));
1714
1715 pThis->regHbaIs |= u32PortsInterrupted;
1716
1717#ifdef LOG_ENABLED
1718 Log(("%s:", __FUNCTION__));
1719 uint32_t const cPortsImpl = RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts));
1720 for (unsigned i = 0; i < cPortsImpl; i++)
1721 {
1722 if ((pThis->regHbaIs >> i) & 0x01)
1723 Log((" P%d", i));
1724 }
1725 Log(("\n"));
1726#endif
1727
1728 *pu32Value = pThis->regHbaIs;
1729
1730 return VINF_SUCCESS;
1731}
1732
1733/**
1734 * Write to the global control register.
1735 */
1736static VBOXSTRICTRC HbaControl_w(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value)
1737{
1738 Log(("%s: write u32Value=%#010x\n"
1739 "%s: AE=%d IE=%d HR=%d\n",
1740 __FUNCTION__, u32Value,
1741 __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
1742 (u32Value & AHCI_HBA_CTRL_HR)));
1743 RT_NOREF(iReg);
1744
1745#ifndef IN_RING3
1746 RT_NOREF(pDevIns, pThis, u32Value);
1747 return VINF_IOM_R3_MMIO_WRITE;
1748#else
1749 /*
1750 * Increase the active thread counter because we might set the host controller
1751 * reset bit.
1752 */
1753 ASMAtomicIncU32(&pThis->cThreadsActive);
1754 ASMAtomicWriteU32(&pThis->regHbaCtrl, (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE);
1755
1756 /*
1757 * Do the HBA reset if requested and there is no other active thread at the moment,
1758 * the work is deferred to the last active thread otherwise.
1759 */
1760 uint32_t cThreadsActive = ASMAtomicDecU32(&pThis->cThreadsActive);
1761 if ( (u32Value & AHCI_HBA_CTRL_HR)
1762 && !cThreadsActive)
1763 ahciR3HBAReset(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC));
1764
1765 return VINF_SUCCESS;
1766#endif
1767}
1768
1769/**
1770 * Read the global control register.
1771 */
1772static VBOXSTRICTRC HbaControl_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1773{
1774 RT_NOREF(pDevIns, iReg);
1775 Log(("%s: read regHbaCtrl=%#010x\n"
1776 "%s: AE=%d IE=%d HR=%d\n",
1777 __FUNCTION__, pThis->regHbaCtrl,
1778 __FUNCTION__, (pThis->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (pThis->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
1779 (pThis->regHbaCtrl & AHCI_HBA_CTRL_HR)));
1780 *pu32Value = pThis->regHbaCtrl;
1781 return VINF_SUCCESS;
1782}
1783
1784/**
1785 * Read the global capabilities register.
1786 */
1787static VBOXSTRICTRC HbaCapabilities_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1788{
1789 RT_NOREF(pDevIns, iReg);
1790 Log(("%s: read regHbaCap=%#010x\n"
1791 "%s: S64A=%d SNCQ=%d SIS=%d SSS=%d SALP=%d SAL=%d SCLO=%d ISS=%d SNZO=%d SAM=%d SPM=%d PMD=%d SSC=%d PSC=%d NCS=%d NP=%d\n",
1792 __FUNCTION__, pThis->regHbaCap,
1793 __FUNCTION__, (pThis->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (pThis->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
1794 (pThis->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (pThis->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
1795 (pThis->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (pThis->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
1796 (pThis->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (pThis->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
1797 (pThis->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (pThis->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
1798 (pThis->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (pThis->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
1799 (pThis->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (pThis->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
1800 (pThis->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (pThis->regHbaCap & AHCI_HBA_CAP_NP)));
1801 *pu32Value = pThis->regHbaCap;
1802 return VINF_SUCCESS;
1803}
1804
1805/**
1806 * Write to the global command completion coalescing control register.
1807 */
1808static VBOXSTRICTRC HbaCccCtl_w(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value)
1809{
1810 RT_NOREF(iReg);
1811 Log(("%s: write u32Value=%#010x\n"
1812 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1813 __FUNCTION__, u32Value,
1814 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
1815 AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
1816
1817 pThis->regHbaCccCtl = u32Value;
1818 pThis->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
1819 pThis->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
1820 pThis->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
1821
1822 if (u32Value & AHCI_HBA_CCC_CTL_EN)
1823 PDMDevHlpTimerSetMillies(pDevIns, pThis->hHbaCccTimer, pThis->uCccTimeout); /* Arm the timer */
1824 else
1825 PDMDevHlpTimerStop(pDevIns, pThis->hHbaCccTimer);
1826
1827 return VINF_SUCCESS;
1828}
1829
1830/**
1831 * Read the global command completion coalescing control register.
1832 */
1833static VBOXSTRICTRC HbaCccCtl_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1834{
1835 RT_NOREF(pDevIns, iReg);
1836 Log(("%s: read regHbaCccCtl=%#010x\n"
1837 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1838 __FUNCTION__, pThis->regHbaCccCtl,
1839 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(pThis->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(pThis->regHbaCccCtl),
1840 AHCI_HBA_CCC_CTL_INT_GET(pThis->regHbaCccCtl), (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
1841 *pu32Value = pThis->regHbaCccCtl;
1842 return VINF_SUCCESS;
1843}
1844
1845/**
1846 * Write to the global command completion coalescing ports register.
1847 */
1848static VBOXSTRICTRC HbaCccPorts_w(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value)
1849{
1850 RT_NOREF(pDevIns, iReg);
1851 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1852
1853 pThis->regHbaCccPorts = u32Value;
1854
1855 return VINF_SUCCESS;
1856}
1857
1858/**
1859 * Read the global command completion coalescing ports register.
1860 */
1861static VBOXSTRICTRC HbaCccPorts_r(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t *pu32Value)
1862{
1863 RT_NOREF(pDevIns, iReg);
1864 Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, pThis->regHbaCccPorts));
1865
1866#ifdef LOG_ENABLED
1867 Log(("%s:", __FUNCTION__));
1868 uint32_t const cPortsImpl = RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts));
1869 for (unsigned i = 0; i < cPortsImpl; i++)
1870 {
1871 if ((pThis->regHbaCccPorts >> i) & 0x01)
1872 Log((" P%d", i));
1873 }
1874 Log(("\n"));
1875#endif
1876
1877 *pu32Value = pThis->regHbaCccPorts;
1878 return VINF_SUCCESS;
1879}
1880
1881/**
1882 * Invalid write to global register
1883 */
1884static VBOXSTRICTRC HbaInvalid_w(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t iReg, uint32_t u32Value)
1885{
1886 RT_NOREF(pDevIns, pThis, iReg, u32Value);
1887 Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1888 return VINF_SUCCESS;
1889}
1890
1891/**
1892 * Invalid Port write.
1893 */
1894static VBOXSTRICTRC PortInvalid_w(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t u32Value)
1895{
1896 RT_NOREF(pDevIns, pThis, pAhciPort, iReg, u32Value);
1897 ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1898 return VINF_SUCCESS;
1899}
1900
1901/**
1902 * Invalid Port read.
1903 */
1904static VBOXSTRICTRC PortInvalid_r(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1905{
1906 RT_NOREF(pDevIns, pThis, pAhciPort, iReg, pu32Value);
1907 ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
1908 return VINF_SUCCESS;
1909}
1910
1911/**
1912 * Register descriptor table for global HBA registers
1913 */
1914static const AHCIOPREG g_aOpRegs[] =
1915{
1916 {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
1917 {"HbaControl" , HbaControl_r, HbaControl_w},
1918 {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
1919 {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
1920 {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
1921 {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
1922 {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
1923};
1924
1925/**
1926 * Register descriptor table for port registers
1927 */
1928static const AHCIPORTOPREG g_aPortOpRegs[] =
1929{
1930 {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
1931 {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
1932 {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
1933 {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
1934 {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
1935 {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
1936 {"PortCmd", PortCmd_r, PortCmd_w},
1937 {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
1938 {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
1939 {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
1940 {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
1941 {"PortSControl", PortSControl_r, PortSControl_w},
1942 {"PortSError", PortSError_r, PortSError_w},
1943 {"PortSActive", PortSActive_r, PortSActive_w},
1944 {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
1945 {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
1946};
1947
1948#ifdef IN_RING3
1949
1950/**
1951 * Reset initiated by system software for one port.
1952 *
1953 * @param pAhciPort The port to reset, shared bits.
1954 * @param pAhciPortR3 The port to reset, ring-3 bits.
1955 */
1956static void ahciR3PortSwReset(PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3)
1957{
1958 bool fAllTasksCanceled;
1959
1960 /* Cancel all tasks first. */
1961 fAllTasksCanceled = ahciR3CancelActiveTasks(pAhciPortR3);
1962 Assert(fAllTasksCanceled);
1963
1964 Assert(pAhciPort->cTasksActive == 0);
1965
1966 pAhciPort->regIS = 0;
1967 pAhciPort->regIE = 0;
1968 pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
1969 AHCI_PORT_CMD_SUD | /* Device has spun up. */
1970 AHCI_PORT_CMD_POD; /* Port is powered on. */
1971
1972 /* Hotplugging supported?. */
1973 if (pAhciPort->fHotpluggable)
1974 pAhciPort->regCMD |= AHCI_PORT_CMD_HPCP;
1975
1976 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
1977 pAhciPort->regSIG = UINT32_MAX;
1978 pAhciPort->regSSTS = 0;
1979 pAhciPort->regSCTL = 0;
1980 pAhciPort->regSERR = 0;
1981 pAhciPort->regSACT = 0;
1982 pAhciPort->regCI = 0;
1983
1984 pAhciPort->fResetDevice = false;
1985 pAhciPort->fPoweredOn = true;
1986 pAhciPort->fSpunUp = true;
1987 pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
1988 pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
1989
1990 pAhciPort->u32TasksNew = 0;
1991 pAhciPort->u32TasksRedo = 0;
1992 pAhciPort->u32TasksFinished = 0;
1993 pAhciPort->u32QueuedTasksFinished = 0;
1994 pAhciPort->u32CurrentCommandSlot = 0;
1995
1996 if (pAhciPort->fPresent)
1997 {
1998 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
1999
2000 if (pAhciPort->fPoweredOn)
2001 {
2002 /*
2003 * Set states in the Port Signature and SStatus registers.
2004 */
2005 if (pAhciPort->fATAPI)
2006 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
2007 else
2008 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
2009 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
2010 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
2011 (0x03 << 0); /* Device detected and communication established. */
2012 }
2013 }
2014}
2015
2016/**
2017 * Hardware reset used for machine power on and reset.
2018 *
2019 * @param pAhciPort The port to reset, shared bits.
2020 */
2021static void ahciPortHwReset(PAHCIPORT pAhciPort)
2022{
2023 /* Reset the address registers. */
2024 pAhciPort->regCLB = 0;
2025 pAhciPort->regCLBU = 0;
2026 pAhciPort->regFB = 0;
2027 pAhciPort->regFBU = 0;
2028
2029 /* Reset calculated addresses. */
2030 pAhciPort->GCPhysAddrClb = 0;
2031 pAhciPort->GCPhysAddrFb = 0;
2032}
2033
2034/**
2035 * Create implemented ports bitmap.
2036 *
2037 * @returns 32bit bitmask with a bit set for every implemented port.
2038 * @param cPorts Number of ports.
2039 */
2040static uint32_t ahciGetPortsImplemented(unsigned cPorts)
2041{
2042 uint32_t uPortsImplemented = 0;
2043
2044 for (unsigned i = 0; i < cPorts; i++)
2045 uPortsImplemented |= (1 << i);
2046
2047 return uPortsImplemented;
2048}
2049
2050/**
2051 * Reset the entire HBA.
2052 *
2053 * @param pDevIns The device instance.
2054 * @param pThis The shared AHCI state.
2055 * @param pThisCC The ring-3 AHCI state.
2056 */
2057static void ahciR3HBAReset(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIR3 pThisCC)
2058{
2059 unsigned i;
2060 int rc = VINF_SUCCESS;
2061
2062 LogRel(("AHCI#%u: Reset the HBA\n", pDevIns->iInstance));
2063
2064 /* Stop the CCC timer. */
2065 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
2066 {
2067 rc = PDMDevHlpTimerStop(pDevIns, pThis->hHbaCccTimer);
2068 if (RT_FAILURE(rc))
2069 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
2070 }
2071
2072 /* Reset every port */
2073 uint32_t const cPortsImpl = RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThisCC->aPorts));
2074 for (i = 0; i < cPortsImpl; i++)
2075 {
2076 PAHCIPORT pAhciPort = &pThis->aPorts[i];
2077 PAHCIPORTR3 pAhciPortR3 = &pThisCC->aPorts[i];
2078
2079 pAhciPort->iLUN = i;
2080 pAhciPortR3->iLUN = i;
2081 ahciR3PortSwReset(pAhciPort, pAhciPortR3);
2082 }
2083
2084 /* Init Global registers */
2085 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2)
2086 | AHCI_HBA_CAP_S64A /* 64bit addressing supported */
2087 | AHCI_HBA_CAP_SAM /* AHCI mode only */
2088 | AHCI_HBA_CAP_SNCQ /* Support native command queuing */
2089 | AHCI_HBA_CAP_SSS /* Staggered spin up */
2090 | AHCI_HBA_CAP_CCCS /* Support command completion coalescing */
2091 | AHCI_HBA_CAP_NCS_SET(pThis->cCmdSlotsAvail) /* Number of command slots we support */
2092 | AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
2093 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
2094 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
2095 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
2096 pThis->regHbaCccCtl = 0;
2097 pThis->regHbaCccPorts = 0;
2098 pThis->uCccTimeout = 0;
2099 pThis->uCccPortNr = 0;
2100 pThis->uCccNr = 0;
2101
2102 /* Clear pending interrupts. */
2103 pThis->regHbaIs = 0;
2104 pThis->u32PortsInterrupted = 0;
2105 ahciHbaClearInterrupt(pDevIns);
2106
2107 pThis->f64BitAddr = false;
2108 pThis->u32PortsInterrupted = 0;
2109 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
2110 /* Clear the HBA Reset bit */
2111 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
2112}
2113
2114#endif /* IN_RING3 */
2115
2116/**
2117 * Reads from a AHCI controller register.
2118 *
2119 * @returns Strict VBox status code.
2120 *
2121 * @param pDevIns The device instance.
2122 * @param pThis The shared AHCI state.
2123 * @param uReg The register to write.
2124 * @param pv Where to store the result.
2125 * @param cb Number of bytes read.
2126 */
2127static VBOXSTRICTRC ahciRegisterRead(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t uReg, void *pv, unsigned cb)
2128{
2129 VBOXSTRICTRC rc;
2130 uint32_t iReg;
2131
2132 /*
2133 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
2134 * Otherwise it accesses the registers of a port.
2135 */
2136 if (uReg < AHCI_HBA_GLOBAL_SIZE)
2137 {
2138 iReg = uReg >> 2;
2139 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
2140 if (iReg < RT_ELEMENTS(g_aOpRegs))
2141 {
2142 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2143 rc = pReg->pfnRead(pDevIns, pThis, iReg, (uint32_t *)pv);
2144 }
2145 else
2146 {
2147 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2148 *(uint32_t *)pv = 0;
2149 rc = VINF_SUCCESS;
2150 }
2151 }
2152 else
2153 {
2154 uint32_t iRegOffset;
2155 uint32_t iPort;
2156
2157 /* Calculate accessed port. */
2158 uReg -= AHCI_HBA_GLOBAL_SIZE;
2159 iPort = uReg / AHCI_PORT_REGISTER_SIZE;
2160 iRegOffset = (uReg % AHCI_PORT_REGISTER_SIZE);
2161 iReg = iRegOffset >> 2;
2162
2163 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
2164
2165 if (RT_LIKELY( iPort < RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts))
2166 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2167 {
2168 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2169 rc = pPortReg->pfnRead(pDevIns, pThis, &pThis->aPorts[iPort], iReg, (uint32_t *)pv);
2170 }
2171 else
2172 {
2173 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2174 rc = VINF_IOM_MMIO_UNUSED_00;
2175 }
2176
2177 /*
2178 * Windows Vista tries to read one byte from some registers instead of four.
2179 * Correct the value according to the read size.
2180 */
2181 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2182 {
2183 switch (cb)
2184 {
2185 case 1:
2186 {
2187 uint8_t uNewValue;
2188 uint8_t *p = (uint8_t *)pv;
2189
2190 iRegOffset &= 3;
2191 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2192 uNewValue = p[iRegOffset];
2193 /* Clear old value */
2194 *(uint32_t *)pv = 0;
2195 *(uint8_t *)pv = uNewValue;
2196 break;
2197 }
2198 default:
2199 ASSERT_GUEST_MSG_FAILED(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
2200 __FUNCTION__, cb, iPort, iRegOffset, iReg));
2201 }
2202 }
2203 }
2204
2205 return rc;
2206}
2207
2208/**
2209 * Writes a value to one of the AHCI controller registers.
2210 *
2211 * @returns Strict VBox status code.
2212 *
2213 * @param pDevIns The device instance.
2214 * @param pThis The shared AHCI state.
2215 * @param offReg The offset of the register to write to.
2216 * @param u32Value The value to write.
2217 */
2218static VBOXSTRICTRC ahciRegisterWrite(PPDMDEVINS pDevIns, PAHCI pThis, uint32_t offReg, uint32_t u32Value)
2219{
2220 VBOXSTRICTRC rc;
2221 uint32_t iReg;
2222
2223 /*
2224 * If the access offset is smaller than 100h the guest accesses the global registers.
2225 * Otherwise it accesses the registers of a port.
2226 */
2227 if (offReg < AHCI_HBA_GLOBAL_SIZE)
2228 {
2229 Log3(("Write global HBA register\n"));
2230 iReg = offReg >> 2;
2231 if (iReg < RT_ELEMENTS(g_aOpRegs))
2232 {
2233 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2234 rc = pReg->pfnWrite(pDevIns, pThis, iReg, u32Value);
2235 }
2236 else
2237 {
2238 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2239 rc = VINF_SUCCESS;
2240 }
2241 }
2242 else
2243 {
2244 uint32_t iPort;
2245 Log3(("Write Port register\n"));
2246 /* Calculate accessed port. */
2247 offReg -= AHCI_HBA_GLOBAL_SIZE;
2248 iPort = offReg / AHCI_PORT_REGISTER_SIZE;
2249 iReg = (offReg % AHCI_PORT_REGISTER_SIZE) >> 2;
2250 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2251 if (RT_LIKELY( iPort < RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts))
2252 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2253 {
2254 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2255 rc = pPortReg->pfnWrite(pDevIns, pThis, &pThis->aPorts[iPort], iReg, u32Value);
2256 }
2257 else
2258 {
2259 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2260 rc = VINF_SUCCESS;
2261 }
2262 }
2263
2264 return rc;
2265}
2266
2267
2268/**
2269 * @callback_method_impl{FNIOMMMIONEWWRITE}
2270 */
2271static DECLCALLBACK(VBOXSTRICTRC) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
2272{
2273 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
2274 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d off=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, off));
2275 RT_NOREF(pvUser);
2276
2277 VBOXSTRICTRC rc = ahciRegisterRead(pDevIns, pThis, off, pv, cb);
2278
2279 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d off=%RGp rc=%Rrc\n",
2280 pDevIns->iInstance, pv, cb, pv, cb, off, VBOXSTRICTRC_VAL(rc)));
2281 return rc;
2282}
2283
2284/**
2285 * @callback_method_impl{FNIOMMMIONEWWRITE}
2286 */
2287static DECLCALLBACK(VBOXSTRICTRC) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
2288{
2289 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
2290
2291 Assert(cb == 4 || cb == 8); /* Assert IOM flags & sanity */
2292 Assert(!(off & (cb - 1))); /* Ditto. */
2293
2294 /* Break up 64 bits writes into two dword writes. */
2295 /** @todo Eliminate this code once the IOM/EM starts taking care of these
2296 * situations. */
2297 if (cb == 8)
2298 {
2299 /*
2300 * Only write the first 4 bytes if they weren't already.
2301 * It is possible that the last write to the register caused a world
2302 * switch and we entered this function again.
2303 * Writing the first 4 bytes again could cause indeterminate behavior
2304 * which can cause errors in the guest.
2305 */
2306 VBOXSTRICTRC rc = VINF_SUCCESS;
2307 if (!pThis->f8ByteMMIO4BytesWrittenSuccessfully)
2308 {
2309 rc = ahciMMIOWrite(pDevIns, pvUser, off, pv, 4);
2310 if (rc != VINF_SUCCESS)
2311 return rc;
2312
2313 pThis->f8ByteMMIO4BytesWrittenSuccessfully = true;
2314 }
2315
2316 rc = ahciMMIOWrite(pDevIns, pvUser, off + 4, (uint8_t *)pv + 4, 4);
2317 /*
2318 * Reset flag again so that the first 4 bytes are written again on the next
2319 * 8byte MMIO access.
2320 */
2321 if (rc == VINF_SUCCESS)
2322 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
2323
2324 return rc;
2325 }
2326
2327 /* Do the access. */
2328 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, off));
2329 return ahciRegisterWrite(pDevIns, pThis, off, *(uint32_t const *)pv);
2330}
2331
2332
2333/**
2334 * @callback_method_impl{FNIOMIOPORTNEWOUT,
2335 * Fake IDE port handler provided to make solaris happy.}
2336 */
2337static DECLCALLBACK(VBOXSTRICTRC)
2338ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
2339{
2340 RT_NOREF(pDevIns, pvUser, offPort, u32, cb);
2341 ASSERT_GUEST_MSG_FAILED(("Should not happen\n"));
2342 return VINF_SUCCESS;
2343}
2344
2345/**
2346 * @callback_method_impl{FNIOMIOPORTNEWIN,
2347 * Fake IDE port handler provided to make solaris happy.}
2348 */
2349static DECLCALLBACK(VBOXSTRICTRC)
2350ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
2351{
2352 /** @todo we should set *pu32 to something. */
2353 RT_NOREF(pDevIns, pvUser, offPort, pu32, cb);
2354 ASSERT_GUEST_MSG_FAILED(("Should not happen\n"));
2355 return VINF_SUCCESS;
2356}
2357
2358
2359/**
2360 * @callback_method_impl{FNIOMIOPORTNEWOUT,
2361 * I/O port handler for writes to the index/data register pair.}
2362 */
2363static DECLCALLBACK(VBOXSTRICTRC) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
2364{
2365 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
2366 VBOXSTRICTRC rc = VINF_SUCCESS;
2367 RT_NOREF(pvUser, cb);
2368
2369 if (offPort >= 8)
2370 {
2371 ASSERT_GUEST(cb == 4);
2372
2373 uint32_t const iReg = (offPort - 8) / 4;
2374 if (iReg == 0)
2375 {
2376 /* Write the index register. */
2377 pThis->regIdx = u32;
2378 }
2379 else
2380 {
2381 /** @todo range check? */
2382 ASSERT_GUEST(iReg == 1);
2383 rc = ahciRegisterWrite(pDevIns, pThis, pThis->regIdx, u32);
2384 if (rc == VINF_IOM_R3_MMIO_WRITE)
2385 rc = VINF_IOM_R3_IOPORT_WRITE;
2386 }
2387 }
2388 /* else: ignore */
2389
2390 Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d offPort=%#x rc=%Rrc\n",
2391 pDevIns->iInstance, &u32, cb, &u32, cb, offPort, VBOXSTRICTRC_VAL(rc)));
2392 return rc;
2393}
2394
2395/**
2396 * @callback_method_impl{FNIOMIOPORTNEWOUT,
2397 * I/O port handler for reads from the index/data register pair.}
2398 */
2399static DECLCALLBACK(VBOXSTRICTRC) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
2400{
2401 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
2402 VBOXSTRICTRC rc = VINF_SUCCESS;
2403 RT_NOREF(pvUser);
2404
2405 if (offPort >= 8)
2406 {
2407 ASSERT_GUEST(cb == 4);
2408
2409 uint32_t const iReg = (offPort - 8) / 4;
2410 if (iReg == 0)
2411 {
2412 /* Read the index register. */
2413 *pu32 = pThis->regIdx;
2414 }
2415 else
2416 {
2417 /** @todo range check? */
2418 ASSERT_GUEST(iReg == 1);
2419 rc = ahciRegisterRead(pDevIns, pThis, pThis->regIdx, pu32, cb);
2420 if (rc == VINF_IOM_R3_MMIO_READ)
2421 rc = VINF_IOM_R3_IOPORT_READ;
2422 else if (rc == VINF_IOM_MMIO_UNUSED_00)
2423 rc = VERR_IOM_IOPORT_UNUSED;
2424 }
2425 }
2426 else
2427 *pu32 = UINT32_MAX;
2428
2429 Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d offPort=%#x rc=%Rrc\n",
2430 pDevIns->iInstance, pu32, cb, pu32, cb, offPort, VBOXSTRICTRC_VAL(rc)));
2431 return rc;
2432}
2433
2434#ifdef IN_RING3
2435
2436/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2437
2438/**
2439 * Gets the pointer to the status LED of a unit.
2440 *
2441 * @returns VBox status code.
2442 * @param pInterface Pointer to the interface structure containing the called function pointer.
2443 * @param iLUN The unit which status LED we desire.
2444 * @param ppLed Where to store the LED pointer.
2445 */
2446static DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2447{
2448 PAHCICC pThisCC = RT_FROM_MEMBER(pInterface, AHCICC, ILeds);
2449 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2450 {
2451 PAHCI pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PAHCI);
2452 *ppLed = &pThis->aPorts[iLUN].Led;
2453 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2454 return VINF_SUCCESS;
2455 }
2456 return VERR_PDM_LUN_NOT_FOUND;
2457}
2458
2459/**
2460 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2461 */
2462static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2463{
2464 PAHCICC pThisCC = RT_FROM_MEMBER(pInterface, AHCICC, IBase);
2465 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
2466 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds);
2467 return NULL;
2468}
2469
2470/**
2471 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2472 */
2473static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2474{
2475 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IBase);
2476 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPortR3->IBase);
2477 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pAhciPortR3->IPort);
2478 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pAhciPortR3->IMediaExPort);
2479 return NULL;
2480}
2481
2482/**
2483 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2484 */
2485static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2486 uint32_t *piInstance, uint32_t *piLUN)
2487{
2488 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IPort);
2489 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
2490
2491 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2492 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2493 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2494
2495 *ppcszController = pDevIns->pReg->szName;
2496 *piInstance = pDevIns->iInstance;
2497 *piLUN = pAhciPortR3->iLUN;
2498
2499 return VINF_SUCCESS;
2500}
2501
2502/**
2503 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryScsiInqStrings}
2504 */
2505static DECLCALLBACK(int) ahciR3PortQueryScsiInqStrings(PPDMIMEDIAPORT pInterface, const char **ppszVendorId,
2506 const char **ppszProductId, const char **ppszRevision)
2507{
2508 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IPort);
2509 PAHCI pThis = PDMDEVINS_2_DATA(pAhciPortR3->pDevIns, PAHCI);
2510 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
2511
2512 if (ppszVendorId)
2513 *ppszVendorId = &pAhciPort->szInquiryVendorId[0];
2514 if (ppszProductId)
2515 *ppszProductId = &pAhciPort->szInquiryProductId[0];
2516 if (ppszRevision)
2517 *ppszRevision = &pAhciPort->szInquiryRevision[0];
2518 return VINF_SUCCESS;
2519}
2520
2521#ifdef LOG_ENABLED
2522
2523/**
2524 * Dump info about the FIS
2525 *
2526 * @returns nothing
2527 * @param pAhciPort The port the command FIS was read from (shared bits).
2528 * @param cmdFis The FIS to print info from.
2529 */
2530static void ahciDumpFisInfo(PAHCIPORT pAhciPort, uint8_t *cmdFis)
2531{
2532 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2533 /* Print FIS type. */
2534 switch (cmdFis[AHCI_CMDFIS_TYPE])
2535 {
2536 case AHCI_CMDFIS_TYPE_H2D:
2537 {
2538 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2539 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2540 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2541 ahciLog(("%s: Command register update\n", __FUNCTION__));
2542 else
2543 ahciLog(("%s: Control register update\n", __FUNCTION__));
2544 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2545 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2546 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2547 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2548 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2549 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2550
2551 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2552 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2553 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2554 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2555
2556 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2557 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2558 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2559 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2560 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2561 break;
2562 }
2563 case AHCI_CMDFIS_TYPE_D2H:
2564 {
2565 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2566 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2567 break;
2568 }
2569 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2570 {
2571 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2572 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2573 break;
2574 }
2575 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2576 {
2577 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2578 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2579 break;
2580 }
2581 case AHCI_CMDFIS_TYPE_DMASETUP:
2582 {
2583 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2584 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2585 break;
2586 }
2587 case AHCI_CMDFIS_TYPE_PIOSETUP:
2588 {
2589 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2590 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2591 break;
2592 }
2593 case AHCI_CMDFIS_TYPE_DATA:
2594 {
2595 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2596 break;
2597 }
2598 default:
2599 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2600 break;
2601 }
2602 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2603}
2604
2605/**
2606 * Dump info about the command header
2607 *
2608 * @returns nothing
2609 * @param pAhciPort Pointer to the port the command header was read from
2610 * (shared bits).
2611 * @param pCmdHdr The command header to print info from.
2612 */
2613static void ahciDumpCmdHdrInfo(PAHCIPORT pAhciPort, CmdHdr *pCmdHdr)
2614{
2615 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2616 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2617 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2618 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2619 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2620 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2621 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2622 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2623 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2624 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2625 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2626 ahciLog(("%s: Device write\n", __FUNCTION__));
2627 else
2628 ahciLog(("%s: Device read\n", __FUNCTION__));
2629 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2630 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2631 else
2632 ahciLog(("%s: ATA command\n", __FUNCTION__));
2633
2634 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2635 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2636}
2637
2638#endif /* LOG_ENABLED */
2639
2640/**
2641 * Post the first D2H FIS from the device into guest memory.
2642 *
2643 * @returns nothing
2644 * @param pDevIns The device instance.
2645 * @param pAhciPort Pointer to the port which "receives" the FIS (shared bits).
2646 */
2647static void ahciPostFirstD2HFisIntoMemory(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort)
2648{
2649 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2650
2651 pAhciPort->fFirstD2HFisSent = true;
2652
2653 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2654 memset(&d2hFis[0], 0, sizeof(d2hFis));
2655 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2656 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2657
2658 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2659
2660 /* Set the signature based on the device type. */
2661 if (pAhciPort->fATAPI)
2662 {
2663 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2664 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2665 }
2666 else
2667 {
2668 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2669 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2670 }
2671
2672 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2673 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2674 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2675
2676 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2677 if (!pAhciPort->fATAPI)
2678 pAhciPort->regTFD |= ATA_STAT_READY;
2679
2680 ahciPostFisIntoMemory(pDevIns, pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2681}
2682
2683/**
2684 * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
2685 *
2686 * @returns VBox status code
2687 * @param pDevIns The device instance.
2688 * @param pAhciPort The port which "receives" the FIS(shared bits).
2689 * @param uFisType The type of the FIS.
2690 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2691 */
2692static int ahciPostFisIntoMemory(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2693{
2694 int rc = VINF_SUCCESS;
2695 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2696 unsigned cbFis = 0;
2697
2698 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2699
2700 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2701 {
2702 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2703
2704 /* Determine the offset and size of the FIS based on uFisType. */
2705 switch (uFisType)
2706 {
2707 case AHCI_CMDFIS_TYPE_D2H:
2708 {
2709 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2710 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2711 break;
2712 }
2713 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2714 {
2715 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2716 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2717 break;
2718 }
2719 case AHCI_CMDFIS_TYPE_DMASETUP:
2720 {
2721 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2722 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2723 break;
2724 }
2725 case AHCI_CMDFIS_TYPE_PIOSETUP:
2726 {
2727 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2728 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2729 break;
2730 }
2731 default:
2732 /*
2733 * We should post the unknown FIS into memory too but this never happens because
2734 * we know which FIS types we generate. ;)
2735 */
2736 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2737 }
2738
2739 /* Post the FIS into memory. */
2740 ahciLog(("%s: PDMDevHlpPCIPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2741 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysAddrRecFis, pCmdFis, cbFis);
2742 }
2743
2744 return rc;
2745}
2746
2747DECLINLINE(void) ahciReqSetStatus(PAHCIREQ pAhciReq, uint8_t u8Error, uint8_t u8Status)
2748{
2749 pAhciReq->cmdFis[AHCI_CMDFIS_ERR] = u8Error;
2750 pAhciReq->cmdFis[AHCI_CMDFIS_STS] = u8Status;
2751}
2752
2753static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2754{
2755 for (uint32_t i = 0; i < cbSize; i++)
2756 {
2757 if (*pbSrc)
2758 pbDst[i ^ 1] = *pbSrc++;
2759 else
2760 pbDst[i ^ 1] = ' ';
2761 }
2762}
2763
2764static uint32_t ataChecksum(void* ptr, size_t count)
2765{
2766 uint8_t u8Sum = 0xa5, *p = (uint8_t*)ptr;
2767 size_t i;
2768
2769 for (i = 0; i < count; i++)
2770 {
2771 u8Sum += *p++;
2772 }
2773
2774 return (uint8_t)-(int32_t)u8Sum;
2775}
2776
2777static int ahciIdentifySS(PAHCI pThis, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3, void *pvBuf)
2778{
2779 uint16_t *p = (uint16_t *)pvBuf;
2780 memset(p, 0, 512);
2781 p[0] = RT_H2LE_U16(0x0040);
2782 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2783 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2784 /* Block size; obsolete, but required for the BIOS. */
2785 p[5] = RT_H2LE_U16(512);
2786 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2787 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2788 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2789 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2790 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
2791 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2792 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2793#if ATA_MAX_MULT_SECTORS > 1
2794 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
2795#endif
2796 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
2797 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2798 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2799 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2800 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2801 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
2802 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2803 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2804 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2805 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
2806 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
2807 if (pAhciPort->cMultSectors)
2808 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
2809 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
2810 {
2811 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2812 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2813 }
2814 else
2815 {
2816 /* Report maximum number of sectors possible with LBA28 */
2817 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
2818 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
2819 }
2820 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2821 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2822 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2823 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2824 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2825 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2826 if ( pAhciPort->fTrimEnabled
2827 || pAhciPort->cbSector != 512
2828 || pAhciPortR3->pDrvMedia->pfnIsNonRotational(pAhciPortR3->pDrvMedia))
2829 {
2830 p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
2831 p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
2832 }
2833 else
2834 {
2835 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2836 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2837 }
2838 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
2839 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2840 p[84] = RT_H2LE_U16(1 << 14);
2841 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
2842 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2843 p[87] = RT_H2LE_U16(1 << 14);
2844 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2845 p[93] = RT_H2LE_U16(0x00);
2846 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2847 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2848 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
2849 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
2850
2851 /* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
2852 if (pAhciPort->cLogSectorsPerPhysicalExp)
2853 p[106] = RT_H2LE_U16(RT_BIT(14) | RT_BIT(13) | pAhciPort->cLogSectorsPerPhysicalExp);
2854
2855 if (pAhciPort->cbSector != 512)
2856 {
2857 uint32_t cSectorSizeInWords = pAhciPort->cbSector / sizeof(uint16_t);
2858 /* Enable reporting of logical sector size. */
2859 p[106] |= RT_H2LE_U16(RT_BIT(12) | RT_BIT(14));
2860 p[117] = RT_H2LE_U16(cSectorSizeInWords);
2861 p[118] = RT_H2LE_U16(cSectorSizeInWords >> 16);
2862 }
2863
2864 if (pAhciPortR3->pDrvMedia->pfnIsNonRotational(pAhciPortR3->pDrvMedia))
2865 p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
2866
2867 if (pAhciPort->fTrimEnabled) /** @todo Set bit 14 in word 69 too? (Deterministic read after TRIM). */
2868 p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
2869
2870 /* The following are SATA specific */
2871 p[75] = RT_H2LE_U16(pThis->cCmdSlotsAvail - 1); /* Number of commands we support, 0's based */
2872 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2873
2874 uint32_t uCsum = ataChecksum(p, 510);
2875 p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
2876
2877 return VINF_SUCCESS;
2878}
2879
2880static int ahciR3AtapiIdentify(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, PAHCIPORT pAhciPort, size_t cbData, size_t *pcbData)
2881{
2882 uint16_t p[256];
2883
2884 memset(p, 0, 512);
2885 /* Removable CDROM, 50us response, 12 byte packets */
2886 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
2887 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2888 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2889 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2890 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2891 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2892 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2893 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2894 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2895 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2896 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
2897 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2898 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2899 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2900 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2901 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2902 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2903 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
2904 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
2905 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2906 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2907 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
2908 p[83] = RT_H2LE_U16(1 << 14);
2909 p[84] = RT_H2LE_U16(1 << 14);
2910 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
2911 p[86] = RT_H2LE_U16(0);
2912 p[87] = RT_H2LE_U16(1 << 14);
2913 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2914 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
2915
2916 /* The following are SATA specific */
2917 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2918 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2919
2920 /* Copy the buffer in to the scatter gather list. */
2921 *pcbData = ahciR3CopyBufferToPrdtl(pDevIns, pAhciReq, (void *)&p[0], RT_MIN(cbData, sizeof(p)), 0 /* cbSkip */);
2922 return VINF_SUCCESS;
2923}
2924
2925/**
2926 * Reset all values after a reset of the attached storage device.
2927 *
2928 * @returns nothing
2929 * @param pDevIns The device instance.
2930 * @param pThis The shared AHCI state.
2931 * @param pAhciPort The port the device is attached to, shared bits(shared
2932 * bits).
2933 * @param pAhciReq The state to get the tag number from.
2934 */
2935static void ahciFinishStorageDeviceReset(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIREQ pAhciReq)
2936{
2937 int rc;
2938
2939 /* Send a status good D2H FIS. */
2940 pAhciPort->fResetDevice = false;
2941 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2942 ahciPostFirstD2HFisIntoMemory(pDevIns, pAhciPort);
2943
2944 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
2945 if (pAhciPort->fATAPI)
2946 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
2947 else
2948 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
2949 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
2950
2951 rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
2952 AssertRC(rc);
2953}
2954
2955/**
2956 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
2957 *
2958 * @returns nothing.
2959 * @param pDevIns The device instance.
2960 * @param pThis The shared AHCI state.
2961 * @param pAhciPort The device to reset(shared bits).
2962 * @param pAhciReq The task state.
2963 */
2964static void ahciDeviceReset(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIREQ pAhciReq)
2965{
2966 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
2967
2968 /*
2969 * Because this ATAPI only and ATAPI can't have
2970 * more than one command active at a time the task counter should be 0
2971 * and it is possible to finish the reset now.
2972 */
2973 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
2974 ahciFinishStorageDeviceReset(pDevIns, pThis, pAhciPort, pAhciReq);
2975}
2976
2977/**
2978 * Create a PIO setup FIS and post it into the memory area of the guest.
2979 *
2980 * @returns nothing.
2981 * @param pDevIns The device instance.
2982 * @param pThis The shared AHCI state.
2983 * @param pAhciPort The port of the SATA controller (shared bits).
2984 * @param cbTransfer Transfer size of the request.
2985 * @param pCmdFis Pointer to the command FIS from the guest.
2986 * @param fRead Flag whether this is a read request.
2987 * @param fInterrupt If an interrupt should be send to the guest.
2988 */
2989static void ahciSendPioSetupFis(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort,
2990 size_t cbTransfer, uint8_t *pCmdFis, bool fRead, bool fInterrupt)
2991{
2992 uint8_t abPioSetupFis[20];
2993 bool fAssertIntr = false;
2994
2995 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
2996
2997 AssertMsg( cbTransfer > 0
2998 && cbTransfer <= 65534,
2999 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
3000
3001 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3002 {
3003 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
3004 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
3005 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3006 if (fRead)
3007 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
3008 abPioSetupFis[AHCI_CMDFIS_STS] = pCmdFis[AHCI_CMDFIS_STS];
3009 abPioSetupFis[AHCI_CMDFIS_ERR] = pCmdFis[AHCI_CMDFIS_ERR];
3010 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3011 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3012 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3013 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3014 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3015 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3016 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3017 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3018 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3019
3020 /* Set transfer count. */
3021 abPioSetupFis[16] = (cbTransfer >> 8) & 0xff;
3022 abPioSetupFis[17] = cbTransfer & 0xff;
3023
3024 /* Update registers. */
3025 pAhciPort->regTFD = (pCmdFis[AHCI_CMDFIS_ERR] << 8) | pCmdFis[AHCI_CMDFIS_STS];
3026
3027 ahciPostFisIntoMemory(pDevIns, pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
3028
3029 if (fInterrupt)
3030 {
3031 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
3032 /* Check if we should assert an interrupt */
3033 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
3034 fAssertIntr = true;
3035 }
3036
3037 if (fAssertIntr)
3038 {
3039 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
3040 AssertRC(rc);
3041 }
3042 }
3043}
3044
3045/**
3046 * Build a D2H FIS and post into the memory area of the guest.
3047 *
3048 * @returns Nothing
3049 * @param pDevIns The device instance.
3050 * @param pThis The shared AHCI state.
3051 * @param pAhciPort The port of the SATA controller (shared bits).
3052 * @param uTag The tag of the request.
3053 * @param pCmdFis Pointer to the command FIS from the guest.
3054 * @param fInterrupt If an interrupt should be send to the guest.
3055 */
3056static void ahciSendD2HFis(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, uint32_t uTag, uint8_t *pCmdFis, bool fInterrupt)
3057{
3058 uint8_t d2hFis[20];
3059 bool fAssertIntr = false;
3060
3061 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
3062
3063 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3064 {
3065 memset(&d2hFis[0], 0, sizeof(d2hFis));
3066 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
3067 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3068 d2hFis[AHCI_CMDFIS_STS] = pCmdFis[AHCI_CMDFIS_STS];
3069 d2hFis[AHCI_CMDFIS_ERR] = pCmdFis[AHCI_CMDFIS_ERR];
3070 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3071 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3072 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3073 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3074 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3075 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3076 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3077 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3078 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3079
3080 /* Update registers. */
3081 pAhciPort->regTFD = (pCmdFis[AHCI_CMDFIS_ERR] << 8) | pCmdFis[AHCI_CMDFIS_STS];
3082
3083 ahciPostFisIntoMemory(pDevIns, pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
3084
3085 if (pCmdFis[AHCI_CMDFIS_STS] & ATA_STAT_ERR)
3086 {
3087 /* Error bit is set. */
3088 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3089 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3090 fAssertIntr = true;
3091 /*
3092 * Don't mark the command slot as completed because the guest
3093 * needs it to identify the failed command.
3094 */
3095 }
3096 else if (fInterrupt)
3097 {
3098 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
3099 /* Check if we should assert an interrupt */
3100 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
3101 fAssertIntr = true;
3102
3103 /* Mark command as completed. */
3104 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(uTag));
3105 }
3106
3107 if (fAssertIntr)
3108 {
3109 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
3110 AssertRC(rc);
3111 }
3112 }
3113}
3114
3115/**
3116 * Build a SDB Fis and post it into the memory area of the guest.
3117 *
3118 * @returns Nothing
3119 * @param pDevIns The device instance.
3120 * @param pThis The shared AHCI state.
3121 * @param pAhciPort The port for which the SDB Fis is send, shared bits.
3122 * @param pAhciPortR3 The port for which the SDB Fis is send, ring-3 bits.
3123 * @param uFinishedTasks Bitmask of finished tasks.
3124 * @param fInterrupt If an interrupt should be asserted.
3125 */
3126static void ahciSendSDBFis(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3,
3127 uint32_t uFinishedTasks, bool fInterrupt)
3128{
3129 uint32_t sdbFis[2];
3130 bool fAssertIntr = false;
3131 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPortR3->pTaskErr, PAHCIREQ);
3132
3133 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3134
3135 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3136 {
3137 memset(&sdbFis[0], 0, sizeof(sdbFis));
3138 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3139 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3140 if (RT_UNLIKELY(pTaskErr))
3141 {
3142 sdbFis[0] = pTaskErr->cmdFis[AHCI_CMDFIS_ERR];
3143 sdbFis[0] |= (pTaskErr->cmdFis[AHCI_CMDFIS_STS] & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3144
3145 /* Update registers. */
3146 pAhciPort->regTFD = (pTaskErr->cmdFis[AHCI_CMDFIS_ERR] << 8) | pTaskErr->cmdFis[AHCI_CMDFIS_STS];
3147 }
3148 else
3149 {
3150 sdbFis[0] = 0;
3151 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
3152 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
3153 }
3154
3155 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
3156
3157 ahciPostFisIntoMemory(pDevIns, pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3158
3159 if (RT_UNLIKELY(pTaskErr))
3160 {
3161 /* Error bit is set. */
3162 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3163 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3164 fAssertIntr = true;
3165 }
3166
3167 if (fInterrupt)
3168 {
3169 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
3170 /* Check if we should assert an interrupt */
3171 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
3172 fAssertIntr = true;
3173 }
3174
3175 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3176
3177 if (fAssertIntr)
3178 {
3179 int rc = ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
3180 AssertRC(rc);
3181 }
3182 }
3183}
3184
3185static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
3186{
3187 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
3188 if (fLBA48)
3189 {
3190 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
3191 return 65536;
3192 else
3193 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
3194 }
3195 else
3196 {
3197 if (!pCmdFis[AHCI_CMDFIS_SECTC])
3198 return 256;
3199 else
3200 return pCmdFis[AHCI_CMDFIS_SECTC];
3201 }
3202}
3203
3204static uint64_t ahciGetSector(PAHCIPORT pAhciPort, uint8_t *pCmdFis, bool fLBA48)
3205{
3206 uint64_t iLBA;
3207 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
3208 {
3209 /* any LBA variant */
3210 if (fLBA48)
3211 {
3212 /* LBA48 */
3213 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3214 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3215 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3216 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3217 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3218 pCmdFis[AHCI_CMDFIS_SECTN];
3219 }
3220 else
3221 {
3222 /* LBA */
3223 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3224 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
3225 }
3226 }
3227 else
3228 {
3229 /* CHS */
3230 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
3231 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
3232 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
3233 }
3234 return iLBA;
3235}
3236
3237static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
3238{
3239 uint64_t uLBA;
3240
3241 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3242 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3243 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3244 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3245 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3246 pCmdFis[AHCI_CMDFIS_SECTN];
3247
3248 return uLBA;
3249}
3250
3251DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
3252{
3253 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
3254 return 65536;
3255 else
3256 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
3257}
3258
3259/**
3260 * Copy from guest to host memory worker.
3261 *
3262 * @copydoc FNAHCIR3MEMCOPYCALLBACK
3263 */
3264static DECLCALLBACK(void) ahciR3CopyBufferFromGuestWorker(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
3265 size_t cbCopy, size_t *pcbSkip)
3266{
3267 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
3268 cbCopy -= cbSkipped;
3269 GCPhys += cbSkipped;
3270 *pcbSkip -= cbSkipped;
3271
3272 while (cbCopy)
3273 {
3274 size_t cbSeg = cbCopy;
3275 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
3276
3277 AssertPtr(pvSeg);
3278 Log5Func(("%RGp LB %#zx\n", GCPhys, cbSeg));
3279 PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvSeg, cbSeg);
3280 Log7Func(("%.*Rhxd\n", cbSeg, pvSeg));
3281 GCPhys += cbSeg;
3282 cbCopy -= cbSeg;
3283 }
3284}
3285
3286/**
3287 * Copy from host to guest memory worker.
3288 *
3289 * @copydoc FNAHCIR3MEMCOPYCALLBACK
3290 */
3291static DECLCALLBACK(void) ahciR3CopyBufferToGuestWorker(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
3292 size_t cbCopy, size_t *pcbSkip)
3293{
3294 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
3295 cbCopy -= cbSkipped;
3296 GCPhys += cbSkipped;
3297 *pcbSkip -= cbSkipped;
3298
3299 while (cbCopy)
3300 {
3301 size_t cbSeg = cbCopy;
3302 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
3303
3304 AssertPtr(pvSeg);
3305 Log5Func(("%RGp LB %#zx\n", GCPhys, cbSeg));
3306 Log6Func(("%.*Rhxd\n", cbSeg, pvSeg));
3307 PDMDevHlpPCIPhysWriteUser(pDevIns, GCPhys, pvSeg, cbSeg);
3308 GCPhys += cbSeg;
3309 cbCopy -= cbSeg;
3310 }
3311}
3312
3313/**
3314 * Walks the PRDTL list copying data between the guest and host memory buffers.
3315 *
3316 * @returns Amount of bytes copied.
3317 * @param pDevIns The device instance.
3318 * @param pAhciReq AHCI request structure.
3319 * @param pfnCopyWorker The copy method to apply for each guest buffer.
3320 * @param pSgBuf The host S/G buffer.
3321 * @param cbSkip How many bytes to skip in advance before starting to copy.
3322 * @param cbCopy How many bytes to copy.
3323 */
3324static size_t ahciR3PrdtlWalk(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
3325 PFNAHCIR3MEMCOPYCALLBACK pfnCopyWorker,
3326 PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
3327{
3328 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
3329 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
3330 size_t cbCopied = 0;
3331
3332 /*
3333 * Add the amount to skip to the host buffer size to avoid a
3334 * few conditionals later on.
3335 */
3336 cbCopy += cbSkip;
3337
3338 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
3339
3340 do
3341 {
3342 SGLEntry aPrdtlEntries[32];
3343 uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
3344 ? cPrdtlEntries
3345 : RT_ELEMENTS(aPrdtlEntries);
3346
3347 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0],
3348 cPrdtlEntriesRead * sizeof(SGLEntry));
3349
3350 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbCopy; i++)
3351 {
3352 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
3353 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
3354
3355 cbThisCopy = (uint32_t)RT_MIN(cbThisCopy, cbCopy);
3356
3357 /* Copy into SG entry. */
3358 pfnCopyWorker(pDevIns, GCPhysAddrDataBase, pSgBuf, cbThisCopy, &cbSkip);
3359
3360 cbCopy -= cbThisCopy;
3361 cbCopied += cbThisCopy;
3362 }
3363
3364 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
3365 cPrdtlEntries -= cPrdtlEntriesRead;
3366 } while (cPrdtlEntries && cbCopy);
3367
3368 if (cbCopied < cbCopy)
3369 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
3370
3371 return cbCopied;
3372}
3373
3374/**
3375 * Copies a data buffer into the S/G buffer set up by the guest.
3376 *
3377 * @returns Amount of bytes copied to the PRDTL.
3378 * @param pDevIns The device instance.
3379 * @param pAhciReq AHCI request structure.
3380 * @param pSgBuf The S/G buffer to copy from.
3381 * @param cbSkip How many bytes to skip in advance before starting to copy.
3382 * @param cbCopy How many bytes to copy.
3383 */
3384static size_t ahciR3CopySgBufToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
3385{
3386 return ahciR3PrdtlWalk(pDevIns, pAhciReq, ahciR3CopyBufferToGuestWorker, pSgBuf, cbSkip, cbCopy);
3387}
3388
3389/**
3390 * Copies the S/G buffer into a data buffer.
3391 *
3392 * @returns Amount of bytes copied from the PRDTL.
3393 * @param pDevIns The device instance.
3394 * @param pAhciReq AHCI request structure.
3395 * @param pSgBuf The S/G buffer to copy into.
3396 * @param cbSkip How many bytes to skip in advance before starting to copy.
3397 * @param cbCopy How many bytes to copy.
3398 */
3399static size_t ahciR3CopySgBufFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
3400{
3401 return ahciR3PrdtlWalk(pDevIns, pAhciReq, ahciR3CopyBufferFromGuestWorker, pSgBuf, cbSkip, cbCopy);
3402}
3403
3404/**
3405 * Copy a simple memory buffer to the guest memory buffer.
3406 *
3407 * @returns Amount of bytes copied from the PRDTL.
3408 * @param pDevIns The device instance.
3409 * @param pAhciReq AHCI request structure.
3410 * @param pvSrc The buffer to copy from.
3411 * @param cbSrc How many bytes to copy.
3412 * @param cbSkip How many bytes to skip initially.
3413 */
3414static size_t ahciR3CopyBufferToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, const void *pvSrc, size_t cbSrc, size_t cbSkip)
3415{
3416 RTSGSEG Seg;
3417 RTSGBUF SgBuf;
3418 Seg.pvSeg = (void *)pvSrc;
3419 Seg.cbSeg = cbSrc;
3420 RTSgBufInit(&SgBuf, &Seg, 1);
3421 return ahciR3CopySgBufToPrdtl(pDevIns, pAhciReq, &SgBuf, cbSkip, cbSrc);
3422}
3423
3424/**
3425 * Calculates the size of the guest buffer described by the PRDT.
3426 *
3427 * @returns VBox status code.
3428 * @param pDevIns The device instance.
3429 * @param pAhciReq AHCI request structure.
3430 * @param pcbPrdt Where to store the size of the guest buffer.
3431 */
3432static int ahciR3PrdtQuerySize(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, size_t *pcbPrdt)
3433{
3434 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
3435 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
3436 size_t cbPrdt = 0;
3437
3438 do
3439 {
3440 SGLEntry aPrdtlEntries[32];
3441 uint32_t const cPrdtlEntriesRead = RT_MIN(cPrdtlEntries, RT_ELEMENTS(aPrdtlEntries));
3442
3443 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
3444
3445 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
3446 cbPrdt += (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
3447
3448 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
3449 cPrdtlEntries -= cPrdtlEntriesRead;
3450 } while (cPrdtlEntries);
3451
3452 *pcbPrdt = cbPrdt;
3453 return VINF_SUCCESS;
3454}
3455
3456/**
3457 * Cancels all active tasks on the port.
3458 *
3459 * @returns Whether all active tasks were canceled.
3460 * @param pAhciPortR3 The AHCI port, ring-3 bits.
3461 */
3462static bool ahciR3CancelActiveTasks(PAHCIPORTR3 pAhciPortR3)
3463{
3464 if (pAhciPortR3->pDrvMediaEx)
3465 {
3466 int rc = pAhciPortR3->pDrvMediaEx->pfnIoReqCancelAll(pAhciPortR3->pDrvMediaEx);
3467 AssertRC(rc);
3468 }
3469 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
3470}
3471
3472/**
3473 * Creates the array of ranges to trim.
3474 *
3475 * @returns VBox status code.
3476 * @param pDevIns The device instance.
3477 * @param pAhciPort AHCI port state, shared bits.
3478 * @param pAhciReq The request handling the TRIM request.
3479 * @param idxRangeStart Index of the first range to start copying.
3480 * @param paRanges Where to store the ranges.
3481 * @param cRanges Number of ranges fitting into the array.
3482 * @param pcRanges Where to store the amount of ranges actually copied on success.
3483 */
3484static int ahciTrimRangesCreate(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort, PAHCIREQ pAhciReq, uint32_t idxRangeStart,
3485 PRTRANGE paRanges, uint32_t cRanges, uint32_t *pcRanges)
3486{
3487 SGLEntry aPrdtlEntries[32];
3488 uint64_t aRanges[64];
3489 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
3490 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
3491 int rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
3492 uint32_t idxRange = 0;
3493
3494 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
3495
3496 AssertMsgReturn(pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
3497
3498 if (!cPrdtlEntries)
3499 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
3500
3501 /* Convert the ranges from ATA to our format. */
3502 while ( cPrdtlEntries
3503 && idxRange < cRanges)
3504 {
3505 uint32_t cPrdtlEntriesRead = RT_MIN(cPrdtlEntries, RT_ELEMENTS(aPrdtlEntries));
3506
3507 rc = VINF_SUCCESS;
3508 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
3509
3510 for (uint32_t i = 0; i < cPrdtlEntriesRead && idxRange < cRanges; i++)
3511 {
3512 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
3513 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
3514
3515 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
3516
3517 /* Copy into buffer. */
3518 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
3519
3520 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges) && idxRange < cRanges; idxRangeSrc++)
3521 {
3522 /* Skip range if told to do so. */
3523 if (!idxRangeStart)
3524 {
3525 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
3526 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
3527 {
3528 paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
3529 paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
3530 idxRange++;
3531 }
3532 else
3533 break;
3534 }
3535 else
3536 idxRangeStart--;
3537 }
3538 }
3539
3540 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
3541 cPrdtlEntries -= cPrdtlEntriesRead;
3542 }
3543
3544 *pcRanges = idxRange;
3545
3546 LogFlowFunc(("returns rc=%Rrc\n", rc));
3547 return rc;
3548}
3549
3550/**
3551 * Allocates a new AHCI request.
3552 *
3553 * @returns A new AHCI request structure or NULL if out of memory.
3554 * @param pAhciPortR3 The AHCI port, ring-3 bits.
3555 * @param uTag The tag to assign.
3556 */
3557static PAHCIREQ ahciR3ReqAlloc(PAHCIPORTR3 pAhciPortR3, uint32_t uTag)
3558{
3559 PAHCIREQ pAhciReq = NULL;
3560 PDMMEDIAEXIOREQ hIoReq = NULL;
3561
3562 int rc = pAhciPortR3->pDrvMediaEx->pfnIoReqAlloc(pAhciPortR3->pDrvMediaEx, &hIoReq, (void **)&pAhciReq,
3563 uTag, PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
3564 if (RT_SUCCESS(rc))
3565 {
3566 pAhciReq->hIoReq = hIoReq;
3567 pAhciReq->fMapped = false;
3568 }
3569 else
3570 pAhciReq = NULL;
3571 return pAhciReq;
3572}
3573
3574/**
3575 * Frees a given AHCI request structure.
3576 *
3577 * @returns nothing.
3578 * @param pAhciPortR3 The AHCI port, ring-3 bits.
3579 * @param pAhciReq The request to free.
3580 */
3581static void ahciR3ReqFree(PAHCIPORTR3 pAhciPortR3, PAHCIREQ pAhciReq)
3582{
3583 if ( pAhciReq
3584 && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK))
3585 {
3586 int rc = pAhciPortR3->pDrvMediaEx->pfnIoReqFree(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq);
3587 AssertRC(rc);
3588 }
3589}
3590
3591/**
3592 * Complete a data transfer task by freeing all occupied resources
3593 * and notifying the guest.
3594 *
3595 * @returns Flag whether the given request was canceled inbetween;
3596 *
3597 * @param pDevIns The device instance.
3598 * @param pThis The shared AHCI state.
3599 * @param pThisCC The ring-3 AHCI state.
3600 * @param pAhciPort Pointer to the port where to request completed, shared bits.
3601 * @param pAhciPortR3 Pointer to the port where to request completed, ring-3 bits.
3602 * @param pAhciReq Pointer to the task which finished.
3603 * @param rcReq IPRT status code of the completed request.
3604 */
3605static bool ahciR3TransferComplete(PPDMDEVINS pDevIns, PAHCI pThis, PAHCICC pThisCC,
3606 PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3, PAHCIREQ pAhciReq, int rcReq)
3607{
3608 bool fCanceled = false;
3609
3610 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d\n",
3611 pAhciPort, pAhciReq, rcReq));
3612
3613 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, pAhciReq->uOffset, pAhciReq->cbTransfer);
3614
3615 if (pAhciReq->fMapped)
3616 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pAhciReq->PgLck);
3617
3618 if (rcReq != VERR_PDM_MEDIAEX_IOREQ_CANCELED)
3619 {
3620 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ)
3621 pAhciPort->Led.Actual.s.fReading = 0;
3622 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
3623 pAhciPort->Led.Actual.s.fWriting = 0;
3624 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
3625 pAhciPort->Led.Actual.s.fWriting = 0;
3626 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_SCSI)
3627 {
3628 pAhciPort->Led.Actual.s.fWriting = 0;
3629 pAhciPort->Led.Actual.s.fReading = 0;
3630 }
3631
3632 if (RT_FAILURE(rcReq))
3633 {
3634 /* Log the error. */
3635 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
3636 {
3637 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
3638 LogRel(("AHCI#%uP%u: Flush returned rc=%Rrc\n",
3639 pDevIns->iInstance, pAhciPort->iLUN, rcReq));
3640 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
3641 LogRel(("AHCI#%uP%u: Trim returned rc=%Rrc\n",
3642 pDevIns->iInstance, pAhciPort->iLUN, rcReq));
3643 else
3644 LogRel(("AHCI#%uP%u: %s at offset %llu (%zu bytes left) returned rc=%Rrc\n",
3645 pDevIns->iInstance, pAhciPort->iLUN,
3646 pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ
3647 ? "Read"
3648 : "Write",
3649 pAhciReq->uOffset,
3650 pAhciReq->cbTransfer, rcReq));
3651 }
3652
3653 ahciReqSetStatus(pAhciReq, ID_ERR, ATA_STAT_READY | ATA_STAT_ERR);
3654 /*
3655 * We have to duplicate the request here as the underlying I/O
3656 * request will be freed later.
3657 */
3658 PAHCIREQ pReqDup = (PAHCIREQ)RTMemDup(pAhciReq, sizeof(AHCIREQ));
3659 if ( pReqDup
3660 && !ASMAtomicCmpXchgPtr(&pAhciPortR3->pTaskErr, pReqDup, NULL))
3661 RTMemFree(pReqDup);
3662 }
3663 else
3664 {
3665 /* Status will be set already for non I/O requests. */
3666 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_SCSI)
3667 {
3668 if (pAhciReq->u8ScsiSts == SCSI_STATUS_OK)
3669 {
3670 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
3671 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
3672 | ((pAhciReq->fFlags & AHCI_REQ_XFER_2_HOST) ? ATAPI_INT_REASON_IO : 0)
3673 | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
3674 }
3675 else
3676 {
3677 ahciReqSetStatus(pAhciReq, pAhciPort->abATAPISense[2] << 4, ATA_STAT_READY | ATA_STAT_ERR);
3678 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
3679 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
3680 pAhciReq->cbTransfer = 0;
3681 LogFlowFunc(("SCSI request completed with %u status\n", pAhciReq->u8ScsiSts));
3682 }
3683 }
3684 else if (pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_INVALID)
3685 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
3686
3687 /* Write updated command header into memory of the guest. */
3688 uint32_t u32PRDBC = 0;
3689 if (pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_INVALID)
3690 {
3691 size_t cbXfer = 0;
3692 int rc = pAhciPortR3->pDrvMediaEx->pfnIoReqQueryXferSize(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq, &cbXfer);
3693 AssertRC(rc);
3694 u32PRDBC = (uint32_t)RT_MIN(cbXfer, pAhciReq->cbTransfer);
3695 }
3696 else
3697 u32PRDBC = (uint32_t)pAhciReq->cbTransfer;
3698
3699 PDMDevHlpPCIPhysWriteMeta(pDevIns, pAhciReq->GCPhysCmdHdrAddr + RT_UOFFSETOF(CmdHdr, u32PRDBC),
3700 &u32PRDBC, sizeof(u32PRDBC));
3701
3702 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
3703 {
3704 /*
3705 * The guest tried to transfer more data than there is space in the buffer.
3706 * Terminate task and set the overflow bit.
3707 */
3708 /* Notify the guest. */
3709 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
3710 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
3711 ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
3712 }
3713 }
3714
3715 /*
3716 * Make a copy of the required data now and free the request. Otherwise the guest
3717 * might issue a new request with the same tag and we run into a conflict when allocating
3718 * a new request with the same tag later on.
3719 */
3720 uint32_t fFlags = pAhciReq->fFlags;
3721 uint32_t uTag = pAhciReq->uTag;
3722 size_t cbTransfer = pAhciReq->cbTransfer;
3723 bool fRead = pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ;
3724 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
3725 memcpy(&cmdFis[0], &pAhciReq->cmdFis[0], sizeof(cmdFis));
3726
3727 ahciR3ReqFree(pAhciPortR3, pAhciReq);
3728
3729 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
3730 if (fFlags & AHCI_REQ_PIO_DATA)
3731 ahciSendPioSetupFis(pDevIns, pThis, pAhciPort, cbTransfer, &cmdFis[0], fRead, false /* fInterrupt */);
3732
3733 if (fFlags & AHCI_REQ_CLEAR_SACT)
3734 {
3735 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPortR3->pTaskErr, PAHCIREQ))
3736 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(uTag));
3737 }
3738
3739 if (fFlags & AHCI_REQ_IS_QUEUED)
3740 {
3741 /*
3742 * Always raise an interrupt after task completion; delaying
3743 * this (interrupt coalescing) increases latency and has a significant
3744 * impact on performance (see @bugref{5071})
3745 */
3746 ahciSendSDBFis(pDevIns, pThis, pAhciPort, pAhciPortR3, 0, true);
3747 }
3748 else
3749 ahciSendD2HFis(pDevIns, pThis, pAhciPort, uTag, &cmdFis[0], true);
3750 }
3751 else
3752 {
3753 /*
3754 * Task was canceled, do the cleanup but DO NOT access the guest memory!
3755 * The guest might use it for other things now because it doesn't know about that task anymore.
3756 */
3757 fCanceled = true;
3758
3759 /* Leave a log message about the canceled request. */
3760 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
3761 {
3762 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
3763 LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
3764 pDevIns->iInstance, pAhciPort->iLUN, rcReq));
3765 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
3766 LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
3767 pDevIns->iInstance,pAhciPort->iLUN, rcReq));
3768 else
3769 LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%zu bytes left) returned rc=%Rrc\n",
3770 pDevIns->iInstance, pAhciPort->iLUN,
3771 pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ
3772 ? "read"
3773 : "write",
3774 pAhciReq->uOffset,
3775 pAhciReq->cbTransfer, rcReq));
3776 }
3777
3778 ahciR3ReqFree(pAhciPortR3, pAhciReq);
3779 }
3780
3781 /*
3782 * Decrement the active task counter as the last step or we might run into a
3783 * hang during power off otherwise (see @bugref{7859}).
3784 * Before it could happen that we signal PDM that we are done while we still have to
3785 * copy the data to the guest but EMT might be busy destroying the driver chains
3786 * below us while we have to delegate copying data to EMT instead of doing it
3787 * on this thread.
3788 */
3789 ASMAtomicDecU32(&pAhciPort->cTasksActive);
3790
3791 if (pAhciPort->cTasksActive == 0 && pThisCC->fSignalIdle)
3792 PDMDevHlpAsyncNotificationCompleted(pDevIns);
3793
3794 return fCanceled;
3795}
3796
3797/**
3798 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
3799 */
3800static DECLCALLBACK(int) ahciR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3801 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
3802 size_t cbCopy)
3803{
3804 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3805 int rc = VINF_SUCCESS;
3806 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
3807 RT_NOREF(hIoReq);
3808
3809 ahciR3CopySgBufToPrdtl(pAhciPortR3->pDevIns, pIoReq, pSgBuf, offDst, cbCopy);
3810
3811 if (pIoReq->fFlags & AHCI_REQ_OVERFLOW)
3812 rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
3813
3814 return rc;
3815}
3816
3817/**
3818 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
3819 */
3820static DECLCALLBACK(int) ahciR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3821 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
3822 size_t cbCopy)
3823{
3824 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3825 int rc = VINF_SUCCESS;
3826 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
3827 RT_NOREF(hIoReq);
3828
3829 ahciR3CopySgBufFromPrdtl(pAhciPortR3->pDevIns, pIoReq, pSgBuf, offSrc, cbCopy);
3830 if (pIoReq->fFlags & AHCI_REQ_OVERFLOW)
3831 rc = VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
3832
3833 return rc;
3834}
3835
3836/**
3837 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryBuf}
3838 */
3839static DECLCALLBACK(int) ahciR3IoReqQueryBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3840 void *pvIoReqAlloc, void **ppvBuf, size_t *pcbBuf)
3841{
3842 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3843 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
3844 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
3845 int rc = VERR_NOT_SUPPORTED;
3846 RT_NOREF(hIoReq);
3847
3848 /* Only allow single 4KB page aligned buffers at the moment. */
3849 if ( pIoReq->cPrdtlEntries == 1
3850 && pIoReq->cbTransfer == _4K)
3851 {
3852 RTGCPHYS GCPhysPrdt = pIoReq->GCPhysPrdtl;
3853 SGLEntry PrdtEntry;
3854
3855 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysPrdt, &PrdtEntry, sizeof(SGLEntry));
3856
3857 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(PrdtEntry.u32DBAUp, PrdtEntry.u32DBA);
3858 uint32_t cbData = (PrdtEntry.u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
3859
3860 if ( cbData >= _4K
3861 && !(GCPhysAddrDataBase & (_4K - 1)))
3862 {
3863 rc = PDMDevHlpPCIPhysGCPhys2CCPtr(pDevIns, NULL /* pPciDev */, GCPhysAddrDataBase, 0, ppvBuf, &pIoReq->PgLck);
3864 if (RT_SUCCESS(rc))
3865 {
3866 pIoReq->fMapped = true;
3867 *pcbBuf = cbData;
3868 }
3869 else
3870 rc = VERR_NOT_SUPPORTED;
3871 }
3872 }
3873
3874 return rc;
3875}
3876
3877/**
3878 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
3879 */
3880static DECLCALLBACK(int) ahciR3IoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3881 void *pvIoReqAlloc, uint32_t idxRangeStart,
3882 uint32_t cRanges, PRTRANGE paRanges,
3883 uint32_t *pcRanges)
3884{
3885 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3886 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
3887 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
3888 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
3889 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
3890 RT_NOREF(hIoReq);
3891
3892 return ahciTrimRangesCreate(pDevIns, pAhciPort, pIoReq, idxRangeStart, paRanges, cRanges, pcRanges);
3893}
3894
3895/**
3896 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
3897 */
3898static DECLCALLBACK(int) ahciR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3899 void *pvIoReqAlloc, int rcReq)
3900{
3901 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3902 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
3903 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
3904 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
3905 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
3906 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
3907 RT_NOREF(hIoReq);
3908
3909 ahciR3TransferComplete(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3, pIoReq, rcReq);
3910 return VINF_SUCCESS;
3911}
3912
3913/**
3914 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
3915 */
3916static DECLCALLBACK(void) ahciR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
3917 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
3918{
3919 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3920 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
3921 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
3922 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
3923 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
3924 RT_NOREF(hIoReq, pvIoReqAlloc);
3925
3926 switch (enmState)
3927 {
3928 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
3929 {
3930 /* Make sure the request is not accounted for so the VM can suspend successfully. */
3931 uint32_t cTasksActive = ASMAtomicDecU32(&pAhciPort->cTasksActive);
3932 if (!cTasksActive && pThisCC->fSignalIdle)
3933 PDMDevHlpAsyncNotificationCompleted(pDevIns);
3934 break;
3935 }
3936 case PDMMEDIAEXIOREQSTATE_ACTIVE:
3937 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
3938 ASMAtomicIncU32(&pAhciPort->cTasksActive);
3939 break;
3940 default:
3941 AssertMsgFailed(("Invalid request state given %u\n", enmState));
3942 }
3943}
3944
3945/**
3946 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
3947 */
3948static DECLCALLBACK(void) ahciR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
3949{
3950 PAHCIPORTR3 pAhciPortR3 = RT_FROM_MEMBER(pInterface, AHCIPORTR3, IMediaExPort);
3951 PPDMDEVINS pDevIns = pAhciPortR3->pDevIns;
3952 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
3953 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
3954 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
3955
3956 if (pThisCC->pMediaNotify)
3957 {
3958 int rc = PDMDevHlpVMReqCallNoWait(pDevIns, VMCPUID_ANY,
3959 (PFNRT)pThisCC->pMediaNotify->pfnEjected, 2,
3960 pThisCC->pMediaNotify, pAhciPort->iLUN);
3961 AssertRC(rc);
3962 }
3963}
3964
3965/**
3966 * Process an non read/write ATA command.
3967 *
3968 * @returns The direction of the data transfer
3969 * @param pDevIns The device instance.
3970 * @param pThis The shared AHCI state.
3971 * @param pAhciPort The AHCI port of the request, shared bits.
3972 * @param pAhciPortR3 The AHCI port of the request, ring-3 bits.
3973 * @param pAhciReq The AHCI request state.
3974 * @param pCmdFis Pointer to the command FIS.
3975 */
3976static PDMMEDIAEXIOREQTYPE ahciProcessCmd(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3,
3977 PAHCIREQ pAhciReq, uint8_t *pCmdFis)
3978{
3979 PDMMEDIAEXIOREQTYPE enmType = PDMMEDIAEXIOREQTYPE_INVALID;
3980 bool fLBA48 = false;
3981
3982 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
3983
3984 pAhciReq->cbTransfer = 0;
3985
3986 switch (pCmdFis[AHCI_CMDFIS_CMD])
3987 {
3988 case ATA_IDENTIFY_DEVICE:
3989 {
3990 if (pAhciPortR3->pDrvMedia && !pAhciPort->fATAPI)
3991 {
3992 uint16_t u16Temp[256];
3993
3994 /* Fill the buffer. */
3995 ahciIdentifySS(pThis, pAhciPort, pAhciPortR3, u16Temp);
3996
3997 /* Copy the buffer. */
3998 size_t cbCopied = ahciR3CopyBufferToPrdtl(pDevIns, pAhciReq, &u16Temp[0], sizeof(u16Temp), 0 /* cbSkip */);
3999
4000 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
4001 pAhciReq->cbTransfer = cbCopied;
4002 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4003 }
4004 else
4005 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR);
4006 break;
4007 }
4008 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
4009 case ATA_READ_NATIVE_MAX_ADDRESS:
4010 break;
4011 case ATA_SET_FEATURES:
4012 {
4013 switch (pCmdFis[AHCI_CMDFIS_FET])
4014 {
4015 case 0x02: /* write cache enable */
4016 case 0xaa: /* read look-ahead enable */
4017 case 0x55: /* read look-ahead disable */
4018 case 0xcc: /* reverting to power-on defaults enable */
4019 case 0x66: /* reverting to power-on defaults disable */
4020 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4021 break;
4022 case 0x82: /* write cache disable */
4023 enmType = PDMMEDIAEXIOREQTYPE_FLUSH;
4024 break;
4025 case 0x03:
4026 {
4027 /* set transfer mode */
4028 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4029 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
4030 {
4031 case 0x00: /* PIO default */
4032 case 0x08: /* PIO mode */
4033 break;
4034 case ATA_MODE_MDMA: /* MDMA mode */
4035 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
4036 break;
4037 case ATA_MODE_UDMA: /* UDMA mode */
4038 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
4039 break;
4040 }
4041 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4042 break;
4043 }
4044 default:
4045 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4046 }
4047 break;
4048 }
4049 case ATA_DEVICE_RESET:
4050 {
4051 if (!pAhciPort->fATAPI)
4052 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4053 else
4054 {
4055 /* Reset the device. */
4056 ahciDeviceReset(pDevIns, pThis, pAhciPort, pAhciReq);
4057 }
4058 break;
4059 }
4060 case ATA_FLUSH_CACHE_EXT:
4061 case ATA_FLUSH_CACHE:
4062 enmType = PDMMEDIAEXIOREQTYPE_FLUSH;
4063 break;
4064 case ATA_PACKET:
4065 if (!pAhciPort->fATAPI)
4066 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4067 else
4068 enmType = PDMMEDIAEXIOREQTYPE_SCSI;
4069 break;
4070 case ATA_IDENTIFY_PACKET_DEVICE:
4071 if (!pAhciPort->fATAPI)
4072 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4073 else
4074 {
4075 size_t cbData;
4076 ahciR3AtapiIdentify(pDevIns, pAhciReq, pAhciPort, 512, &cbData);
4077
4078 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
4079 pAhciReq->cbTransfer = cbData;
4080 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
4081 | ((pAhciReq->fFlags & AHCI_REQ_XFER_2_HOST) ? ATAPI_INT_REASON_IO : 0)
4082 | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
4083
4084 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4085 }
4086 break;
4087 case ATA_SET_MULTIPLE_MODE:
4088 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
4089 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
4090 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
4091 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4092 else
4093 {
4094 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4095 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
4096 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4097 }
4098 break;
4099 case ATA_STANDBY_IMMEDIATE:
4100 break; /* Do nothing. */
4101 case ATA_CHECK_POWER_MODE:
4102 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
4103 RT_FALL_THRU();
4104 case ATA_INITIALIZE_DEVICE_PARAMETERS:
4105 case ATA_IDLE_IMMEDIATE:
4106 case ATA_RECALIBRATE:
4107 case ATA_NOP:
4108 case ATA_READ_VERIFY_SECTORS_EXT:
4109 case ATA_READ_VERIFY_SECTORS:
4110 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
4111 case ATA_SLEEP:
4112 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
4113 break;
4114 case ATA_READ_DMA_EXT:
4115 fLBA48 = true;
4116 RT_FALL_THRU();
4117 case ATA_READ_DMA:
4118 {
4119 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
4120 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
4121 enmType = PDMMEDIAEXIOREQTYPE_READ;
4122 break;
4123 }
4124 case ATA_WRITE_DMA_EXT:
4125 fLBA48 = true;
4126 RT_FALL_THRU();
4127 case ATA_WRITE_DMA:
4128 {
4129 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
4130 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
4131 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
4132 break;
4133 }
4134 case ATA_READ_FPDMA_QUEUED:
4135 {
4136 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
4137 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
4138 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
4139 enmType = PDMMEDIAEXIOREQTYPE_READ;
4140 break;
4141 }
4142 case ATA_WRITE_FPDMA_QUEUED:
4143 {
4144 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
4145 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
4146 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
4147 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
4148 break;
4149 }
4150 case ATA_READ_LOG_EXT:
4151 {
4152 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
4153 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
4154 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
4155
4156 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
4157
4158 uint8_t aBuf[512];
4159
4160 memset(aBuf, 0, sizeof(aBuf));
4161
4162 if (offLogRead + cbLogRead <= sizeof(aBuf))
4163 {
4164 switch (iPage)
4165 {
4166 case 0x10:
4167 {
4168 LogFlow(("Reading error page\n"));
4169 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPortR3->pTaskErr, NULL, PAHCIREQ);
4170 if (pTaskErr)
4171 {
4172 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
4173 aBuf[2] = pTaskErr->cmdFis[AHCI_CMDFIS_STS];
4174 aBuf[3] = pTaskErr->cmdFis[AHCI_CMDFIS_ERR];
4175 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
4176 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
4177 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
4178 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
4179 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
4180 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
4181 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
4182 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
4183 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
4184
4185 /* Calculate checksum */
4186 uint8_t uChkSum = 0;
4187 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
4188 uChkSum += aBuf[i];
4189
4190 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
4191
4192 /* Finally free the error task state structure because it is completely unused now. */
4193 RTMemFree(pTaskErr);
4194 }
4195
4196 /*
4197 * Reading this log page results in an abort of all outstanding commands
4198 * and clearing the SActive register and TaskFile register.
4199 *
4200 * See SATA2 1.2 spec chapter 4.2.3.4
4201 */
4202 bool fAbortedAll = ahciR3CancelActiveTasks(pAhciPortR3);
4203 Assert(fAbortedAll); NOREF(fAbortedAll);
4204 ahciSendSDBFis(pDevIns, pThis, pAhciPort, pAhciPortR3, UINT32_C(0xffffffff), true);
4205
4206 break;
4207 }
4208 }
4209
4210 /* Copy the buffer. */
4211 size_t cbCopied = ahciR3CopyBufferToPrdtl(pDevIns, pAhciReq, &aBuf[offLogRead], cbLogRead, 0 /* cbSkip */);
4212
4213 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
4214 pAhciReq->cbTransfer = cbCopied;
4215 }
4216
4217 break;
4218 }
4219 case ATA_DATA_SET_MANAGEMENT:
4220 {
4221 if (pAhciPort->fTrimEnabled)
4222 {
4223 /* Check that the trim bit is set and all other bits are 0. */
4224 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
4225 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
4226 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4227 else
4228 enmType = PDMMEDIAEXIOREQTYPE_DISCARD;
4229 break;
4230 }
4231 /* else: fall through and report error to the guest. */
4232 }
4233 RT_FALL_THRU();
4234 /* All not implemented commands go below. */
4235 case ATA_SECURITY_FREEZE_LOCK:
4236 case ATA_SMART:
4237 case ATA_NV_CACHE:
4238 case ATA_IDLE:
4239 case ATA_TRUSTED_RECEIVE_DMA: /* Windows 8+ */
4240 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4241 break;
4242 default: /* For debugging purposes. */
4243 AssertMsgFailed(("Unknown command issued (%#x)\n", pCmdFis[AHCI_CMDFIS_CMD]));
4244 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
4245 }
4246
4247 return enmType;
4248}
4249
4250/**
4251 * Retrieve a command FIS from guest memory.
4252 *
4253 * @returns whether the H2D FIS was successfully read from the guest memory.
4254 * @param pDevIns The device instance.
4255 * @param pThis The shared AHCI state.
4256 * @param pAhciPort The AHCI port of the request, shared bits.
4257 * @param pAhciReq The state of the actual task.
4258 */
4259static bool ahciPortTaskGetCommandFis(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIREQ pAhciReq)
4260{
4261 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
4262 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
4263 false);
4264
4265 /*
4266 * First we are reading the command header pointed to by regCLB.
4267 * From this we get the address of the command table which we are reading too.
4268 * We can process the Command FIS afterwards.
4269 */
4270 CmdHdr cmdHdr;
4271 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
4272 LogFlow(("%s: PDMDevHlpPCIPhysReadMeta GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
4273 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
4274 PDMDevHlpPCIPhysReadMeta(pDevIns, pAhciReq->GCPhysCmdHdrAddr, &cmdHdr, sizeof(CmdHdr));
4275
4276#ifdef LOG_ENABLED
4277 /* Print some infos about the command header. */
4278 ahciDumpCmdHdrInfo(pAhciPort, &cmdHdr);
4279#endif
4280
4281 RTGCPHYS GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(cmdHdr.u32CmdTblAddrUp, cmdHdr.u32CmdTblAddr);
4282
4283 AssertMsgReturn((cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
4284 ("This is not a command FIS!!\n"),
4285 false);
4286
4287 /* Read the command Fis. */
4288 LogFlow(("%s: PDMDevHlpPCIPhysReadMeta GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
4289 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
4290
4291 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
4292 ("This is not a command FIS\n"),
4293 false);
4294
4295 /* Set transfer direction. */
4296 pAhciReq->fFlags |= (cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? 0 : AHCI_REQ_XFER_2_HOST;
4297
4298 /* If this is an ATAPI command read the atapi command. */
4299 if (cmdHdr.u32DescInf & AHCI_CMDHDR_A)
4300 {
4301 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
4302 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
4303 }
4304
4305 /* We "received" the FIS. Clear the BSY bit in regTFD. */
4306 if ((cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
4307 {
4308 /*
4309 * We need to send a FIS which clears the busy bit if this is a queued command so that the guest can queue other commands.
4310 * but this FIS does not assert an interrupt
4311 */
4312 ahciSendD2HFis(pDevIns, pThis, pAhciPort, pAhciReq->uTag, pAhciReq->cmdFis, false);
4313 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
4314 }
4315
4316 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(cmdHdr.u32CmdTblAddrUp, cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4317 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(cmdHdr.u32DescInf);
4318
4319#ifdef LOG_ENABLED
4320 /* Print some infos about the FIS. */
4321 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
4322
4323 /* Print the PRDT */
4324 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
4325 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
4326
4327 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
4328 {
4329 SGLEntry SGEntry;
4330
4331 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
4332 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
4333
4334 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
4335 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
4336
4337 GCPhysPrdtl += sizeof(SGLEntry);
4338 }
4339#endif
4340
4341 return true;
4342}
4343
4344/**
4345 * Submits a given request for execution.
4346 *
4347 * @returns Flag whether the request was canceled inbetween.
4348 * @param pDevIns The device instance.
4349 * @param pThis The shared AHCI state.
4350 * @param pThisCC The ring-3 AHCI state.
4351 * @param pAhciPort The port the request is for, shared bits.
4352 * @param pAhciPortR3 The port the request is for, ring-3 bits.
4353 * @param pAhciReq The request to submit.
4354 * @param enmType The request type.
4355 */
4356static bool ahciR3ReqSubmit(PPDMDEVINS pDevIns, PAHCI pThis, PAHCICC pThisCC, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3,
4357 PAHCIREQ pAhciReq, PDMMEDIAEXIOREQTYPE enmType)
4358{
4359 int rc = VINF_SUCCESS;
4360 bool fReqCanceled = false;
4361
4362 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, pAhciReq->enmType, pAhciReq->uOffset, pAhciReq->cbTransfer);
4363
4364 if (enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
4365 rc = pAhciPortR3->pDrvMediaEx->pfnIoReqFlush(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq);
4366 else if (enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
4367 {
4368 uint32_t cRangesMax;
4369
4370 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
4371 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
4372 cRangesMax = 65536 * 512 / 8;
4373 else
4374 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
4375
4376 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
4377 rc = pAhciPortR3->pDrvMediaEx->pfnIoReqDiscard(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq,
4378 cRangesMax);
4379 }
4380 else if (enmType == PDMMEDIAEXIOREQTYPE_READ)
4381 {
4382 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
4383 rc = pAhciPortR3->pDrvMediaEx->pfnIoReqRead(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq,
4384 pAhciReq->uOffset, pAhciReq->cbTransfer);
4385 }
4386 else if (enmType == PDMMEDIAEXIOREQTYPE_WRITE)
4387 {
4388 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
4389 rc = pAhciPortR3->pDrvMediaEx->pfnIoReqWrite(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq,
4390 pAhciReq->uOffset, pAhciReq->cbTransfer);
4391 }
4392 else if (enmType == PDMMEDIAEXIOREQTYPE_SCSI)
4393 {
4394 size_t cbBuf = 0;
4395
4396 if (pAhciReq->cPrdtlEntries)
4397 rc = ahciR3PrdtQuerySize(pDevIns, pAhciReq, &cbBuf);
4398 pAhciReq->cbTransfer = cbBuf;
4399 if (RT_SUCCESS(rc))
4400 {
4401 if (cbBuf && (pAhciReq->fFlags & AHCI_REQ_XFER_2_HOST))
4402 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
4403 else if (cbBuf)
4404 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
4405 rc = pAhciPortR3->pDrvMediaEx->pfnIoReqSendScsiCmd(pAhciPortR3->pDrvMediaEx, pAhciReq->hIoReq,
4406 0, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE,
4407 PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, NULL, cbBuf,
4408 &pAhciPort->abATAPISense[0], sizeof(pAhciPort->abATAPISense), NULL,
4409 &pAhciReq->u8ScsiSts, 30 * RT_MS_1SEC);
4410 }
4411 }
4412
4413 if (rc == VINF_SUCCESS)
4414 fReqCanceled = ahciR3TransferComplete(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3, pAhciReq, VINF_SUCCESS);
4415 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
4416 fReqCanceled = ahciR3TransferComplete(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3, pAhciReq, rc);
4417
4418 return fReqCanceled;
4419}
4420
4421/**
4422 * Prepares the command for execution coping it from guest memory and doing a few
4423 * validation checks on it.
4424 *
4425 * @returns Whether the command was successfully fetched from guest memory and
4426 * can be continued.
4427 * @param pDevIns The device instance.
4428 * @param pThis The shared AHCI state.
4429 * @param pAhciPort The AHCI port the request is for, shared bits.
4430 * @param pAhciReq Request structure to copy the command to.
4431 */
4432static bool ahciR3CmdPrepare(PPDMDEVINS pDevIns, PAHCI pThis, PAHCIPORT pAhciPort, PAHCIREQ pAhciReq)
4433{
4434 /* Set current command slot */
4435 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
4436
4437 bool fContinue = ahciPortTaskGetCommandFis(pDevIns, pThis, pAhciPort, pAhciReq);
4438 if (fContinue)
4439 {
4440 /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
4441 if (pAhciPort->regSACT & RT_BIT_32(pAhciReq->uTag))
4442 {
4443 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
4444 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(pAhciReq->uTag));
4445 }
4446
4447 if (pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
4448 {
4449 /*
4450 * It is possible that the request counter can get one higher than the maximum because
4451 * the request counter is decremented after the guest was notified about the completed
4452 * request (see @bugref{7859}). If the completing thread is preempted in between the
4453 * guest might already issue another request before the request counter is decremented
4454 * which would trigger the following assertion incorrectly in the past.
4455 */
4456 AssertLogRelMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) <= AHCI_NR_COMMAND_SLOTS,
4457 ("AHCI#%uP%u: There are more than %u (+1) requests active",
4458 pDevIns->iInstance, pAhciPort->iLUN,
4459 AHCI_NR_COMMAND_SLOTS));
4460 ASMAtomicIncU32(&pAhciPort->cTasksActive);
4461 }
4462 else
4463 {
4464 /* If the reset bit is set put the device into reset state. */
4465 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
4466 {
4467 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
4468 pAhciPort->fResetDevice = true;
4469 ahciSendD2HFis(pDevIns, pThis, pAhciPort, pAhciReq->uTag, pAhciReq->cmdFis, true);
4470 }
4471 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
4472 ahciFinishStorageDeviceReset(pDevIns, pThis, pAhciPort, pAhciReq);
4473 else /* We are not in a reset state update the control registers. */
4474 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
4475
4476 fContinue = false;
4477 }
4478 }
4479 else
4480 {
4481 /*
4482 * Couldn't find anything in either the AHCI or SATA spec which
4483 * indicates what should be done if the FIS is not read successfully.
4484 * The closest thing is in the state machine, stating that the device
4485 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
4486 * Do the same here and ignore any corrupt FIS types, after all
4487 * the guest messed up everything and this behavior is undefined.
4488 */
4489 fContinue = false;
4490 }
4491
4492 return fContinue;
4493}
4494
4495/**
4496 * @callback_method_impl{FNPDMTHREADDEV, The async IO thread for one port.}
4497 */
4498static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4499{
4500 PAHCIPORTR3 pAhciPortR3 = (PAHCIPORTR3)pThread->pvUser;
4501 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4502 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
4503 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
4504 int rc = VINF_SUCCESS;
4505
4506 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
4507
4508 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
4509 return VINF_SUCCESS;
4510
4511 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4512 {
4513 unsigned idx = 0;
4514 uint32_t u32Tasks = 0;
4515 uint32_t u32RegHbaCtrl = 0;
4516
4517 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
4518 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
4519 if (!u32Tasks)
4520 {
4521 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
4522 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
4523 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
4524 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
4525 break;
4526 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
4527 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
4528 }
4529
4530 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
4531 ASMAtomicIncU32(&pThis->cThreadsActive);
4532
4533 /* Check whether the thread should be suspended. */
4534 if (pThisCC->fSignalIdle)
4535 {
4536 if (!ASMAtomicDecU32(&pThis->cThreadsActive))
4537 PDMDevHlpAsyncNotificationCompleted(pDevIns);
4538 continue;
4539 }
4540
4541 /*
4542 * Check whether the global host controller bit is set and go to sleep immediately again
4543 * if it is set.
4544 */
4545 u32RegHbaCtrl = ASMAtomicReadU32(&pThis->regHbaCtrl);
4546 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
4547 && !ASMAtomicDecU32(&pThis->cThreadsActive))
4548 {
4549 ahciR3HBAReset(pDevIns, pThis, pThisCC);
4550 if (pThisCC->fSignalIdle)
4551 PDMDevHlpAsyncNotificationCompleted(pDevIns);
4552 continue;
4553 }
4554
4555 idx = ASMBitFirstSetU32(u32Tasks);
4556 while ( idx
4557 && !pAhciPort->fPortReset)
4558 {
4559 bool fReqCanceled = false;
4560
4561 /* Decrement to get the slot number. */
4562 idx--;
4563 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
4564
4565 PAHCIREQ pAhciReq = ahciR3ReqAlloc(pAhciPortR3, idx);
4566 if (RT_LIKELY(pAhciReq))
4567 {
4568 pAhciReq->uTag = idx;
4569 pAhciReq->fFlags = 0;
4570
4571 bool fContinue = ahciR3CmdPrepare(pDevIns, pThis, pAhciPort, pAhciReq);
4572 if (fContinue)
4573 {
4574 PDMMEDIAEXIOREQTYPE enmType = ahciProcessCmd(pDevIns, pThis, pAhciPort, pAhciPortR3,
4575 pAhciReq, pAhciReq->cmdFis);
4576 pAhciReq->enmType = enmType;
4577
4578 if (enmType != PDMMEDIAEXIOREQTYPE_INVALID)
4579 fReqCanceled = ahciR3ReqSubmit(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3, pAhciReq, enmType);
4580 else
4581 fReqCanceled = ahciR3TransferComplete(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3,
4582 pAhciReq, VINF_SUCCESS);
4583 } /* Command */
4584 else
4585 ahciR3ReqFree(pAhciPortR3, pAhciReq);
4586 }
4587 else /* !Request allocated, use on stack variant to signal the error. */
4588 {
4589 AHCIREQ Req;
4590 Req.uTag = idx;
4591 Req.fFlags = AHCI_REQ_IS_ON_STACK;
4592 Req.fMapped = false;
4593 Req.cbTransfer = 0;
4594 Req.uOffset = 0;
4595 Req.enmType = PDMMEDIAEXIOREQTYPE_INVALID;
4596
4597 bool fContinue = ahciR3CmdPrepare(pDevIns, pThis, pAhciPort, &Req);
4598 if (fContinue)
4599 fReqCanceled = ahciR3TransferComplete(pDevIns, pThis, pThisCC, pAhciPort, pAhciPortR3, &Req, VERR_NO_MEMORY);
4600 }
4601
4602 /*
4603 * Don't process other requests if the last one was canceled,
4604 * the others are not valid anymore.
4605 */
4606 if (fReqCanceled)
4607 break;
4608
4609 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
4610 idx = ASMBitFirstSetU32(u32Tasks);
4611 } /* while tasks available */
4612
4613 /* Check whether a port reset was active. */
4614 if ( ASMAtomicReadBool(&pAhciPort->fPortReset)
4615 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
4616 ahciPortResetFinish(pDevIns, pThis, pAhciPort, pAhciPortR3);
4617
4618 /*
4619 * Check whether a host controller reset is pending and execute the reset
4620 * if this is the last active thread.
4621 */
4622 u32RegHbaCtrl = ASMAtomicReadU32(&pThis->regHbaCtrl);
4623 uint32_t cThreadsActive = ASMAtomicDecU32(&pThis->cThreadsActive);
4624 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
4625 && !cThreadsActive)
4626 ahciR3HBAReset(pDevIns, pThis, pThisCC);
4627
4628 if (!cThreadsActive && pThisCC->fSignalIdle)
4629 PDMDevHlpAsyncNotificationCompleted(pDevIns);
4630 } /* While running */
4631
4632 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
4633 return VINF_SUCCESS;
4634}
4635
4636/**
4637 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
4638 */
4639static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4640{
4641 PAHCIPORTR3 pAhciPortR3 = (PAHCIPORTR3)pThread->pvUser;
4642 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4643 PAHCIPORT pAhciPort = &RT_SAFE_SUBSCRIPT(pThis->aPorts, pAhciPortR3->iLUN);
4644 return PDMDevHlpSUPSemEventSignal(pDevIns, pAhciPort->hEvtProcess);
4645}
4646
4647/* -=-=-=-=- DBGF -=-=-=-=- */
4648
4649/**
4650 * AHCI status info callback.
4651 *
4652 * @param pDevIns The device instance.
4653 * @param pHlp The output helpers.
4654 * @param pszArgs The arguments.
4655 */
4656static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4657{
4658 RT_NOREF(pszArgs);
4659 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4660
4661 /*
4662 * Show info.
4663 */
4664 pHlp->pfnPrintf(pHlp,
4665 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
4666 pDevIns->pReg->szName,
4667 pDevIns->iInstance,
4668 PDMDevHlpMmioGetMappingAddress(pDevIns, pThis->hMmio),
4669 pThis->cPortsImpl,
4670 pDevIns->fRCEnabled,
4671 pDevIns->fR0Enabled);
4672
4673 /*
4674 * Show global registers.
4675 */
4676 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
4677 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
4678 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
4679 pHlp->pfnPrintf(pHlp, "HbaPi=%#x\n", pThis->regHbaPi);
4680 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
4681 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
4682 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
4683 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
4684
4685 /*
4686 * Per port data.
4687 */
4688 uint32_t const cPortsImpl = RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts));
4689 for (unsigned i = 0; i < cPortsImpl; i++)
4690 {
4691 PAHCIPORT pThisPort = &pThis->aPorts[i];
4692
4693 pHlp->pfnPrintf(pHlp, "Port %d: device-attached=%RTbool\n", pThisPort->iLUN, pThisPort->fPresent);
4694 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
4695 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
4696 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
4697 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
4698 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
4699 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
4700 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
4701 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
4702 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
4703 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
4704 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
4705 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
4706 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
4707 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
4708 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
4709 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
4710 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
4711 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
4712 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
4713 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSent=%RTbool\n", pThisPort->fFirstD2HFisSent);
4714 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
4715 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
4716 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
4717 pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
4718 pHlp->pfnPrintf(pHlp, "\n");
4719 }
4720}
4721
4722/* -=-=-=-=- Helper -=-=-=-=- */
4723
4724/**
4725 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
4726 *
4727 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
4728 * use of it in strict builds (which is why it's up here).
4729 *
4730 * @returns true if quiesced, false if busy.
4731 * @param pDevIns The device instance.
4732 */
4733static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
4734{
4735 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4736
4737 if (pThis->cThreadsActive)
4738 return false;
4739
4740 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aPorts); i++)
4741 {
4742 PAHCIPORT pThisPort = &pThis->aPorts[i];
4743 if (pThisPort->fPresent)
4744 {
4745 if ( (pThisPort->cTasksActive != 0)
4746 || (pThisPort->u32TasksNew != 0))
4747 return false;
4748 }
4749 }
4750 return true;
4751}
4752
4753/* -=-=-=-=- Saved State -=-=-=-=- */
4754
4755/**
4756 * @callback_method_impl{FNSSMDEVSAVEPREP}
4757 */
4758static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4759{
4760 RT_NOREF(pDevIns, pSSM);
4761 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
4762 return VINF_SUCCESS;
4763}
4764
4765/**
4766 * @callback_method_impl{FNSSMDEVLOADPREP}
4767 */
4768static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4769{
4770 RT_NOREF(pDevIns, pSSM);
4771 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
4772 return VINF_SUCCESS;
4773}
4774
4775/**
4776 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4777 */
4778static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4779{
4780 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4781 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4782 RT_NOREF(uPass);
4783
4784 /* config. */
4785 pHlp->pfnSSMPutU32(pSSM, pThis->cPortsImpl);
4786 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
4787 {
4788 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fPresent);
4789 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fHotpluggable);
4790 pHlp->pfnSSMPutStrZ(pSSM, pThis->aPorts[i].szSerialNumber);
4791 pHlp->pfnSSMPutStrZ(pSSM, pThis->aPorts[i].szFirmwareRevision);
4792 pHlp->pfnSSMPutStrZ(pSSM, pThis->aPorts[i].szModelNumber);
4793 }
4794
4795 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
4796 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
4797 {
4798 uint32_t iPort;
4799 int rc = pHlp->pfnCFGMQueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
4800 AssertRCReturn(rc, rc);
4801 pHlp->pfnSSMPutU32(pSSM, iPort);
4802 }
4803
4804 return VINF_SSM_DONT_CALL_AGAIN;
4805}
4806
4807/**
4808 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4809 */
4810static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4811{
4812 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4813 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4814 uint32_t i;
4815 int rc;
4816
4817 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
4818
4819 /* The config */
4820 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4821 AssertRCReturn(rc, rc);
4822
4823 /* The main device structure. */
4824 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaCap);
4825 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaCtrl);
4826 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaIs);
4827 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaPi);
4828 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaVs);
4829 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaCccCtl);
4830 pHlp->pfnSSMPutU32(pSSM, pThis->regHbaCccPorts);
4831 pHlp->pfnSSMPutU8(pSSM, pThis->uCccPortNr);
4832 pHlp->pfnSSMPutU64(pSSM, pThis->uCccTimeout);
4833 pHlp->pfnSSMPutU32(pSSM, pThis->uCccNr);
4834 pHlp->pfnSSMPutU32(pSSM, pThis->uCccCurrentNr);
4835 pHlp->pfnSSMPutU32(pSSM, pThis->u32PortsInterrupted);
4836 pHlp->pfnSSMPutBool(pSSM, pThis->fReset);
4837 pHlp->pfnSSMPutBool(pSSM, pThis->f64BitAddr);
4838 pHlp->pfnSSMPutBool(pSSM, pDevIns->fR0Enabled);
4839 pHlp->pfnSSMPutBool(pSSM, pDevIns->fRCEnabled);
4840 pHlp->pfnSSMPutBool(pSSM, pThis->fLegacyPortResetMethod);
4841
4842 /* Now every port. */
4843 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
4844 {
4845 Assert(pThis->aPorts[i].cTasksActive == 0);
4846 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regCLB);
4847 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regCLBU);
4848 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regFB);
4849 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regFBU);
4850 pHlp->pfnSSMPutGCPhys(pSSM, pThis->aPorts[i].GCPhysAddrClb);
4851 pHlp->pfnSSMPutGCPhys(pSSM, pThis->aPorts[i].GCPhysAddrFb);
4852 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regIS);
4853 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regIE);
4854 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regCMD);
4855 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regTFD);
4856 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regSIG);
4857 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regSSTS);
4858 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regSCTL);
4859 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regSERR);
4860 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regSACT);
4861 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].regCI);
4862 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].PCHSGeometry.cCylinders);
4863 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].PCHSGeometry.cHeads);
4864 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].PCHSGeometry.cSectors);
4865 pHlp->pfnSSMPutU64(pSSM, pThis->aPorts[i].cTotalSectors);
4866 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].cMultSectors);
4867 pHlp->pfnSSMPutU8(pSSM, pThis->aPorts[i].uATATransferMode);
4868 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fResetDevice);
4869 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fPoweredOn);
4870 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fSpunUp);
4871 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].u32TasksFinished);
4872 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].u32QueuedTasksFinished);
4873 pHlp->pfnSSMPutU32(pSSM, pThis->aPorts[i].u32CurrentCommandSlot);
4874
4875 /* ATAPI saved state. */
4876 pHlp->pfnSSMPutBool(pSSM, pThis->aPorts[i].fATAPI);
4877 pHlp->pfnSSMPutMem(pSSM, &pThis->aPorts[i].abATAPISense[0], sizeof(pThis->aPorts[i].abATAPISense));
4878 }
4879
4880 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
4881}
4882
4883/**
4884 * Loads a saved legacy ATA emulated device state.
4885 *
4886 * @returns VBox status code.
4887 * @param pHlp The device helper call table.
4888 * @param pSSM The handle to the saved state.
4889 */
4890static int ahciR3LoadLegacyEmulationState(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
4891{
4892 int rc;
4893 uint32_t u32Version;
4894 uint32_t u32;
4895 uint32_t u32IOBuffer;
4896
4897 /* Test for correct version. */
4898 rc = pHlp->pfnSSMGetU32(pSSM, &u32Version);
4899 AssertRCReturn(rc, rc);
4900 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
4901
4902 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
4903 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
4904 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
4905 {
4906 AssertMsgFailed(("u32Version=%d\n", u32Version));
4907 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4908 }
4909
4910 pHlp->pfnSSMSkip(pSSM, 19 + 5 * sizeof(bool) + 8 /* sizeof(BMDMAState) */);
4911
4912 for (uint32_t j = 0; j < 2; j++)
4913 {
4914 pHlp->pfnSSMSkip(pSSM, 88 + 5 * sizeof(bool) );
4915
4916 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
4917 pHlp->pfnSSMSkip(pSSM, 64);
4918 else
4919 pHlp->pfnSSMSkip(pSSM, 2);
4920 /** @todo triple-check this hack after passthrough is working */
4921 pHlp->pfnSSMSkip(pSSM, 1);
4922
4923 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
4924 pHlp->pfnSSMSkip(pSSM, 4);
4925
4926 pHlp->pfnSSMSkip(pSSM, sizeof(PDMLED));
4927 pHlp->pfnSSMGetU32(pSSM, &u32IOBuffer);
4928 if (u32IOBuffer)
4929 pHlp->pfnSSMSkip(pSSM, u32IOBuffer);
4930 }
4931
4932 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
4933 if (RT_FAILURE(rc))
4934 return rc;
4935 if (u32 != ~0U)
4936 {
4937 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
4938 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
4939 return rc;
4940 }
4941
4942 return VINF_SUCCESS;
4943}
4944
4945/**
4946 * @callback_method_impl{FNSSMDEVLOADEXEC}
4947 */
4948static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4949{
4950 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
4951 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4952 uint32_t u32;
4953 int rc;
4954
4955 if ( uVersion > AHCI_SAVED_STATE_VERSION
4956 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
4957 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4958
4959 /* Deal with the priod after removing the saved IDE bits where the saved
4960 state version remained unchanged. */
4961 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
4962 && pHlp->pfnSSMHandleRevision(pSSM) >= 79045
4963 && pHlp->pfnSSMHandleRevision(pSSM) < 79201)
4964 uVersion++;
4965
4966 /*
4967 * Check whether we have to resort to the legacy port reset method to
4968 * prevent older BIOS versions from failing after a reset.
4969 */
4970 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
4971 pThis->fLegacyPortResetMethod = true;
4972
4973 /* Verify config. */
4974 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
4975 {
4976 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
4977 AssertRCReturn(rc, rc);
4978 if (u32 != pThis->cPortsImpl)
4979 {
4980 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
4981 if ( u32 < pThis->cPortsImpl
4982 || u32 > AHCI_MAX_NR_PORTS_IMPL)
4983 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
4984 u32, pThis->cPortsImpl);
4985 }
4986
4987 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
4988 {
4989 bool fInUse;
4990 rc = pHlp->pfnSSMGetBool(pSSM, &fInUse);
4991 AssertRCReturn(rc, rc);
4992 if (fInUse != pThis->aPorts[i].fPresent)
4993 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
4994 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
4995 fInUse ? "target" : "source", i);
4996
4997 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
4998 {
4999 bool fHotpluggable;
5000 rc = pHlp->pfnSSMGetBool(pSSM, &fHotpluggable);
5001 AssertRCReturn(rc, rc);
5002 if (fHotpluggable != pThis->aPorts[i].fHotpluggable)
5003 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
5004 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
5005 i, fHotpluggable, pThis->aPorts[i].fHotpluggable);
5006 }
5007 else
5008 Assert(pThis->aPorts[i].fHotpluggable);
5009
5010 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
5011 rc = pHlp->pfnSSMGetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
5012 AssertRCReturn(rc, rc);
5013 if (strcmp(szSerialNumber, pThis->aPorts[i].szSerialNumber))
5014 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
5015 i, szSerialNumber, pThis->aPorts[i].szSerialNumber));
5016
5017 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
5018 rc = pHlp->pfnSSMGetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
5019 AssertRCReturn(rc, rc);
5020 if (strcmp(szFirmwareRevision, pThis->aPorts[i].szFirmwareRevision))
5021 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
5022 i, szFirmwareRevision, pThis->aPorts[i].szFirmwareRevision));
5023
5024 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
5025 rc = pHlp->pfnSSMGetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
5026 AssertRCReturn(rc, rc);
5027 if (strcmp(szModelNumber, pThis->aPorts[i].szModelNumber))
5028 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
5029 i, szModelNumber, pThis->aPorts[i].szModelNumber));
5030 }
5031
5032 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
5033 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
5034 {
5035 uint32_t iPort;
5036 rc = pHlp->pfnCFGMQueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
5037 AssertRCReturn(rc, rc);
5038
5039 uint32_t iPortSaved;
5040 rc = pHlp->pfnSSMGetU32(pSSM, &iPortSaved);
5041 AssertRCReturn(rc, rc);
5042
5043 if (iPortSaved != iPort)
5044 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
5045 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
5046 }
5047 }
5048
5049 if (uPass == SSM_PASS_FINAL)
5050 {
5051 /* Restore data. */
5052
5053 /* The main device structure. */
5054 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaCap);
5055 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaCtrl);
5056 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaIs);
5057 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaPi);
5058 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaVs);
5059 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaCccCtl);
5060 pHlp->pfnSSMGetU32(pSSM, &pThis->regHbaCccPorts);
5061 pHlp->pfnSSMGetU8(pSSM, &pThis->uCccPortNr);
5062 pHlp->pfnSSMGetU64(pSSM, &pThis->uCccTimeout);
5063 pHlp->pfnSSMGetU32(pSSM, &pThis->uCccNr);
5064 pHlp->pfnSSMGetU32(pSSM, &pThis->uCccCurrentNr);
5065
5066 pHlp->pfnSSMGetU32V(pSSM, &pThis->u32PortsInterrupted);
5067 pHlp->pfnSSMGetBool(pSSM, &pThis->fReset);
5068 pHlp->pfnSSMGetBool(pSSM, &pThis->f64BitAddr);
5069 bool fIgn;
5070 pHlp->pfnSSMGetBool(pSSM, &fIgn); /* Was fR0Enabled, which should never have been saved! */
5071 pHlp->pfnSSMGetBool(pSSM, &fIgn); /* Was fGCEnabled, which should never have been saved! */
5072 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
5073 pHlp->pfnSSMGetBool(pSSM, &pThis->fLegacyPortResetMethod);
5074
5075 /* Now every port. */
5076 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5077 {
5078 PAHCIPORT pAhciPort = &pThis->aPorts[i];
5079
5080 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regCLB);
5081 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regCLBU);
5082 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regFB);
5083 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regFBU);
5084 pHlp->pfnSSMGetGCPhysV(pSSM, &pThis->aPorts[i].GCPhysAddrClb);
5085 pHlp->pfnSSMGetGCPhysV(pSSM, &pThis->aPorts[i].GCPhysAddrFb);
5086 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].regIS);
5087 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regIE);
5088 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regCMD);
5089 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regTFD);
5090 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regSIG);
5091 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regSSTS);
5092 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regSCTL);
5093 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].regSERR);
5094 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].regSACT);
5095 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].regCI);
5096 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].PCHSGeometry.cCylinders);
5097 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].PCHSGeometry.cHeads);
5098 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].PCHSGeometry.cSectors);
5099 pHlp->pfnSSMGetU64(pSSM, &pThis->aPorts[i].cTotalSectors);
5100 pHlp->pfnSSMGetU32(pSSM, &pThis->aPorts[i].cMultSectors);
5101 pHlp->pfnSSMGetU8(pSSM, &pThis->aPorts[i].uATATransferMode);
5102 pHlp->pfnSSMGetBool(pSSM, &pThis->aPorts[i].fResetDevice);
5103
5104 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
5105 pHlp->pfnSSMSkip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
5106
5107 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
5108 {
5109 /* The old positions in the FIFO, not required. */
5110 pHlp->pfnSSMSkip(pSSM, 2*sizeof(uint8_t));
5111 }
5112 pHlp->pfnSSMGetBool(pSSM, &pThis->aPorts[i].fPoweredOn);
5113 pHlp->pfnSSMGetBool(pSSM, &pThis->aPorts[i].fSpunUp);
5114 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].u32TasksFinished);
5115 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].u32QueuedTasksFinished);
5116
5117 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
5118 pHlp->pfnSSMGetU32V(pSSM, &pThis->aPorts[i].u32CurrentCommandSlot);
5119
5120 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
5121 {
5122 pHlp->pfnSSMGetBool(pSSM, &pThis->aPorts[i].fATAPI);
5123 pHlp->pfnSSMGetMem(pSSM, pThis->aPorts[i].abATAPISense, sizeof(pThis->aPorts[i].abATAPISense));
5124 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_ATAPI_REMOVE)
5125 {
5126 pHlp->pfnSSMSkip(pSSM, 1); /* cNotifiedMediaChange. */
5127 pHlp->pfnSSMSkip(pSSM, 4); /* MediaEventStatus */
5128 }
5129 }
5130 else if (pThis->aPorts[i].fATAPI)
5131 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=false config=true"));
5132
5133 /* Check if we have tasks pending. */
5134 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
5135 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
5136
5137 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
5138
5139 if (pAhciPort->u32TasksNew)
5140 {
5141 /*
5142 * There are tasks pending. The VM was saved after a task failed
5143 * because of non-fatal error. Set the redo flag.
5144 */
5145 pAhciPort->fRedo = true;
5146 }
5147 }
5148
5149 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
5150 {
5151 for (uint32_t i = 0; i < 2; i++)
5152 {
5153 rc = ahciR3LoadLegacyEmulationState(pHlp, pSSM);
5154 if(RT_FAILURE(rc))
5155 return rc;
5156 }
5157 }
5158
5159 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
5160 if (RT_FAILURE(rc))
5161 return rc;
5162 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
5163 }
5164
5165 return VINF_SUCCESS;
5166}
5167
5168/* -=-=-=-=- device PDM interface -=-=-=-=- */
5169
5170/**
5171 * Configure the attached device for a port.
5172 *
5173 * Used by ahciR3Construct and ahciR3Attach.
5174 *
5175 * @returns VBox status code
5176 * @param pDevIns The device instance data.
5177 * @param pAhciPort The port for which the device is to be configured, shared bits.
5178 * @param pAhciPortR3 The port for which the device is to be configured, ring-3 bits.
5179 */
5180static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3)
5181{
5182 /* Query the media interface. */
5183 pAhciPortR3->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pAhciPortR3->pDrvBase, PDMIMEDIA);
5184 AssertMsgReturn(RT_VALID_PTR(pAhciPortR3->pDrvMedia),
5185 ("AHCI configuration error: LUN#%d misses the basic media interface!\n", pAhciPort->iLUN),
5186 VERR_PDM_MISSING_INTERFACE);
5187
5188 /* Get the extended media interface. */
5189 pAhciPortR3->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pAhciPortR3->pDrvBase, PDMIMEDIAEX);
5190 AssertMsgReturn(RT_VALID_PTR(pAhciPortR3->pDrvMediaEx),
5191 ("AHCI configuration error: LUN#%d misses the extended media interface!\n", pAhciPort->iLUN),
5192 VERR_PDM_MISSING_INTERFACE);
5193
5194 /*
5195 * Validate type.
5196 */
5197 PDMMEDIATYPE enmType = pAhciPortR3->pDrvMedia->pfnGetType(pAhciPortR3->pDrvMedia);
5198 AssertMsgReturn(enmType == PDMMEDIATYPE_HARD_DISK || enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD,
5199 ("AHCI configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%u\n", pAhciPort->iLUN, enmType),
5200 VERR_PDM_UNSUPPORTED_BLOCK_TYPE);
5201
5202 int rc = pAhciPortR3->pDrvMediaEx->pfnIoReqAllocSizeSet(pAhciPortR3->pDrvMediaEx, sizeof(AHCIREQ));
5203 if (RT_FAILURE(rc))
5204 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5205 N_("AHCI configuration error: LUN#%u: Failed to set I/O request size!"),
5206 pAhciPort->iLUN);
5207
5208 uint32_t fFeatures = 0;
5209 rc = pAhciPortR3->pDrvMediaEx->pfnQueryFeatures(pAhciPortR3->pDrvMediaEx, &fFeatures);
5210 if (RT_FAILURE(rc))
5211 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5212 N_("AHCI configuration error: LUN#%u: Failed to query features of device"),
5213 pAhciPort->iLUN);
5214
5215 if (fFeatures & PDMIMEDIAEX_FEATURE_F_DISCARD)
5216 pAhciPort->fTrimEnabled = true;
5217
5218 pAhciPort->fPresent = true;
5219
5220 pAhciPort->fATAPI = (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
5221 && RT_BOOL(fFeatures & PDMIMEDIAEX_FEATURE_F_RAWSCSICMD);
5222 if (pAhciPort->fATAPI)
5223 {
5224 pAhciPort->PCHSGeometry.cCylinders = 0;
5225 pAhciPort->PCHSGeometry.cHeads = 0;
5226 pAhciPort->PCHSGeometry.cSectors = 0;
5227 LogRel(("AHCI: LUN#%d: CD/DVD\n", pAhciPort->iLUN));
5228 }
5229 else
5230 {
5231 pAhciPort->cbSector = pAhciPortR3->pDrvMedia->pfnGetSectorSize(pAhciPortR3->pDrvMedia);
5232 pAhciPort->cTotalSectors = pAhciPortR3->pDrvMedia->pfnGetSize(pAhciPortR3->pDrvMedia) / pAhciPort->cbSector;
5233 rc = pAhciPortR3->pDrvMedia->pfnBiosGetPCHSGeometry(pAhciPortR3->pDrvMedia, &pAhciPort->PCHSGeometry);
5234 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
5235 {
5236 pAhciPort->PCHSGeometry.cCylinders = 0;
5237 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
5238 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
5239 }
5240 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
5241 {
5242 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
5243 rc = VINF_SUCCESS;
5244 }
5245 AssertRC(rc);
5246
5247 if ( pAhciPort->PCHSGeometry.cCylinders == 0
5248 || pAhciPort->PCHSGeometry.cHeads == 0
5249 || pAhciPort->PCHSGeometry.cSectors == 0)
5250 {
5251 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
5252 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
5253 pAhciPort->PCHSGeometry.cHeads = 16;
5254 pAhciPort->PCHSGeometry.cSectors = 63;
5255 /* Set the disk geometry information. Ignore errors. */
5256 pAhciPortR3->pDrvMedia->pfnBiosSetPCHSGeometry(pAhciPortR3->pDrvMedia, &pAhciPort->PCHSGeometry);
5257 rc = VINF_SUCCESS;
5258 }
5259 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
5260 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
5261 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
5262 pAhciPort->cTotalSectors));
5263 if (pAhciPort->fTrimEnabled)
5264 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
5265 }
5266 return rc;
5267}
5268
5269/**
5270 * Callback employed by ahciR3Suspend and ahciR3PowerOff.
5271 *
5272 * @returns true if we've quiesced, false if we're still working.
5273 * @param pDevIns The device instance.
5274 */
5275static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
5276{
5277 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5278 return false;
5279
5280 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5281 ASMAtomicWriteBool(&pThisCC->fSignalIdle, false);
5282 return true;
5283}
5284
5285/**
5286 * Common worker for ahciR3Suspend and ahciR3PowerOff.
5287 */
5288static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
5289{
5290 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5291
5292 ASMAtomicWriteBool(&pThisCC->fSignalIdle, true);
5293 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5294 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
5295 else
5296 ASMAtomicWriteBool(&pThisCC->fSignalIdle, false);
5297
5298 for (uint32_t i = 0; i < RT_ELEMENTS(pThisCC->aPorts); i++)
5299 {
5300 PAHCIPORTR3 pThisPort = &pThisCC->aPorts[i];
5301 if (pThisPort->pDrvMediaEx)
5302 pThisPort->pDrvMediaEx->pfnNotifySuspend(pThisPort->pDrvMediaEx);
5303 }
5304}
5305
5306/**
5307 * Suspend notification.
5308 *
5309 * @param pDevIns The device instance data.
5310 */
5311static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
5312{
5313 Log(("ahciR3Suspend\n"));
5314 ahciR3SuspendOrPowerOff(pDevIns);
5315}
5316
5317/**
5318 * Resume notification.
5319 *
5320 * @param pDevIns The device instance data.
5321 */
5322static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
5323{
5324 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5325
5326 /*
5327 * Check if one of the ports has pending tasks.
5328 * Queue a notification item again in this case.
5329 */
5330 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aPorts); i++)
5331 {
5332 PAHCIPORT pAhciPort = &pThis->aPorts[i];
5333
5334 if (pAhciPort->u32TasksRedo)
5335 {
5336 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
5337 pAhciPort->u32TasksRedo = 0;
5338
5339 Assert(pAhciPort->fRedo);
5340 pAhciPort->fRedo = false;
5341
5342 /* Notify the async IO thread. */
5343 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pAhciPort->hEvtProcess);
5344 AssertRC(rc);
5345 }
5346 }
5347
5348 Log(("%s:\n", __FUNCTION__));
5349}
5350
5351/**
5352 * Initializes the VPD data of a attached device.
5353 *
5354 * @returns VBox status code.
5355 * @param pDevIns The device instance.
5356 * @param pAhciPort The attached device, shared bits.
5357 * @param pAhciPortR3 The attached device, ring-3 bits.
5358 * @param pszName Name of the port to get the CFGM node.
5359 */
5360static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPORT pAhciPort, PAHCIPORTR3 pAhciPortR3, const char *pszName)
5361{
5362 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5363
5364 /* Generate a default serial number. */
5365 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
5366 RTUUID Uuid;
5367
5368 int rc = VINF_SUCCESS;
5369 if (pAhciPortR3->pDrvMedia)
5370 rc = pAhciPortR3->pDrvMedia->pfnGetUuid(pAhciPortR3->pDrvMedia, &Uuid);
5371 else
5372 RTUuidClear(&Uuid);
5373
5374 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
5375 {
5376 /* Generate a predictable serial for drives which don't have a UUID. */
5377 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d", pAhciPort->iLUN);
5378 }
5379 else
5380 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
5381
5382 /* Get user config if present using defaults otherwise. */
5383 PCFGMNODE pCfgNode = pHlp->pfnCFGMGetChild(pDevIns->pCfg, pszName);
5384 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber,
5385 sizeof(pAhciPort->szSerialNumber), szSerial);
5386 if (RT_FAILURE(rc))
5387 {
5388 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5389 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5390 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
5391 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
5392 }
5393
5394 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision,
5395 sizeof(pAhciPort->szFirmwareRevision), "1.0");
5396 if (RT_FAILURE(rc))
5397 {
5398 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5399 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5400 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
5401 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
5402 }
5403
5404 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
5405 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
5406 if (RT_FAILURE(rc))
5407 {
5408 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5409 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5410 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
5411 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
5412 }
5413
5414 rc = pHlp->pfnCFGMQueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
5415 if (RT_FAILURE(rc))
5416 return PDMDEV_SET_ERROR(pDevIns, rc,
5417 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
5418 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
5419 return PDMDEV_SET_ERROR(pDevIns, rc,
5420 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
5421
5422 /* There are three other identification strings for CD drives used for INQUIRY */
5423 if (pAhciPort->fATAPI)
5424 {
5425 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId,
5426 sizeof(pAhciPort->szInquiryVendorId), "VBOX");
5427 if (RT_FAILURE(rc))
5428 {
5429 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5430 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5431 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
5432 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
5433 }
5434
5435 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId,
5436 sizeof(pAhciPort->szInquiryProductId), "CD-ROM");
5437 if (RT_FAILURE(rc))
5438 {
5439 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5440 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5441 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
5442 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
5443 }
5444
5445 rc = pHlp->pfnCFGMQueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision,
5446 sizeof(pAhciPort->szInquiryRevision), "1.0");
5447 if (RT_FAILURE(rc))
5448 {
5449 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
5450 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
5451 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
5452 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
5453 }
5454 }
5455
5456 return rc;
5457}
5458
5459
5460/**
5461 * Detach notification.
5462 *
5463 * One harddisk at one port has been unplugged.
5464 * The VM is suspended at this point.
5465 *
5466 * @param pDevIns The device instance.
5467 * @param iLUN The logical unit which is being detached.
5468 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5469 */
5470static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5471{
5472 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5473 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5474 int rc = VINF_SUCCESS;
5475
5476 Log(("%s:\n", __FUNCTION__));
5477
5478 AssertMsgReturnVoid(iLUN < RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThisCC->aPorts)), ("iLUN=%u", iLUN));
5479 PAHCIPORT pAhciPort = &pThis->aPorts[iLUN];
5480 PAHCIPORTR3 pAhciPortR3 = &pThisCC->aPorts[iLUN];
5481 AssertMsgReturnVoid( pAhciPort->fHotpluggable
5482 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
5483 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
5484
5485
5486 if (pAhciPortR3->pAsyncIOThread)
5487 {
5488 int rcThread;
5489 /* Destroy the thread. */
5490 rc = PDMDevHlpThreadDestroy(pDevIns, pAhciPortR3->pAsyncIOThread, &rcThread);
5491 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
5492 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
5493
5494 pAhciPortR3->pAsyncIOThread = NULL;
5495 pAhciPort->fWrkThreadSleeping = true;
5496 }
5497
5498 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
5499 {
5500 /*
5501 * Inform the guest about the removed device.
5502 */
5503 pAhciPort->regSSTS = 0;
5504 pAhciPort->regSIG = 0;
5505 /*
5506 * Clear CR bit too to prevent submission of new commands when CI is written
5507 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
5508 */
5509 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
5510 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
5511 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
5512 if (pAhciPort->regIE & (AHCI_PORT_IE_CPDE | AHCI_PORT_IE_PCE | AHCI_PORT_IE_PRCE))
5513 ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
5514 }
5515
5516 /*
5517 * Zero some important members.
5518 */
5519 pAhciPortR3->pDrvBase = NULL;
5520 pAhciPortR3->pDrvMedia = NULL;
5521 pAhciPortR3->pDrvMediaEx = NULL;
5522 pAhciPort->fPresent = false;
5523}
5524
5525/**
5526 * Attach command.
5527 *
5528 * This is called when we change block driver for one port.
5529 * The VM is suspended at this point.
5530 *
5531 * @returns VBox status code.
5532 * @param pDevIns The device instance.
5533 * @param iLUN The logical unit which is being detached.
5534 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5535 */
5536static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5537{
5538 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5539 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5540 int rc;
5541
5542 Log(("%s:\n", __FUNCTION__));
5543
5544 /* the usual paranoia */
5545 AssertMsgReturn(iLUN < RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThisCC->aPorts)), ("iLUN=%u", iLUN), VERR_PDM_LUN_NOT_FOUND);
5546 PAHCIPORT pAhciPort = &pThis->aPorts[iLUN];
5547 PAHCIPORTR3 pAhciPortR3 = &pThisCC->aPorts[iLUN];
5548 AssertRelease(!pAhciPortR3->pDrvBase);
5549 AssertRelease(!pAhciPortR3->pDrvMedia);
5550 AssertRelease(!pAhciPortR3->pDrvMediaEx);
5551 Assert(pAhciPort->iLUN == iLUN);
5552 Assert(pAhciPortR3->iLUN == iLUN);
5553
5554 AssertMsgReturn( pAhciPort->fHotpluggable
5555 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
5556 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
5557 VERR_INVALID_PARAMETER);
5558
5559 /*
5560 * Try attach the block device and get the interfaces,
5561 * required as well as optional.
5562 */
5563 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPortR3->IBase, &pAhciPortR3->pDrvBase, pAhciPortR3->szDesc);
5564 if (RT_SUCCESS(rc))
5565 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort, pAhciPortR3);
5566 else
5567 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
5568
5569 if (RT_FAILURE(rc))
5570 {
5571 pAhciPortR3->pDrvBase = NULL;
5572 pAhciPortR3->pDrvMedia = NULL;
5573 pAhciPortR3->pDrvMediaEx = NULL;
5574 pAhciPort->fPresent = false;
5575 }
5576 else
5577 {
5578 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pAhciPort->hEvtProcess);
5579 if (RT_FAILURE(rc))
5580 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5581 N_("AHCI: Failed to create SUP event semaphore"));
5582
5583 /* Create the async IO thread. */
5584 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPortR3->pAsyncIOThread, pAhciPortR3, ahciAsyncIOLoop,
5585 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, pAhciPortR3->szDesc);
5586 if (RT_FAILURE(rc))
5587 return rc;
5588
5589 /*
5590 * Init vendor product data.
5591 */
5592 if (RT_SUCCESS(rc))
5593 rc = ahciR3VpdInit(pDevIns, pAhciPort, pAhciPortR3, pAhciPortR3->szDesc);
5594
5595 /* Inform the guest about the added device in case of hotplugging. */
5596 if ( RT_SUCCESS(rc)
5597 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
5598 {
5599 AssertMsgReturn(pAhciPort->fHotpluggable,
5600 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
5601 VERR_NOT_SUPPORTED);
5602
5603 /*
5604 * Initialize registers
5605 */
5606 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
5607 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
5608 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
5609
5610 if (pAhciPort->fATAPI)
5611 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
5612 else
5613 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
5614 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
5615 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
5616 (0x03 << 0); /* Device detected and communication established. */
5617
5618 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5619 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
5620 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
5621 ahciHbaSetInterrupt(pDevIns, pThis, pAhciPort->iLUN, VERR_IGNORED);
5622 }
5623
5624 }
5625
5626 return rc;
5627}
5628
5629/**
5630 * Common reset worker.
5631 *
5632 * @param pDevIns The device instance data.
5633 */
5634static int ahciR3ResetCommon(PPDMDEVINS pDevIns)
5635{
5636 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5637 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5638 ahciR3HBAReset(pDevIns, pThis, pThisCC);
5639
5640 /* Hardware reset for the ports. */
5641 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aPorts); i++)
5642 ahciPortHwReset(&pThis->aPorts[i]);
5643 return VINF_SUCCESS;
5644}
5645
5646/**
5647 * Callback employed by ahciR3Reset.
5648 *
5649 * @returns true if we've quiesced, false if we're still working.
5650 * @param pDevIns The device instance.
5651 */
5652static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
5653{
5654 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5655
5656 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5657 return false;
5658 ASMAtomicWriteBool(&pThisCC->fSignalIdle, false);
5659
5660 ahciR3ResetCommon(pDevIns);
5661 return true;
5662}
5663
5664/**
5665 * Reset notification.
5666 *
5667 * @param pDevIns The device instance data.
5668 */
5669static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
5670{
5671 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5672
5673 ASMAtomicWriteBool(&pThisCC->fSignalIdle, true);
5674 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5675 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
5676 else
5677 {
5678 ASMAtomicWriteBool(&pThisCC->fSignalIdle, false);
5679 ahciR3ResetCommon(pDevIns);
5680 }
5681}
5682
5683/**
5684 * Poweroff notification.
5685 *
5686 * @param pDevIns Pointer to the device instance
5687 */
5688static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
5689{
5690 Log(("achiR3PowerOff\n"));
5691 ahciR3SuspendOrPowerOff(pDevIns);
5692}
5693
5694/**
5695 * Destroy a driver instance.
5696 *
5697 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5698 * resources can be freed correctly.
5699 *
5700 * @param pDevIns The device instance data.
5701 */
5702static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
5703{
5704 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5705 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5706 int rc = VINF_SUCCESS;
5707
5708 /*
5709 * At this point the async I/O thread is suspended and will not enter
5710 * this module again. So, no coordination is needed here and PDM
5711 * will take care of terminating and cleaning up the thread.
5712 */
5713 if (PDMDevHlpCritSectIsInitialized(pDevIns, &pThis->lock))
5714 {
5715 PDMDevHlpTimerDestroy(pDevIns, pThis->hHbaCccTimer);
5716 pThis->hHbaCccTimer = NIL_TMTIMERHANDLE;
5717
5718 Log(("%s: Destruct every port\n", __FUNCTION__));
5719 uint32_t const cPortsImpl = RT_MIN(pThis->cPortsImpl, RT_ELEMENTS(pThis->aPorts));
5720 for (unsigned iActPort = 0; iActPort < cPortsImpl; iActPort++)
5721 {
5722 PAHCIPORT pAhciPort = &pThis->aPorts[iActPort];
5723
5724 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
5725 {
5726 PDMDevHlpSUPSemEventClose(pDevIns, pAhciPort->hEvtProcess);
5727 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
5728 }
5729 }
5730
5731 PDMDevHlpCritSectDelete(pDevIns, &pThis->lock);
5732 }
5733
5734 return rc;
5735}
5736
5737/**
5738 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5739 */
5740static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5741{
5742 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5743 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
5744 PAHCIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAHCICC);
5745 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5746 PPDMIBASE pBase;
5747 int rc;
5748 unsigned i;
5749 uint32_t cbTotalBufferSize = 0; /** @todo r=bird: cbTotalBufferSize isn't ever set. */
5750
5751 LogFlowFunc(("pThis=%#p\n", pThis));
5752 /*
5753 * Initialize the instance data (everything touched by the destructor need
5754 * to be initialized here!).
5755 */
5756 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
5757 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
5758
5759 PDMPciDevSetVendorId(pPciDev, 0x8086); /* Intel */
5760 PDMPciDevSetDeviceId(pPciDev, 0x2829); /* ICH-8M */
5761 PDMPciDevSetCommand(pPciDev, 0x0000);
5762#ifdef VBOX_WITH_MSI_DEVICES
5763 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
5764 PDMPciDevSetCapabilityList(pPciDev, 0x80);
5765#else
5766 PDMPciDevSetCapabilityList(pPciDev, 0x70);
5767#endif
5768 PDMPciDevSetRevisionId(pPciDev, 0x02);
5769 PDMPciDevSetClassProg(pPciDev, 0x01);
5770 PDMPciDevSetClassSub(pPciDev, 0x06);
5771 PDMPciDevSetClassBase(pPciDev, 0x01);
5772 PDMPciDevSetBaseAddress(pPciDev, 5, false, false, false, 0x00000000);
5773
5774 PDMPciDevSetInterruptLine(pPciDev, 0x00);
5775 PDMPciDevSetInterruptPin(pPciDev, 0x01);
5776
5777 PDMPciDevSetByte(pPciDev, 0x70, VBOX_PCI_CAP_ID_PM); /* Capability ID: PCI Power Management Interface */
5778 PDMPciDevSetByte(pPciDev, 0x71, 0xa8); /* next */
5779 PDMPciDevSetByte(pPciDev, 0x72, 0x03); /* version ? */
5780
5781 PDMPciDevSetByte(pPciDev, 0x90, 0x40); /* AHCI mode. */
5782 PDMPciDevSetByte(pPciDev, 0x92, 0x3f);
5783 PDMPciDevSetByte(pPciDev, 0x94, 0x80);
5784 PDMPciDevSetByte(pPciDev, 0x95, 0x01);
5785 PDMPciDevSetByte(pPciDev, 0x97, 0x78);
5786
5787 PDMPciDevSetByte(pPciDev, 0xa8, 0x12); /* SATACR capability */
5788 PDMPciDevSetByte(pPciDev, 0xa9, 0x00); /* next */
5789 PDMPciDevSetWord(pPciDev, 0xaa, 0x0010); /* Revision */
5790 PDMPciDevSetDWord(pPciDev, 0xac, 0x00000028); /* SATA Capability Register 1 */
5791
5792 pThis->cThreadsActive = 0;
5793
5794 pThisCC->pDevIns = pDevIns;
5795 pThisCC->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
5796 pThisCC->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
5797
5798 /* Initialize port members. */
5799 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5800 {
5801 PAHCIPORT pAhciPort = &pThis->aPorts[i];
5802 PAHCIPORTR3 pAhciPortR3 = &pThisCC->aPorts[i];
5803 pAhciPortR3->pDevIns = pDevIns;
5804 pAhciPort->iLUN = i;
5805 pAhciPortR3->iLUN = i;
5806 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
5807 pAhciPortR3->pDrvBase = NULL;
5808 pAhciPortR3->pAsyncIOThread = NULL;
5809 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
5810 pAhciPort->fHotpluggable = true;
5811 }
5812
5813 /*
5814 * Init locks, using explicit locking where necessary.
5815 */
5816 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5817 AssertRCReturn(rc, rc);
5818
5819 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
5820 if (RT_FAILURE(rc))
5821 {
5822 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
5823 return rc;
5824 }
5825
5826 /*
5827 * Validate and read configuration.
5828 */
5829 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
5830 "PrimaryMaster|PrimarySlave|SecondaryMaster"
5831 "|SecondarySlave|PortCount|Bootable|CmdSlotsAvail|TigerHack",
5832 "Port*");
5833
5834 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
5835 if (RT_FAILURE(rc))
5836 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read PortCount as integer"));
5837 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
5838 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
5839 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5840 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
5841 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
5842 if (pThis->cPortsImpl < 1)
5843 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5844 N_("AHCI configuration error: PortCount=%u should be at least 1"),
5845 pThis->cPortsImpl);
5846
5847 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
5848 if (RT_FAILURE(rc))
5849 return PDMDEV_SET_ERROR(pDevIns, rc,
5850 N_("AHCI configuration error: failed to read Bootable as boolean"));
5851
5852 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
5853 if (RT_FAILURE(rc))
5854 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
5855 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
5856 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
5857 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5858 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
5859 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
5860 if (pThis->cCmdSlotsAvail < 1)
5861 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
5862 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
5863 pThis->cCmdSlotsAvail);
5864 bool fTigerHack;
5865 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TigerHack", &fTigerHack, false);
5866 if (RT_FAILURE(rc))
5867 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read TigerHack as boolean"));
5868
5869
5870 /*
5871 * Register the PCI device, it's I/O regions.
5872 */
5873 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
5874 if (RT_FAILURE(rc))
5875 return rc;
5876
5877#ifdef VBOX_WITH_MSI_DEVICES
5878 PDMMSIREG MsiReg;
5879 RT_ZERO(MsiReg);
5880 MsiReg.cMsiVectors = 1;
5881 MsiReg.iMsiCapOffset = 0x80;
5882 MsiReg.iMsiNextOffset = 0x70;
5883 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
5884 if (RT_FAILURE(rc))
5885 {
5886 PCIDevSetCapabilityList(pPciDev, 0x70);
5887 /* That's OK, we can work without MSI */
5888 }
5889#endif
5890
5891 /*
5892 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..3)
5893 * for the legacy IDE registers are not available. We set up "fake" entries
5894 * in the PCI configuration register. That means they are available but
5895 * read and writes from/to them have no effect. No guest should access them
5896 * anyway because the controller is marked as AHCI in the Programming
5897 * interface and we don't have an option to change to IDE emulation (real
5898 * hardware provides an option in the BIOS to switch to it which also changes
5899 * device Id and other things in the PCI configuration space).
5900 */
5901 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, 8 /*cPorts*/,
5902 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/,
5903 "AHCI Fake #0", NULL /*paExtDescs*/, &pThis->hIoPortsLegacyFake0);
5904 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI I/O region")));
5905
5906 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 1 /*iPciRegion*/, 1 /*cPorts*/,
5907 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/,
5908 "AHCI Fake #1", NULL /*paExtDescs*/, &pThis->hIoPortsLegacyFake1);
5909 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI I/O region")));
5910
5911 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 2 /*iPciRegion*/, 8 /*cPorts*/,
5912 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/,
5913 "AHCI Fake #2", NULL /*paExtDescs*/, &pThis->hIoPortsLegacyFake2);
5914 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI I/O region")));
5915
5916 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 3 /*iPciRegion*/, 1 /*cPorts*/,
5917 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/,
5918 "AHCI Fake #3", NULL /*paExtDescs*/, &pThis->hIoPortsLegacyFake3);
5919 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI I/O region")));
5920
5921 /*
5922 * The non-fake PCI I/O regions:
5923 * Note! The 4352 byte MMIO region will be rounded up to PAGE_SIZE.
5924 */
5925 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 4 /*iPciRegion*/, 0x10 /*cPorts*/,
5926 ahciIdxDataWrite, ahciIdxDataRead, NULL /*pvUser*/,
5927 "AHCI IDX/DATA", NULL /*paExtDescs*/, &pThis->hIoPortIdxData);
5928 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI I/O region for BMDMA")));
5929
5930
5931 /** @todo change this to IOMMMIO_FLAGS_WRITE_ONLY_DWORD once EM/IOM starts
5932 * handling 2nd DWORD failures on split accesses correctly. */
5933 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 5 /*iPciRegion*/, 4352 /*cbRegion*/, PCI_ADDRESS_SPACE_MEM,
5934 ahciMMIOWrite, ahciMMIORead, NULL /*pvUser*/,
5935 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
5936 "AHCI", &pThis->hMmio);
5937 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot register PCI memory region for registers")));
5938
5939 /*
5940 * Create the timer for command completion coalescing feature.
5941 */
5942 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
5943 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, "AHCI CCC", &pThis->hHbaCccTimer);
5944 AssertRCReturn(rc, rc);
5945
5946 /*
5947 * Initialize ports.
5948 */
5949
5950 /* Initialize static members on every port. */
5951 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5952 ahciPortHwReset(&pThis->aPorts[i]);
5953
5954 /* Attach drivers to every available port. */
5955 for (i = 0; i < pThis->cPortsImpl; i++)
5956 {
5957 PAHCIPORT pAhciPort = &pThis->aPorts[i];
5958 PAHCIPORTR3 pAhciPortR3 = &pThisCC->aPorts[i];
5959
5960 RTStrPrintf(pAhciPortR3->szDesc, sizeof(pAhciPortR3->szDesc), "Port%u", i);
5961
5962 /*
5963 * Init interfaces.
5964 */
5965 pAhciPortR3->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
5966 pAhciPortR3->IMediaExPort.pfnIoReqCompleteNotify = ahciR3IoReqCompleteNotify;
5967 pAhciPortR3->IMediaExPort.pfnIoReqCopyFromBuf = ahciR3IoReqCopyFromBuf;
5968 pAhciPortR3->IMediaExPort.pfnIoReqCopyToBuf = ahciR3IoReqCopyToBuf;
5969 pAhciPortR3->IMediaExPort.pfnIoReqQueryBuf = ahciR3IoReqQueryBuf;
5970 pAhciPortR3->IMediaExPort.pfnIoReqQueryDiscardRanges = ahciR3IoReqQueryDiscardRanges;
5971 pAhciPortR3->IMediaExPort.pfnIoReqStateChanged = ahciR3IoReqStateChanged;
5972 pAhciPortR3->IMediaExPort.pfnMediumEjected = ahciR3MediumEjected;
5973 pAhciPortR3->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
5974 pAhciPortR3->IPort.pfnQueryScsiInqStrings = ahciR3PortQueryScsiInqStrings;
5975 pAhciPort->fWrkThreadSleeping = true;
5976
5977 /* Query per port configuration options if available. */
5978 PCFGMNODE pCfgPort = pHlp->pfnCFGMGetChild(pDevIns->pCfg, pAhciPortR3->szDesc);
5979 if (pCfgPort)
5980 {
5981 rc = pHlp->pfnCFGMQueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
5982 if (RT_FAILURE(rc))
5983 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
5984 }
5985
5986 /*
5987 * Attach the block driver
5988 */
5989 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPortR3->IBase, &pAhciPortR3->pDrvBase, pAhciPortR3->szDesc);
5990 if (RT_SUCCESS(rc))
5991 {
5992 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort, pAhciPortR3);
5993 if (RT_FAILURE(rc))
5994 {
5995 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, pAhciPortR3->szDesc));
5996 return rc;
5997 }
5998
5999 /* Mark that a device is present on that port */
6000 if (i < 6)
6001 pPciDev->abConfig[0x93] |= (1 << i);
6002
6003 /*
6004 * Init vendor product data.
6005 */
6006 rc = ahciR3VpdInit(pDevIns, pAhciPort, pAhciPortR3, pAhciPortR3->szDesc);
6007 if (RT_FAILURE(rc))
6008 return rc;
6009
6010 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pAhciPort->hEvtProcess);
6011 if (RT_FAILURE(rc))
6012 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6013 N_("AHCI: Failed to create SUP event semaphore"));
6014
6015 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPortR3->pAsyncIOThread, pAhciPortR3, ahciAsyncIOLoop,
6016 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, pAhciPortR3->szDesc);
6017 if (RT_FAILURE(rc))
6018 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6019 N_("AHCI: Failed to create worker thread %s"), pAhciPortR3->szDesc);
6020 }
6021 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
6022 {
6023 pAhciPortR3->pDrvBase = NULL;
6024 pAhciPort->fPresent = false;
6025 rc = VINF_SUCCESS;
6026 LogRel(("AHCI: %s: No driver attached\n", pAhciPortR3->szDesc));
6027 }
6028 else
6029 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6030 N_("AHCI: Failed to attach drive to %s"), pAhciPortR3->szDesc);
6031 }
6032
6033 /*
6034 * Attach status driver (optional).
6035 */
6036 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
6037 if (RT_SUCCESS(rc))
6038 {
6039 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
6040 pThisCC->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
6041 }
6042 else
6043 AssertMsgReturn(rc == VERR_PDM_NO_ATTACHED_DRIVER, ("Failed to attach to status driver. rc=%Rrc\n", rc),
6044 PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver")));
6045
6046 /*
6047 * Saved state.
6048 */
6049 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
6050 NULL, ahciR3LiveExec, NULL,
6051 ahciR3SavePrep, ahciR3SaveExec, NULL,
6052 ahciR3LoadPrep, ahciR3LoadExec, NULL);
6053 if (RT_FAILURE(rc))
6054 return rc;
6055
6056 /*
6057 * Register the info item.
6058 */
6059 char szTmp[128];
6060 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
6061 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
6062
6063 return ahciR3ResetCommon(pDevIns);
6064}
6065
6066#else /* !IN_RING3 */
6067
6068/**
6069 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
6070 */
6071static DECLCALLBACK(int) ahciRZConstruct(PPDMDEVINS pDevIns)
6072{
6073 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
6074 PAHCI pThis = PDMDEVINS_2_DATA(pDevIns, PAHCI);
6075
6076 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
6077 AssertRCReturn(rc, rc);
6078
6079 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsLegacyFake0, ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/);
6080 AssertRCReturn(rc, rc);
6081 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsLegacyFake1, ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/);
6082 AssertRCReturn(rc, rc);
6083 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsLegacyFake2, ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/);
6084 AssertRCReturn(rc, rc);
6085 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsLegacyFake3, ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL /*pvUser*/);
6086 AssertRCReturn(rc, rc);
6087
6088 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortIdxData, ahciIdxDataWrite, ahciIdxDataRead, NULL /*pvUser*/);
6089 AssertRCReturn(rc, rc);
6090
6091 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, ahciMMIOWrite, ahciMMIORead, NULL /*pvUser*/);
6092 AssertRCReturn(rc, rc);
6093
6094 return VINF_SUCCESS;
6095}
6096
6097#endif /* !IN_RING3 */
6098
6099/**
6100 * The device registration structure.
6101 */
6102const PDMDEVREG g_DeviceAHCI =
6103{
6104 /* .u32Version = */ PDM_DEVREG_VERSION,
6105 /* .uReserved0 = */ 0,
6106 /* .szName = */ "ahci",
6107 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
6108 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION
6109 | PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
6110 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
6111 /* .cMaxInstances = */ ~0U,
6112 /* .uSharedVersion = */ 42,
6113 /* .cbInstanceShared = */ sizeof(AHCI),
6114 /* .cbInstanceCC = */ sizeof(AHCICC),
6115 /* .cbInstanceRC = */ sizeof(AHCIRC),
6116 /* .cMaxPciDevices = */ 1,
6117 /* .cMaxMsixVectors = */ 0,
6118 /* .pszDescription = */ "Intel AHCI controller.\n",
6119#if defined(IN_RING3)
6120 /* .pszRCMod = */ "VBoxDDRC.rc",
6121 /* .pszR0Mod = */ "VBoxDDR0.r0",
6122 /* .pfnConstruct = */ ahciR3Construct,
6123 /* .pfnDestruct = */ ahciR3Destruct,
6124 /* .pfnRelocate = */ NULL,
6125 /* .pfnMemSetup = */ NULL,
6126 /* .pfnPowerOn = */ NULL,
6127 /* .pfnReset = */ ahciR3Reset,
6128 /* .pfnSuspend = */ ahciR3Suspend,
6129 /* .pfnResume = */ ahciR3Resume,
6130 /* .pfnAttach = */ ahciR3Attach,
6131 /* .pfnDetach = */ ahciR3Detach,
6132 /* .pfnQueryInterface = */ NULL,
6133 /* .pfnInitComplete = */ NULL,
6134 /* .pfnPowerOff = */ ahciR3PowerOff,
6135 /* .pfnSoftReset = */ NULL,
6136 /* .pfnReserved0 = */ NULL,
6137 /* .pfnReserved1 = */ NULL,
6138 /* .pfnReserved2 = */ NULL,
6139 /* .pfnReserved3 = */ NULL,
6140 /* .pfnReserved4 = */ NULL,
6141 /* .pfnReserved5 = */ NULL,
6142 /* .pfnReserved6 = */ NULL,
6143 /* .pfnReserved7 = */ NULL,
6144#elif defined(IN_RING0)
6145 /* .pfnEarlyConstruct = */ NULL,
6146 /* .pfnConstruct = */ ahciRZConstruct,
6147 /* .pfnDestruct = */ NULL,
6148 /* .pfnFinalDestruct = */ NULL,
6149 /* .pfnRequest = */ NULL,
6150 /* .pfnReserved0 = */ NULL,
6151 /* .pfnReserved1 = */ NULL,
6152 /* .pfnReserved2 = */ NULL,
6153 /* .pfnReserved3 = */ NULL,
6154 /* .pfnReserved4 = */ NULL,
6155 /* .pfnReserved5 = */ NULL,
6156 /* .pfnReserved6 = */ NULL,
6157 /* .pfnReserved7 = */ NULL,
6158#elif defined(IN_RC)
6159 /* .pfnConstruct = */ ahciRZConstruct,
6160 /* .pfnReserved0 = */ NULL,
6161 /* .pfnReserved1 = */ NULL,
6162 /* .pfnReserved2 = */ NULL,
6163 /* .pfnReserved3 = */ NULL,
6164 /* .pfnReserved4 = */ NULL,
6165 /* .pfnReserved5 = */ NULL,
6166 /* .pfnReserved6 = */ NULL,
6167 /* .pfnReserved7 = */ NULL,
6168#else
6169# error "Not in IN_RING3, IN_RING0 or IN_RC!"
6170#endif
6171 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
6172};
6173
6174#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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