VirtualBox

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

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

AHCI: Fix race condition during port reset causing a release assertion when canceling outstanding requests

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