VirtualBox

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

Last change on this file since 99286 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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

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