VirtualBox

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

最後變更 在這個檔案從53037是 52961,由 vboxsync 提交於 10 年 前

AHCI: Fail the request with an overflow error if allocating I/O memory fails

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

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