VirtualBox

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

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

AHCI: Fix STAM alignment

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