VirtualBox

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

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

AHCI: Fix ATAPI with EFI

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 308.4 KB
Line 
1/* $Id: DevAHCI.cpp 42891 2012-08-20 19:08:35Z 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 {
3988 /* Set the media type if we can detect it. */
3989 uint8_t *pbBuf = (uint8_t *)pvBuf;
3990
3991 /** @todo: Implemented only for formatted TOC now. */
3992 if ( (pAhciReq->aATAPICmd[1] & 0xf) == 0
3993 && cbTransfer >= 6)
3994 {
3995 uint32_t NewMediaType;
3996 uint32_t OldMediaType;
3997
3998 if (pbBuf[5] & 0x4)
3999 NewMediaType = ATA_MEDIA_TYPE_DATA;
4000 else
4001 NewMediaType = ATA_MEDIA_TYPE_CDDA;
4002
4003 OldMediaType = ataMediumTypeSet(pAhciPort, NewMediaType);
4004
4005 if (OldMediaType != NewMediaType)
4006 LogRel(("AHCI: LUN#%d: CD-ROM passthrough, detected %s CD\n",
4007 pAhciPort->iLUN,
4008 NewMediaType == ATA_MEDIA_TYPE_DATA
4009 ? "data"
4010 : "audio"));
4011 }
4012 else /* Play safe and set to unknown. */
4013 ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
4014 }
4015
4016 if (cbTransfer)
4017 {
4018 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
4019
4020 /* Reply with the same amount of data as the real drive. */
4021 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf,
4022 cbTransfer);
4023 }
4024 else
4025 *pcbData = 0;
4026 }
4027 else
4028 *pcbData = cbTransfer;
4029 atapiCmdOK(pAhciPort, pAhciReq);
4030 }
4031 else
4032 {
4033 if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
4034 {
4035 uint8_t u8Cmd = pAhciReq->aATAPICmd[0];
4036 do
4037 {
4038 /* don't log superfluous errors */
4039 if ( rc == VERR_DEV_IO_ERROR
4040 && ( u8Cmd == SCSI_TEST_UNIT_READY
4041 || u8Cmd == SCSI_READ_CAPACITY
4042 || u8Cmd == SCSI_READ_DVD_STRUCTURE
4043 || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
4044 break;
4045 pAhciPort->cErrors++;
4046 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
4047 pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
4048 } while (0);
4049 }
4050 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
4051 }
4052
4053 if (pvBuf)
4054 RTMemFree(pvBuf);
4055
4056 return VINF_SUCCESS;
4057}
4058
4059static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
4060{
4061 size_t cbTransfered = 0;
4062 int rc, rcSourceSink;
4063
4064 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax,
4065 &cbTransfered);
4066
4067 pAhciReq->cmdHdr.u32PRDBC = cbTransfered;
4068 pAhciReq->cbTransfer = cbTransfered;
4069
4070 LogFlow(("cbTransfered=%d\n", cbTransfered));
4071
4072 /* Write updated command header into memory of the guest. */
4073 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr,
4074 &pAhciReq->cmdHdr, sizeof(CmdHdr));
4075
4076 return rcSourceSink;
4077}
4078
4079static int atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc)
4080{
4081 uint8_t *pbBuf = NULL;
4082 uint32_t cSectors = pAhciReq->cbTransfer / 2048;
4083 uint32_t iATAPILBA = pAhciReq->uOffset / 2048;
4084 uint8_t *pbBufDst;
4085 uint8_t *pbBufSrc = (uint8_t *)pAhciReq->u.Io.DataSeg.pvSeg;
4086
4087 pbBuf = (uint8_t *)RTMemAlloc(pAhciReq->cbTransfer);
4088 if (RT_UNLIKELY(!pbBuf))
4089 return VERR_NO_MEMORY;
4090
4091 pbBufDst = pbBuf;
4092
4093 for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4094 {
4095 /* sync bytes */
4096 *pbBufDst++ = 0x00;
4097 memset(pbBufDst, 0xff, 11);
4098 pbBufDst += 11;
4099 /* MSF */
4100 ataLBA2MSF(pbBufDst, i);
4101 pbBufDst += 3;
4102 *pbBufDst++ = 0x01; /* mode 1 data */
4103 /* data */
4104 memcpy(pbBufDst, pbBufSrc, 2048);
4105 pbBufDst += 2048;
4106 pbBufSrc += 2048;
4107 /* ECC */
4108 memset(pbBufDst, 0, 288);
4109 pbBufDst += 288;
4110 }
4111
4112 *ppvProc = pbBuf;
4113 *pcbProc = pAhciReq->cbTransfer;
4114
4115 return VINF_SUCCESS;
4116}
4117
4118static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
4119{
4120 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
4121
4122 switch (cbSector)
4123 {
4124 case 2048:
4125 pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
4126 pAhciReq->cbTransfer = cSectors * cbSector;
4127 break;
4128 case 2352:
4129 {
4130 pAhciReq->u.Io.pfnPostProcess = atapiReadSectors2352PostProcess;
4131 pAhciReq->uOffset = (uint64_t)iATAPILBA * 2048;
4132 pAhciReq->cbTransfer = cSectors * 2048;
4133 break;
4134 }
4135 default:
4136 AssertMsgFailed(("Unsupported sectors size\n"));
4137 break;
4138 }
4139
4140 return VINF_SUCCESS;
4141}
4142
4143static AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4144{
4145 AHCITXDIR rc = AHCITXDIR_NONE;
4146 const uint8_t *pbPacket;
4147 uint32_t cbMax;
4148
4149 pbPacket = pAhciReq->aATAPICmd;
4150
4151 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
4152
4153 switch (pbPacket[0])
4154 {
4155 case SCSI_TEST_UNIT_READY:
4156 if (pAhciPort->cNotifiedMediaChange > 0)
4157 {
4158 if (pAhciPort->cNotifiedMediaChange-- > 2)
4159 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4160 else
4161 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4162 }
4163 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4164 atapiCmdOK(pAhciPort, pAhciReq);
4165 else
4166 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4167 break;
4168 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4169 cbMax = ataBE2H_U16(pbPacket + 7);
4170 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4171 break;
4172 case SCSI_MODE_SENSE_10:
4173 {
4174 uint8_t uPageControl, uPageCode;
4175 cbMax = ataBE2H_U16(pbPacket + 7);
4176 uPageControl = pbPacket[2] >> 6;
4177 uPageCode = pbPacket[2] & 0x3f;
4178 switch (uPageControl)
4179 {
4180 case SCSI_PAGECONTROL_CURRENT:
4181 switch (uPageCode)
4182 {
4183 case SCSI_MODEPAGE_ERROR_RECOVERY:
4184 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
4185 break;
4186 case SCSI_MODEPAGE_CD_STATUS:
4187 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
4188 break;
4189 default:
4190 goto error_cmd;
4191 }
4192 break;
4193 case SCSI_PAGECONTROL_CHANGEABLE:
4194 goto error_cmd;
4195 case SCSI_PAGECONTROL_DEFAULT:
4196 goto error_cmd;
4197 default:
4198 case SCSI_PAGECONTROL_SAVED:
4199 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
4200 break;
4201 }
4202 }
4203 break;
4204 case SCSI_REQUEST_SENSE:
4205 cbMax = pbPacket[4];
4206 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
4207 break;
4208 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4209 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4210 {
4211 if (pbPacket[4] & 1)
4212 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
4213 else
4214 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
4215 atapiCmdOK(pAhciPort, pAhciReq);
4216 }
4217 else
4218 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4219 break;
4220 case SCSI_READ_10:
4221 case SCSI_READ_12:
4222 {
4223 uint32_t cSectors, iATAPILBA;
4224
4225 if (pAhciPort->cNotifiedMediaChange > 0)
4226 {
4227 pAhciPort->cNotifiedMediaChange-- ;
4228 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4229 break;
4230 }
4231 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4232 {
4233 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4234 break;
4235 }
4236 if (pbPacket[0] == SCSI_READ_10)
4237 cSectors = ataBE2H_U16(pbPacket + 7);
4238 else
4239 cSectors = ataBE2H_U32(pbPacket + 6);
4240 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4241 if (cSectors == 0)
4242 {
4243 atapiCmdOK(pAhciPort, pAhciReq);
4244 break;
4245 }
4246 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4247 {
4248 /* Rate limited logging, one log line per second. For
4249 * guests that insist on reading from places outside the
4250 * valid area this often generates too many release log
4251 * entries otherwise. */
4252 static uint64_t uLastLogTS = 0;
4253 if (RTTimeMilliTS() >= uLastLogTS + 1000)
4254 {
4255 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4256 uLastLogTS = RTTimeMilliTS();
4257 }
4258 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4259 break;
4260 }
4261 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4262 rc = AHCITXDIR_READ;
4263 }
4264 break;
4265 case SCSI_READ_CD:
4266 {
4267 uint32_t cSectors, iATAPILBA;
4268
4269 if (pAhciPort->cNotifiedMediaChange > 0)
4270 {
4271 pAhciPort->cNotifiedMediaChange-- ;
4272 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4273 break;
4274 }
4275 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4276 {
4277 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4278 break;
4279 }
4280 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
4281 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4282 if (cSectors == 0)
4283 {
4284 atapiCmdOK(pAhciPort, pAhciReq);
4285 break;
4286 }
4287 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4288 {
4289 /* Rate limited logging, one log line per second. For
4290 * guests that insist on reading from places outside the
4291 * valid area this often generates too many release log
4292 * entries otherwise. */
4293 static uint64_t uLastLogTS = 0;
4294 if (RTTimeMilliTS() >= uLastLogTS + 1000)
4295 {
4296 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4297 uLastLogTS = RTTimeMilliTS();
4298 }
4299 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4300 break;
4301 }
4302 switch (pbPacket[9] & 0xf8)
4303 {
4304 case 0x00:
4305 /* nothing */
4306 atapiCmdOK(pAhciPort, pAhciReq);
4307 break;
4308 case 0x10:
4309 /* normal read */
4310 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4311 rc = AHCITXDIR_READ;
4312 break;
4313 case 0xf8:
4314 /* read all data */
4315 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
4316 rc = AHCITXDIR_READ;
4317 break;
4318 default:
4319 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
4320 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4321 break;
4322 }
4323 }
4324 break;
4325 case SCSI_SEEK_10:
4326 {
4327 uint32_t iATAPILBA;
4328 if (pAhciPort->cNotifiedMediaChange > 0)
4329 {
4330 pAhciPort->cNotifiedMediaChange-- ;
4331 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4332 break;
4333 }
4334 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4335 {
4336 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4337 break;
4338 }
4339 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4340 if (iATAPILBA > pAhciPort->cTotalSectors)
4341 {
4342 /* Rate limited logging, one log line per second. For
4343 * guests that insist on seeking to places outside the
4344 * valid area this often generates too many release log
4345 * entries otherwise. */
4346 static uint64_t uLastLogTS = 0;
4347 if (RTTimeMilliTS() >= uLastLogTS + 1000)
4348 {
4349 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
4350 uLastLogTS = RTTimeMilliTS();
4351 }
4352 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4353 break;
4354 }
4355 atapiCmdOK(pAhciPort, pAhciReq);
4356 pAhciReq->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
4357 }
4358 break;
4359 case SCSI_START_STOP_UNIT:
4360 {
4361 int rc2 = VINF_SUCCESS;
4362 switch (pbPacket[4] & 3)
4363 {
4364 case 0: /* 00 - Stop motor */
4365 case 1: /* 01 - Start motor */
4366 break;
4367 case 2: /* 10 - Eject media */
4368 {
4369 /* This must be done from EMT. */
4370 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4371 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
4372
4373 rc2 = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4374 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4375 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4376 Assert(RT_SUCCESS(rc2) || (rc2 == VERR_PDM_MEDIA_LOCKED) || (rc2 = VERR_PDM_MEDIA_NOT_MOUNTED));
4377 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4378 {
4379 rc2 = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4380 (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
4381 pAhci->pMediaNotify, pAhciPort->iLUN);
4382 AssertRC(rc);
4383 }
4384 break;
4385 }
4386 case 3: /* 11 - Load media */
4387 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
4388 break;
4389 }
4390 if (RT_SUCCESS(rc2))
4391 atapiCmdOK(pAhciPort, pAhciReq);
4392 else
4393 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4394 }
4395 break;
4396 case SCSI_MECHANISM_STATUS:
4397 {
4398 cbMax = ataBE2H_U16(pbPacket + 8);
4399 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4400 }
4401 break;
4402 case SCSI_READ_TOC_PMA_ATIP:
4403 {
4404 uint8_t format;
4405
4406 if (pAhciPort->cNotifiedMediaChange > 0)
4407 {
4408 pAhciPort->cNotifiedMediaChange-- ;
4409 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4410 break;
4411 }
4412 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4413 {
4414 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4415 break;
4416 }
4417 cbMax = ataBE2H_U16(pbPacket + 7);
4418 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
4419 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
4420 * the other field is clear... */
4421 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
4422 switch (format)
4423 {
4424 case 0:
4425 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
4426 break;
4427 case 1:
4428 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
4429 break;
4430 case 2:
4431 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
4432 break;
4433 default:
4434 error_cmd:
4435 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4436 break;
4437 }
4438 }
4439 break;
4440 case SCSI_READ_CAPACITY:
4441 if (pAhciPort->cNotifiedMediaChange > 0)
4442 {
4443 pAhciPort->cNotifiedMediaChange-- ;
4444 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4445 break;
4446 }
4447 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4448 {
4449 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4450 break;
4451 }
4452 atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
4453 break;
4454 case SCSI_READ_DISC_INFORMATION:
4455 if (pAhciPort->cNotifiedMediaChange > 0)
4456 {
4457 pAhciPort->cNotifiedMediaChange-- ;
4458 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4459 break;
4460 }
4461 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4462 {
4463 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4464 break;
4465 }
4466 cbMax = ataBE2H_U16(pbPacket + 7);
4467 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
4468 break;
4469 case SCSI_READ_TRACK_INFORMATION:
4470 if (pAhciPort->cNotifiedMediaChange > 0)
4471 {
4472 pAhciPort->cNotifiedMediaChange-- ;
4473 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4474 break;
4475 }
4476 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4477 {
4478 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4479 break;
4480 }
4481 cbMax = ataBE2H_U16(pbPacket + 7);
4482 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
4483 break;
4484 case SCSI_GET_CONFIGURATION:
4485 /* No media change stuff here, it can confuse Linux guests. */
4486 cbMax = ataBE2H_U16(pbPacket + 7);
4487 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
4488 break;
4489 case SCSI_INQUIRY:
4490 cbMax = pbPacket[4];
4491 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
4492 break;
4493 default:
4494 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4495 break;
4496 }
4497
4498 return rc;
4499}
4500
4501/*
4502 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
4503 */
4504static AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4505{
4506 const uint8_t *pbPacket;
4507 uint32_t cSectors, iATAPILBA;
4508 uint32_t cbTransfer = 0;
4509 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4510
4511 pbPacket = pAhciReq->aATAPICmd;
4512 switch (pbPacket[0])
4513 {
4514 case SCSI_BLANK:
4515 goto sendcmd;
4516 case SCSI_CLOSE_TRACK_SESSION:
4517 goto sendcmd;
4518 case SCSI_ERASE_10:
4519 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4520 cbTransfer = ataBE2H_U16(pbPacket + 7);
4521 Log2(("ATAPI PT: lba %d\n", iATAPILBA));
4522 enmTxDir = AHCITXDIR_WRITE;
4523 goto sendcmd;
4524 case SCSI_FORMAT_UNIT:
4525 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4526 enmTxDir = AHCITXDIR_WRITE;
4527 goto sendcmd;
4528 case SCSI_GET_CONFIGURATION:
4529 cbTransfer = ataBE2H_U16(pbPacket + 7);
4530 enmTxDir = AHCITXDIR_READ;
4531 goto sendcmd;
4532 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4533 cbTransfer = ataBE2H_U16(pbPacket + 7);
4534 if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
4535 {
4536 pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
4537 atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4538 break;
4539 }
4540 enmTxDir = AHCITXDIR_READ;
4541 goto sendcmd;
4542 case SCSI_GET_PERFORMANCE:
4543 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4544 enmTxDir = AHCITXDIR_READ;
4545 goto sendcmd;
4546 case SCSI_INQUIRY:
4547 cbTransfer = ataBE2H_U16(pbPacket + 3);
4548 enmTxDir = AHCITXDIR_READ;
4549 goto sendcmd;
4550 case SCSI_LOAD_UNLOAD_MEDIUM:
4551 goto sendcmd;
4552 case SCSI_MECHANISM_STATUS:
4553 cbTransfer = ataBE2H_U16(pbPacket + 8);
4554 enmTxDir = AHCITXDIR_READ;
4555 goto sendcmd;
4556 case SCSI_MODE_SELECT_10:
4557 cbTransfer = ataBE2H_U16(pbPacket + 7);
4558 enmTxDir = AHCITXDIR_WRITE;
4559 goto sendcmd;
4560 case SCSI_MODE_SENSE_10:
4561 cbTransfer = ataBE2H_U16(pbPacket + 7);
4562 enmTxDir = AHCITXDIR_READ;
4563 goto sendcmd;
4564 case SCSI_PAUSE_RESUME:
4565 goto sendcmd;
4566 case SCSI_PLAY_AUDIO_10:
4567 goto sendcmd;
4568 case SCSI_PLAY_AUDIO_12:
4569 goto sendcmd;
4570 case SCSI_PLAY_AUDIO_MSF:
4571 goto sendcmd;
4572 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4573 /** @todo do not forget to unlock when a VM is shut down */
4574 goto sendcmd;
4575 case SCSI_READ_10:
4576 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4577 cSectors = ataBE2H_U16(pbPacket + 7);
4578 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4579 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4580 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4581 enmTxDir = AHCITXDIR_READ;
4582 goto sendcmd;
4583 case SCSI_READ_12:
4584 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4585 cSectors = ataBE2H_U32(pbPacket + 6);
4586 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4587 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4588 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4589 enmTxDir = AHCITXDIR_READ;
4590 goto sendcmd;
4591 case SCSI_READ_BUFFER:
4592 cbTransfer = ataBE2H_U24(pbPacket + 6);
4593 enmTxDir = AHCITXDIR_READ;
4594 goto sendcmd;
4595 case SCSI_READ_BUFFER_CAPACITY:
4596 cbTransfer = ataBE2H_U16(pbPacket + 7);
4597 enmTxDir = AHCITXDIR_READ;
4598 goto sendcmd;
4599 case SCSI_READ_CAPACITY:
4600 cbTransfer = 8;
4601 enmTxDir = AHCITXDIR_READ;
4602 goto sendcmd;
4603 case SCSI_READ_CD:
4604 {
4605 /* Get sector size based on the expected sector type field. */
4606 switch ((pbPacket[1] >> 2) & 0x7)
4607 {
4608 case 0x0: /* All types. */
4609 if (ASMAtomicReadU32(&pAhciPort->MediaTrackType) == ATA_MEDIA_TYPE_CDDA)
4610 pAhciReq->cbATAPISector = 2352;
4611 else
4612 pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
4613 break;
4614 case 0x1: /* CD-DA */
4615 pAhciReq->cbATAPISector = 2352;
4616 break;
4617 case 0x2: /* Mode 1 */
4618 pAhciReq->cbATAPISector = 2048;
4619 break;
4620 case 0x3: /* Mode 2 formless */
4621 pAhciReq->cbATAPISector = 2336;
4622 break;
4623 case 0x4: /* Mode 2 form 1 */
4624 pAhciReq->cbATAPISector = 2048;
4625 break;
4626 case 0x5: /* Mode 2 form 2 */
4627 pAhciReq->cbATAPISector = 2324;
4628 break;
4629 default: /* Reserved */
4630 AssertMsgFailed(("Unknown sector type\n"));
4631 pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
4632 }
4633
4634 cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
4635 enmTxDir = AHCITXDIR_READ;
4636 goto sendcmd;
4637 }
4638 case SCSI_READ_CD_MSF:
4639 cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
4640 if (cSectors > 32)
4641 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
4642 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4643 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4644 enmTxDir = AHCITXDIR_READ;
4645 goto sendcmd;
4646 case SCSI_READ_DISC_INFORMATION:
4647 cbTransfer = ataBE2H_U16(pbPacket + 7);
4648 enmTxDir = AHCITXDIR_READ;
4649 goto sendcmd;
4650 case SCSI_READ_DVD_STRUCTURE:
4651 cbTransfer = ataBE2H_U16(pbPacket + 8);
4652 enmTxDir = AHCITXDIR_READ;
4653 goto sendcmd;
4654 case SCSI_READ_FORMAT_CAPACITIES:
4655 cbTransfer = ataBE2H_U16(pbPacket + 7);
4656 enmTxDir = AHCITXDIR_READ;
4657 goto sendcmd;
4658 case SCSI_READ_SUBCHANNEL:
4659 cbTransfer = ataBE2H_U16(pbPacket + 7);
4660 enmTxDir = AHCITXDIR_READ;
4661 goto sendcmd;
4662 case SCSI_READ_TOC_PMA_ATIP:
4663 cbTransfer = ataBE2H_U16(pbPacket + 7);
4664 enmTxDir = AHCITXDIR_READ;
4665 goto sendcmd;
4666 case SCSI_READ_TRACK_INFORMATION:
4667 cbTransfer = ataBE2H_U16(pbPacket + 7);
4668 enmTxDir = AHCITXDIR_READ;
4669 goto sendcmd;
4670 case SCSI_REPAIR_TRACK:
4671 goto sendcmd;
4672 case SCSI_REPORT_KEY:
4673 cbTransfer = ataBE2H_U16(pbPacket + 8);
4674 enmTxDir = AHCITXDIR_READ;
4675 goto sendcmd;
4676 case SCSI_REQUEST_SENSE:
4677 cbTransfer = pbPacket[4];
4678 if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
4679 {
4680 pAhciReq->cbTransfer = cbTransfer;
4681 pAhciReq->enmTxDir = AHCITXDIR_READ;
4682 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
4683 break;
4684 }
4685 enmTxDir = AHCITXDIR_READ;
4686 goto sendcmd;
4687 case SCSI_RESERVE_TRACK:
4688 goto sendcmd;
4689 case SCSI_SCAN:
4690 goto sendcmd;
4691 case SCSI_SEEK_10:
4692 goto sendcmd;
4693 case SCSI_SEND_CUE_SHEET:
4694 cbTransfer = ataBE2H_U24(pbPacket + 6);
4695 enmTxDir = AHCITXDIR_WRITE;
4696 goto sendcmd;
4697 case SCSI_SEND_DVD_STRUCTURE:
4698 cbTransfer = ataBE2H_U16(pbPacket + 8);
4699 enmTxDir = AHCITXDIR_WRITE;
4700 goto sendcmd;
4701 case SCSI_SEND_EVENT:
4702 cbTransfer = ataBE2H_U16(pbPacket + 8);
4703 enmTxDir = AHCITXDIR_WRITE;
4704 goto sendcmd;
4705 case SCSI_SEND_KEY:
4706 cbTransfer = ataBE2H_U16(pbPacket + 8);
4707 enmTxDir = AHCITXDIR_WRITE;
4708 goto sendcmd;
4709 case SCSI_SEND_OPC_INFORMATION:
4710 cbTransfer = ataBE2H_U16(pbPacket + 7);
4711 enmTxDir = AHCITXDIR_WRITE;
4712 goto sendcmd;
4713 case SCSI_SET_CD_SPEED:
4714 goto sendcmd;
4715 case SCSI_SET_READ_AHEAD:
4716 goto sendcmd;
4717 case SCSI_SET_STREAMING:
4718 cbTransfer = ataBE2H_U16(pbPacket + 9);
4719 enmTxDir = AHCITXDIR_WRITE;
4720 goto sendcmd;
4721 case SCSI_START_STOP_UNIT:
4722 goto sendcmd;
4723 case SCSI_STOP_PLAY_SCAN:
4724 goto sendcmd;
4725 case SCSI_SYNCHRONIZE_CACHE:
4726 goto sendcmd;
4727 case SCSI_TEST_UNIT_READY:
4728 goto sendcmd;
4729 case SCSI_VERIFY_10:
4730 goto sendcmd;
4731 case SCSI_WRITE_10:
4732 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4733 cSectors = ataBE2H_U16(pbPacket + 7);
4734 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4735 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4736 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4737 enmTxDir = AHCITXDIR_WRITE;
4738 goto sendcmd;
4739 case SCSI_WRITE_12:
4740 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4741 cSectors = ataBE2H_U32(pbPacket + 6);
4742 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4743 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4744 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4745 enmTxDir = AHCITXDIR_WRITE;
4746 goto sendcmd;
4747 case SCSI_WRITE_AND_VERIFY_10:
4748 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4749 cSectors = ataBE2H_U16(pbPacket + 7);
4750 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4751 /* The sector size is determined by the async I/O thread. */
4752 pAhciReq->cbATAPISector = 0;
4753 /* Preliminary, will be corrected once the sector size is known. */
4754 cbTransfer = cSectors;
4755 enmTxDir = AHCITXDIR_WRITE;
4756 goto sendcmd;
4757 case SCSI_WRITE_BUFFER:
4758 switch (pbPacket[1] & 0x1f)
4759 {
4760 case 0x04: /* download microcode */
4761 case 0x05: /* download microcode and save */
4762 case 0x06: /* download microcode with offsets */
4763 case 0x07: /* download microcode with offsets and save */
4764 case 0x0e: /* download microcode with offsets and defer activation */
4765 case 0x0f: /* activate deferred microcode */
4766 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
4767 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4768 break;
4769 default:
4770 cbTransfer = ataBE2H_U16(pbPacket + 6);
4771 enmTxDir = AHCITXDIR_WRITE;
4772 goto sendcmd;
4773 }
4774 break;
4775 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
4776 cbTransfer = ataBE2H_U32(pbPacket + 6);
4777 enmTxDir = AHCITXDIR_READ;
4778 goto sendcmd;
4779 case SCSI_REZERO_UNIT:
4780 /* Obsolete command used by cdrecord. What else would one expect?
4781 * This command is not sent to the drive, it is handled internally,
4782 * as the Linux kernel doesn't like it (message "scsi: unknown
4783 * opcode 0x01" in syslog) and replies with a sense code of 0,
4784 * which sends cdrecord to an endless loop. */
4785 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4786 break;
4787 default:
4788 LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
4789 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4790 break;
4791 sendcmd:
4792 /* Send a command to the drive, passing data in/out as required. */
4793 Log2(("ATAPI PT: max size %d\n", cbTransfer));
4794 if (cbTransfer == 0)
4795 enmTxDir = AHCITXDIR_NONE;
4796 pAhciReq->enmTxDir = enmTxDir;
4797 pAhciReq->cbTransfer = cbTransfer;
4798 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
4799 }
4800
4801 return AHCITXDIR_NONE;
4802}
4803
4804static AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4805{
4806 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4807 const uint8_t *pbPacket;
4808
4809 pbPacket = pAhciReq->aATAPICmd;
4810#ifdef DEBUG
4811 Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
4812#else /* !DEBUG */
4813 Log(("%s: LUN#%d CMD=%#04x\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0]));
4814#endif /* !DEBUG */
4815 Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
4816
4817 if (pAhciPort->fATAPIPassthrough)
4818 enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
4819 else
4820 enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
4821
4822 return enmTxDir;
4823}
4824
4825/**
4826 * Reset all values after a reset of the attached storage device.
4827 *
4828 * @returns nothing
4829 * @param pAhciPort The port the device is attached to.
4830 * @param pAhciReq The state to get the tag number from.
4831 */
4832static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4833{
4834 int rc;
4835
4836 /* Send a status good D2H FIS. */
4837 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
4838 pAhciPort->fResetDevice = false;
4839 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
4840 ahciPostFirstD2HFisIntoMemory(pAhciPort);
4841
4842 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
4843 if (pAhciPort->fATAPI)
4844 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
4845 else
4846 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
4847 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
4848
4849 rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
4850 AssertRC(rc);
4851}
4852
4853/**
4854 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
4855 *
4856 * @returns nothing.
4857 * @param pAhciPort The device to reset.
4858 * @param pAhciReq The task state.
4859 */
4860static void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4861{
4862 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
4863
4864 /*
4865 * Because this ATAPI only and ATAPI can't have
4866 * more than one command active at a time the task counter should be 0
4867 * and it is possible to finish the reset now.
4868 */
4869 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
4870 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
4871}
4872
4873/**
4874 * Create a PIO setup FIS and post it into the memory area of the guest.
4875 *
4876 * @returns nothing.
4877 * @param pAhciPort The port of the SATA controller.
4878 * @param pAhciReq The state of the task.
4879 * @param pCmdFis Pointer to the command FIS from the guest.
4880 * @param fInterrupt If an interrupt should be send to the guest.
4881 */
4882static void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
4883 bool fInterrupt)
4884{
4885 uint8_t abPioSetupFis[20];
4886 bool fAssertIntr = false;
4887 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4888
4889 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
4890
4891 AssertMsg( pAhciReq->cbTransfer > 0
4892 && pAhciReq->cbTransfer <= 65534,
4893 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
4894
4895 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
4896 {
4897 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
4898 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
4899 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
4900 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
4901 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
4902 abPioSetupFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
4903 abPioSetupFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
4904 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
4905 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
4906 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
4907 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
4908 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
4909 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
4910 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
4911 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
4912 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
4913
4914 /* Set transfer count. */
4915 abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
4916 abPioSetupFis[17] = pAhciReq->cbTransfer & 0xff;
4917
4918 /* Update registers. */
4919 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
4920
4921 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
4922
4923 if (fInterrupt)
4924 {
4925 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
4926 /* Check if we should assert an interrupt */
4927 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
4928 fAssertIntr = true;
4929 }
4930
4931 if (fAssertIntr)
4932 {
4933 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
4934 AssertRC(rc);
4935 }
4936 }
4937}
4938
4939/**
4940 * Build a D2H FIS and post into the memory area of the guest.
4941 *
4942 * @returns Nothing
4943 * @param pAhciPort The port of the SATA controller.
4944 * @param pAhciReq The state of the task.
4945 * @param pCmdFis Pointer to the command FIS from the guest.
4946 * @param fInterrupt If an interrupt should be send to the guest.
4947 */
4948static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
4949{
4950 uint8_t d2hFis[20];
4951 bool fAssertIntr = false;
4952 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4953
4954 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
4955
4956 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
4957 {
4958 memset(&d2hFis[0], 0, sizeof(d2hFis));
4959 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
4960 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
4961 d2hFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
4962 d2hFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
4963 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
4964 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
4965 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
4966 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
4967 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
4968 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
4969 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
4970 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
4971 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
4972
4973 /* Update registers. */
4974 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
4975
4976 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
4977
4978 if (pAhciReq->uATARegStatus & ATA_STAT_ERR)
4979 {
4980 /* Error bit is set. */
4981 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
4982 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
4983 fAssertIntr = true;
4984 /*
4985 * Don't mark the command slot as completed because the guest
4986 * needs it to identify the failed command.
4987 */
4988 }
4989 else if (fInterrupt)
4990 {
4991 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
4992 /* Check if we should assert an interrupt */
4993 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
4994 fAssertIntr = true;
4995
4996 /* Mark command as completed. */
4997 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
4998 }
4999
5000 if (fAssertIntr)
5001 {
5002 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5003 AssertRC(rc);
5004 }
5005 }
5006}
5007
5008/**
5009 * Build a SDB Fis and post it into the memory area of the guest.
5010 *
5011 * @returns Nothing
5012 * @param pAhciPort The port for which the SDB Fis is send.
5013 * @param uFinishedTasks Bitmask of finished tasks.
5014 * @param fInterrupt If an interrupt should be asserted.
5015 */
5016static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
5017{
5018 uint32_t sdbFis[2];
5019 bool fAssertIntr = false;
5020 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5021 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
5022
5023 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
5024
5025 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5026 {
5027 memset(&sdbFis[0], 0, sizeof(sdbFis));
5028 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
5029 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
5030 if (RT_UNLIKELY(pTaskErr))
5031 {
5032 sdbFis[0] = pTaskErr->uATARegError;
5033 sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
5034
5035 /* Update registers. */
5036 pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
5037 }
5038 else
5039 {
5040 sdbFis[0] = 0;
5041 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
5042 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
5043 }
5044
5045 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
5046
5047 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
5048
5049 if (RT_UNLIKELY(pTaskErr))
5050 {
5051 /* Error bit is set. */
5052 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5053 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5054 fAssertIntr = true;
5055 }
5056
5057 if (fInterrupt)
5058 {
5059 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
5060 /* Check if we should assert an interrupt */
5061 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
5062 fAssertIntr = true;
5063 }
5064
5065 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
5066
5067 if (fAssertIntr)
5068 {
5069 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5070 AssertRC(rc);
5071 }
5072 }
5073}
5074
5075static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
5076{
5077 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
5078 if (fLBA48)
5079 {
5080 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
5081 return 65536;
5082 else
5083 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
5084 }
5085 else
5086 {
5087 if (!pCmdFis[AHCI_CMDFIS_SECTC])
5088 return 256;
5089 else
5090 return pCmdFis[AHCI_CMDFIS_SECTC];
5091 }
5092}
5093
5094static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
5095{
5096 uint64_t iLBA;
5097 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
5098 {
5099 /* any LBA variant */
5100 if (fLBA48)
5101 {
5102 /* LBA48 */
5103 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5104 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5105 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5106 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5107 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5108 pCmdFis[AHCI_CMDFIS_SECTN];
5109 }
5110 else
5111 {
5112 /* LBA */
5113 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5114 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
5115 }
5116 }
5117 else
5118 {
5119 /* CHS */
5120 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
5121 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
5122 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
5123 }
5124 return iLBA;
5125}
5126
5127static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
5128{
5129 uint64_t uLBA;
5130
5131 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5132 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5133 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5134 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5135 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5136 pCmdFis[AHCI_CMDFIS_SECTN];
5137
5138 return uLBA;
5139}
5140
5141DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
5142{
5143 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
5144 return 65536;
5145 else
5146 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
5147}
5148
5149DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
5150{
5151 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
5152}
5153
5154/**
5155 * Allocates memory for the given request using already allocated memory if possible.
5156 *
5157 * @returns Pointer to the memory or NULL on failure
5158 * @param pAhciReq The request to allocate memory for.
5159 * @param cb The amount of memory to allocate.
5160 */
5161static void *ahciReqMemAlloc(PAHCIREQ pAhciReq, size_t cb)
5162{
5163 if (pAhciReq->cbAlloc > cb)
5164 {
5165 pAhciReq->cAllocTooMuch++;
5166 }
5167 else if (pAhciReq->cbAlloc < cb)
5168 {
5169 if (pAhciReq->cbAlloc)
5170 RTMemPageFree(pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5171
5172 pAhciReq->cbAlloc = RT_ALIGN_Z(cb, _4K);
5173 pAhciReq->pvAlloc = RTMemPageAlloc(pAhciReq->cbAlloc);
5174 pAhciReq->cAllocTooMuch = 0;
5175 if (RT_UNLIKELY(!pAhciReq->pvAlloc))
5176 pAhciReq->cbAlloc = 0;
5177 }
5178
5179 return pAhciReq->pvAlloc;
5180}
5181
5182/**
5183 * Frees memory allocated for the given request.
5184 *
5185 * @returns nothing.
5186 * @param pAhciReq The request.
5187 */
5188static void ahciReqMemFree(PAHCIREQ pAhciReq)
5189{
5190 if (pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH)
5191 {
5192 RTMemPageFree(pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5193 pAhciReq->cbAlloc = 0;
5194 pAhciReq->cAllocTooMuch = 0;
5195 }
5196}
5197
5198/**
5199 * Copies a data buffer into the S/G buffer set up by the guest.
5200 *
5201 * @returns Amount of bytes copied to the PRDTL.
5202 * @param pDevIns Pointer to the device instance data.
5203 * @param pAhciReq AHCI request structure.
5204 * @param pvBuf The buffer to copy from.
5205 * @param cbBuf The size of the buffer.
5206 */
5207static size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5208 void *pvBuf, size_t cbBuf)
5209{
5210 uint8_t *pbBuf = (uint8_t *)pvBuf;
5211 SGLEntry aPrdtlEntries[32];
5212 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5213 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5214 size_t cbCopied = 0;
5215
5216 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5217
5218 do
5219 {
5220 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5221 ? cPrdtlEntries
5222 : RT_ELEMENTS(aPrdtlEntries);
5223
5224 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5225
5226 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5227 {
5228 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5229 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5230
5231 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5232
5233 /* Copy into SG entry. */
5234 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5235
5236 pbBuf += cbThisCopy;
5237 cbBuf -= cbThisCopy;
5238 cbCopied += cbThisCopy;
5239 }
5240
5241 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5242 cPrdtlEntries -= cPrdtlEntriesRead;
5243 } while (cPrdtlEntries && cbBuf);
5244
5245 if (cbCopied < cbBuf)
5246 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5247
5248 return cbCopied;
5249}
5250
5251/**
5252 * Copies the S/G buffer into a data buffer.
5253 *
5254 * @returns Amount of bytes copied to the PRDTL.
5255 * @param pDevIns Pointer to the device instance data.
5256 * @param pAhciReq AHCI request structure.
5257 * @param pvBuf The buffer to copy to.
5258 * @param cbBuf The size of the buffer.
5259 */
5260static size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5261 void *pvBuf, size_t cbBuf)
5262{
5263 uint8_t *pbBuf = (uint8_t *)pvBuf;
5264 SGLEntry aPrdtlEntries[32];
5265 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5266 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5267 size_t cbCopied = 0;
5268
5269 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5270
5271 do
5272 {
5273 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5274 ? cPrdtlEntries
5275 : RT_ELEMENTS(aPrdtlEntries);
5276
5277 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5278
5279 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5280 {
5281 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5282 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5283
5284 cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
5285
5286 /* Copy into buffer. */
5287 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5288
5289 pbBuf += cbThisCopy;
5290 cbBuf -= cbThisCopy;
5291 cbCopied += cbThisCopy;
5292 }
5293
5294 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5295 cPrdtlEntries -= cPrdtlEntriesRead;
5296 } while (cPrdtlEntries && cbBuf);
5297
5298 if (cbCopied < cbBuf)
5299 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5300
5301 return cbCopied;
5302}
5303
5304/**
5305 * Allocate I/O memory and copies the guest buffer for writes.
5306 *
5307 * @returns VBox status code.
5308 * @param pAhciReq The request state.
5309 * @param cbTransfer Amount of bytes to allocate.
5310 */
5311static int ahciIoBufAllocate(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, size_t cbTransfer)
5312{
5313 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5314 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5315 ("Allocating I/O memory for a non I/O request is not allowed\n"));
5316
5317 pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciReq, cbTransfer);
5318 if (!pAhciReq->u.Io.DataSeg.pvSeg)
5319 return VERR_NO_MEMORY;
5320
5321 pAhciReq->u.Io.DataSeg.cbSeg = cbTransfer;
5322 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
5323 {
5324 ahciCopyFromPrdtl(pDevIns, pAhciReq,
5325 pAhciReq->u.Io.DataSeg.pvSeg,
5326 cbTransfer);
5327 }
5328 return VINF_SUCCESS;
5329}
5330
5331static void ahciIoBufFree(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5332 bool fCopyToGuest)
5333{
5334 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5335 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5336 ("Freeing I/O memory for a non I/O request is not allowed\n"));
5337
5338 if ( pAhciReq->enmTxDir == AHCITXDIR_READ
5339 && fCopyToGuest)
5340 {
5341 if (pAhciReq->u.Io.pfnPostProcess)
5342 {
5343 void *pv = NULL;
5344 size_t cb = 0;
5345 int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
5346
5347 if (RT_SUCCESS(rc))
5348 {
5349 ahciCopyToPrdtl(pDevIns, pAhciReq, pv, cb);
5350 RTMemFree(pv);
5351 }
5352 }
5353 else
5354 ahciCopyToPrdtl(pDevIns, pAhciReq,
5355 pAhciReq->u.Io.DataSeg.pvSeg,
5356 pAhciReq->u.Io.DataSeg.cbSeg);
5357 }
5358
5359 ahciReqMemFree(pAhciReq);
5360 pAhciReq->u.Io.DataSeg.pvSeg = NULL;
5361 pAhciReq->u.Io.DataSeg.cbSeg = 0;
5362}
5363
5364
5365/**
5366 * Cancels all active tasks on the port.
5367 *
5368 * @returns Whether all active tasks were canceled.
5369 * @param pAhciPort The ahci port.
5370 */
5371static bool ahciCancelActiveTasks(PAHCIPort pAhciPort)
5372{
5373 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aCachedTasks); i++)
5374 {
5375 PAHCIREQ pAhciReq = pAhciPort->aCachedTasks[i];
5376
5377 if (VALID_PTR(pAhciReq))
5378 {
5379 bool fXchg = false;
5380 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE, fXchg);
5381
5382 if (fXchg)
5383 {
5384 /* Task is active and was canceled. */
5385 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
5386 ("Task was canceled but none is active\n"));
5387 ASMAtomicDecU32(&pAhciPort->cTasksActive);
5388
5389 /*
5390 * Clear the pointer in the cached array. The controller will allocate a
5391 * a new task structure for this tag.
5392 */
5393 ASMAtomicWriteNullPtr(&pAhciPort->aCachedTasks[i]);
5394 LogRel(("AHCI#%dP%d: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
5395 pAhciPort->iLUN, pAhciReq->uTag));
5396 }
5397 else
5398 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
5399 ("Invalid task state, must be free!\n"));
5400 }
5401 }
5402
5403 AssertRelease(!ASMAtomicReadU32(&pAhciPort->cTasksActive));
5404 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
5405}
5406
5407/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
5408
5409/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
5410#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
5411
5412static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
5413{
5414 int rc;
5415 LogRel(("AHCI: Host disk full\n"));
5416 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
5417 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
5418 AssertRC(rc);
5419}
5420
5421static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
5422{
5423 int rc;
5424 LogRel(("AHCI: File too big\n"));
5425 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
5426 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"));
5427 AssertRC(rc);
5428}
5429
5430static void ahciWarningISCSI(PPDMDEVINS pDevIns)
5431{
5432 int rc;
5433 LogRel(("AHCI: iSCSI target unavailable\n"));
5434 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
5435 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
5436 AssertRC(rc);
5437}
5438
5439bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
5440{
5441 if (rc == VERR_DISK_FULL)
5442 {
5443 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5444 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
5445 return true;
5446 }
5447 if (rc == VERR_FILE_TOO_BIG)
5448 {
5449 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5450 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
5451 return true;
5452 }
5453 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
5454 {
5455 /* iSCSI connection abort (first error) or failure to reestablish
5456 * connection (second error). Pause VM. On resume we'll retry. */
5457 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5458 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
5459 return true;
5460 }
5461 return false;
5462}
5463
5464/**
5465 * Creates the array of ranges to trim.
5466 *
5467 * @returns VBox status code.
5468 * @param pAhciPort AHCI port state.
5469 * @param pAhciReq The request handling the TRIM request.
5470 */
5471static int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5472{
5473 SGLEntry aPrdtlEntries[32];
5474 uint64_t aRanges[64];
5475 unsigned cRangesMax;
5476 unsigned cRanges = 0;
5477 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
5478 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5479 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
5480 int rc = VINF_SUCCESS;
5481
5482 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
5483
5484 AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
5485
5486 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
5487 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
5488 cRangesMax = 65536 * 512 / 8;
5489 else
5490 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
5491
5492 if (!cPrdtlEntries)
5493 {
5494 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5495 return VINF_SUCCESS;
5496 }
5497
5498 do
5499 {
5500 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5501 ? cPrdtlEntries
5502 : RT_ELEMENTS(aPrdtlEntries);
5503
5504 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5505
5506 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5507 {
5508 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5509 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5510
5511 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5512
5513 /* Copy into buffer. */
5514 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5515
5516 for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
5517 {
5518 aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
5519 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRange]) != 0)
5520 cRanges++;
5521 else
5522 break;
5523 }
5524 }
5525
5526 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5527 cPrdtlEntries -= cPrdtlEntriesRead;
5528 } while (cPrdtlEntries);
5529
5530 if (RT_UNLIKELY(!cRanges))
5531 {
5532 return VERR_BUFFER_OVERFLOW;
5533 }
5534
5535 pAhciReq->u.Trim.cRanges = cRanges;
5536 pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
5537 if (pAhciReq->u.Trim.paRanges)
5538 {
5539 uint32_t idxRange = 0;
5540
5541 cPrdtlEntries = pAhciReq->cPrdtlEntries;
5542 GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5543
5544 /* Convert the ranges from the guest to our format. */
5545 do
5546 {
5547 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5548 ? cPrdtlEntries
5549 : RT_ELEMENTS(aPrdtlEntries);
5550
5551 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5552
5553 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5554 {
5555 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5556 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5557
5558 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5559
5560 /* Copy into buffer. */
5561 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5562
5563 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
5564 {
5565 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
5566 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
5567 {
5568 pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * 512;
5569 pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * 512;
5570 idxRange++;
5571 }
5572 else
5573 break;
5574 }
5575 }
5576
5577 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5578 cPrdtlEntries -= cPrdtlEntriesRead;
5579 } while (idxRange < cRanges);
5580 }
5581 else
5582 rc = VERR_NO_MEMORY;
5583
5584 LogFlowFunc(("returns rc=%Rrc\n", rc));
5585 return rc;
5586}
5587
5588/**
5589 * Destroy the trim range list.
5590 *
5591 * @returns nothing.
5592 * @param pAhciReq The task state.
5593 */
5594static void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
5595{
5596 AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
5597 RTMemFree(pAhciReq->u.Trim.paRanges);
5598}
5599
5600/**
5601 * Complete a data transfer task by freeing all occupied resources
5602 * and notifying the guest.
5603 *
5604 * @returns VBox status code
5605 *
5606 * @param pAhciPort Pointer to the port where to request completed.
5607 * @param pAhciReq Pointer to the task which finished.
5608 * @param rcReq IPRT status code of the completed request.
5609 * @param fFreeReq Flag whether to free the request if it was canceled.
5610 */
5611static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq, bool fFreeReq)
5612{
5613 bool fXchg = false;
5614 bool fRedo = false;
5615
5616 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
5617
5618 if (fXchg)
5619 {
5620 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
5621 {
5622 ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, true /* fCopyToGuest */);
5623 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
5624 pAhciPort->Led.Actual.s.fReading = 0;
5625 }
5626 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
5627 {
5628 ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, false /* fCopyToGuest */);
5629 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
5630 pAhciPort->Led.Actual.s.fWriting = 0;
5631 }
5632 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
5633 {
5634 ahciTrimRangesDestroy(pAhciReq);
5635 pAhciPort->Led.Actual.s.fWriting = 0;
5636 }
5637
5638 if (RT_FAILURE(rcReq))
5639 {
5640 /* Log the error. */
5641 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5642 {
5643 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
5644 LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
5645 pAhciPort->iLUN, rcReq));
5646 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
5647 LogRel(("AHCI#%u: Trim returned rc=%Rrc\n",
5648 pAhciPort->iLUN, rcReq));
5649 else
5650 LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
5651 pAhciPort->iLUN,
5652 pAhciReq->enmTxDir == AHCITXDIR_READ
5653 ? "Read"
5654 : "Write",
5655 pAhciReq->uOffset,
5656 pAhciReq->cbTransfer, rcReq));
5657 }
5658
5659 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
5660 if (!fRedo)
5661 {
5662 pAhciReq->cmdHdr.u32PRDBC = 0;
5663 pAhciReq->uATARegError = ID_ERR;
5664 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5665 ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
5666 }
5667 else
5668 ASMAtomicOrU32(&pAhciPort->u32TasksNew, RT_BIT_32(pAhciReq->uTag));
5669 }
5670 else
5671 {
5672 pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer;
5673
5674 /* Status will be set by already for non I/O requests. */
5675 if (pAhciReq->enmTxDir != AHCITXDIR_NONE)
5676 {
5677 pAhciReq->uATARegError = 0;
5678 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5679 }
5680
5681 /* Write updated command header into memory of the guest. */
5682 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr,
5683 &pAhciReq->cmdHdr, sizeof(CmdHdr));
5684
5685 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
5686 {
5687 /*
5688 * The guest tried to transfer more data than there is space in the buffer.
5689 * Terminate task and set the overflow bit.
5690 */
5691 /* Notify the guest. */
5692 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
5693 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
5694 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5695 }
5696 }
5697
5698 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,
5699 ("Inconsistent request counter\n"));
5700 ASMAtomicDecU32(&pAhciPort->cTasksActive);
5701
5702 if (!fRedo)
5703 {
5704
5705 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
5706 if (pAhciReq->fFlags & AHCI_REQ_PIO_DATA)
5707 ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
5708
5709 if (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT)
5710 {
5711 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
5712 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
5713 }
5714
5715 if (pAhciReq->fFlags & AHCI_REQ_IS_QUEUED)
5716 {
5717 /*
5718 * Always raise an interrupt after task completion; delaying
5719 * this (interrupt coalescing) increases latency and has a significant
5720 * impact on performance (see @bugref{5071})
5721 */
5722 ahciSendSDBFis(pAhciPort, 0, true);
5723 }
5724 else
5725 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
5726 }
5727 }
5728 else
5729 {
5730 /*
5731 * Task was canceled, do the cleanup but DO NOT access the guest memory!
5732 * The guest might use it for other things now because it doesn't know about that task anymore.
5733 */
5734 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_CANCELED,
5735 ("Task is not active but wasn't canceled!\n"));
5736
5737 if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
5738 ahciTrimRangesDestroy(pAhciReq);
5739 else if (pAhciReq->enmTxDir != AHCITXDIR_FLUSH)
5740 ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, false /* fCopyToGuest */);
5741
5742 /* Leave a log message about the canceled request. */
5743 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5744 {
5745 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
5746 LogRel(("AHCI#%u: Canceled flush returned rc=%Rrc\n",
5747 pAhciPort->iLUN, rcReq));
5748 else
5749 LogRel(("AHCI#%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
5750 pAhciPort->iLUN,
5751 pAhciReq->enmTxDir == AHCITXDIR_READ
5752 ? "read"
5753 : "write",
5754 pAhciReq->uOffset,
5755 pAhciReq->cbTransfer, rcReq));
5756 }
5757
5758 /* Finally free the task state structure because it is completely unused now. */
5759 if (fFreeReq)
5760 RTMemFree(pAhciReq);
5761 }
5762
5763 return VINF_SUCCESS;
5764}
5765
5766/**
5767 * Notification callback for a completed transfer.
5768 *
5769 * @returns VBox status code.
5770 * @param pInterface Pointer to the interface.
5771 * @param pvUser User data.
5772 * @param rcReq IPRT Status code of the completed request.
5773 */
5774static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
5775{
5776 PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
5777 PAHCIREQ pAhciReq = (PAHCIREQ)pvUser;
5778
5779 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
5780 __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
5781
5782 int rc = ahciTransferComplete(pAhciPort, pAhciReq, rcReq, true);
5783
5784 if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
5785 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
5786 return rc;
5787}
5788
5789/**
5790 * Process an non read/write ATA command.
5791 *
5792 * @returns The direction of the data transfer
5793 * @param pCmdHdr Pointer to the command header.
5794 */
5795static AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
5796{
5797 AHCITXDIR rc = AHCITXDIR_NONE;
5798 bool fLBA48 = false;
5799 CmdHdr *pCmdHdr = &pAhciReq->cmdHdr;
5800
5801 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
5802
5803 pAhciReq->cbTransfer = 0;
5804
5805 switch (pCmdFis[AHCI_CMDFIS_CMD])
5806 {
5807 case ATA_IDENTIFY_DEVICE:
5808 {
5809 if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
5810 {
5811 int rc2;
5812 uint16_t u16Temp[256];
5813 size_t cbCopied;
5814
5815 /* Fill the buffer. */
5816 ahciIdentifySS(pAhciPort, u16Temp);
5817
5818 /* Copy the buffer. */
5819 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5820 &u16Temp[0], sizeof(u16Temp));
5821
5822 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
5823 pAhciReq->cbTransfer = cbCopied;
5824 }
5825 else
5826 {
5827 pAhciReq->uATARegError = ABRT_ERR;
5828 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
5829 }
5830 break;
5831 }
5832 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
5833 case ATA_READ_NATIVE_MAX_ADDRESS:
5834 break;
5835 case ATA_SET_FEATURES:
5836 {
5837 switch (pCmdFis[AHCI_CMDFIS_FET])
5838 {
5839 case 0x02: /* write cache enable */
5840 case 0xaa: /* read look-ahead enable */
5841 case 0x55: /* read look-ahead disable */
5842 case 0xcc: /* reverting to power-on defaults enable */
5843 case 0x66: /* reverting to power-on defaults disable */
5844 pAhciReq->uATARegError = 0;
5845 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5846 break;
5847 case 0x82: /* write cache disable */
5848 rc = AHCITXDIR_FLUSH;
5849 break;
5850 case 0x03:
5851 { /* set transfer mode */
5852 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
5853 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
5854 {
5855 case 0x00: /* PIO default */
5856 case 0x08: /* PIO mode */
5857 break;
5858 case ATA_MODE_MDMA: /* MDMA mode */
5859 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
5860 break;
5861 case ATA_MODE_UDMA: /* UDMA mode */
5862 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
5863 break;
5864 }
5865 break;
5866 }
5867 default:
5868 pAhciReq->uATARegError = ABRT_ERR;
5869 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5870 }
5871 break;
5872 }
5873 case ATA_DEVICE_RESET:
5874 {
5875 if (!pAhciPort->fATAPI)
5876 {
5877 pAhciReq->uATARegError = ABRT_ERR;
5878 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5879 }
5880 else
5881 {
5882 /* Reset the device. */
5883 ahciDeviceReset(pAhciPort, pAhciReq);
5884 }
5885 break;
5886 }
5887 case ATA_FLUSH_CACHE_EXT:
5888 case ATA_FLUSH_CACHE:
5889 rc = AHCITXDIR_FLUSH;
5890 break;
5891 case ATA_PACKET:
5892 if (!pAhciPort->fATAPI)
5893 {
5894 pAhciReq->uATARegError = ABRT_ERR;
5895 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5896 }
5897 else
5898 rc = atapiParseCmd(pAhciPort, pAhciReq);
5899 break;
5900 case ATA_IDENTIFY_PACKET_DEVICE:
5901 if (!pAhciPort->fATAPI)
5902 {
5903 pAhciReq->uATARegError = ABRT_ERR;
5904 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5905 }
5906 else
5907 {
5908 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
5909
5910 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
5911 pAhciReq->uATARegError = 0;
5912 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5913 }
5914 break;
5915 case ATA_SET_MULTIPLE_MODE:
5916 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
5917 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
5918 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
5919 {
5920 pAhciReq->uATARegError = ABRT_ERR;
5921 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5922 }
5923 else
5924 {
5925 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
5926 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
5927 pAhciReq->uATARegError = 0;
5928 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5929 }
5930 break;
5931 case ATA_STANDBY_IMMEDIATE:
5932 break; /* Do nothing. */
5933 case ATA_CHECK_POWER_MODE:
5934 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
5935 /* fall through */
5936 case ATA_INITIALIZE_DEVICE_PARAMETERS:
5937 case ATA_IDLE_IMMEDIATE:
5938 case ATA_RECALIBRATE:
5939 case ATA_NOP:
5940 case ATA_READ_VERIFY_SECTORS_EXT:
5941 case ATA_READ_VERIFY_SECTORS:
5942 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
5943 case ATA_SLEEP:
5944 pAhciReq->uATARegError = 0;
5945 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5946 break;
5947 case ATA_READ_DMA_EXT:
5948 fLBA48 = true;
5949 case ATA_READ_DMA:
5950 {
5951 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5952 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5953 rc = AHCITXDIR_READ;
5954 break;
5955 }
5956 case ATA_WRITE_DMA_EXT:
5957 fLBA48 = true;
5958 case ATA_WRITE_DMA:
5959 {
5960 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5961 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5962 rc = AHCITXDIR_WRITE;
5963 break;
5964 }
5965 case ATA_READ_FPDMA_QUEUED:
5966 {
5967 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5968 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5969 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
5970 rc = AHCITXDIR_READ;
5971 break;
5972 }
5973 case ATA_WRITE_FPDMA_QUEUED:
5974 {
5975 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5976 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5977 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
5978 rc = AHCITXDIR_WRITE;
5979 break;
5980 }
5981 case ATA_READ_LOG_EXT:
5982 {
5983 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
5984 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
5985 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
5986 size_t cbCopied;
5987
5988 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
5989
5990 uint8_t aBuf[512];
5991
5992 memset(aBuf, 0, sizeof(aBuf));
5993
5994 if (offLogRead + cbLogRead <= sizeof(aBuf))
5995 {
5996 switch (iPage)
5997 {
5998 case 0x10:
5999 {
6000 LogFlow(("Reading error page\n"));
6001 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6002 if (pTaskErr)
6003 {
6004 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6005 aBuf[2] = pTaskErr->uATARegStatus;
6006 aBuf[3] = pTaskErr->uATARegError;
6007 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6008 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6009 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6010 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6011 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6012 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6013 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6014 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6015 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6016
6017 /* Calculate checksum */
6018 uint8_t uChkSum = 0;
6019 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6020 uChkSum += aBuf[i];
6021
6022 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6023
6024 /*
6025 * Reading this log page results in an abort of all outstanding commands
6026 * and clearing the SActive register and TaskFile register.
6027 */
6028 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6029 }
6030 break;
6031 }
6032 }
6033
6034 /* Copy the buffer. */
6035 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6036 &aBuf[offLogRead], cbLogRead);
6037
6038 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6039 pAhciReq->cbTransfer = cbCopied;
6040 }
6041
6042 break;
6043 }
6044 case ATA_DATA_SET_MANAGEMENT:
6045 {
6046 if ( ( !pAhciPort->fAsyncInterface
6047 && pAhciPort->pDrvBlock->pfnDiscard)
6048 || ( pAhciPort->fAsyncInterface
6049 && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
6050 {
6051 /* Check that the trim bit is set and all other bits are 0. */
6052 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6053 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6054 {
6055 pAhciReq->uATARegError = ABRT_ERR;
6056 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6057 }
6058 else
6059 rc = AHCITXDIR_TRIM;
6060 break;
6061 }
6062 /* else: fall through and report error to the guest. */
6063 }
6064 /* All not implemented commands go below. */
6065 case ATA_SECURITY_FREEZE_LOCK:
6066 case ATA_SMART:
6067 case ATA_NV_CACHE:
6068 case ATA_IDLE:
6069 pAhciReq->uATARegError = ABRT_ERR;
6070 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6071 break;
6072 default: /* For debugging purposes. */
6073 AssertMsgFailed(("Unknown command issued\n"));
6074 pAhciReq->uATARegError = ABRT_ERR;
6075 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6076 }
6077
6078 return rc;
6079}
6080
6081/**
6082 * Retrieve a command FIS from guest memory.
6083 *
6084 * @returns nothing
6085 * @param pAhciReq The state of the actual task.
6086 */
6087static void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6088{
6089 RTGCPHYS GCPhysAddrCmdTbl;
6090
6091 AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
6092
6093 /*
6094 * First we are reading the command header pointed to by regCLB.
6095 * From this we get the address of the command table which we are reading too.
6096 * We can process the Command FIS afterwards.
6097 */
6098 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6099 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6100 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6101 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6102
6103#ifdef DEBUG
6104 /* Print some infos about the command header. */
6105 ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
6106#endif
6107
6108 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
6109
6110 AssertMsg((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6111 ("This is not a command FIS!!\n"));
6112
6113 /* Read the command Fis. */
6114 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6115 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6116
6117 /* Set transfer direction. */
6118 pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
6119
6120 /* If this is an ATAPI command read the atapi command. */
6121 if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6122 {
6123 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6124 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6125 }
6126
6127 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6128 if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6129 {
6130 /*
6131 * 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.
6132 * but this FIS does not assert an interrupt
6133 */
6134 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6135 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6136 }
6137
6138 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6139 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
6140
6141#ifdef DEBUG
6142 /* Print some infos about the FIS. */
6143 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6144
6145 /* Print the PRDT */
6146 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6147 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6148
6149 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6150 {
6151 SGLEntry SGEntry;
6152
6153 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6154 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6155
6156 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6157 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6158
6159 GCPhysPrdtl += sizeof(SGLEntry);
6160 }
6161#endif
6162}
6163
6164/**
6165 * Transmit queue consumer
6166 * Queue a new async task.
6167 *
6168 * @returns Success indicator.
6169 * If false the item will not be removed and the flushing will stop.
6170 * @param pDevIns The device instance.
6171 * @param pItem The item to consume. Upon return this item will be freed.
6172 */
6173static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6174{
6175 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6176 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6177 PAHCIPort pAhciPort = &pAhci->ahciPort[pNotifierItem->iPort];
6178 int rc = VINF_SUCCESS;
6179
6180 if (!pAhciPort->fAsyncInterface)
6181 {
6182 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6183 /* Notify the async IO thread. */
6184 rc = RTSemEventSignal(pAhciPort->AsyncIORequestSem);
6185 AssertRC(rc);
6186 }
6187 else
6188 {
6189 unsigned idx = 0;
6190 uint32_t u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6191
6192 idx = ASMBitFirstSetU32(u32Tasks);
6193 while (idx)
6194 {
6195 AHCITXDIR enmTxDir;
6196 PAHCIREQ pAhciReq;
6197
6198 /* Decrement to get the slot number. */
6199 idx--;
6200 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6201
6202 /*
6203 * Check if there is already an allocated task struct in the cache.
6204 * Allocate a new task otherwise.
6205 */
6206 if (!pAhciPort->aCachedTasks[idx])
6207 {
6208 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6209 AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n"));
6210 pAhciReq->enmTxState = AHCITXSTATE_FREE;
6211 pAhciPort->aCachedTasks[idx] = pAhciReq;
6212 }
6213 else
6214 pAhciReq = pAhciPort->aCachedTasks[idx];
6215
6216 bool fXchg;
6217 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE, fXchg);
6218 AssertMsg(fXchg, ("Task is already active\n"));
6219
6220 pAhciReq->uATARegStatus = 0;
6221 pAhciReq->uATARegError = 0;
6222 pAhciReq->fFlags = 0;
6223
6224 /* Set current command slot */
6225 pAhciReq->uTag = idx;
6226 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6227
6228 ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6229
6230 /* 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. */
6231 if (pAhciPort->regSACT & (1 << idx))
6232 {
6233 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6234 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
6235 }
6236
6237 if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
6238 {
6239 /* If the reset bit is set put the device into reset state. */
6240 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6241 {
6242 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6243 pAhciPort->fResetDevice = true;
6244 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6245
6246 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6247 AssertMsg(fXchg, ("Task is not active\n"));
6248 return true;
6249 }
6250 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6251 {
6252 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6253
6254 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6255 AssertMsg(fXchg, ("Task is not active\n"));
6256 return true;
6257 }
6258 else /* We are not in a reset state update the control registers. */
6259 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6260 }
6261 else
6262 {
6263 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
6264 ("There are more than 32 requests active"));
6265 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6266
6267 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6268 pAhciReq->enmTxDir = enmTxDir;
6269
6270 if (enmTxDir != AHCITXDIR_NONE)
6271 {
6272 if ( enmTxDir != AHCITXDIR_FLUSH
6273 && enmTxDir != AHCITXDIR_TRIM)
6274 {
6275 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6276
6277 rc = ahciIoBufAllocate(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->cbTransfer);
6278 if (RT_FAILURE(rc))
6279 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
6280 }
6281
6282 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6283 {
6284 if (enmTxDir == AHCITXDIR_FLUSH)
6285 {
6286 rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
6287 pAhciReq);
6288 }
6289 else if (enmTxDir == AHCITXDIR_TRIM)
6290 {
6291 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6292 if (RT_SUCCESS(rc))
6293 {
6294 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6295 rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
6296 pAhciReq->u.Trim.cRanges, pAhciReq);
6297 }
6298 }
6299 else if (enmTxDir == AHCITXDIR_READ)
6300 {
6301 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6302 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6303 &pAhciReq->u.Io.DataSeg, 1,
6304 pAhciReq->cbTransfer,
6305 pAhciReq);
6306 }
6307 else
6308 {
6309 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6310 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6311 &pAhciReq->u.Io.DataSeg, 1,
6312 pAhciReq->cbTransfer,
6313 pAhciReq);
6314 }
6315 if (rc == VINF_VD_ASYNC_IO_FINISHED)
6316 rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6317 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6318 rc = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
6319 }
6320 }
6321 else
6322 rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6323 } /* Command */
6324
6325 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6326 idx = ASMBitFirstSetU32(u32Tasks);
6327 } /* while tasks available */
6328 } /* fUseAsyncInterface */
6329
6330 return true;
6331}
6332
6333/* The async IO thread for one port. */
6334static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6335{
6336 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6337 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6338 PAHCIREQ pAhciReq;
6339 int rc = VINF_SUCCESS;
6340 uint64_t u64StartTime = 0;
6341 uint64_t u64StopTime = 0;
6342 uint32_t uIORequestsProcessed = 0;
6343 uint32_t uIOsPerSec = 0;
6344 uint32_t fTasksToProcess = 0;
6345 unsigned idx = 0;
6346
6347 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6348
6349 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6350 return VINF_SUCCESS;
6351
6352 /* We use only one task structure. */
6353 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6354 if (!pAhciReq)
6355 {
6356 AssertMsgFailed(("Failed to allocate task state memory\n"));
6357 return VERR_NO_MEMORY;
6358 }
6359
6360 pAhciReq->enmTxState = AHCITXSTATE_FREE;
6361
6362 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6363 {
6364 /* New run to get number of I/O requests per second?. */
6365 if (!u64StartTime)
6366 u64StartTime = RTTimeMilliTS();
6367
6368 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
6369 if (pAhci->fSignalIdle)
6370 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6371
6372 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
6373 if (rc == VERR_TIMEOUT)
6374 {
6375 /* No I/O requests in-between. Reset statistics and wait again. */
6376 pAhciPort->StatIORequestsPerSecond.c = 0;
6377 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
6378 }
6379
6380 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
6381 break;
6382
6383 /* Go to sleep again if we are in redo mode. */
6384 if (RT_UNLIKELY(pAhciPort->fRedo))
6385 continue;
6386
6387 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
6388
6389 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
6390 fTasksToProcess = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6391
6392 idx = ASMBitFirstSetU32(fTasksToProcess);
6393
6394 /* Process commands. */
6395 while ( idx
6396 && RT_LIKELY(!pAhciPort->fPortReset))
6397 {
6398 AHCITXDIR enmTxDir;
6399
6400 idx--;
6401 STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
6402
6403 pAhciReq->uATARegStatus = 0;
6404 pAhciReq->uATARegError = 0;
6405 pAhciReq->fFlags = 0;
6406 pAhciReq->uTag = idx;
6407 AssertMsg(pAhciReq->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number %u!!\n", __FUNCTION__, pAhciReq->uTag));
6408
6409 bool fXchg;
6410 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE, fXchg);
6411 AssertMsg(fXchg, ("Task is already active\n"));
6412
6413 /* Set current command slot */
6414 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6415
6416 /* 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. */
6417 if (pAhciPort->regSACT & (1 << idx))
6418 {
6419 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6420 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
6421 }
6422
6423 ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6424
6425 ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciReq->uTag));
6426
6427 if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
6428 {
6429 /* If the reset bit is set put the device into reset state. */
6430 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6431 {
6432 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6433 pAhciPort->fResetDevice = true;
6434 ahciSendD2HFis(pAhciPort, pAhciReq, &pAhciReq->cmdFis[0], true);
6435 }
6436 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6437 {
6438 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6439 }
6440 /* TODO: We are not in a reset state update the control registers. */
6441
6442 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6443 AssertMsg(fXchg, ("Task is already free\n"));
6444 }
6445 else
6446 {
6447 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
6448 ("There are more than 32 requests active"));
6449 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6450 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, &pAhciReq->cmdFis[0]);
6451 pAhciReq->enmTxDir = enmTxDir;
6452
6453 if (enmTxDir == AHCITXDIR_FLUSH)
6454 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
6455 else if (enmTxDir == AHCITXDIR_TRIM)
6456 {
6457 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6458 if (RT_SUCCESS(rc))
6459 {
6460 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6461 rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock,
6462 pAhciReq->u.Trim.paRanges,
6463 pAhciReq->u.Trim.cRanges);
6464 pAhciPort->Led.Actual.s.fWriting = 0;
6465 }
6466 }
6467 else if (enmTxDir != AHCITXDIR_NONE)
6468 {
6469 uint64_t uOffset = 0;
6470 size_t cbTransfer = 0;
6471
6472 rc = ahciIoBufAllocate(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->cbTransfer);
6473 if (RT_FAILURE(rc))
6474 AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
6475
6476 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6477 {
6478 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6479
6480 /* Initialize all values. */
6481 uOffset = pAhciReq->uOffset;
6482 cbTransfer = pAhciReq->cbTransfer;
6483
6484 STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, b);
6485
6486 AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
6487 AssertMsg(!(cbTransfer % 512), ("Number of bytes to process is not sector aligned %lu\n", cbTransfer));
6488
6489 if (enmTxDir == AHCITXDIR_READ)
6490 {
6491 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6492 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
6493 pAhciReq->u.Io.DataSeg.pvSeg,
6494 cbTransfer);
6495 pAhciPort->Led.Actual.s.fReading = 0;
6496 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
6497 }
6498 else
6499 {
6500 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6501 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
6502 pAhciReq->u.Io.DataSeg.pvSeg,
6503 cbTransfer);
6504 pAhciPort->Led.Actual.s.fWriting = 0;
6505 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
6506 }
6507
6508 STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, b);
6509 }
6510 }
6511
6512 ahciTransferComplete(pAhciPort, pAhciReq, rc, false /* fFreeReq */);
6513 uIORequestsProcessed++;
6514 STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
6515 }
6516
6517 if (!pAhciPort->fRedo)
6518 {
6519#ifdef DEBUG
6520 /* Be paranoid. */
6521 memset(&pAhciReq->cmdHdr, 0, sizeof(CmdHdr));
6522 memset(&pAhciReq->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
6523 pAhciReq->GCPhysCmdHdrAddr = 0;
6524 pAhciReq->uOffset = 0;
6525 pAhciReq->cbTransfer = 0;
6526#endif
6527 }
6528 fTasksToProcess &= ~(1 << idx);
6529 idx = ASMBitFirstSetU32(fTasksToProcess);
6530 } /* while tasks to process */
6531
6532 u64StopTime = RTTimeMilliTS();
6533 /* Check if one second has passed. */
6534 if (u64StopTime - u64StartTime >= 1000)
6535 {
6536 /* Calculate number of I/O requests per second. */
6537 uIOsPerSec = uIORequestsProcessed / ((u64StopTime - u64StartTime) / 1000);
6538 ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
6539 u64StartTime = 0;
6540 uIORequestsProcessed = 0;
6541 /* For the release statistics. There is no macro to set the counter to a specific value. */
6542 pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
6543 }
6544 } /* While running */
6545
6546 if (pAhci->fSignalIdle)
6547 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6548
6549 RTMemFree(pAhciReq);
6550 memset(pAhciPort->aCachedTasks, 0, sizeof(pAhciPort->aCachedTasks));
6551
6552 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
6553 return VINF_SUCCESS;
6554}
6555
6556/**
6557 * Unblock the async I/O thread so it can respond to a state change.
6558 *
6559 * @returns VBox status code.
6560 * @param pDevIns The pcnet device instance.
6561 * @param pThread The send thread.
6562 */
6563static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6564{
6565 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6566 return RTSemEventSignal(pAhciPort->AsyncIORequestSem);
6567}
6568
6569/* -=-=-=-=- DBGF -=-=-=-=- */
6570
6571/**
6572 * AHCI status info callback.
6573 *
6574 * @param pDevIns The device instance.
6575 * @param pHlp The output helpers.
6576 * @param pszArgs The arguments.
6577 */
6578static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6579{
6580 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6581
6582 /*
6583 * Show info.
6584 */
6585 pHlp->pfnPrintf(pHlp,
6586 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
6587 pDevIns->pReg->szName,
6588 pDevIns->iInstance,
6589 pThis->MMIOBase,
6590 pThis->cPortsImpl,
6591 pThis->fGCEnabled ? true : false,
6592 pThis->fR0Enabled ? true : false);
6593
6594 /*
6595 * Show global registers.
6596 */
6597 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
6598 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
6599 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
6600 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
6601 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
6602 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
6603 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
6604 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
6605
6606 /*
6607 * Per port data.
6608 */
6609 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
6610 {
6611 PAHCIPort pThisPort = &pThis->ahciPort[i];
6612
6613 pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
6614 pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
6615 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
6616 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
6617 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
6618 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
6619 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
6620 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
6621 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
6622 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
6623 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
6624 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
6625 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
6626 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
6627 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
6628 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
6629 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
6630 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
6631 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
6632 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
6633 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
6634 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
6635 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
6636 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
6637 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
6638 pHlp->pfnPrintf(pHlp, "PortAsyncIoThreadIdle=%RTbool\n", pThisPort->fAsyncIOThreadIdle);
6639 pHlp->pfnPrintf(pHlp, "\n");
6640 }
6641}
6642
6643/* -=-=-=-=- Helper -=-=-=-=- */
6644
6645/**
6646 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
6647 *
6648 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
6649 * use of it in strict builds (which is why it's up here).
6650 *
6651 * @returns true if quiesced, false if busy.
6652 * @param pDevIns The device instance.
6653 */
6654static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
6655{
6656 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6657
6658 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
6659 {
6660 PAHCIPort pThisPort = &pThis->ahciPort[i];
6661 if (pThisPort->pDrvBase)
6662 {
6663 bool fFinished;
6664 if (pThisPort->fAsyncInterface)
6665 fFinished = (pThisPort->cTasksActive == 0);
6666 else
6667 fFinished = ((pThisPort->cTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
6668 if (!fFinished)
6669 return false;
6670 }
6671 }
6672 return true;
6673}
6674
6675/* -=-=-=-=- Saved State -=-=-=-=- */
6676
6677/**
6678 * @copydoc FNDEVSSMSAVEPREP
6679 */
6680static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6681{
6682 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6683 return VINF_SUCCESS;
6684}
6685
6686/**
6687 * @copydoc FNDEVSSMLOADPREP
6688 */
6689static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6690{
6691 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6692 return VINF_SUCCESS;
6693}
6694
6695/**
6696 * @copydoc FNDEVSSMLIVEEXEC
6697 */
6698static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6699{
6700 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6701
6702 /* config. */
6703 SSMR3PutU32(pSSM, pThis->cPortsImpl);
6704 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6705 {
6706 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
6707 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6708 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6709 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6710 }
6711
6712 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6713 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6714 {
6715 uint32_t iPort;
6716 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6717 AssertRCReturn(rc, rc);
6718 SSMR3PutU32(pSSM, iPort);
6719 }
6720
6721 return VINF_SSM_DONT_CALL_AGAIN;
6722}
6723
6724/**
6725 * @copydoc FNDEVSSMSAVEEXEC
6726 */
6727static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6728{
6729 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6730 uint32_t i;
6731 int rc;
6732
6733 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6734
6735 /* The config */
6736 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6737 AssertRCReturn(rc, rc);
6738
6739 /* The main device structure. */
6740 SSMR3PutU32(pSSM, pThis->regHbaCap);
6741 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
6742 SSMR3PutU32(pSSM, pThis->regHbaIs);
6743 SSMR3PutU32(pSSM, pThis->regHbaPi);
6744 SSMR3PutU32(pSSM, pThis->regHbaVs);
6745 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
6746 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
6747 SSMR3PutU8(pSSM, pThis->uCccPortNr);
6748 SSMR3PutU64(pSSM, pThis->uCccTimeout);
6749 SSMR3PutU32(pSSM, pThis->uCccNr);
6750 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
6751 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
6752 SSMR3PutBool(pSSM, pThis->fReset);
6753 SSMR3PutBool(pSSM, pThis->f64BitAddr);
6754 SSMR3PutBool(pSSM, pThis->fR0Enabled);
6755 SSMR3PutBool(pSSM, pThis->fGCEnabled);
6756
6757 /* Now every port. */
6758 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6759 {
6760 Assert(pThis->ahciPort[i].cTasksActive == 0);
6761 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
6762 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
6763 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
6764 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
6765 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6766 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6767 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
6768 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
6769 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
6770 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
6771 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
6772 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
6773 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
6774 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
6775 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
6776 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
6777 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
6778 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
6779 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
6780 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
6781 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
6782 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
6783 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
6784 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
6785 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
6786 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
6787 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
6788 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
6789
6790 /* ATAPI saved state. */
6791 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
6792 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
6793 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
6794 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
6795 }
6796
6797 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
6798}
6799
6800/**
6801 * Loads a saved legacy ATA emulated device state.
6802 *
6803 * @returns VBox status code.
6804 * @param pSSM The handle to the saved state.
6805 */
6806static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
6807{
6808 int rc;
6809 uint32_t u32Version;
6810 uint32_t u32;
6811 uint32_t u32IOBuffer;
6812
6813 /* Test for correct version. */
6814 rc = SSMR3GetU32(pSSM, &u32Version);
6815 AssertRCReturn(rc, rc);
6816 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
6817
6818 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
6819 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
6820 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
6821 {
6822 AssertMsgFailed(("u32Version=%d\n", u32Version));
6823 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6824 }
6825
6826 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
6827
6828 for (uint32_t j = 0; j < 2; j++)
6829 {
6830 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
6831
6832 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
6833 SSMR3Skip(pSSM, 64);
6834 else
6835 SSMR3Skip(pSSM, 2);
6836 /** @todo triple-check this hack after passthrough is working */
6837 SSMR3Skip(pSSM, 1);
6838
6839 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
6840 SSMR3Skip(pSSM, 4);
6841
6842 SSMR3Skip(pSSM, sizeof(PDMLED));
6843 SSMR3GetU32(pSSM, &u32IOBuffer);
6844 if (u32IOBuffer)
6845 SSMR3Skip(pSSM, u32IOBuffer);
6846 }
6847
6848 rc = SSMR3GetU32(pSSM, &u32);
6849 if (RT_FAILURE(rc))
6850 return rc;
6851 if (u32 != ~0U)
6852 {
6853 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
6854 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
6855 return rc;
6856 }
6857
6858 return VINF_SUCCESS;
6859}
6860
6861/**
6862 * Loads a saved AHCI device state.
6863 *
6864 * @returns VBox status code.
6865 * @param pDevIns The device instance.
6866 * @param pSSM The handle to the saved state.
6867 * @param uVersion The data unit version number.
6868 * @param uPass The data pass.
6869 */
6870static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
6871{
6872 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6873 uint32_t u32;
6874 int rc;
6875
6876 if ( uVersion > AHCI_SAVED_STATE_VERSION
6877 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
6878 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6879
6880 /* Deal with the priod after removing the saved IDE bits where the saved
6881 state version remained unchanged. */
6882 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
6883 && SSMR3HandleRevision(pSSM) >= 79045
6884 && SSMR3HandleRevision(pSSM) < 79201)
6885 uVersion++;
6886
6887 /* Verify config. */
6888 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
6889 {
6890 rc = SSMR3GetU32(pSSM, &u32);
6891 AssertRCReturn(rc, rc);
6892 if (u32 != pThis->cPortsImpl)
6893 {
6894 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
6895 if ( u32 < pThis->cPortsImpl
6896 || u32 > AHCI_MAX_NR_PORTS_IMPL)
6897 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
6898 u32, pThis->cPortsImpl);
6899 }
6900
6901 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6902 {
6903 bool fInUse;
6904 rc = SSMR3GetBool(pSSM, &fInUse);
6905 AssertRCReturn(rc, rc);
6906 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
6907 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
6908 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
6909 fInUse ? "target" : "source", i );
6910
6911 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
6912 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
6913 AssertRCReturn(rc, rc);
6914 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
6915 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
6916 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
6917
6918 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
6919 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
6920 AssertRCReturn(rc, rc);
6921 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
6922 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
6923 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
6924
6925 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
6926 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
6927 AssertRCReturn(rc, rc);
6928 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
6929 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
6930 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
6931 }
6932
6933 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6934 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6935 {
6936 uint32_t iPort;
6937 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6938 AssertRCReturn(rc, rc);
6939
6940 uint32_t iPortSaved;
6941 rc = SSMR3GetU32(pSSM, &iPortSaved);
6942 AssertRCReturn(rc, rc);
6943
6944 if (iPortSaved != iPort)
6945 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
6946 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
6947 }
6948 }
6949
6950 if (uPass == SSM_PASS_FINAL)
6951 {
6952 /* Restore data. */
6953
6954 /* The main device structure. */
6955 SSMR3GetU32(pSSM, &pThis->regHbaCap);
6956 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
6957 SSMR3GetU32(pSSM, &pThis->regHbaIs);
6958 SSMR3GetU32(pSSM, &pThis->regHbaPi);
6959 SSMR3GetU32(pSSM, &pThis->regHbaVs);
6960 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
6961 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
6962 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
6963 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
6964 SSMR3GetU32(pSSM, &pThis->uCccNr);
6965 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
6966
6967 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
6968 SSMR3GetBool(pSSM, &pThis->fReset);
6969 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
6970 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
6971 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
6972
6973 /* Now every port. */
6974 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6975 {
6976 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6977
6978 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
6979 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
6980 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
6981 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
6982 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
6983 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
6984 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
6985 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
6986 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
6987 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
6988 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
6989 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
6990 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
6991 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
6992 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
6993 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
6994 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
6995 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
6996 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
6997 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
6998 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
6999 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7000 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7001
7002 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7003 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7004
7005 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7006 {
7007 /* The old positions in the FIFO, not required. */
7008 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7009 }
7010 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7011 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7012 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7013 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7014
7015 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7016 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7017
7018 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7019 {
7020 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7021 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7022 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7023 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7024 }
7025 else if (pThis->ahciPort[i].fATAPI)
7026 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
7027
7028 /* Check if we have tasks pending. */
7029 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7030 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7031
7032 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7033
7034 if (pAhciPort->u32TasksNew)
7035 {
7036 /*
7037 * There are tasks pending. The VM was saved after a task failed
7038 * because of non-fatal error. Set the redo flag.
7039 */
7040 pAhciPort->fRedo = true;
7041 }
7042 }
7043
7044 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7045 {
7046 for (uint32_t i = 0; i < 2; i++)
7047 {
7048 rc = ahciR3LoadLegacyEmulationState(pSSM);
7049 if(RT_FAILURE(rc))
7050 return rc;
7051 }
7052 }
7053
7054 rc = SSMR3GetU32(pSSM, &u32);
7055 if (RT_FAILURE(rc))
7056 return rc;
7057 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7058 }
7059
7060 return VINF_SUCCESS;
7061}
7062
7063/* -=-=-=-=- device PDM interface -=-=-=-=- */
7064
7065static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7066{
7067 uint32_t i;
7068 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7069
7070 pAhci->pDevInsRC += offDelta;
7071 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7072 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7073
7074 /* Relocate every port. */
7075 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7076 {
7077 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7078 pAhciPort->pAhciRC += offDelta;
7079 pAhciPort->pDevInsRC += offDelta;
7080 }
7081}
7082
7083/**
7084 * Destroy a driver instance.
7085 *
7086 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
7087 * resources can be freed correctly.
7088 *
7089 * @param pDevIns The device instance data.
7090 */
7091static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
7092{
7093 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7094 int rc = VINF_SUCCESS;
7095 unsigned iActPort = 0;
7096 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
7097
7098 /*
7099 * At this point the async I/O thread is suspended and will not enter
7100 * this module again. So, no coordination is needed here and PDM
7101 * will take care of terminating and cleaning up the thread.
7102 */
7103 if (PDMCritSectIsInitialized(&pAhci->lock))
7104 {
7105 TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
7106
7107 Log(("%s: Destruct every port\n", __FUNCTION__));
7108 for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
7109 {
7110 PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
7111
7112 if (pAhciPort->pAsyncIOThread)
7113 {
7114 /* Destroy the event semaphore. */
7115 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
7116 if (RT_FAILURE(rc))
7117 {
7118 Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
7119 }
7120 }
7121
7122 /* Free all cached tasks. */
7123 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
7124 {
7125 if (pAhciPort->aCachedTasks[i])
7126 RTMemFree(pAhciPort->aCachedTasks[i]);
7127 }
7128 }
7129
7130 PDMR3CritSectDelete(&pAhci->lock);
7131 }
7132
7133 return rc;
7134}
7135
7136/**
7137 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7138 * from now on, regardless if there was a medium inserted or not.
7139 */
7140static void ahciMediumRemoved(PAHCIPort pAhciPort)
7141{
7142 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7143}
7144
7145
7146/**
7147 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7148 * there was already a medium inserted, don't forget to send the "medium
7149 * removed" event first.
7150 */
7151static void ahciMediumInserted(PAHCIPort pAhciPort)
7152{
7153 uint32_t OldStatus, NewStatus;
7154 do
7155 {
7156 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7157 switch (OldStatus)
7158 {
7159 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7160 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7161 /* no change, we will send "medium removed" + "medium inserted" */
7162 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7163 break;
7164 default:
7165 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7166 break;
7167 }
7168 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7169}
7170
7171/**
7172 * Called when a media is mounted.
7173 *
7174 * @param pInterface Pointer to the interface structure containing the called function pointer.
7175 */
7176static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
7177{
7178 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7179 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7180
7181 /* Ignore the call if we're called while being attached. */
7182 if (!pAhciPort->pDrvBlock)
7183 return;
7184
7185 if (pAhciPort->fATAPI)
7186 {
7187 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7188
7189 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7190
7191 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7192 if (pAhciPort->cNotifiedMediaChange < 2)
7193 pAhciPort->cNotifiedMediaChange = 2;
7194 ahciMediumInserted(pAhciPort);
7195 ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7196 }
7197 else
7198 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7199}
7200
7201/**
7202 * Called when a media is unmounted
7203 * @param pInterface Pointer to the interface structure containing the called function pointer.
7204 */
7205static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7206{
7207 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7208 Log(("%s:\n", __FUNCTION__));
7209
7210 pAhciPort->cTotalSectors = 0;
7211
7212 if (pAhciPort->fATAPI)
7213 {
7214 /*
7215 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7216 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7217 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7218 * present and 2 in which it is changed.
7219 */
7220 pAhciPort->cNotifiedMediaChange = 4;
7221 ahciMediumRemoved(pAhciPort);
7222 ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7223 }
7224 else
7225 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7226}
7227
7228/**
7229 * Configure the attached device for a port.
7230 *
7231 * Used by ahciR3Construct and ahciR3Attach.
7232 *
7233 * @returns VBox status code
7234 * @param pDevIns The device instance data.
7235 * @param pAhciPort The port for which the device is to be configured.
7236 */
7237static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7238{
7239 int rc = VINF_SUCCESS;
7240 PDMBLOCKTYPE enmType;
7241
7242 /*
7243 * Query the block and blockbios interfaces.
7244 */
7245 pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
7246 if (!pAhciPort->pDrvBlock)
7247 {
7248 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
7249 return VERR_PDM_MISSING_INTERFACE;
7250 }
7251 pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
7252 if (!pAhciPort->pDrvBlockBios)
7253 {
7254 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
7255 return VERR_PDM_MISSING_INTERFACE;
7256 }
7257
7258 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7259
7260 /* Try to get the optional async block interface. */
7261 pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
7262
7263 /*
7264 * Validate type.
7265 */
7266 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
7267
7268 if ( enmType != PDMBLOCKTYPE_HARD_DISK
7269 && enmType != PDMBLOCKTYPE_CDROM
7270 && enmType != PDMBLOCKTYPE_DVD)
7271 {
7272 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
7273 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
7274 }
7275
7276 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
7277 && !pAhciPort->pDrvMount)
7278 {
7279 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
7280 return VERR_INTERNAL_ERROR;
7281 }
7282 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
7283 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
7284
7285 if (pAhciPort->fATAPI)
7286 {
7287 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7288 pAhciPort->PCHSGeometry.cCylinders = 0;
7289 pAhciPort->PCHSGeometry.cHeads = 0;
7290 pAhciPort->PCHSGeometry.cSectors = 0;
7291 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7292 }
7293 else
7294 {
7295 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
7296 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
7297 &pAhciPort->PCHSGeometry);
7298 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7299 {
7300 pAhciPort->PCHSGeometry.cCylinders = 0;
7301 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7302 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7303 }
7304 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7305 {
7306 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7307 rc = VINF_SUCCESS;
7308 }
7309 AssertRC(rc);
7310
7311 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7312 || pAhciPort->PCHSGeometry.cHeads == 0
7313 || pAhciPort->PCHSGeometry.cSectors == 0)
7314 {
7315 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7316 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7317 pAhciPort->PCHSGeometry.cHeads = 16;
7318 pAhciPort->PCHSGeometry.cSectors = 63;
7319 /* Set the disk geometry information. Ignore errors. */
7320 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
7321 &pAhciPort->PCHSGeometry);
7322 rc = VINF_SUCCESS;
7323 }
7324 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7325 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7326 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7327 pAhciPort->cTotalSectors));
7328 if (pAhciPort->pDrvBlock->pfnDiscard)
7329 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7330 }
7331 return rc;
7332}
7333
7334/**
7335 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7336 *
7337 * @returns true if we've quiesced, false if we're still working.
7338 * @param pDevIns The device instance.
7339 */
7340static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7341{
7342 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7343 return false;
7344
7345 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7346 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7347 return true;
7348}
7349
7350/**
7351 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7352 */
7353static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7354{
7355 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7356
7357 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7358 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7359 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7360 else
7361 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7362}
7363
7364/**
7365 * Suspend notification.
7366 *
7367 * @param pDevIns The device instance data.
7368 */
7369static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7370{
7371 Log(("ahciR3Suspend\n"));
7372 ahciR3SuspendOrPowerOff(pDevIns);
7373}
7374
7375/**
7376 * Resume notification.
7377 *
7378 * @param pDevIns The device instance data.
7379 */
7380static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7381{
7382 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7383
7384 /*
7385 * Check if one of the ports has pending tasks.
7386 * Queue a notification item again in this case.
7387 */
7388 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7389 {
7390 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7391
7392 if (pAhciPort->u32TasksNew)
7393 {
7394 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7395 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7396
7397 Assert(pAhciPort->fRedo);
7398 pAhciPort->fRedo = false;
7399
7400 pItem->iPort = pAhci->ahciPort[i].iLUN;
7401 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7402 }
7403 }
7404
7405 Log(("%s:\n", __FUNCTION__));
7406}
7407
7408/**
7409 * Initializes the VPD data of a attached device.
7410 *
7411 * @returns VBox status code.
7412 * @param pDevIns The device instance.
7413 * @param pAhciPort The attached device.
7414 * @param szName Name of the port to get the CFGM node.
7415 */
7416static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7417{
7418 int rc = VINF_SUCCESS;
7419 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7420
7421 /* Generate a default serial number. */
7422 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7423 RTUUID Uuid;
7424
7425 if (pAhciPort->pDrvBlock)
7426 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
7427 else
7428 RTUuidClear(&Uuid);
7429
7430 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7431 {
7432 /* Generate a predictable serial for drives which don't have a UUID. */
7433 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7434 pAhciPort->iLUN);
7435 }
7436 else
7437 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7438
7439 /* Get user config if present using defaults otherwise. */
7440 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7441 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7442 szSerial);
7443 if (RT_FAILURE(rc))
7444 {
7445 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7446 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7447 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7448 return PDMDEV_SET_ERROR(pDevIns, rc,
7449 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7450 }
7451
7452 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7453 "1.0");
7454 if (RT_FAILURE(rc))
7455 {
7456 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7457 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7458 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7459 return PDMDEV_SET_ERROR(pDevIns, rc,
7460 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7461 }
7462
7463 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7464 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7465 if (RT_FAILURE(rc))
7466 {
7467 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7468 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7469 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7470 return PDMDEV_SET_ERROR(pDevIns, rc,
7471 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7472 }
7473
7474 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7475 if (RT_FAILURE(rc))
7476 return PDMDEV_SET_ERROR(pDevIns, rc,
7477 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7478
7479 /* There are three other identification strings for CD drives used for INQUIRY */
7480 if (pAhciPort->fATAPI)
7481 {
7482 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7483 "VBOX");
7484 if (RT_FAILURE(rc))
7485 {
7486 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7487 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7488 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7489 return PDMDEV_SET_ERROR(pDevIns, rc,
7490 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7491 }
7492
7493 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7494 "CD-ROM");
7495 if (RT_FAILURE(rc))
7496 {
7497 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7498 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7499 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7500 return PDMDEV_SET_ERROR(pDevIns, rc,
7501 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7502 }
7503
7504 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7505 "1.0");
7506 if (RT_FAILURE(rc))
7507 {
7508 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7509 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7510 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7511 return PDMDEV_SET_ERROR(pDevIns, rc,
7512 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7513 }
7514 }
7515
7516 return rc;
7517}
7518
7519
7520/**
7521 * Detach notification.
7522 *
7523 * One harddisk at one port has been unplugged.
7524 * The VM is suspended at this point.
7525 *
7526 * @param pDevIns The device instance.
7527 * @param iLUN The logical unit which is being detached.
7528 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7529 */
7530static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7531{
7532 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7533 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7534 int rc = VINF_SUCCESS;
7535
7536 Log(("%s:\n", __FUNCTION__));
7537
7538 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7539
7540 if (!pAhciPort->fAsyncInterface)
7541 {
7542 int rcThread;
7543 /* Destroy the thread. */
7544 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
7545 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
7546 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
7547
7548 pAhciPort->pAsyncIOThread = NULL;
7549
7550 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
7551 if (RT_FAILURE(rc))
7552 AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
7553 }
7554
7555 if (pAhciPort->fATAPI)
7556 ahciMediumRemoved(pAhciPort);
7557
7558 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7559 {
7560 /*
7561 * Inform the guest about the removed device.
7562 */
7563 pAhciPort->regSSTS = 0;
7564 /*
7565 * Clear CR bit too to prevent submission of new commands when CI is written
7566 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
7567 */
7568 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
7569 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
7570 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_N);
7571 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7572 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7573 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7574 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7575 }
7576
7577 /*
7578 * Zero some important members.
7579 */
7580 pAhciPort->pDrvBase = NULL;
7581 pAhciPort->pDrvBlock = NULL;
7582 pAhciPort->pDrvBlockAsync = NULL;
7583 pAhciPort->pDrvBlockBios = NULL;
7584}
7585
7586/**
7587 * Attach command.
7588 *
7589 * This is called when we change block driver for one port.
7590 * The VM is suspended at this point.
7591 *
7592 * @returns VBox status code.
7593 * @param pDevIns The device instance.
7594 * @param iLUN The logical unit which is being detached.
7595 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7596 */
7597static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7598{
7599 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7600 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7601 int rc;
7602
7603 Log(("%s:\n", __FUNCTION__));
7604
7605 /* the usual paranoia */
7606 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7607 AssertRelease(!pAhciPort->pDrvBase);
7608 AssertRelease(!pAhciPort->pDrvBlock);
7609 AssertRelease(!pAhciPort->pDrvBlockAsync);
7610 Assert(pAhciPort->iLUN == iLUN);
7611
7612 /*
7613 * Try attach the block device and get the interfaces,
7614 * required as well as optional.
7615 */
7616 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
7617 if (RT_SUCCESS(rc))
7618 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
7619 else
7620 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
7621
7622 if (RT_FAILURE(rc))
7623 {
7624 pAhciPort->pDrvBase = NULL;
7625 pAhciPort->pDrvBlock = NULL;
7626 }
7627 else
7628 {
7629 char szName[24];
7630 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
7631
7632 if ( pAhciPort->pDrvBlockAsync
7633 && !pAhciPort->fATAPI)
7634 pAhciPort->fAsyncInterface = true;
7635 else
7636 {
7637 pAhciPort->fAsyncInterface = false;
7638
7639 /* Create event semaphore. */
7640 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
7641 if (RT_FAILURE(rc))
7642 {
7643 Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
7644 return rc;
7645 }
7646
7647 /* Create the async IO thread. */
7648 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
7649 RTTHREADTYPE_IO, szName);
7650 if (RT_FAILURE(rc))
7651 {
7652 AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
7653 return rc;
7654 }
7655 }
7656
7657 /*
7658 * Init vendor product data.
7659 */
7660 if (RT_SUCCESS(rc))
7661 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
7662
7663 /* Inform the guest about the added device in case of hotplugging. */
7664 if ( RT_SUCCESS(rc)
7665 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7666 {
7667 /*
7668 * Initialize registers
7669 */
7670 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
7671 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7672 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7673
7674 if (pAhciPort->fATAPI)
7675 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
7676 else
7677 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
7678 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
7679 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
7680 (0x03 << 0); /* Device detected and communication established. */
7681
7682 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7683 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7684 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7685 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7686 }
7687
7688 }
7689
7690 return rc;
7691}
7692
7693/**
7694 * Common reset worker.
7695 *
7696 * @param pDevIns The device instance data.
7697 */
7698static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
7699{
7700 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7701
7702 ahciHBAReset(pAhci);
7703
7704 /* Hardware reset for the ports. */
7705 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7706 ahciPortHwReset(&pAhci->ahciPort[i]);
7707 return VINF_SUCCESS;
7708}
7709
7710/**
7711 * Callback employed by ahciR3Reset.
7712 *
7713 * @returns true if we've quiesced, false if we're still working.
7714 * @param pDevIns The device instance.
7715 */
7716static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
7717{
7718 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7719
7720 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7721 return false;
7722 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7723
7724 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7725 return true;
7726}
7727
7728/**
7729 * Reset notification.
7730 *
7731 * @param pDevIns The device instance data.
7732 */
7733static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
7734{
7735 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7736
7737 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7738 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7739 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
7740 else
7741 {
7742 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7743 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7744 }
7745}
7746
7747/**
7748 * Poweroff notification.
7749 *
7750 * @param pDevIns Pointer to the device instance
7751 */
7752static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
7753{
7754 Log(("achiR3PowerOff\n"));
7755 ahciR3SuspendOrPowerOff(pDevIns);
7756}
7757
7758/**
7759 * @interface_method_impl{PDMDEVREG,pfnConstruct}
7760 */
7761static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
7762{
7763 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7764 PPDMIBASE pBase;
7765 int rc = VINF_SUCCESS;
7766 unsigned i = 0;
7767 bool fGCEnabled = false;
7768 bool fR0Enabled = false;
7769 uint32_t cbTotalBufferSize = 0;
7770 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
7771
7772 LogFlowFunc(("pThis=%#p\n", pThis));
7773
7774 /*
7775 * Validate and read configuration.
7776 */
7777 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
7778 "R0Enabled\0"
7779 "PrimaryMaster\0"
7780 "PrimarySlave\0"
7781 "SecondaryMaster\0"
7782 "SecondarySlave\0"
7783 "PortCount\0"
7784 "UseAsyncInterfaceIfAvailable\0"
7785 "Bootable\0"
7786 "CmdSlotsAvail\0"))
7787 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
7788 N_("AHCI configuration error: unknown option specified"));
7789
7790 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
7791 if (RT_FAILURE(rc))
7792 return PDMDEV_SET_ERROR(pDevIns, rc,
7793 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
7794 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
7795
7796 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
7797 if (RT_FAILURE(rc))
7798 return PDMDEV_SET_ERROR(pDevIns, rc,
7799 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
7800 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
7801
7802 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
7803 if (RT_FAILURE(rc))
7804 return PDMDEV_SET_ERROR(pDevIns, rc,
7805 N_("AHCI configuration error: failed to read PortCount as integer"));
7806 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
7807 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
7808 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
7809 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
7810 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
7811 if (pThis->cPortsImpl < 1)
7812 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
7813 N_("AHCI configuration error: PortCount=%u should be at least 1"),
7814 pThis->cPortsImpl);
7815
7816 rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
7817 if (RT_FAILURE(rc))
7818 return PDMDEV_SET_ERROR(pDevIns, rc,
7819 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
7820
7821 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
7822 if (RT_FAILURE(rc))
7823 return PDMDEV_SET_ERROR(pDevIns, rc,
7824 N_("AHCI configuration error: failed to read Bootable as boolean"));
7825
7826 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
7827 if (RT_FAILURE(rc))
7828 return PDMDEV_SET_ERROR(pDevIns, rc,
7829 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
7830 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
7831 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
7832 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
7833 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
7834 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
7835 if (pThis->cCmdSlotsAvail < 1)
7836 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
7837 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
7838 pThis->cCmdSlotsAvail);
7839
7840 pThis->fR0Enabled = fR0Enabled;
7841 pThis->fGCEnabled = fGCEnabled;
7842 pThis->pDevInsR3 = pDevIns;
7843 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
7844 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7845
7846 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
7847 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
7848 PCIDevSetCommand (&pThis->dev, 0x0000);
7849#ifdef VBOX_WITH_MSI_DEVICES
7850 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
7851 PCIDevSetCapabilityList(&pThis->dev, 0x80);
7852#else
7853 PCIDevSetCapabilityList(&pThis->dev, 0x70);
7854#endif
7855 PCIDevSetRevisionId (&pThis->dev, 0x02);
7856 PCIDevSetClassProg (&pThis->dev, 0x01);
7857 PCIDevSetClassSub (&pThis->dev, 0x06);
7858 PCIDevSetClassBase (&pThis->dev, 0x01);
7859 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
7860
7861 PCIDevSetInterruptLine(&pThis->dev, 0x00);
7862 PCIDevSetInterruptPin (&pThis->dev, 0x01);
7863
7864 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
7865 pThis->dev.config[0x71] = 0xa8; /* next */
7866 pThis->dev.config[0x72] = 0x03; /* version ? */
7867
7868 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
7869 pThis->dev.config[0x92] = 0x3f;
7870 pThis->dev.config[0x94] = 0x80;
7871 pThis->dev.config[0x95] = 0x01;
7872 pThis->dev.config[0x97] = 0x78;
7873
7874 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
7875 pThis->dev.config[0xa9] = 0x00; /* next */
7876 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
7877 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
7878
7879 /*
7880 * Register the PCI device, it's I/O regions.
7881 */
7882 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
7883 if (RT_FAILURE(rc))
7884 return rc;
7885
7886#ifdef VBOX_WITH_MSI_DEVICES
7887 PDMMSIREG aMsiReg;
7888
7889 RT_ZERO(aMsiReg);
7890 aMsiReg.cMsiVectors = 1;
7891 aMsiReg.iMsiCapOffset = 0x80;
7892 aMsiReg.iMsiNextOffset = 0x70;
7893 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg);
7894 if (RT_FAILURE (rc))
7895 {
7896 LogRel(("Chipset cannot do MSI: %Rrc\n", rc));
7897 PCIDevSetCapabilityList(&pThis->dev, 0x70);
7898 /* That's OK, we can work without MSI */
7899 }
7900#endif
7901
7902 /*
7903 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
7904 * IDE registers are not available.
7905 * We set up "fake" entries in the PCI configuration register.
7906 * That means they are available but read and writes from/to them have no effect.
7907 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
7908 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
7909 * to switch to it which also changes device Id and other things in the PCI configuration space).
7910 */
7911 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
7912 if (RT_FAILURE(rc))
7913 return PDMDEV_SET_ERROR(pDevIns, rc,
7914 N_("AHCI cannot register PCI I/O region"));
7915
7916 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
7917 if (RT_FAILURE(rc))
7918 return PDMDEV_SET_ERROR(pDevIns, rc,
7919 N_("AHCI cannot register PCI I/O region"));
7920
7921 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
7922 if (RT_FAILURE(rc))
7923 return PDMDEV_SET_ERROR(pDevIns, rc,
7924 N_("AHCI cannot register PCI I/O region"));
7925
7926 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
7927 if (RT_FAILURE(rc))
7928 return PDMDEV_SET_ERROR(pDevIns, rc,
7929 N_("AHCI cannot register PCI I/O region"));
7930
7931 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
7932 if (RT_FAILURE(rc))
7933 return PDMDEV_SET_ERROR(pDevIns, rc,
7934 N_("AHCI cannot register PCI I/O region for BMDMA"));
7935
7936 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
7937 if (RT_FAILURE(rc))
7938 return PDMDEV_SET_ERROR(pDevIns, rc,
7939 N_("AHCI cannot register PCI memory region for registers"));
7940
7941 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
7942 if (RT_FAILURE(rc))
7943 {
7944 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
7945 return rc;
7946 }
7947
7948 /* Create the timer for command completion coalescing feature. */
7949 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
7950 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
7951 if (RT_FAILURE(rc))
7952 {
7953 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
7954 return rc;
7955 }
7956 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
7957 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
7958
7959 /* Status LUN. */
7960 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
7961 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
7962
7963 /*
7964 * Create the notification queue.
7965 *
7966 * We need 2 items for every port because of SMP races.
7967 */
7968 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL*2, 0,
7969 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
7970 if (RT_FAILURE(rc))
7971 return rc;
7972 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
7973 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
7974
7975 /* Initialize static members on every port. */
7976 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7977 {
7978 /*
7979 * Init members of the port.
7980 */
7981 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7982 pAhciPort->pDevInsR3 = pDevIns;
7983 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
7984 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
7985 pAhciPort->iLUN = i;
7986 pAhciPort->pAhciR3 = pThis;
7987 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
7988 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
7989 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
7990 pAhciPort->pDrvBase = NULL;
7991
7992 /* Register statistics counter. */
7993 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
7994 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
7995 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
7996 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
7997 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
7998 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
7999 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8000 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8001#ifdef VBOX_WITH_STATISTICS
8002 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8003 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8004 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8005 "Amount of time to map the guest buffers into R3.", "/Devices/SATA%d/Port%d/ProfileMapIntoR3", iInstance, i);
8006 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8007 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8008 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8009 "Amount of time to destroy the scatter gather list and free associated resources.", "/Devices/SATA%d/Port%d/ProfileDestroyScatterGatherList", iInstance, i);
8010#endif
8011
8012 ahciPortHwReset(pAhciPort);
8013 }
8014
8015 /* Attach drivers to every available port. */
8016 for (i = 0; i < pThis->cPortsImpl; i++)
8017 {
8018 char szName[24];
8019 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8020
8021 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8022 /*
8023 * Init interfaces.
8024 */
8025 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8026 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciTransferCompleteNotify;
8027 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8028 pAhciPort->IMountNotify.pfnMountNotify = ahciMountNotify;
8029 pAhciPort->IMountNotify.pfnUnmountNotify = ahciUnmountNotify;
8030 pAhciPort->fAsyncIOThreadIdle = true;
8031
8032 /*
8033 * Attach the block driver
8034 */
8035 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8036 if (RT_SUCCESS(rc))
8037 {
8038 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8039 if (RT_FAILURE(rc))
8040 {
8041 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8042 return rc;
8043 }
8044
8045 /* Mark that a device is present on that port */
8046 if (i < 6)
8047 pThis->dev.config[0x93] |= (1 << i);
8048
8049 /*
8050 * Init vendor product data.
8051 */
8052 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8053 if (RT_FAILURE(rc))
8054 return rc;
8055
8056 /*
8057 * If the new async interface is available we use a PDMQueue to transmit
8058 * the requests into R3.
8059 * Otherwise we use a event semaphore and a async I/O thread which processes them.
8060 */
8061 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
8062 {
8063 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
8064 pAhciPort->fAsyncInterface = true;
8065 }
8066 else
8067 {
8068 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
8069 pAhciPort->fAsyncInterface = false;
8070
8071 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
8072 AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
8073
8074
8075 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
8076 RTTHREADTYPE_IO, szName);
8077 AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
8078 }
8079 }
8080 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8081 {
8082 pAhciPort->pDrvBase = NULL;
8083 rc = VINF_SUCCESS;
8084 LogRel(("%s: no driver attached\n", szName));
8085 }
8086 else
8087 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8088 N_("AHCI: Failed to attach drive to %s"), szName);
8089 }
8090
8091 /*
8092 * Attach status driver (optional).
8093 */
8094 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8095 if (RT_SUCCESS(rc))
8096 {
8097 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8098 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8099 }
8100 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8101 {
8102 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8103 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8104 }
8105 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
8106 NULL, ahciR3LiveExec, NULL,
8107 ahciR3SavePrep, ahciR3SaveExec, NULL,
8108 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8109 if (RT_FAILURE(rc))
8110 return rc;
8111
8112 /*
8113 * Register the info item.
8114 */
8115 char szTmp[128];
8116 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8117 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8118
8119 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8120}
8121
8122/**
8123 * The device registration structure.
8124 */
8125const PDMDEVREG g_DeviceAHCI =
8126{
8127 /* u32Version */
8128 PDM_DEVREG_VERSION,
8129 /* szName */
8130 "ahci",
8131 /* szRCMod */
8132 "VBoxDDGC.gc",
8133 /* szR0Mod */
8134 "VBoxDDR0.r0",
8135 /* pszDescription */
8136 "Intel AHCI controller.\n",
8137 /* fFlags */
8138 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8139 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
8140 /* fClass */
8141 PDM_DEVREG_CLASS_STORAGE,
8142 /* cMaxInstances */
8143 ~0U,
8144 /* cbInstance */
8145 sizeof(AHCI),
8146 /* pfnConstruct */
8147 ahciR3Construct,
8148 /* pfnDestruct */
8149 ahciR3Destruct,
8150 /* pfnRelocate */
8151 ahciR3Relocate,
8152 /* pfnIOCtl */
8153 NULL,
8154 /* pfnPowerOn */
8155 NULL,
8156 /* pfnReset */
8157 ahciR3Reset,
8158 /* pfnSuspend */
8159 ahciR3Suspend,
8160 /* pfnResume */
8161 ahciR3Resume,
8162 /* pfnAttach */
8163 ahciR3Attach,
8164 /* pfnDetach */
8165 ahciR3Detach,
8166 /* pfnQueryInterface. */
8167 NULL,
8168 /* pfnInitComplete */
8169 NULL,
8170 /* pfnPowerOff */
8171 ahciR3PowerOff,
8172 /* pfnSoftReset */
8173 NULL,
8174 /* u32VersionEnd */
8175 PDM_DEVREG_VERSION
8176};
8177
8178#endif /* IN_RING3 */
8179#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