VirtualBox

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

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

AHCI: Make sure the async notification handler is called from the async I/O worker thread too when a request completes, minor cleanup (ahciTransferComplete doesn't return a status code but a boolean)

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

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