VirtualBox

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

Last change on this file since 53411 was 53147, checked in by vboxsync, 10 years ago

Storage/AHCI: Free the I/O memory of cached request structures before unmounting the CD/DVD medium. Fixes a crash when a medium was removed from a drive without inserting a new one before the AHCI controller is destroyed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 324.4 KB
Line 
1/* $Id: DevAHCI.cpp 53147 2014-10-26 17:40:21Z 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, PAHCIREQ pAhciReqExcept);
945static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree);
946#endif
947RT_C_DECLS_END
948
949#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
950#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
951#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
952#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
953#define PDMIBLOCKPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
954#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
955#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
956
957#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
958
959#ifdef IN_RING3
960
961# ifdef LOG_USE_C99
962# define ahciLog(a) \
963 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
964# else
965# define ahciLog(a) \
966 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
967# endif
968
969#elif IN_RING0
970
971# ifdef LOG_USE_C99
972# define ahciLog(a) \
973 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
974# else
975# define ahciLog(a) \
976 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
977# endif
978
979#elif IN_RC
980
981# ifdef LOG_USE_C99
982# define ahciLog(a) \
983 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
984# else
985# define ahciLog(a) \
986 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
987# endif
988
989#endif
990
991/**
992 * Update PCI IRQ levels
993 */
994static void ahciHbaClearInterrupt(PAHCI pAhci)
995{
996 Log(("%s: Clearing interrupt\n", __FUNCTION__));
997 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
998}
999
1000/**
1001 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
1002 */
1003static int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
1004{
1005 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
1006
1007 int rc = PDMCritSectEnter(&pAhci->lock, rcBusy);
1008 if (rc != VINF_SUCCESS)
1009 return rc;
1010
1011 if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
1012 {
1013 if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
1014 {
1015 pAhci->uCccCurrentNr++;
1016 if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
1017 {
1018 /* Reset command completion coalescing state. */
1019 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
1020 pAhci->uCccCurrentNr = 0;
1021
1022 pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
1023 if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
1024 {
1025 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
1026 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
1027 }
1028 }
1029 }
1030 else
1031 {
1032 /* If only the bit of the actual port is set assert an interrupt
1033 * because the interrupt status register was already read by the guest
1034 * and we need to send a new notification.
1035 * Otherwise an interrupt is still pending.
1036 */
1037 ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
1038 if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
1039 {
1040 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
1041 PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
1042 }
1043 }
1044 }
1045
1046 PDMCritSectLeave(&pAhci->lock);
1047 return VINF_SUCCESS;
1048}
1049
1050#ifdef IN_RING3
1051/*
1052 * Assert irq when an CCC timeout occurs
1053 */
1054DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1055{
1056 PAHCI pAhci = (PAHCI)pvUser;
1057
1058 int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
1059 AssertRC(rc);
1060}
1061
1062/**
1063 * Finishes the port reset of the given port.
1064 *
1065 * @returns nothing.
1066 * @param pAhciPort The port to finish the reset on.
1067 */
1068static void ahciPortResetFinish(PAHCIPort pAhciPort)
1069{
1070 /* Cancel all tasks first. */
1071 bool fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort, NULL);
1072 Assert(fAllTasksCanceled);
1073
1074 /* Signature for SATA device. */
1075 if (pAhciPort->fATAPI)
1076 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1077 else
1078 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1079
1080 /* We received a COMINIT from the device. Tell the guest. */
1081 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
1082 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1083 pAhciPort->regTFD |= ATA_STAT_BUSY;
1084
1085 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
1086 {
1087 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1088 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1089
1090 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1091 {
1092 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1093 AssertRC(rc);
1094 }
1095 }
1096
1097 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1098 (0x03 << 0); /* Device detected and communication established. */
1099
1100 /*
1101 * Use the maximum allowed speed.
1102 * (Not that it changes anything really)
1103 */
1104 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1105 {
1106 case 0x01:
1107 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1108 break;
1109 case 0x02:
1110 case 0x00:
1111 default:
1112 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1113 break;
1114 }
1115
1116 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1117}
1118#endif
1119
1120/**
1121 * Kicks the I/O thread from RC or R0.
1122 *
1123 * @returns nothing.
1124 * @param pAhci The AHCI controller instance.
1125 * @param pAhciPort The port to kick.
1126 */
1127static void ahciIoThreadKick(PAHCI pAhci, PAHCIPort pAhciPort)
1128{
1129#ifdef IN_RC
1130 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
1131 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1132
1133 if (pItem)
1134 {
1135 pItem->iPort = pAhciPort->iLUN;
1136 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1137 }
1138#else
1139 LogFlowFunc(("Signal event semaphore\n"));
1140 int rc = SUPSemEventSignal(pAhci->pSupDrvSession, pAhciPort->hEvtProcess);
1141 AssertRC(rc);
1142#endif
1143}
1144
1145static int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1146{
1147 uint32_t uCIValue;
1148
1149 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1150
1151 /* Update the CI register first. */
1152 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1153 pAhciPort->regCI &= ~uCIValue;
1154
1155 if ( (pAhciPort->regCMD & AHCI_PORT_CMD_CR)
1156 && u32Value > 0)
1157 {
1158 /*
1159 * Clear all tasks which are already marked as busy. The guest
1160 * shouldn't write already busy tasks actually.
1161 */
1162 u32Value &= ~pAhciPort->regCI;
1163
1164 ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
1165
1166 /* Send a notification to R3 if u32TasksNew was 0 before our write. */
1167 if (ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1168 ahciIoThreadKick(ahci, pAhciPort);
1169 }
1170
1171 pAhciPort->regCI |= u32Value;
1172
1173 return VINF_SUCCESS;
1174}
1175
1176static int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1177{
1178 uint32_t uCIValue = 0;
1179
1180 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
1181
1182 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
1183
1184 pAhciPort->regCI &= ~uCIValue;
1185
1186 *pu32Value = pAhciPort->regCI;
1187
1188 return VINF_SUCCESS;
1189}
1190
1191static int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1192{
1193 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1194
1195 pAhciPort->regSACT |= u32Value;
1196
1197 return VINF_SUCCESS;
1198}
1199
1200static int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1201{
1202 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1203
1204 pAhciPort->regSACT &= ~u32TasksFinished;
1205
1206 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1207 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1208
1209 *pu32Value = pAhciPort->regSACT;
1210
1211 return VINF_SUCCESS;
1212}
1213
1214static int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1215{
1216 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1217
1218 if ( (u32Value & AHCI_PORT_SERR_X)
1219 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1220 {
1221 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1222 pAhciPort->regTFD |= ATA_STAT_ERR;
1223 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1224 }
1225
1226 if ( (u32Value & AHCI_PORT_SERR_N)
1227 && (pAhciPort->regSERR & AHCI_PORT_SERR_N))
1228 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
1229
1230 pAhciPort->regSERR &= ~u32Value;
1231
1232 return VINF_SUCCESS;
1233}
1234
1235static int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1236{
1237 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1238 *pu32Value = pAhciPort->regSERR;
1239 return VINF_SUCCESS;
1240}
1241
1242static int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1243{
1244 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1245 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1246 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1247
1248#ifndef IN_RING3
1249 return VINF_IOM_R3_MMIO_WRITE;
1250#else
1251 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1252 {
1253 if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
1254 LogRel(("AHCI#%u: Port %d reset\n", ahci->CTX_SUFF(pDevIns)->iInstance,
1255 pAhciPort->iLUN));
1256
1257 pAhciPort->regSSTS = 0;
1258 pAhciPort->regSIG = ~0;
1259 pAhciPort->regTFD = 0x7f;
1260 pAhciPort->fFirstD2HFisSend = false;
1261 pAhciPort->regSCTL = u32Value;
1262 }
1263 else if ( (u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT
1264 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT
1265 && pAhciPort->pDrvBase)
1266 {
1267 /* Do the port reset here, so the guest sees the new status immediately. */
1268 if (ahci->fLegacyPortResetMethod)
1269 {
1270 ahciPortResetFinish(pAhciPort);
1271 pAhciPort->regSCTL = u32Value; /* Update after finishing the reset, so the I/O thread doesn't get a chance to do the reset. */
1272 }
1273 else
1274 {
1275 pAhciPort->regSSTS = 0x1; /* Indicate device presence detected but communication not established. */
1276 pAhciPort->regSCTL = u32Value; /* Update before kicking the I/O thread. */
1277
1278 /* Kick the thread to finish the reset. */
1279 ahciIoThreadKick(ahci, pAhciPort);
1280 }
1281 }
1282 else /* Just update the value if there is no device attached. */
1283 pAhciPort->regSCTL = u32Value;
1284
1285 return VINF_SUCCESS;
1286#endif
1287}
1288
1289static int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1290{
1291 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1292 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1293 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1294 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1295
1296 *pu32Value = pAhciPort->regSCTL;
1297 return VINF_SUCCESS;
1298}
1299
1300static int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1301{
1302 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1303 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1304 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1305 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1306
1307 *pu32Value = pAhciPort->regSSTS;
1308 return VINF_SUCCESS;
1309}
1310
1311static int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1312{
1313 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1314 *pu32Value = pAhciPort->regSIG;
1315 return VINF_SUCCESS;
1316}
1317
1318static int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1319{
1320 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1321 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1322 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1323 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1324 *pu32Value = pAhciPort->regTFD;
1325 return VINF_SUCCESS;
1326}
1327
1328/**
1329 * Read from the port command register.
1330 */
1331static int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1332{
1333 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot)));
1334 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",
1335 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1336 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1337 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1338 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1339 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1340 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1341 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
1342 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1343 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1344 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1345 *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
1346 return VINF_SUCCESS;
1347}
1348
1349/**
1350 * Write to the port command register.
1351 * This is the register where all the data transfer is started
1352 */
1353static int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1354{
1355 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1356 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",
1357 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1358 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1359 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1360 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1361 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1362 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1363 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1364 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1365 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1366 (u32Value & AHCI_PORT_CMD_ST)));
1367
1368 /* The PxCMD.CCS bits are R/O and maintained separately. */
1369 u32Value &= ~AHCI_PORT_CMD_CCS;
1370
1371 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1372 {
1373 if (u32Value & AHCI_PORT_CMD_CLO)
1374 {
1375 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1376 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1377 /* Clear the CLO bit. */
1378 u32Value &= ~(AHCI_PORT_CMD_CLO);
1379 }
1380
1381 if (u32Value & AHCI_PORT_CMD_ST)
1382 {
1383 /*
1384 * Set engine state to running if there is a device attached and
1385 * IS.PCS is clear.
1386 */
1387 if ( pAhciPort->pDrvBase
1388 && !(pAhciPort->regIS & AHCI_PORT_IS_PCS))
1389 {
1390 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1391 u32Value |= AHCI_PORT_CMD_CR;
1392
1393 /* If there is something in CI, kick the I/O thread. */
1394 if ( pAhciPort->regCI > 0
1395 && ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
1396 {
1397 ASMAtomicOrU32(&pAhciPort->u32TasksNew, pAhciPort->regCI);
1398#ifdef IN_RC
1399 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
1400 AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
1401
1402 pItem->iPort = pAhciPort->iLUN;
1403 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1404#else
1405 LogFlowFunc(("Signal event semaphore\n"));
1406 int rc = SUPSemEventSignal(ahci->pSupDrvSession, pAhciPort->hEvtProcess);
1407 AssertRC(rc);
1408#endif
1409 }
1410 }
1411 else
1412 u32Value &= ~AHCI_PORT_CMD_CR;
1413 }
1414 else
1415 {
1416 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1417 /* Clear command issue register. */
1418 pAhciPort->regCI = 0;
1419 pAhciPort->regSACT = 0;
1420 /* Clear current command slot. */
1421 pAhciPort->u32CurrentCommandSlot = 0;
1422 u32Value &= ~AHCI_PORT_CMD_CR;
1423 }
1424 }
1425 else if (pAhciPort->pDrvBase)
1426 {
1427 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1428 {
1429 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1430 pAhciPort->fPoweredOn = true;
1431
1432 /*
1433 * Set states in the Port Signature and SStatus registers.
1434 */
1435 if (pAhciPort->fATAPI)
1436 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1437 else
1438 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1439 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1440 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1441 (0x03 << 0); /* Device detected and communication established. */
1442
1443 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1444 {
1445#ifndef IN_RING3
1446 return VINF_IOM_R3_MMIO_WRITE;
1447#else
1448 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1449 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1450
1451 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1452 {
1453 int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
1454 AssertRC(rc);
1455 }
1456#endif
1457 }
1458 }
1459
1460 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1461 {
1462 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1463 pAhciPort->fSpunUp = true;
1464 }
1465 }
1466
1467 if (u32Value & AHCI_PORT_CMD_FRE)
1468 {
1469 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1470
1471 u32Value |= AHCI_PORT_CMD_FR;
1472
1473 /* Send the first D2H FIS only if it wasn't already send. */
1474 if ( !pAhciPort->fFirstD2HFisSend
1475 && pAhciPort->pDrvBase)
1476 {
1477#ifndef IN_RING3
1478 return VINF_IOM_R3_MMIO_WRITE;
1479#else
1480 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1481 pAhciPort->fFirstD2HFisSend = true;
1482#endif
1483 }
1484 }
1485 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1486 {
1487 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1488 u32Value &= ~AHCI_PORT_CMD_FR;
1489 }
1490
1491 pAhciPort->regCMD = u32Value;
1492
1493 return VINF_SUCCESS;
1494}
1495
1496/**
1497 * Read from the port interrupt enable register.
1498 */
1499static int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1500{
1501 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1502 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",
1503 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1504 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1505 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1506 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1507 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1508 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1509 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1510 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1511 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1512 *pu32Value = pAhciPort->regIE;
1513 return VINF_SUCCESS;
1514}
1515
1516/**
1517 * Write to the port interrupt enable register.
1518 */
1519static int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1520{
1521 int rc = VINF_SUCCESS;
1522 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1523 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",
1524 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1525 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1526 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1527 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1528 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1529 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1530 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1531 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1532 (u32Value & AHCI_PORT_IE_DHRE)));
1533
1534 u32Value &= AHCI_PORT_IE_READONLY;
1535
1536 /* Check if some a interrupt status bit changed*/
1537 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1538
1539 if (u32Value & u32IntrStatus)
1540 rc = ahciHbaSetInterrupt(ahci, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
1541
1542 if (rc == VINF_SUCCESS)
1543 pAhciPort->regIE = u32Value;
1544
1545 return rc;
1546}
1547
1548/**
1549 * Read from the port interrupt status register.
1550 */
1551static int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1552{
1553 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1554 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",
1555 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1556 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1557 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1558 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1559 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1560 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1561 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1562 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1563 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1564 *pu32Value = pAhciPort->regIS;
1565 return VINF_SUCCESS;
1566}
1567
1568/**
1569 * Write to the port interrupt status register.
1570 */
1571static int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1572{
1573 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1574 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1575
1576 return VINF_SUCCESS;
1577}
1578
1579/**
1580 * Read from the port FIS base address upper 32bit register.
1581 */
1582static int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1583{
1584 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1585 *pu32Value = pAhciPort->regFBU;
1586 return VINF_SUCCESS;
1587}
1588
1589/**
1590 * Write to the port FIS base address upper 32bit register.
1591 */
1592static int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1593{
1594 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1595
1596 pAhciPort->regFBU = u32Value;
1597 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1598
1599 return VINF_SUCCESS;
1600}
1601
1602/**
1603 * Read from the port FIS base address register.
1604 */
1605static int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1606{
1607 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1608 *pu32Value = pAhciPort->regFB;
1609 return VINF_SUCCESS;
1610}
1611
1612/**
1613 * Write to the port FIS base address register.
1614 */
1615static int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1616{
1617 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1618
1619 Assert(!(u32Value & ~AHCI_PORT_FB_RESERVED));
1620
1621 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1622 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1623
1624 return VINF_SUCCESS;
1625}
1626
1627/**
1628 * Write to the port command list base address upper 32bit register.
1629 */
1630static int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1631{
1632 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1633
1634 pAhciPort->regCLBU = u32Value;
1635 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1636
1637 return VINF_SUCCESS;
1638}
1639
1640/**
1641 * Read from the port command list base address upper 32bit register.
1642 */
1643static int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1644{
1645 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1646 *pu32Value = pAhciPort->regCLBU;
1647 return VINF_SUCCESS;
1648}
1649
1650/**
1651 * Read from the port command list base address register.
1652 */
1653static int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1654{
1655 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1656 *pu32Value = pAhciPort->regCLB;
1657 return VINF_SUCCESS;
1658}
1659
1660/**
1661 * Write to the port command list base address register.
1662 */
1663static int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1664{
1665 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1666
1667 Assert(!(u32Value & ~AHCI_PORT_CLB_RESERVED));
1668
1669 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1670 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1671
1672 return VINF_SUCCESS;
1673}
1674
1675/**
1676 * Read from the global Version register.
1677 */
1678static int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1679{
1680 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
1681 *pu32Value = ahci->regHbaVs;
1682 return VINF_SUCCESS;
1683}
1684
1685/**
1686 * Read from the global Ports implemented register.
1687 */
1688static int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1689{
1690 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
1691 *pu32Value = ahci->regHbaPi;
1692 return VINF_SUCCESS;
1693}
1694
1695/**
1696 * Write to the global interrupt status register.
1697 */
1698static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1699{
1700 int rc;
1701 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1702
1703 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_WRITE);
1704 if (rc != VINF_SUCCESS)
1705 return rc;
1706
1707 ahci->regHbaIs &= ~(u32Value);
1708
1709 /*
1710 * Update interrupt status register and check for ports who
1711 * set the interrupt inbetween.
1712 */
1713 bool fClear = true;
1714 ahci->regHbaIs |= ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
1715 if (!ahci->regHbaIs)
1716 {
1717 unsigned i = 0;
1718
1719 /* Check if the cleared ports have a interrupt status bit set. */
1720 while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
1721 {
1722 if (u32Value & 0x01)
1723 {
1724 PAHCIPort pAhciPort = &ahci->ahciPort[i];
1725
1726 if (pAhciPort->regIE & pAhciPort->regIS)
1727 {
1728 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1729 ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
1730 fClear = false;
1731 break;
1732 }
1733 }
1734 u32Value >>= 1;
1735 i++;
1736 }
1737 }
1738 else
1739 fClear = false;
1740
1741 if (fClear)
1742 ahciHbaClearInterrupt(ahci);
1743 else
1744 {
1745 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
1746 /*
1747 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1748 * line is still high.
1749 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1750 */
1751 PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 0);
1752 PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 1);
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, NULL);
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 /*
4640 * Free the I/O memory of all cached tasks of this port
4641 * because the driver providing I/O memory allocation interface
4642 * is about to be destroyed.
4643 */
4644 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
4645 {
4646 if (pAhciPort->aCachedTasks[i])
4647 ahciReqMemFree(pAhciPort, pAhciPort->aCachedTasks[i], true /* fForceFree */);
4648 }
4649
4650 rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4651 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4652 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4653 Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
4654 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4655 {
4656 rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4657 (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
4658 pAhci->pMediaNotify, pAhciPort->iLUN);
4659 AssertRC(rc);
4660 }
4661 break;
4662 }
4663 case 3: /* 11 - Load media */
4664 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
4665 break;
4666 }
4667 if (RT_SUCCESS(rc))
4668 atapiCmdOK(pAhciPort, pAhciReq);
4669 else
4670 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4671 break;
4672 }
4673 case SCSI_MECHANISM_STATUS:
4674 {
4675 cbMax = ataBE2H_U16(pbPacket + 8);
4676 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4677 break;
4678 }
4679 case SCSI_READ_TOC_PMA_ATIP:
4680 {
4681 uint8_t format;
4682
4683 if (pAhciPort->cNotifiedMediaChange > 0)
4684 {
4685 pAhciPort->cNotifiedMediaChange-- ;
4686 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4687 break;
4688 }
4689 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4690 {
4691 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4692 break;
4693 }
4694 cbMax = ataBE2H_U16(pbPacket + 7);
4695 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
4696 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
4697 * the other field is clear... */
4698 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
4699 switch (format)
4700 {
4701 case 0:
4702 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
4703 break;
4704 case 1:
4705 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
4706 break;
4707 case 2:
4708 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
4709 break;
4710 default:
4711 error_cmd:
4712 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4713 break;
4714 }
4715 break;
4716 }
4717 case SCSI_READ_CAPACITY:
4718 if (pAhciPort->cNotifiedMediaChange > 0)
4719 {
4720 pAhciPort->cNotifiedMediaChange-- ;
4721 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4722 break;
4723 }
4724 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4725 {
4726 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4727 break;
4728 }
4729 atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
4730 break;
4731 case SCSI_READ_DISC_INFORMATION:
4732 if (pAhciPort->cNotifiedMediaChange > 0)
4733 {
4734 pAhciPort->cNotifiedMediaChange-- ;
4735 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4736 break;
4737 }
4738 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4739 {
4740 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4741 break;
4742 }
4743 cbMax = ataBE2H_U16(pbPacket + 7);
4744 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
4745 break;
4746 case SCSI_READ_TRACK_INFORMATION:
4747 if (pAhciPort->cNotifiedMediaChange > 0)
4748 {
4749 pAhciPort->cNotifiedMediaChange-- ;
4750 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4751 break;
4752 }
4753 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4754 {
4755 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4756 break;
4757 }
4758 cbMax = ataBE2H_U16(pbPacket + 7);
4759 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
4760 break;
4761 case SCSI_GET_CONFIGURATION:
4762 /* No media change stuff here, it can confuse Linux guests. */
4763 cbMax = ataBE2H_U16(pbPacket + 7);
4764 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
4765 break;
4766 case SCSI_INQUIRY:
4767 cbMax = pbPacket[4];
4768 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
4769 break;
4770 case SCSI_READ_DVD_STRUCTURE:
4771 cbMax = ataBE2H_U16(pbPacket + 8);
4772 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DVD_STRUCTURE);
4773 break;
4774 default:
4775 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4776 break;
4777 }
4778
4779 return enmTxDir;
4780}
4781
4782/*
4783 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
4784 */
4785static AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4786{
4787 const uint8_t *pbPacket;
4788 uint32_t cSectors, iATAPILBA;
4789 uint32_t cbTransfer = 0;
4790 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4791
4792 pbPacket = pAhciReq->aATAPICmd;
4793 switch (pbPacket[0])
4794 {
4795 case SCSI_BLANK:
4796 goto sendcmd;
4797 case SCSI_CLOSE_TRACK_SESSION:
4798 goto sendcmd;
4799 case SCSI_ERASE_10:
4800 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4801 cbTransfer = ataBE2H_U16(pbPacket + 7);
4802 Log2(("ATAPI PT: lba %d\n", iATAPILBA));
4803 enmTxDir = AHCITXDIR_WRITE;
4804 goto sendcmd;
4805 case SCSI_FORMAT_UNIT:
4806 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4807 enmTxDir = AHCITXDIR_WRITE;
4808 goto sendcmd;
4809 case SCSI_GET_CONFIGURATION:
4810 cbTransfer = ataBE2H_U16(pbPacket + 7);
4811 enmTxDir = AHCITXDIR_READ;
4812 goto sendcmd;
4813 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4814 cbTransfer = ataBE2H_U16(pbPacket + 7);
4815 if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
4816 {
4817 pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
4818 atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4819 break;
4820 }
4821 enmTxDir = AHCITXDIR_READ;
4822 goto sendcmd;
4823 case SCSI_GET_PERFORMANCE:
4824 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4825 enmTxDir = AHCITXDIR_READ;
4826 goto sendcmd;
4827 case SCSI_INQUIRY:
4828 cbTransfer = ataBE2H_U16(pbPacket + 3);
4829 enmTxDir = AHCITXDIR_READ;
4830 goto sendcmd;
4831 case SCSI_LOAD_UNLOAD_MEDIUM:
4832 goto sendcmd;
4833 case SCSI_MECHANISM_STATUS:
4834 cbTransfer = ataBE2H_U16(pbPacket + 8);
4835 enmTxDir = AHCITXDIR_READ;
4836 goto sendcmd;
4837 case SCSI_MODE_SELECT_10:
4838 cbTransfer = ataBE2H_U16(pbPacket + 7);
4839 enmTxDir = AHCITXDIR_WRITE;
4840 goto sendcmd;
4841 case SCSI_MODE_SENSE_10:
4842 cbTransfer = ataBE2H_U16(pbPacket + 7);
4843 enmTxDir = AHCITXDIR_READ;
4844 goto sendcmd;
4845 case SCSI_PAUSE_RESUME:
4846 goto sendcmd;
4847 case SCSI_PLAY_AUDIO_10:
4848 goto sendcmd;
4849 case SCSI_PLAY_AUDIO_12:
4850 goto sendcmd;
4851 case SCSI_PLAY_AUDIO_MSF:
4852 goto sendcmd;
4853 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4854 /** @todo do not forget to unlock when a VM is shut down */
4855 goto sendcmd;
4856 case SCSI_READ_10:
4857 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4858 cSectors = ataBE2H_U16(pbPacket + 7);
4859 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4860 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4861 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4862 enmTxDir = AHCITXDIR_READ;
4863 goto sendcmd;
4864 case SCSI_READ_12:
4865 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4866 cSectors = ataBE2H_U32(pbPacket + 6);
4867 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4868 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4869 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4870 enmTxDir = AHCITXDIR_READ;
4871 goto sendcmd;
4872 case SCSI_READ_BUFFER:
4873 cbTransfer = ataBE2H_U24(pbPacket + 6);
4874 enmTxDir = AHCITXDIR_READ;
4875 goto sendcmd;
4876 case SCSI_READ_BUFFER_CAPACITY:
4877 cbTransfer = ataBE2H_U16(pbPacket + 7);
4878 enmTxDir = AHCITXDIR_READ;
4879 goto sendcmd;
4880 case SCSI_READ_CAPACITY:
4881 cbTransfer = 8;
4882 enmTxDir = AHCITXDIR_READ;
4883 goto sendcmd;
4884 case SCSI_READ_CD:
4885 case SCSI_READ_CD_MSF:
4886 {
4887 /* Get sector size based on the expected sector type field. */
4888 switch ((pbPacket[1] >> 2) & 0x7)
4889 {
4890 case 0x0: /* All types. */
4891 {
4892 uint32_t iLbaStart;
4893
4894 if (pbPacket[0] == SCSI_READ_CD)
4895 iLbaStart = ataBE2H_U32(&pbPacket[2]);
4896 else
4897 iLbaStart = ataMSF2LBA(&pbPacket[3]);
4898
4899 if (pAhciPort->pTrackList)
4900 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
4901 else
4902 pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
4903 break;
4904 }
4905 case 0x1: /* CD-DA */
4906 pAhciReq->cbATAPISector = 2352;
4907 break;
4908 case 0x2: /* Mode 1 */
4909 pAhciReq->cbATAPISector = 2048;
4910 break;
4911 case 0x3: /* Mode 2 formless */
4912 pAhciReq->cbATAPISector = 2336;
4913 break;
4914 case 0x4: /* Mode 2 form 1 */
4915 pAhciReq->cbATAPISector = 2048;
4916 break;
4917 case 0x5: /* Mode 2 form 2 */
4918 pAhciReq->cbATAPISector = 2324;
4919 break;
4920 default: /* Reserved */
4921 AssertMsgFailed(("Unknown sector type\n"));
4922 pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
4923 }
4924
4925 if (pbPacket[0] == SCSI_READ_CD)
4926 cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
4927 else /* SCSI_READ_MSF */
4928 {
4929 cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
4930 if (cSectors > 32)
4931 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
4932 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4933 }
4934 enmTxDir = AHCITXDIR_READ;
4935 goto sendcmd;
4936 }
4937 case SCSI_READ_DISC_INFORMATION:
4938 cbTransfer = ataBE2H_U16(pbPacket + 7);
4939 enmTxDir = AHCITXDIR_READ;
4940 goto sendcmd;
4941 case SCSI_READ_DVD_STRUCTURE:
4942 cbTransfer = ataBE2H_U16(pbPacket + 8);
4943 enmTxDir = AHCITXDIR_READ;
4944 goto sendcmd;
4945 case SCSI_READ_FORMAT_CAPACITIES:
4946 cbTransfer = ataBE2H_U16(pbPacket + 7);
4947 enmTxDir = AHCITXDIR_READ;
4948 goto sendcmd;
4949 case SCSI_READ_SUBCHANNEL:
4950 cbTransfer = ataBE2H_U16(pbPacket + 7);
4951 enmTxDir = AHCITXDIR_READ;
4952 goto sendcmd;
4953 case SCSI_READ_TOC_PMA_ATIP:
4954 cbTransfer = ataBE2H_U16(pbPacket + 7);
4955 enmTxDir = AHCITXDIR_READ;
4956 goto sendcmd;
4957 case SCSI_READ_TRACK_INFORMATION:
4958 cbTransfer = ataBE2H_U16(pbPacket + 7);
4959 enmTxDir = AHCITXDIR_READ;
4960 goto sendcmd;
4961 case SCSI_REPAIR_TRACK:
4962 goto sendcmd;
4963 case SCSI_REPORT_KEY:
4964 cbTransfer = ataBE2H_U16(pbPacket + 8);
4965 enmTxDir = AHCITXDIR_READ;
4966 goto sendcmd;
4967 case SCSI_REQUEST_SENSE:
4968 cbTransfer = pbPacket[4];
4969 if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
4970 {
4971 pAhciReq->cbTransfer = cbTransfer;
4972 pAhciReq->enmTxDir = AHCITXDIR_READ;
4973 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
4974 break;
4975 }
4976 enmTxDir = AHCITXDIR_READ;
4977 goto sendcmd;
4978 case SCSI_RESERVE_TRACK:
4979 goto sendcmd;
4980 case SCSI_SCAN:
4981 goto sendcmd;
4982 case SCSI_SEEK_10:
4983 goto sendcmd;
4984 case SCSI_SEND_CUE_SHEET:
4985 cbTransfer = ataBE2H_U24(pbPacket + 6);
4986 enmTxDir = AHCITXDIR_WRITE;
4987 goto sendcmd;
4988 case SCSI_SEND_DVD_STRUCTURE:
4989 cbTransfer = ataBE2H_U16(pbPacket + 8);
4990 enmTxDir = AHCITXDIR_WRITE;
4991 goto sendcmd;
4992 case SCSI_SEND_EVENT:
4993 cbTransfer = ataBE2H_U16(pbPacket + 8);
4994 enmTxDir = AHCITXDIR_WRITE;
4995 goto sendcmd;
4996 case SCSI_SEND_KEY:
4997 cbTransfer = ataBE2H_U16(pbPacket + 8);
4998 enmTxDir = AHCITXDIR_WRITE;
4999 goto sendcmd;
5000 case SCSI_SEND_OPC_INFORMATION:
5001 cbTransfer = ataBE2H_U16(pbPacket + 7);
5002 enmTxDir = AHCITXDIR_WRITE;
5003 goto sendcmd;
5004 case SCSI_SET_CD_SPEED:
5005 goto sendcmd;
5006 case SCSI_SET_READ_AHEAD:
5007 goto sendcmd;
5008 case SCSI_SET_STREAMING:
5009 cbTransfer = ataBE2H_U16(pbPacket + 9);
5010 enmTxDir = AHCITXDIR_WRITE;
5011 goto sendcmd;
5012 case SCSI_START_STOP_UNIT:
5013 goto sendcmd;
5014 case SCSI_STOP_PLAY_SCAN:
5015 goto sendcmd;
5016 case SCSI_SYNCHRONIZE_CACHE:
5017 goto sendcmd;
5018 case SCSI_TEST_UNIT_READY:
5019 goto sendcmd;
5020 case SCSI_VERIFY_10:
5021 goto sendcmd;
5022 case SCSI_WRITE_10:
5023 case SCSI_WRITE_AND_VERIFY_10:
5024 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5025 cSectors = ataBE2H_U16(pbPacket + 7);
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_12:
5035 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5036 cSectors = ataBE2H_U32(pbPacket + 6);
5037 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5038 if (pAhciPort->pTrackList)
5039 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5040 else
5041 pAhciReq->cbATAPISector = 2048;
5042 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5043 enmTxDir = AHCITXDIR_WRITE;
5044 goto sendcmd;
5045 case SCSI_WRITE_BUFFER:
5046 switch (pbPacket[1] & 0x1f)
5047 {
5048 case 0x04: /* download microcode */
5049 case 0x05: /* download microcode and save */
5050 case 0x06: /* download microcode with offsets */
5051 case 0x07: /* download microcode with offsets and save */
5052 case 0x0e: /* download microcode with offsets and defer activation */
5053 case 0x0f: /* activate deferred microcode */
5054 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
5055 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
5056 break;
5057 default:
5058 cbTransfer = ataBE2H_U16(pbPacket + 6);
5059 enmTxDir = AHCITXDIR_WRITE;
5060 goto sendcmd;
5061 }
5062 break;
5063 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
5064 cbTransfer = ataBE2H_U32(pbPacket + 6);
5065 enmTxDir = AHCITXDIR_READ;
5066 goto sendcmd;
5067 case SCSI_REZERO_UNIT:
5068 /* Obsolete command used by cdrecord. What else would one expect?
5069 * This command is not sent to the drive, it is handled internally,
5070 * as the Linux kernel doesn't like it (message "scsi: unknown
5071 * opcode 0x01" in syslog) and replies with a sense code of 0,
5072 * which sends cdrecord to an endless loop. */
5073 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5074 break;
5075 default:
5076 LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
5077 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5078 break;
5079 sendcmd:
5080 /* Send a command to the drive, passing data in/out as required. */
5081 Log2(("ATAPI PT: max size %d\n", cbTransfer));
5082 if (cbTransfer == 0)
5083 enmTxDir = AHCITXDIR_NONE;
5084 pAhciReq->enmTxDir = enmTxDir;
5085 pAhciReq->cbTransfer = cbTransfer;
5086 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
5087 }
5088
5089 return AHCITXDIR_NONE;
5090}
5091
5092static AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5093{
5094 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
5095 const uint8_t *pbPacket;
5096
5097 pbPacket = pAhciReq->aATAPICmd;
5098 Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
5099 Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
5100
5101 if (pAhciPort->fATAPIPassthrough)
5102 enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
5103 else
5104 enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
5105
5106 return enmTxDir;
5107}
5108
5109/**
5110 * Reset all values after a reset of the attached storage device.
5111 *
5112 * @returns nothing
5113 * @param pAhciPort The port the device is attached to.
5114 * @param pAhciReq The state to get the tag number from.
5115 */
5116static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5117{
5118 int rc;
5119
5120 /* Send a status good D2H FIS. */
5121 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
5122 pAhciPort->fResetDevice = false;
5123 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5124 ahciPostFirstD2HFisIntoMemory(pAhciPort);
5125
5126 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
5127 if (pAhciPort->fATAPI)
5128 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
5129 else
5130 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
5131 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5132
5133 rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5134 AssertRC(rc);
5135}
5136
5137/**
5138 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
5139 *
5140 * @returns nothing.
5141 * @param pAhciPort The device to reset.
5142 * @param pAhciReq The task state.
5143 */
5144static void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5145{
5146 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
5147
5148 /*
5149 * Because this ATAPI only and ATAPI can't have
5150 * more than one command active at a time the task counter should be 0
5151 * and it is possible to finish the reset now.
5152 */
5153 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
5154 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
5155}
5156
5157/**
5158 * Create a PIO setup FIS and post it into the memory area of the guest.
5159 *
5160 * @returns nothing.
5161 * @param pAhciPort The port of the SATA controller.
5162 * @param pAhciReq The state of the task.
5163 * @param pCmdFis Pointer to the command FIS from the guest.
5164 * @param fInterrupt If an interrupt should be send to the guest.
5165 */
5166static void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
5167 bool fInterrupt)
5168{
5169 uint8_t abPioSetupFis[20];
5170 bool fAssertIntr = false;
5171 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5172
5173 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
5174
5175 AssertMsg( pAhciReq->cbTransfer > 0
5176 && pAhciReq->cbTransfer <= 65534,
5177 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
5178
5179 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5180 {
5181 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
5182 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
5183 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5184 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
5185 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
5186 abPioSetupFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5187 abPioSetupFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5188 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5189 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5190 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5191 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5192 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5193 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5194 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5195 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5196 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5197
5198 /* Set transfer count. */
5199 abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
5200 abPioSetupFis[17] = pAhciReq->cbTransfer & 0xff;
5201
5202 /* Update registers. */
5203 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5204
5205 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
5206
5207 if (fInterrupt)
5208 {
5209 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
5210 /* Check if we should assert an interrupt */
5211 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
5212 fAssertIntr = true;
5213 }
5214
5215 if (fAssertIntr)
5216 {
5217 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5218 AssertRC(rc);
5219 }
5220 }
5221}
5222
5223/**
5224 * Build a D2H FIS and post into the memory area of the guest.
5225 *
5226 * @returns Nothing
5227 * @param pAhciPort The port of the SATA controller.
5228 * @param pAhciReq The state of the task.
5229 * @param pCmdFis Pointer to the command FIS from the guest.
5230 * @param fInterrupt If an interrupt should be send to the guest.
5231 */
5232static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
5233{
5234 uint8_t d2hFis[20];
5235 bool fAssertIntr = false;
5236 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5237
5238 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
5239
5240 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5241 {
5242 memset(&d2hFis[0], 0, sizeof(d2hFis));
5243 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
5244 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5245 d2hFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5246 d2hFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5247 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5248 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5249 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5250 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5251 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5252 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5253 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5254 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5255 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5256
5257 /* Update registers. */
5258 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5259
5260 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
5261
5262 if (pAhciReq->uATARegStatus & ATA_STAT_ERR)
5263 {
5264 /* Error bit is set. */
5265 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5266 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5267 fAssertIntr = true;
5268 /*
5269 * Don't mark the command slot as completed because the guest
5270 * needs it to identify the failed command.
5271 */
5272 }
5273 else if (fInterrupt)
5274 {
5275 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
5276 /* Check if we should assert an interrupt */
5277 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
5278 fAssertIntr = true;
5279
5280 /* Mark command as completed. */
5281 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5282 }
5283
5284 if (fAssertIntr)
5285 {
5286 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5287 AssertRC(rc);
5288 }
5289 }
5290}
5291
5292/**
5293 * Build a SDB Fis and post it into the memory area of the guest.
5294 *
5295 * @returns Nothing
5296 * @param pAhciPort The port for which the SDB Fis is send.
5297 * @param uFinishedTasks Bitmask of finished tasks.
5298 * @param fInterrupt If an interrupt should be asserted.
5299 */
5300static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
5301{
5302 uint32_t sdbFis[2];
5303 bool fAssertIntr = false;
5304 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5305 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
5306
5307 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
5308
5309 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5310 {
5311 memset(&sdbFis[0], 0, sizeof(sdbFis));
5312 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
5313 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
5314 if (RT_UNLIKELY(pTaskErr))
5315 {
5316 sdbFis[0] = pTaskErr->uATARegError;
5317 sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
5318
5319 /* Update registers. */
5320 pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
5321 }
5322 else
5323 {
5324 sdbFis[0] = 0;
5325 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
5326 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
5327 }
5328
5329 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
5330
5331 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
5332
5333 if (RT_UNLIKELY(pTaskErr))
5334 {
5335 /* Error bit is set. */
5336 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5337 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5338 fAssertIntr = true;
5339 }
5340
5341 if (fInterrupt)
5342 {
5343 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
5344 /* Check if we should assert an interrupt */
5345 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
5346 fAssertIntr = true;
5347 }
5348
5349 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
5350
5351 if (fAssertIntr)
5352 {
5353 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5354 AssertRC(rc);
5355 }
5356 }
5357}
5358
5359static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
5360{
5361 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
5362 if (fLBA48)
5363 {
5364 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
5365 return 65536;
5366 else
5367 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
5368 }
5369 else
5370 {
5371 if (!pCmdFis[AHCI_CMDFIS_SECTC])
5372 return 256;
5373 else
5374 return pCmdFis[AHCI_CMDFIS_SECTC];
5375 }
5376}
5377
5378static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
5379{
5380 uint64_t iLBA;
5381 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
5382 {
5383 /* any LBA variant */
5384 if (fLBA48)
5385 {
5386 /* LBA48 */
5387 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5388 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5389 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5390 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5391 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5392 pCmdFis[AHCI_CMDFIS_SECTN];
5393 }
5394 else
5395 {
5396 /* LBA */
5397 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5398 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
5399 }
5400 }
5401 else
5402 {
5403 /* CHS */
5404 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
5405 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
5406 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
5407 }
5408 return iLBA;
5409}
5410
5411static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
5412{
5413 uint64_t uLBA;
5414
5415 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5416 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5417 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5418 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5419 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5420 pCmdFis[AHCI_CMDFIS_SECTN];
5421
5422 return uLBA;
5423}
5424
5425DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
5426{
5427 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
5428 return 65536;
5429 else
5430 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
5431}
5432
5433DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
5434{
5435 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
5436}
5437
5438/**
5439 * Allocates memory for the given request using already allocated memory if possible.
5440 *
5441 * @returns Pointer to the memory or NULL on failure
5442 * @param pAhciPort The AHCI port.
5443 * @param pAhciReq The request to allocate memory for.
5444 * @param cb The amount of memory to allocate.
5445 */
5446static void *ahciReqMemAlloc(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cb)
5447{
5448 if (pAhciReq->cbAlloc > cb)
5449 {
5450 pAhciReq->cAllocTooMuch++;
5451 }
5452 else if (pAhciReq->cbAlloc < cb)
5453 {
5454 if (pAhciReq->cbAlloc)
5455 pAhciPort->pDrvBlock->pfnIoBufFree(pAhciPort->pDrvBlock, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5456
5457 pAhciReq->pvAlloc = NULL;
5458 pAhciReq->cbAlloc = RT_ALIGN_Z(cb, _4K);
5459 int rc = pAhciPort->pDrvBlock->pfnIoBufAlloc(pAhciPort->pDrvBlock, pAhciReq->cbAlloc, &pAhciReq->pvAlloc);
5460 if (RT_FAILURE(rc))
5461 pAhciReq->pvAlloc = NULL;
5462
5463 pAhciReq->cAllocTooMuch = 0;
5464 if (RT_UNLIKELY(!pAhciReq->pvAlloc))
5465 pAhciReq->cbAlloc = 0;
5466 }
5467
5468 return pAhciReq->pvAlloc;
5469}
5470
5471/**
5472 * Frees memory allocated for the given request.
5473 *
5474 * @returns nothing.
5475 * @param pAhciPort The AHCI port.
5476 * @param pAhciReq The request.
5477 * @param fForceFree Flag whether to force a free
5478 */
5479static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree)
5480{
5481 if ( pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH
5482 || fForceFree)
5483 {
5484 if (pAhciReq->cbAlloc)
5485 {
5486 pAhciPort->pDrvBlock->pfnIoBufFree(pAhciPort->pDrvBlock, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5487 pAhciReq->cbAlloc = 0;
5488 pAhciReq->cAllocTooMuch = 0;
5489 }
5490 }
5491}
5492
5493/**
5494 * Copies a data buffer into the S/G buffer set up by the guest.
5495 *
5496 * @returns Amount of bytes copied to the PRDTL.
5497 * @param pDevIns Pointer to the device instance data.
5498 * @param pAhciReq AHCI request structure.
5499 * @param pvBuf The buffer to copy from.
5500 * @param cbBuf The size of the buffer.
5501 */
5502static size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5503 void *pvBuf, size_t cbBuf)
5504{
5505 uint8_t *pbBuf = (uint8_t *)pvBuf;
5506 SGLEntry aPrdtlEntries[32];
5507 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5508 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5509 size_t cbCopied = 0;
5510
5511 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5512
5513 do
5514 {
5515 uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
5516 ? cPrdtlEntries
5517 : RT_ELEMENTS(aPrdtlEntries);
5518
5519 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5520
5521 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5522 {
5523 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5524 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5525
5526 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5527
5528 /* Copy into SG entry. */
5529 PDMDevHlpPCIPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5530
5531 pbBuf += cbThisCopy;
5532 cbBuf -= cbThisCopy;
5533 cbCopied += cbThisCopy;
5534 }
5535
5536 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5537 cPrdtlEntries -= cPrdtlEntriesRead;
5538 } while (cPrdtlEntries && cbBuf);
5539
5540 if (cbCopied < cbBuf)
5541 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5542
5543 return cbCopied;
5544}
5545
5546/**
5547 * Copies the S/G buffer into a data buffer.
5548 *
5549 * @returns Amount of bytes copied to the PRDTL.
5550 * @param pDevIns Pointer to the device instance data.
5551 * @param pAhciReq AHCI request structure.
5552 * @param pvBuf The buffer to copy to.
5553 * @param cbBuf The size of the buffer.
5554 */
5555static size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5556 void *pvBuf, size_t cbBuf)
5557{
5558 uint8_t *pbBuf = (uint8_t *)pvBuf;
5559 SGLEntry aPrdtlEntries[32];
5560 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5561 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5562 size_t cbCopied = 0;
5563
5564 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5565
5566 do
5567 {
5568 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5569 ? cPrdtlEntries
5570 : RT_ELEMENTS(aPrdtlEntries);
5571
5572 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5573
5574 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5575 {
5576 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5577 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5578
5579 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5580
5581 /* Copy into buffer. */
5582 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5583
5584 pbBuf += cbThisCopy;
5585 cbBuf -= cbThisCopy;
5586 cbCopied += cbThisCopy;
5587 }
5588
5589 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5590 cPrdtlEntries -= cPrdtlEntriesRead;
5591 } while (cPrdtlEntries && cbBuf);
5592
5593 if (cbCopied < cbBuf)
5594 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5595
5596 return cbCopied;
5597}
5598
5599/**
5600 * Allocate I/O memory and copies the guest buffer for writes.
5601 *
5602 * @returns VBox status code.
5603 * @param pAhciPort The AHCI port.
5604 * @param pAhciReq The request state.
5605 * @param cbTransfer Amount of bytes to allocate.
5606 */
5607static int ahciIoBufAllocate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbTransfer)
5608{
5609 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5610 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5611 ("Allocating I/O memory for a non I/O request is not allowed\n"));
5612
5613 pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciPort, pAhciReq, cbTransfer);
5614 if (!pAhciReq->u.Io.DataSeg.pvSeg)
5615 return VERR_NO_MEMORY;
5616
5617 pAhciReq->u.Io.DataSeg.cbSeg = cbTransfer;
5618 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
5619 {
5620 ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5621 pAhciReq->u.Io.DataSeg.pvSeg,
5622 cbTransfer);
5623 }
5624 return VINF_SUCCESS;
5625}
5626
5627/**
5628 * Frees the I/O memory of the given request and updates the guest buffer if necessary.
5629 *
5630 * @returns nothing.
5631 * @param pAhciPort The AHCI port.
5632 * @param pAhciReq The request state.
5633 * @param fCopyToGuest Flag whether to update the guest buffer if necessary.
5634 * Nothing is copied if false even if the request was a read.
5635 */
5636static void ahciIoBufFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq,
5637 bool fCopyToGuest)
5638{
5639 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5640 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5641 ("Freeing I/O memory for a non I/O request is not allowed\n"));
5642
5643 if ( pAhciReq->enmTxDir == AHCITXDIR_READ
5644 && fCopyToGuest)
5645 {
5646 if (pAhciReq->u.Io.pfnPostProcess)
5647 {
5648 void *pv = NULL;
5649 size_t cb = 0;
5650 int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
5651
5652 if (RT_SUCCESS(rc))
5653 {
5654 pAhciReq->cbTransfer = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pv, cb);
5655 RTMemFree(pv);
5656 }
5657 }
5658 else
5659 ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5660 pAhciReq->u.Io.DataSeg.pvSeg,
5661 pAhciReq->u.Io.DataSeg.cbSeg);
5662 }
5663
5664 ahciReqMemFree(pAhciPort, pAhciReq, false /* fForceFree */);
5665 pAhciReq->u.Io.DataSeg.pvSeg = NULL;
5666 pAhciReq->u.Io.DataSeg.cbSeg = 0;
5667}
5668
5669
5670/**
5671 * Free all cached tasks on the given port.
5672 *
5673 * @returns nothing.
5674 * @param pAhciPort The AHCI port.
5675 */
5676static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort)
5677{
5678 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
5679 {
5680 if (pAhciPort->aCachedTasks[i])
5681 {
5682 ahciReqMemFree(pAhciPort, pAhciPort->aCachedTasks[i], true /* fForceFree */);
5683 RTMemFree(pAhciPort->aCachedTasks[i]);
5684 pAhciPort->aCachedTasks[i] = NULL;
5685 }
5686 }
5687}
5688
5689/**
5690 * Cancels all active tasks on the port.
5691 *
5692 * @returns Whether all active tasks were canceled.
5693 * @param pAhciPort The ahci port.
5694 * @param pAhciReqExcept The given request is excepted from the cancelling
5695 * (used for error page reading).
5696 */
5697static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept)
5698{
5699 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aCachedTasks); i++)
5700 {
5701 PAHCIREQ pAhciReq = pAhciPort->aCachedTasks[i];
5702
5703 if ( VALID_PTR(pAhciReq)
5704 && pAhciReq != pAhciReqExcept)
5705 {
5706 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
5707
5708 if (fXchg)
5709 {
5710 /* Task is active and was canceled. */
5711 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
5712 ("Task was canceled but none is active\n"));
5713 ASMAtomicDecU32(&pAhciPort->cTasksActive);
5714
5715 /*
5716 * Clear the pointer in the cached array. The controller will allocate a
5717 * a new task structure for this tag.
5718 */
5719 ASMAtomicWriteNullPtr(&pAhciPort->aCachedTasks[i]);
5720 LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
5721 pAhciPort->iLUN, pAhciReq->uTag));
5722 }
5723 else
5724 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
5725 ("Invalid task state, must be free!\n"));
5726 }
5727 }
5728
5729 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
5730}
5731
5732/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
5733
5734/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
5735#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
5736
5737static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
5738{
5739 int rc;
5740 LogRel(("AHCI: Host disk full\n"));
5741 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
5742 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
5743 AssertRC(rc);
5744}
5745
5746static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
5747{
5748 int rc;
5749 LogRel(("AHCI: File too big\n"));
5750 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
5751 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"));
5752 AssertRC(rc);
5753}
5754
5755static void ahciWarningISCSI(PPDMDEVINS pDevIns)
5756{
5757 int rc;
5758 LogRel(("AHCI: iSCSI target unavailable\n"));
5759 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
5760 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
5761 AssertRC(rc);
5762}
5763
5764bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
5765{
5766 if (rc == VERR_DISK_FULL)
5767 {
5768 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5769 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
5770 return true;
5771 }
5772 if (rc == VERR_FILE_TOO_BIG)
5773 {
5774 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5775 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
5776 return true;
5777 }
5778 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
5779 {
5780 /* iSCSI connection abort (first error) or failure to reestablish
5781 * connection (second error). Pause VM. On resume we'll retry. */
5782 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5783 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
5784 return true;
5785 }
5786 if (rc == VERR_VD_DEK_MISSING)
5787 {
5788 /* Error message already set. */
5789 ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false);
5790 return true;
5791 }
5792
5793 return false;
5794}
5795
5796/**
5797 * Creates the array of ranges to trim.
5798 *
5799 * @returns VBox status code.
5800 * @param pAhciPort AHCI port state.
5801 * @param pAhciReq The request handling the TRIM request.
5802 */
5803static int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5804{
5805 SGLEntry aPrdtlEntries[32];
5806 uint64_t aRanges[64];
5807 unsigned cRangesMax;
5808 unsigned cRanges = 0;
5809 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
5810 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5811 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
5812 int rc = VINF_SUCCESS;
5813
5814 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
5815
5816 AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
5817
5818 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
5819 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
5820 cRangesMax = 65536 * 512 / 8;
5821 else
5822 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
5823
5824 if (!cPrdtlEntries)
5825 {
5826 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5827 return VINF_SUCCESS;
5828 }
5829
5830 do
5831 {
5832 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5833 ? cPrdtlEntries
5834 : RT_ELEMENTS(aPrdtlEntries);
5835
5836 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5837
5838 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5839 {
5840 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5841 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5842
5843 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5844
5845 /* Copy into buffer. */
5846 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5847
5848 for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
5849 {
5850 aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
5851 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRange]) != 0)
5852 cRanges++;
5853 else
5854 break;
5855 }
5856 }
5857
5858 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5859 cPrdtlEntries -= cPrdtlEntriesRead;
5860 } while (cPrdtlEntries);
5861
5862 if (RT_UNLIKELY(!cRanges))
5863 {
5864 return VERR_BUFFER_OVERFLOW;
5865 }
5866
5867 pAhciReq->u.Trim.cRanges = cRanges;
5868 pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
5869 if (pAhciReq->u.Trim.paRanges)
5870 {
5871 uint32_t idxRange = 0;
5872
5873 cPrdtlEntries = pAhciReq->cPrdtlEntries;
5874 GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5875
5876 /* Convert the ranges from the guest to our format. */
5877 do
5878 {
5879 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5880 ? cPrdtlEntries
5881 : RT_ELEMENTS(aPrdtlEntries);
5882
5883 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5884
5885 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5886 {
5887 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5888 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5889
5890 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5891
5892 /* Copy into buffer. */
5893 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5894
5895 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
5896 {
5897 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
5898 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
5899 {
5900 pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
5901 pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
5902 idxRange++;
5903 }
5904 else
5905 break;
5906 }
5907 }
5908
5909 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5910 cPrdtlEntries -= cPrdtlEntriesRead;
5911 } while (idxRange < cRanges);
5912 }
5913 else
5914 rc = VERR_NO_MEMORY;
5915
5916 LogFlowFunc(("returns rc=%Rrc\n", rc));
5917 return rc;
5918}
5919
5920/**
5921 * Destroy the trim range list.
5922 *
5923 * @returns nothing.
5924 * @param pAhciReq The task state.
5925 */
5926static void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
5927{
5928 AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
5929 RTMemFree(pAhciReq->u.Trim.paRanges);
5930}
5931
5932/**
5933 * Complete a data transfer task by freeing all occupied resources
5934 * and notifying the guest.
5935 *
5936 * @returns Flag whether the given request was canceled inbetween;
5937 *
5938 * @param pAhciPort Pointer to the port where to request completed.
5939 * @param pAhciReq Pointer to the task which finished.
5940 * @param rcReq IPRT status code of the completed request.
5941 * @param fFreeReq Flag whether to free the request if it was canceled.
5942 */
5943static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq, bool fFreeReq)
5944{
5945 bool fXchg = false;
5946 bool fRedo = false;
5947 bool fCanceled = false;
5948 uint64_t tsNow = RTTimeMilliTS();
5949 AHCITXSTATE enmTxState = AHCITXSTATE_INVALID;
5950
5951 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d fFreeReq=%RTbool\n",
5952 pAhciPort, pAhciReq, rcReq, fFreeReq));
5953
5954 enmTxState = (AHCITXSTATE)ASMAtomicReadU32((volatile uint32_t *)&pAhciReq->enmTxState);
5955 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, enmTxState, pAhciReq->uOffset, pAhciReq->cbTransfer);
5956 VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(pAhciReq, tsNow);
5957
5958 /*
5959 * Leave a release log entry if the request was active for more than 25 seconds
5960 * (30 seconds is the timeout of the guest).
5961 */
5962 if (tsNow - pAhciReq->tsStart >= 25 * 1000)
5963 {
5964 const char *pcszReq = NULL;
5965
5966 switch (pAhciReq->enmTxDir)
5967 {
5968 case AHCITXDIR_READ:
5969 pcszReq = "Read";
5970 break;
5971 case AHCITXDIR_WRITE:
5972 pcszReq = "Write";
5973 break;
5974 case AHCITXDIR_FLUSH:
5975 pcszReq = "Flush";
5976 break;
5977 case AHCITXDIR_TRIM:
5978 pcszReq = "Trim";
5979 break;
5980 default:
5981 pcszReq = "<Invalid>";
5982 }
5983
5984 LogRel(("AHCI#%uP%u: %s request was active for %llu seconds\n",
5985 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, pcszReq, (tsNow - pAhciReq->tsStart) / 1000));
5986 }
5987
5988 bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset);
5989 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
5990
5991 if (fXchg && !fPortReset)
5992 {
5993 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
5994 {
5995 ahciIoBufFree(pAhciPort, pAhciReq, true /* fCopyToGuest */);
5996 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
5997 pAhciPort->Led.Actual.s.fReading = 0;
5998 }
5999 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
6000 {
6001 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6002 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
6003 pAhciPort->Led.Actual.s.fWriting = 0;
6004 }
6005 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6006 {
6007 ahciTrimRangesDestroy(pAhciReq);
6008 pAhciPort->Led.Actual.s.fWriting = 0;
6009 }
6010
6011 if (RT_FAILURE(rcReq))
6012 {
6013 /* Log the error. */
6014 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6015 {
6016 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6017 LogRel(("AHCI#%uP%u: Flush returned rc=%Rrc\n",
6018 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6019 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6020 LogRel(("AHCI#%uP%u: Trim returned rc=%Rrc\n",
6021 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6022 else
6023 LogRel(("AHCI#%uP%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6024 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6025 pAhciReq->enmTxDir == AHCITXDIR_READ
6026 ? "Read"
6027 : "Write",
6028 pAhciReq->uOffset,
6029 pAhciReq->cbTransfer, rcReq));
6030 }
6031
6032 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
6033 if (!fRedo)
6034 {
6035 pAhciReq->cmdHdr.u32PRDBC = 0;
6036 pAhciReq->uATARegError = ID_ERR;
6037 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6038 ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
6039 }
6040 else
6041 ASMAtomicOrU32(&pAhciPort->u32TasksRedo, RT_BIT_32(pAhciReq->uTag));
6042 }
6043 else
6044 {
6045 pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer;
6046
6047 /* Status will be set by already for non I/O requests. */
6048 if (pAhciReq->enmTxDir != AHCITXDIR_NONE)
6049 {
6050 pAhciReq->uATARegError = 0;
6051 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6052 }
6053
6054 /* Write updated command header into memory of the guest. */
6055 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6056
6057 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
6058 {
6059 /*
6060 * The guest tried to transfer more data than there is space in the buffer.
6061 * Terminate task and set the overflow bit.
6062 */
6063 /* Notify the guest. */
6064 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
6065 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
6066 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
6067 }
6068 }
6069
6070 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,
6071 ("Inconsistent request counter\n"));
6072 ASMAtomicDecU32(&pAhciPort->cTasksActive);
6073
6074 if (!fRedo)
6075 {
6076
6077 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
6078 if (pAhciReq->fFlags & AHCI_REQ_PIO_DATA)
6079 ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
6080
6081 if (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT)
6082 {
6083 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
6084 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
6085 }
6086
6087 if (pAhciReq->fFlags & AHCI_REQ_IS_QUEUED)
6088 {
6089 /*
6090 * Always raise an interrupt after task completion; delaying
6091 * this (interrupt coalescing) increases latency and has a significant
6092 * impact on performance (see @bugref{5071})
6093 */
6094 ahciSendSDBFis(pAhciPort, 0, true);
6095 }
6096 else
6097 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6098 }
6099 }
6100 else
6101 {
6102 /*
6103 * Task was canceled, do the cleanup but DO NOT access the guest memory!
6104 * The guest might use it for other things now because it doesn't know about that task anymore.
6105 */
6106 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_CANCELED || fPortReset,
6107 ("Task is not active but wasn't canceled and no port reset is active!\n"));
6108
6109 /*
6110 * If this handler switched the request state from active to free the request counter
6111 * must be decremented.
6112 */
6113 if (fXchg)
6114 {
6115 Assert(fPortReset);
6116 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,
6117 ("Inconsistent request counter\n"));
6118 ASMAtomicDecU32(&pAhciPort->cTasksActive);
6119 }
6120
6121 fCanceled = true;
6122 ASMAtomicXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE);
6123
6124 if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6125 ahciTrimRangesDestroy(pAhciReq);
6126 else if (pAhciReq->enmTxDir != AHCITXDIR_FLUSH)
6127 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6128
6129 /* Leave a log message about the canceled request. */
6130 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6131 {
6132 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6133 LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
6134 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6135 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6136 LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
6137 pAhciPort->CTX_SUFF(pDevIns)->iInstance,pAhciPort->iLUN, rcReq));
6138 else
6139 LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6140 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6141 pAhciReq->enmTxDir == AHCITXDIR_READ
6142 ? "read"
6143 : "write",
6144 pAhciReq->uOffset,
6145 pAhciReq->cbTransfer, rcReq));
6146 }
6147
6148 /* Finally free the task state structure because it is completely unused now. */
6149 if (fFreeReq)
6150 RTMemFree(pAhciReq);
6151 }
6152
6153 if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
6154 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6155
6156 return fCanceled;
6157}
6158
6159/**
6160 * Notification callback for a completed transfer.
6161 *
6162 * @returns VBox status code.
6163 * @param pInterface Pointer to the interface.
6164 * @param pvUser User data.
6165 * @param rcReq IPRT Status code of the completed request.
6166 */
6167static DECLCALLBACK(int) ahciR3TransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
6168{
6169 PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
6170 PAHCIREQ pAhciReq = (PAHCIREQ)pvUser;
6171
6172 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
6173 __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
6174
6175 ahciTransferComplete(pAhciPort, pAhciReq, rcReq, true);
6176
6177 return VINF_SUCCESS;
6178}
6179
6180/**
6181 * Process an non read/write ATA command.
6182 *
6183 * @returns The direction of the data transfer
6184 * @param pCmdHdr Pointer to the command header.
6185 */
6186static AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
6187{
6188 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
6189 bool fLBA48 = false;
6190 CmdHdr *pCmdHdr = &pAhciReq->cmdHdr;
6191
6192 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
6193
6194 pAhciReq->cbTransfer = 0;
6195
6196 switch (pCmdFis[AHCI_CMDFIS_CMD])
6197 {
6198 case ATA_IDENTIFY_DEVICE:
6199 {
6200 if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
6201 {
6202 uint16_t u16Temp[256];
6203 size_t cbCopied;
6204
6205 /* Fill the buffer. */
6206 ahciIdentifySS(pAhciPort, u16Temp);
6207
6208 /* Copy the buffer. */
6209 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6210 &u16Temp[0], sizeof(u16Temp));
6211
6212 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6213 pAhciReq->cbTransfer = cbCopied;
6214 }
6215 else
6216 {
6217 pAhciReq->uATARegError = ABRT_ERR;
6218 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
6219 }
6220 break;
6221 }
6222 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
6223 case ATA_READ_NATIVE_MAX_ADDRESS:
6224 break;
6225 case ATA_SET_FEATURES:
6226 {
6227 switch (pCmdFis[AHCI_CMDFIS_FET])
6228 {
6229 case 0x02: /* write cache enable */
6230 case 0xaa: /* read look-ahead enable */
6231 case 0x55: /* read look-ahead disable */
6232 case 0xcc: /* reverting to power-on defaults enable */
6233 case 0x66: /* reverting to power-on defaults disable */
6234 pAhciReq->uATARegError = 0;
6235 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6236 break;
6237 case 0x82: /* write cache disable */
6238 enmTxDir = AHCITXDIR_FLUSH;
6239 break;
6240 case 0x03:
6241 {
6242 /* set transfer mode */
6243 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6244 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
6245 {
6246 case 0x00: /* PIO default */
6247 case 0x08: /* PIO mode */
6248 break;
6249 case ATA_MODE_MDMA: /* MDMA mode */
6250 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
6251 break;
6252 case ATA_MODE_UDMA: /* UDMA mode */
6253 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6254 break;
6255 }
6256 break;
6257 }
6258 default:
6259 pAhciReq->uATARegError = ABRT_ERR;
6260 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6261 }
6262 break;
6263 }
6264 case ATA_DEVICE_RESET:
6265 {
6266 if (!pAhciPort->fATAPI)
6267 {
6268 pAhciReq->uATARegError = ABRT_ERR;
6269 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6270 }
6271 else
6272 {
6273 /* Reset the device. */
6274 ahciDeviceReset(pAhciPort, pAhciReq);
6275 }
6276 break;
6277 }
6278 case ATA_FLUSH_CACHE_EXT:
6279 case ATA_FLUSH_CACHE:
6280 enmTxDir = AHCITXDIR_FLUSH;
6281 break;
6282 case ATA_PACKET:
6283 if (!pAhciPort->fATAPI)
6284 {
6285 pAhciReq->uATARegError = ABRT_ERR;
6286 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6287 }
6288 else
6289 enmTxDir = atapiParseCmd(pAhciPort, pAhciReq);
6290 break;
6291 case ATA_IDENTIFY_PACKET_DEVICE:
6292 if (!pAhciPort->fATAPI)
6293 {
6294 pAhciReq->uATARegError = ABRT_ERR;
6295 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6296 }
6297 else
6298 {
6299 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6300
6301 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6302 pAhciReq->uATARegError = 0;
6303 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6304 }
6305 break;
6306 case ATA_SET_MULTIPLE_MODE:
6307 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
6308 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
6309 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6310 {
6311 pAhciReq->uATARegError = ABRT_ERR;
6312 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6313 }
6314 else
6315 {
6316 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6317 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6318 pAhciReq->uATARegError = 0;
6319 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6320 }
6321 break;
6322 case ATA_STANDBY_IMMEDIATE:
6323 break; /* Do nothing. */
6324 case ATA_CHECK_POWER_MODE:
6325 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
6326 /* fall through */
6327 case ATA_INITIALIZE_DEVICE_PARAMETERS:
6328 case ATA_IDLE_IMMEDIATE:
6329 case ATA_RECALIBRATE:
6330 case ATA_NOP:
6331 case ATA_READ_VERIFY_SECTORS_EXT:
6332 case ATA_READ_VERIFY_SECTORS:
6333 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
6334 case ATA_SLEEP:
6335 pAhciReq->uATARegError = 0;
6336 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6337 break;
6338 case ATA_READ_DMA_EXT:
6339 fLBA48 = true;
6340 case ATA_READ_DMA:
6341 {
6342 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6343 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6344 enmTxDir = AHCITXDIR_READ;
6345 break;
6346 }
6347 case ATA_WRITE_DMA_EXT:
6348 fLBA48 = true;
6349 case ATA_WRITE_DMA:
6350 {
6351 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6352 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6353 enmTxDir = AHCITXDIR_WRITE;
6354 break;
6355 }
6356 case ATA_READ_FPDMA_QUEUED:
6357 {
6358 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6359 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6360 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6361 enmTxDir = AHCITXDIR_READ;
6362 break;
6363 }
6364 case ATA_WRITE_FPDMA_QUEUED:
6365 {
6366 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6367 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6368 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6369 enmTxDir = AHCITXDIR_WRITE;
6370 break;
6371 }
6372 case ATA_READ_LOG_EXT:
6373 {
6374 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6375 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6376 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6377 size_t cbCopied;
6378
6379 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6380
6381 uint8_t aBuf[512];
6382
6383 memset(aBuf, 0, sizeof(aBuf));
6384
6385 if (offLogRead + cbLogRead <= sizeof(aBuf))
6386 {
6387 switch (iPage)
6388 {
6389 case 0x10:
6390 {
6391 LogFlow(("Reading error page\n"));
6392 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6393 if (pTaskErr)
6394 {
6395 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6396 aBuf[2] = pTaskErr->uATARegStatus;
6397 aBuf[3] = pTaskErr->uATARegError;
6398 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6399 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6400 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6401 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6402 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6403 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6404 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6405 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6406 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6407
6408 /* Calculate checksum */
6409 uint8_t uChkSum = 0;
6410 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6411 uChkSum += aBuf[i];
6412
6413 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6414
6415 if (pTaskErr->enmTxDir == AHCITXDIR_TRIM)
6416 ahciTrimRangesDestroy(pTaskErr);
6417 else if (pTaskErr->enmTxDir != AHCITXDIR_FLUSH)
6418 ahciIoBufFree(pAhciPort, pTaskErr, false /* fCopyToGuest */);
6419
6420 /* Finally free the error task state structure because it is completely unused now. */
6421 RTMemFree(pTaskErr);
6422 }
6423
6424 /*
6425 * Reading this log page results in an abort of all outstanding commands
6426 * and clearing the SActive register and TaskFile register.
6427 *
6428 * See SATA2 1.2 spec chapter 4.2.3.4
6429 */
6430 bool fAbortedAll = ahciCancelActiveTasks(pAhciPort, pAhciReq);
6431 Assert(fAbortedAll);
6432 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6433
6434 break;
6435 }
6436 }
6437
6438 /* Copy the buffer. */
6439 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6440 &aBuf[offLogRead], cbLogRead);
6441
6442 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6443 pAhciReq->cbTransfer = cbCopied;
6444 }
6445
6446 break;
6447 }
6448 case ATA_DATA_SET_MANAGEMENT:
6449 {
6450 if ( ( !pAhciPort->fAsyncInterface
6451 && pAhciPort->pDrvBlock->pfnDiscard)
6452 || ( pAhciPort->fAsyncInterface
6453 && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
6454 {
6455 /* Check that the trim bit is set and all other bits are 0. */
6456 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6457 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6458 {
6459 pAhciReq->uATARegError = ABRT_ERR;
6460 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6461 }
6462 else
6463 enmTxDir = AHCITXDIR_TRIM;
6464 break;
6465 }
6466 /* else: fall through and report error to the guest. */
6467 }
6468 /* All not implemented commands go below. */
6469 case ATA_SECURITY_FREEZE_LOCK:
6470 case ATA_SMART:
6471 case ATA_NV_CACHE:
6472 case ATA_IDLE:
6473 pAhciReq->uATARegError = ABRT_ERR;
6474 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6475 break;
6476 default: /* For debugging purposes. */
6477 AssertMsgFailed(("Unknown command issued\n"));
6478 pAhciReq->uATARegError = ABRT_ERR;
6479 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6480 }
6481
6482 return enmTxDir;
6483}
6484
6485/**
6486 * Retrieve a command FIS from guest memory.
6487 *
6488 * @returns whether the H2D FIS was successfully read from the guest memory.
6489 * @param pAhciReq The state of the actual task.
6490 */
6491static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6492{
6493 RTGCPHYS GCPhysAddrCmdTbl;
6494
6495 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
6496 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
6497 false);
6498
6499 /*
6500 * First we are reading the command header pointed to by regCLB.
6501 * From this we get the address of the command table which we are reading too.
6502 * We can process the Command FIS afterwards.
6503 */
6504 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6505 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6506 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6507 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6508
6509#ifdef LOG_ENABLED
6510 /* Print some infos about the command header. */
6511 ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
6512#endif
6513
6514 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
6515
6516 AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6517 ("This is not a command FIS!!\n"),
6518 false);
6519
6520 /* Read the command Fis. */
6521 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6522 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6523
6524 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
6525 ("This is not a command FIS\n"),
6526 false);
6527
6528 /* Set transfer direction. */
6529 pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
6530
6531 /* If this is an ATAPI command read the atapi command. */
6532 if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6533 {
6534 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6535 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6536 }
6537
6538 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6539 if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6540 {
6541 /*
6542 * 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.
6543 * but this FIS does not assert an interrupt
6544 */
6545 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6546 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6547 }
6548
6549 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6550 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
6551
6552#ifdef LOG_ENABLED
6553 /* Print some infos about the FIS. */
6554 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6555
6556 /* Print the PRDT */
6557 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6558 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6559
6560 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6561 {
6562 SGLEntry SGEntry;
6563
6564 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6565 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6566
6567 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6568 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6569
6570 GCPhysPrdtl += sizeof(SGLEntry);
6571 }
6572#endif
6573
6574 return true;
6575}
6576
6577/**
6578 * Transmit queue consumer
6579 * Queue a new async task.
6580 *
6581 * @returns Success indicator.
6582 * If false the item will not be removed and the flushing will stop.
6583 * @param pDevIns The device instance.
6584 * @param pItem The item to consume. Upon return this item will be freed.
6585 */
6586static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6587{
6588 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6589 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6590 PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
6591 int rc = VINF_SUCCESS;
6592
6593 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6594 /* Notify the async IO thread. */
6595 rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6596 AssertRC(rc);
6597
6598 return true;
6599}
6600
6601/* The async IO thread for one port. */
6602static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6603{
6604 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6605 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6606 int rc = VINF_SUCCESS;
6607 uint64_t u64StartTime = 0;
6608 uint64_t u64StopTime = 0;
6609 uint32_t uIORequestsProcessed = 0;
6610 uint32_t uIOsPerSec = 0;
6611 uint32_t fTasksToProcess = 0;
6612
6613 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6614
6615 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6616 return VINF_SUCCESS;
6617
6618 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6619 {
6620 unsigned idx = 0;
6621 uint32_t u32Tasks = 0;
6622 uint32_t u32RegHbaCtrl = 0;
6623
6624 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
6625 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6626 if (!u32Tasks)
6627 {
6628 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
6629 rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
6630 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
6631 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
6632 break;
6633 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
6634 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6635 }
6636
6637 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
6638 ASMAtomicIncU32(&pAhci->cThreadsActive);
6639
6640 /*
6641 * Check whether the global host controller bit is set and go to sleep immediately again
6642 * if it is set.
6643 */
6644 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6645 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
6646 && !ASMAtomicDecU32(&pAhci->cThreadsActive))
6647 {
6648 ahciHBAReset(pAhci);
6649 continue;
6650 }
6651
6652 idx = ASMBitFirstSetU32(u32Tasks);
6653 while ( idx
6654 && !pAhciPort->fPortReset)
6655 {
6656 bool fReqCanceled = false;
6657 AHCITXDIR enmTxDir;
6658 PAHCIREQ pAhciReq;
6659
6660 /* Decrement to get the slot number. */
6661 idx--;
6662 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6663
6664 /*
6665 * Check if there is already an allocated task struct in the cache.
6666 * Allocate a new task otherwise.
6667 */
6668 if (!pAhciPort->aCachedTasks[idx])
6669 {
6670 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6671 AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n"));
6672 pAhciReq->enmTxState = AHCITXSTATE_FREE;
6673 pAhciPort->aCachedTasks[idx] = pAhciReq;
6674 }
6675 else
6676 pAhciReq = pAhciPort->aCachedTasks[idx];
6677
6678 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE);
6679 AssertMsg(fXchg, ("Task is already active\n"));
6680
6681 pAhciReq->tsStart = RTTimeMilliTS();
6682 pAhciReq->uATARegStatus = 0;
6683 pAhciReq->uATARegError = 0;
6684 pAhciReq->fFlags = 0;
6685
6686 /* Set current command slot */
6687 pAhciReq->uTag = idx;
6688 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6689
6690 bool fFisRead = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6691 if (RT_UNLIKELY(!fFisRead))
6692 {
6693 /*
6694 * Couldn't find anything in either the AHCI or SATA spec which
6695 * indicates what should be done if the FIS is not read successfully.
6696 * The closest thing is in the state machine, stating that the device
6697 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
6698 * Do the same here and ignore any corrupt FIS types, after all
6699 * the guest messed up everything and this behavior is undefined.
6700 */
6701 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
6702 Assert(fXchg);
6703 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6704 idx = ASMBitFirstSetU32(u32Tasks);
6705 continue;
6706 }
6707
6708 /* 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. */
6709 if (pAhciPort->regSACT & (1 << idx))
6710 {
6711 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6712 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
6713 }
6714
6715 if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
6716 {
6717 /* If the reset bit is set put the device into reset state. */
6718 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6719 {
6720 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6721 pAhciPort->fResetDevice = true;
6722 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6723 }
6724 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6725 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6726 else /* We are not in a reset state update the control registers. */
6727 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6728
6729 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
6730 AssertMsg(fXchg, ("Task is not active\n"));
6731 break;
6732 }
6733 else
6734 {
6735 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
6736 ("There are more than 32 requests active"));
6737 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6738
6739 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6740 pAhciReq->enmTxDir = enmTxDir;
6741
6742 if (enmTxDir != AHCITXDIR_NONE)
6743 {
6744 if ( enmTxDir != AHCITXDIR_FLUSH
6745 && enmTxDir != AHCITXDIR_TRIM)
6746 {
6747 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6748
6749 rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
6750 if (RT_FAILURE(rc))
6751 {
6752 /* In case we can't allocate enough memory fail the request with an overflow error. */
6753 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
6754 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
6755 }
6756 }
6757
6758 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6759 {
6760 if (pAhciPort->fAsyncInterface)
6761 {
6762 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);
6763 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);
6764 if (enmTxDir == AHCITXDIR_FLUSH)
6765 {
6766 rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
6767 pAhciReq);
6768 }
6769 else if (enmTxDir == AHCITXDIR_TRIM)
6770 {
6771 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6772 if (RT_SUCCESS(rc))
6773 {
6774 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6775 rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
6776 pAhciReq->u.Trim.cRanges, pAhciReq);
6777 }
6778 }
6779 else if (enmTxDir == AHCITXDIR_READ)
6780 {
6781 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6782 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6783 &pAhciReq->u.Io.DataSeg, 1,
6784 pAhciReq->cbTransfer,
6785 pAhciReq);
6786 }
6787 else
6788 {
6789 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6790 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6791 &pAhciReq->u.Io.DataSeg, 1,
6792 pAhciReq->cbTransfer,
6793 pAhciReq);
6794 }
6795 if (rc == VINF_VD_ASYNC_IO_FINISHED)
6796 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6797 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6798 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
6799 }
6800 else
6801 {
6802 if (enmTxDir == AHCITXDIR_FLUSH)
6803 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
6804 else if (enmTxDir == AHCITXDIR_TRIM)
6805 {
6806 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6807 if (RT_SUCCESS(rc))
6808 {
6809 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6810 rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock, pAhciReq->u.Trim.paRanges,
6811 pAhciReq->u.Trim.cRanges);
6812 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6813 }
6814 }
6815 else if (enmTxDir == AHCITXDIR_READ)
6816 {
6817 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6818 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, pAhciReq->uOffset,
6819 pAhciReq->u.Io.DataSeg.pvSeg,
6820 pAhciReq->cbTransfer);
6821 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;
6822 }
6823 else
6824 {
6825 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6826 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, pAhciReq->uOffset,
6827 pAhciReq->u.Io.DataSeg.pvSeg,
6828 pAhciReq->cbTransfer);
6829 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6830 }
6831 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
6832 }
6833 }
6834 }
6835 else
6836 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6837 } /* Command */
6838
6839 /*
6840 * Don't process other requests if the last one was canceled,
6841 * the others are not valid anymore.
6842 */
6843 if (fReqCanceled)
6844 break;
6845
6846 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6847 idx = ASMBitFirstSetU32(u32Tasks);
6848 } /* while tasks available */
6849
6850 /* Check whether a port reset was active. */
6851 if ( ASMAtomicReadBool(&pAhciPort->fPortReset)
6852 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
6853 ahciPortResetFinish(pAhciPort);
6854
6855 /*
6856 * Check whether a host controller reset is pending and execute the reset
6857 * if this is the last active thread.
6858 */
6859 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6860 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
6861 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
6862 && !cThreadsActive)
6863 ahciHBAReset(pAhci);
6864 } /* While running */
6865
6866 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
6867 return VINF_SUCCESS;
6868}
6869
6870/**
6871 * Unblock the async I/O thread so it can respond to a state change.
6872 *
6873 * @returns VBox status code.
6874 * @param pDevIns The device instance.
6875 * @param pThread The send thread.
6876 */
6877static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6878{
6879 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6880 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6881 return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6882}
6883
6884/* -=-=-=-=- DBGF -=-=-=-=- */
6885
6886/**
6887 * AHCI status info callback.
6888 *
6889 * @param pDevIns The device instance.
6890 * @param pHlp The output helpers.
6891 * @param pszArgs The arguments.
6892 */
6893static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6894{
6895 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6896
6897 /*
6898 * Show info.
6899 */
6900 pHlp->pfnPrintf(pHlp,
6901 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
6902 pDevIns->pReg->szName,
6903 pDevIns->iInstance,
6904 pThis->MMIOBase,
6905 pThis->cPortsImpl,
6906 pThis->fGCEnabled ? true : false,
6907 pThis->fR0Enabled ? true : false);
6908
6909 /*
6910 * Show global registers.
6911 */
6912 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
6913 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
6914 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
6915 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
6916 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
6917 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
6918 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
6919 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
6920
6921 /*
6922 * Per port data.
6923 */
6924 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
6925 {
6926 PAHCIPort pThisPort = &pThis->ahciPort[i];
6927
6928 pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
6929 pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
6930 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
6931 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
6932 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
6933 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
6934 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
6935 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
6936 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
6937 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
6938 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
6939 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
6940 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
6941 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
6942 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
6943 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
6944 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
6945 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
6946 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
6947 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
6948 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
6949 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
6950 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
6951 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
6952 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
6953 pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
6954 pHlp->pfnPrintf(pHlp, "\n");
6955 }
6956}
6957
6958/* -=-=-=-=- Helper -=-=-=-=- */
6959
6960/**
6961 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
6962 *
6963 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
6964 * use of it in strict builds (which is why it's up here).
6965 *
6966 * @returns true if quiesced, false if busy.
6967 * @param pDevIns The device instance.
6968 */
6969static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
6970{
6971 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6972
6973 if (pThis->cThreadsActive)
6974 return false;
6975
6976 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
6977 {
6978 PAHCIPort pThisPort = &pThis->ahciPort[i];
6979 if (pThisPort->pDrvBase)
6980 {
6981 if ( (pThisPort->cTasksActive != 0)
6982 || (pThisPort->u32TasksNew != 0))
6983 return false;
6984 }
6985 }
6986 return true;
6987}
6988
6989/* -=-=-=-=- Saved State -=-=-=-=- */
6990
6991/**
6992 * @copydoc FNDEVSSMSAVEPREP
6993 */
6994static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6995{
6996 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6997 return VINF_SUCCESS;
6998}
6999
7000/**
7001 * @copydoc FNDEVSSMLOADPREP
7002 */
7003static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7004{
7005 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
7006 return VINF_SUCCESS;
7007}
7008
7009/**
7010 * @copydoc FNDEVSSMLIVEEXEC
7011 */
7012static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
7013{
7014 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7015
7016 /* config. */
7017 SSMR3PutU32(pSSM, pThis->cPortsImpl);
7018 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7019 {
7020 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
7021 SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
7022 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
7023 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
7024 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
7025 }
7026
7027 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7028 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7029 {
7030 uint32_t iPort;
7031 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7032 AssertRCReturn(rc, rc);
7033 SSMR3PutU32(pSSM, iPort);
7034 }
7035
7036 return VINF_SSM_DONT_CALL_AGAIN;
7037}
7038
7039/**
7040 * @copydoc FNDEVSSMSAVEEXEC
7041 */
7042static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7043{
7044 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7045 uint32_t i;
7046 int rc;
7047
7048 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
7049
7050 /* The config */
7051 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
7052 AssertRCReturn(rc, rc);
7053
7054 /* The main device structure. */
7055 SSMR3PutU32(pSSM, pThis->regHbaCap);
7056 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
7057 SSMR3PutU32(pSSM, pThis->regHbaIs);
7058 SSMR3PutU32(pSSM, pThis->regHbaPi);
7059 SSMR3PutU32(pSSM, pThis->regHbaVs);
7060 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
7061 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
7062 SSMR3PutU8(pSSM, pThis->uCccPortNr);
7063 SSMR3PutU64(pSSM, pThis->uCccTimeout);
7064 SSMR3PutU32(pSSM, pThis->uCccNr);
7065 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
7066 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
7067 SSMR3PutBool(pSSM, pThis->fReset);
7068 SSMR3PutBool(pSSM, pThis->f64BitAddr);
7069 SSMR3PutBool(pSSM, pThis->fR0Enabled);
7070 SSMR3PutBool(pSSM, pThis->fGCEnabled);
7071 SSMR3PutBool(pSSM, pThis->fLegacyPortResetMethod);
7072
7073 /* Now every port. */
7074 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7075 {
7076 Assert(pThis->ahciPort[i].cTasksActive == 0);
7077 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
7078 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
7079 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
7080 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
7081 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
7082 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
7083 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
7084 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
7085 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
7086 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
7087 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
7088 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
7089 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
7090 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
7091 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
7092 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
7093 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
7094 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
7095 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
7096 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
7097 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
7098 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
7099 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
7100 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
7101 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
7102 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
7103 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
7104 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
7105
7106 /* ATAPI saved state. */
7107 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
7108 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
7109 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
7110 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
7111 }
7112
7113 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
7114}
7115
7116/**
7117 * Loads a saved legacy ATA emulated device state.
7118 *
7119 * @returns VBox status code.
7120 * @param pSSM The handle to the saved state.
7121 */
7122static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
7123{
7124 int rc;
7125 uint32_t u32Version;
7126 uint32_t u32;
7127 uint32_t u32IOBuffer;
7128
7129 /* Test for correct version. */
7130 rc = SSMR3GetU32(pSSM, &u32Version);
7131 AssertRCReturn(rc, rc);
7132 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
7133
7134 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
7135 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
7136 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7137 {
7138 AssertMsgFailed(("u32Version=%d\n", u32Version));
7139 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7140 }
7141
7142 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
7143
7144 for (uint32_t j = 0; j < 2; j++)
7145 {
7146 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
7147
7148 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
7149 SSMR3Skip(pSSM, 64);
7150 else
7151 SSMR3Skip(pSSM, 2);
7152 /** @todo triple-check this hack after passthrough is working */
7153 SSMR3Skip(pSSM, 1);
7154
7155 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7156 SSMR3Skip(pSSM, 4);
7157
7158 SSMR3Skip(pSSM, sizeof(PDMLED));
7159 SSMR3GetU32(pSSM, &u32IOBuffer);
7160 if (u32IOBuffer)
7161 SSMR3Skip(pSSM, u32IOBuffer);
7162 }
7163
7164 rc = SSMR3GetU32(pSSM, &u32);
7165 if (RT_FAILURE(rc))
7166 return rc;
7167 if (u32 != ~0U)
7168 {
7169 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
7170 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
7171 return rc;
7172 }
7173
7174 return VINF_SUCCESS;
7175}
7176
7177/**
7178 * Loads a saved AHCI device state.
7179 *
7180 * @returns VBox status code.
7181 * @param pDevIns The device instance.
7182 * @param pSSM The handle to the saved state.
7183 * @param uVersion The data unit version number.
7184 * @param uPass The data pass.
7185 */
7186static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
7187{
7188 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7189 uint32_t u32;
7190 int rc;
7191
7192 if ( uVersion > AHCI_SAVED_STATE_VERSION
7193 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
7194 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7195
7196 /* Deal with the priod after removing the saved IDE bits where the saved
7197 state version remained unchanged. */
7198 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
7199 && SSMR3HandleRevision(pSSM) >= 79045
7200 && SSMR3HandleRevision(pSSM) < 79201)
7201 uVersion++;
7202
7203 /*
7204 * Check whether we have to resort to the legacy port reset method to
7205 * prevent older BIOS versions from failing after a reset.
7206 */
7207 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7208 pThis->fLegacyPortResetMethod = true;
7209
7210 /* Verify config. */
7211 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
7212 {
7213 rc = SSMR3GetU32(pSSM, &u32);
7214 AssertRCReturn(rc, rc);
7215 if (u32 != pThis->cPortsImpl)
7216 {
7217 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
7218 if ( u32 < pThis->cPortsImpl
7219 || u32 > AHCI_MAX_NR_PORTS_IMPL)
7220 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
7221 u32, pThis->cPortsImpl);
7222 }
7223
7224 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7225 {
7226 bool fInUse;
7227 rc = SSMR3GetBool(pSSM, &fInUse);
7228 AssertRCReturn(rc, rc);
7229 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
7230 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7231 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
7232 fInUse ? "target" : "source", i );
7233
7234 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
7235 {
7236 bool fHotpluggable;
7237 rc = SSMR3GetBool(pSSM, &fHotpluggable);
7238 AssertRCReturn(rc, rc);
7239 if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
7240 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7241 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
7242 i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
7243 }
7244 else
7245 Assert(pThis->ahciPort[i].fHotpluggable);
7246
7247 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
7248 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
7249 AssertRCReturn(rc, rc);
7250 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
7251 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
7252 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
7253
7254 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
7255 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
7256 AssertRCReturn(rc, rc);
7257 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
7258 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
7259 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
7260
7261 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
7262 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
7263 AssertRCReturn(rc, rc);
7264 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
7265 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
7266 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
7267 }
7268
7269 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7270 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7271 {
7272 uint32_t iPort;
7273 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7274 AssertRCReturn(rc, rc);
7275
7276 uint32_t iPortSaved;
7277 rc = SSMR3GetU32(pSSM, &iPortSaved);
7278 AssertRCReturn(rc, rc);
7279
7280 if (iPortSaved != iPort)
7281 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
7282 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
7283 }
7284 }
7285
7286 if (uPass == SSM_PASS_FINAL)
7287 {
7288 /* Restore data. */
7289
7290 /* The main device structure. */
7291 SSMR3GetU32(pSSM, &pThis->regHbaCap);
7292 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
7293 SSMR3GetU32(pSSM, &pThis->regHbaIs);
7294 SSMR3GetU32(pSSM, &pThis->regHbaPi);
7295 SSMR3GetU32(pSSM, &pThis->regHbaVs);
7296 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
7297 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
7298 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
7299 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
7300 SSMR3GetU32(pSSM, &pThis->uCccNr);
7301 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
7302
7303 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
7304 SSMR3GetBool(pSSM, &pThis->fReset);
7305 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
7306 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
7307 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
7308 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7309 SSMR3GetBool(pSSM, &pThis->fLegacyPortResetMethod);
7310
7311 /* Now every port. */
7312 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7313 {
7314 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7315
7316 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
7317 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
7318 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
7319 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
7320 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
7321 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
7322 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
7323 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
7324 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
7325 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
7326 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
7327 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
7328 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
7329 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
7330 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
7331 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
7332 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
7333 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
7334 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
7335 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
7336 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
7337 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7338 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7339
7340 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7341 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7342
7343 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7344 {
7345 /* The old positions in the FIFO, not required. */
7346 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7347 }
7348 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7349 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7350 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7351 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7352
7353 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7354 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7355
7356 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7357 {
7358 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7359 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7360 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7361 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7362 }
7363 else if (pThis->ahciPort[i].fATAPI)
7364 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
7365
7366 /* Check if we have tasks pending. */
7367 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7368 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7369
7370 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7371
7372 if (pAhciPort->u32TasksNew)
7373 {
7374 /*
7375 * There are tasks pending. The VM was saved after a task failed
7376 * because of non-fatal error. Set the redo flag.
7377 */
7378 pAhciPort->fRedo = true;
7379 }
7380 }
7381
7382 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7383 {
7384 for (uint32_t i = 0; i < 2; i++)
7385 {
7386 rc = ahciR3LoadLegacyEmulationState(pSSM);
7387 if(RT_FAILURE(rc))
7388 return rc;
7389 }
7390 }
7391
7392 rc = SSMR3GetU32(pSSM, &u32);
7393 if (RT_FAILURE(rc))
7394 return rc;
7395 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7396 }
7397
7398 return VINF_SUCCESS;
7399}
7400
7401/* -=-=-=-=- device PDM interface -=-=-=-=- */
7402
7403static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7404{
7405 uint32_t i;
7406 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7407
7408 pAhci->pDevInsRC += offDelta;
7409 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7410 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7411
7412 /* Relocate every port. */
7413 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7414 {
7415 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7416 pAhciPort->pAhciRC += offDelta;
7417 pAhciPort->pDevInsRC += offDelta;
7418 }
7419}
7420
7421/**
7422 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7423 * from now on, regardless if there was a medium inserted or not.
7424 */
7425static void ahciMediumRemoved(PAHCIPort pAhciPort)
7426{
7427 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7428}
7429
7430/**
7431 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7432 * there was already a medium inserted, don't forget to send the "medium
7433 * removed" event first.
7434 */
7435static void ahciMediumInserted(PAHCIPort pAhciPort)
7436{
7437 uint32_t OldStatus, NewStatus;
7438 do
7439 {
7440 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7441 switch (OldStatus)
7442 {
7443 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7444 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7445 /* no change, we will send "medium removed" + "medium inserted" */
7446 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7447 break;
7448 default:
7449 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7450 break;
7451 }
7452 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7453}
7454
7455/**
7456 * Called when a media is mounted.
7457 *
7458 * @param pInterface Pointer to the interface structure containing the called function pointer.
7459 */
7460static DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
7461{
7462 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7463 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7464
7465 /* Ignore the call if we're called while being attached. */
7466 if (!pAhciPort->pDrvBlock)
7467 return;
7468
7469 if (pAhciPort->fATAPI)
7470 {
7471 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7472
7473 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7474
7475 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7476 if (pAhciPort->cNotifiedMediaChange < 2)
7477 pAhciPort->cNotifiedMediaChange = 2;
7478 ahciMediumInserted(pAhciPort);
7479 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7480 }
7481 else
7482 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7483}
7484
7485/**
7486 * Called when a media is unmounted
7487 * @param pInterface Pointer to the interface structure containing the called function pointer.
7488 */
7489static DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7490{
7491 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7492 Log(("%s:\n", __FUNCTION__));
7493
7494 pAhciPort->cTotalSectors = 0;
7495
7496 if (pAhciPort->fATAPI)
7497 {
7498 /*
7499 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7500 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7501 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7502 * present and 2 in which it is changed.
7503 */
7504 pAhciPort->cNotifiedMediaChange = 4;
7505 ahciMediumRemoved(pAhciPort);
7506 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7507 }
7508 else
7509 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7510}
7511
7512/**
7513 * Configure the attached device for a port.
7514 *
7515 * Used by ahciR3Construct and ahciR3Attach.
7516 *
7517 * @returns VBox status code
7518 * @param pDevIns The device instance data.
7519 * @param pAhciPort The port for which the device is to be configured.
7520 */
7521static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7522{
7523 int rc = VINF_SUCCESS;
7524 PDMBLOCKTYPE enmType;
7525
7526 /*
7527 * Query the block and blockbios interfaces.
7528 */
7529 pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
7530 if (!pAhciPort->pDrvBlock)
7531 {
7532 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
7533 return VERR_PDM_MISSING_INTERFACE;
7534 }
7535 pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
7536 if (!pAhciPort->pDrvBlockBios)
7537 {
7538 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
7539 return VERR_PDM_MISSING_INTERFACE;
7540 }
7541
7542 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7543
7544 /* Try to get the optional async block interface. */
7545 pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
7546
7547 /*
7548 * Validate type.
7549 */
7550 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
7551
7552 if ( enmType != PDMBLOCKTYPE_HARD_DISK
7553 && enmType != PDMBLOCKTYPE_CDROM
7554 && enmType != PDMBLOCKTYPE_DVD)
7555 {
7556 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
7557 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
7558 }
7559
7560 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
7561 && !pAhciPort->pDrvMount)
7562 {
7563 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
7564 return VERR_INTERNAL_ERROR;
7565 }
7566 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
7567 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
7568
7569 if (pAhciPort->fATAPI)
7570 {
7571 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7572 pAhciPort->PCHSGeometry.cCylinders = 0;
7573 pAhciPort->PCHSGeometry.cHeads = 0;
7574 pAhciPort->PCHSGeometry.cSectors = 0;
7575 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7576 }
7577 else
7578 {
7579 pAhciPort->cbSector = pAhciPort->pDrvBlock->pfnGetSectorSize(pAhciPort->pDrvBlock);
7580 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / pAhciPort->cbSector;
7581 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
7582 &pAhciPort->PCHSGeometry);
7583 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7584 {
7585 pAhciPort->PCHSGeometry.cCylinders = 0;
7586 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7587 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7588 }
7589 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7590 {
7591 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7592 rc = VINF_SUCCESS;
7593 }
7594 AssertRC(rc);
7595
7596 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7597 || pAhciPort->PCHSGeometry.cHeads == 0
7598 || pAhciPort->PCHSGeometry.cSectors == 0)
7599 {
7600 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7601 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7602 pAhciPort->PCHSGeometry.cHeads = 16;
7603 pAhciPort->PCHSGeometry.cSectors = 63;
7604 /* Set the disk geometry information. Ignore errors. */
7605 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
7606 &pAhciPort->PCHSGeometry);
7607 rc = VINF_SUCCESS;
7608 }
7609 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7610 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7611 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7612 pAhciPort->cTotalSectors));
7613 if (pAhciPort->pDrvBlock->pfnDiscard)
7614 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7615 }
7616 return rc;
7617}
7618
7619/**
7620 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7621 *
7622 * @returns true if we've quiesced, false if we're still working.
7623 * @param pDevIns The device instance.
7624 */
7625static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7626{
7627 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7628 return false;
7629
7630 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7631 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7632 /*
7633 * Free all cached tasks here, not possible on destruct because the driver
7634 * is destroyed before us.
7635 */
7636 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7637 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7638 return true;
7639}
7640
7641/**
7642 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7643 */
7644static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7645{
7646 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7647
7648 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7649 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7650 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7651 else
7652 {
7653 /*
7654 * Free all cached tasks here, not possible on destruct because the driver
7655 * is destroyed before us.
7656 */
7657 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7658 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7659
7660 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7661 }
7662}
7663
7664/**
7665 * Suspend notification.
7666 *
7667 * @param pDevIns The device instance data.
7668 */
7669static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7670{
7671 Log(("ahciR3Suspend\n"));
7672 ahciR3SuspendOrPowerOff(pDevIns);
7673}
7674
7675/**
7676 * Resume notification.
7677 *
7678 * @param pDevIns The device instance data.
7679 */
7680static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7681{
7682 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7683
7684 /*
7685 * Check if one of the ports has pending tasks.
7686 * Queue a notification item again in this case.
7687 */
7688 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7689 {
7690 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7691
7692 if (pAhciPort->u32TasksRedo)
7693 {
7694 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7695 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7696
7697 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
7698 pAhciPort->u32TasksRedo = 0;
7699
7700 Assert(pAhciPort->fRedo);
7701 pAhciPort->fRedo = false;
7702
7703 pItem->iPort = pAhci->ahciPort[i].iLUN;
7704 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7705 }
7706 }
7707
7708 Log(("%s:\n", __FUNCTION__));
7709}
7710
7711/**
7712 * Initializes the VPD data of a attached device.
7713 *
7714 * @returns VBox status code.
7715 * @param pDevIns The device instance.
7716 * @param pAhciPort The attached device.
7717 * @param szName Name of the port to get the CFGM node.
7718 */
7719static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7720{
7721 int rc = VINF_SUCCESS;
7722 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7723
7724 /* Generate a default serial number. */
7725 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7726 RTUUID Uuid;
7727
7728 if (pAhciPort->pDrvBlock)
7729 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
7730 else
7731 RTUuidClear(&Uuid);
7732
7733 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7734 {
7735 /* Generate a predictable serial for drives which don't have a UUID. */
7736 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7737 pAhciPort->iLUN);
7738 }
7739 else
7740 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7741
7742 /* Get user config if present using defaults otherwise. */
7743 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7744 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7745 szSerial);
7746 if (RT_FAILURE(rc))
7747 {
7748 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7749 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7750 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7751 return PDMDEV_SET_ERROR(pDevIns, rc,
7752 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7753 }
7754
7755 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7756 "1.0");
7757 if (RT_FAILURE(rc))
7758 {
7759 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7760 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7761 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7762 return PDMDEV_SET_ERROR(pDevIns, rc,
7763 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7764 }
7765
7766 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7767 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7768 if (RT_FAILURE(rc))
7769 {
7770 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7771 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7772 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7773 return PDMDEV_SET_ERROR(pDevIns, rc,
7774 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7775 }
7776
7777 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7778 if (RT_FAILURE(rc))
7779 return PDMDEV_SET_ERROR(pDevIns, rc,
7780 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7781
7782 rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
7783 if (RT_FAILURE(rc))
7784 return PDMDEV_SET_ERROR(pDevIns, rc,
7785 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
7786 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
7787 return PDMDEV_SET_ERROR(pDevIns, rc,
7788 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
7789
7790 /* There are three other identification strings for CD drives used for INQUIRY */
7791 if (pAhciPort->fATAPI)
7792 {
7793 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7794 "VBOX");
7795 if (RT_FAILURE(rc))
7796 {
7797 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7798 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7799 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7800 return PDMDEV_SET_ERROR(pDevIns, rc,
7801 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7802 }
7803
7804 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7805 "CD-ROM");
7806 if (RT_FAILURE(rc))
7807 {
7808 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7809 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7810 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7811 return PDMDEV_SET_ERROR(pDevIns, rc,
7812 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7813 }
7814
7815 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7816 "1.0");
7817 if (RT_FAILURE(rc))
7818 {
7819 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7820 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7821 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7822 return PDMDEV_SET_ERROR(pDevIns, rc,
7823 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7824 }
7825 }
7826
7827 return rc;
7828}
7829
7830
7831/**
7832 * Detach notification.
7833 *
7834 * One harddisk at one port has been unplugged.
7835 * The VM is suspended at this point.
7836 *
7837 * @param pDevIns The device instance.
7838 * @param iLUN The logical unit which is being detached.
7839 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7840 */
7841static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7842{
7843 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7844 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7845 int rc = VINF_SUCCESS;
7846
7847 Log(("%s:\n", __FUNCTION__));
7848
7849 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7850 AssertMsgReturnVoid( pAhciPort->fHotpluggable
7851 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7852 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
7853
7854
7855 if (pAhciPort->pAsyncIOThread)
7856 {
7857 int rcThread;
7858 /* Destroy the thread. */
7859 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
7860 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
7861 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
7862
7863 pAhciPort->pAsyncIOThread = NULL;
7864 pAhciPort->fWrkThreadSleeping = true;
7865 }
7866
7867 if (pAhciPort->fATAPI)
7868 ahciMediumRemoved(pAhciPort);
7869
7870 /* Free all cached I/O tasks. */
7871 ahciR3PortCachedReqsFree(pAhciPort);
7872
7873 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7874 {
7875 /*
7876 * Inform the guest about the removed device.
7877 */
7878 pAhciPort->regSSTS = 0;
7879 pAhciPort->regSIG = 0;
7880 /*
7881 * Clear CR bit too to prevent submission of new commands when CI is written
7882 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
7883 */
7884 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
7885 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7886 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7887 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7888 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7889 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7890 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7891 }
7892
7893 /*
7894 * Zero some important members.
7895 */
7896 pAhciPort->pDrvBase = NULL;
7897 pAhciPort->pDrvBlock = NULL;
7898 pAhciPort->pDrvBlockAsync = NULL;
7899 pAhciPort->pDrvBlockBios = NULL;
7900}
7901
7902/**
7903 * Attach command.
7904 *
7905 * This is called when we change block driver for one port.
7906 * The VM is suspended at this point.
7907 *
7908 * @returns VBox status code.
7909 * @param pDevIns The device instance.
7910 * @param iLUN The logical unit which is being detached.
7911 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7912 */
7913static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7914{
7915 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7916 PAHCIPort pAhciPort = &pThis->ahciPort[iLUN];
7917 int rc;
7918
7919 Log(("%s:\n", __FUNCTION__));
7920
7921 /* the usual paranoia */
7922 AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
7923 AssertRelease(!pAhciPort->pDrvBase);
7924 AssertRelease(!pAhciPort->pDrvBlock);
7925 AssertRelease(!pAhciPort->pDrvBlockAsync);
7926 Assert(pAhciPort->iLUN == iLUN);
7927
7928 AssertMsgReturn( pAhciPort->fHotpluggable
7929 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7930 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7931 VERR_INVALID_PARAMETER);
7932
7933 /*
7934 * Try attach the block device and get the interfaces,
7935 * required as well as optional.
7936 */
7937 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
7938 if (RT_SUCCESS(rc))
7939 {
7940 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
7941
7942 /*
7943 * In case there is a medium inserted.
7944 */
7945 ahciMediumInserted(pAhciPort);
7946 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7947 }
7948 else
7949 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
7950
7951 if (RT_FAILURE(rc))
7952 {
7953 pAhciPort->pDrvBase = NULL;
7954 pAhciPort->pDrvBlock = NULL;
7955 }
7956 else
7957 {
7958 char szName[24];
7959 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
7960
7961 if ( pAhciPort->pDrvBlockAsync
7962 && !pAhciPort->fATAPI)
7963 pAhciPort->fAsyncInterface = true;
7964 else
7965 pAhciPort->fAsyncInterface = false;
7966
7967 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
7968 if (RT_FAILURE(rc))
7969 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7970 N_("AHCI: Failed to create SUP event semaphore"));
7971
7972 /* Create the async IO thread. */
7973 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
7974 RTTHREADTYPE_IO, szName);
7975 if (RT_FAILURE(rc))
7976 return rc;
7977
7978 /*
7979 * Init vendor product data.
7980 */
7981 if (RT_SUCCESS(rc))
7982 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
7983
7984 /* Inform the guest about the added device in case of hotplugging. */
7985 if ( RT_SUCCESS(rc)
7986 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7987 {
7988 AssertMsgReturn(pAhciPort->fHotpluggable,
7989 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7990 VERR_NOT_SUPPORTED);
7991
7992 /*
7993 * Initialize registers
7994 */
7995 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
7996 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7997 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7998
7999 if (pAhciPort->fATAPI)
8000 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
8001 else
8002 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
8003 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
8004 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
8005 (0x03 << 0); /* Device detected and communication established. */
8006
8007 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
8008 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
8009 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
8010 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
8011 }
8012
8013 }
8014
8015 return rc;
8016}
8017
8018/**
8019 * Common reset worker.
8020 *
8021 * @param pDevIns The device instance data.
8022 */
8023static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
8024{
8025 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
8026
8027 ahciHBAReset(pAhci);
8028
8029 /* Hardware reset for the ports. */
8030 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
8031 ahciPortHwReset(&pAhci->ahciPort[i]);
8032 return VINF_SUCCESS;
8033}
8034
8035/**
8036 * Callback employed by ahciR3Reset.
8037 *
8038 * @returns true if we've quiesced, false if we're still working.
8039 * @param pDevIns The device instance.
8040 */
8041static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
8042{
8043 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8044
8045 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8046 return false;
8047 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8048
8049 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8050 return true;
8051}
8052
8053/**
8054 * Reset notification.
8055 *
8056 * @param pDevIns The device instance data.
8057 */
8058static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
8059{
8060 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8061
8062 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
8063 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8064 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
8065 else
8066 {
8067 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8068 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8069 }
8070}
8071
8072/**
8073 * Poweroff notification.
8074 *
8075 * @param pDevIns Pointer to the device instance
8076 */
8077static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
8078{
8079 Log(("achiR3PowerOff\n"));
8080 ahciR3SuspendOrPowerOff(pDevIns);
8081}
8082
8083/**
8084 * Destroy a driver instance.
8085 *
8086 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
8087 * resources can be freed correctly.
8088 *
8089 * @param pDevIns The device instance data.
8090 */
8091static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
8092{
8093 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8094 int rc = VINF_SUCCESS;
8095 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
8096
8097 /*
8098 * At this point the async I/O thread is suspended and will not enter
8099 * this module again. So, no coordination is needed here and PDM
8100 * will take care of terminating and cleaning up the thread.
8101 */
8102 if (PDMCritSectIsInitialized(&pThis->lock))
8103 {
8104 TMR3TimerDestroy(pThis->CTX_SUFF(pHbaCccTimer));
8105 pThis->CTX_SUFF(pHbaCccTimer) = NULL;
8106
8107 Log(("%s: Destruct every port\n", __FUNCTION__));
8108 for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
8109 {
8110 PAHCIPort pAhciPort = &pThis->ahciPort[iActPort];
8111
8112 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
8113 {
8114 SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
8115 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8116 }
8117
8118#ifdef VBOX_STRICT
8119 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
8120 Assert(!pAhciPort->aCachedTasks[i]);
8121#endif
8122 }
8123
8124 PDMR3CritSectDelete(&pThis->lock);
8125 }
8126
8127 return rc;
8128}
8129
8130/**
8131 * @interface_method_impl{PDMDEVREG,pfnConstruct}
8132 */
8133static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
8134{
8135 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8136 PPDMIBASE pBase;
8137 int rc = VINF_SUCCESS;
8138 unsigned i = 0;
8139 bool fGCEnabled = false;
8140 bool fR0Enabled = false;
8141 uint32_t cbTotalBufferSize = 0;
8142 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
8143
8144 LogFlowFunc(("pThis=%#p\n", pThis));
8145
8146 /*
8147 * Validate and read configuration.
8148 */
8149 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
8150 "R0Enabled\0"
8151 "PrimaryMaster\0"
8152 "PrimarySlave\0"
8153 "SecondaryMaster\0"
8154 "SecondarySlave\0"
8155 "PortCount\0"
8156 "UseAsyncInterfaceIfAvailable\0"
8157 "Bootable\0"
8158 "CmdSlotsAvail\0"))
8159 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
8160 N_("AHCI configuration error: unknown option specified"));
8161
8162 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
8163 if (RT_FAILURE(rc))
8164 return PDMDEV_SET_ERROR(pDevIns, rc,
8165 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
8166 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
8167
8168 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
8169 if (RT_FAILURE(rc))
8170 return PDMDEV_SET_ERROR(pDevIns, rc,
8171 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
8172 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
8173
8174 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8175 if (RT_FAILURE(rc))
8176 return PDMDEV_SET_ERROR(pDevIns, rc,
8177 N_("AHCI configuration error: failed to read PortCount as integer"));
8178 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
8179 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
8180 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8181 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
8182 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8183 if (pThis->cPortsImpl < 1)
8184 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8185 N_("AHCI configuration error: PortCount=%u should be at least 1"),
8186 pThis->cPortsImpl);
8187
8188 rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
8189 if (RT_FAILURE(rc))
8190 return PDMDEV_SET_ERROR(pDevIns, rc,
8191 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
8192
8193 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
8194 if (RT_FAILURE(rc))
8195 return PDMDEV_SET_ERROR(pDevIns, rc,
8196 N_("AHCI configuration error: failed to read Bootable as boolean"));
8197
8198 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
8199 if (RT_FAILURE(rc))
8200 return PDMDEV_SET_ERROR(pDevIns, rc,
8201 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
8202 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
8203 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
8204 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8205 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
8206 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
8207 if (pThis->cCmdSlotsAvail < 1)
8208 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8209 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
8210 pThis->cCmdSlotsAvail);
8211
8212 /*
8213 * Initialize the instance data (everything touched by the destructor need
8214 * to be initialized here!).
8215 */
8216 pThis->fR0Enabled = fR0Enabled;
8217 pThis->fGCEnabled = fGCEnabled;
8218 pThis->pDevInsR3 = pDevIns;
8219 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8220 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8221 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
8222
8223 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
8224 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
8225 PCIDevSetCommand (&pThis->dev, 0x0000);
8226#ifdef VBOX_WITH_MSI_DEVICES
8227 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8228 PCIDevSetCapabilityList(&pThis->dev, 0x80);
8229#else
8230 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8231#endif
8232 PCIDevSetRevisionId (&pThis->dev, 0x02);
8233 PCIDevSetClassProg (&pThis->dev, 0x01);
8234 PCIDevSetClassSub (&pThis->dev, 0x06);
8235 PCIDevSetClassBase (&pThis->dev, 0x01);
8236 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
8237
8238 PCIDevSetInterruptLine(&pThis->dev, 0x00);
8239 PCIDevSetInterruptPin (&pThis->dev, 0x01);
8240
8241 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
8242 pThis->dev.config[0x71] = 0xa8; /* next */
8243 pThis->dev.config[0x72] = 0x03; /* version ? */
8244
8245 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
8246 pThis->dev.config[0x92] = 0x3f;
8247 pThis->dev.config[0x94] = 0x80;
8248 pThis->dev.config[0x95] = 0x01;
8249 pThis->dev.config[0x97] = 0x78;
8250
8251 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
8252 pThis->dev.config[0xa9] = 0x00; /* next */
8253 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
8254 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
8255
8256 pThis->cThreadsActive = 0;
8257
8258 /* Initialize port members. */
8259 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8260 {
8261 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8262 pAhciPort->pDevInsR3 = pDevIns;
8263 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8264 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8265 pAhciPort->iLUN = i;
8266 pAhciPort->pAhciR3 = pThis;
8267 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
8268 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
8269 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
8270 pAhciPort->pDrvBase = NULL;
8271 pAhciPort->pAsyncIOThread = NULL;
8272 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8273 pAhciPort->fHotpluggable = true;
8274 }
8275
8276 /*
8277 * Init locks, using explicit locking where necessary.
8278 */
8279 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
8280 if (RT_FAILURE(rc))
8281 return rc;
8282
8283 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
8284 if (RT_FAILURE(rc))
8285 {
8286 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
8287 return rc;
8288 }
8289
8290 /*
8291 * Register the PCI device, it's I/O regions.
8292 */
8293 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
8294 if (RT_FAILURE(rc))
8295 return rc;
8296
8297#ifdef VBOX_WITH_MSI_DEVICES
8298 PDMMSIREG MsiReg;
8299 RT_ZERO(MsiReg);
8300 MsiReg.cMsiVectors = 1;
8301 MsiReg.iMsiCapOffset = 0x80;
8302 MsiReg.iMsiNextOffset = 0x70;
8303 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
8304 if (RT_FAILURE(rc))
8305 {
8306 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8307 /* That's OK, we can work without MSI */
8308 }
8309#endif
8310
8311 /*
8312 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
8313 * IDE registers are not available.
8314 * We set up "fake" entries in the PCI configuration register.
8315 * That means they are available but read and writes from/to them have no effect.
8316 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
8317 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
8318 * to switch to it which also changes device Id and other things in the PCI configuration space).
8319 */
8320 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8321 if (RT_FAILURE(rc))
8322 return PDMDEV_SET_ERROR(pDevIns, rc,
8323 N_("AHCI cannot register PCI I/O region"));
8324
8325 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8326 if (RT_FAILURE(rc))
8327 return PDMDEV_SET_ERROR(pDevIns, rc,
8328 N_("AHCI cannot register PCI I/O region"));
8329
8330 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8331 if (RT_FAILURE(rc))
8332 return PDMDEV_SET_ERROR(pDevIns, rc,
8333 N_("AHCI cannot register PCI I/O region"));
8334
8335 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8336 if (RT_FAILURE(rc))
8337 return PDMDEV_SET_ERROR(pDevIns, rc,
8338 N_("AHCI cannot register PCI I/O region"));
8339
8340 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
8341 if (RT_FAILURE(rc))
8342 return PDMDEV_SET_ERROR(pDevIns, rc,
8343 N_("AHCI cannot register PCI I/O region for BMDMA"));
8344
8345 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
8346 if (RT_FAILURE(rc))
8347 return PDMDEV_SET_ERROR(pDevIns, rc,
8348 N_("AHCI cannot register PCI memory region for registers"));
8349
8350 /* Create the timer for command completion coalescing feature. */
8351 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
8352 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
8353 if (RT_FAILURE(rc))
8354 {
8355 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
8356 return rc;
8357 }
8358 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
8359 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
8360
8361 /* Status LUN. */
8362 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
8363 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
8364
8365 /*
8366 * Create the notification queue.
8367 *
8368 * We need 2 items for every port because of SMP races.
8369 */
8370 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8371 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
8372 if (RT_FAILURE(rc))
8373 return rc;
8374 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
8375 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
8376
8377 /* Initialize static members on every port. */
8378 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8379 {
8380 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8381
8382 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8383 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
8384 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8385 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
8386 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8387 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
8388 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8389 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8390#ifdef VBOX_WITH_STATISTICS
8391 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8392 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8393 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8394 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8395#endif
8396
8397 ahciPortHwReset(pAhciPort);
8398 }
8399
8400 /* Attach drivers to every available port. */
8401 for (i = 0; i < pThis->cPortsImpl; i++)
8402 {
8403 char szName[24];
8404 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8405
8406 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8407 /*
8408 * Init interfaces.
8409 */
8410 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8411 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciR3TransferCompleteNotify;
8412 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8413 pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
8414 pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
8415 pAhciPort->fWrkThreadSleeping = true;
8416
8417 /* Query per port configuration options if available. */
8418 PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
8419 if (pCfgPort)
8420 {
8421 rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
8422 if (RT_FAILURE(rc))
8423 return PDMDEV_SET_ERROR(pDevIns, rc,
8424 N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
8425 }
8426
8427 /*
8428 * Attach the block driver
8429 */
8430 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8431 if (RT_SUCCESS(rc))
8432 {
8433 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8434 if (RT_FAILURE(rc))
8435 {
8436 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8437 return rc;
8438 }
8439
8440 /* Mark that a device is present on that port */
8441 if (i < 6)
8442 pThis->dev.config[0x93] |= (1 << i);
8443
8444 /*
8445 * Init vendor product data.
8446 */
8447 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8448 if (RT_FAILURE(rc))
8449 return rc;
8450
8451 /*
8452 * If the new async interface is available we use a PDMQueue to transmit
8453 * the requests into R3.
8454 * Otherwise we use a event semaphore and a async I/O thread which processes them.
8455 */
8456 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
8457 {
8458 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
8459 pAhciPort->fAsyncInterface = true;
8460 }
8461 else
8462 {
8463 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
8464 pAhciPort->fAsyncInterface = false;
8465 }
8466
8467 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8468 if (RT_FAILURE(rc))
8469 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8470 N_("AHCI: Failed to create SUP event semaphore"));
8471
8472 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
8473 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
8474 if (RT_FAILURE(rc))
8475 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8476 N_("AHCI: Failed to create worker thread %s"), szName);
8477 }
8478 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8479 {
8480 pAhciPort->pDrvBase = NULL;
8481 rc = VINF_SUCCESS;
8482 LogRel(("%s: no driver attached\n", szName));
8483 }
8484 else
8485 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8486 N_("AHCI: Failed to attach drive to %s"), szName);
8487 }
8488
8489 /*
8490 * Attach status driver (optional).
8491 */
8492 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8493 if (RT_SUCCESS(rc))
8494 {
8495 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8496 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8497 }
8498 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8499 {
8500 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8501 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8502 }
8503 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
8504 NULL, ahciR3LiveExec, NULL,
8505 ahciR3SavePrep, ahciR3SaveExec, NULL,
8506 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8507 if (RT_FAILURE(rc))
8508 return rc;
8509
8510 /*
8511 * Register the info item.
8512 */
8513 char szTmp[128];
8514 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8515 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8516
8517 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8518}
8519
8520/**
8521 * The device registration structure.
8522 */
8523const PDMDEVREG g_DeviceAHCI =
8524{
8525 /* u32Version */
8526 PDM_DEVREG_VERSION,
8527 /* szName */
8528 "ahci",
8529 /* szRCMod */
8530 "VBoxDDGC.gc",
8531 /* szR0Mod */
8532 "VBoxDDR0.r0",
8533 /* pszDescription */
8534 "Intel AHCI controller.\n",
8535 /* fFlags */
8536 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8537 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
8538 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
8539 /* fClass */
8540 PDM_DEVREG_CLASS_STORAGE,
8541 /* cMaxInstances */
8542 ~0U,
8543 /* cbInstance */
8544 sizeof(AHCI),
8545 /* pfnConstruct */
8546 ahciR3Construct,
8547 /* pfnDestruct */
8548 ahciR3Destruct,
8549 /* pfnRelocate */
8550 ahciR3Relocate,
8551 /* pfnMemSetup */
8552 NULL,
8553 /* pfnPowerOn */
8554 NULL,
8555 /* pfnReset */
8556 ahciR3Reset,
8557 /* pfnSuspend */
8558 ahciR3Suspend,
8559 /* pfnResume */
8560 ahciR3Resume,
8561 /* pfnAttach */
8562 ahciR3Attach,
8563 /* pfnDetach */
8564 ahciR3Detach,
8565 /* pfnQueryInterface. */
8566 NULL,
8567 /* pfnInitComplete */
8568 NULL,
8569 /* pfnPowerOff */
8570 ahciR3PowerOff,
8571 /* pfnSoftReset */
8572 NULL,
8573 /* u32VersionEnd */
8574 PDM_DEVREG_VERSION
8575};
8576
8577#endif /* IN_RING3 */
8578#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