VirtualBox

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

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

AHCI: Fix compatibility with saved states from previous versions

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