VirtualBox

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

Last change on this file since 42999 was 42999, checked in by vboxsync, 12 years ago

AHCI/Passthrough: Apply fixes for audio CD passthrough

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