VirtualBox

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

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

PDM,Devices: Changed PDM_DEVREG_FLAGS_MSI_X into a registration field giving the max MSI-X vector count config for the device (typically VBOX_MSIX_MAX_ENTRIES). bugref:9218

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