VirtualBox

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

Last change on this file since 81885 was 81885, checked in by vboxsync, 5 years ago

DevAHCI: Converted I/O ports and MMIO handlers to new style. bugref:9218

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

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