VirtualBox

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

Last change on this file since 33000 was 32957, checked in by vboxsync, 14 years ago

AHCI: Implement SuspendOnError to give the user a chance to fix certain errors like broken iSCSI connections.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use