VirtualBox

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

Last change on this file since 36235 was 35560, checked in by vboxsync, 14 years ago

PDM: introduced fEject parameter to PDMIMOUNT::pfnUnmount which is false if we don't need to eject the medium during unmount

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