VirtualBox

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

Last change on this file since 64001 was 64001, checked in by vboxsync, 8 years ago

AHCI: alignment fix for x86

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