VirtualBox

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

Last change on this file since 53097 was 53075, checked in by vboxsync, 10 years ago

AHCI: temporarily disabled r96292 to check if it cures the performance regression

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