VirtualBox

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

Last change on this file since 86075 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

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