VirtualBox

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

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

DevAHCI: s/pAhci/pThis/g. bugref:9218

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

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