VirtualBox

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

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

AHCI: Report errors of completed requests to the guest (not tested yet)

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