VirtualBox

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

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

AHCI: Must duplicate the request structure when saving the request for GET LOG PAGE later because we don't manage the request memory anymore

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 319.2 KB
Line 
1/* $Id: DevAHCI.cpp 64020 2016-09-26 16:47:34Z vboxsync $ */
2/** @file
3 * DevAHCI - AHCI controller device (disk and cdrom).
4 *
5 * Implements the AHCI standard 1.1
6 */
7
8/*
9 * Copyright (C) 2006-2016 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
21 *
22 * This component implements an AHCI serial ATA controller. The device is split
23 * into two parts. The first part implements the register interface for the
24 * guest and the second one does the data transfer.
25 *
26 * The guest can access the controller in two ways. The first one is the native
27 * way implementing the registers described in the AHCI specification and is
28 * the preferred one. The second implements the I/O ports used for booting from
29 * the hard disk and for guests which don't have an AHCI SATA driver.
30 *
31 * The data is transfered using the extended media interface, asynchronously if
32 * it is supported by the driver below otherwise it weill be done synchronous.
33 * Either way a thread is used to process new requests from the guest.
34 */
35
36
37/*********************************************************************************************************************************
38* Header Files *
39*********************************************************************************************************************************/
40#define LOG_GROUP LOG_GROUP_DEV_AHCI
41#include <VBox/vmm/pdmdev.h>
42#include <VBox/vmm/pdmstorageifs.h>
43#include <VBox/vmm/pdmqueue.h>
44#include <VBox/vmm/pdmthread.h>
45#include <VBox/vmm/pdmcritsect.h>
46#include <VBox/sup.h>
47#include <VBox/scsi.h>
48#include <iprt/assert.h>
49#include <iprt/asm.h>
50#include <iprt/string.h>
51#include <iprt/list.h>
52#ifdef IN_RING3
53# include <iprt/param.h>
54# include <iprt/thread.h>
55# include <iprt/semaphore.h>
56# include <iprt/alloc.h>
57# include <iprt/uuid.h>
58# include <iprt/time.h>
59#endif
60#include "PIIX3ATABmDma.h"
61#include "ide.h"
62#include "ATAPIPassthrough.h"
63#include "VBoxDD.h"
64
65#if defined(VBOX_WITH_DTRACE) \
66 && defined(IN_RING3) \
67 && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
68# include "dtrace/VBoxDD.h"
69#else
70# define VBOXDD_AHCI_REQ_SUBMIT(a,b,c,d) do { } while (0)
71# define VBOXDD_AHCI_REQ_COMPLETED(a,b,c,d) do { } while (0)
72#endif
73
74/** Maximum number of ports available.
75 * Spec defines 32 but we have one allocated for command completion coalescing
76 * and another for a reserved future feature.
77 */
78#define AHCI_MAX_NR_PORTS_IMPL 30
79/** Maximum number of command slots available. */
80#define AHCI_NR_COMMAND_SLOTS 32
81
82#define AHCI_MAX_ALLOC_TOO_MUCH 20
83
84/** The current saved state version. */
85#define AHCI_SAVED_STATE_VERSION 8
86/** The saved state version before changing the port reset logic in an incompatible way. */
87#define AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES 7
88/** Saved state version before the per port hotplug port was added. */
89#define AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG 6
90/** Saved state version before legacy ATA emulation was dropped. */
91#define AHCI_SAVED_STATE_VERSION_IDE_EMULATION 5
92/** Saved state version before ATAPI support was added. */
93#define AHCI_SAVED_STATE_VERSION_PRE_ATAPI 3
94/** The saved state version use in VirtualBox 3.0 and earlier.
95 * This was before the config was added and ahciIOTasks was dropped. */
96#define AHCI_SAVED_STATE_VERSION_VBOX_30 2
97/* for Older ATA state Read handling */
98#define ATA_CTL_SAVED_STATE_VERSION 3
99#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
100#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
101
102/** The maximum number of release log entries per device. */
103#define MAX_LOG_REL_ERRORS 1024
104
105/**
106 * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
107 * Set to 1 to disable multi-sector read support. According to the ATA
108 * specification this must be a power of 2 and it must fit in an 8 bit
109 * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
110 */
111#define ATA_MAX_MULT_SECTORS 128
112
113/**
114 * Fastest PIO mode supported by the drive.
115 */
116#define ATA_PIO_MODE_MAX 4
117/**
118 * Fastest MDMA mode supported by the drive.
119 */
120#define ATA_MDMA_MODE_MAX 2
121/**
122 * Fastest UDMA mode supported by the drive.
123 */
124#define ATA_UDMA_MODE_MAX 6
125
126/**
127 * Length of the configurable VPD data (without termination)
128 */
129#define AHCI_SERIAL_NUMBER_LENGTH 20
130#define AHCI_FIRMWARE_REVISION_LENGTH 8
131#define AHCI_MODEL_NUMBER_LENGTH 40
132#define AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH 8
133#define AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH 16
134#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH 4
135
136/* MediaEventStatus */
137#define ATA_EVENT_STATUS_UNCHANGED 0 /**< medium event status not changed */
138#define ATA_EVENT_STATUS_MEDIA_NEW 1 /**< new medium inserted */
139#define ATA_EVENT_STATUS_MEDIA_REMOVED 2 /**< medium removed */
140#define ATA_EVENT_STATUS_MEDIA_CHANGED 3 /**< medium was removed + new medium was inserted */
141#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED 4 /**< medium eject requested (eject button pressed) */
142
143/* Media track type */
144#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
145
146/** ATAPI sense info size. */
147#define ATAPI_SENSE_SIZE 64
148
149/**
150 * Command Header.
151 */
152#pragma pack(1)
153typedef struct
154{
155 /** Description Information. */
156 uint32_t u32DescInf;
157 /** Command status. */
158 uint32_t u32PRDBC;
159 /** Command Table Base Address. */
160 uint32_t u32CmdTblAddr;
161 /** Command Table Base Address - upper 32-bits. */
162 uint32_t u32CmdTblAddrUp;
163 /** Reserved */
164 uint32_t u32Reserved[4];
165} CmdHdr;
166#pragma pack()
167AssertCompileSize(CmdHdr, 32);
168
169/* Defines for the command header. */
170#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
171#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
172#define AHCI_CMDHDR_C RT_BIT(10)
173#define AHCI_CMDHDR_B RT_BIT(9)
174#define AHCI_CMDHDR_R RT_BIT(8)
175#define AHCI_CMDHDR_P RT_BIT(7)
176#define AHCI_CMDHDR_W RT_BIT(6)
177#define AHCI_CMDHDR_A RT_BIT(5)
178#define AHCI_CMDHDR_CFL_MASK 0x1f
179
180#define AHCI_CMDHDR_PRDT_OFFSET 0x80
181#define AHCI_CMDHDR_ACMD_OFFSET 0x40
182
183/* Defines for the command FIS. */
184/* Defines that are used in the first double word. */
185#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
186# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
187# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
188# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
189# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
190# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
191# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
192# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
193# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
194# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
195# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
196# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
197# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
198# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
199
200#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
201#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
202#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
203#define AHCI_CMDFIS_D RT_BIT(5)
204
205#define AHCI_CMDFIS_CMD 2
206#define AHCI_CMDFIS_FET 3
207
208#define AHCI_CMDFIS_SECTN 4
209#define AHCI_CMDFIS_CYLL 5
210#define AHCI_CMDFIS_CYLH 6
211#define AHCI_CMDFIS_HEAD 7
212
213#define AHCI_CMDFIS_SECTNEXP 8
214#define AHCI_CMDFIS_CYLLEXP 9
215#define AHCI_CMDFIS_CYLHEXP 10
216#define AHCI_CMDFIS_FETEXP 11
217
218#define AHCI_CMDFIS_SECTC 12
219#define AHCI_CMDFIS_SECTCEXP 13
220#define AHCI_CMDFIS_CTL 15
221# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
222# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
223
224/* For D2H FIS */
225#define AHCI_CMDFIS_STS 2
226#define AHCI_CMDFIS_ERR 3
227
228/** Pointer to a task state. */
229typedef struct AHCIREQ *PAHCIREQ;
230
231/**
232 * Data processing callback
233 *
234 * @returns VBox status code.
235 * @param pAhciReq The task state.
236 * @param pSgBuf Buffer holding the data to process.
237 * @param cbBuf Size of the buffer.
238 * @param offBuf Offset into the guest buffer.
239 * @param ppvProc Where to store the pointer to the buffer holding the processed data on success.
240 * Must be freed with RTMemFree().
241 * @param pcbProc Where to store the size of the buffer on success.
242 */
243typedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, PRTSGBUF pSgBuf, size_t cbBuf,
244 uint32_t offBuf, void **ppvProc, size_t *pcbProc);
245/** Pointer to a FNAHCIPOSTPROCESS() function. */
246typedef FNAHCIPOSTPROCESS *PFNAHCIPOSTPROCESS;
247
248/** Task encountered a buffer overflow. */
249#define AHCI_REQ_OVERFLOW RT_BIT_32(0)
250/** Request is a PIO data command, if this flag is not set it either is
251 * a command which does not transfer data or a DMA command based on the transfer size. */
252#define AHCI_REQ_PIO_DATA RT_BIT_32(1)
253/** The request has the SACT register set. */
254#define AHCI_REQ_CLEAR_SACT RT_BIT_32(2)
255/** Flag whether the request is queued. */
256#define AHCI_REQ_IS_QUEUED RT_BIT_32(3)
257/** Flag whether the request is stored on the stack. */
258#define AHCI_REQ_IS_ON_STACK RT_BIT_32(4)
259
260/**
261 * A task state.
262 */
263typedef struct AHCIREQ
264{
265 /** The I/O request handle from the driver below associated with this request. */
266 PDMMEDIAEXIOREQ hIoReq;
267 /** Tag of the task. */
268 uint32_t uTag;
269 /** The command Fis for this task. */
270 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
271 /** The ATAPI command data. */
272 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
273 /** Size of one sector for the ATAPI transfer. */
274 uint32_t cbATAPISector;
275 /** Physical address of the command header. - GC */
276 RTGCPHYS GCPhysCmdHdrAddr;
277 /** Physical address of the PRDT */
278 RTGCPHYS GCPhysPrdtl;
279 /** Number of entries in the PRDTL. */
280 unsigned cPrdtlEntries;
281 /** Data direction. */
282 PDMMEDIAEXIOREQTYPE enmType;
283 /** Start offset. */
284 uint64_t uOffset;
285 /** Number of bytes to transfer. */
286 uint32_t cbTransfer;
287 /** Flags for this task. */
288 uint32_t fFlags;
289 /** Post processing callback.
290 * If this is set we will use a buffer for the data
291 * and the callback returns a buffer with the final data. */
292 PFNAHCIPOSTPROCESS pfnPostProcess;
293} AHCIREQ;
294
295/**
296 * Notifier queue item.
297 */
298typedef struct DEVPORTNOTIFIERQUEUEITEM
299{
300 /** The core part owned by the queue manager. */
301 PDMQUEUEITEMCORE Core;
302 /** The port to process. */
303 uint8_t iPort;
304} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
305
306
307/**
308 * @implements PDMIBASE
309 * @implements PDMIMEDIAPORT
310 * @implements PDMIMEDIAEXPORT
311 * @implements PDMIMOUNTNOTIFY
312 */
313typedef struct AHCIPort
314{
315 /** Pointer to the device instance - HC ptr */
316 PPDMDEVINSR3 pDevInsR3;
317 /** Pointer to the device instance - R0 ptr */
318 PPDMDEVINSR0 pDevInsR0;
319 /** Pointer to the device instance - RC ptr. */
320 PPDMDEVINSRC pDevInsRC;
321
322#if HC_ARCH_BITS == 64
323 uint32_t Alignment0;
324#endif
325
326 /** Pointer to the parent AHCI structure - R3 ptr. */
327 R3PTRTYPE(struct AHCI *) pAhciR3;
328 /** Pointer to the parent AHCI structure - R0 ptr. */
329 R0PTRTYPE(struct AHCI *) pAhciR0;
330 /** Pointer to the parent AHCI structure - RC ptr. */
331 RCPTRTYPE(struct AHCI *) pAhciRC;
332
333 /** Command List Base Address. */
334 uint32_t regCLB;
335 /** Command List Base Address upper bits. */
336 uint32_t regCLBU;
337 /** FIS Base Address. */
338 uint32_t regFB;
339 /** FIS Base Address upper bits. */
340 uint32_t regFBU;
341 /** Interrupt Status. */
342 volatile uint32_t regIS;
343 /** Interrupt Enable. */
344 uint32_t regIE;
345 /** Command. */
346 uint32_t regCMD;
347 /** Task File Data. */
348 uint32_t regTFD;
349 /** Signature */
350 uint32_t regSIG;
351 /** Serial ATA Status. */
352 uint32_t regSSTS;
353 /** Serial ATA Control. */
354 uint32_t regSCTL;
355 /** Serial ATA Error. */
356 uint32_t regSERR;
357 /** Serial ATA Active. */
358 volatile uint32_t regSACT;
359 /** Command Issue. */
360 uint32_t regCI;
361
362 /** Current number of active tasks. */
363 volatile uint32_t cTasksActive;
364 /** Command List Base Address */
365 volatile RTGCPHYS GCPhysAddrClb;
366 /** FIS Base Address */
367 volatile RTGCPHYS GCPhysAddrFb;
368
369 /** Device is powered on. */
370 bool fPoweredOn;
371 /** Device has spun up. */
372 bool fSpunUp;
373 /** First D2H FIS was send. */
374 bool fFirstD2HFisSend;
375 /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
376 bool fNonRotational;
377 /** Attached device is a CD/DVD drive. */
378 bool fATAPI;
379 /** Passthrough SCSI commands. */
380 bool fATAPIPassthrough;
381 /** Flag whether this port is in a reset state. */
382 volatile bool fPortReset;
383 /** Flag whether TRIM is supported. */
384 bool fTrimEnabled;
385 /** Flag if we are in a device reset. */
386 bool fResetDevice;
387 /** Flag whether this port is hot plug capable. */
388 bool fHotpluggable;
389 /** Flag whether the port is in redo task mode. */
390 volatile bool fRedo;
391 /** Flag whether the worker thread is sleeping. */
392 volatile bool fWrkThreadSleeping;
393
394 bool afAlignment[3];
395
396 /** Number of total sectors. */
397 uint64_t cTotalSectors;
398 /** Size of one sector. */
399 uint32_t cbSector;
400 /** Currently configured number of sectors in a multi-sector transfer. */
401 uint32_t cMultSectors;
402 /** Currently active transfer mode (MDMA/UDMA) and speed. */
403 uint8_t uATATransferMode;
404 /** ATAPI sense data. */
405 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
406 /** HACK: Countdown till we report a newly unmounted drive as mounted. */
407 uint8_t cNotifiedMediaChange;
408 /** Exponent of logical sectors in a physical sector, number of logical sectors is 2^exp. */
409 uint8_t cLogSectorsPerPhysicalExp;
410 /** The same for GET_EVENT_STATUS for mechanism */
411 volatile uint32_t MediaEventStatus;
412 /** Media type if known. */
413 volatile uint32_t MediaTrackType;
414 /** The LUN. */
415 RTUINT iLUN;
416
417 /** Bitmap for finished tasks (R3 -> Guest). */
418 volatile uint32_t u32TasksFinished;
419 /** Bitmap for finished queued tasks (R3 -> Guest). */
420 volatile uint32_t u32QueuedTasksFinished;
421 /** Bitmap for new queued tasks (Guest -> R3). */
422 volatile uint32_t u32TasksNew;
423 /** Bitmap of tasks which must be redone because of a non fatal error. */
424 volatile uint32_t u32TasksRedo;
425
426 /** Current command slot processed.
427 * Accessed by the guest by reading the CMD register.
428 * Holds the command slot of the command processed at the moment. */
429 volatile uint32_t u32CurrentCommandSlot;
430
431#if HC_ARCH_BITS == 64
432 uint32_t u32Alignment2;
433#endif
434
435 /** Device specific settings (R3 only stuff). */
436 /** Pointer to the attached driver's base interface. */
437 R3PTRTYPE(PPDMIBASE) pDrvBase;
438 /** Pointer to the attached driver's block interface. */
439 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
440 /** Pointer to the attached driver's extended interface. */
441 R3PTRTYPE(PPDMIMEDIAEX) pDrvMediaEx;
442 /** Pointer to the attached driver's mount interface. */
443 R3PTRTYPE(PPDMIMOUNT) pDrvMount;
444 /** The base interface. */
445 PDMIBASE IBase;
446 /** The block port interface. */
447 PDMIMEDIAPORT IPort;
448 /** The extended media port interface. */
449 PDMIMEDIAEXPORT IMediaExPort;
450 /** The mount notify interface. */
451 PDMIMOUNTNOTIFY IMountNotify;
452 /** Physical geometry of this image. */
453 PDMMEDIAGEOMETRY PCHSGeometry;
454 /** The status LED state for this drive. */
455 PDMLED Led;
456
457#if HC_ARCH_BITS == 64
458 uint32_t u32Alignment3;
459#endif
460
461 /** Async IO Thread. */
462 R3PTRTYPE(PPDMTHREAD) pAsyncIOThread;
463 /** First task throwing an error. */
464 R3PTRTYPE(volatile PAHCIREQ) pTaskErr;
465 /** The current tracklist of the loaded medium if passthrough is used. */
466 R3PTRTYPE(PTRACKLIST) pTrackList;
467
468 /** The event semaphore the processing thread waits on. */
469 SUPSEMEVENT hEvtProcess;
470
471 /** Release statistics: number of DMA commands. */
472 STAMCOUNTER StatDMA;
473 /** Release statistics: number of bytes written. */
474 STAMCOUNTER StatBytesWritten;
475 /** Release statistics: number of bytes read. */
476 STAMCOUNTER StatBytesRead;
477 /** Release statistics: Number of I/O requests processed per second. */
478 STAMCOUNTER StatIORequestsPerSecond;
479#ifdef VBOX_WITH_STATISTICS
480 /** Statistics: Time to complete one request. */
481 STAMPROFILE StatProfileProcessTime;
482 /** Statistics: Amount of time to read/write data. */
483 STAMPROFILE StatProfileReadWrite;
484#endif /* VBOX_WITH_STATISTICS */
485
486 /** The serial numnber to use for IDENTIFY DEVICE commands. */
487 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
488 /** The firmware revision to use for IDENTIFY DEVICE commands. */
489 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
490 /** The model number to use for IDENTIFY DEVICE commands. */
491 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
492 /** The vendor identification string for SCSI INQUIRY commands. */
493 char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
494 /** The product identification string for SCSI INQUIRY commands. */
495 char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
496 /** The revision string for SCSI INQUIRY commands. */
497 char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
498 /** Error counter */
499 uint32_t cErrors;
500
501 uint32_t u32Alignment5;
502
503} AHCIPort;
504/** Pointer to the state of an AHCI port. */
505typedef AHCIPort *PAHCIPort;
506
507AssertCompileMemberAlignment(AHCIPort, StatDMA, 8);
508AssertCompileSizeAlignment(AHCIPort, 8);
509
510/**
511 * Main AHCI device state.
512 *
513 * @implements PDMILEDPORTS
514 */
515typedef struct AHCI
516{
517 /** The PCI device structure. */
518 PCIDEVICE dev;
519 /** Pointer to the device instance - R3 ptr */
520 PPDMDEVINSR3 pDevInsR3;
521 /** Pointer to the device instance - R0 ptr */
522 PPDMDEVINSR0 pDevInsR0;
523 /** Pointer to the device instance - RC ptr. */
524 PPDMDEVINSRC pDevInsRC;
525
526#if HC_ARCH_BITS == 64
527 uint32_t Alignment0;
528#endif
529
530 /** Status LUN: The base interface. */
531 PDMIBASE IBase;
532 /** Status LUN: Leds interface. */
533 PDMILEDPORTS ILeds;
534 /** Status LUN: Partner of ILeds. */
535 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
536 /** Status LUN: Media Notifys. */
537 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
538
539#if HC_ARCH_BITS == 32
540 uint32_t Alignment1;
541#endif
542
543 /** Base address of the MMIO region. */
544 RTGCPHYS MMIOBase;
545 /** Base address of the I/O port region for Idx/Data. */
546 RTIOPORT IOPortBase;
547
548 /** Global Host Control register of the HBA */
549
550 /** HBA Capabilities - Readonly */
551 uint32_t regHbaCap;
552 /** HBA Control */
553 uint32_t regHbaCtrl;
554 /** Interrupt Status */
555 uint32_t regHbaIs;
556 /** Ports Implemented - Readonly */
557 uint32_t regHbaPi;
558 /** AHCI Version - Readonly */
559 uint32_t regHbaVs;
560 /** Command completion coalescing control */
561 uint32_t regHbaCccCtl;
562 /** Command completion coalescing ports */
563 uint32_t regHbaCccPorts;
564
565 /** Index register for BIOS access. */
566 uint32_t regIdx;
567
568#if HC_ARCH_BITS == 64
569 uint32_t Alignment3;
570#endif
571
572 /** Countdown timer for command completion coalescing - R3 ptr */
573 PTMTIMERR3 pHbaCccTimerR3;
574 /** Countdown timer for command completion coalescing - R0 ptr */
575 PTMTIMERR0 pHbaCccTimerR0;
576 /** Countdown timer for command completion coalescing - RC ptr */
577 PTMTIMERRC pHbaCccTimerRC;
578
579#if HC_ARCH_BITS == 64
580 uint32_t Alignment4;
581#endif
582
583 /** Queue to send tasks to R3. - HC ptr */
584 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
585 /** Queue to send tasks to R3. - HC ptr */
586 R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
587 /** Queue to send tasks to R3. - RC ptr */
588 RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
589
590#if HC_ARCH_BITS == 64
591 uint32_t Alignment5;
592#endif
593
594
595 /** Which port number is used to mark an CCC interrupt */
596 uint8_t uCccPortNr;
597
598#if HC_ARCH_BITS == 64
599 uint32_t Alignment6;
600#endif
601
602 /** Timeout value */
603 uint64_t uCccTimeout;
604 /** Number of completions used to assert an interrupt */
605 uint32_t uCccNr;
606 /** Current number of completed commands */
607 uint32_t uCccCurrentNr;
608
609 /** Register structure per port */
610 AHCIPort ahciPort[AHCI_MAX_NR_PORTS_IMPL];
611
612 /** The critical section. */
613 PDMCRITSECT lock;
614
615 /** Bitmask of ports which asserted an interrupt. */
616 volatile uint32_t u32PortsInterrupted;
617 /** Number of I/O threads currently active - used for async controller reset handling. */
618 volatile uint32_t cThreadsActive;
619 /** Device is in a reset state. */
620 bool fReset;
621 /** Supports 64bit addressing */
622 bool f64BitAddr;
623 /** GC enabled. */
624 bool fGCEnabled;
625 /** R0 enabled. */
626 bool fR0Enabled;
627 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
628 * a port is entering the idle state. */
629 bool volatile fSignalIdle;
630 /** Flag whether the controller has BIOS access enabled. */
631 bool fBootable;
632 /** Flag whether the legacy port reset method should be used to make it work with saved states. */
633 bool fLegacyPortResetMethod;
634
635 /** Number of usable ports on this controller. */
636 uint32_t cPortsImpl;
637 /** Number of usable command slots for each port. */
638 uint32_t cCmdSlotsAvail;
639
640 /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
641 volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
642
643#if HC_ARCH_BITS == 64
644 uint32_t Alignment7;
645#endif
646
647 /** The support driver session handle. */
648 R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession;
649} AHCI;
650/** Pointer to the state of an AHCI device. */
651typedef AHCI *PAHCI;
652
653AssertCompileMemberAlignment(AHCI, ahciPort, 8);
654
655/**
656 * Scatter gather list entry.
657 */
658typedef struct
659{
660 /** Data Base Address. */
661 uint32_t u32DBA;
662 /** Data Base Address - Upper 32-bits. */
663 uint32_t u32DBAUp;
664 /** Reserved */
665 uint32_t u32Reserved;
666 /** Description information. */
667 uint32_t u32DescInf;
668} SGLEntry;
669AssertCompileSize(SGLEntry, 16);
670
671#ifdef IN_RING3
672/**
673 * Memory buffer callback.
674 *
675 * @returns nothing.
676 * @param pThis The NVME controller instance.
677 * @param GCPhys The guest physical address of the memory buffer.
678 * @param pSgBuf The pointer to the host R3 S/G buffer.
679 * @param cbCopy How many bytes to copy between the two buffers.
680 * @param pcbSkip Initially contains the amount of bytes to skip
681 * starting from the guest physical address before
682 * accessing the S/G buffer and start copying data.
683 * On return this contains the remaining amount if
684 * cbCopy < *pcbSkip or 0 otherwise.
685 */
686typedef DECLCALLBACK(void) AHCIR3MEMCOPYCALLBACK(PAHCI pThis, RTGCPHYS GCPhys, PRTSGBUF pSgBuf, size_t cbCopy,
687 size_t *pcbSkip);
688/** Pointer to a memory copy buffer callback. */
689typedef AHCIR3MEMCOPYCALLBACK *PAHCIR3MEMCOPYCALLBACK;
690#endif
691
692/** Defines for a scatter gather list entry. */
693#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
694#define SGLENTRY_DESCINF_I RT_BIT(31)
695#define SGLENTRY_DESCINF_DBC 0x3fffff
696#define SGLENTRY_DESCINF_READONLY 0x803fffff
697
698/* Defines for the global host control registers for the HBA. */
699
700#define AHCI_HBA_GLOBAL_SIZE 0x100
701
702/* Defines for the HBA Capabilities - Readonly */
703#define AHCI_HBA_CAP_S64A RT_BIT(31)
704#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
705#define AHCI_HBA_CAP_SIS RT_BIT(28)
706#define AHCI_HBA_CAP_SSS RT_BIT(27)
707#define AHCI_HBA_CAP_SALP RT_BIT(26)
708#define AHCI_HBA_CAP_SAL RT_BIT(25)
709#define AHCI_HBA_CAP_SCLO RT_BIT(24)
710#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
711# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
712# define AHCI_HBA_CAP_ISS_GEN1 RT_BIT(0)
713# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
714#define AHCI_HBA_CAP_SNZO RT_BIT(19)
715#define AHCI_HBA_CAP_SAM RT_BIT(18)
716#define AHCI_HBA_CAP_SPM RT_BIT(17)
717#define AHCI_HBA_CAP_PMD RT_BIT(15)
718#define AHCI_HBA_CAP_SSC RT_BIT(14)
719#define AHCI_HBA_CAP_PSC RT_BIT(13)
720#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
721#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
722#define AHCI_HBA_CAP_CCCS RT_BIT(7)
723#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
724#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
725
726/* Defines for the HBA Control register - Read/Write */
727#define AHCI_HBA_CTRL_AE RT_BIT(31)
728#define AHCI_HBA_CTRL_IE RT_BIT(1)
729#define AHCI_HBA_CTRL_HR RT_BIT(0)
730#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
731
732/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
733#define AHCI_HBA_VS_MJR (1 << 16)
734#define AHCI_HBA_VS_MNR 0x100
735
736/* Defines for the command completion coalescing control register */
737#define AHCI_HBA_CCC_CTL_TV 0xffff0000
738#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
739#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
740
741#define AHCI_HBA_CCC_CTL_CC 0xff00
742#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
743#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
744
745#define AHCI_HBA_CCC_CTL_INT 0xf8
746#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
747#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
748
749#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
750
751/* Defines for the port registers. */
752
753#define AHCI_PORT_REGISTER_SIZE 0x80
754
755#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
756
757#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
758
759#define AHCI_PORT_IS_CPDS RT_BIT(31)
760#define AHCI_PORT_IS_TFES RT_BIT(30)
761#define AHCI_PORT_IS_HBFS RT_BIT(29)
762#define AHCI_PORT_IS_HBDS RT_BIT(28)
763#define AHCI_PORT_IS_IFS RT_BIT(27)
764#define AHCI_PORT_IS_INFS RT_BIT(26)
765#define AHCI_PORT_IS_OFS RT_BIT(24)
766#define AHCI_PORT_IS_IPMS RT_BIT(23)
767#define AHCI_PORT_IS_PRCS RT_BIT(22)
768#define AHCI_PORT_IS_DIS RT_BIT(7)
769#define AHCI_PORT_IS_PCS RT_BIT(6)
770#define AHCI_PORT_IS_DPS RT_BIT(5)
771#define AHCI_PORT_IS_UFS RT_BIT(4)
772#define AHCI_PORT_IS_SDBS RT_BIT(3)
773#define AHCI_PORT_IS_DSS RT_BIT(2)
774#define AHCI_PORT_IS_PSS RT_BIT(1)
775#define AHCI_PORT_IS_DHRS RT_BIT(0)
776#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
777
778#define AHCI_PORT_IE_CPDE RT_BIT(31)
779#define AHCI_PORT_IE_TFEE RT_BIT(30)
780#define AHCI_PORT_IE_HBFE RT_BIT(29)
781#define AHCI_PORT_IE_HBDE RT_BIT(28)
782#define AHCI_PORT_IE_IFE RT_BIT(27)
783#define AHCI_PORT_IE_INFE RT_BIT(26)
784#define AHCI_PORT_IE_OFE RT_BIT(24)
785#define AHCI_PORT_IE_IPME RT_BIT(23)
786#define AHCI_PORT_IE_PRCE RT_BIT(22)
787#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
788#define AHCI_PORT_IE_PCE RT_BIT(6)
789#define AHCI_PORT_IE_DPE RT_BIT(5)
790#define AHCI_PORT_IE_UFE RT_BIT(4)
791#define AHCI_PORT_IE_SDBE RT_BIT(3)
792#define AHCI_PORT_IE_DSE RT_BIT(2)
793#define AHCI_PORT_IE_PSE RT_BIT(1)
794#define AHCI_PORT_IE_DHRE RT_BIT(0)
795#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
796
797#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
798#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
799# define AHCI_PORT_CMD_ICC_IDLE 0x0
800# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
801# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
802# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
803#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
804#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
805#define AHCI_PORT_CMD_DLAE RT_BIT(25)
806#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
807#define AHCI_PORT_CMD_CPD RT_BIT(20)
808#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
809#define AHCI_PORT_CMD_HPCP RT_BIT(18)
810#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
811#define AHCI_PORT_CMD_CPS RT_BIT(16)
812#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
813#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
814#define AHCI_PORT_CMD_ISS RT_BIT(13) /* Readonly */
815#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
816#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
817#define AHCI_PORT_CMD_FRE RT_BIT(4)
818#define AHCI_PORT_CMD_CLO RT_BIT(3)
819#define AHCI_PORT_CMD_POD RT_BIT(2)
820#define AHCI_PORT_CMD_SUD RT_BIT(1)
821#define AHCI_PORT_CMD_ST RT_BIT(0)
822#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
823
824#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
825#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
826#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
827#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
828#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
829#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
830#define AHCI_PORT_SCTL_DET_NINIT 0
831#define AHCI_PORT_SCTL_DET_INIT 1
832#define AHCI_PORT_SCTL_DET_OFFLINE 4
833#define AHCI_PORT_SCTL_READONLY 0xfff
834
835#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
836#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
837#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
838#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
839#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
840#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
841
842#define AHCI_PORT_TFD_BSY RT_BIT(7)
843#define AHCI_PORT_TFD_DRQ RT_BIT(3)
844#define AHCI_PORT_TFD_ERR RT_BIT(0)
845
846#define AHCI_PORT_SERR_X RT_BIT(26)
847#define AHCI_PORT_SERR_W RT_BIT(18)
848#define AHCI_PORT_SERR_N RT_BIT(16)
849
850/* Signatures for attached storage devices. */
851#define AHCI_PORT_SIG_DISK 0x00000101
852#define AHCI_PORT_SIG_ATAPI 0xeb140101
853
854/*
855 * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
856 * regFB points to the base of this area.
857 * Every FIS type has an offset where it is posted in this area.
858 */
859#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
860#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
861#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
862#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
863#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
864
865/** Mask to get the LBA value from a LBA range. */
866#define AHCI_RANGE_LBA_MASK UINT64_C(0xffffffffffff)
867/** Mas to get the length value from a LBA range. */
868#define AHCI_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
869/** Returns the length of the range in sectors. */
870#define AHCI_RANGE_LENGTH_GET(val) (((val) & AHCI_RANGE_LENGTH_MASK) >> 48)
871
872/**
873 * AHCI register operator.
874 */
875typedef struct ahci_opreg
876{
877 const char *pszName;
878 int (*pfnRead )(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value);
879 int (*pfnWrite)(PAHCI pAhci, uint32_t iReg, uint32_t u32Value);
880} AHCIOPREG;
881
882/**
883 * AHCI port register operator.
884 */
885typedef struct pAhciPort_opreg
886{
887 const char *pszName;
888 int (*pfnRead )(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
889 int (*pfnWrite)(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
890} AHCIPORTOPREG;
891
892#ifndef VBOX_DEVICE_STRUCT_TESTCASE
893RT_C_DECLS_BEGIN
894#ifdef IN_RING3
895static void ahciHBAReset(PAHCI pThis);
896static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
897static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
898static size_t ahciR3CopyBufferToPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, const void *pvSrc,
899 size_t cbSrc, size_t cbSkip);
900static size_t ahciR3CopyBufferFromPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, void *pvDst, size_t cbDst);
901static bool ahciCancelActiveTasks(PAHCIPort pAhciPort);
902#endif
903RT_C_DECLS_END
904
905#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
906#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
907#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
908#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
909#define PDMIMEDIAPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
910#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
911#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
912
913#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
914
915#ifdef IN_RING3
916
917# ifdef LOG_USE_C99
918# define ahciLog(a) \
919 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
920# else
921# define ahciLog(a) \
922 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
923# endif
924
925#elif defined(IN_RING0)
926
927# ifdef LOG_USE_C99
928# define ahciLog(a) \
929 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
930# else
931# define ahciLog(a) \
932 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
933# endif
934
935#elif defined(IN_RC)
936
937# ifdef LOG_USE_C99
938# define ahciLog(a) \
939 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
940# else
941# define ahciLog(a) \
942 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
943# endif
944
945#endif
946
947/**
948 * Update PCI IRQ levels
949 */
950static void ahciHbaClearInterrupt(PAHCI pAhci)
951{
952 Log(("%s: Clearing interrupt\n", __FUNCTION__));
953 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
954}
955
956/**
957 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
958 */
959static int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
960{
961 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
962
963 int rc = PDMCritSectEnter(&pAhci->lock, rcBusy);
964 if (rc != VINF_SUCCESS)
965 return rc;
966
967 if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
968 {
969 if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
970 {
971 pAhci->uCccCurrentNr++;
972 if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
973 {
974 /* Reset command completion coalescing state. */
975 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
976 pAhci->uCccCurrentNr = 0;
977
978 pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
979 if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
980 {
981 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
982 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
983 }
984 }
985 }
986 else
987 {
988 /* If only the bit of the actual port is set assert an interrupt
989 * because the interrupt status register was already read by the guest
990 * and we need to send a new notification.
991 * Otherwise an interrupt is still pending.
992 */
993 ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
994 if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
995 {
996 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
997 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
998 }
999 }
1000 }
1001
1002 PDMCritSectLeave(&pAhci->lock);
1003 return VINF_SUCCESS;
1004}
1005
1006#ifdef IN_RING3
1007
1008/*
1009 * Assert irq when an CCC timeout occurs
1010 */
1011static DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1012{
1013 RT_NOREF(pDevIns, pTimer);
1014 PAHCI pAhci = (PAHCI)pvUser;
1015
1016 int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
1017 AssertRC(rc);
1018}
1019
1020/**
1021 * Finishes the port reset of the given port.
1022 *
1023 * @returns nothing.
1024 * @param pAhciPort The port to finish the reset on.
1025 */
1026static void ahciPortResetFinish(PAHCIPort pAhciPort)
1027{
1028 /* Cancel all tasks first. */
1029 bool fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort);
1030 Assert(fAllTasksCanceled); NOREF(fAllTasksCanceled);
1031
1032 /* Signature for SATA device. */
1033 if (pAhciPort->fATAPI)
1034 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1035 else
1036 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1037
1038 /* We received a COMINIT from the device. Tell the guest. */
1039 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
1040 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1041 pAhciPort->regTFD |= ATA_STAT_BUSY;
1042
1043 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
1044 {
1045 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1046 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1047
1048 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1049 {
1050 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1051 AssertRC(rc);
1052 }
1053 }
1054
1055 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1056 (0x03 << 0); /* Device detected and communication established. */
1057
1058 /*
1059 * Use the maximum allowed speed.
1060 * (Not that it changes anything really)
1061 */
1062 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1063 {
1064 case 0x01:
1065 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1066 break;
1067 case 0x02:
1068 case 0x00:
1069 default:
1070 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1071 break;
1072 }
1073
1074 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1075}
1076
1077#endif /* IN_RING3 */
1078
1079/**
1080 * Kicks the I/O thread from RC or R0.
1081 *
1082 * @returns nothing.
1083 * @param pAhci The AHCI controller instance.
1084 * @param pAhciPort The port to kick.
1085 */
1086static void ahciIoThreadKick(PAHCI pAhci, PAHCIPort pAhciPort)
1087{
1088#ifdef IN_RC
1089 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
1090 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1091
1092 if (pItem)
1093 {
1094 pItem->iPort = pAhciPort->iLUN;
1095 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1096 }
1097#else
1098 LogFlowFunc(("Signal event semaphore\n"));
1099 int rc = SUPSemEventSignal(pAhci->pSupDrvSession, pAhciPort->hEvtProcess);
1100 AssertRC(rc);
1101#endif
1102}
1103
1104static int PortCmdIssue_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1105{
1106 RT_NOREF1(iReg);
1107 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1108
1109 /* Update the CI register first. */
1110 uint32_t uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1111 pAhciPort->regCI &= ~uCIValue;
1112
1113 if ( (pAhciPort->regCMD & AHCI_PORT_CMD_CR)
1114 && u32Value > 0)
1115 {
1116 /*
1117 * Clear all tasks which are already marked as busy. The guest
1118 * shouldn't write already busy tasks actually.
1119 */
1120 u32Value &= ~pAhciPort->regCI;
1121
1122 ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
1123
1124 /* Send a notification to R3 if u32TasksNew was 0 before our write. */
1125 if (ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1126 ahciIoThreadKick(pAhci, pAhciPort);
1127 }
1128
1129 pAhciPort->regCI |= u32Value;
1130
1131 return VINF_SUCCESS;
1132}
1133
1134static int PortCmdIssue_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1135{
1136 RT_NOREF2(pAhci, iReg);
1137
1138 uint32_t uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1139 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
1140
1141 pAhciPort->regCI &= ~uCIValue;
1142 *pu32Value = pAhciPort->regCI;
1143
1144 return VINF_SUCCESS;
1145}
1146
1147static int PortSActive_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1148{
1149 RT_NOREF2(pAhci, iReg);
1150 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1151
1152 pAhciPort->regSACT |= u32Value;
1153
1154 return VINF_SUCCESS;
1155}
1156
1157static int PortSActive_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1158{
1159 RT_NOREF2(pAhci, iReg);
1160
1161 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1162 pAhciPort->regSACT &= ~u32TasksFinished;
1163
1164 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1165 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1166
1167 *pu32Value = pAhciPort->regSACT;
1168
1169 return VINF_SUCCESS;
1170}
1171
1172static int PortSError_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1173{
1174 RT_NOREF2(pAhci, iReg);
1175 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1176
1177 if ( (u32Value & AHCI_PORT_SERR_X)
1178 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1179 {
1180 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1181 pAhciPort->regTFD |= ATA_STAT_ERR;
1182 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1183 }
1184
1185 if ( (u32Value & AHCI_PORT_SERR_N)
1186 && (pAhciPort->regSERR & AHCI_PORT_SERR_N))
1187 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
1188
1189 pAhciPort->regSERR &= ~u32Value;
1190
1191 return VINF_SUCCESS;
1192}
1193
1194static int PortSError_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1195{
1196 RT_NOREF2(pAhci, iReg);
1197 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1198 *pu32Value = pAhciPort->regSERR;
1199 return VINF_SUCCESS;
1200}
1201
1202static int PortSControl_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1203{
1204 RT_NOREF2(pAhci, iReg);
1205 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1206 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1207 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1208
1209#ifndef IN_RING3
1210 RT_NOREF2(pAhciPort, u32Value);
1211 return VINF_IOM_R3_MMIO_WRITE;
1212#else
1213 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1214 {
1215 if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
1216 LogRel(("AHCI#%u: Port %d reset\n", pAhci->CTX_SUFF(pDevIns)->iInstance,
1217 pAhciPort->iLUN));
1218
1219 pAhciPort->regSSTS = 0;
1220 pAhciPort->regSIG = UINT32_MAX;
1221 pAhciPort->regTFD = 0x7f;
1222 pAhciPort->fFirstD2HFisSend = false;
1223 pAhciPort->regSCTL = u32Value;
1224 }
1225 else if ( (u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT
1226 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT
1227 && pAhciPort->pDrvBase)
1228 {
1229 /* Do the port reset here, so the guest sees the new status immediately. */
1230 if (pAhci->fLegacyPortResetMethod)
1231 {
1232 ahciPortResetFinish(pAhciPort);
1233 pAhciPort->regSCTL = u32Value; /* Update after finishing the reset, so the I/O thread doesn't get a chance to do the reset. */
1234 }
1235 else
1236 {
1237 pAhciPort->regSSTS = 0x1; /* Indicate device presence detected but communication not established. */
1238 pAhciPort->regSCTL = u32Value; /* Update before kicking the I/O thread. */
1239
1240 /* Kick the thread to finish the reset. */
1241 ahciIoThreadKick(pAhci, pAhciPort);
1242 }
1243 }
1244 else /* Just update the value if there is no device attached. */
1245 pAhciPort->regSCTL = u32Value;
1246
1247 return VINF_SUCCESS;
1248#endif
1249}
1250
1251static int PortSControl_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1252{
1253 RT_NOREF2(pAhci, iReg);
1254 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1255 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1256 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1257 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1258
1259 *pu32Value = pAhciPort->regSCTL;
1260 return VINF_SUCCESS;
1261}
1262
1263static int PortSStatus_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1264{
1265 RT_NOREF2(pAhci, iReg);
1266 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1267 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1268 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1269 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1270
1271 *pu32Value = pAhciPort->regSSTS;
1272 return VINF_SUCCESS;
1273}
1274
1275static int PortSignature_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1276{
1277 RT_NOREF2(pAhci, iReg);
1278 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1279 *pu32Value = pAhciPort->regSIG;
1280 return VINF_SUCCESS;
1281}
1282
1283static int PortTaskFileData_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1284{
1285 RT_NOREF2(pAhci, iReg);
1286 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1287 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1288 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1289 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1290 *pu32Value = pAhciPort->regTFD;
1291 return VINF_SUCCESS;
1292}
1293
1294/**
1295 * Read from the port command register.
1296 */
1297static int PortCmd_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1298{
1299 RT_NOREF2(pAhci, iReg);
1300 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot)));
1301 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",
1302 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1303 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1304 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1305 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1306 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1307 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1308 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
1309 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1310 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1311 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1312 *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
1313 return VINF_SUCCESS;
1314}
1315
1316/**
1317 * Write to the port command register.
1318 * This is the register where all the data transfer is started
1319 */
1320static int PortCmd_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1321{
1322 RT_NOREF1(iReg);
1323 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1324 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",
1325 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1326 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1327 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1328 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1329 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1330 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1331 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1332 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1333 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1334 (u32Value & AHCI_PORT_CMD_ST)));
1335
1336 /* The PxCMD.CCS bits are R/O and maintained separately. */
1337 u32Value &= ~AHCI_PORT_CMD_CCS;
1338
1339 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1340 {
1341 if (u32Value & AHCI_PORT_CMD_CLO)
1342 {
1343 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1344 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1345 /* Clear the CLO bit. */
1346 u32Value &= ~(AHCI_PORT_CMD_CLO);
1347 }
1348
1349 if (u32Value & AHCI_PORT_CMD_ST)
1350 {
1351 /*
1352 * Set engine state to running if there is a device attached and
1353 * IS.PCS is clear.
1354 */
1355 if ( pAhciPort->pDrvBase
1356 && !(pAhciPort->regIS & AHCI_PORT_IS_PCS))
1357 {
1358 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1359 u32Value |= AHCI_PORT_CMD_CR;
1360
1361 /* If there is something in CI, kick the I/O thread. */
1362 if ( pAhciPort->regCI > 0
1363 && ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1364 {
1365 ASMAtomicOrU32(&pAhciPort->u32TasksNew, pAhciPort->regCI);
1366#ifdef IN_RC
1367 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
1368 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1369
1370 pItem->iPort = pAhciPort->iLUN;
1371 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1372#else
1373 LogFlowFunc(("Signal event semaphore\n"));
1374 int rc = SUPSemEventSignal(pAhci->pSupDrvSession, pAhciPort->hEvtProcess);
1375 AssertRC(rc);
1376#endif
1377 }
1378 }
1379 else
1380 u32Value &= ~AHCI_PORT_CMD_CR;
1381 }
1382 else
1383 {
1384 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1385 /* Clear command issue register. */
1386 pAhciPort->regCI = 0;
1387 pAhciPort->regSACT = 0;
1388 /* Clear current command slot. */
1389 pAhciPort->u32CurrentCommandSlot = 0;
1390 u32Value &= ~AHCI_PORT_CMD_CR;
1391 }
1392 }
1393 else if (pAhciPort->pDrvBase)
1394 {
1395 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1396 {
1397 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1398 pAhciPort->fPoweredOn = true;
1399
1400 /*
1401 * Set states in the Port Signature and SStatus registers.
1402 */
1403 if (pAhciPort->fATAPI)
1404 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1405 else
1406 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1407 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1408 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1409 (0x03 << 0); /* Device detected and communication established. */
1410
1411 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1412 {
1413#ifndef IN_RING3
1414 return VINF_IOM_R3_MMIO_WRITE;
1415#else
1416 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1417 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1418
1419 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1420 {
1421 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1422 AssertRC(rc);
1423 }
1424#endif
1425 }
1426 }
1427
1428 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1429 {
1430 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1431 pAhciPort->fSpunUp = true;
1432 }
1433 }
1434
1435 if (u32Value & AHCI_PORT_CMD_FRE)
1436 {
1437 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1438
1439 u32Value |= AHCI_PORT_CMD_FR;
1440
1441 /* Send the first D2H FIS only if it wasn't already send. */
1442 if ( !pAhciPort->fFirstD2HFisSend
1443 && pAhciPort->pDrvBase)
1444 {
1445#ifndef IN_RING3
1446 return VINF_IOM_R3_MMIO_WRITE;
1447#else
1448 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1449 pAhciPort->fFirstD2HFisSend = true;
1450#endif
1451 }
1452 }
1453 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1454 {
1455 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1456 u32Value &= ~AHCI_PORT_CMD_FR;
1457 }
1458
1459 pAhciPort->regCMD = u32Value;
1460
1461 return VINF_SUCCESS;
1462}
1463
1464/**
1465 * Read from the port interrupt enable register.
1466 */
1467static int PortIntrEnable_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1468{
1469 RT_NOREF2(pAhci, iReg);
1470 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1471 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",
1472 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1473 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1474 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1475 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1476 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1477 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1478 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1479 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1480 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1481 *pu32Value = pAhciPort->regIE;
1482 return VINF_SUCCESS;
1483}
1484
1485/**
1486 * Write to the port interrupt enable register.
1487 */
1488static int PortIntrEnable_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1489{
1490 RT_NOREF1(iReg);
1491 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1492 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",
1493 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1494 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1495 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1496 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1497 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1498 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1499 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1500 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1501 (u32Value & AHCI_PORT_IE_DHRE)));
1502
1503 u32Value &= AHCI_PORT_IE_READONLY;
1504
1505 /* Check if some a interrupt status bit changed*/
1506 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1507
1508 int rc = VINF_SUCCESS;
1509 if (u32Value & u32IntrStatus)
1510 rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
1511
1512 if (rc == VINF_SUCCESS)
1513 pAhciPort->regIE = u32Value;
1514
1515 return rc;
1516}
1517
1518/**
1519 * Read from the port interrupt status register.
1520 */
1521static int PortIntrSts_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1522{
1523 RT_NOREF2(pAhci, iReg);
1524 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1525 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",
1526 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1527 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1528 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1529 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1530 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1531 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1532 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1533 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1534 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1535 *pu32Value = pAhciPort->regIS;
1536 return VINF_SUCCESS;
1537}
1538
1539/**
1540 * Write to the port interrupt status register.
1541 */
1542static int PortIntrSts_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1543{
1544 RT_NOREF2(pAhci, iReg);
1545 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1546 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1547
1548 return VINF_SUCCESS;
1549}
1550
1551/**
1552 * Read from the port FIS base address upper 32bit register.
1553 */
1554static int PortFisAddrUp_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1555{
1556 RT_NOREF2(pAhci, iReg);
1557 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1558 *pu32Value = pAhciPort->regFBU;
1559 return VINF_SUCCESS;
1560}
1561
1562/**
1563 * Write to the port FIS base address upper 32bit register.
1564 */
1565static int PortFisAddrUp_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1566{
1567 RT_NOREF2(pAhci, iReg);
1568 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1569
1570 pAhciPort->regFBU = u32Value;
1571 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1572
1573 return VINF_SUCCESS;
1574}
1575
1576/**
1577 * Read from the port FIS base address register.
1578 */
1579static int PortFisAddr_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1580{
1581 RT_NOREF2(pAhci, iReg);
1582 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1583 *pu32Value = pAhciPort->regFB;
1584 return VINF_SUCCESS;
1585}
1586
1587/**
1588 * Write to the port FIS base address register.
1589 */
1590static int PortFisAddr_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1591{
1592 RT_NOREF2(pAhci, iReg);
1593 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1594
1595 Assert(!(u32Value & ~AHCI_PORT_FB_RESERVED));
1596
1597 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1598 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1599
1600 return VINF_SUCCESS;
1601}
1602
1603/**
1604 * Write to the port command list base address upper 32bit register.
1605 */
1606static int PortCmdLstAddrUp_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1607{
1608 RT_NOREF2(pAhci, iReg);
1609 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1610
1611 pAhciPort->regCLBU = u32Value;
1612 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1613
1614 return VINF_SUCCESS;
1615}
1616
1617/**
1618 * Read from the port command list base address upper 32bit register.
1619 */
1620static int PortCmdLstAddrUp_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1621{
1622 RT_NOREF2(pAhci, iReg);
1623 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1624 *pu32Value = pAhciPort->regCLBU;
1625 return VINF_SUCCESS;
1626}
1627
1628/**
1629 * Read from the port command list base address register.
1630 */
1631static int PortCmdLstAddr_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1632{
1633 RT_NOREF2(pAhci, iReg);
1634 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1635 *pu32Value = pAhciPort->regCLB;
1636 return VINF_SUCCESS;
1637}
1638
1639/**
1640 * Write to the port command list base address register.
1641 */
1642static int PortCmdLstAddr_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1643{
1644 RT_NOREF2(pAhci, iReg);
1645 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1646
1647 Assert(!(u32Value & ~AHCI_PORT_CLB_RESERVED));
1648
1649 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1650 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1651
1652 return VINF_SUCCESS;
1653}
1654
1655/**
1656 * Read from the global Version register.
1657 */
1658static int HbaVersion_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1659{
1660 RT_NOREF1(iReg);
1661 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, pAhci->regHbaVs));
1662 *pu32Value = pAhci->regHbaVs;
1663 return VINF_SUCCESS;
1664}
1665
1666/**
1667 * Read from the global Ports implemented register.
1668 */
1669static int HbaPortsImplemented_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1670{
1671 RT_NOREF1(iReg);
1672 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, pAhci->regHbaPi));
1673 *pu32Value = pAhci->regHbaPi;
1674 return VINF_SUCCESS;
1675}
1676
1677/**
1678 * Write to the global interrupt status register.
1679 */
1680static int HbaInterruptStatus_w(PAHCI pAhci, uint32_t iReg, uint32_t u32Value)
1681{
1682 RT_NOREF1(iReg);
1683 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1684
1685 int rc = PDMCritSectEnter(&pAhci->lock, VINF_IOM_R3_MMIO_WRITE);
1686 if (rc != VINF_SUCCESS)
1687 return rc;
1688
1689 pAhci->regHbaIs &= ~(u32Value);
1690
1691 /*
1692 * Update interrupt status register and check for ports who
1693 * set the interrupt inbetween.
1694 */
1695 bool fClear = true;
1696 pAhci->regHbaIs |= ASMAtomicXchgU32(&pAhci->u32PortsInterrupted, 0);
1697 if (!pAhci->regHbaIs)
1698 {
1699 unsigned i = 0;
1700
1701 /* Check if the cleared ports have a interrupt status bit set. */
1702 while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
1703 {
1704 if (u32Value & 0x01)
1705 {
1706 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
1707
1708 if (pAhciPort->regIE & pAhciPort->regIS)
1709 {
1710 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1711 ASMAtomicOrU32(&pAhci->u32PortsInterrupted, 1 << i);
1712 fClear = false;
1713 break;
1714 }
1715 }
1716 u32Value >>= 1;
1717 i++;
1718 }
1719 }
1720 else
1721 fClear = false;
1722
1723 if (fClear)
1724 ahciHbaClearInterrupt(pAhci);
1725 else
1726 {
1727 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, pAhci->u32PortsInterrupted));
1728 /*
1729 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1730 * line is still high.
1731 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1732 */
1733 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
1734 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
1735 }
1736
1737 PDMCritSectLeave(&pAhci->lock);
1738 return VINF_SUCCESS;
1739}
1740
1741/**
1742 * Read from the global interrupt status register.
1743 */
1744static int HbaInterruptStatus_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1745{
1746 RT_NOREF1(iReg);
1747
1748 int rc = PDMCritSectEnter(&pAhci->lock, VINF_IOM_R3_MMIO_READ);
1749 if (rc != VINF_SUCCESS)
1750 return rc;
1751
1752 uint32_t u32PortsInterrupted = ASMAtomicXchgU32(&pAhci->u32PortsInterrupted, 0);
1753
1754 PDMCritSectLeave(&pAhci->lock);
1755 Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, pAhci->regHbaIs, u32PortsInterrupted));
1756
1757 pAhci->regHbaIs |= u32PortsInterrupted;
1758
1759#ifdef LOG_ENABLED
1760 Log(("%s:", __FUNCTION__));
1761 unsigned i;
1762 for (i = 0; i < pAhci->cPortsImpl; i++)
1763 {
1764 if ((pAhci->regHbaIs >> i) & 0x01)
1765 Log((" P%d", i));
1766 }
1767 Log(("\n"));
1768#endif
1769
1770 *pu32Value = pAhci->regHbaIs;
1771
1772 return VINF_SUCCESS;
1773}
1774
1775/**
1776 * Write to the global control register.
1777 */
1778static int HbaControl_w(PAHCI pAhci, uint32_t iReg, uint32_t u32Value)
1779{
1780 RT_NOREF1(iReg);
1781 Log(("%s: write u32Value=%#010x\n"
1782 "%s: AE=%d IE=%d HR=%d\n",
1783 __FUNCTION__, u32Value,
1784 __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
1785 (u32Value & AHCI_HBA_CTRL_HR)));
1786
1787#ifndef IN_RING3
1788 RT_NOREF2(pAhci, u32Value);
1789 return VINF_IOM_R3_MMIO_WRITE;
1790#else
1791 /*
1792 * Increase the active thread counter because we might set the host controller
1793 * reset bit.
1794 */
1795 ASMAtomicIncU32(&pAhci->cThreadsActive);
1796 ASMAtomicWriteU32(&pAhci->regHbaCtrl, (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE);
1797
1798 /*
1799 * Do the HBA reset if requested and there is no other active thread at the moment,
1800 * the work is deferred to the last active thread otherwise.
1801 */
1802 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
1803 if ( (u32Value & AHCI_HBA_CTRL_HR)
1804 && !cThreadsActive)
1805 ahciHBAReset(pAhci);
1806
1807 return VINF_SUCCESS;
1808#endif
1809}
1810
1811/**
1812 * Read the global control register.
1813 */
1814static int HbaControl_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1815{
1816 RT_NOREF1(iReg);
1817 Log(("%s: read regHbaCtrl=%#010x\n"
1818 "%s: AE=%d IE=%d HR=%d\n",
1819 __FUNCTION__, pAhci->regHbaCtrl,
1820 __FUNCTION__, (pAhci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
1821 (pAhci->regHbaCtrl & AHCI_HBA_CTRL_HR)));
1822 *pu32Value = pAhci->regHbaCtrl;
1823 return VINF_SUCCESS;
1824}
1825
1826/**
1827 * Read the global capabilities register.
1828 */
1829static int HbaCapabilities_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1830{
1831 RT_NOREF1(iReg);
1832 Log(("%s: read regHbaCap=%#010x\n"
1833 "%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",
1834 __FUNCTION__, pAhci->regHbaCap,
1835 __FUNCTION__, (pAhci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (pAhci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
1836 (pAhci->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (pAhci->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
1837 (pAhci->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (pAhci->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
1838 (pAhci->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (pAhci->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
1839 (pAhci->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (pAhci->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
1840 (pAhci->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (pAhci->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
1841 (pAhci->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (pAhci->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
1842 (pAhci->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (pAhci->regHbaCap & AHCI_HBA_CAP_NP)));
1843 *pu32Value = pAhci->regHbaCap;
1844 return VINF_SUCCESS;
1845}
1846
1847/**
1848 * Write to the global command completion coalescing control register.
1849 */
1850static int HbaCccCtl_w(PAHCI pAhci, uint32_t iReg, uint32_t u32Value)
1851{
1852 RT_NOREF1(iReg);
1853 Log(("%s: write u32Value=%#010x\n"
1854 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1855 __FUNCTION__, u32Value,
1856 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
1857 AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
1858
1859 pAhci->regHbaCccCtl = u32Value;
1860 pAhci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
1861 pAhci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
1862 pAhci->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
1863
1864 if (u32Value & AHCI_HBA_CCC_CTL_EN)
1865 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout); /* Arm the timer */
1866 else
1867 TMTimerStop(pAhci->CTX_SUFF(pHbaCccTimer));
1868
1869 return VINF_SUCCESS;
1870}
1871
1872/**
1873 * Read the global command completion coalescing control register.
1874 */
1875static int HbaCccCtl_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1876{
1877 RT_NOREF1(iReg);
1878 Log(("%s: read regHbaCccCtl=%#010x\n"
1879 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1880 __FUNCTION__, pAhci->regHbaCccCtl,
1881 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(pAhci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(pAhci->regHbaCccCtl),
1882 AHCI_HBA_CCC_CTL_INT_GET(pAhci->regHbaCccCtl), (pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
1883 *pu32Value = pAhci->regHbaCccCtl;
1884 return VINF_SUCCESS;
1885}
1886
1887/**
1888 * Write to the global command completion coalescing ports register.
1889 */
1890static int HbaCccPorts_w(PAHCI pAhci, uint32_t iReg, uint32_t u32Value)
1891{
1892 RT_NOREF1(iReg);
1893 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1894
1895 pAhci->regHbaCccPorts = u32Value;
1896
1897 return VINF_SUCCESS;
1898}
1899
1900/**
1901 * Read the global command completion coalescing ports register.
1902 */
1903static int HbaCccPorts_r(PAHCI pAhci, uint32_t iReg, uint32_t *pu32Value)
1904{
1905 RT_NOREF1(iReg);
1906 Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, pAhci->regHbaCccPorts));
1907
1908#ifdef LOG_ENABLED
1909 Log(("%s:", __FUNCTION__));
1910 unsigned i;
1911 for (i = 0; i < pAhci->cPortsImpl; i++)
1912 {
1913 if ((pAhci->regHbaCccPorts >> i) & 0x01)
1914 Log((" P%d", i));
1915 }
1916 Log(("\n"));
1917#endif
1918
1919 *pu32Value = pAhci->regHbaCccPorts;
1920 return VINF_SUCCESS;
1921}
1922
1923/**
1924 * Invalid write to global register
1925 */
1926static int HbaInvalid_w(PAHCI pAhci, uint32_t iReg, uint32_t u32Value)
1927{
1928 RT_NOREF3(pAhci, iReg, u32Value);
1929 Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1930 return VINF_SUCCESS;
1931}
1932
1933/**
1934 * Invalid Port write.
1935 */
1936static int PortInvalid_w(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1937{
1938 RT_NOREF4(pAhci, pAhciPort, iReg, u32Value);
1939 ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1940 return VINF_SUCCESS;
1941}
1942
1943/**
1944 * Invalid Port read.
1945 */
1946static int PortInvalid_r(PAHCI pAhci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1947{
1948 RT_NOREF4(pAhci, pAhciPort, iReg, pu32Value);
1949 ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
1950 return VINF_SUCCESS;
1951}
1952
1953/**
1954 * Register descriptor table for global HBA registers
1955 */
1956static const AHCIOPREG g_aOpRegs[] =
1957{
1958 {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
1959 {"HbaControl" , HbaControl_r, HbaControl_w},
1960 {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
1961 {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
1962 {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
1963 {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
1964 {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
1965};
1966
1967/**
1968 * Register descriptor table for port registers
1969 */
1970static const AHCIPORTOPREG g_aPortOpRegs[] =
1971{
1972 {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
1973 {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
1974 {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
1975 {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
1976 {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
1977 {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
1978 {"PortCmd", PortCmd_r, PortCmd_w},
1979 {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
1980 {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
1981 {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
1982 {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
1983 {"PortSControl", PortSControl_r, PortSControl_w},
1984 {"PortSError", PortSError_r, PortSError_w},
1985 {"PortSActive", PortSActive_r, PortSActive_w},
1986 {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
1987 {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
1988};
1989
1990#ifdef IN_RING3
1991/**
1992 * Reset initiated by system software for one port.
1993 *
1994 * @param pAhciPort The port to reset.
1995 */
1996static void ahciPortSwReset(PAHCIPort pAhciPort)
1997{
1998 bool fAllTasksCanceled;
1999
2000 /* Cancel all tasks first. */
2001 fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort);
2002 Assert(fAllTasksCanceled);
2003
2004 Assert(pAhciPort->cTasksActive == 0);
2005
2006 pAhciPort->regIS = 0;
2007 pAhciPort->regIE = 0;
2008 pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
2009 AHCI_PORT_CMD_SUD | /* Device has spun up. */
2010 AHCI_PORT_CMD_POD; /* Port is powered on. */
2011
2012 /* Hotplugging supported?. */
2013 if (pAhciPort->fHotpluggable)
2014 pAhciPort->regCMD |= AHCI_PORT_CMD_HPCP;
2015
2016 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2017 pAhciPort->regSIG = UINT32_MAX;
2018 pAhciPort->regSSTS = 0;
2019 pAhciPort->regSCTL = 0;
2020 pAhciPort->regSERR = 0;
2021 pAhciPort->regSACT = 0;
2022 pAhciPort->regCI = 0;
2023
2024 pAhciPort->fResetDevice = false;
2025 pAhciPort->fPoweredOn = true;
2026 pAhciPort->fSpunUp = true;
2027 pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
2028 pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
2029
2030 pAhciPort->u32TasksNew = 0;
2031 pAhciPort->u32TasksRedo = 0;
2032 pAhciPort->u32TasksFinished = 0;
2033 pAhciPort->u32QueuedTasksFinished = 0;
2034 pAhciPort->u32CurrentCommandSlot = 0;
2035
2036 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
2037 ASMAtomicWriteU32(&pAhciPort->MediaTrackType, ATA_MEDIA_TYPE_UNKNOWN);
2038
2039 if (pAhciPort->pDrvBase)
2040 {
2041 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
2042
2043 if (pAhciPort->fPoweredOn)
2044 {
2045 /*
2046 * Set states in the Port Signature and SStatus registers.
2047 */
2048 if (pAhciPort->fATAPI)
2049 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
2050 else
2051 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
2052 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
2053 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
2054 (0x03 << 0); /* Device detected and communication established. */
2055 }
2056 }
2057}
2058
2059/**
2060 * Hardware reset used for machine power on and reset.
2061 *
2062 * @param pAhciport The port to reset.
2063 */
2064static void ahciPortHwReset(PAHCIPort pAhciPort)
2065{
2066 /* Reset the address registers. */
2067 pAhciPort->regCLB = 0;
2068 pAhciPort->regCLBU = 0;
2069 pAhciPort->regFB = 0;
2070 pAhciPort->regFBU = 0;
2071
2072 /* Reset calculated addresses. */
2073 pAhciPort->GCPhysAddrClb = 0;
2074 pAhciPort->GCPhysAddrFb = 0;
2075}
2076
2077/**
2078 * Create implemented ports bitmap.
2079 *
2080 * @returns 32bit bitmask with a bit set for every implemented port.
2081 * @param cPorts Number of ports.
2082 */
2083static uint32_t ahciGetPortsImplemented(unsigned cPorts)
2084{
2085 uint32_t uPortsImplemented = 0;
2086
2087 for (unsigned i = 0; i < cPorts; i++)
2088 uPortsImplemented |= (1 << i);
2089
2090 return uPortsImplemented;
2091}
2092
2093/**
2094 * Reset the entire HBA.
2095 *
2096 * @param pThis The HBA state.
2097 */
2098static void ahciHBAReset(PAHCI pThis)
2099{
2100 unsigned i;
2101 int rc = VINF_SUCCESS;
2102
2103 LogRel(("AHCI#%u: Reset the HBA\n", pThis->CTX_SUFF(pDevIns)->iInstance));
2104
2105 /* Stop the CCC timer. */
2106 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
2107 {
2108 rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
2109 if (RT_FAILURE(rc))
2110 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
2111 }
2112
2113 /* Reset every port */
2114 for (i = 0; i < pThis->cPortsImpl; i++)
2115 {
2116 PAHCIPort pAhciPort = &pThis->ahciPort[i];
2117
2118 pAhciPort->iLUN = i;
2119 ahciPortSwReset(pAhciPort);
2120 }
2121
2122 /* Init Global registers */
2123 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
2124 AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
2125 AHCI_HBA_CAP_SAM | /* AHCI mode only */
2126 AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
2127 AHCI_HBA_CAP_SSS | /* Staggered spin up */
2128 AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
2129 AHCI_HBA_CAP_NCS_SET(pThis->cCmdSlotsAvail) | /* Number of command slots we support */
2130 AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
2131 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
2132 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
2133 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
2134 pThis->regHbaCccCtl = 0;
2135 pThis->regHbaCccPorts = 0;
2136 pThis->uCccTimeout = 0;
2137 pThis->uCccPortNr = 0;
2138 pThis->uCccNr = 0;
2139
2140 /* Clear pending interrupts. */
2141 pThis->regHbaIs = 0;
2142 pThis->u32PortsInterrupted = 0;
2143 ahciHbaClearInterrupt(pThis);
2144
2145 pThis->f64BitAddr = false;
2146 pThis->u32PortsInterrupted = 0;
2147 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
2148 /* Clear the HBA Reset bit */
2149 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
2150}
2151#endif
2152
2153/**
2154 * Reads from a AHCI controller register.
2155 *
2156 * @returns VBox status code.
2157 *
2158 * @param pAhci The AHCI instance.
2159 * @param uReg The register to write.
2160 * @param pv Where to store the result.
2161 * @param cb Number of bytes read.
2162 */
2163static int ahciRegisterRead(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
2164{
2165 int rc = VINF_SUCCESS;
2166 uint32_t iReg;
2167
2168 /*
2169 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
2170 * Otherwise it accesses the registers of a port.
2171 */
2172 if (uReg < AHCI_HBA_GLOBAL_SIZE)
2173 {
2174 iReg = uReg >> 2;
2175 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
2176 if (iReg < RT_ELEMENTS(g_aOpRegs))
2177 {
2178 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2179 rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
2180 }
2181 else
2182 {
2183 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2184 *(uint32_t *)pv = 0;
2185 }
2186 }
2187 else
2188 {
2189 uint32_t iRegOffset;
2190 uint32_t iPort;
2191
2192 /* Calculate accessed port. */
2193 uReg -= AHCI_HBA_GLOBAL_SIZE;
2194 iPort = uReg / AHCI_PORT_REGISTER_SIZE;
2195 iRegOffset = (uReg % AHCI_PORT_REGISTER_SIZE);
2196 iReg = iRegOffset >> 2;
2197
2198 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
2199
2200 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2201 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2202 {
2203 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2204 rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
2205 }
2206 else
2207 {
2208 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2209 rc = VINF_IOM_MMIO_UNUSED_00;
2210 }
2211
2212 /*
2213 * Windows Vista tries to read one byte from some registers instead of four.
2214 * Correct the value according to the read size.
2215 */
2216 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2217 {
2218 switch (cb)
2219 {
2220 case 1:
2221 {
2222 uint8_t uNewValue;
2223 uint8_t *p = (uint8_t *)pv;
2224
2225 iRegOffset &= 3;
2226 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2227 uNewValue = p[iRegOffset];
2228 /* Clear old value */
2229 *(uint32_t *)pv = 0;
2230 *(uint8_t *)pv = uNewValue;
2231 break;
2232 }
2233 default:
2234 AssertMsgFailed(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
2235 __FUNCTION__, cb, iPort, iRegOffset, iReg));
2236 }
2237 }
2238 }
2239
2240 return rc;
2241}
2242
2243/**
2244 * Writes a value to one of the AHCI controller registers.
2245 *
2246 * @returns VBox status code.
2247 *
2248 * @param pAhci The AHCI instance.
2249 * @param offReg The offset of the register to write to.
2250 * @param u32Value The value to write.
2251 */
2252static int ahciRegisterWrite(PAHCI pAhci, uint32_t offReg, uint32_t u32Value)
2253{
2254 int rc;
2255 uint32_t iReg;
2256
2257 /*
2258 * If the access offset is smaller than 100h the guest accesses the global registers.
2259 * Otherwise it accesses the registers of a port.
2260 */
2261 if (offReg < AHCI_HBA_GLOBAL_SIZE)
2262 {
2263 Log3(("Write global HBA register\n"));
2264 iReg = offReg >> 2;
2265 if (iReg < RT_ELEMENTS(g_aOpRegs))
2266 {
2267 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2268 rc = pReg->pfnWrite(pAhci, iReg, u32Value);
2269 }
2270 else
2271 {
2272 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2273 rc = VINF_SUCCESS;
2274 }
2275 }
2276 else
2277 {
2278 uint32_t iPort;
2279 Log3(("Write Port register\n"));
2280 /* Calculate accessed port. */
2281 offReg -= AHCI_HBA_GLOBAL_SIZE;
2282 iPort = offReg / AHCI_PORT_REGISTER_SIZE;
2283 iReg = (offReg % AHCI_PORT_REGISTER_SIZE) >> 2;
2284 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2285 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2286 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2287 {
2288 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2289 rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, u32Value);
2290 }
2291 else
2292 {
2293 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2294 rc = VINF_SUCCESS;
2295 }
2296 }
2297
2298 return rc;
2299}
2300
2301/**
2302 * Memory mapped I/O Handler for read operations.
2303 *
2304 * @returns VBox status code.
2305 *
2306 * @param pDevIns The device instance.
2307 * @param pvUser User argument.
2308 * @param GCPhysAddr Physical address (in GC) where the read starts.
2309 * @param pv Where to store the result.
2310 * @param cb Number of bytes read.
2311 */
2312PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2313{
2314 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2315 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2316 RT_NOREF1(pvUser);
2317
2318 int rc = ahciRegisterRead(pAhci, GCPhysAddr - pAhci->MMIOBase, pv, cb);
2319
2320 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
2321 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
2322 return rc;
2323}
2324
2325
2326/**
2327 * Memory mapped I/O Handler for write operations.
2328 *
2329 * @returns VBox status code.
2330 *
2331 * @param pDevIns The device instance.
2332 * @param pvUser User argument.
2333 * @param GCPhysAddr Physical address (in GC) where the read starts.
2334 * @param pv Where to fetch the result.
2335 * @param cb Number of bytes to write.
2336 */
2337PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
2338{
2339 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2340 Assert(cb == 4 || cb == 8);
2341 Assert(!(GCPhysAddr & (cb - 1)));
2342
2343 /* Break up 64 bits writes into two dword writes. */
2344 /** @todo Eliminate this code once the IOM/EM starts taking care of these
2345 * situations. */
2346 if (cb == 8)
2347 {
2348 /*
2349 * Only write the first 4 bytes if they weren't already.
2350 * It is possible that the last write to the register caused a world
2351 * switch and we entered this function again.
2352 * Writing the first 4 bytes again could cause indeterminate behavior
2353 * which can cause errors in the guest.
2354 */
2355 int rc = VINF_SUCCESS;
2356 if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
2357 {
2358 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
2359 if (rc != VINF_SUCCESS)
2360 return rc;
2361
2362 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
2363 }
2364
2365 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
2366 /*
2367 * Reset flag again so that the first 4 bytes are written again on the next
2368 * 8byte MMIO access.
2369 */
2370 if (rc == VINF_SUCCESS)
2371 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
2372
2373 return rc;
2374 }
2375
2376 /* Do the access. */
2377 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2378 return ahciRegisterWrite(pAhci, GCPhysAddr - pAhci->MMIOBase, *(uint32_t const *)pv);
2379}
2380
2381PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2382{
2383 RT_NOREF5(pDevIns, pvUser, Port, u32, cb);
2384 AssertMsgFailed(("Should not happen\n"));
2385 return VINF_SUCCESS;
2386}
2387
2388PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2389{
2390 RT_NOREF5(pDevIns, pvUser, Port, pu32, cb);
2391 AssertMsgFailed(("Should not happen\n"));
2392 return VINF_SUCCESS;
2393}
2394
2395/**
2396 * I/O port handler for writes to the index/data register pair.
2397 *
2398 * @returns VBox status code.
2399 *
2400 * @param pDevIns The device instance.
2401 * @param pvUser User argument.
2402 * @param Port Port address where the write starts.
2403 * @param pv Where to fetch the result.
2404 * @param cb Number of bytes to write.
2405 */
2406PDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2407{
2408 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2409 int rc = VINF_SUCCESS;
2410 RT_NOREF2(pvUser, cb);
2411
2412 if (Port - pAhci->IOPortBase >= 8)
2413 {
2414 unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
2415
2416 Assert(cb == 4);
2417
2418 if (iReg == 0)
2419 {
2420 /* Write the index register. */
2421 pAhci->regIdx = u32;
2422 }
2423 else
2424 {
2425 /** @todo range check? */
2426 Assert(iReg == 1);
2427 rc = ahciRegisterWrite(pAhci, pAhci->regIdx, u32);
2428 if (rc == VINF_IOM_R3_MMIO_WRITE)
2429 rc = VINF_IOM_R3_IOPORT_WRITE;
2430 }
2431 }
2432 /* else: ignore */
2433
2434 Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
2435 pDevIns->iInstance, &u32, cb, &u32, cb, Port, rc));
2436 return rc;
2437}
2438
2439/**
2440 * I/O port handler for reads from the index/data register pair.
2441 *
2442 * @returns VBox status code.
2443 *
2444 * @param pDevIns The device instance.
2445 * @param pvUser User argument.
2446 * @param Port Port address where the read starts.
2447 * @param pv Where to fetch the result.
2448 * @param cb Number of bytes to write.
2449 */
2450PDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2451{
2452 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2453 int rc = VINF_SUCCESS;
2454 RT_NOREF1(pvUser);
2455
2456 if (Port - pAhci->IOPortBase >= 8)
2457 {
2458 unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
2459
2460 Assert(cb == 4);
2461
2462 if (iReg == 0)
2463 {
2464 /* Read the index register. */
2465 *pu32 = pAhci->regIdx;
2466 }
2467 else
2468 {
2469 Assert(iReg == 1);
2470 /** @todo range check? */
2471 rc = ahciRegisterRead(pAhci, pAhci->regIdx, pu32, cb);
2472 if (rc == VINF_IOM_R3_MMIO_READ)
2473 rc = VINF_IOM_R3_IOPORT_READ;
2474 else if (rc == VINF_IOM_MMIO_UNUSED_00)
2475 rc = VERR_IOM_IOPORT_UNUSED;
2476 }
2477 }
2478 else
2479 *pu32 = UINT32_C(0xffffffff);
2480
2481 Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
2482 pDevIns->iInstance, pu32, cb, pu32, cb, Port, rc));
2483 return rc;
2484}
2485
2486#ifdef IN_RING3
2487
2488/**
2489 * @callback_method_impl{FNPCIIOREGIONMAP}
2490 */
2491static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
2492 RTGCPHYS cb, PCIADDRESSSPACE enmType)
2493{
2494 RT_NOREF(iRegion, enmType);
2495 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2496 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2497
2498 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
2499
2500 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2501 Assert(cb >= 4352);
2502
2503 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2504 /** @todo change this to IOMMMIO_FLAGS_WRITE_ONLY_DWORD once EM/IOM starts
2505 * handling 2nd DWORD failures on split accesses correctly. */
2506 int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
2507 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
2508 ahciMMIOWrite, ahciMMIORead, "AHCI");
2509 if (RT_FAILURE(rc))
2510 return rc;
2511
2512 if (pThis->fR0Enabled)
2513 {
2514 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2515 if (RT_FAILURE(rc))
2516 return rc;
2517 }
2518
2519 if (pThis->fGCEnabled)
2520 {
2521 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2522 if (RT_FAILURE(rc))
2523 return rc;
2524 }
2525
2526 pThis->MMIOBase = GCPhysAddress;
2527 return rc;
2528}
2529
2530
2531/**
2532 * @callback_method_impl{FNPCIIOREGIONMAP,
2533 * Map the legacy I/O port ranges to make Solaris work with the
2534 * controller.}
2535 */
2536static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
2537 RTGCPHYS cb, PCIADDRESSSPACE enmType)
2538{
2539 RT_NOREF(iRegion, enmType);
2540 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2541 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2542 int rc = VINF_SUCCESS;
2543
2544 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
2545
2546 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2547
2548 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2549 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2550 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2551 if (RT_FAILURE(rc))
2552 return rc;
2553
2554 if (pThis->fR0Enabled)
2555 {
2556 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2557 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2558 if (RT_FAILURE(rc))
2559 return rc;
2560 }
2561
2562 if (pThis->fGCEnabled)
2563 {
2564 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2565 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2566 if (RT_FAILURE(rc))
2567 return rc;
2568 }
2569
2570 return rc;
2571}
2572
2573/**
2574 * @callback_method_impl{FNPCIIOREGIONMAP,
2575 * Map the BMDMA I/O port range (used for the Index/Data pair register access)}
2576 */
2577static DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress,
2578 RTGCPHYS cb, PCIADDRESSSPACE enmType)
2579{
2580 RT_NOREF(iRegion, enmType);
2581 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2582 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2583 int rc = VINF_SUCCESS;
2584
2585 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
2586
2587 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2588
2589 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2590 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2591 ahciIdxDataWrite, ahciIdxDataRead, NULL, NULL, "AHCI IDX/DATA");
2592 if (RT_FAILURE(rc))
2593 return rc;
2594
2595 if (pThis->fR0Enabled)
2596 {
2597 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2598 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2599 if (RT_FAILURE(rc))
2600 return rc;
2601 }
2602
2603 if (pThis->fGCEnabled)
2604 {
2605 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2606 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2607 if (RT_FAILURE(rc))
2608 return rc;
2609 }
2610
2611 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
2612 return rc;
2613}
2614
2615/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2616
2617/**
2618 * Gets the pointer to the status LED of a unit.
2619 *
2620 * @returns VBox status code.
2621 * @param pInterface Pointer to the interface structure containing the called function pointer.
2622 * @param iLUN The unit which status LED we desire.
2623 * @param ppLed Where to store the LED pointer.
2624 */
2625static DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2626{
2627 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2628 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2629 {
2630 *ppLed = &pAhci->ahciPort[iLUN].Led;
2631 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2632 return VINF_SUCCESS;
2633 }
2634 return VERR_PDM_LUN_NOT_FOUND;
2635}
2636
2637/**
2638 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2639 */
2640static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2641{
2642 PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
2643 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2644 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
2645 return NULL;
2646}
2647
2648/**
2649 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2650 */
2651static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2652{
2653 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2654 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
2655 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pAhciPort->IPort);
2656 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pAhciPort->IMediaExPort);
2657 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
2658 return NULL;
2659}
2660
2661/**
2662 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2663 */
2664static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2665 uint32_t *piInstance, uint32_t *piLUN)
2666{
2667 PAHCIPort pAhciPort = PDMIMEDIAPORT_2_PAHCIPORT(pInterface);
2668 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
2669
2670 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2671 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2672 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2673
2674 *ppcszController = pDevIns->pReg->szName;
2675 *piInstance = pDevIns->iInstance;
2676 *piLUN = pAhciPort->iLUN;
2677
2678 return VINF_SUCCESS;
2679}
2680
2681#ifdef LOG_ENABLED
2682
2683/**
2684 * Dump info about the FIS
2685 *
2686 * @returns nothing
2687 * @param pAhciPort The port the command FIS was read from.
2688 * @param cmdFis The FIS to print info from.
2689 */
2690static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2691{
2692 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2693 /* Print FIS type. */
2694 switch (cmdFis[AHCI_CMDFIS_TYPE])
2695 {
2696 case AHCI_CMDFIS_TYPE_H2D:
2697 {
2698 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2699 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2700 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2701 ahciLog(("%s: Command register update\n", __FUNCTION__));
2702 else
2703 ahciLog(("%s: Control register update\n", __FUNCTION__));
2704 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2705 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2706 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2707 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2708 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2709 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2710
2711 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2712 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2713 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2714 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2715
2716 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2717 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2718 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2719 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2720 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2721 break;
2722 }
2723 case AHCI_CMDFIS_TYPE_D2H:
2724 {
2725 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2726 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2727 break;
2728 }
2729 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2730 {
2731 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2732 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2733 break;
2734 }
2735 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2736 {
2737 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2738 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2739 break;
2740 }
2741 case AHCI_CMDFIS_TYPE_DMASETUP:
2742 {
2743 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2744 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2745 break;
2746 }
2747 case AHCI_CMDFIS_TYPE_PIOSETUP:
2748 {
2749 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2750 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2751 break;
2752 }
2753 case AHCI_CMDFIS_TYPE_DATA:
2754 {
2755 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2756 break;
2757 }
2758 default:
2759 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2760 break;
2761 }
2762 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2763}
2764
2765/**
2766 * Dump info about the command header
2767 *
2768 * @returns nothing
2769 * @param pAhciPort Pointer to the port the command header was read from.
2770 * @param pCmdHdr The command header to print info from.
2771 */
2772static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2773{
2774 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2775 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2776 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2777 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2778 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2779 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2780 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2781 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2782 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2783 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2784 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2785 ahciLog(("%s: Device write\n", __FUNCTION__));
2786 else
2787 ahciLog(("%s: Device read\n", __FUNCTION__));
2788 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2789 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2790 else
2791 ahciLog(("%s: ATA command\n", __FUNCTION__));
2792
2793 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2794 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2795}
2796
2797#endif /* LOG_ENABLED */
2798
2799/**
2800 * Post the first D2H FIS from the device into guest memory.
2801 *
2802 * @returns nothing
2803 * @param pAhciPort Pointer to the port which "receives" the FIS.
2804 */
2805static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2806{
2807 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2808
2809 pAhciPort->fFirstD2HFisSend = true;
2810
2811 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2812 memset(&d2hFis[0], 0, sizeof(d2hFis));
2813 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2814 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2815
2816 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2817
2818 /* Set the signature based on the device type. */
2819 if (pAhciPort->fATAPI)
2820 {
2821 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2822 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2823 }
2824 else
2825 {
2826 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2827 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2828 }
2829
2830 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2831 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2832 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2833
2834 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2835 if (!pAhciPort->fATAPI)
2836 pAhciPort->regTFD |= ATA_STAT_READY;
2837
2838 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2839}
2840
2841/**
2842 * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
2843 *
2844 * @returns VBox status code
2845 * @param pAhciPort The port which "receives" the FIS.
2846 * @param uFisType The type of the FIS.
2847 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2848 */
2849static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2850{
2851 int rc = VINF_SUCCESS;
2852 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2853 unsigned cbFis = 0;
2854
2855 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2856
2857 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2858 {
2859 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2860
2861 /* Determine the offset and size of the FIS based on uFisType. */
2862 switch (uFisType)
2863 {
2864 case AHCI_CMDFIS_TYPE_D2H:
2865 {
2866 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2867 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2868 break;
2869 }
2870 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2871 {
2872 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2873 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2874 break;
2875 }
2876 case AHCI_CMDFIS_TYPE_DMASETUP:
2877 {
2878 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2879 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2880 break;
2881 }
2882 case AHCI_CMDFIS_TYPE_PIOSETUP:
2883 {
2884 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2885 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2886 break;
2887 }
2888 default:
2889 /*
2890 * We should post the unknown FIS into memory too but this never happens because
2891 * we know which FIS types we generate. ;)
2892 */
2893 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2894 }
2895
2896 /* Post the FIS into memory. */
2897 ahciLog(("%s: PDMDevHlpPCIPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2898 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2899 }
2900
2901 return rc;
2902}
2903
2904DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2905{
2906 pbBuf[0] = val >> 8;
2907 pbBuf[1] = val;
2908}
2909
2910
2911DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2912{
2913 pbBuf[0] = val >> 16;
2914 pbBuf[1] = val >> 8;
2915 pbBuf[2] = val;
2916}
2917
2918
2919DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2920{
2921 pbBuf[0] = val >> 24;
2922 pbBuf[1] = val >> 16;
2923 pbBuf[2] = val >> 8;
2924 pbBuf[3] = val;
2925}
2926
2927
2928DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2929{
2930 return (pbBuf[0] << 8) | pbBuf[1];
2931}
2932
2933
2934DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2935{
2936 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2937}
2938
2939
2940DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2941{
2942 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2943}
2944
2945
2946DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2947{
2948 iATAPILBA += 150;
2949 pbBuf[0] = (iATAPILBA / 75) / 60;
2950 pbBuf[1] = (iATAPILBA / 75) % 60;
2951 pbBuf[2] = iATAPILBA % 75;
2952}
2953
2954
2955DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2956{
2957 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2958}
2959
2960DECLINLINE(void) ahciReqSetStatus(PAHCIREQ pAhciReq, uint8_t u8Error, uint8_t u8Status)
2961{
2962 pAhciReq->cmdFis[AHCI_CMDFIS_ERR] = u8Error;
2963 pAhciReq->cmdFis[AHCI_CMDFIS_STS] = u8Status;
2964}
2965
2966static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
2967{
2968 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
2969 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2970 | ((pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_WRITE) ? ATAPI_INT_REASON_IO : 0)
2971 | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2972 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
2973 pAhciPort->abATAPISense[0] = 0x70;
2974 pAhciPort->abATAPISense[7] = 10;
2975}
2976
2977static void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
2978{
2979 Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
2980 pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
2981 ahciReqSetStatus(pAhciReq, pabATAPISense[2] << 4, ATA_STAT_READY | ATA_STAT_ERR);
2982 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2983 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2984 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
2985 memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
2986}
2987
2988/** @todo deprecated function - doesn't provide enough info. Replace by direct
2989 * calls to atapiCmdError() with full data. */
2990static void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
2991{
2992 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
2993 memset(abATAPISense, '\0', sizeof(abATAPISense));
2994 abATAPISense[0] = 0x70 | (1 << 7);
2995 abATAPISense[2] = uATAPISenseKey & 0x0f;
2996 abATAPISense[7] = 10;
2997 abATAPISense[12] = uATAPIASC;
2998 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
2999}
3000
3001static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3002{
3003 for (uint32_t i = 0; i < cbSize; i++)
3004 {
3005 if (*pbSrc)
3006 pbDst[i] = *pbSrc++;
3007 else
3008 pbDst[i] = ' ';
3009 }
3010}
3011
3012static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3013{
3014 for (uint32_t i = 0; i < cbSize; i++)
3015 {
3016 if (*pbSrc)
3017 pbDst[i ^ 1] = *pbSrc++;
3018 else
3019 pbDst[i ^ 1] = ' ';
3020 }
3021}
3022
3023static uint32_t ataChecksum(void* ptr, size_t count)
3024{
3025 uint8_t u8Sum = 0xa5, *p = (uint8_t*)ptr;
3026 size_t i;
3027
3028 for (i = 0; i < count; i++)
3029 {
3030 u8Sum += *p++;
3031 }
3032
3033 return (uint8_t)-(int32_t)u8Sum;
3034}
3035
3036static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
3037{
3038 uint16_t *p = (uint16_t *)pvBuf;
3039 memset(p, 0, 512);
3040 p[0] = RT_H2LE_U16(0x0040);
3041 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3042 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3043 /* Block size; obsolete, but required for the BIOS. */
3044 p[5] = RT_H2LE_U16(512);
3045 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3046 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3047 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3048 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3049 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
3050 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3051 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3052#if ATA_MAX_MULT_SECTORS > 1
3053 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
3054#endif
3055 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
3056 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3057 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3058 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3059 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3060 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
3061 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3062 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3063 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3064 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
3065 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
3066 if (pAhciPort->cMultSectors)
3067 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
3068 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
3069 {
3070 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3071 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3072 }
3073 else
3074 {
3075 /* Report maximum number of sectors possible with LBA28 */
3076 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
3077 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
3078 }
3079 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3080 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3081 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3082 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3083 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3084 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3085 if ( pAhciPort->fTrimEnabled
3086 || pAhciPort->cbSector != 512
3087 || pAhciPort->fNonRotational)
3088 {
3089 p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
3090 p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
3091 }
3092 else
3093 {
3094 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3095 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3096 }
3097 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
3098 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3099 p[84] = RT_H2LE_U16(1 << 14);
3100 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
3101 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3102 p[87] = RT_H2LE_U16(1 << 14);
3103 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3104 p[93] = RT_H2LE_U16(0x00);
3105 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3106 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3107 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
3108 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
3109
3110 /* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
3111 if (pAhciPort->cLogSectorsPerPhysicalExp)
3112 p[106] = RT_H2LE_U16(RT_BIT(14) | RT_BIT(13) | pAhciPort->cLogSectorsPerPhysicalExp);
3113
3114 if (pAhciPort->cbSector != 512)
3115 {
3116 uint32_t cSectorSizeInWords = pAhciPort->cbSector / sizeof(uint16_t);
3117 /* Enable reporting of logical sector size. */
3118 p[106] |= RT_H2LE_U16(RT_BIT(12) | RT_BIT(14));
3119 p[117] = RT_H2LE_U16(cSectorSizeInWords);
3120 p[118] = RT_H2LE_U16(cSectorSizeInWords >> 16);
3121 }
3122
3123 if (pAhciPort->fNonRotational)
3124 p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
3125
3126 if (pAhciPort->fTrimEnabled) /** @todo Set bit 14 in word 69 too? (Deterministic read after TRIM). */
3127 p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
3128
3129 /* The following are SATA specific */
3130 p[75] = RT_H2LE_U16(pAhciPort->CTX_SUFF(pAhci)->cCmdSlotsAvail-1); /* Number of commands we support, 0's based */
3131 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3132
3133 uint32_t uCsum = ataChecksum(p, 510);
3134 p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
3135
3136 return VINF_SUCCESS;
3137}
3138
3139typedef int (*PAtapiFunc)(PAHCIREQ, PAHCIPort, size_t, size_t *);
3140
3141static int atapiGetConfigurationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3142static int atapiGetEventStatusNotificationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3143static int atapiIdentifySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3144static int atapiInquirySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3145static int atapiMechanismStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3146static int atapiModeSenseErrorRecoverySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3147static int atapiModeSenseCDStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3148static int atapiReadCapacitySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3149static int atapiReadDiscInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3150static int atapiReadTOCNormalSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3151static int atapiReadTOCMultiSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3152static int atapiReadTOCRawSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3153static int atapiReadTrackInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3154static int atapiRequestSenseSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3155static int atapiPassthroughSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3156static int atapiReadDVDStructureSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3157
3158/**
3159 * Source/sink function indexes for g_apfnAtapiFuncs.
3160 */
3161typedef enum ATAPIFN
3162{
3163 ATAFN_SS_NULL = 0,
3164 ATAFN_SS_ATAPI_GET_CONFIGURATION,
3165 ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION,
3166 ATAFN_SS_ATAPI_IDENTIFY,
3167 ATAFN_SS_ATAPI_INQUIRY,
3168 ATAFN_SS_ATAPI_MECHANISM_STATUS,
3169 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
3170 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
3171 ATAFN_SS_ATAPI_READ_CAPACITY,
3172 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
3173 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
3174 ATAFN_SS_ATAPI_READ_TOC_MULTI,
3175 ATAFN_SS_ATAPI_READ_TOC_RAW,
3176 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
3177 ATAFN_SS_ATAPI_REQUEST_SENSE,
3178 ATAFN_SS_ATAPI_PASSTHROUGH,
3179 ATAFN_SS_ATAPI_READ_DVD_STRUCTURE,
3180 ATAFN_SS_MAX
3181} ATAPIFN;
3182
3183/**
3184 * Array of source/sink functions, the index is ATAFNSS.
3185 * Make sure ATAFNSS and this array match!
3186 */
3187static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
3188{
3189 NULL,
3190 atapiGetConfigurationSS,
3191 atapiGetEventStatusNotificationSS,
3192 atapiIdentifySS,
3193 atapiInquirySS,
3194 atapiMechanismStatusSS,
3195 atapiModeSenseErrorRecoverySS,
3196 atapiModeSenseCDStatusSS,
3197 atapiReadCapacitySS,
3198 atapiReadDiscInformationSS,
3199 atapiReadTOCNormalSS,
3200 atapiReadTOCMultiSS,
3201 atapiReadTOCRawSS,
3202 atapiReadTrackInformationSS,
3203 atapiRequestSenseSS,
3204 atapiPassthroughSS,
3205 atapiReadDVDStructureSS
3206};
3207
3208static int atapiIdentifySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3209{
3210 uint16_t p[256];
3211
3212 memset(p, 0, 512);
3213 /* Removable CDROM, 50us response, 12 byte packets */
3214 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
3215 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3216 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3217 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3218 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3219 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3220 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3221 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3222 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3223 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3224 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
3225 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3226 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3227 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3228 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3229 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3230 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3231 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
3232 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
3233 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3234 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3235 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
3236 p[83] = RT_H2LE_U16(1 << 14);
3237 p[84] = RT_H2LE_U16(1 << 14);
3238 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
3239 p[86] = RT_H2LE_U16(0);
3240 p[87] = RT_H2LE_U16(1 << 14);
3241 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3242 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
3243
3244 /* The following are SATA specific */
3245 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
3246 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3247
3248 /* Copy the buffer in to the scatter gather list. */
3249 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&p[0],
3250 RT_MIN(cbData, sizeof(p)), 0 /* cbSkip */);
3251
3252 atapiCmdOK(pAhciPort, pAhciReq);
3253 return VINF_SUCCESS;
3254}
3255
3256static int atapiReadCapacitySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3257{
3258 uint8_t aBuf[8];
3259
3260 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
3261 ataH2BE_U32(aBuf + 4, 2048);
3262
3263 /* Copy the buffer in to the scatter gather list. */
3264 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3265 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3266
3267 atapiCmdOK(pAhciPort, pAhciReq);
3268 return VINF_SUCCESS;
3269}
3270
3271
3272static int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3273{
3274 uint8_t aBuf[34];
3275
3276 memset(aBuf, '\0', 34);
3277 ataH2BE_U16(aBuf, 32);
3278 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
3279 aBuf[3] = 1; /* number of first track */
3280 aBuf[4] = 1; /* number of sessions (LSB) */
3281 aBuf[5] = 1; /* first track number in last session (LSB) */
3282 aBuf[6] = 1; /* last track number in last session (LSB) */
3283 aBuf[7] = (0 << 7) | (0 << 6) | (1 << 5) | (0 << 2) | (0 << 0); /* disc id not valid, disc bar code not valid, unrestricted use, not dirty, not RW medium */
3284 aBuf[8] = 0; /* disc type = CD-ROM */
3285 aBuf[9] = 0; /* number of sessions (MSB) */
3286 aBuf[10] = 0; /* number of sessions (MSB) */
3287 aBuf[11] = 0; /* number of sessions (MSB) */
3288 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
3289 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
3290
3291 /* Copy the buffer in to the scatter gather list. */
3292 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3293 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3294
3295 atapiCmdOK(pAhciPort, pAhciReq);
3296 return VINF_SUCCESS;
3297}
3298
3299
3300static int atapiReadTrackInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3301{
3302 uint8_t aBuf[36];
3303
3304 /* Accept address/number type of 1 only, and only track 1 exists. */
3305 if ((pAhciReq->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciReq->aATAPICmd[2]) != 1)
3306 {
3307 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3308 return VINF_SUCCESS;
3309 }
3310 memset(aBuf, '\0', 36);
3311 ataH2BE_U16(aBuf, 34);
3312 aBuf[2] = 1; /* track number (LSB) */
3313 aBuf[3] = 1; /* session number (LSB) */
3314 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
3315 aBuf[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
3316 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
3317 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
3318 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
3319 aBuf[32] = 0; /* track number (MSB) */
3320 aBuf[33] = 0; /* session number (MSB) */
3321
3322 /* Copy the buffer in to the scatter gather list. */
3323 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3324 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3325
3326 atapiCmdOK(pAhciPort, pAhciReq);
3327 return VINF_SUCCESS;
3328}
3329
3330static size_t atapiGetConfigurationFillFeatureListProfiles(uint8_t *pbBuf, size_t cbBuf)
3331{
3332 if (cbBuf < 3*4)
3333 return 0;
3334
3335 ataH2BE_U16(pbBuf, 0x0); /* feature 0: list of profiles supported */
3336 pbBuf[2] = (0 << 2) | (1 << 1) | (1 << 0); /* version 0, persistent, current */
3337 pbBuf[3] = 8; /* additional bytes for profiles */
3338 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3339 * before CD-ROM read capability. */
3340 ataH2BE_U16(pbBuf + 4, 0x10); /* profile: read-only DVD */
3341 pbBuf[6] = (0 << 0); /* NOT current profile */
3342 ataH2BE_U16(pbBuf + 8, 0x08); /* profile: read only CD */
3343 pbBuf[10] = (1 << 0); /* current profile */
3344
3345 return 3*4; /* Header + 2 profiles entries */
3346}
3347
3348static size_t atapiGetConfigurationFillFeatureCore(uint8_t *pbBuf, size_t cbBuf)
3349{
3350 if (cbBuf < 12)
3351 return 0;
3352
3353 ataH2BE_U16(pbBuf, 0x1); /* feature 0001h: Core Feature */
3354 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3355 pbBuf[3] = 8; /* Additional length */
3356 ataH2BE_U16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
3357 pbBuf[8] = RT_BIT(0); /* DBE */
3358 /* Rest is reserved. */
3359
3360 return 12;
3361}
3362
3363static size_t atapiGetConfigurationFillFeatureMorphing(uint8_t *pbBuf, size_t cbBuf)
3364{
3365 if (cbBuf < 8)
3366 return 0;
3367
3368 ataH2BE_U16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
3369 pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3370 pbBuf[3] = 4; /* Additional length */
3371 pbBuf[4] = RT_BIT(1) | 0x0; /* OCEvent | !ASYNC */
3372 /* Rest is reserved. */
3373
3374 return 8;
3375}
3376
3377static size_t atapiGetConfigurationFillFeatureRemovableMedium(uint8_t *pbBuf, size_t cbBuf)
3378{
3379 if (cbBuf < 8)
3380 return 0;
3381
3382 ataH2BE_U16(pbBuf, 0x3); /* feature 0003h: Removable Medium Feature */
3383 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3384 pbBuf[3] = 4; /* Additional length */
3385 /* Tray type loading | Load | Eject | !Pvnt Jmpr | !DBML | Lock */
3386 pbBuf[4] = (0x2 << 5) | RT_BIT(4) | RT_BIT(3) | (0x0 << 2) | (0x0 << 1) | RT_BIT(0);
3387 /* Rest is reserved. */
3388
3389 return 8;
3390}
3391
3392static size_t atapiGetConfigurationFillFeatureRandomReadable(uint8_t *pbBuf, size_t cbBuf)
3393{
3394 if (cbBuf < 12)
3395 return 0;
3396
3397 ataH2BE_U16(pbBuf, 0x10); /* feature 0010h: Random Readable Feature */
3398 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3399 pbBuf[3] = 8; /* Additional length */
3400 ataH2BE_U32(pbBuf + 4, 2048); /* Logical block size. */
3401 ataH2BE_U16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
3402 pbBuf[10] = 0; /* PP not present */
3403 /* Rest is reserved. */
3404
3405 return 12;
3406}
3407
3408static size_t atapiGetConfigurationFillFeatureCDRead(uint8_t *pbBuf, size_t cbBuf)
3409{
3410 if (cbBuf < 8)
3411 return 0;
3412
3413 ataH2BE_U16(pbBuf, 0x1e); /* feature 001Eh: CD Read Feature */
3414 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3415 pbBuf[3] = 0; /* Additional length */
3416 pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
3417 /* Rest is reserved. */
3418
3419 return 8;
3420}
3421
3422static size_t atapiGetConfigurationFillFeaturePowerManagement(uint8_t *pbBuf, size_t cbBuf)
3423{
3424 if (cbBuf < 4)
3425 return 0;
3426
3427 ataH2BE_U16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
3428 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3429 pbBuf[3] = 0; /* Additional length */
3430
3431 return 4;
3432}
3433
3434static size_t atapiGetConfigurationFillFeatureTimeout(uint8_t *pbBuf, size_t cbBuf)
3435{
3436 if (cbBuf < 8)
3437 return 0;
3438
3439 ataH2BE_U16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
3440 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3441 pbBuf[3] = 4; /* Additional length */
3442 pbBuf[4] = 0x0; /* !Group3 */
3443
3444 return 8;
3445}
3446
3447static int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3448{
3449 uint8_t aBuf[80];
3450 uint8_t *pbBuf = &aBuf[0];
3451 size_t cbBuf = sizeof(aBuf);
3452 size_t cbCopied = 0;
3453
3454 /* Accept valid request types only, and only starting feature 0. */
3455 if ((pAhciReq->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciReq->aATAPICmd[2]) != 0)
3456 {
3457 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3458 return VINF_SUCCESS;
3459 }
3460 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3461 * way to differentiate them right now is based on the image size). */
3462 if (pAhciPort->cTotalSectors)
3463 ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
3464 else
3465 ataH2BE_U16(pbBuf + 6, 0x00); /* current profile: none -> no media */
3466 cbBuf -= 8;
3467 pbBuf += 8;
3468
3469 cbCopied = atapiGetConfigurationFillFeatureListProfiles(pbBuf, cbBuf);
3470 cbBuf -= cbCopied;
3471 pbBuf += cbCopied;
3472
3473 cbCopied = atapiGetConfigurationFillFeatureCore(pbBuf, cbBuf);
3474 cbBuf -= cbCopied;
3475 pbBuf += cbCopied;
3476
3477 cbCopied = atapiGetConfigurationFillFeatureMorphing(pbBuf, cbBuf);
3478 cbBuf -= cbCopied;
3479 pbBuf += cbCopied;
3480
3481 cbCopied = atapiGetConfigurationFillFeatureRemovableMedium(pbBuf, cbBuf);
3482 cbBuf -= cbCopied;
3483 pbBuf += cbCopied;
3484
3485 cbCopied = atapiGetConfigurationFillFeatureRandomReadable(pbBuf, cbBuf);
3486 cbBuf -= cbCopied;
3487 pbBuf += cbCopied;
3488
3489 cbCopied = atapiGetConfigurationFillFeatureCDRead(pbBuf, cbBuf);
3490 cbBuf -= cbCopied;
3491 pbBuf += cbCopied;
3492
3493 cbCopied = atapiGetConfigurationFillFeaturePowerManagement(pbBuf, cbBuf);
3494 cbBuf -= cbCopied;
3495 pbBuf += cbCopied;
3496
3497 cbCopied = atapiGetConfigurationFillFeatureTimeout(pbBuf, cbBuf);
3498 cbBuf -= cbCopied;
3499 pbBuf += cbCopied;
3500
3501 /* Set data length now. */
3502 ataH2BE_U32(&aBuf[0], (uint32_t)(sizeof(aBuf) - cbBuf));
3503
3504 /* Copy the buffer in to the scatter gather list. */
3505 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3506 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3507
3508 atapiCmdOK(pAhciPort, pAhciReq);
3509 return VINF_SUCCESS;
3510}
3511
3512
3513static int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3514{
3515 uint8_t abBuf[8];
3516
3517 Assert(pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ);
3518 Assert(pAhciReq->cbTransfer <= 8);
3519
3520 if (!(pAhciReq->aATAPICmd[1] & 1))
3521 {
3522 /* no asynchronous operation supported */
3523 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3524 return VINF_SUCCESS;
3525 }
3526
3527 uint32_t OldStatus, NewStatus;
3528 do
3529 {
3530 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
3531 NewStatus = ATA_EVENT_STATUS_UNCHANGED;
3532 switch (OldStatus)
3533 {
3534 case ATA_EVENT_STATUS_MEDIA_NEW:
3535 /* mount */
3536 ataH2BE_U16(abBuf + 0, 6);
3537 abBuf[2] = 0x04; /* media */
3538 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3539 abBuf[4] = 0x02; /* new medium */
3540 abBuf[5] = 0x02; /* medium present / door closed */
3541 abBuf[6] = 0x00;
3542 abBuf[7] = 0x00;
3543 break;
3544
3545 case ATA_EVENT_STATUS_MEDIA_CHANGED:
3546 case ATA_EVENT_STATUS_MEDIA_REMOVED:
3547 /* umount */
3548 ataH2BE_U16(abBuf + 0, 6);
3549 abBuf[2] = 0x04; /* media */
3550 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3551 abBuf[4] = 0x03; /* media removal */
3552 abBuf[5] = 0x00; /* medium absent / door closed */
3553 abBuf[6] = 0x00;
3554 abBuf[7] = 0x00;
3555 if (OldStatus == ATA_EVENT_STATUS_MEDIA_CHANGED)
3556 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
3557 break;
3558
3559 case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
3560 ataH2BE_U16(abBuf + 0, 6);
3561 abBuf[2] = 0x04; /* media */
3562 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3563 abBuf[4] = 0x01; /* eject requested (eject button pressed) */
3564 abBuf[5] = 0x02; /* medium present / door closed */
3565 abBuf[6] = 0x00;
3566 abBuf[7] = 0x00;
3567 break;
3568
3569 case ATA_EVENT_STATUS_UNCHANGED:
3570 default:
3571 ataH2BE_U16(abBuf + 0, 6);
3572 abBuf[2] = 0x01; /* operational change request / notification */
3573 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3574 abBuf[4] = 0x00;
3575 abBuf[5] = 0x00;
3576 abBuf[6] = 0x00;
3577 abBuf[7] = 0x00;
3578 break;
3579 }
3580 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
3581
3582 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&abBuf[0],
3583 RT_MIN(cbData, sizeof(abBuf)), 0 /* cbSkip */);
3584
3585 atapiCmdOK(pAhciPort, pAhciReq);
3586 return VINF_SUCCESS;
3587}
3588
3589
3590static int atapiInquirySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3591{
3592 uint8_t aBuf[36];
3593
3594 aBuf[0] = 0x05; /* CD-ROM */
3595 aBuf[1] = 0x80; /* removable */
3596 aBuf[2] = 0x00; /* ISO */
3597 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3598 aBuf[4] = 31; /* additional length */
3599 aBuf[5] = 0; /* reserved */
3600 aBuf[6] = 0; /* reserved */
3601 aBuf[7] = 0; /* reserved */
3602 ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
3603 ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
3604 ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
3605
3606 /* Copy the buffer in to the scatter gather list. */
3607 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3608 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3609
3610 atapiCmdOK(pAhciPort, pAhciReq);
3611 return VINF_SUCCESS;
3612}
3613
3614
3615static int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3616{
3617 uint8_t aBuf[16];
3618
3619 ataH2BE_U16(&aBuf[0], 16 + 6);
3620 aBuf[2] = 0x70;
3621 aBuf[3] = 0;
3622 aBuf[4] = 0;
3623 aBuf[5] = 0;
3624 aBuf[6] = 0;
3625 aBuf[7] = 0;
3626
3627 aBuf[8] = 0x01;
3628 aBuf[9] = 0x06;
3629 aBuf[10] = 0x00;
3630 aBuf[11] = 0x05;
3631 aBuf[12] = 0x00;
3632 aBuf[13] = 0x00;
3633 aBuf[14] = 0x00;
3634 aBuf[15] = 0x00;
3635
3636 /* Copy the buffer in to the scatter gather list. */
3637 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3638 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3639
3640 atapiCmdOK(pAhciPort, pAhciReq);
3641 return VINF_SUCCESS;
3642}
3643
3644
3645static int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3646{
3647 uint8_t aBuf[40];
3648
3649 ataH2BE_U16(&aBuf[0], 38);
3650 aBuf[2] = 0x70;
3651 aBuf[3] = 0;
3652 aBuf[4] = 0;
3653 aBuf[5] = 0;
3654 aBuf[6] = 0;
3655 aBuf[7] = 0;
3656
3657 aBuf[8] = 0x2a;
3658 aBuf[9] = 30; /* page length */
3659 aBuf[10] = 0x08; /* DVD-ROM read support */
3660 aBuf[11] = 0x00; /* no write support */
3661 /* The following claims we support audio play. This is obviously false,
3662 * but the Linux generic CDROM support makes many features depend on this
3663 * capability. If it's not set, this causes many things to be disabled. */
3664 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3665 aBuf[13] = 0x00; /* no subchannel reads supported */
3666 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3667 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3668 aBuf[14] |= 1 << 1; /* report lock state */
3669 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3670 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3671 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3672 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3673 Just write the value DevATA is using. */
3674 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3675 aBuf[24] = 0; /* reserved */
3676 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3677 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3678 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3679 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3680 aBuf[32] = 0; /* reserved */
3681 aBuf[33] = 0; /* reserved */
3682 aBuf[34] = 0; /* reserved */
3683 aBuf[35] = 1; /* rotation control CAV */
3684 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3685 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3686
3687 /* Copy the buffer in to the scatter gather list. */
3688 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3689 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3690
3691 atapiCmdOK(pAhciPort, pAhciReq);
3692 return VINF_SUCCESS;
3693}
3694
3695
3696static int atapiRequestSenseSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3697{
3698 /* Copy the buffer in to the scatter gather list. */
3699 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq,
3700 pAhciPort->abATAPISense, RT_MIN(cbData, sizeof(pAhciPort->abATAPISense)),
3701 0 /* cbSkip */);
3702
3703 atapiCmdOK(pAhciPort, pAhciReq);
3704 return VINF_SUCCESS;
3705}
3706
3707
3708static int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3709{
3710 uint8_t aBuf[8];
3711
3712 ataH2BE_U16(&aBuf[0], 0);
3713 /* no current LBA */
3714 aBuf[2] = 0;
3715 aBuf[3] = 0;
3716 aBuf[4] = 0;
3717 aBuf[5] = 1;
3718 ataH2BE_U16(aBuf + 6, 0);
3719
3720 /* Copy the buffer in to the scatter gather list. */
3721 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3722 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3723
3724 atapiCmdOK(pAhciPort, pAhciReq);
3725 return VINF_SUCCESS;
3726}
3727
3728
3729static int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3730{
3731 uint8_t aBuf[20], *q, iStartTrack;
3732 bool fMSF;
3733 uint32_t cbSize;
3734
3735 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3736 iStartTrack = pAhciReq->aATAPICmd[6];
3737 if (iStartTrack > 1 && iStartTrack != 0xaa)
3738 {
3739 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3740 return VINF_SUCCESS;
3741 }
3742 q = aBuf + 2;
3743 *q++ = 1; /* first session */
3744 *q++ = 1; /* last session */
3745 if (iStartTrack <= 1)
3746 {
3747 *q++ = 0; /* reserved */
3748 *q++ = 0x14; /* ADR, control */
3749 *q++ = 1; /* track number */
3750 *q++ = 0; /* reserved */
3751 if (fMSF)
3752 {
3753 *q++ = 0; /* reserved */
3754 ataLBA2MSF(q, 0);
3755 q += 3;
3756 }
3757 else
3758 {
3759 /* sector 0 */
3760 ataH2BE_U32(q, 0);
3761 q += 4;
3762 }
3763 }
3764 /* lead out track */
3765 *q++ = 0; /* reserved */
3766 *q++ = 0x14; /* ADR, control */
3767 *q++ = 0xaa; /* track number */
3768 *q++ = 0; /* reserved */
3769 if (fMSF)
3770 {
3771 *q++ = 0; /* reserved */
3772 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3773 q += 3;
3774 }
3775 else
3776 {
3777 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3778 q += 4;
3779 }
3780 cbSize = q - aBuf;
3781 ataH2BE_U16(aBuf, cbSize - 2);
3782
3783 /* Copy the buffer in to the scatter gather list. */
3784 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3785 RT_MIN(cbData, cbSize), 0 /* cbSkip */);
3786
3787 atapiCmdOK(pAhciPort, pAhciReq);
3788 return VINF_SUCCESS;
3789}
3790
3791
3792static int atapiReadTOCMultiSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3793{
3794 uint8_t aBuf[12];
3795 bool fMSF;
3796
3797 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3798 /* multi session: only a single session defined */
3799/** @todo double-check this stuff against what a real drive says for a CD-ROM (not a CD-R) with only a single data session. Maybe solve the problem with "cdrdao read-toc" not being able to figure out whether numbers are in BCD or hex. */
3800 memset(aBuf, 0, 12);
3801 aBuf[1] = 0x0a;
3802 aBuf[2] = 0x01;
3803 aBuf[3] = 0x01;
3804 aBuf[5] = 0x14; /* ADR, control */
3805 aBuf[6] = 1; /* first track in last complete session */
3806 if (fMSF)
3807 {
3808 aBuf[8] = 0; /* reserved */
3809 ataLBA2MSF(&aBuf[9], 0);
3810 }
3811 else
3812 {
3813 /* sector 0 */
3814 ataH2BE_U32(aBuf + 8, 0);
3815 }
3816
3817 /* Copy the buffer in to the scatter gather list. */
3818 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3819 RT_MIN(cbData, sizeof(aBuf)), 0 /* cbSkip */);
3820
3821 atapiCmdOK(pAhciPort, pAhciReq);
3822 return VINF_SUCCESS;
3823}
3824
3825
3826static int atapiReadTOCRawSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3827{
3828 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3829 uint8_t *q, iStartTrack;
3830 bool fMSF;
3831 uint32_t cbSize;
3832
3833 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3834 iStartTrack = pAhciReq->aATAPICmd[6];
3835
3836 q = aBuf + 2;
3837 *q++ = 1; /* first session */
3838 *q++ = 1; /* last session */
3839
3840 *q++ = 1; /* session number */
3841 *q++ = 0x14; /* data track */
3842 *q++ = 0; /* track number */
3843 *q++ = 0xa0; /* first track in program area */
3844 *q++ = 0; /* min */
3845 *q++ = 0; /* sec */
3846 *q++ = 0; /* frame */
3847 *q++ = 0;
3848 *q++ = 1; /* first track */
3849 *q++ = 0x00; /* disk type CD-DA or CD data */
3850 *q++ = 0;
3851
3852 *q++ = 1; /* session number */
3853 *q++ = 0x14; /* data track */
3854 *q++ = 0; /* track number */
3855 *q++ = 0xa1; /* last track in program area */
3856 *q++ = 0; /* min */
3857 *q++ = 0; /* sec */
3858 *q++ = 0; /* frame */
3859 *q++ = 0;
3860 *q++ = 1; /* last track */
3861 *q++ = 0;
3862 *q++ = 0;
3863
3864 *q++ = 1; /* session number */
3865 *q++ = 0x14; /* data track */
3866 *q++ = 0; /* track number */
3867 *q++ = 0xa2; /* lead-out */
3868 *q++ = 0; /* min */
3869 *q++ = 0; /* sec */
3870 *q++ = 0; /* frame */
3871 if (fMSF)
3872 {
3873 *q++ = 0; /* reserved */
3874 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3875 q += 3;
3876 }
3877 else
3878 {
3879 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3880 q += 4;
3881 }
3882
3883 *q++ = 1; /* session number */
3884 *q++ = 0x14; /* ADR, control */
3885 *q++ = 0; /* track number */
3886 *q++ = 1; /* point */
3887 *q++ = 0; /* min */
3888 *q++ = 0; /* sec */
3889 *q++ = 0; /* frame */
3890 if (fMSF)
3891 {
3892 *q++ = 0; /* reserved */
3893 ataLBA2MSF(q, 0);
3894 q += 3;
3895 }
3896 else
3897 {
3898 /* sector 0 */
3899 ataH2BE_U32(q, 0);
3900 q += 4;
3901 }
3902
3903 cbSize = q - aBuf;
3904 ataH2BE_U16(aBuf, cbSize - 2);
3905
3906 /* Copy the buffer in to the scatter gather list. */
3907 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
3908 RT_MIN(cbData, cbSize), 0 /* cbSkip */);
3909
3910 atapiCmdOK(pAhciPort, pAhciReq);
3911 return VINF_SUCCESS;
3912}
3913
3914/**
3915 * Sets the given media track type.
3916 */
3917static uint32_t ahciMediumTypeSet(PAHCIPort pAhciPort, uint32_t MediaTrackType)
3918{
3919 return ASMAtomicXchgU32(&pAhciPort->MediaTrackType, MediaTrackType);
3920}
3921
3922static int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3923{
3924 RT_NOREF(cbData);
3925 int rc = VINF_SUCCESS;
3926 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
3927 uint32_t cbTransfer;
3928 void *pvBuf = NULL;
3929
3930 cbTransfer = pAhciReq->cbTransfer;
3931
3932 if (cbTransfer)
3933 {
3934 pvBuf = (uint8_t *)RTMemAlloc(cbTransfer);
3935 if (!pvBuf)
3936 return VERR_NO_MEMORY;
3937
3938 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
3939 {
3940 ahciR3CopyBufferFromPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, pvBuf, cbTransfer);
3941 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
3942 return VINF_SUCCESS;
3943 }
3944 }
3945
3946 /* Simple heuristics: if there is at least one sector of data
3947 * to transfer, it's worth updating the LEDs. */
3948 if (cbTransfer >= 2048)
3949 {
3950 if (pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_WRITE)
3951 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
3952 else
3953 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
3954 }
3955
3956 if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
3957 {
3958 /* Linux accepts commands with up to 100KB of data, but expects
3959 * us to handle commands with up to 128KB of data. The usual
3960 * imbalance of powers. */
3961 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
3962 uint32_t iATAPILBA, cSectors;
3963 uint8_t *pbBuf = (uint8_t *)pvBuf;
3964
3965 switch (pAhciReq->aATAPICmd[0])
3966 {
3967 case SCSI_READ_10:
3968 case SCSI_WRITE_10:
3969 case SCSI_WRITE_AND_VERIFY_10:
3970 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3971 cSectors = ataBE2H_U16(pAhciReq->aATAPICmd + 7);
3972 break;
3973 case SCSI_READ_12:
3974 case SCSI_WRITE_12:
3975 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3976 cSectors = ataBE2H_U32(pAhciReq->aATAPICmd + 6);
3977 break;
3978 case SCSI_READ_CD:
3979 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
3980 cSectors = ataBE2H_U24(pAhciReq->aATAPICmd + 6);
3981 break;
3982 case SCSI_READ_CD_MSF:
3983 iATAPILBA = ataMSF2LBA(pAhciReq->aATAPICmd + 3);
3984 cSectors = ataMSF2LBA(pAhciReq->aATAPICmd + 6) - iATAPILBA;
3985 break;
3986 default:
3987 AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciReq->aATAPICmd[0]));
3988 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
3989 LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
3990 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
3991 RTMemFree(pvBuf);
3992 return VINF_SUCCESS;
3993 }
3994 memcpy(aATAPICmd, pAhciReq->aATAPICmd, ATAPI_PACKET_SIZE);
3995 uint32_t cReqSectors = 0;
3996 for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
3997 {
3998 if (i * pAhciReq->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
3999 cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciReq->cbATAPISector;
4000 else
4001 cReqSectors = i;
4002 uint32_t cbCurrTX = pAhciReq->cbATAPISector * cReqSectors;
4003 switch (pAhciReq->aATAPICmd[0])
4004 {
4005 case SCSI_READ_10:
4006 case SCSI_WRITE_10:
4007 case SCSI_WRITE_AND_VERIFY_10:
4008 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4009 ataH2BE_U16(aATAPICmd + 7, cReqSectors);
4010 break;
4011 case SCSI_READ_12:
4012 case SCSI_WRITE_12:
4013 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4014 ataH2BE_U32(aATAPICmd + 6, cReqSectors);
4015 break;
4016 case SCSI_READ_CD:
4017 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4018 ataH2BE_U24(aATAPICmd + 6, cReqSectors);
4019 break;
4020 case SCSI_READ_CD_MSF:
4021 ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
4022 ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
4023 break;
4024 }
4025 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4026 aATAPICmd,
4027 pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ
4028 ? PDMMEDIATXDIR_FROM_DEVICE
4029 : PDMMEDIATXDIR_TO_DEVICE,
4030 pbBuf,
4031 &cbCurrTX,
4032 abATAPISense,
4033 sizeof(abATAPISense),
4034 30000 /**< @todo timeout */);
4035 if (rc != VINF_SUCCESS)
4036 break;
4037 iATAPILBA += cReqSectors;
4038 pbBuf += pAhciReq->cbATAPISector * cReqSectors;
4039 }
4040 }
4041 else
4042 {
4043 PDMMEDIATXDIR enmBlockTxDir = PDMMEDIATXDIR_NONE;
4044
4045 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ)
4046 enmBlockTxDir = PDMMEDIATXDIR_FROM_DEVICE;
4047 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
4048 enmBlockTxDir = PDMMEDIATXDIR_TO_DEVICE;
4049 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_INVALID)
4050 enmBlockTxDir = PDMMEDIATXDIR_NONE;
4051 else
4052 AssertMsgFailed(("Invalid transfer direction %d\n", pAhciReq->enmType));
4053
4054 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4055 pAhciReq->aATAPICmd,
4056 enmBlockTxDir,
4057 pvBuf,
4058 &cbTransfer,
4059 abATAPISense,
4060 sizeof(abATAPISense),
4061 30000 /**< @todo timeout */);
4062 }
4063
4064 /* Update the LEDs and the read/write statistics. */
4065 if (cbTransfer >= 2048)
4066 {
4067 if (pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_WRITE)
4068 {
4069 pAhciPort->Led.Actual.s.fReading = 0;
4070 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
4071 }
4072 else
4073 {
4074 pAhciPort->Led.Actual.s.fWriting = 0;
4075 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
4076 }
4077 }
4078
4079 if (RT_SUCCESS(rc))
4080 {
4081 /* Do post processing for certain commands. */
4082 switch (pAhciReq->aATAPICmd[0])
4083 {
4084 case SCSI_SEND_CUE_SHEET:
4085 case SCSI_READ_TOC_PMA_ATIP:
4086 {
4087 if (!pAhciPort->pTrackList)
4088 rc = ATAPIPassthroughTrackListCreateEmpty(&pAhciPort->pTrackList);
4089
4090 if (RT_SUCCESS(rc))
4091 rc = ATAPIPassthroughTrackListUpdate(pAhciPort->pTrackList, pAhciReq->aATAPICmd, pvBuf);
4092
4093 if ( RT_FAILURE(rc)
4094 && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4095 LogRel(("AHCI: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n",
4096 rc, pAhciReq->aATAPICmd[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP"));
4097 break;
4098 }
4099 case SCSI_SYNCHRONIZE_CACHE:
4100 {
4101 if (pAhciPort->pTrackList)
4102 ATAPIPassthroughTrackListClear(pAhciPort->pTrackList);
4103 break;
4104 }
4105 }
4106
4107 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ)
4108 {
4109 Assert(cbTransfer <= pAhciReq->cbTransfer);
4110
4111 if (pAhciReq->aATAPICmd[0] == SCSI_INQUIRY)
4112 {
4113 /* Make sure that the real drive cannot be identified.
4114 * Motivation: changing the VM configuration should be as
4115 * invisible as possible to the guest. */
4116 if (cbTransfer >= 8 + 8)
4117 ataSCSIPadStr((uint8_t *)pvBuf + 8, "VBOX", 8);
4118 if (cbTransfer >= 16 + 16)
4119 ataSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
4120 if (cbTransfer >= 32 + 4)
4121 ataSCSIPadStr((uint8_t *)pvBuf + 32, "1.0", 4);
4122 }
4123
4124 if (cbTransfer)
4125 {
4126 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
4127
4128 /* Reply with the same amount of data as the real drive. */
4129 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, pvBuf,
4130 cbTransfer, 0 /* cbSkip */);
4131 }
4132 else
4133 *pcbData = 0;
4134 }
4135 else
4136 *pcbData = cbTransfer;
4137 atapiCmdOK(pAhciPort, pAhciReq);
4138 }
4139 else
4140 {
4141 if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
4142 {
4143 uint8_t u8Cmd = pAhciReq->aATAPICmd[0];
4144 do
4145 {
4146 /* don't log superfluous errors */
4147 if ( rc == VERR_DEV_IO_ERROR
4148 && ( u8Cmd == SCSI_TEST_UNIT_READY
4149 || u8Cmd == SCSI_READ_CAPACITY
4150 || u8Cmd == SCSI_READ_DVD_STRUCTURE
4151 || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
4152 break;
4153 pAhciPort->cErrors++;
4154 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
4155 pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
4156 } while (0);
4157 }
4158 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
4159 }
4160
4161 if (pvBuf)
4162 RTMemFree(pvBuf);
4163
4164 return VINF_SUCCESS;
4165}
4166
4167/** @todo Revise ASAP. */
4168/* Keep in sync with DevATA.cpp! */
4169static int atapiReadDVDStructureSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
4170{
4171 uint8_t aBuf[25]; /* Counted a maximum of 20 bytes but better be on the safe side. */
4172 uint8_t *buf = aBuf;
4173 int media = pAhciReq->aATAPICmd[1];
4174 int format = pAhciReq->aATAPICmd[7];
4175
4176 uint16_t max_len = RT_MIN(ataBE2H_U16(&pAhciReq->aATAPICmd[8]), sizeof(aBuf));
4177
4178 memset(buf, 0, max_len);
4179
4180 switch (format) {
4181 case 0x00:
4182 case 0x01:
4183 case 0x02:
4184 case 0x03:
4185 case 0x04:
4186 case 0x05:
4187 case 0x06:
4188 case 0x07:
4189 case 0x08:
4190 case 0x09:
4191 case 0x0a:
4192 case 0x0b:
4193 case 0x0c:
4194 case 0x0d:
4195 case 0x0e:
4196 case 0x0f:
4197 case 0x10:
4198 case 0x11:
4199 case 0x30:
4200 case 0x31:
4201 case 0xff:
4202 if (media == 0)
4203 {
4204 int uASC = SCSI_ASC_NONE;
4205
4206 switch (format)
4207 {
4208 case 0x0: /* Physical format information */
4209 {
4210 int layer = pAhciReq->aATAPICmd[6];
4211 uint64_t total_sectors;
4212
4213 if (layer != 0)
4214 {
4215 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4216 break;
4217 }
4218
4219 total_sectors = pAhciPort->cTotalSectors;
4220 total_sectors >>= 2;
4221 if (total_sectors == 0)
4222 {
4223 uASC = -SCSI_ASC_MEDIUM_NOT_PRESENT;
4224 break;
4225 }
4226
4227 buf[4] = 1; /* DVD-ROM, part version 1 */
4228 buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
4229 buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
4230 buf[7] = 0; /* default densities */
4231
4232 /* FIXME: 0x30000 per spec? */
4233 ataH2BE_U32(buf + 8, 0); /* start sector */
4234 ataH2BE_U32(buf + 12, total_sectors - 1); /* end sector */
4235 ataH2BE_U32(buf + 16, total_sectors - 1); /* l0 end sector */
4236
4237 /* Size of buffer, not including 2 byte size field */
4238 ataH2BE_U32(&buf[0], 2048 + 2);
4239
4240 /* 2k data + 4 byte header */
4241 uASC = (2048 + 4);
4242 break;
4243 }
4244 case 0x01: /* DVD copyright information */
4245 buf[4] = 0; /* no copyright data */
4246 buf[5] = 0; /* no region restrictions */
4247
4248 /* Size of buffer, not including 2 byte size field */
4249 ataH2BE_U16(buf, 4 + 2);
4250
4251 /* 4 byte header + 4 byte data */
4252 uASC = (4 + 4);
4253 break;
4254
4255 case 0x03: /* BCA information - invalid field for no BCA info */
4256 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4257 break;
4258
4259 case 0x04: /* DVD disc manufacturing information */
4260 /* Size of buffer, not including 2 byte size field */
4261 ataH2BE_U16(buf, 2048 + 2);
4262
4263 /* 2k data + 4 byte header */
4264 uASC = (2048 + 4);
4265 break;
4266 case 0xff:
4267 /*
4268 * This lists all the command capabilities above. Add new ones
4269 * in order and update the length and buffer return values.
4270 */
4271
4272 buf[4] = 0x00; /* Physical format */
4273 buf[5] = 0x40; /* Not writable, is readable */
4274 ataH2BE_U16((buf + 6), 2048 + 4);
4275
4276 buf[8] = 0x01; /* Copyright info */
4277 buf[9] = 0x40; /* Not writable, is readable */
4278 ataH2BE_U16((buf + 10), 4 + 4);
4279
4280 buf[12] = 0x03; /* BCA info */
4281 buf[13] = 0x40; /* Not writable, is readable */
4282 ataH2BE_U16((buf + 14), 188 + 4);
4283
4284 buf[16] = 0x04; /* Manufacturing info */
4285 buf[17] = 0x40; /* Not writable, is readable */
4286 ataH2BE_U16((buf + 18), 2048 + 4);
4287
4288 /* Size of buffer, not including 2 byte size field */
4289 ataH2BE_U16(buf, 16 + 2);
4290
4291 /* data written + 4 byte header */
4292 uASC = (16 + 4);
4293 break;
4294 default: /** @todo formats beyond DVD-ROM requires */
4295 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4296 }
4297
4298 if (uASC < 0)
4299 {
4300 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, -uASC);
4301 return false;
4302 }
4303 break;
4304 }
4305 /** @todo BD support, fall through for now */
4306
4307 /* Generic disk structures */
4308 case 0x80: /** @todo AACS volume identifier */
4309 case 0x81: /** @todo AACS media serial number */
4310 case 0x82: /** @todo AACS media identifier */
4311 case 0x83: /** @todo AACS media key block */
4312 case 0x90: /** @todo List of recognized format layers */
4313 case 0xc0: /** @todo Write protection status */
4314 default:
4315 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST,
4316 SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4317 return false;
4318 }
4319
4320 /* Copy the buffer into the scatter gather list. */
4321 *pcbData = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq, (void *)&aBuf[0],
4322 RT_MIN(cbData, max_len), 0 /* cbSkip */);
4323
4324 atapiCmdOK(pAhciPort, pAhciReq);
4325 return false;
4326}
4327
4328static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
4329{
4330 size_t cbTransfered = 0;
4331 int rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax, &cbTransfered);
4332
4333 pAhciReq->cbTransfer = (uint32_t)cbTransfered;
4334 Assert(pAhciReq->cbTransfer == cbTransfered);
4335
4336 LogFlow(("cbTransfered=%d\n", cbTransfered));
4337
4338 /* Write updated command header into memory of the guest. */
4339 uint32_t u32PRDBC = (uint32_t)cbTransfered;
4340 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr + RT_OFFSETOF(CmdHdr, u32PRDBC),
4341 &u32PRDBC, sizeof(u32PRDBC));
4342
4343 return rcSourceSink;
4344}
4345
4346static DECLCALLBACK(int) atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, PRTSGBUF pSgBuf, size_t cbBuf,
4347 uint32_t offBuf, void **ppvProc, size_t *pcbProc)
4348{
4349 uint8_t *pbBuf = NULL;
4350 uint32_t cSectorsOff = offBuf / 2048;
4351 uint32_t cSectors = cbBuf / 2048;
4352 uint32_t iATAPILBA = cSectorsOff + pAhciReq->uOffset / 2048;
4353 size_t cbAlloc = cbBuf + cSectors * (1 + 11 + 3 + 1 + 288); /* Per sector data like ECC. */
4354
4355 AssertReturn((offBuf % 2048 == 0) && (cbBuf % 2048 == 0), VERR_INVALID_STATE);
4356
4357 pbBuf = (uint8_t *)RTMemAlloc(cbAlloc);
4358 if (RT_UNLIKELY(!pbBuf))
4359 return VERR_NO_MEMORY;
4360
4361 uint8_t *pbBufDst = pbBuf;
4362
4363 for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4364 {
4365 /* sync bytes */
4366 *pbBufDst++ = 0x00;
4367 memset(pbBufDst, 0xff, 11);
4368 pbBufDst += 11;
4369 /* MSF */
4370 ataLBA2MSF(pbBufDst, i);
4371 pbBufDst += 3;
4372 *pbBufDst++ = 0x01; /* mode 1 data */
4373 /* data */
4374 RTSgBufCopyToBuf(pSgBuf, pbBufDst, 2048);
4375 pbBufDst += 2048;
4376 /* ECC */
4377 memset(pbBufDst, 0, 288);
4378 pbBufDst += 288;
4379 }
4380
4381 *ppvProc = pbBuf;
4382 *pcbProc = cbAlloc;
4383 return VINF_SUCCESS;
4384}
4385
4386static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
4387{
4388 RT_NOREF(pAhciPort);
4389 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
4390
4391 switch (cbSector)
4392 {
4393 case 2048:
4394 pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
4395 pAhciReq->cbTransfer = cSectors * cbSector;
4396 break;
4397 case 2352:
4398 {
4399 pAhciReq->pfnPostProcess = atapiReadSectors2352PostProcess;
4400 pAhciReq->uOffset = (uint64_t)iATAPILBA * 2048;
4401 pAhciReq->cbTransfer = cSectors * 2048;
4402 break;
4403 }
4404 default:
4405 AssertMsgFailed(("Unsupported sectors size\n"));
4406 break;
4407 }
4408
4409 return VINF_SUCCESS;
4410}
4411
4412static PDMMEDIAEXIOREQTYPE atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4413{
4414 PDMMEDIAEXIOREQTYPE enmType = PDMMEDIAEXIOREQTYPE_INVALID;
4415 const uint8_t *pbPacket;
4416 uint32_t cbMax;
4417
4418 pbPacket = pAhciReq->aATAPICmd;
4419
4420 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
4421
4422 switch (pbPacket[0])
4423 {
4424 case SCSI_TEST_UNIT_READY:
4425 if (pAhciPort->cNotifiedMediaChange > 0)
4426 {
4427 if (pAhciPort->cNotifiedMediaChange-- > 2)
4428 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4429 else
4430 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4431 }
4432 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4433 atapiCmdOK(pAhciPort, pAhciReq);
4434 else
4435 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4436 break;
4437 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4438 cbMax = ataBE2H_U16(pbPacket + 7);
4439 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4440 break;
4441 case SCSI_MODE_SENSE_10:
4442 {
4443 uint8_t uPageControl, uPageCode;
4444 cbMax = ataBE2H_U16(pbPacket + 7);
4445 uPageControl = pbPacket[2] >> 6;
4446 uPageCode = pbPacket[2] & 0x3f;
4447 switch (uPageControl)
4448 {
4449 case SCSI_PAGECONTROL_CURRENT:
4450 switch (uPageCode)
4451 {
4452 case SCSI_MODEPAGE_ERROR_RECOVERY:
4453 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
4454 break;
4455 case SCSI_MODEPAGE_CD_STATUS:
4456 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
4457 break;
4458 default:
4459 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4460 break;
4461 }
4462 break;
4463 case SCSI_PAGECONTROL_CHANGEABLE:
4464 case SCSI_PAGECONTROL_DEFAULT:
4465 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4466 break;
4467 default:
4468 case SCSI_PAGECONTROL_SAVED:
4469 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
4470 break;
4471 }
4472 break;
4473 }
4474 case SCSI_REQUEST_SENSE:
4475 cbMax = pbPacket[4];
4476 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
4477 break;
4478 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4479 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4480 {
4481 if (pbPacket[4] & 1)
4482 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
4483 else
4484 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
4485 atapiCmdOK(pAhciPort, pAhciReq);
4486 }
4487 else
4488 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4489 break;
4490 case SCSI_READ_10:
4491 case SCSI_READ_12:
4492 {
4493 uint32_t cSectors, iATAPILBA;
4494
4495 if (pAhciPort->cNotifiedMediaChange > 0)
4496 {
4497 pAhciPort->cNotifiedMediaChange-- ;
4498 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4499 break;
4500 }
4501 if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4502 {
4503 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4504 break;
4505 }
4506 if (pbPacket[0] == SCSI_READ_10)
4507 cSectors = ataBE2H_U16(pbPacket + 7);
4508 else
4509 cSectors = ataBE2H_U32(pbPacket + 6);
4510 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4511 if (cSectors == 0)
4512 {
4513 atapiCmdOK(pAhciPort, pAhciReq);
4514 break;
4515 }
4516 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4517 {
4518 /* Rate limited logging, one log line per second. For
4519 * guests that insist on reading from places outside the
4520 * valid area this often generates too many release log
4521 * entries otherwise. */
4522 static uint64_t s_uLastLogTS = 0;
4523 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4524 {
4525 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4526 s_uLastLogTS = RTTimeMilliTS();
4527 }
4528 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4529 break;
4530 }
4531 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4532 enmType = PDMMEDIAEXIOREQTYPE_READ;
4533 break;
4534 }
4535 case SCSI_READ_CD:
4536 {
4537 uint32_t cSectors, iATAPILBA;
4538
4539 if (pAhciPort->cNotifiedMediaChange > 0)
4540 {
4541 pAhciPort->cNotifiedMediaChange-- ;
4542 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4543 break;
4544 }
4545 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4546 {
4547 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4548 break;
4549 }
4550 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
4551 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4552 if (cSectors == 0)
4553 {
4554 atapiCmdOK(pAhciPort, pAhciReq);
4555 break;
4556 }
4557 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4558 {
4559 /* Rate limited logging, one log line per second. For
4560 * guests that insist on reading from places outside the
4561 * valid area this often generates too many release log
4562 * entries otherwise. */
4563 static uint64_t s_uLastLogTS = 0;
4564 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4565 {
4566 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4567 s_uLastLogTS = RTTimeMilliTS();
4568 }
4569 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4570 break;
4571 }
4572 switch (pbPacket[9] & 0xf8)
4573 {
4574 case 0x00:
4575 /* nothing */
4576 atapiCmdOK(pAhciPort, pAhciReq);
4577 break;
4578 case 0x10:
4579 /* normal read */
4580 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4581 enmType = PDMMEDIAEXIOREQTYPE_READ;
4582 break;
4583 case 0xf8:
4584 /* read all data */
4585 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
4586 enmType = PDMMEDIAEXIOREQTYPE_READ;
4587 break;
4588 default:
4589 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
4590 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4591 break;
4592 }
4593 break;
4594 }
4595 case SCSI_SEEK_10:
4596 {
4597 uint32_t iATAPILBA;
4598 if (pAhciPort->cNotifiedMediaChange > 0)
4599 {
4600 pAhciPort->cNotifiedMediaChange-- ;
4601 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4602 break;
4603 }
4604 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4605 {
4606 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4607 break;
4608 }
4609 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4610 if (iATAPILBA > pAhciPort->cTotalSectors)
4611 {
4612 /* Rate limited logging, one log line per second. For
4613 * guests that insist on seeking to places outside the
4614 * valid area this often generates too many release log
4615 * entries otherwise. */
4616 static uint64_t s_uLastLogTS = 0;
4617 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4618 {
4619 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
4620 s_uLastLogTS = RTTimeMilliTS();
4621 }
4622 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4623 break;
4624 }
4625 atapiCmdOK(pAhciPort, pAhciReq);
4626 pAhciReq->cmdFis[AHCI_CMDFIS_STS] |= ATA_STAT_SEEK; /* Linux expects this. */
4627 break;
4628 }
4629 case SCSI_START_STOP_UNIT:
4630 {
4631 int rc = VINF_SUCCESS;
4632 switch (pbPacket[4] & 3)
4633 {
4634 case 0: /* 00 - Stop motor */
4635 case 1: /* 01 - Start motor */
4636 break;
4637 case 2: /* 10 - Eject media */
4638 {
4639 /* This must be done from EMT. */
4640 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4641 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
4642
4643 rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4644 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4645 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4646 Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
4647 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4648 {
4649 rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4650 (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
4651 pAhci->pMediaNotify, pAhciPort->iLUN);
4652 AssertRC(rc);
4653 }
4654 break;
4655 }
4656 case 3: /* 11 - Load media */
4657 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
4658 break;
4659 }
4660 if (RT_SUCCESS(rc))
4661 atapiCmdOK(pAhciPort, pAhciReq);
4662 else
4663 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4664 break;
4665 }
4666 case SCSI_MECHANISM_STATUS:
4667 {
4668 cbMax = ataBE2H_U16(pbPacket + 8);
4669 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4670 break;
4671 }
4672 case SCSI_READ_TOC_PMA_ATIP:
4673 {
4674 uint8_t format;
4675
4676 if (pAhciPort->cNotifiedMediaChange > 0)
4677 {
4678 pAhciPort->cNotifiedMediaChange-- ;
4679 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4680 break;
4681 }
4682 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4683 {
4684 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4685 break;
4686 }
4687 cbMax = ataBE2H_U16(pbPacket + 7);
4688 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
4689 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
4690 * the other field is clear... */
4691 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
4692 switch (format)
4693 {
4694 case 0:
4695 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
4696 break;
4697 case 1:
4698 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
4699 break;
4700 case 2:
4701 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
4702 break;
4703 default:
4704 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4705 break;
4706 }
4707 break;
4708 }
4709 case SCSI_READ_CAPACITY:
4710 if (pAhciPort->cNotifiedMediaChange > 0)
4711 {
4712 pAhciPort->cNotifiedMediaChange-- ;
4713 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4714 break;
4715 }
4716 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4717 {
4718 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4719 break;
4720 }
4721 atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
4722 break;
4723 case SCSI_READ_DISC_INFORMATION:
4724 if (pAhciPort->cNotifiedMediaChange > 0)
4725 {
4726 pAhciPort->cNotifiedMediaChange-- ;
4727 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4728 break;
4729 }
4730 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4731 {
4732 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4733 break;
4734 }
4735 cbMax = ataBE2H_U16(pbPacket + 7);
4736 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
4737 break;
4738 case SCSI_READ_TRACK_INFORMATION:
4739 if (pAhciPort->cNotifiedMediaChange > 0)
4740 {
4741 pAhciPort->cNotifiedMediaChange-- ;
4742 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4743 break;
4744 }
4745 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4746 {
4747 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4748 break;
4749 }
4750 cbMax = ataBE2H_U16(pbPacket + 7);
4751 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
4752 break;
4753 case SCSI_GET_CONFIGURATION:
4754 /* No media change stuff here, it can confuse Linux guests. */
4755 cbMax = ataBE2H_U16(pbPacket + 7);
4756 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
4757 break;
4758 case SCSI_INQUIRY:
4759 cbMax = pbPacket[4];
4760 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
4761 break;
4762 case SCSI_READ_DVD_STRUCTURE:
4763 cbMax = ataBE2H_U16(pbPacket + 8);
4764 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DVD_STRUCTURE);
4765 break;
4766 default:
4767 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4768 break;
4769 }
4770
4771 return enmType;
4772}
4773
4774/*
4775 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
4776 */
4777static PDMMEDIAEXIOREQTYPE atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4778{
4779 const uint8_t *pbPacket;
4780 uint32_t cSectors, iATAPILBA;
4781 uint32_t cbTransfer = 0;
4782 PDMMEDIAEXIOREQTYPE enmType = PDMMEDIAEXIOREQTYPE_INVALID;
4783 bool fSendCmd = false;
4784
4785 pbPacket = pAhciReq->aATAPICmd;
4786 switch (pbPacket[0])
4787 {
4788 case SCSI_BLANK:
4789 fSendCmd = true;
4790 break;
4791 case SCSI_CLOSE_TRACK_SESSION:
4792 fSendCmd = true;
4793 break;
4794 case SCSI_ERASE_10:
4795 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4796 cbTransfer = ataBE2H_U16(pbPacket + 7);
4797 Log2(("ATAPI PT: lba %d\n", iATAPILBA));
4798 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
4799 fSendCmd = true;
4800 break;
4801 case SCSI_FORMAT_UNIT:
4802 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4803 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
4804 fSendCmd = true;
4805 break;
4806 case SCSI_GET_CONFIGURATION:
4807 cbTransfer = ataBE2H_U16(pbPacket + 7);
4808 enmType = PDMMEDIAEXIOREQTYPE_READ;
4809 fSendCmd = true;
4810 break;
4811 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4812 cbTransfer = ataBE2H_U16(pbPacket + 7);
4813 if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
4814 {
4815 pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
4816 atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4817 break;
4818 }
4819 enmType = PDMMEDIAEXIOREQTYPE_READ;
4820 fSendCmd = true;
4821 break;
4822 case SCSI_GET_PERFORMANCE:
4823 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4824 enmType = PDMMEDIAEXIOREQTYPE_READ;
4825 fSendCmd = true;
4826 break;
4827 case SCSI_INQUIRY:
4828 cbTransfer = ataBE2H_U16(pbPacket + 3);
4829 enmType = PDMMEDIAEXIOREQTYPE_READ;
4830 fSendCmd = true;
4831 break;
4832 case SCSI_LOAD_UNLOAD_MEDIUM:
4833 fSendCmd = true;
4834 break;
4835 case SCSI_MECHANISM_STATUS:
4836 cbTransfer = ataBE2H_U16(pbPacket + 8);
4837 enmType = PDMMEDIAEXIOREQTYPE_READ;
4838 fSendCmd = true;
4839 break;
4840 case SCSI_MODE_SELECT_10:
4841 cbTransfer = ataBE2H_U16(pbPacket + 7);
4842 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
4843 fSendCmd = true;
4844 break;
4845 case SCSI_MODE_SENSE_10:
4846 cbTransfer = ataBE2H_U16(pbPacket + 7);
4847 enmType = PDMMEDIAEXIOREQTYPE_READ;
4848 fSendCmd = true;
4849 break;
4850 case SCSI_PAUSE_RESUME:
4851 fSendCmd = true;
4852 break;
4853 case SCSI_PLAY_AUDIO_10:
4854 fSendCmd = true;
4855 break;
4856 case SCSI_PLAY_AUDIO_12:
4857 fSendCmd = true;
4858 break;
4859 case SCSI_PLAY_AUDIO_MSF:
4860 fSendCmd = true;
4861 break;
4862 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4863 /** @todo do not forget to unlock when a VM is shut down */
4864 fSendCmd = true;
4865 break;
4866 case SCSI_READ_10:
4867 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4868 cSectors = ataBE2H_U16(pbPacket + 7);
4869 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4870 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4871 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4872 enmType = PDMMEDIAEXIOREQTYPE_READ;
4873 fSendCmd = true;
4874 break;
4875 case SCSI_READ_12:
4876 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4877 cSectors = ataBE2H_U32(pbPacket + 6);
4878 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4879 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4880 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4881 enmType = PDMMEDIAEXIOREQTYPE_READ;
4882 fSendCmd = true;
4883 break;
4884 case SCSI_READ_BUFFER:
4885 cbTransfer = ataBE2H_U24(pbPacket + 6);
4886 enmType = PDMMEDIAEXIOREQTYPE_READ;
4887 fSendCmd = true;
4888 break;
4889 case SCSI_READ_BUFFER_CAPACITY:
4890 cbTransfer = ataBE2H_U16(pbPacket + 7);
4891 enmType = PDMMEDIAEXIOREQTYPE_READ;
4892 fSendCmd = true;
4893 break;
4894 case SCSI_READ_CAPACITY:
4895 cbTransfer = 8;
4896 enmType = PDMMEDIAEXIOREQTYPE_READ;
4897 fSendCmd = true;
4898 break;
4899 case SCSI_READ_CD:
4900 case SCSI_READ_CD_MSF:
4901 {
4902 /* Get sector size based on the expected sector type field. */
4903 switch ((pbPacket[1] >> 2) & 0x7)
4904 {
4905 case 0x0: /* All types. */
4906 {
4907 uint32_t iLbaStart;
4908
4909 if (pbPacket[0] == SCSI_READ_CD)
4910 iLbaStart = ataBE2H_U32(&pbPacket[2]);
4911 else
4912 iLbaStart = ataMSF2LBA(&pbPacket[3]);
4913
4914 if (pAhciPort->pTrackList)
4915 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
4916 else
4917 pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
4918 break;
4919 }
4920 case 0x1: /* CD-DA */
4921 pAhciReq->cbATAPISector = 2352;
4922 break;
4923 case 0x2: /* Mode 1 */
4924 pAhciReq->cbATAPISector = 2048;
4925 break;
4926 case 0x3: /* Mode 2 formless */
4927 pAhciReq->cbATAPISector = 2336;
4928 break;
4929 case 0x4: /* Mode 2 form 1 */
4930 pAhciReq->cbATAPISector = 2048;
4931 break;
4932 case 0x5: /* Mode 2 form 2 */
4933 pAhciReq->cbATAPISector = 2324;
4934 break;
4935 default: /* Reserved */
4936 AssertMsgFailed(("Unknown sector type\n"));
4937 pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
4938 }
4939
4940 if (pbPacket[0] == SCSI_READ_CD)
4941 cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
4942 else /* SCSI_READ_MSF */
4943 {
4944 cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
4945 if (cSectors > 32)
4946 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
4947 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4948 }
4949 enmType = PDMMEDIAEXIOREQTYPE_READ;
4950 fSendCmd = true;
4951 break;
4952 }
4953 case SCSI_READ_DISC_INFORMATION:
4954 cbTransfer = ataBE2H_U16(pbPacket + 7);
4955 enmType = PDMMEDIAEXIOREQTYPE_READ;
4956 fSendCmd = true;
4957 break;
4958 case SCSI_READ_DVD_STRUCTURE:
4959 cbTransfer = ataBE2H_U16(pbPacket + 8);
4960 enmType = PDMMEDIAEXIOREQTYPE_READ;
4961 fSendCmd = true;
4962 break;
4963 case SCSI_READ_FORMAT_CAPACITIES:
4964 cbTransfer = ataBE2H_U16(pbPacket + 7);
4965 enmType = PDMMEDIAEXIOREQTYPE_READ;
4966 fSendCmd = true;
4967 break;
4968 case SCSI_READ_SUBCHANNEL:
4969 cbTransfer = ataBE2H_U16(pbPacket + 7);
4970 enmType = PDMMEDIAEXIOREQTYPE_READ;
4971 fSendCmd = true;
4972 break;
4973 case SCSI_READ_TOC_PMA_ATIP:
4974 cbTransfer = ataBE2H_U16(pbPacket + 7);
4975 enmType = PDMMEDIAEXIOREQTYPE_READ;
4976 fSendCmd = true;
4977 break;
4978 case SCSI_READ_TRACK_INFORMATION:
4979 cbTransfer = ataBE2H_U16(pbPacket + 7);
4980 enmType = PDMMEDIAEXIOREQTYPE_READ;
4981 fSendCmd = true;
4982 break;
4983 case SCSI_REPAIR_TRACK:
4984 fSendCmd = true;
4985 break;
4986 case SCSI_REPORT_KEY:
4987 cbTransfer = ataBE2H_U16(pbPacket + 8);
4988 enmType = PDMMEDIAEXIOREQTYPE_READ;
4989 fSendCmd = true;
4990 break;
4991 case SCSI_REQUEST_SENSE:
4992 cbTransfer = pbPacket[4];
4993 if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
4994 {
4995 pAhciReq->cbTransfer = cbTransfer;
4996 pAhciReq->enmType = PDMMEDIAEXIOREQTYPE_READ;
4997 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
4998 break;
4999 }
5000 enmType = PDMMEDIAEXIOREQTYPE_READ;
5001 fSendCmd = true;
5002 break;
5003 case SCSI_RESERVE_TRACK:
5004 fSendCmd = true;
5005 break;
5006 case SCSI_SCAN:
5007 fSendCmd = true;
5008 break;
5009 case SCSI_SEEK_10:
5010 fSendCmd = true;
5011 break;
5012 case SCSI_SEND_CUE_SHEET:
5013 cbTransfer = ataBE2H_U24(pbPacket + 6);
5014 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5015 fSendCmd = true;
5016 break;
5017 case SCSI_SEND_DVD_STRUCTURE:
5018 cbTransfer = ataBE2H_U16(pbPacket + 8);
5019 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5020 fSendCmd = true;
5021 break;
5022 case SCSI_SEND_EVENT:
5023 cbTransfer = ataBE2H_U16(pbPacket + 8);
5024 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5025 fSendCmd = true;
5026 break;
5027 case SCSI_SEND_KEY:
5028 cbTransfer = ataBE2H_U16(pbPacket + 8);
5029 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5030 fSendCmd = true;
5031 break;
5032 case SCSI_SEND_OPC_INFORMATION:
5033 cbTransfer = ataBE2H_U16(pbPacket + 7);
5034 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5035 fSendCmd = true;
5036 break;
5037 case SCSI_SET_CD_SPEED:
5038 fSendCmd = true;
5039 break;
5040 case SCSI_SET_READ_AHEAD:
5041 fSendCmd = true;
5042 break;
5043 case SCSI_SET_STREAMING:
5044 cbTransfer = ataBE2H_U16(pbPacket + 9);
5045 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5046 fSendCmd = true;
5047 break;
5048 case SCSI_START_STOP_UNIT:
5049 fSendCmd = true;
5050 break;
5051 case SCSI_STOP_PLAY_SCAN:
5052 fSendCmd = true;
5053 break;
5054 case SCSI_SYNCHRONIZE_CACHE:
5055 fSendCmd = true;
5056 break;
5057 case SCSI_TEST_UNIT_READY:
5058 fSendCmd = true;
5059 break;
5060 case SCSI_VERIFY_10:
5061 fSendCmd = true;
5062 break;
5063 case SCSI_WRITE_10:
5064 case SCSI_WRITE_AND_VERIFY_10:
5065 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5066 cSectors = ataBE2H_U16(pbPacket + 7);
5067 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5068 if (pAhciPort->pTrackList)
5069 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5070 else
5071 pAhciReq->cbATAPISector = 2048;
5072 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5073 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5074 fSendCmd = true;
5075 break;
5076 case SCSI_WRITE_12:
5077 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5078 cSectors = ataBE2H_U32(pbPacket + 6);
5079 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5080 if (pAhciPort->pTrackList)
5081 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5082 else
5083 pAhciReq->cbATAPISector = 2048;
5084 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5085 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5086 fSendCmd = true;
5087 break;
5088 case SCSI_WRITE_BUFFER:
5089 switch (pbPacket[1] & 0x1f)
5090 {
5091 case 0x04: /* download microcode */
5092 case 0x05: /* download microcode and save */
5093 case 0x06: /* download microcode with offsets */
5094 case 0x07: /* download microcode with offsets and save */
5095 case 0x0e: /* download microcode with offsets and defer activation */
5096 case 0x0f: /* activate deferred microcode */
5097 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
5098 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
5099 break;
5100 default:
5101 cbTransfer = ataBE2H_U16(pbPacket + 6);
5102 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
5103 fSendCmd = true;
5104 break;
5105 }
5106 break;
5107 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
5108 cbTransfer = ataBE2H_U32(pbPacket + 6);
5109 enmType = PDMMEDIAEXIOREQTYPE_READ;
5110 fSendCmd = true;
5111 break;
5112 case SCSI_REZERO_UNIT:
5113 /* Obsolete command used by cdrecord. What else would one expect?
5114 * This command is not sent to the drive, it is handled internally,
5115 * as the Linux kernel doesn't like it (message "scsi: unknown
5116 * opcode 0x01" in syslog) and replies with a sense code of 0,
5117 * which sends cdrecord to an endless loop. */
5118 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5119 break;
5120 default:
5121 LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
5122 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5123 break;
5124 }
5125
5126 if (fSendCmd)
5127 {
5128 /* Send a command to the drive, passing data in/out as required. */
5129 Log2(("ATAPI PT: max size %d\n", cbTransfer));
5130 if (cbTransfer == 0)
5131 enmType = PDMMEDIAEXIOREQTYPE_INVALID;
5132 pAhciReq->enmType = enmType;
5133 pAhciReq->cbTransfer = cbTransfer;
5134 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
5135 }
5136
5137 return PDMMEDIAEXIOREQTYPE_INVALID;
5138}
5139
5140static PDMMEDIAEXIOREQTYPE atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5141{
5142 PDMMEDIAEXIOREQTYPE enmType = PDMMEDIAEXIOREQTYPE_INVALID;
5143 const uint8_t *pbPacket;
5144
5145 pbPacket = pAhciReq->aATAPICmd;
5146 Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
5147 Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
5148
5149 if (pAhciPort->fATAPIPassthrough)
5150 enmType = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
5151 else
5152 enmType = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
5153
5154 return enmType;
5155}
5156
5157/**
5158 * Reset all values after a reset of the attached storage device.
5159 *
5160 * @returns nothing
5161 * @param pAhciPort The port the device is attached to.
5162 * @param pAhciReq The state to get the tag number from.
5163 */
5164static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5165{
5166 int rc;
5167
5168 /* Send a status good D2H FIS. */
5169 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
5170 pAhciPort->fResetDevice = false;
5171 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5172 ahciPostFirstD2HFisIntoMemory(pAhciPort);
5173
5174 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
5175 if (pAhciPort->fATAPI)
5176 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
5177 else
5178 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
5179 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5180
5181 rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5182 AssertRC(rc);
5183}
5184
5185/**
5186 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
5187 *
5188 * @returns nothing.
5189 * @param pAhciPort The device to reset.
5190 * @param pAhciReq The task state.
5191 */
5192static void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5193{
5194 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
5195
5196 /*
5197 * Because this ATAPI only and ATAPI can't have
5198 * more than one command active at a time the task counter should be 0
5199 * and it is possible to finish the reset now.
5200 */
5201 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
5202 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
5203}
5204
5205/**
5206 * Create a PIO setup FIS and post it into the memory area of the guest.
5207 *
5208 * @returns nothing.
5209 * @param pAhciPort The port of the SATA controller.
5210 * @param pAhciReq The state of the task.
5211 * @param pCmdFis Pointer to the command FIS from the guest.
5212 * @param fInterrupt If an interrupt should be send to the guest.
5213 */
5214static void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
5215 bool fInterrupt)
5216{
5217 uint8_t abPioSetupFis[20];
5218 bool fAssertIntr = false;
5219 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5220
5221 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
5222
5223 AssertMsg( pAhciReq->cbTransfer > 0
5224 && pAhciReq->cbTransfer <= 65534,
5225 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
5226
5227 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5228 {
5229 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
5230 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
5231 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5232 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ)
5233 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
5234 abPioSetupFis[AHCI_CMDFIS_STS] = pCmdFis[AHCI_CMDFIS_STS];
5235 abPioSetupFis[AHCI_CMDFIS_ERR] = pCmdFis[AHCI_CMDFIS_ERR];
5236 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5237 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5238 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5239 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5240 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5241 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5242 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5243 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5244 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5245
5246 /* Set transfer count. */
5247 abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
5248 abPioSetupFis[17] = pAhciReq->cbTransfer & 0xff;
5249
5250 /* Update registers. */
5251 pAhciPort->regTFD = (pCmdFis[AHCI_CMDFIS_ERR] << 8) | pCmdFis[AHCI_CMDFIS_STS];
5252
5253 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
5254
5255 if (fInterrupt)
5256 {
5257 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
5258 /* Check if we should assert an interrupt */
5259 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
5260 fAssertIntr = true;
5261 }
5262
5263 if (fAssertIntr)
5264 {
5265 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5266 AssertRC(rc);
5267 }
5268 }
5269}
5270
5271/**
5272 * Build a D2H FIS and post into the memory area of the guest.
5273 *
5274 * @returns Nothing
5275 * @param pAhciPort The port of the SATA controller.
5276 * @param pAhciReq The state of the task.
5277 * @param pCmdFis Pointer to the command FIS from the guest.
5278 * @param fInterrupt If an interrupt should be send to the guest.
5279 */
5280static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
5281{
5282 uint8_t d2hFis[20];
5283 bool fAssertIntr = false;
5284 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5285
5286 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
5287
5288 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5289 {
5290 memset(&d2hFis[0], 0, sizeof(d2hFis));
5291 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
5292 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5293 d2hFis[AHCI_CMDFIS_STS] = pCmdFis[AHCI_CMDFIS_STS];
5294 d2hFis[AHCI_CMDFIS_ERR] = pCmdFis[AHCI_CMDFIS_ERR];
5295 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5296 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5297 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5298 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5299 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5300 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5301 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5302 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5303 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5304
5305 /* Update registers. */
5306 pAhciPort->regTFD = (pCmdFis[AHCI_CMDFIS_ERR] << 8) | pCmdFis[AHCI_CMDFIS_STS];
5307
5308 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
5309
5310 if (pCmdFis[AHCI_CMDFIS_STS] & ATA_STAT_ERR)
5311 {
5312 /* Error bit is set. */
5313 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5314 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5315 fAssertIntr = true;
5316 /*
5317 * Don't mark the command slot as completed because the guest
5318 * needs it to identify the failed command.
5319 */
5320 }
5321 else if (fInterrupt)
5322 {
5323 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
5324 /* Check if we should assert an interrupt */
5325 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
5326 fAssertIntr = true;
5327
5328 /* Mark command as completed. */
5329 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5330 }
5331
5332 if (fAssertIntr)
5333 {
5334 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5335 AssertRC(rc);
5336 }
5337 }
5338}
5339
5340/**
5341 * Build a SDB Fis and post it into the memory area of the guest.
5342 *
5343 * @returns Nothing
5344 * @param pAhciPort The port for which the SDB Fis is send.
5345 * @param uFinishedTasks Bitmask of finished tasks.
5346 * @param fInterrupt If an interrupt should be asserted.
5347 */
5348static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
5349{
5350 uint32_t sdbFis[2];
5351 bool fAssertIntr = false;
5352 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5353 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
5354
5355 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
5356
5357 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5358 {
5359 memset(&sdbFis[0], 0, sizeof(sdbFis));
5360 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
5361 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
5362 if (RT_UNLIKELY(pTaskErr))
5363 {
5364 sdbFis[0] = pTaskErr->cmdFis[AHCI_CMDFIS_ERR];
5365 sdbFis[0] |= (pTaskErr->cmdFis[AHCI_CMDFIS_STS] & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
5366
5367 /* Update registers. */
5368 pAhciPort->regTFD = (pTaskErr->cmdFis[AHCI_CMDFIS_ERR] << 8) | pTaskErr->cmdFis[AHCI_CMDFIS_STS];
5369 }
5370 else
5371 {
5372 sdbFis[0] = 0;
5373 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
5374 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
5375 }
5376
5377 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
5378
5379 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
5380
5381 if (RT_UNLIKELY(pTaskErr))
5382 {
5383 /* Error bit is set. */
5384 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5385 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5386 fAssertIntr = true;
5387 }
5388
5389 if (fInterrupt)
5390 {
5391 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
5392 /* Check if we should assert an interrupt */
5393 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
5394 fAssertIntr = true;
5395 }
5396
5397 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
5398
5399 if (fAssertIntr)
5400 {
5401 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5402 AssertRC(rc);
5403 }
5404 }
5405}
5406
5407static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
5408{
5409 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
5410 if (fLBA48)
5411 {
5412 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
5413 return 65536;
5414 else
5415 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
5416 }
5417 else
5418 {
5419 if (!pCmdFis[AHCI_CMDFIS_SECTC])
5420 return 256;
5421 else
5422 return pCmdFis[AHCI_CMDFIS_SECTC];
5423 }
5424}
5425
5426static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
5427{
5428 uint64_t iLBA;
5429 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
5430 {
5431 /* any LBA variant */
5432 if (fLBA48)
5433 {
5434 /* LBA48 */
5435 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5436 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5437 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5438 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5439 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5440 pCmdFis[AHCI_CMDFIS_SECTN];
5441 }
5442 else
5443 {
5444 /* LBA */
5445 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5446 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
5447 }
5448 }
5449 else
5450 {
5451 /* CHS */
5452 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
5453 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
5454 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
5455 }
5456 return iLBA;
5457}
5458
5459static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
5460{
5461 uint64_t uLBA;
5462
5463 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5464 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5465 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5466 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5467 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5468 pCmdFis[AHCI_CMDFIS_SECTN];
5469
5470 return uLBA;
5471}
5472
5473DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
5474{
5475 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
5476 return 65536;
5477 else
5478 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
5479}
5480
5481/**
5482 * Copy from guest to host memory worker.
5483 *
5484 * @copydoc{AHCIR3MEMCOPYCALLBACK}
5485 */
5486static DECLCALLBACK(void) ahciR3CopyBufferFromGuestWorker(PAHCI pThis, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
5487 size_t cbCopy, size_t *pcbSkip)
5488{
5489 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
5490 cbCopy -= cbSkipped;
5491 GCPhys += cbSkipped;
5492 *pcbSkip -= cbSkipped;
5493
5494 while (cbCopy)
5495 {
5496 size_t cbSeg = cbCopy;
5497 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
5498
5499 AssertPtr(pvSeg);
5500 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhys, pvSeg, cbSeg);
5501 GCPhys += cbSeg;
5502 cbCopy -= cbSeg;
5503 }
5504}
5505
5506/**
5507 * Copy from host to guest memory worker.
5508 *
5509 * @copydoc{AHCIR3MEMCOPYCALLBACK}
5510 */
5511static DECLCALLBACK(void) ahciR3CopyBufferToGuestWorker(PAHCI pThis, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
5512 size_t cbCopy, size_t *pcbSkip)
5513{
5514 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
5515 cbCopy -= cbSkipped;
5516 GCPhys += cbSkipped;
5517 *pcbSkip -= cbSkipped;
5518
5519 while (cbCopy)
5520 {
5521 size_t cbSeg = cbCopy;
5522 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
5523
5524 AssertPtr(pvSeg);
5525 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhys, pvSeg, cbSeg);
5526 GCPhys += cbSeg;
5527 cbCopy -= cbSeg;
5528 }
5529}
5530
5531/**
5532 * Walks the PRDTL list copying data between the guest and host memory buffers.
5533 *
5534 * @returns Amount of bytes copied.
5535 * @param pThis The AHCI controller device instance.
5536 * @param pAhciReq AHCI request structure.
5537 * @param pfnCopyWorker The copy method to apply for each guest buffer.
5538 * @param pSgBuf The host S/G buffer.
5539 * @param cbSkip How many bytes to skip in advance before starting to copy.
5540 * @param cbCopy How many bytes to copy.
5541 */
5542static size_t ahciR3PrdtlWalk(PAHCI pThis, PAHCIREQ pAhciReq,
5543 PAHCIR3MEMCOPYCALLBACK pfnCopyWorker,
5544 PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
5545{
5546 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5547 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5548 size_t cbCopied = 0;
5549
5550 /*
5551 * Add the amount to skip to the host buffer size to avoid a
5552 * few conditionals later on.
5553 */
5554 cbCopy += cbSkip;
5555
5556 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5557
5558 do
5559 {
5560 SGLEntry aPrdtlEntries[32];
5561 uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
5562 ? cPrdtlEntries
5563 : RT_ELEMENTS(aPrdtlEntries);
5564
5565 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysPrdtl, &aPrdtlEntries[0],
5566 cPrdtlEntriesRead * sizeof(SGLEntry));
5567
5568 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbCopy; i++)
5569 {
5570 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5571 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5572
5573 cbThisCopy = (uint32_t)RT_MIN(cbThisCopy, cbCopy);
5574
5575 /* Copy into SG entry. */
5576 pfnCopyWorker(pThis, GCPhysAddrDataBase, pSgBuf, cbThisCopy, &cbSkip);
5577
5578 cbCopy -= cbThisCopy;
5579 cbCopied += cbThisCopy;
5580 }
5581
5582 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5583 cPrdtlEntries -= cPrdtlEntriesRead;
5584 } while (cPrdtlEntries && cbCopy);
5585
5586 if (cbCopied < cbCopy)
5587 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5588
5589 return cbCopied;
5590}
5591
5592/**
5593 * Copies a data buffer into the S/G buffer set up by the guest.
5594 *
5595 * @returns Amount of bytes copied to the PRDTL.
5596 * @param pThis The AHCI controller device instance.
5597 * @param pAhciReq AHCI request structure.
5598 * @param pSgBuf The S/G buffer to copy from.
5599 * @param cbSkip How many bytes to skip in advance before starting to copy.
5600 * @param cbCopy How many bytes to copy.
5601 */
5602static size_t ahciR3CopySgBufToPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, PRTSGBUF pSgBuf,
5603 size_t cbSkip, size_t cbCopy)
5604{
5605 return ahciR3PrdtlWalk(pThis, pAhciReq, ahciR3CopyBufferToGuestWorker,
5606 pSgBuf, cbSkip, cbCopy);
5607}
5608
5609/**
5610 * Copies the S/G buffer into a data buffer.
5611 *
5612 * @returns Amount of bytes copied from the PRDTL.
5613 * @param pThis The AHCI controller device instance.
5614 * @param pAhciReq AHCI request structure.
5615 * @param pSgBuf The S/G buffer to copy into.
5616 * @param cbSkip How many bytes to skip in advance before starting to copy.
5617 * @param cbCopy How many bytes to copy.
5618 */
5619static size_t ahciR3CopySgBufFromPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, PRTSGBUF pSgBuf,
5620 size_t cbSkip, size_t cbCopy)
5621{
5622 return ahciR3PrdtlWalk(pThis, pAhciReq, ahciR3CopyBufferFromGuestWorker,
5623 pSgBuf, cbSkip, cbCopy);
5624}
5625
5626/**
5627 * Copy a simple memory buffer to the guest memory buffer.
5628 *
5629 * @returns Amount of bytes copied from the PRDTL.
5630 * @param pThis The AHCI controller device instance.
5631 * @param pAhciReq AHCI request structure.
5632 * @param pvSrc The buffer to copy from.
5633 * @param cbSrc How many bytes to copy.
5634 * @param cbSkip How many bytes to skip initially.
5635 */
5636static size_t ahciR3CopyBufferToPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, const void *pvSrc,
5637 size_t cbSrc, size_t cbSkip)
5638{
5639 RTSGSEG Seg;
5640 RTSGBUF SgBuf;
5641 Seg.pvSeg = (void *)pvSrc;
5642 Seg.cbSeg = cbSrc;
5643 RTSgBufInit(&SgBuf, &Seg, 1);
5644 return ahciR3CopySgBufToPrdtl(pThis, pAhciReq, &SgBuf, cbSkip, cbSrc);
5645}
5646
5647/**
5648 * Copy a data from the geust memory buffer into a simple memory buffer.
5649 *
5650 * @returns Amount of bytes copied from the PRDTL.
5651 * @param pThis The AHCI controller device instance.
5652 * @param pAhciReq AHCI request structure.
5653 * @param pvDst The buffer to copy into.
5654 * @param cbDst How many bytes to copy.
5655 */
5656static size_t ahciR3CopyBufferFromPrdtl(PAHCI pThis, PAHCIREQ pAhciReq, void *pvDst,
5657 size_t cbDst)
5658{
5659 RTSGSEG Seg;
5660 RTSGBUF SgBuf;
5661 Seg.pvSeg = pvDst;
5662 Seg.cbSeg = cbDst;
5663 RTSgBufInit(&SgBuf, &Seg, 1);
5664 return ahciR3CopySgBufFromPrdtl(pThis, pAhciReq, &SgBuf, 0 /* cbSkip */, cbDst);
5665}
5666
5667/**
5668 * Cancels all active tasks on the port.
5669 *
5670 * @returns Whether all active tasks were canceled.
5671 * @param pAhciPort The AHCI port.
5672 * @param pAhciReqExcept The given request is excepted from the cancelling
5673 * (used for error page reading).
5674 */
5675static bool ahciCancelActiveTasks(PAHCIPort pAhciPort)
5676{
5677 if (pAhciPort->pDrvMediaEx)
5678 {
5679 int rc = pAhciPort->pDrvMediaEx->pfnIoReqCancelAll(pAhciPort->pDrvMediaEx);
5680 AssertRC(rc);
5681 }
5682 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
5683}
5684
5685/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
5686
5687/** Makes a PAHCIPort out of a PPDMIMEDIAASYNCPORT. */
5688#define PDMIMEDIAASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
5689
5690static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
5691{
5692 int rc;
5693 LogRel(("AHCI: Host disk full\n"));
5694 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
5695 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
5696 AssertRC(rc);
5697}
5698
5699static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
5700{
5701 int rc;
5702 LogRel(("AHCI: File too big\n"));
5703 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
5704 N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
5705 AssertRC(rc);
5706}
5707
5708static void ahciWarningISCSI(PPDMDEVINS pDevIns)
5709{
5710 int rc;
5711 LogRel(("AHCI: iSCSI target unavailable\n"));
5712 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
5713 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
5714 AssertRC(rc);
5715}
5716
5717bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
5718{
5719 if (rc == VERR_DISK_FULL)
5720 {
5721 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5722 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
5723 return true;
5724 }
5725 if (rc == VERR_FILE_TOO_BIG)
5726 {
5727 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5728 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
5729 return true;
5730 }
5731 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
5732 {
5733 /* iSCSI connection abort (first error) or failure to reestablish
5734 * connection (second error). Pause VM. On resume we'll retry. */
5735 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5736 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
5737 return true;
5738 }
5739 if (rc == VERR_VD_DEK_MISSING)
5740 {
5741 /* Error message already set. */
5742 ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false);
5743 return true;
5744 }
5745
5746 return false;
5747}
5748
5749/**
5750 * Creates the array of ranges to trim.
5751 *
5752 * @returns VBox status code.
5753 * @param pAhciPort AHCI port state.
5754 * @param pAhciReq The request handling the TRIM request.
5755 * @param idxRangeStart Index of the first range to start copying.
5756 * @param paRanges Where to store the ranges.
5757 * @param cRanges Number of ranges fitting into the array.
5758 * @param pcRanges Where to store the amount of ranges actually copied on success.
5759 */
5760static int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t idxRangeStart,
5761 PRTRANGE paRanges, uint32_t cRanges, uint32_t *pcRanges)
5762{
5763 SGLEntry aPrdtlEntries[32];
5764 uint64_t aRanges[64];
5765 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
5766 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5767 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
5768 int rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
5769 uint32_t idxRange = 0;
5770
5771 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
5772
5773 AssertMsgReturn(pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
5774
5775 if (!cPrdtlEntries)
5776 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5777
5778 /* Convert the ranges from ATA to our format. */
5779 while ( cPrdtlEntries
5780 && idxRange < cRanges)
5781 {
5782 uint32_t cPrdtlEntriesRead = RT_MIN(cPrdtlEntries, RT_ELEMENTS(aPrdtlEntries));
5783
5784 rc = VINF_SUCCESS;
5785 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5786
5787 for (uint32_t i = 0; i < cPrdtlEntriesRead && idxRange < cRanges; i++)
5788 {
5789 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5790 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5791
5792 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5793
5794 /* Copy into buffer. */
5795 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5796
5797 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges) && idxRange < cRanges; idxRangeSrc++)
5798 {
5799 /* Skip range if told to do so. */
5800 if (!idxRangeStart)
5801 {
5802 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
5803 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
5804 {
5805 paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
5806 paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
5807 idxRange++;
5808 }
5809 else
5810 break;
5811 }
5812 else
5813 idxRangeStart--;
5814 }
5815 }
5816
5817 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5818 cPrdtlEntries -= cPrdtlEntriesRead;
5819 }
5820
5821 *pcRanges = idxRange;
5822
5823 LogFlowFunc(("returns rc=%Rrc\n", rc));
5824 return rc;
5825}
5826
5827/**
5828 * Allocates a new AHCI request.
5829 *
5830 * @returns A new AHCI request structure or NULL if out of memory.
5831 * @param pAhciPort The AHCI port.
5832 * @param uTag The tag to assign.
5833 */
5834static PAHCIREQ ahciR3ReqAlloc(PAHCIPort pAhciPort, uint32_t uTag)
5835{
5836 PAHCIREQ pAhciReq = NULL;
5837 PDMMEDIAEXIOREQ hIoReq = NULL;
5838
5839 int rc = pAhciPort->pDrvMediaEx->pfnIoReqAlloc(pAhciPort->pDrvMediaEx, &hIoReq, (void **)&pAhciReq,
5840 uTag, 0 /* fFlags */);
5841 if (RT_SUCCESS(rc))
5842 {
5843 pAhciReq->hIoReq = hIoReq;
5844 pAhciReq->pfnPostProcess = NULL;
5845 }
5846 else
5847 pAhciReq = NULL;
5848 return pAhciReq;
5849}
5850
5851/**
5852 * Frees a given AHCI request structure.
5853 *
5854 * @returns nothing.
5855 * @param pAhciPort The AHCI port.
5856 */
5857static void ahciR3ReqFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5858{
5859 int rc = pAhciPort->pDrvMediaEx->pfnIoReqFree(pAhciPort->pDrvMediaEx, pAhciReq->hIoReq);
5860 AssertRC(rc);
5861}
5862
5863/**
5864 * Complete a data transfer task by freeing all occupied resources
5865 * and notifying the guest.
5866 *
5867 * @returns Flag whether the given request was canceled inbetween;
5868 *
5869 * @param pAhciPort Pointer to the port where to request completed.
5870 * @param pAhciReq Pointer to the task which finished.
5871 * @param rcReq IPRT status code of the completed request.
5872 */
5873static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq)
5874{
5875 bool fRedo = false;
5876 bool fCanceled = false;
5877
5878 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d\n",
5879 pAhciPort, pAhciReq, rcReq));
5880
5881 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, pAhciReq->uOffset, pAhciReq->cbTransfer);
5882
5883 if (rcReq != VERR_PDM_MEDIAEX_IOREQ_CANCELED)
5884 {
5885 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ)
5886 {
5887 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
5888 pAhciPort->Led.Actual.s.fReading = 0;
5889 }
5890 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_WRITE)
5891 {
5892 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
5893 pAhciPort->Led.Actual.s.fWriting = 0;
5894 }
5895 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
5896 pAhciPort->Led.Actual.s.fWriting = 0;
5897
5898 if (RT_FAILURE(rcReq))
5899 {
5900 /* Log the error. */
5901 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5902 {
5903 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
5904 LogRel(("AHCI#%uP%u: Flush returned rc=%Rrc\n",
5905 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
5906 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
5907 LogRel(("AHCI#%uP%u: Trim returned rc=%Rrc\n",
5908 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
5909 else
5910 LogRel(("AHCI#%uP%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
5911 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
5912 pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ
5913 ? "Read"
5914 : "Write",
5915 pAhciReq->uOffset,
5916 pAhciReq->cbTransfer, rcReq));
5917 }
5918
5919 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
5920 if (!fRedo)
5921 {
5922 ahciReqSetStatus(pAhciReq, ID_ERR, ATA_STAT_READY | ATA_STAT_ERR);
5923 /*
5924 * We have to duplicate the request here as the underlying I/O
5925 * request will be freed later.
5926 */
5927 PAHCIREQ pReqDup = (PAHCIREQ)RTMemDup(pAhciReq, sizeof(AHCIREQ));
5928 if ( pReqDup
5929 && !ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pReqDup, NULL))
5930 RTMemFree(pReqDup);
5931 }
5932 else
5933 ASMAtomicOrU32(&pAhciPort->u32TasksRedo, RT_BIT_32(pAhciReq->uTag));
5934 }
5935 else
5936 {
5937 /* Status will be set already for non I/O requests. */
5938 if (pAhciReq->enmType != PDMMEDIAEXIOREQTYPE_INVALID)
5939 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
5940
5941 /* Write updated command header into memory of the guest. */
5942 uint32_t u32PRDBC = pAhciReq->cbTransfer;
5943 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr + RT_OFFSETOF(CmdHdr, u32PRDBC),
5944 &u32PRDBC, sizeof(u32PRDBC));
5945
5946 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
5947 {
5948 /*
5949 * The guest tried to transfer more data than there is space in the buffer.
5950 * Terminate task and set the overflow bit.
5951 */
5952 /* Notify the guest. */
5953 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
5954 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
5955 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5956 }
5957 }
5958
5959 if (!fRedo)
5960 {
5961
5962 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
5963 if (pAhciReq->fFlags & AHCI_REQ_PIO_DATA)
5964 ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
5965
5966 if (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT)
5967 {
5968 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
5969 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
5970 }
5971
5972 if (pAhciReq->fFlags & AHCI_REQ_IS_QUEUED)
5973 {
5974 /*
5975 * Always raise an interrupt after task completion; delaying
5976 * this (interrupt coalescing) increases latency and has a significant
5977 * impact on performance (see @bugref{5071})
5978 */
5979 ahciSendSDBFis(pAhciPort, 0, true);
5980 }
5981 else
5982 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
5983 }
5984 }
5985 else
5986 {
5987 /*
5988 * Task was canceled, do the cleanup but DO NOT access the guest memory!
5989 * The guest might use it for other things now because it doesn't know about that task anymore.
5990 */
5991 fCanceled = true;
5992
5993 /* Leave a log message about the canceled request. */
5994 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5995 {
5996 if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
5997 LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
5998 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
5999 else if (pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
6000 LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
6001 pAhciPort->CTX_SUFF(pDevIns)->iInstance,pAhciPort->iLUN, rcReq));
6002 else
6003 LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6004 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6005 pAhciReq->enmType == PDMMEDIAEXIOREQTYPE_READ
6006 ? "read"
6007 : "write",
6008 pAhciReq->uOffset,
6009 pAhciReq->cbTransfer, rcReq));
6010 }
6011 }
6012
6013 /*
6014 * Decrement the active task counter as the last step or we might run into a
6015 * hang during power off otherwise (see @bugref{7859}).
6016 * Before it could happen that we signal PDM that we are done while we still have to
6017 * copy the data to the guest but EMT might be busy destroying the driver chains
6018 * below us while we have to delegate copying data to EMT instead of doing it
6019 * on this thread.
6020 */
6021 ASMAtomicDecU32(&pAhciPort->cTasksActive);
6022
6023 if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
6024 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6025
6026 /* Don't free the request if it is on the stack. */
6027 if ( pAhciReq
6028 && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK))
6029 ahciR3ReqFree(pAhciPort, pAhciReq);
6030 return fCanceled;
6031}
6032
6033/**
6034 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
6035 */
6036static DECLCALLBACK(int) ahciR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
6037 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
6038 size_t cbCopy)
6039{
6040 RT_NOREF1(hIoReq);
6041 PAHCIPort pAhciPort = RT_FROM_MEMBER(pInterface, AHCIPort, IMediaExPort);
6042 int rc = VINF_SUCCESS;
6043 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
6044
6045 if (!pIoReq->pfnPostProcess)
6046 ahciR3CopySgBufToPrdtl(pAhciPort->CTX_SUFF(pAhci), pIoReq, pSgBuf, offDst, cbCopy);
6047 else
6048 {
6049 /* Post process data and copy afterwards. */
6050 void *pv = NULL;
6051 size_t cb = 0;
6052 rc = pIoReq->pfnPostProcess(pIoReq, pSgBuf, cbCopy, offDst, &pv, &cb);
6053 if (RT_SUCCESS(rc))
6054 {
6055 ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pIoReq, pv, cb, offDst);
6056 RTMemFree(pv);
6057 }
6058 }
6059
6060 if (pIoReq->fFlags & AHCI_REQ_OVERFLOW)
6061 rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
6062
6063 return rc;
6064}
6065
6066/**
6067 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
6068 */
6069static DECLCALLBACK(int) ahciR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
6070 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
6071 size_t cbCopy)
6072{
6073 RT_NOREF1(hIoReq);
6074 PAHCIPort pAhciPort = RT_FROM_MEMBER(pInterface, AHCIPort, IMediaExPort);
6075 int rc = VINF_SUCCESS;
6076 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
6077
6078 ahciR3CopySgBufFromPrdtl(pAhciPort->CTX_SUFF(pAhci), pIoReq, pSgBuf, offSrc, cbCopy);
6079 if (pIoReq->fFlags & AHCI_REQ_OVERFLOW)
6080 rc = VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
6081
6082 return rc;
6083}
6084
6085/**
6086 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
6087 */
6088static DECLCALLBACK(int) ahciR3IoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
6089 void *pvIoReqAlloc, uint32_t idxRangeStart,
6090 uint32_t cRanges, PRTRANGE paRanges,
6091 uint32_t *pcRanges)
6092{
6093 RT_NOREF1(hIoReq);
6094 PAHCIPort pAhciPort = RT_FROM_MEMBER(pInterface, AHCIPort, IMediaExPort);
6095 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
6096
6097 return ahciTrimRangesCreate(pAhciPort, pIoReq, idxRangeStart, paRanges, cRanges, pcRanges);
6098}
6099
6100/**
6101 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
6102 */
6103static DECLCALLBACK(int) ahciR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
6104 void *pvIoReqAlloc, int rcReq)
6105{
6106 RT_NOREF(hIoReq);
6107 PAHCIPort pAhciPort = RT_FROM_MEMBER(pInterface, AHCIPort, IMediaExPort);
6108 ahciTransferComplete(pAhciPort, (PAHCIREQ)pvIoReqAlloc, rcReq);
6109 return VINF_SUCCESS;
6110}
6111
6112/**
6113 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
6114 */
6115static DECLCALLBACK(void) ahciR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
6116 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
6117{
6118 RT_NOREF(hIoReq);
6119 PAHCIPort pAhciPort = RT_FROM_MEMBER(pInterface, AHCIPort, IMediaExPort);
6120 PAHCIREQ pIoReq = (PAHCIREQ)pvIoReqAlloc;
6121
6122 RT_NOREF3(pAhciPort, pIoReq, enmState);
6123 AssertLogRelMsgFailed(("This should not be hit because I/O requests should not be suspended\n"));
6124}
6125
6126
6127/**
6128 * Process an non read/write ATA command.
6129 *
6130 * @returns The direction of the data transfer
6131 * @param pCmdHdr Pointer to the command header.
6132 */
6133static PDMMEDIAEXIOREQTYPE ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
6134{
6135 PDMMEDIAEXIOREQTYPE enmType = PDMMEDIAEXIOREQTYPE_INVALID;
6136 bool fLBA48 = false;
6137
6138 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
6139
6140 pAhciReq->cbTransfer = 0;
6141
6142 switch (pCmdFis[AHCI_CMDFIS_CMD])
6143 {
6144 case ATA_IDENTIFY_DEVICE:
6145 {
6146 if (pAhciPort->pDrvMedia && !pAhciPort->fATAPI)
6147 {
6148 uint16_t u16Temp[256];
6149
6150 /* Fill the buffer. */
6151 ahciIdentifySS(pAhciPort, u16Temp);
6152
6153 /* Copy the buffer. */
6154 uint32_t cbCopied = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq,
6155 &u16Temp[0], sizeof(u16Temp), 0 /* cbSkip */);
6156
6157 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6158 pAhciReq->cbTransfer = cbCopied;
6159 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6160 }
6161 else
6162 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR);
6163 break;
6164 }
6165 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
6166 case ATA_READ_NATIVE_MAX_ADDRESS:
6167 break;
6168 case ATA_SET_FEATURES:
6169 {
6170 switch (pCmdFis[AHCI_CMDFIS_FET])
6171 {
6172 case 0x02: /* write cache enable */
6173 case 0xaa: /* read look-ahead enable */
6174 case 0x55: /* read look-ahead disable */
6175 case 0xcc: /* reverting to power-on defaults enable */
6176 case 0x66: /* reverting to power-on defaults disable */
6177 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6178 break;
6179 case 0x82: /* write cache disable */
6180 enmType = PDMMEDIAEXIOREQTYPE_FLUSH;
6181 break;
6182 case 0x03:
6183 {
6184 /* set transfer mode */
6185 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6186 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
6187 {
6188 case 0x00: /* PIO default */
6189 case 0x08: /* PIO mode */
6190 break;
6191 case ATA_MODE_MDMA: /* MDMA mode */
6192 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
6193 break;
6194 case ATA_MODE_UDMA: /* UDMA mode */
6195 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6196 break;
6197 }
6198 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6199 break;
6200 }
6201 default:
6202 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6203 }
6204 break;
6205 }
6206 case ATA_DEVICE_RESET:
6207 {
6208 if (!pAhciPort->fATAPI)
6209 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6210 else
6211 {
6212 /* Reset the device. */
6213 ahciDeviceReset(pAhciPort, pAhciReq);
6214 }
6215 break;
6216 }
6217 case ATA_FLUSH_CACHE_EXT:
6218 case ATA_FLUSH_CACHE:
6219 enmType = PDMMEDIAEXIOREQTYPE_FLUSH;
6220 break;
6221 case ATA_PACKET:
6222 if (!pAhciPort->fATAPI)
6223 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6224 else
6225 enmType = atapiParseCmd(pAhciPort, pAhciReq);
6226 break;
6227 case ATA_IDENTIFY_PACKET_DEVICE:
6228 if (!pAhciPort->fATAPI)
6229 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6230 else
6231 {
6232 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6233
6234 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6235 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6236 }
6237 break;
6238 case ATA_SET_MULTIPLE_MODE:
6239 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
6240 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
6241 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6242 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6243 else
6244 {
6245 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6246 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6247 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6248 }
6249 break;
6250 case ATA_STANDBY_IMMEDIATE:
6251 break; /* Do nothing. */
6252 case ATA_CHECK_POWER_MODE:
6253 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
6254 /* fall through */
6255 case ATA_INITIALIZE_DEVICE_PARAMETERS:
6256 case ATA_IDLE_IMMEDIATE:
6257 case ATA_RECALIBRATE:
6258 case ATA_NOP:
6259 case ATA_READ_VERIFY_SECTORS_EXT:
6260 case ATA_READ_VERIFY_SECTORS:
6261 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
6262 case ATA_SLEEP:
6263 ahciReqSetStatus(pAhciReq, 0, ATA_STAT_READY | ATA_STAT_SEEK);
6264 break;
6265 case ATA_READ_DMA_EXT:
6266 fLBA48 = true;
6267 case ATA_READ_DMA:
6268 {
6269 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6270 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6271 enmType = PDMMEDIAEXIOREQTYPE_READ;
6272 break;
6273 }
6274 case ATA_WRITE_DMA_EXT:
6275 fLBA48 = true;
6276 case ATA_WRITE_DMA:
6277 {
6278 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6279 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6280 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
6281 break;
6282 }
6283 case ATA_READ_FPDMA_QUEUED:
6284 {
6285 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6286 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6287 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6288 enmType = PDMMEDIAEXIOREQTYPE_READ;
6289 break;
6290 }
6291 case ATA_WRITE_FPDMA_QUEUED:
6292 {
6293 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6294 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6295 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6296 enmType = PDMMEDIAEXIOREQTYPE_WRITE;
6297 break;
6298 }
6299 case ATA_READ_LOG_EXT:
6300 {
6301 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6302 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6303 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6304
6305 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6306
6307 uint8_t aBuf[512];
6308
6309 memset(aBuf, 0, sizeof(aBuf));
6310
6311 if (offLogRead + cbLogRead <= sizeof(aBuf))
6312 {
6313 switch (iPage)
6314 {
6315 case 0x10:
6316 {
6317 LogFlow(("Reading error page\n"));
6318 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6319 if (pTaskErr)
6320 {
6321 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6322 aBuf[2] = pTaskErr->cmdFis[AHCI_CMDFIS_STS];
6323 aBuf[3] = pTaskErr->cmdFis[AHCI_CMDFIS_ERR];
6324 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6325 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6326 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6327 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6328 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6329 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6330 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6331 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6332 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6333
6334 /* Calculate checksum */
6335 uint8_t uChkSum = 0;
6336 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6337 uChkSum += aBuf[i];
6338
6339 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6340
6341 /* Finally free the error task state structure because it is completely unused now. */
6342 RTMemFree(pTaskErr);
6343 }
6344
6345 /*
6346 * Reading this log page results in an abort of all outstanding commands
6347 * and clearing the SActive register and TaskFile register.
6348 *
6349 * See SATA2 1.2 spec chapter 4.2.3.4
6350 */
6351 bool fAbortedAll = ahciCancelActiveTasks(pAhciPort);
6352 Assert(fAbortedAll); NOREF(fAbortedAll);
6353 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6354
6355 break;
6356 }
6357 }
6358
6359 /* Copy the buffer. */
6360 uint32_t cbCopied = ahciR3CopyBufferToPrdtl(pAhciPort->CTX_SUFF(pAhci), pAhciReq,
6361 &aBuf[offLogRead], cbLogRead, 0 /* cbSkip */);
6362
6363 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6364 pAhciReq->cbTransfer = cbCopied;
6365 }
6366
6367 break;
6368 }
6369 case ATA_DATA_SET_MANAGEMENT:
6370 {
6371 if (pAhciPort->fTrimEnabled)
6372 {
6373 /* Check that the trim bit is set and all other bits are 0. */
6374 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6375 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6376 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6377 else
6378 enmType = PDMMEDIAEXIOREQTYPE_DISCARD;
6379 break;
6380 }
6381 /* else: fall through and report error to the guest. */
6382 }
6383 /* All not implemented commands go below. */
6384 case ATA_SECURITY_FREEZE_LOCK:
6385 case ATA_SMART:
6386 case ATA_NV_CACHE:
6387 case ATA_IDLE:
6388 case ATA_TRUSTED_RECEIVE_DMA: /* Windows 8+ */
6389 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6390 break;
6391 default: /* For debugging purposes. */
6392 AssertMsgFailed(("Unknown command issued (%#x)\n", pCmdFis[AHCI_CMDFIS_CMD]));
6393 ahciReqSetStatus(pAhciReq, ABRT_ERR, ATA_STAT_READY | ATA_STAT_ERR);
6394 }
6395
6396 return enmType;
6397}
6398
6399/**
6400 * Retrieve a command FIS from guest memory.
6401 *
6402 * @returns whether the H2D FIS was successfully read from the guest memory.
6403 * @param pAhciReq The state of the actual task.
6404 */
6405static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6406{
6407 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
6408 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
6409 false);
6410
6411 /*
6412 * First we are reading the command header pointed to by regCLB.
6413 * From this we get the address of the command table which we are reading too.
6414 * We can process the Command FIS afterwards.
6415 */
6416 CmdHdr cmdHdr;
6417 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6418 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6419 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6420 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &cmdHdr, sizeof(CmdHdr));
6421
6422#ifdef LOG_ENABLED
6423 /* Print some infos about the command header. */
6424 ahciDumpCmdHdrInfo(pAhciPort, &cmdHdr);
6425#endif
6426
6427 RTGCPHYS GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(cmdHdr.u32CmdTblAddrUp, cmdHdr.u32CmdTblAddr);
6428
6429 AssertMsgReturn((cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6430 ("This is not a command FIS!!\n"),
6431 false);
6432
6433 /* Read the command Fis. */
6434 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6435 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6436
6437 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
6438 ("This is not a command FIS\n"),
6439 false);
6440
6441 /* Set transfer direction. */
6442 pAhciReq->enmType = (cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMMEDIAEXIOREQTYPE_WRITE : PDMMEDIAEXIOREQTYPE_READ;
6443
6444 /* If this is an ATAPI command read the atapi command. */
6445 if (cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6446 {
6447 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6448 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6449 }
6450
6451 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6452 if ((cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6453 {
6454 /*
6455 * 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.
6456 * but this FIS does not assert an interrupt
6457 */
6458 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6459 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6460 }
6461
6462 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(cmdHdr.u32CmdTblAddrUp, cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6463 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(cmdHdr.u32DescInf);
6464
6465#ifdef LOG_ENABLED
6466 /* Print some infos about the FIS. */
6467 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6468
6469 /* Print the PRDT */
6470 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6471 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6472
6473 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6474 {
6475 SGLEntry SGEntry;
6476
6477 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6478 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6479
6480 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6481 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6482
6483 GCPhysPrdtl += sizeof(SGLEntry);
6484 }
6485#endif
6486
6487 return true;
6488}
6489
6490/**
6491 * Submits a given request for execution.
6492 *
6493 * @returns Flag whether the request was canceled inbetween.
6494 * @param pAhciPort The port the request is for.
6495 * @param pAhciReq The request to submit.
6496 * @param enmType The request type.
6497 */
6498static bool ahciR3ReqSubmit(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, PDMMEDIAEXIOREQTYPE enmType)
6499{
6500 int rc = VINF_SUCCESS;
6501 bool fReqCanceled = false;
6502
6503 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, pAhciReq->enmType, pAhciReq->uOffset, pAhciReq->cbTransfer);
6504
6505 if (enmType == PDMMEDIAEXIOREQTYPE_FLUSH)
6506 rc = pAhciPort->pDrvMediaEx->pfnIoReqFlush(pAhciPort->pDrvMediaEx, pAhciReq->hIoReq);
6507 else if (enmType == PDMMEDIAEXIOREQTYPE_DISCARD)
6508 {
6509 uint32_t cRangesMax;
6510
6511 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
6512 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
6513 cRangesMax = 65536 * 512 / 8;
6514 else
6515 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
6516
6517 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6518 rc = pAhciPort->pDrvMediaEx->pfnIoReqDiscard(pAhciPort->pDrvMediaEx, pAhciReq->hIoReq,
6519 cRangesMax);
6520 }
6521 else if (enmType == PDMMEDIAEXIOREQTYPE_READ)
6522 {
6523 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6524 rc = pAhciPort->pDrvMediaEx->pfnIoReqRead(pAhciPort->pDrvMediaEx, pAhciReq->hIoReq,
6525 pAhciReq->uOffset, pAhciReq->cbTransfer);
6526 }
6527 else
6528 {
6529 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6530 rc = pAhciPort->pDrvMediaEx->pfnIoReqWrite(pAhciPort->pDrvMediaEx, pAhciReq->hIoReq,
6531 pAhciReq->uOffset, pAhciReq->cbTransfer);
6532 }
6533
6534 if (rc == VINF_SUCCESS)
6535 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6536 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
6537 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc);
6538
6539 return fReqCanceled;
6540}
6541
6542/**
6543 * Prepares the command for execution coping it from guest memory and doing a few
6544 * validation checks on it.
6545 *
6546 * @returns Whether the command was successfully fetched from guest memory and
6547 * can be continued.
6548 * @param pAhciPort The AHCI port the request is for.
6549 * @param pAhciReq Request structure to copy the command to.
6550 */
6551static bool ahciR3CmdPrepare(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6552{
6553 /* Set current command slot */
6554 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6555
6556 bool fContinue = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6557 if (fContinue)
6558 {
6559 /* 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. */
6560 if (pAhciPort->regSACT & RT_BIT_32(pAhciReq->uTag))
6561 {
6562 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6563 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(pAhciReq->uTag));
6564 }
6565
6566 if (pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
6567 {
6568 /*
6569 * It is possible that the request counter can get one higher than the maximum because
6570 * the request counter is decremented after the guest was notified about the completed
6571 * request (see @bugref{7859}). If the completing thread is preempted in between the
6572 * guest might already issue another request before the request counter is decremented
6573 * which would trigger the following assertion incorrectly in the past.
6574 */
6575 AssertLogRelMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) <= AHCI_NR_COMMAND_SLOTS,
6576 ("AHCI#%uP%u: There are more than %u (+1) requests active",
6577 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6578 AHCI_NR_COMMAND_SLOTS));
6579 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6580 }
6581 else
6582 {
6583 /* If the reset bit is set put the device into reset state. */
6584 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6585 {
6586 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6587 pAhciPort->fResetDevice = true;
6588 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6589 }
6590 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6591 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6592 else /* We are not in a reset state update the control registers. */
6593 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6594
6595 fContinue = false;
6596 }
6597 }
6598 else
6599 {
6600 /*
6601 * Couldn't find anything in either the AHCI or SATA spec which
6602 * indicates what should be done if the FIS is not read successfully.
6603 * The closest thing is in the state machine, stating that the device
6604 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
6605 * Do the same here and ignore any corrupt FIS types, after all
6606 * the guest messed up everything and this behavior is undefined.
6607 */
6608 fContinue = false;
6609 }
6610
6611 return fContinue;
6612}
6613
6614/**
6615 * Transmit queue consumer
6616 * Queue a new async task.
6617 *
6618 * @returns Success indicator.
6619 * If false the item will not be removed and the flushing will stop.
6620 * @param pDevIns The device instance.
6621 * @param pItem The item to consume. Upon return this item will be freed.
6622 */
6623static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6624{
6625 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6626 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6627 PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
6628 int rc = VINF_SUCCESS;
6629
6630 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6631 /* Notify the async IO thread. */
6632 rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6633 AssertRC(rc);
6634
6635 return true;
6636}
6637
6638/* The async IO thread for one port. */
6639static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6640{
6641 RT_NOREF(pDevIns);
6642 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6643 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6644 int rc = VINF_SUCCESS;
6645
6646 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6647
6648 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6649 return VINF_SUCCESS;
6650
6651 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6652 {
6653 unsigned idx = 0;
6654 uint32_t u32Tasks = 0;
6655 uint32_t u32RegHbaCtrl = 0;
6656
6657 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
6658 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6659 if (!u32Tasks)
6660 {
6661 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
6662 rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
6663 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
6664 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
6665 break;
6666 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
6667 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6668 }
6669
6670 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
6671 ASMAtomicIncU32(&pAhci->cThreadsActive);
6672
6673 /* Check whether the thread should be suspended. */
6674 if (pAhci->fSignalIdle)
6675 {
6676 if (!ASMAtomicDecU32(&pAhci->cThreadsActive))
6677 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6678 continue;
6679 }
6680
6681 /*
6682 * Check whether the global host controller bit is set and go to sleep immediately again
6683 * if it is set.
6684 */
6685 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6686 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
6687 && !ASMAtomicDecU32(&pAhci->cThreadsActive))
6688 {
6689 ahciHBAReset(pAhci);
6690 if (pAhci->fSignalIdle)
6691 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6692 continue;
6693 }
6694
6695 idx = ASMBitFirstSetU32(u32Tasks);
6696 while ( idx
6697 && !pAhciPort->fPortReset)
6698 {
6699 bool fReqCanceled = false;
6700
6701 /* Decrement to get the slot number. */
6702 idx--;
6703 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6704
6705 PAHCIREQ pAhciReq = ahciR3ReqAlloc(pAhciPort, idx);
6706 if (RT_LIKELY(pAhciReq))
6707 {
6708 pAhciReq->uTag = idx;
6709 pAhciReq->fFlags = 0;
6710
6711 bool fContinue = ahciR3CmdPrepare(pAhciPort, pAhciReq);
6712 if (fContinue)
6713 {
6714 PDMMEDIAEXIOREQTYPE enmType = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6715 pAhciReq->enmType = enmType;
6716
6717 if (enmType != PDMMEDIAEXIOREQTYPE_INVALID)
6718 fReqCanceled = ahciR3ReqSubmit(pAhciPort, pAhciReq, enmType);
6719 else
6720 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6721 } /* Command */
6722 else
6723 ahciR3ReqFree(pAhciPort, pAhciReq);
6724 }
6725 else /* !Request allocated, use on stack variant to signal the error. */
6726 {
6727 AHCIREQ Req;
6728 Req.uTag = idx;
6729 Req.fFlags = AHCI_REQ_IS_ON_STACK;
6730
6731 bool fContinue = ahciR3CmdPrepare(pAhciPort, &Req);
6732 if (fContinue)
6733 fReqCanceled = ahciTransferComplete(pAhciPort, &Req, VERR_NO_MEMORY);
6734 }
6735
6736 /*
6737 * Don't process other requests if the last one was canceled,
6738 * the others are not valid anymore.
6739 */
6740 if (fReqCanceled)
6741 break;
6742
6743 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6744 idx = ASMBitFirstSetU32(u32Tasks);
6745 } /* while tasks available */
6746
6747 /* Check whether a port reset was active. */
6748 if ( ASMAtomicReadBool(&pAhciPort->fPortReset)
6749 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
6750 ahciPortResetFinish(pAhciPort);
6751
6752 /*
6753 * Check whether a host controller reset is pending and execute the reset
6754 * if this is the last active thread.
6755 */
6756 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6757 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
6758 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
6759 && !cThreadsActive)
6760 ahciHBAReset(pAhci);
6761
6762 if (!cThreadsActive && pAhci->fSignalIdle)
6763 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6764 } /* While running */
6765
6766 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
6767 return VINF_SUCCESS;
6768}
6769
6770/**
6771 * Unblock the async I/O thread so it can respond to a state change.
6772 *
6773 * @returns VBox status code.
6774 * @param pDevIns The device instance.
6775 * @param pThread The send thread.
6776 */
6777static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6778{
6779 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6780 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6781 return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6782}
6783
6784/* -=-=-=-=- DBGF -=-=-=-=- */
6785
6786/**
6787 * AHCI status info callback.
6788 *
6789 * @param pDevIns The device instance.
6790 * @param pHlp The output helpers.
6791 * @param pszArgs The arguments.
6792 */
6793static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6794{
6795 RT_NOREF(pszArgs);
6796 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6797
6798 /*
6799 * Show info.
6800 */
6801 pHlp->pfnPrintf(pHlp,
6802 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
6803 pDevIns->pReg->szName,
6804 pDevIns->iInstance,
6805 pThis->MMIOBase,
6806 pThis->cPortsImpl,
6807 pThis->fGCEnabled ? true : false,
6808 pThis->fR0Enabled ? true : false);
6809
6810 /*
6811 * Show global registers.
6812 */
6813 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
6814 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
6815 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
6816 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
6817 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
6818 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
6819 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
6820 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
6821
6822 /*
6823 * Per port data.
6824 */
6825 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
6826 {
6827 PAHCIPort pThisPort = &pThis->ahciPort[i];
6828
6829 pHlp->pfnPrintf(pHlp, "Port %d: device-attached=%RTbool\n",
6830 pThisPort->iLUN, pThisPort->pDrvBase != NULL);
6831 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
6832 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
6833 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
6834 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
6835 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
6836 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
6837 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
6838 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
6839 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
6840 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
6841 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
6842 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
6843 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
6844 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
6845 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
6846 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
6847 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
6848 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
6849 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
6850 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
6851 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
6852 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
6853 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
6854 pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
6855 pHlp->pfnPrintf(pHlp, "\n");
6856 }
6857}
6858
6859/* -=-=-=-=- Helper -=-=-=-=- */
6860
6861/**
6862 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
6863 *
6864 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
6865 * use of it in strict builds (which is why it's up here).
6866 *
6867 * @returns true if quiesced, false if busy.
6868 * @param pDevIns The device instance.
6869 */
6870static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
6871{
6872 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6873
6874 if (pThis->cThreadsActive)
6875 return false;
6876
6877 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
6878 {
6879 PAHCIPort pThisPort = &pThis->ahciPort[i];
6880 if (pThisPort->pDrvBase)
6881 {
6882 if ( (pThisPort->cTasksActive != 0)
6883 || (pThisPort->u32TasksNew != 0))
6884 return false;
6885 }
6886 }
6887 return true;
6888}
6889
6890/* -=-=-=-=- Saved State -=-=-=-=- */
6891
6892/**
6893 * @callback_method_impl{FNSSMDEVSAVEPREP}
6894 */
6895static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6896{
6897 RT_NOREF(pDevIns, pSSM);
6898 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6899 return VINF_SUCCESS;
6900}
6901
6902/**
6903 * @callback_method_impl{FNSSMDEVLOADPREP}
6904 */
6905static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6906{
6907 RT_NOREF(pDevIns, pSSM);
6908 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6909 return VINF_SUCCESS;
6910}
6911
6912/**
6913 * @callback_method_impl{FNSSMDEVLIVEEXEC}
6914 */
6915static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6916{
6917 RT_NOREF(uPass);
6918 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6919
6920 /* config. */
6921 SSMR3PutU32(pSSM, pThis->cPortsImpl);
6922 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6923 {
6924 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
6925 SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
6926 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6927 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6928 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6929 }
6930
6931 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6932 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6933 {
6934 uint32_t iPort;
6935 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6936 AssertRCReturn(rc, rc);
6937 SSMR3PutU32(pSSM, iPort);
6938 }
6939
6940 return VINF_SSM_DONT_CALL_AGAIN;
6941}
6942
6943/**
6944 * @callback_method_impl{FNSSMDEVSAVEEXEC}
6945 */
6946static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6947{
6948 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6949 uint32_t i;
6950 int rc;
6951
6952 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6953
6954 /* The config */
6955 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6956 AssertRCReturn(rc, rc);
6957
6958 /* The main device structure. */
6959 SSMR3PutU32(pSSM, pThis->regHbaCap);
6960 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
6961 SSMR3PutU32(pSSM, pThis->regHbaIs);
6962 SSMR3PutU32(pSSM, pThis->regHbaPi);
6963 SSMR3PutU32(pSSM, pThis->regHbaVs);
6964 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
6965 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
6966 SSMR3PutU8(pSSM, pThis->uCccPortNr);
6967 SSMR3PutU64(pSSM, pThis->uCccTimeout);
6968 SSMR3PutU32(pSSM, pThis->uCccNr);
6969 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
6970 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
6971 SSMR3PutBool(pSSM, pThis->fReset);
6972 SSMR3PutBool(pSSM, pThis->f64BitAddr);
6973 SSMR3PutBool(pSSM, pThis->fR0Enabled);
6974 SSMR3PutBool(pSSM, pThis->fGCEnabled);
6975 SSMR3PutBool(pSSM, pThis->fLegacyPortResetMethod);
6976
6977 /* Now every port. */
6978 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6979 {
6980 Assert(pThis->ahciPort[i].cTasksActive == 0);
6981 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
6982 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
6983 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
6984 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
6985 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6986 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6987 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
6988 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
6989 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
6990 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
6991 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
6992 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
6993 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
6994 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
6995 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
6996 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
6997 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
6998 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
6999 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
7000 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
7001 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
7002 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
7003 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
7004 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
7005 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
7006 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
7007 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
7008 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
7009
7010 /* ATAPI saved state. */
7011 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
7012 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
7013 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
7014 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
7015 }
7016
7017 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
7018}
7019
7020/**
7021 * Loads a saved legacy ATA emulated device state.
7022 *
7023 * @returns VBox status code.
7024 * @param pSSM The handle to the saved state.
7025 */
7026static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
7027{
7028 int rc;
7029 uint32_t u32Version;
7030 uint32_t u32;
7031 uint32_t u32IOBuffer;
7032
7033 /* Test for correct version. */
7034 rc = SSMR3GetU32(pSSM, &u32Version);
7035 AssertRCReturn(rc, rc);
7036 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
7037
7038 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
7039 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
7040 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7041 {
7042 AssertMsgFailed(("u32Version=%d\n", u32Version));
7043 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7044 }
7045
7046 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
7047
7048 for (uint32_t j = 0; j < 2; j++)
7049 {
7050 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
7051
7052 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
7053 SSMR3Skip(pSSM, 64);
7054 else
7055 SSMR3Skip(pSSM, 2);
7056 /** @todo triple-check this hack after passthrough is working */
7057 SSMR3Skip(pSSM, 1);
7058
7059 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7060 SSMR3Skip(pSSM, 4);
7061
7062 SSMR3Skip(pSSM, sizeof(PDMLED));
7063 SSMR3GetU32(pSSM, &u32IOBuffer);
7064 if (u32IOBuffer)
7065 SSMR3Skip(pSSM, u32IOBuffer);
7066 }
7067
7068 rc = SSMR3GetU32(pSSM, &u32);
7069 if (RT_FAILURE(rc))
7070 return rc;
7071 if (u32 != ~0U)
7072 {
7073 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
7074 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
7075 return rc;
7076 }
7077
7078 return VINF_SUCCESS;
7079}
7080
7081/**
7082 * @callback_method_impl{FNSSMDEVLOADEXEC}
7083 */
7084static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
7085{
7086 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7087 uint32_t u32;
7088 int rc;
7089
7090 if ( uVersion > AHCI_SAVED_STATE_VERSION
7091 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
7092 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7093
7094 /* Deal with the priod after removing the saved IDE bits where the saved
7095 state version remained unchanged. */
7096 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
7097 && SSMR3HandleRevision(pSSM) >= 79045
7098 && SSMR3HandleRevision(pSSM) < 79201)
7099 uVersion++;
7100
7101 /*
7102 * Check whether we have to resort to the legacy port reset method to
7103 * prevent older BIOS versions from failing after a reset.
7104 */
7105 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7106 pThis->fLegacyPortResetMethod = true;
7107
7108 /* Verify config. */
7109 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
7110 {
7111 rc = SSMR3GetU32(pSSM, &u32);
7112 AssertRCReturn(rc, rc);
7113 if (u32 != pThis->cPortsImpl)
7114 {
7115 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
7116 if ( u32 < pThis->cPortsImpl
7117 || u32 > AHCI_MAX_NR_PORTS_IMPL)
7118 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
7119 u32, pThis->cPortsImpl);
7120 }
7121
7122 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7123 {
7124 bool fInUse;
7125 rc = SSMR3GetBool(pSSM, &fInUse);
7126 AssertRCReturn(rc, rc);
7127 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
7128 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7129 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
7130 fInUse ? "target" : "source", i );
7131
7132 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
7133 {
7134 bool fHotpluggable;
7135 rc = SSMR3GetBool(pSSM, &fHotpluggable);
7136 AssertRCReturn(rc, rc);
7137 if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
7138 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7139 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
7140 i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
7141 }
7142 else
7143 Assert(pThis->ahciPort[i].fHotpluggable);
7144
7145 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
7146 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
7147 AssertRCReturn(rc, rc);
7148 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
7149 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
7150 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
7151
7152 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
7153 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
7154 AssertRCReturn(rc, rc);
7155 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
7156 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
7157 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
7158
7159 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
7160 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
7161 AssertRCReturn(rc, rc);
7162 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
7163 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
7164 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
7165 }
7166
7167 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7168 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7169 {
7170 uint32_t iPort;
7171 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7172 AssertRCReturn(rc, rc);
7173
7174 uint32_t iPortSaved;
7175 rc = SSMR3GetU32(pSSM, &iPortSaved);
7176 AssertRCReturn(rc, rc);
7177
7178 if (iPortSaved != iPort)
7179 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
7180 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
7181 }
7182 }
7183
7184 if (uPass == SSM_PASS_FINAL)
7185 {
7186 /* Restore data. */
7187
7188 /* The main device structure. */
7189 SSMR3GetU32(pSSM, &pThis->regHbaCap);
7190 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
7191 SSMR3GetU32(pSSM, &pThis->regHbaIs);
7192 SSMR3GetU32(pSSM, &pThis->regHbaPi);
7193 SSMR3GetU32(pSSM, &pThis->regHbaVs);
7194 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
7195 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
7196 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
7197 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
7198 SSMR3GetU32(pSSM, &pThis->uCccNr);
7199 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
7200
7201 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
7202 SSMR3GetBool(pSSM, &pThis->fReset);
7203 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
7204 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
7205 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
7206 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7207 SSMR3GetBool(pSSM, &pThis->fLegacyPortResetMethod);
7208
7209 /* Now every port. */
7210 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7211 {
7212 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7213
7214 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
7215 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
7216 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
7217 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
7218 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
7219 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
7220 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
7221 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
7222 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
7223 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
7224 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
7225 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
7226 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
7227 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
7228 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
7229 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
7230 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
7231 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
7232 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
7233 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
7234 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
7235 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7236 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7237
7238 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7239 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7240
7241 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7242 {
7243 /* The old positions in the FIFO, not required. */
7244 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7245 }
7246 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7247 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7248 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7249 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7250
7251 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7252 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7253
7254 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7255 {
7256 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7257 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7258 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7259 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7260 }
7261 else if (pThis->ahciPort[i].fATAPI)
7262 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=false config=true"));
7263
7264 /* Check if we have tasks pending. */
7265 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7266 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7267
7268 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7269
7270 if (pAhciPort->u32TasksNew)
7271 {
7272 /*
7273 * There are tasks pending. The VM was saved after a task failed
7274 * because of non-fatal error. Set the redo flag.
7275 */
7276 pAhciPort->fRedo = true;
7277 }
7278 }
7279
7280 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7281 {
7282 for (uint32_t i = 0; i < 2; i++)
7283 {
7284 rc = ahciR3LoadLegacyEmulationState(pSSM);
7285 if(RT_FAILURE(rc))
7286 return rc;
7287 }
7288 }
7289
7290 rc = SSMR3GetU32(pSSM, &u32);
7291 if (RT_FAILURE(rc))
7292 return rc;
7293 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7294 }
7295
7296 return VINF_SUCCESS;
7297}
7298
7299/* -=-=-=-=- device PDM interface -=-=-=-=- */
7300
7301static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7302{
7303 uint32_t i;
7304 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7305
7306 pAhci->pDevInsRC += offDelta;
7307 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7308 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7309
7310 /* Relocate every port. */
7311 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7312 {
7313 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7314 pAhciPort->pAhciRC += offDelta;
7315 pAhciPort->pDevInsRC += offDelta;
7316 }
7317}
7318
7319/**
7320 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7321 * from now on, regardless if there was a medium inserted or not.
7322 */
7323static void ahciMediumRemoved(PAHCIPort pAhciPort)
7324{
7325 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7326}
7327
7328/**
7329 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7330 * there was already a medium inserted, don't forget to send the "medium
7331 * removed" event first.
7332 */
7333static void ahciMediumInserted(PAHCIPort pAhciPort)
7334{
7335 uint32_t OldStatus, NewStatus;
7336 do
7337 {
7338 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7339 switch (OldStatus)
7340 {
7341 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7342 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7343 /* no change, we will send "medium removed" + "medium inserted" */
7344 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7345 break;
7346 default:
7347 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7348 break;
7349 }
7350 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7351}
7352
7353/**
7354 * Called when a media is mounted.
7355 *
7356 * @param pInterface Pointer to the interface structure containing the called function pointer.
7357 */
7358static DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
7359{
7360 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7361 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7362
7363 /* Ignore the call if we're called while being attached. */
7364 if (!pAhciPort->pDrvMedia)
7365 return;
7366
7367 if (pAhciPort->fATAPI)
7368 {
7369 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7370
7371 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7372
7373 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7374 if (pAhciPort->cNotifiedMediaChange < 2)
7375 pAhciPort->cNotifiedMediaChange = 2;
7376 ahciMediumInserted(pAhciPort);
7377 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7378 }
7379 else
7380 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7381}
7382
7383/**
7384 * Called when a media is unmounted
7385 * @param pInterface Pointer to the interface structure containing the called function pointer.
7386 */
7387static DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7388{
7389 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7390 Log(("%s:\n", __FUNCTION__));
7391
7392 pAhciPort->cTotalSectors = 0;
7393
7394 if (pAhciPort->fATAPI)
7395 {
7396 /*
7397 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7398 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7399 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7400 * present and 2 in which it is changed.
7401 */
7402 pAhciPort->cNotifiedMediaChange = 4;
7403 ahciMediumRemoved(pAhciPort);
7404 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7405 }
7406 else
7407 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7408}
7409
7410/**
7411 * Configure the attached device for a port.
7412 *
7413 * Used by ahciR3Construct and ahciR3Attach.
7414 *
7415 * @returns VBox status code
7416 * @param pDevIns The device instance data.
7417 * @param pAhciPort The port for which the device is to be configured.
7418 */
7419static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7420{
7421 /* Query the media interface. */
7422 pAhciPort->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIA);
7423 AssertMsgReturn(VALID_PTR(pAhciPort->pDrvMedia),
7424 ("AHCI configuration error: LUN#%d misses the basic media interface!\n", pAhciPort->iLUN),
7425 VERR_PDM_MISSING_INTERFACE);
7426
7427 /* Get the extended media interface. */
7428 pAhciPort->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIAEX);
7429 AssertMsgReturn(VALID_PTR(pAhciPort->pDrvMediaEx),
7430 ("AHCI configuration error: LUN#%d misses the extended media interface!\n", pAhciPort->iLUN),
7431 VERR_PDM_MISSING_INTERFACE);
7432
7433 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7434
7435 /*
7436 * Validate type.
7437 */
7438 PDMMEDIATYPE enmType = pAhciPort->pDrvMedia->pfnGetType(pAhciPort->pDrvMedia);
7439 AssertMsgReturn(enmType == PDMMEDIATYPE_HARD_DISK || enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD,
7440 ("AHCI configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%u\n", pAhciPort->iLUN, enmType),
7441 VERR_PDM_UNSUPPORTED_BLOCK_TYPE);
7442 AssertMsgReturn(enmType == PDMMEDIATYPE_HARD_DISK || pAhciPort->pDrvMount,
7443 ("AHCI configuration error: LUN#%d is CD/DVD-ROM without a mountable interface\n", pAhciPort->iLUN),
7444 VERR_INTERNAL_ERROR);
7445
7446 int rc = pAhciPort->pDrvMediaEx->pfnIoReqAllocSizeSet(pAhciPort->pDrvMediaEx, sizeof(AHCIREQ));
7447 if (RT_FAILURE(rc))
7448 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7449 N_("AHCI configuration error: LUN#%u: Failed to set I/O request size!"),
7450 pAhciPort->iLUN);
7451
7452 uint32_t fFeatures = 0;
7453 rc = pAhciPort->pDrvMediaEx->pfnQueryFeatures(pAhciPort->pDrvMediaEx, &fFeatures);
7454 if (RT_FAILURE(rc))
7455 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7456 N_("AHCI configuration error: LUN#%u: Failed to query features of device"),
7457 pAhciPort->iLUN);
7458
7459 if (fFeatures & PDMIMEDIAEX_FEATURE_F_DISCARD)
7460 pAhciPort->fTrimEnabled = true;
7461
7462 pAhciPort->fATAPI = (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD);
7463 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? !!(fFeatures & PDMIMEDIAEX_FEATURE_F_RAWSCSICMD) : false;
7464 if (pAhciPort->fATAPI)
7465 {
7466 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7467 pAhciPort->PCHSGeometry.cCylinders = 0;
7468 pAhciPort->PCHSGeometry.cHeads = 0;
7469 pAhciPort->PCHSGeometry.cSectors = 0;
7470 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN,
7471 pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7472 }
7473 else
7474 {
7475 pAhciPort->cbSector = pAhciPort->pDrvMedia->pfnGetSectorSize(pAhciPort->pDrvMedia);
7476 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / pAhciPort->cbSector;
7477 rc = pAhciPort->pDrvMedia->pfnBiosGetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7478 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7479 {
7480 pAhciPort->PCHSGeometry.cCylinders = 0;
7481 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7482 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7483 }
7484 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7485 {
7486 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7487 rc = VINF_SUCCESS;
7488 }
7489 AssertRC(rc);
7490
7491 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7492 || pAhciPort->PCHSGeometry.cHeads == 0
7493 || pAhciPort->PCHSGeometry.cSectors == 0)
7494 {
7495 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7496 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7497 pAhciPort->PCHSGeometry.cHeads = 16;
7498 pAhciPort->PCHSGeometry.cSectors = 63;
7499 /* Set the disk geometry information. Ignore errors. */
7500 pAhciPort->pDrvMedia->pfnBiosSetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7501 rc = VINF_SUCCESS;
7502 }
7503 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7504 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7505 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7506 pAhciPort->cTotalSectors));
7507 if (pAhciPort->fTrimEnabled)
7508 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7509 }
7510 return rc;
7511}
7512
7513/**
7514 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7515 *
7516 * @returns true if we've quiesced, false if we're still working.
7517 * @param pDevIns The device instance.
7518 */
7519static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7520{
7521 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7522 return false;
7523
7524 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7525 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7526 return true;
7527}
7528
7529/**
7530 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7531 */
7532static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7533{
7534 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7535
7536 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7537 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7538 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7539 else
7540 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7541}
7542
7543/**
7544 * Suspend notification.
7545 *
7546 * @param pDevIns The device instance data.
7547 */
7548static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7549{
7550 Log(("ahciR3Suspend\n"));
7551 ahciR3SuspendOrPowerOff(pDevIns);
7552}
7553
7554/**
7555 * Resume notification.
7556 *
7557 * @param pDevIns The device instance data.
7558 */
7559static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7560{
7561 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7562
7563 /*
7564 * Check if one of the ports has pending tasks.
7565 * Queue a notification item again in this case.
7566 */
7567 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7568 {
7569 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7570
7571 if (pAhciPort->u32TasksRedo)
7572 {
7573 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7574 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7575
7576 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
7577 pAhciPort->u32TasksRedo = 0;
7578
7579 Assert(pAhciPort->fRedo);
7580 pAhciPort->fRedo = false;
7581
7582 pItem->iPort = pAhci->ahciPort[i].iLUN;
7583 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7584 }
7585 }
7586
7587 Log(("%s:\n", __FUNCTION__));
7588}
7589
7590/**
7591 * Initializes the VPD data of a attached device.
7592 *
7593 * @returns VBox status code.
7594 * @param pDevIns The device instance.
7595 * @param pAhciPort The attached device.
7596 * @param szName Name of the port to get the CFGM node.
7597 */
7598static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7599{
7600
7601 /* Generate a default serial number. */
7602 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7603 RTUUID Uuid;
7604
7605 int rc = VINF_SUCCESS;
7606 if (pAhciPort->pDrvMedia)
7607 rc = pAhciPort->pDrvMedia->pfnGetUuid(pAhciPort->pDrvMedia, &Uuid);
7608 else
7609 RTUuidClear(&Uuid);
7610
7611 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7612 {
7613 /* Generate a predictable serial for drives which don't have a UUID. */
7614 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7615 pAhciPort->iLUN);
7616 }
7617 else
7618 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7619
7620 /* Get user config if present using defaults otherwise. */
7621 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7622 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7623 szSerial);
7624 if (RT_FAILURE(rc))
7625 {
7626 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7627 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7628 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7629 return PDMDEV_SET_ERROR(pDevIns, rc,
7630 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7631 }
7632
7633 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7634 "1.0");
7635 if (RT_FAILURE(rc))
7636 {
7637 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7638 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7639 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7640 return PDMDEV_SET_ERROR(pDevIns, rc,
7641 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7642 }
7643
7644 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7645 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7646 if (RT_FAILURE(rc))
7647 {
7648 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7649 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7650 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7651 return PDMDEV_SET_ERROR(pDevIns, rc,
7652 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7653 }
7654
7655 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7656 if (RT_FAILURE(rc))
7657 return PDMDEV_SET_ERROR(pDevIns, rc,
7658 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7659
7660 rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
7661 if (RT_FAILURE(rc))
7662 return PDMDEV_SET_ERROR(pDevIns, rc,
7663 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
7664 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
7665 return PDMDEV_SET_ERROR(pDevIns, rc,
7666 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
7667
7668 /* There are three other identification strings for CD drives used for INQUIRY */
7669 if (pAhciPort->fATAPI)
7670 {
7671 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7672 "VBOX");
7673 if (RT_FAILURE(rc))
7674 {
7675 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7676 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7677 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7678 return PDMDEV_SET_ERROR(pDevIns, rc,
7679 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7680 }
7681
7682 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7683 "CD-ROM");
7684 if (RT_FAILURE(rc))
7685 {
7686 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7687 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7688 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7689 return PDMDEV_SET_ERROR(pDevIns, rc,
7690 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7691 }
7692
7693 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7694 "1.0");
7695 if (RT_FAILURE(rc))
7696 {
7697 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7698 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7699 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7700 return PDMDEV_SET_ERROR(pDevIns, rc,
7701 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7702 }
7703 }
7704
7705 return rc;
7706}
7707
7708
7709/**
7710 * Detach notification.
7711 *
7712 * One harddisk at one port has been unplugged.
7713 * The VM is suspended at this point.
7714 *
7715 * @param pDevIns The device instance.
7716 * @param iLUN The logical unit which is being detached.
7717 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7718 */
7719static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7720{
7721 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7722 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7723 int rc = VINF_SUCCESS;
7724
7725 Log(("%s:\n", __FUNCTION__));
7726
7727 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7728 AssertMsgReturnVoid( pAhciPort->fHotpluggable
7729 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7730 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
7731
7732
7733 if (pAhciPort->pAsyncIOThread)
7734 {
7735 int rcThread;
7736 /* Destroy the thread. */
7737 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
7738 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
7739 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
7740
7741 pAhciPort->pAsyncIOThread = NULL;
7742 pAhciPort->fWrkThreadSleeping = true;
7743 }
7744
7745 if (pAhciPort->fATAPI)
7746 ahciMediumRemoved(pAhciPort);
7747
7748 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7749 {
7750 /*
7751 * Inform the guest about the removed device.
7752 */
7753 pAhciPort->regSSTS = 0;
7754 pAhciPort->regSIG = 0;
7755 /*
7756 * Clear CR bit too to prevent submission of new commands when CI is written
7757 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
7758 */
7759 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
7760 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7761 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7762 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7763 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7764 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7765 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7766 }
7767
7768 /*
7769 * Zero some important members.
7770 */
7771 pAhciPort->pDrvBase = NULL;
7772 pAhciPort->pDrvMedia = NULL;
7773 pAhciPort->pDrvMediaEx = NULL;
7774}
7775
7776/**
7777 * Attach command.
7778 *
7779 * This is called when we change block driver for one port.
7780 * The VM is suspended at this point.
7781 *
7782 * @returns VBox status code.
7783 * @param pDevIns The device instance.
7784 * @param iLUN The logical unit which is being detached.
7785 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7786 */
7787static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7788{
7789 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7790 PAHCIPort pAhciPort = &pThis->ahciPort[iLUN];
7791 int rc;
7792
7793 Log(("%s:\n", __FUNCTION__));
7794
7795 /* the usual paranoia */
7796 AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
7797 AssertRelease(!pAhciPort->pDrvBase);
7798 AssertRelease(!pAhciPort->pDrvMedia);
7799 AssertRelease(!pAhciPort->pDrvMediaEx);
7800 Assert(pAhciPort->iLUN == iLUN);
7801
7802 AssertMsgReturn( pAhciPort->fHotpluggable
7803 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7804 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7805 VERR_INVALID_PARAMETER);
7806
7807 /*
7808 * Try attach the block device and get the interfaces,
7809 * required as well as optional.
7810 */
7811 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
7812 if (RT_SUCCESS(rc))
7813 {
7814 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
7815
7816 /*
7817 * In case there is a medium inserted.
7818 */
7819 ahciMediumInserted(pAhciPort);
7820 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7821 }
7822 else
7823 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
7824
7825 if (RT_FAILURE(rc))
7826 {
7827 pAhciPort->pDrvBase = NULL;
7828 pAhciPort->pDrvMedia = NULL;
7829 }
7830 else
7831 {
7832 char szName[24];
7833 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
7834
7835 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
7836 if (RT_FAILURE(rc))
7837 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7838 N_("AHCI: Failed to create SUP event semaphore"));
7839
7840 /* Create the async IO thread. */
7841 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
7842 RTTHREADTYPE_IO, szName);
7843 if (RT_FAILURE(rc))
7844 return rc;
7845
7846 /*
7847 * Init vendor product data.
7848 */
7849 if (RT_SUCCESS(rc))
7850 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
7851
7852 /* Inform the guest about the added device in case of hotplugging. */
7853 if ( RT_SUCCESS(rc)
7854 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7855 {
7856 AssertMsgReturn(pAhciPort->fHotpluggable,
7857 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7858 VERR_NOT_SUPPORTED);
7859
7860 /*
7861 * Initialize registers
7862 */
7863 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
7864 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7865 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7866
7867 if (pAhciPort->fATAPI)
7868 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
7869 else
7870 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
7871 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
7872 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
7873 (0x03 << 0); /* Device detected and communication established. */
7874
7875 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7876 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7877 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7878 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7879 }
7880
7881 }
7882
7883 return rc;
7884}
7885
7886/**
7887 * Common reset worker.
7888 *
7889 * @param pDevIns The device instance data.
7890 */
7891static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
7892{
7893 RT_NOREF(fConstructor);
7894 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7895
7896 ahciHBAReset(pAhci);
7897
7898 /* Hardware reset for the ports. */
7899 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7900 ahciPortHwReset(&pAhci->ahciPort[i]);
7901 return VINF_SUCCESS;
7902}
7903
7904/**
7905 * Callback employed by ahciR3Reset.
7906 *
7907 * @returns true if we've quiesced, false if we're still working.
7908 * @param pDevIns The device instance.
7909 */
7910static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
7911{
7912 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7913
7914 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7915 return false;
7916 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7917
7918 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7919 return true;
7920}
7921
7922/**
7923 * Reset notification.
7924 *
7925 * @param pDevIns The device instance data.
7926 */
7927static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
7928{
7929 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7930
7931 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7932 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7933 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
7934 else
7935 {
7936 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7937 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7938 }
7939}
7940
7941/**
7942 * Poweroff notification.
7943 *
7944 * @param pDevIns Pointer to the device instance
7945 */
7946static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
7947{
7948 Log(("achiR3PowerOff\n"));
7949 ahciR3SuspendOrPowerOff(pDevIns);
7950}
7951
7952/**
7953 * Destroy a driver instance.
7954 *
7955 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
7956 * resources can be freed correctly.
7957 *
7958 * @param pDevIns The device instance data.
7959 */
7960static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
7961{
7962 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7963 int rc = VINF_SUCCESS;
7964 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
7965
7966 /*
7967 * At this point the async I/O thread is suspended and will not enter
7968 * this module again. So, no coordination is needed here and PDM
7969 * will take care of terminating and cleaning up the thread.
7970 */
7971 if (PDMCritSectIsInitialized(&pThis->lock))
7972 {
7973 TMR3TimerDestroy(pThis->CTX_SUFF(pHbaCccTimer));
7974 pThis->CTX_SUFF(pHbaCccTimer) = NULL;
7975
7976 Log(("%s: Destruct every port\n", __FUNCTION__));
7977 for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
7978 {
7979 PAHCIPort pAhciPort = &pThis->ahciPort[iActPort];
7980
7981 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
7982 {
7983 SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
7984 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
7985 }
7986 }
7987
7988 PDMR3CritSectDelete(&pThis->lock);
7989 }
7990
7991 return rc;
7992}
7993
7994/**
7995 * @interface_method_impl{PDMDEVREG,pfnConstruct}
7996 */
7997static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
7998{
7999 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8000 PPDMIBASE pBase;
8001 int rc = VINF_SUCCESS;
8002 unsigned i = 0;
8003 bool fGCEnabled = false;
8004 bool fR0Enabled = false;
8005 uint32_t cbTotalBufferSize = 0;
8006 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
8007
8008 LogFlowFunc(("pThis=%#p\n", pThis));
8009
8010 /*
8011 * Validate and read configuration.
8012 */
8013 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
8014 "R0Enabled\0"
8015 "PrimaryMaster\0"
8016 "PrimarySlave\0"
8017 "SecondaryMaster\0"
8018 "SecondarySlave\0"
8019 "PortCount\0"
8020 "Bootable\0"
8021 "CmdSlotsAvail\0"))
8022 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
8023 N_("AHCI configuration error: unknown option specified"));
8024
8025 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
8026 if (RT_FAILURE(rc))
8027 return PDMDEV_SET_ERROR(pDevIns, rc,
8028 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
8029 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
8030
8031 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
8032 if (RT_FAILURE(rc))
8033 return PDMDEV_SET_ERROR(pDevIns, rc,
8034 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
8035 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
8036
8037 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8038 if (RT_FAILURE(rc))
8039 return PDMDEV_SET_ERROR(pDevIns, rc,
8040 N_("AHCI configuration error: failed to read PortCount as integer"));
8041 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
8042 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
8043 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8044 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
8045 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8046 if (pThis->cPortsImpl < 1)
8047 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8048 N_("AHCI configuration error: PortCount=%u should be at least 1"),
8049 pThis->cPortsImpl);
8050
8051 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
8052 if (RT_FAILURE(rc))
8053 return PDMDEV_SET_ERROR(pDevIns, rc,
8054 N_("AHCI configuration error: failed to read Bootable as boolean"));
8055
8056 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
8057 if (RT_FAILURE(rc))
8058 return PDMDEV_SET_ERROR(pDevIns, rc,
8059 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
8060 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
8061 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
8062 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8063 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
8064 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
8065 if (pThis->cCmdSlotsAvail < 1)
8066 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8067 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
8068 pThis->cCmdSlotsAvail);
8069
8070 /*
8071 * Initialize the instance data (everything touched by the destructor need
8072 * to be initialized here!).
8073 */
8074 pThis->fR0Enabled = fR0Enabled;
8075 pThis->fGCEnabled = fGCEnabled;
8076 pThis->pDevInsR3 = pDevIns;
8077 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8078 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8079 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
8080
8081 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
8082 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
8083 PCIDevSetCommand (&pThis->dev, 0x0000);
8084#ifdef VBOX_WITH_MSI_DEVICES
8085 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8086 PCIDevSetCapabilityList(&pThis->dev, 0x80);
8087#else
8088 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8089#endif
8090 PCIDevSetRevisionId (&pThis->dev, 0x02);
8091 PCIDevSetClassProg (&pThis->dev, 0x01);
8092 PCIDevSetClassSub (&pThis->dev, 0x06);
8093 PCIDevSetClassBase (&pThis->dev, 0x01);
8094 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
8095
8096 PCIDevSetInterruptLine(&pThis->dev, 0x00);
8097 PCIDevSetInterruptPin (&pThis->dev, 0x01);
8098
8099 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
8100 pThis->dev.config[0x71] = 0xa8; /* next */
8101 pThis->dev.config[0x72] = 0x03; /* version ? */
8102
8103 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
8104 pThis->dev.config[0x92] = 0x3f;
8105 pThis->dev.config[0x94] = 0x80;
8106 pThis->dev.config[0x95] = 0x01;
8107 pThis->dev.config[0x97] = 0x78;
8108
8109 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
8110 pThis->dev.config[0xa9] = 0x00; /* next */
8111 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
8112 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
8113
8114 pThis->cThreadsActive = 0;
8115
8116 /* Initialize port members. */
8117 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8118 {
8119 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8120 pAhciPort->pDevInsR3 = pDevIns;
8121 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8122 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8123 pAhciPort->iLUN = i;
8124 pAhciPort->pAhciR3 = pThis;
8125 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
8126 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
8127 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
8128 pAhciPort->pDrvBase = NULL;
8129 pAhciPort->pAsyncIOThread = NULL;
8130 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8131 pAhciPort->fHotpluggable = true;
8132 }
8133
8134 /*
8135 * Init locks, using explicit locking where necessary.
8136 */
8137 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
8138 if (RT_FAILURE(rc))
8139 return rc;
8140
8141 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
8142 if (RT_FAILURE(rc))
8143 {
8144 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
8145 return rc;
8146 }
8147
8148 /*
8149 * Register the PCI device, it's I/O regions.
8150 */
8151 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
8152 if (RT_FAILURE(rc))
8153 return rc;
8154
8155#ifdef VBOX_WITH_MSI_DEVICES
8156 PDMMSIREG MsiReg;
8157 RT_ZERO(MsiReg);
8158 MsiReg.cMsiVectors = 1;
8159 MsiReg.iMsiCapOffset = 0x80;
8160 MsiReg.iMsiNextOffset = 0x70;
8161 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
8162 if (RT_FAILURE(rc))
8163 {
8164 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8165 /* That's OK, we can work without MSI */
8166 }
8167#endif
8168
8169 /*
8170 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
8171 * IDE registers are not available.
8172 * We set up "fake" entries in the PCI configuration register.
8173 * That means they are available but read and writes from/to them have no effect.
8174 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
8175 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
8176 * to switch to it which also changes device Id and other things in the PCI configuration space).
8177 */
8178 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8179 if (RT_FAILURE(rc))
8180 return PDMDEV_SET_ERROR(pDevIns, rc,
8181 N_("AHCI cannot register PCI I/O region"));
8182
8183 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8184 if (RT_FAILURE(rc))
8185 return PDMDEV_SET_ERROR(pDevIns, rc,
8186 N_("AHCI cannot register PCI I/O region"));
8187
8188 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8189 if (RT_FAILURE(rc))
8190 return PDMDEV_SET_ERROR(pDevIns, rc,
8191 N_("AHCI cannot register PCI I/O region"));
8192
8193 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8194 if (RT_FAILURE(rc))
8195 return PDMDEV_SET_ERROR(pDevIns, rc,
8196 N_("AHCI cannot register PCI I/O region"));
8197
8198 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
8199 if (RT_FAILURE(rc))
8200 return PDMDEV_SET_ERROR(pDevIns, rc,
8201 N_("AHCI cannot register PCI I/O region for BMDMA"));
8202
8203 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
8204 if (RT_FAILURE(rc))
8205 return PDMDEV_SET_ERROR(pDevIns, rc,
8206 N_("AHCI cannot register PCI memory region for registers"));
8207
8208 /* Create the timer for command completion coalescing feature. */
8209 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
8210 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
8211 if (RT_FAILURE(rc))
8212 {
8213 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
8214 return rc;
8215 }
8216 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
8217 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
8218
8219 /* Status LUN. */
8220 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
8221 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
8222
8223 /*
8224 * Create the notification queue.
8225 *
8226 * We need 2 items for every port because of SMP races.
8227 */
8228 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8229 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
8230 if (RT_FAILURE(rc))
8231 return rc;
8232 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
8233 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
8234
8235 /* Initialize static members on every port. */
8236 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8237 {
8238 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8239
8240 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8241 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
8242 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8243 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
8244 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8245 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
8246 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8247 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8248#ifdef VBOX_WITH_STATISTICS
8249 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8250 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8251 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8252 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8253#endif
8254
8255 ahciPortHwReset(pAhciPort);
8256 }
8257
8258 /* Attach drivers to every available port. */
8259 for (i = 0; i < pThis->cPortsImpl; i++)
8260 {
8261 char szName[24];
8262 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8263
8264 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8265 /*
8266 * Init interfaces.
8267 */
8268 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8269 pAhciPort->IMediaExPort.pfnIoReqCompleteNotify = ahciR3IoReqCompleteNotify;
8270 pAhciPort->IMediaExPort.pfnIoReqCopyFromBuf = ahciR3IoReqCopyFromBuf;
8271 pAhciPort->IMediaExPort.pfnIoReqCopyToBuf = ahciR3IoReqCopyToBuf;
8272 pAhciPort->IMediaExPort.pfnIoReqQueryDiscardRanges = ahciR3IoReqQueryDiscardRanges;
8273 pAhciPort->IMediaExPort.pfnIoReqStateChanged = ahciR3IoReqStateChanged;
8274 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8275 pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
8276 pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
8277 pAhciPort->fWrkThreadSleeping = true;
8278
8279 /* Query per port configuration options if available. */
8280 PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
8281 if (pCfgPort)
8282 {
8283 rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
8284 if (RT_FAILURE(rc))
8285 return PDMDEV_SET_ERROR(pDevIns, rc,
8286 N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
8287 }
8288
8289 /*
8290 * Attach the block driver
8291 */
8292 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8293 if (RT_SUCCESS(rc))
8294 {
8295 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8296 if (RT_FAILURE(rc))
8297 {
8298 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8299 return rc;
8300 }
8301
8302 /* Mark that a device is present on that port */
8303 if (i < 6)
8304 pThis->dev.config[0x93] |= (1 << i);
8305
8306 /*
8307 * Init vendor product data.
8308 */
8309 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8310 if (RT_FAILURE(rc))
8311 return rc;
8312
8313 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8314 if (RT_FAILURE(rc))
8315 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8316 N_("AHCI: Failed to create SUP event semaphore"));
8317
8318 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
8319 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
8320 if (RT_FAILURE(rc))
8321 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8322 N_("AHCI: Failed to create worker thread %s"), szName);
8323 }
8324 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8325 {
8326 pAhciPort->pDrvBase = NULL;
8327 rc = VINF_SUCCESS;
8328 LogRel(("AHCI: %s: No driver attached\n", szName));
8329 }
8330 else
8331 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8332 N_("AHCI: Failed to attach drive to %s"), szName);
8333 }
8334
8335 /*
8336 * Attach status driver (optional).
8337 */
8338 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8339 if (RT_SUCCESS(rc))
8340 {
8341 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8342 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8343 }
8344 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8345 {
8346 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8347 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8348 }
8349 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
8350 NULL, ahciR3LiveExec, NULL,
8351 ahciR3SavePrep, ahciR3SaveExec, NULL,
8352 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8353 if (RT_FAILURE(rc))
8354 return rc;
8355
8356 /*
8357 * Register the info item.
8358 */
8359 char szTmp[128];
8360 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8361 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8362
8363 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8364}
8365
8366/**
8367 * The device registration structure.
8368 */
8369const PDMDEVREG g_DeviceAHCI =
8370{
8371 /* u32Version */
8372 PDM_DEVREG_VERSION,
8373 /* szName */
8374 "ahci",
8375 /* szRCMod */
8376 "VBoxDDRC.rc",
8377 /* szR0Mod */
8378 "VBoxDDR0.r0",
8379 /* pszDescription */
8380 "Intel AHCI controller.\n",
8381 /* fFlags */
8382 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8383 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
8384 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
8385 /* fClass */
8386 PDM_DEVREG_CLASS_STORAGE,
8387 /* cMaxInstances */
8388 ~0U,
8389 /* cbInstance */
8390 sizeof(AHCI),
8391 /* pfnConstruct */
8392 ahciR3Construct,
8393 /* pfnDestruct */
8394 ahciR3Destruct,
8395 /* pfnRelocate */
8396 ahciR3Relocate,
8397 /* pfnMemSetup */
8398 NULL,
8399 /* pfnPowerOn */
8400 NULL,
8401 /* pfnReset */
8402 ahciR3Reset,
8403 /* pfnSuspend */
8404 ahciR3Suspend,
8405 /* pfnResume */
8406 ahciR3Resume,
8407 /* pfnAttach */
8408 ahciR3Attach,
8409 /* pfnDetach */
8410 ahciR3Detach,
8411 /* pfnQueryInterface. */
8412 NULL,
8413 /* pfnInitComplete */
8414 NULL,
8415 /* pfnPowerOff */
8416 ahciR3PowerOff,
8417 /* pfnSoftReset */
8418 NULL,
8419 /* u32VersionEnd */
8420 PDM_DEVREG_VERSION
8421};
8422
8423#endif /* IN_RING3 */
8424#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