VirtualBox

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

Last change on this file since 56690 was 56676, checked in by vboxsync, 9 years ago

Storage/AHCI: Fix assertion which can trigger erroneously after r100611 in rare circumstances. Also make it only log the assertion in release builds but don't abort the VM

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