VirtualBox

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

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

DevAHCI: Dropped unnecessary pragma pack(1). bugref:9218

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