VirtualBox

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

Last change on this file since 30714 was 30382, checked in by vboxsync, 15 years ago

SATA: Always raise an interrupt after task completion; delaying this (interrupt coalescing) increases latency and has a significant
impact on performance (see #5071)

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette