VirtualBox

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

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

AHCI: DTrace fix

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