VirtualBox

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

Last change on this file since 64413 was 64408, checked in by vboxsync, 8 years ago

AHCI: Query the actual data transfer size and amount of residual data from the layer below to calculate the amount of transfered data properly

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

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