VirtualBox

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

Last change on this file since 51608 was 51566, checked in by vboxsync, 11 years ago

Storage/AHCI: Get rid of ASMAtomic*Size and replace with the *U32 variants to get rid of some compiler warnings

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

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