VirtualBox

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

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

DevAHCI: async suspend, reset and power off handling for the SATA part.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 277.2 KB
Line 
1/* $Id: DevAHCI.cpp 24749 2009-11-18 00:32:14Z 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[4];
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) ahciMMIOMap(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) ahciLegacyFakeIORangeMap(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) ahciStatus_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 *) ahciStatus_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 *) ahciPortQueryInterface(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
2411static DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2412{
2413 uint32_t i;
2414 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2415
2416 pAhci->pDevInsRC += offDelta;
2417 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
2418 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
2419
2420 /* Relocate every port. */
2421 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
2422 {
2423 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
2424 pAhciPort->pAhciRC += offDelta;
2425 pAhciPort->pDevInsRC += offDelta;
2426 }
2427
2428 /* Relocate emulated ATA controllers. */
2429 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
2430 ataControllerRelocate(&pAhci->aCts[i], offDelta);
2431}
2432
2433#ifdef DEBUG
2434
2435/**
2436 * Dump info about the FIS
2437 *
2438 * @returns nothing
2439 * @param pAhciPort The port the command FIS was read from.
2440 * @param cmdFis The FIS to print info from.
2441 */
2442static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2443{
2444 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2445 /* Print FIS type. */
2446 switch (cmdFis[AHCI_CMDFIS_TYPE])
2447 {
2448 case AHCI_CMDFIS_TYPE_H2D:
2449 {
2450 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2451 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2452 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2453 {
2454 ahciLog(("%s: Command register update\n", __FUNCTION__));
2455 }
2456 else
2457 {
2458 ahciLog(("%s: Control register update\n", __FUNCTION__));
2459 }
2460 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2461 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2462 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2463 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2464 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2465 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2466
2467 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2468 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2469 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2470 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2471
2472 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2473 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2474 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2475 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2476 {
2477 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2478 }
2479 }
2480 break;
2481 case AHCI_CMDFIS_TYPE_D2H:
2482 {
2483 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2484 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2485 }
2486 break;
2487 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2488 {
2489 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2490 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2491 }
2492 break;
2493 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2494 {
2495 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2496 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2497 }
2498 break;
2499 case AHCI_CMDFIS_TYPE_DMASETUP:
2500 {
2501 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2502 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2503 }
2504 break;
2505 case AHCI_CMDFIS_TYPE_PIOSETUP:
2506 {
2507 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2508 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2509 }
2510 break;
2511 case AHCI_CMDFIS_TYPE_DATA:
2512 {
2513 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2514 }
2515 break;
2516 default:
2517 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2518 break;
2519 }
2520 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2521}
2522
2523/**
2524 * Dump info about the command header
2525 *
2526 * @returns nothing
2527 * @param pAhciPort Poitner to the port the command header was read from.
2528 * @param pCmdHdr The command header to print info from.
2529 */
2530static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2531{
2532 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2533 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2534 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2535 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2536 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2537 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2538 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2539 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2540 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2541 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2542 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2543 ahciLog(("%s: Device write\n", __FUNCTION__));
2544 else
2545 ahciLog(("%s: Device read\n", __FUNCTION__));
2546 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2547 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2548 else
2549 ahciLog(("%s: ATA command\n", __FUNCTION__));
2550
2551 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2552 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2553}
2554#endif /* DEBUG */
2555
2556/**
2557 * Post the first D2H FIS from the device into guest memory.
2558 *
2559 * @returns nothing
2560 * @param pAhciPort Pointer to the port which "receives" the FIS.
2561 */
2562static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2563{
2564 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2565
2566 pAhciPort->fFirstD2HFisSend = true;
2567
2568 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2569 memset(&d2hFis[0], 0, sizeof(d2hFis));
2570 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2571 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2572
2573 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2574
2575 /* Set the signature based on the device type. */
2576 if (pAhciPort->fATAPI)
2577 {
2578 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2579 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2580 }
2581 else
2582 {
2583 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2584 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2585 }
2586
2587 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2588 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2589 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2590
2591 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2592
2593 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2594}
2595
2596/**
2597 * Post the FIS in the memory area allocated by the guest and set interrupt if neccessary.
2598 *
2599 * @returns VBox status code
2600 * @param pAhciPort The port which "receives" the FIS.
2601 * @param uFisType The type of the FIS.
2602 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2603 */
2604static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2605{
2606 int rc = VINF_SUCCESS;
2607 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2608 unsigned cbFis = 0;
2609
2610 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2611
2612 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2613 {
2614 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2615
2616 /* Determine the offset and size of the FIS based on uFisType. */
2617 switch (uFisType)
2618 {
2619 case AHCI_CMDFIS_TYPE_D2H:
2620 {
2621 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2622 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2623 }
2624 break;
2625 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2626 {
2627 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2628 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2629 }
2630 break;
2631 case AHCI_CMDFIS_TYPE_DMASETUP:
2632 {
2633 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2634 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2635 }
2636 break;
2637 case AHCI_CMDFIS_TYPE_PIOSETUP:
2638 {
2639 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2640 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2641 }
2642 break;
2643 default:
2644 /*
2645 * We should post the unknown FIS into memory too but this never happens because
2646 * we know which FIS types we generate. ;)
2647 */
2648 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2649 }
2650
2651 /* Post the FIS into memory. */
2652 ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2653 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2654 }
2655
2656 return rc;
2657}
2658
2659DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2660{
2661 pbBuf[0] = val >> 8;
2662 pbBuf[1] = val;
2663}
2664
2665
2666DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2667{
2668 pbBuf[0] = val >> 16;
2669 pbBuf[1] = val >> 8;
2670 pbBuf[2] = val;
2671}
2672
2673
2674DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2675{
2676 pbBuf[0] = val >> 24;
2677 pbBuf[1] = val >> 16;
2678 pbBuf[2] = val >> 8;
2679 pbBuf[3] = val;
2680}
2681
2682
2683DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2684{
2685 return (pbBuf[0] << 8) | pbBuf[1];
2686}
2687
2688
2689DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2690{
2691 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2692}
2693
2694
2695DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2696{
2697 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2698}
2699
2700
2701DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2702{
2703 iATAPILBA += 150;
2704 pbBuf[0] = (iATAPILBA / 75) / 60;
2705 pbBuf[1] = (iATAPILBA / 75) % 60;
2706 pbBuf[2] = iATAPILBA % 75;
2707}
2708
2709
2710DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2711{
2712 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2713}
2714
2715static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
2716{
2717 pAhciPortTaskState->uATARegError = 0;
2718 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2719 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2720 | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
2721 | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2722 pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
2723 pAhciPort->uATAPIASC = SCSI_ASC_NONE;
2724}
2725
2726
2727static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
2728{
2729 pAhciPortTaskState->uATARegError = uATAPISenseKey << 4;
2730 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
2731 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2732 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2733 pAhciPort->uATAPISenseKey = uATAPISenseKey;
2734 pAhciPort->uATAPIASC = uATAPIASC;
2735}
2736
2737static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2738{
2739 for (uint32_t i = 0; i < cbSize; i++)
2740 {
2741 if (*pbSrc)
2742 pbDst[i] = *pbSrc++;
2743 else
2744 pbDst[i] = ' ';
2745 }
2746}
2747
2748static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2749{
2750 for (uint32_t i = 0; i < cbSize; i++)
2751 {
2752 if (*pbSrc)
2753 pbDst[i ^ 1] = *pbSrc++;
2754 else
2755 pbDst[i ^ 1] = ' ';
2756 }
2757}
2758
2759static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
2760{
2761 uint16_t *p;
2762 int rc = VINF_SUCCESS;
2763
2764 p = (uint16_t *)pvBuf;
2765 memset(p, 0, 512);
2766 p[0] = RT_H2LE_U16(0x0040);
2767 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2768 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2769 /* Block size; obsolete, but required for the BIOS. */
2770 p[5] = RT_H2LE_U16(512);
2771 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2772 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2773 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2774 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2775 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
2776 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2777 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2778#if ATA_MAX_MULT_SECTORS > 1
2779 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
2780#endif
2781 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
2782 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2783 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2784 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2785 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2786 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
2787 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2788 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2789 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2790 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
2791 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
2792 if (pAhciPort->cMultSectors)
2793 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
2794 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
2795 {
2796 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2797 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2798 }
2799 else
2800 {
2801 /* Report maximum number of sectors possible with LBA28 */
2802 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
2803 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
2804 }
2805 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2806 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2807 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2808 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2809 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2810 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2811 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2812 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2813 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
2814 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2815 p[84] = RT_H2LE_U16(1 << 14);
2816 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
2817 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2818 p[87] = RT_H2LE_U16(1 << 14);
2819 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2820 p[93] = RT_H2LE_U16(0x00);
2821 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2822 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2823 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
2824 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
2825
2826 /* The following are SATA specific */
2827 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2828 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2829
2830 return VINF_SUCCESS;
2831}
2832
2833typedef int (*PAtapiFunc)(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2834
2835static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2836static int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2837static int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2838static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2839static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2840static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2841static int atapiReadCapacitySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2842static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2843static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2844static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2845static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2846static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2847static int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2848//static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2849
2850/**
2851 * Source/sink function indexes for g_apfnAtapiFuncs.
2852 */
2853typedef enum ATAPIFN
2854{
2855 ATAFN_SS_NULL = 0,
2856 ATAFN_SS_ATAPI_GET_CONFIGURATION,
2857 ATAFN_SS_ATAPI_IDENTIFY,
2858 ATAFN_SS_ATAPI_INQUIRY,
2859 ATAFN_SS_ATAPI_MECHANISM_STATUS,
2860 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
2861 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
2862 ATAFN_SS_ATAPI_READ_CAPACITY,
2863 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
2864 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
2865 ATAFN_SS_ATAPI_READ_TOC_MULTI,
2866 ATAFN_SS_ATAPI_READ_TOC_RAW,
2867 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
2868 ATAFN_SS_ATAPI_REQUEST_SENSE,
2869 //ATAFN_SS_ATAPI_PASSTHROUGH,
2870 ATAFN_SS_MAX
2871} ATAPIFN;
2872
2873/**
2874 * Array of source/sink functions, the index is ATAFNSS.
2875 * Make sure ATAFNSS and this array match!
2876 */
2877static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
2878{
2879 NULL,
2880 atapiGetConfigurationSS,
2881 atapiIdentifySS,
2882 atapiInquirySS,
2883 atapiMechanismStatusSS,
2884 atapiModeSenseErrorRecoverySS,
2885 atapiModeSenseCDStatusSS,
2886 atapiReadCapacitySS,
2887 atapiReadDiscInformationSS,
2888 atapiReadTOCNormalSS,
2889 atapiReadTOCMultiSS,
2890 atapiReadTOCRawSS,
2891 atapiReadTrackInformationSS,
2892 atapiRequestSenseSS
2893 //atapiPassthroughSS
2894};
2895
2896static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2897{
2898 uint16_t p[256];
2899 RTUUID Uuid;
2900 int rc;
2901
2902 memset(p, 0, 512);
2903 /* Removable CDROM, 50us response, 12 byte packets */
2904 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
2905 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2906 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2907 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2908 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2909 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2910 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2911 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2912 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2913 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2914 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
2915 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2916 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2917 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2918 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2919 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2920 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2921 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
2922 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
2923 p[75] = RT_H2LE_U16(1); /* queue depth 1 */
2924 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2925 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2926 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
2927 p[83] = RT_H2LE_U16(1 << 14);
2928 p[84] = RT_H2LE_U16(1 << 14);
2929 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
2930 p[86] = RT_H2LE_U16(0);
2931 p[87] = RT_H2LE_U16(1 << 14);
2932 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2933 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
2934
2935 /* The following are SATA specific */
2936 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2937 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2938
2939 /* Copy the buffer in to the scatter gather list. */
2940 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
2941
2942 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2943 return VINF_SUCCESS;
2944}
2945
2946static int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2947{
2948 uint8_t aBuf[8];
2949
2950 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
2951 ataH2BE_U32(aBuf + 4, 2048);
2952
2953 /* Copy the buffer in to the scatter gather list. */
2954 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2955
2956 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2957 return VINF_SUCCESS;
2958}
2959
2960
2961static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2962{
2963 uint8_t aBuf[34];
2964
2965 memset(aBuf, '\0', 34);
2966 ataH2BE_U16(aBuf, 32);
2967 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
2968 aBuf[3] = 1; /* number of first track */
2969 aBuf[4] = 1; /* number of sessions (LSB) */
2970 aBuf[5] = 1; /* first track number in last session (LSB) */
2971 aBuf[6] = 1; /* last track number in last session (LSB) */
2972 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 */
2973 aBuf[8] = 0; /* disc type = CD-ROM */
2974 aBuf[9] = 0; /* number of sessions (MSB) */
2975 aBuf[10] = 0; /* number of sessions (MSB) */
2976 aBuf[11] = 0; /* number of sessions (MSB) */
2977 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
2978 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
2979
2980 /* Copy the buffer in to the scatter gather list. */
2981 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2982
2983 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2984 return VINF_SUCCESS;
2985}
2986
2987
2988static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2989{
2990 uint8_t aBuf[36];
2991
2992 /* Accept address/number type of 1 only, and only track 1 exists. */
2993 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
2994 {
2995 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2996 return VINF_SUCCESS;
2997 }
2998 memset(aBuf, '\0', 36);
2999 ataH2BE_U16(aBuf, 34);
3000 aBuf[2] = 1; /* track number (LSB) */
3001 aBuf[3] = 1; /* session number (LSB) */
3002 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
3003 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 */
3004 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
3005 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
3006 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
3007 aBuf[32] = 0; /* track number (MSB) */
3008 aBuf[33] = 0; /* session number (MSB) */
3009
3010 /* Copy the buffer in to the scatter gather list. */
3011 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3012
3013 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3014 return VINF_SUCCESS;
3015}
3016
3017
3018static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3019{
3020 uint8_t aBuf[32];
3021
3022 /* Accept valid request types only, and only starting feature 0. */
3023 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
3024 {
3025 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3026 return VINF_SUCCESS;
3027 }
3028 memset(aBuf, '\0', 32);
3029 ataH2BE_U32(aBuf, 16);
3030 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3031 * way to differentiate them right now is based on the image size). Also
3032 * implement signalling "no current profile" if no medium is loaded. */
3033 ataH2BE_U16(aBuf + 6, 0x08); /* current profile: read-only CD */
3034
3035 ataH2BE_U16(aBuf + 8, 0); /* feature 0: list of profiles supported */
3036 aBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
3037 aBuf[11] = 8; /* additional bytes for profiles */
3038 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3039 * before CD-ROM read capability. */
3040 ataH2BE_U16(aBuf + 12, 0x10); /* profile: read-only DVD */
3041 aBuf[14] = (0 << 0); /* NOT current profile */
3042 ataH2BE_U16(aBuf + 16, 0x08); /* profile: read only CD */
3043 aBuf[18] = (1 << 0); /* current profile */
3044
3045 /* Copy the buffer in to the scatter gather list. */
3046 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3047
3048 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3049 return VINF_SUCCESS;
3050}
3051
3052
3053static int atapiInquirySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3054{
3055 uint8_t aBuf[36];
3056
3057 aBuf[0] = 0x05; /* CD-ROM */
3058 aBuf[1] = 0x80; /* removable */
3059 aBuf[2] = 0x00; /* ISO */
3060 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3061 aBuf[4] = 31; /* additional length */
3062 aBuf[5] = 0; /* reserved */
3063 aBuf[6] = 0; /* reserved */
3064 aBuf[7] = 0; /* reserved */
3065 ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
3066 ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
3067 ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
3068
3069 /* Copy the buffer in to the scatter gather list. */
3070 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3071
3072 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3073 return VINF_SUCCESS;
3074}
3075
3076
3077static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3078{
3079 uint8_t aBuf[16];
3080
3081 ataH2BE_U16(&aBuf[0], 16 + 6);
3082 aBuf[2] = 0x70;
3083 aBuf[3] = 0;
3084 aBuf[4] = 0;
3085 aBuf[5] = 0;
3086 aBuf[6] = 0;
3087 aBuf[7] = 0;
3088
3089 aBuf[8] = 0x01;
3090 aBuf[9] = 0x06;
3091 aBuf[10] = 0x00;
3092 aBuf[11] = 0x05;
3093 aBuf[12] = 0x00;
3094 aBuf[13] = 0x00;
3095 aBuf[14] = 0x00;
3096 aBuf[15] = 0x00;
3097
3098 /* Copy the buffer in to the scatter gather list. */
3099 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3100
3101 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3102 return VINF_SUCCESS;
3103}
3104
3105
3106static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3107{
3108 uint8_t aBuf[40];
3109
3110 ataH2BE_U16(&aBuf[0], 38);
3111 aBuf[2] = 0x70;
3112 aBuf[3] = 0;
3113 aBuf[4] = 0;
3114 aBuf[5] = 0;
3115 aBuf[6] = 0;
3116 aBuf[7] = 0;
3117
3118 aBuf[8] = 0x2a;
3119 aBuf[9] = 30; /* page length */
3120 aBuf[10] = 0x08; /* DVD-ROM read support */
3121 aBuf[11] = 0x00; /* no write support */
3122 /* The following claims we support audio play. This is obviously false,
3123 * but the Linux generic CDROM support makes many features depend on this
3124 * capability. If it's not set, this causes many things to be disabled. */
3125 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3126 aBuf[13] = 0x00; /* no subchannel reads supported */
3127 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3128 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3129 aBuf[14] |= 1 << 1; /* report lock state */
3130 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3131 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3132 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3133 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3134 Just write the value DevATA is using. */
3135 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3136 aBuf[24] = 0; /* reserved */
3137 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3138 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3139 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3140 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3141 aBuf[32] = 0; /* reserved */
3142 aBuf[33] = 0; /* reserved */
3143 aBuf[34] = 0; /* reserved */
3144 aBuf[35] = 1; /* rotation control CAV */
3145 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3146 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3147
3148 /* Copy the buffer in to the scatter gather list. */
3149 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3150
3151 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3152 return VINF_SUCCESS;
3153}
3154
3155
3156static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3157{
3158 uint8_t aBuf[18];
3159
3160 memset(&aBuf[0], 0, 18);
3161 aBuf[0] = 0x70 | (1 << 7);
3162 aBuf[2] = pAhciPort->uATAPISenseKey;
3163 aBuf[7] = 10;
3164 aBuf[12] = pAhciPort->uATAPIASC;
3165
3166 /* Copy the buffer in to the scatter gather list. */
3167 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3168
3169 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3170 return VINF_SUCCESS;
3171}
3172
3173
3174static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3175{
3176 uint8_t aBuf[8];
3177
3178 ataH2BE_U16(&aBuf[0], 0);
3179 /* no current LBA */
3180 aBuf[2] = 0;
3181 aBuf[3] = 0;
3182 aBuf[4] = 0;
3183 aBuf[5] = 1;
3184 ataH2BE_U16(aBuf + 6, 0);
3185
3186 /* Copy the buffer in to the scatter gather list. */
3187 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3188
3189 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3190 return VINF_SUCCESS;
3191}
3192
3193
3194static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3195{
3196 uint8_t aBuf[20], *q, iStartTrack;
3197 bool fMSF;
3198 uint32_t cbSize;
3199
3200 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3201 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3202 if (iStartTrack > 1 && iStartTrack != 0xaa)
3203 {
3204 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3205 return VINF_SUCCESS;
3206 }
3207 q = aBuf + 2;
3208 *q++ = 1; /* first session */
3209 *q++ = 1; /* last session */
3210 if (iStartTrack <= 1)
3211 {
3212 *q++ = 0; /* reserved */
3213 *q++ = 0x14; /* ADR, control */
3214 *q++ = 1; /* track number */
3215 *q++ = 0; /* reserved */
3216 if (fMSF)
3217 {
3218 *q++ = 0; /* reserved */
3219 ataLBA2MSF(q, 0);
3220 q += 3;
3221 }
3222 else
3223 {
3224 /* sector 0 */
3225 ataH2BE_U32(q, 0);
3226 q += 4;
3227 }
3228 }
3229 /* lead out track */
3230 *q++ = 0; /* reserved */
3231 *q++ = 0x14; /* ADR, control */
3232 *q++ = 0xaa; /* track number */
3233 *q++ = 0; /* reserved */
3234 if (fMSF)
3235 {
3236 *q++ = 0; /* reserved */
3237 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3238 q += 3;
3239 }
3240 else
3241 {
3242 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3243 q += 4;
3244 }
3245 cbSize = q - aBuf;
3246 ataH2BE_U16(aBuf, cbSize - 2);
3247
3248 /* Copy the buffer in to the scatter gather list. */
3249 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3250
3251 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3252 return VINF_SUCCESS;
3253}
3254
3255
3256static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3257{
3258 uint8_t aBuf[12];
3259 bool fMSF;
3260
3261 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3262 /* multi session: only a single session defined */
3263/** @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. */
3264 memset(aBuf, 0, 12);
3265 aBuf[1] = 0x0a;
3266 aBuf[2] = 0x01;
3267 aBuf[3] = 0x01;
3268 aBuf[5] = 0x14; /* ADR, control */
3269 aBuf[6] = 1; /* first track in last complete session */
3270 if (fMSF)
3271 {
3272 aBuf[8] = 0; /* reserved */
3273 ataLBA2MSF(&aBuf[9], 0);
3274 }
3275 else
3276 {
3277 /* sector 0 */
3278 ataH2BE_U32(aBuf + 8, 0);
3279 }
3280
3281 /* Copy the buffer in to the scatter gather list. */
3282 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3283
3284 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3285 return VINF_SUCCESS;
3286}
3287
3288
3289static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3290{
3291 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3292 uint8_t *q, iStartTrack;
3293 bool fMSF;
3294 uint32_t cbSize;
3295
3296 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3297 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3298
3299 q = aBuf + 2;
3300 *q++ = 1; /* first session */
3301 *q++ = 1; /* last session */
3302
3303 *q++ = 1; /* session number */
3304 *q++ = 0x14; /* data track */
3305 *q++ = 0; /* track number */
3306 *q++ = 0xa0; /* first track in program area */
3307 *q++ = 0; /* min */
3308 *q++ = 0; /* sec */
3309 *q++ = 0; /* frame */
3310 *q++ = 0;
3311 *q++ = 1; /* first track */
3312 *q++ = 0x00; /* disk type CD-DA or CD data */
3313 *q++ = 0;
3314
3315 *q++ = 1; /* session number */
3316 *q++ = 0x14; /* data track */
3317 *q++ = 0; /* track number */
3318 *q++ = 0xa1; /* last track in program area */
3319 *q++ = 0; /* min */
3320 *q++ = 0; /* sec */
3321 *q++ = 0; /* frame */
3322 *q++ = 0;
3323 *q++ = 1; /* last track */
3324 *q++ = 0;
3325 *q++ = 0;
3326
3327 *q++ = 1; /* session number */
3328 *q++ = 0x14; /* data track */
3329 *q++ = 0; /* track number */
3330 *q++ = 0xa2; /* lead-out */
3331 *q++ = 0; /* min */
3332 *q++ = 0; /* sec */
3333 *q++ = 0; /* frame */
3334 if (fMSF)
3335 {
3336 *q++ = 0; /* reserved */
3337 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3338 q += 3;
3339 }
3340 else
3341 {
3342 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3343 q += 4;
3344 }
3345
3346 *q++ = 1; /* session number */
3347 *q++ = 0x14; /* ADR, control */
3348 *q++ = 0; /* track number */
3349 *q++ = 1; /* point */
3350 *q++ = 0; /* min */
3351 *q++ = 0; /* sec */
3352 *q++ = 0; /* frame */
3353 if (fMSF)
3354 {
3355 *q++ = 0; /* reserved */
3356 ataLBA2MSF(q, 0);
3357 q += 3;
3358 }
3359 else
3360 {
3361 /* sector 0 */
3362 ataH2BE_U32(q, 0);
3363 q += 4;
3364 }
3365
3366 cbSize = q - aBuf;
3367 ataH2BE_U16(aBuf, cbSize - 2);
3368
3369 /* Copy the buffer in to the scatter gather list. */
3370 *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3371
3372 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3373 return VINF_SUCCESS;
3374}
3375
3376static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
3377{
3378 int cbTransfered;
3379 int rc, rcSourceSink;
3380
3381 /*
3382 * Create scatter gather list. We use a safe mapping here because it is
3383 * possible that the buffer is not a multiple of 512. The normal
3384 * creator would assert later here.
3385 */
3386 ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
3387 rc = ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, false, 0);
3388 AssertRC(rc);
3389
3390 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
3391
3392 pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
3393
3394 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
3395 AssertRC(rc);
3396
3397 /* Write updated command header into memory of the guest. */
3398 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
3399
3400 return rcSourceSink;
3401}
3402
3403static int atapiReadSectors2352PostProcess(PAHCIPORTTASKSTATE pAhciPortTaskState)
3404{
3405 uint32_t cSectors = pAhciPortTaskState->cbTransfer / 2048;
3406 uint32_t iATAPILBA = pAhciPortTaskState->uOffset / 2048;
3407 uint8_t *pbBufDst = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
3408 uint8_t *pbBufSrc = (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg;
3409
3410 for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
3411 {
3412 /* sync bytes */
3413 *pbBufDst++ = 0x00;
3414 memset(pbBufDst, 0xff, 11);
3415 pbBufDst += 11;
3416 /* MSF */
3417 ataLBA2MSF(pbBufDst, i);
3418 pbBufDst += 3;
3419 *pbBufDst++ = 0x01; /* mode 1 data */
3420 /* data */
3421 memcpy(pbBufDst, pbBufSrc, 2048);
3422 pbBufDst += 2048;
3423 pbBufSrc += 2048;
3424 /* ECC */
3425 memset(pbBufDst, 0, 288);
3426 pbBufDst += 288;
3427 }
3428
3429 return VINF_SUCCESS;
3430}
3431
3432static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
3433{
3434 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
3435
3436 switch (cbSector)
3437 {
3438 case 2048:
3439 pAhciPortTaskState->uOffset = iATAPILBA * cbSector;
3440 pAhciPortTaskState->cbTransfer = cSectors * cbSector;
3441 break;
3442 case 2352:
3443 {
3444 pAhciPortTaskState->pfnPostProcess = atapiReadSectors2352PostProcess;
3445 pAhciPortTaskState->uOffset = iATAPILBA * 2048;
3446 pAhciPortTaskState->cbTransfer = cSectors * 2048;
3447 break;
3448 }
3449 default:
3450 AssertMsgFailed(("Unsupported sectors size\n"));
3451 break;
3452 }
3453
3454 return VINF_SUCCESS;
3455}
3456
3457static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3458{
3459 int rc = PDMBLOCKTXDIR_NONE;
3460 const uint8_t *pbPacket;
3461 uint32_t cbMax;
3462
3463 pbPacket = pAhciPortTaskState->aATAPICmd;
3464
3465 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
3466
3467 switch (pbPacket[0])
3468 {
3469 case SCSI_TEST_UNIT_READY:
3470 if (pAhciPort->cNotifiedMediaChange > 0)
3471 {
3472 if (pAhciPort->cNotifiedMediaChange-- > 2)
3473 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3474 else
3475 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3476 }
3477 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3478 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3479 else
3480 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3481 break;
3482 case SCSI_MODE_SENSE_10:
3483 {
3484 uint8_t uPageControl, uPageCode;
3485 cbMax = ataBE2H_U16(pbPacket + 7);
3486 uPageControl = pbPacket[2] >> 6;
3487 uPageCode = pbPacket[2] & 0x3f;
3488 switch (uPageControl)
3489 {
3490 case SCSI_PAGECONTROL_CURRENT:
3491 switch (uPageCode)
3492 {
3493 case SCSI_MODEPAGE_ERROR_RECOVERY:
3494 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
3495 break;
3496 case SCSI_MODEPAGE_CD_STATUS:
3497 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
3498 break;
3499 default:
3500 goto error_cmd;
3501 }
3502 break;
3503 case SCSI_PAGECONTROL_CHANGEABLE:
3504 goto error_cmd;
3505 case SCSI_PAGECONTROL_DEFAULT:
3506 goto error_cmd;
3507 default:
3508 case SCSI_PAGECONTROL_SAVED:
3509 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
3510 break;
3511 }
3512 }
3513 break;
3514 case SCSI_REQUEST_SENSE:
3515 cbMax = pbPacket[4];
3516 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_REQUEST_SENSE);
3517 break;
3518 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
3519 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3520 {
3521 if (pbPacket[4] & 1)
3522 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
3523 else
3524 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
3525 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3526 }
3527 else
3528 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3529 break;
3530 case SCSI_READ_10:
3531 case SCSI_READ_12:
3532 {
3533 uint32_t cSectors, iATAPILBA;
3534
3535 if (pAhciPort->cNotifiedMediaChange > 0)
3536 {
3537 pAhciPort->cNotifiedMediaChange-- ;
3538 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3539 break;
3540 }
3541 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3542 {
3543 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3544 break;
3545 }
3546 if (pbPacket[0] == SCSI_READ_10)
3547 cSectors = ataBE2H_U16(pbPacket + 7);
3548 else
3549 cSectors = ataBE2H_U32(pbPacket + 6);
3550 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3551 if (cSectors == 0)
3552 {
3553 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3554 break;
3555 }
3556 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3557 {
3558 /* Rate limited logging, one log line per second. For
3559 * guests that insist on reading from places outside the
3560 * valid area this often generates too many release log
3561 * entries otherwise. */
3562 static uint64_t uLastLogTS = 0;
3563 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3564 {
3565 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3566 uLastLogTS = RTTimeMilliTS();
3567 }
3568 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3569 break;
3570 }
3571 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3572 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3573 }
3574 break;
3575 case SCSI_READ_CD:
3576 {
3577 uint32_t cSectors, iATAPILBA;
3578
3579 if (pAhciPort->cNotifiedMediaChange > 0)
3580 {
3581 pAhciPort->cNotifiedMediaChange-- ;
3582 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3583 break;
3584 }
3585 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3586 {
3587 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3588 break;
3589 }
3590 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
3591 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3592 if (cSectors == 0)
3593 {
3594 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3595 break;
3596 }
3597 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3598 {
3599 /* Rate limited logging, one log line per second. For
3600 * guests that insist on reading from places outside the
3601 * valid area this often generates too many release log
3602 * entries otherwise. */
3603 static uint64_t uLastLogTS = 0;
3604 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3605 {
3606 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3607 uLastLogTS = RTTimeMilliTS();
3608 }
3609 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3610 break;
3611 }
3612 switch (pbPacket[9] & 0xf8)
3613 {
3614 case 0x00:
3615 /* nothing */
3616 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3617 break;
3618 case 0x10:
3619 /* normal read */
3620 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3621 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3622 break;
3623 case 0xf8:
3624 /* read all data */
3625 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
3626 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3627 break;
3628 default:
3629 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
3630 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3631 break;
3632 }
3633 }
3634 break;
3635 case SCSI_SEEK_10:
3636 {
3637 uint32_t iATAPILBA;
3638 if (pAhciPort->cNotifiedMediaChange > 0)
3639 {
3640 pAhciPort->cNotifiedMediaChange-- ;
3641 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3642 break;
3643 }
3644 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3645 {
3646 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3647 break;
3648 }
3649 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3650 if (iATAPILBA > pAhciPort->cTotalSectors)
3651 {
3652 /* Rate limited logging, one log line per second. For
3653 * guests that insist on seeking to places outside the
3654 * valid area this often generates too many release log
3655 * entries otherwise. */
3656 static uint64_t uLastLogTS = 0;
3657 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3658 {
3659 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
3660 uLastLogTS = RTTimeMilliTS();
3661 }
3662 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3663 break;
3664 }
3665 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3666 pAhciPortTaskState->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
3667 }
3668 break;
3669 case SCSI_START_STOP_UNIT:
3670 {
3671 int rc = VINF_SUCCESS;
3672 switch (pbPacket[4] & 3)
3673 {
3674 case 0: /* 00 - Stop motor */
3675 case 1: /* 01 - Start motor */
3676 break;
3677 case 2: /* 10 - Eject media */
3678 /* This must be done from EMT. */
3679 {
3680 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3681 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
3682
3683 rc = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
3684 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
3685 Assert(RT_SUCCESS(rc) || (rc == VERR_PDM_MEDIA_LOCKED));
3686 }
3687 break;
3688 case 3: /* 11 - Load media */
3689 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
3690 break;
3691 }
3692 if (RT_SUCCESS(rc))
3693 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3694 else
3695 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
3696 }
3697 break;
3698 case SCSI_MECHANISM_STATUS:
3699 {
3700 cbMax = ataBE2H_U16(pbPacket + 8);
3701 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MECHANISM_STATUS);
3702 }
3703 break;
3704 case SCSI_READ_TOC_PMA_ATIP:
3705 {
3706 uint8_t format;
3707
3708 if (pAhciPort->cNotifiedMediaChange > 0)
3709 {
3710 pAhciPort->cNotifiedMediaChange-- ;
3711 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3712 break;
3713 }
3714 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3715 {
3716 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3717 break;
3718 }
3719 cbMax = ataBE2H_U16(pbPacket + 7);
3720 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
3721 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
3722 * the other field is clear... */
3723 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
3724 switch (format)
3725 {
3726 case 0:
3727 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
3728 break;
3729 case 1:
3730 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_MULTI);
3731 break;
3732 case 2:
3733 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_RAW);
3734 break;
3735 default:
3736 error_cmd:
3737 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3738 break;
3739 }
3740 }
3741 break;
3742 case SCSI_READ_CAPACITY:
3743 if (pAhciPort->cNotifiedMediaChange > 0)
3744 {
3745 pAhciPort->cNotifiedMediaChange-- ;
3746 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3747 break;
3748 }
3749 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3750 {
3751 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3752 break;
3753 }
3754 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_CAPACITY);
3755 break;
3756 case SCSI_READ_DISC_INFORMATION:
3757 if (pAhciPort->cNotifiedMediaChange > 0)
3758 {
3759 pAhciPort->cNotifiedMediaChange-- ;
3760 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3761 break;
3762 }
3763 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3764 {
3765 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3766 break;
3767 }
3768 cbMax = ataBE2H_U16(pbPacket + 7);
3769 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
3770 break;
3771 case SCSI_READ_TRACK_INFORMATION:
3772 if (pAhciPort->cNotifiedMediaChange > 0)
3773 {
3774 pAhciPort->cNotifiedMediaChange-- ;
3775 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3776 break;
3777 }
3778 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3779 {
3780 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3781 break;
3782 }
3783 cbMax = ataBE2H_U16(pbPacket + 7);
3784 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
3785 break;
3786 case SCSI_GET_CONFIGURATION:
3787 /* No media change stuff here, it can confuse Linux guests. */
3788 cbMax = ataBE2H_U16(pbPacket + 7);
3789 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_CONFIGURATION);
3790 break;
3791 case SCSI_INQUIRY:
3792 cbMax = pbPacket[4];
3793 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_INQUIRY);
3794 break;
3795 default:
3796 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
3797 break;
3798 }
3799
3800 return rc;
3801}
3802
3803/**
3804 * Reset all values after a reset of the attached storage device.
3805 *
3806 * @returns nothing
3807 * @param pAhciPort The port the device is attached to.
3808 * @param pAhciPortTaskState The state to get the tag number from.
3809 */
3810static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3811{
3812 /* Send a status good D2H FIS. */
3813 pAhciPort->fResetDevice = false;
3814 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3815 ahciPostFirstD2HFisIntoMemory(pAhciPort);
3816
3817 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
3818 pAhciPort->regSIG = 0x101;
3819 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3820
3821 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
3822}
3823
3824/**
3825 * Build a D2H FIS and post into the memory area of the guest.
3826 *
3827 * @returns Nothing
3828 * @param pAhciPort The port of the SATA controller.
3829 * @param pAhciPortTaskState The state of the task.
3830 * @param pCmdFis Pointer to the command FIS from the guest.
3831 * @param fInterrupt If an interrupt should be send to the guest.
3832 */
3833static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis, bool fInterrupt)
3834{
3835 uint8_t d2hFis[20];
3836 bool fAssertIntr = false;
3837 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3838
3839 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
3840
3841 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3842 {
3843 memset(&d2hFis[0], 0, sizeof(d2hFis));
3844 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
3845 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3846 d2hFis[AHCI_CMDFIS_STS] = pAhciPortTaskState->uATARegStatus;
3847 d2hFis[AHCI_CMDFIS_ERR] = pAhciPortTaskState->uATARegError;
3848 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3849 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3850 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3851 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3852 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3853 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3854 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3855 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3856 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3857
3858 /* Update registers. */
3859 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3860
3861 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
3862
3863 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3864 {
3865 /* Error bit is set. */
3866 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3867 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3868 fAssertIntr = true;
3869 }
3870
3871 if (fInterrupt)
3872 {
3873 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
3874 /* Check if we should assert an interrupt */
3875 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
3876 fAssertIntr = true;
3877 }
3878
3879 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3880
3881 if (fAssertIntr)
3882 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3883 }
3884}
3885
3886/**
3887 * Build a SDB Fis and post it into the memory area of the guest.
3888 *
3889 * @returns Nothing
3890 * @param pAhciPort The port for which the SDB Fis is send.
3891 * @param uFinishedTasks Bitmask of finished tasks.
3892 * @param pAhciPortTaskState The state of the last task.
3893 * @param fInterrupt If an interrupt should be asserted.
3894 */
3895static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
3896{
3897 uint32_t sdbFis[2];
3898 bool fAssertIntr = false;
3899 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3900
3901 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3902
3903 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3904 {
3905 memset(&sdbFis[0], 0, sizeof(sdbFis));
3906 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3907 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3908 sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3909 sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3910 sdbFis[1] = uFinishedTasks;
3911
3912 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3913
3914 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3915 {
3916 /* Error bit is set. */
3917 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3918 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3919 fAssertIntr = true;
3920 }
3921
3922 if (fInterrupt)
3923 {
3924 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
3925 /* Check if we should assert an interrupt */
3926 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
3927 fAssertIntr = true;
3928 }
3929
3930 /* Update registers. */
3931 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3932
3933 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3934
3935 if (fAssertIntr)
3936 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3937 }
3938}
3939
3940static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
3941{
3942 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
3943 if (fLBA48)
3944 {
3945 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
3946 return 65536;
3947 else
3948 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
3949 }
3950 else
3951 {
3952 if (!pCmdFis[AHCI_CMDFIS_SECTC])
3953 return 256;
3954 else
3955 return pCmdFis[AHCI_CMDFIS_SECTC];
3956 }
3957}
3958
3959static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
3960{
3961 uint64_t iLBA;
3962 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
3963 {
3964 /* any LBA variant */
3965 if (fLBA48)
3966 {
3967 /* LBA48 */
3968 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3969 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3970 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3971 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3972 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3973 pCmdFis[AHCI_CMDFIS_SECTN];
3974 }
3975 else
3976 {
3977 /* LBA */
3978 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3979 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
3980 }
3981 }
3982 else
3983 {
3984 /* CHS */
3985 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
3986 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
3987 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
3988 }
3989 return iLBA;
3990}
3991
3992static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
3993{
3994 uint64_t uLBA;
3995
3996 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3997 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3998 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3999 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
4000 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
4001 pCmdFis[AHCI_CMDFIS_SECTN];
4002
4003 return uLBA;
4004}
4005
4006DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
4007{
4008 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
4009 return 65536;
4010 else
4011 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
4012}
4013
4014DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
4015{
4016 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
4017}
4018
4019static void ahciScatterGatherListGetTotalBufferSize(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4020{
4021 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4022 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4023 unsigned cActualSGEntry;
4024 SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
4025 unsigned cSGLEntriesGCRead;
4026 unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
4027 RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
4028 uint32_t cbSGBuffers = 0; /* Total number of bytes reserved for this request. */
4029
4030 /* Retrieve the total number of bytes reserved for this request. */
4031 cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4032 ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
4033
4034 /* Set start address of the entries. */
4035 GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4036
4037 do
4038 {
4039 cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
4040 cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4041
4042 /* Read the SG entries. */
4043 PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4044
4045 for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
4046 cbSGBuffers += (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4047
4048 /* Set address to the next entries to read. */
4049 GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
4050
4051 } while (cSGLEntriesGCLeft);
4052
4053 pAhciPortTaskState->cbSGBuffers = cbSGBuffers;
4054}
4055
4056static int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
4057{
4058 if (pAhciPortTaskState->cSGListSize < cSGList)
4059 {
4060 /* The entries are not allocated yet or the number is too small. */
4061 if (pAhciPortTaskState->cSGListSize)
4062 {
4063 RTMemFree(pAhciPortTaskState->pSGListHead);
4064 RTMemFree(pAhciPortTaskState->paSGEntries);
4065 }
4066
4067 /* Allocate R3 scatter gather list. */
4068 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
4069 if (!pAhciPortTaskState->pSGListHead)
4070 return VERR_NO_MEMORY;
4071
4072 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
4073 if (!pAhciPortTaskState->paSGEntries)
4074 return VERR_NO_MEMORY;
4075
4076 /* Reset usage statistics. */
4077 pAhciPortTaskState->cSGListSize = cSGList;
4078 pAhciPortTaskState->cSGListTooBig = 0;
4079 }
4080 else if (pAhciPortTaskState->cSGListSize > cSGList)
4081 {
4082 /*
4083 * The list is too big. Increment counter.
4084 * So that the destroying function can free
4085 * the list if it is too big too many times
4086 * in a row.
4087 */
4088 pAhciPortTaskState->cSGListTooBig++;
4089 }
4090 else
4091 {
4092 /*
4093 * Needed entries matches current size.
4094 * Reset counter.
4095 */
4096 pAhciPortTaskState->cSGListTooBig = 0;
4097 }
4098
4099 pAhciPortTaskState->cSGEntries = cSGList;
4100
4101 if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4102 {
4103 if (pAhciPortTaskState->pvBufferUnaligned)
4104 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4105
4106 Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4107
4108 pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
4109 if (!pAhciPortTaskState->pvBufferUnaligned)
4110 return VERR_NO_MEMORY;
4111
4112 pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
4113 }
4114
4115 /* Make debugging easier. */
4116#ifdef DEBUG
4117 memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
4118 memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4119 if (pAhciPortTaskState->pvBufferUnaligned)
4120 memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4121#endif
4122
4123 return VINF_SUCCESS;
4124}
4125
4126/**
4127 * Fallback scatter gather list creator.
4128 * Used if the normal one fails in PDMDevHlpPhysGCPhys2CCPtr() or
4129 * PDMDevHlpPhysGCPhys2CCPtrReadonly() or post processing
4130 * is used.
4131 *
4132 * returns VBox status code.
4133 * @param pAhciPort The ahci port.
4134 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4135 * @param fReadonly If the mappings should be readonly.
4136 * @param cSGEntriesProcessed Number of entries the normal creator procecssed
4137 * before an error occurred. Used to free
4138 * any ressources allocated before.
4139 * @thread EMT
4140 */
4141static int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
4142 bool fReadonly, unsigned cSGEntriesProcessed)
4143{
4144 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4145 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4146 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4147
4148 Assert(VALID_PTR(pAhciPortTaskState->pSGListHead) || !cSGEntriesProcessed);
4149 Assert(VALID_PTR(pAhciPortTaskState->paSGEntries) || !cSGEntriesProcessed);
4150
4151 for (unsigned cSGEntryCurr = 0; cSGEntryCurr < cSGEntriesProcessed; cSGEntryCurr++)
4152 {
4153 if (pSGInfoCurr->fGuestMemory)
4154 {
4155 /* Release the lock. */
4156 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4157 }
4158
4159 /* Go to the next entry. */
4160 pSGInfoCurr++;
4161 }
4162
4163 if (pAhciPortTaskState->pvBufferUnaligned)
4164 {
4165 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4166 pAhciPortTaskState->pvBufferUnaligned = NULL;
4167 }
4168 if (pAhciPortTaskState->pSGListHead)
4169 {
4170 RTMemFree(pAhciPortTaskState->pSGListHead);
4171 pAhciPortTaskState->pSGListHead = NULL;
4172 }
4173 if (pAhciPortTaskState->paSGEntries)
4174 {
4175 RTMemFree(pAhciPortTaskState->paSGEntries);
4176 pAhciPortTaskState->paSGEntries = NULL;
4177 }
4178 pAhciPortTaskState->cSGListTooBig = 0;
4179 pAhciPortTaskState->cSGEntries = 1;
4180 pAhciPortTaskState->cSGListUsed = 1;
4181 pAhciPortTaskState->cSGListSize = 1;
4182 pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbSGBuffers;
4183
4184 /* Allocate new buffers and SG lists. */
4185 pAhciPortTaskState->pvBufferUnaligned = RTMemAlloc(pAhciPortTaskState->cbSGBuffers);
4186 if (!pAhciPortTaskState->pvBufferUnaligned)
4187 return VERR_NO_MEMORY;
4188
4189 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(1 * sizeof(PDMDATASEG));
4190 if (!pAhciPortTaskState->pSGListHead)
4191 {
4192 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4193 return VERR_NO_MEMORY;
4194 }
4195
4196 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
4197 if (!pAhciPortTaskState->paSGEntries)
4198 {
4199 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4200 RTMemFree(pAhciPortTaskState->pSGListHead);
4201 return VERR_NO_MEMORY;
4202 }
4203
4204 /* Set pointers. */
4205 if (pAhciPortTaskState->cbTransfer)
4206 {
4207 pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbTransfer;
4208
4209 /* Allocate a separate buffer if we have to do post processing . */
4210 if (pAhciPortTaskState->pfnPostProcess)
4211 {
4212 pAhciPortTaskState->pSGListHead[0].pvSeg = RTMemAlloc(pAhciPortTaskState->cbTransfer);
4213 if (!pAhciPortTaskState->pSGListHead[0].pvSeg)
4214 {
4215 RTMemFree(pAhciPortTaskState->paSGEntries);
4216 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4217 RTMemFree(pAhciPortTaskState->pSGListHead);
4218 return VERR_NO_MEMORY;
4219 }
4220 }
4221 else
4222 pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4223 }
4224 else
4225 {
4226 pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbBufferUnaligned;
4227 pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4228 }
4229
4230 pAhciPortTaskState->paSGEntries[0].fGuestMemory = false;
4231 pAhciPortTaskState->paSGEntries[0].u.temp.cUnaligned = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4232 pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4233 pAhciPortTaskState->paSGEntries[0].u.temp.pvBuf = pAhciPortTaskState->pvBufferUnaligned;
4234
4235 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4236 ahciCopyFromSGListIntoBuffer(pDevIns, &pAhciPortTaskState->paSGEntries[0]);
4237
4238 return VINF_SUCCESS;
4239}
4240
4241/**
4242 * Create scatter gather list descriptors.
4243 *
4244 * @returns VBox status code.
4245 * @param pAhciPort The ahci port.
4246 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4247 * @param fReadonly If the mappings should be readonly.
4248 * @thread EMT
4249 */
4250static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly)
4251{
4252 int rc = VINF_SUCCESS;
4253 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4254 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4255 unsigned cActualSGEntry;
4256 unsigned cSGEntriesR3 = 0; /* Needed scatter gather list entries in R3. */
4257 unsigned cSGEntriesProcessed = 0; /* Number of SG entries procesed. */
4258 SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
4259 unsigned cSGLEntriesGCRead;
4260 unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
4261 RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
4262 uint32_t cbSegment; /* Size of the current segments in bytes. */
4263 bool fUnaligned; /* Flag whether the current buffer is unaligned. */
4264 uint32_t cbUnaligned; /* Size of the unaligned buffers. */
4265 uint32_t cUnaligned;
4266 bool fDoMapping = false;
4267 uint32_t cbSGBuffers = 0; /* Total number of bytes reserved for this request. */
4268 RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
4269 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
4270 PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
4271 PPDMDATASEG pSGEntryCurr = NULL;
4272 PPDMDATASEG pSGEntryPrev = NULL;
4273 RTGCPHYS GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4274 uint8_t *pu8BufferUnalignedPos = NULL;
4275 uint32_t cbUnalignedComplete = 0;
4276
4277 STAM_PROFILE_START(&pAhciPort->StatProfileMapIntoR3, a);
4278
4279 pAhciPortTaskState->cbSGBuffers = 0;
4280
4281 /*
4282 * Create a safe mapping when doing post processing because the size of the
4283 * data to transfer and the amount of guest memory reserved can differ
4284 */
4285 if (pAhciPortTaskState->pfnPostProcess)
4286 {
4287 ahciLog(("%s: Request with post processing.\n"));
4288
4289 ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
4290
4291 return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly, 0);
4292 }
4293
4294 /*
4295 * 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
4296 * page aligned. Hence the number of SG list entries in the guest can differ from the ones we need
4297 * because PDMDevHlpPhysGCPhys2CCPtr works only on a page base.
4298 * In the first pass we calculate the number of segments in R3 and in the second pass we map the guest segments into R3.
4299 */
4300 for (int i = 0; i < 2; i++)
4301 {
4302 cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4303 ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
4304
4305 /* Set start address of the entries. */
4306 GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4307 fUnaligned = false;
4308 cbUnaligned = 0;
4309 cUnaligned = 0;
4310 GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4311
4312 if (fDoMapping)
4313 {
4314 ahciLog(("%s: cSGEntriesR3=%u\n", __FUNCTION__, cSGEntriesR3));
4315 /* The number of needed SG entries in R3 is known. Allocate needed memory. */
4316 rc = ahciScatterGatherListAllocate(pAhciPortTaskState, cSGEntriesR3, cbUnalignedComplete);
4317 AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc));
4318
4319 /* We are now able to map the pages into R3. */
4320 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4321 pSGEntryCurr = pAhciPortTaskState->pSGListHead;
4322 pSGEntryPrev = pSGEntryCurr;
4323 pSGInfoPrev = pSGInfoCurr;
4324 /* Initialize first segment to remove the need for additional if checks later in the code. */
4325 pSGEntryCurr->pvSeg = NULL;
4326 pSGEntryCurr->cbSeg = 0;
4327 pSGInfoCurr->fGuestMemory= false;
4328 pu8BufferUnalignedPos = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
4329 pAhciPortTaskState->cSGListUsed = 0;
4330 pAhciPortTaskState->cbSGBuffers = cbSGBuffers;
4331 }
4332
4333 do
4334 {
4335 cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
4336 cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4337
4338 /* Read the SG entries. */
4339 PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4340
4341 for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
4342 {
4343 RTGCPHYS GCPhysAddrDataBase;
4344 uint32_t cbDataToTransfer;
4345
4346 ahciLog(("%s: cActualSGEntry=%u cSGEntriesR3=%u\n", __FUNCTION__, cActualSGEntry, cSGEntriesR3));
4347
4348 cbDataToTransfer = (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4349 ahciLog(("%s: cbDataToTransfer=%u\n", __FUNCTION__, cbDataToTransfer));
4350 cbSGBuffers += cbDataToTransfer;
4351
4352 /* Check if the buffer is sector aligned. */
4353 if (cbDataToTransfer % 512 != 0)
4354 {
4355 if (!fUnaligned)
4356 {
4357 /* We are not in an unaligned buffer but this is the first unaligned one. */
4358 fUnaligned = true;
4359 cbUnaligned = cbDataToTransfer;
4360 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4361 cSGEntriesR3++;
4362 cUnaligned = 1;
4363 ahciLog(("%s: Unaligned buffer found cb=%d\n", __FUNCTION__, cbDataToTransfer));
4364 }
4365 else
4366 {
4367 /* We are already in an unaligned buffer and this one is unaligned too. */
4368 cbUnaligned += cbDataToTransfer;
4369 cUnaligned++;
4370 }
4371
4372 cbUnalignedComplete += cbDataToTransfer;
4373 }
4374 else /* Guest segment size is sector aligned. */
4375 {
4376 if (fUnaligned)
4377 {
4378 if (cbUnaligned % 512 == 0)
4379 {
4380 /*
4381 * The last buffer started at an offset
4382 * not aligned to a sector boundary but this buffer
4383 * is sector aligned. Check if the current size of all
4384 * unaligned segments is a multiple of a sector.
4385 * If that's the case we can now map the segments again into R3.
4386 */
4387 fUnaligned = false;
4388
4389 if (fDoMapping)
4390 {
4391 /* Set up the entry. */
4392 pSGInfoCurr->fGuestMemory = false;
4393 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4394 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4395 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4396
4397 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4398 pSGEntryCurr->cbSeg = cbUnaligned;
4399 pu8BufferUnalignedPos += cbUnaligned;
4400
4401 /*
4402 * If the transfer is to the device we need to copy the content of the not mapped guest
4403 * segments into the temporary buffer.
4404 */
4405 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4406 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4407
4408 /* Advance to next entry saving the pointers to the current ones. */
4409 pSGEntryPrev = pSGEntryCurr;
4410 pSGInfoPrev = pSGInfoCurr;
4411 pSGInfoCurr++;
4412 pSGEntryCurr++;
4413 pAhciPortTaskState->cSGListUsed++;
4414 cSGEntriesProcessed++;
4415 }
4416 }
4417 else
4418 {
4419 cbUnaligned += cbDataToTransfer;
4420 cbUnalignedComplete += cbDataToTransfer;
4421 cUnaligned++;
4422 }
4423 }
4424 else
4425 {
4426 /*
4427 * The size of the guest segment is sector aligned but it is possible that the segment crosses
4428 * a page boundary in a way splitting the segment into parts which are not sector aligned.
4429 * We have to treat them like unaligned guest segments then.
4430 */
4431 GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntry[cActualSGEntry].u32DBAUp, aSGLEntry[cActualSGEntry].u32DBA);
4432
4433 ahciLog(("%s: GCPhysAddrDataBase=%RGp\n", __FUNCTION__, GCPhysAddrDataBase));
4434
4435 /*
4436 * Check if the physical address is page aligned.
4437 */
4438 if (GCPhysAddrDataBase & PAGE_OFFSET_MASK)
4439 {
4440 RTGCPHYS GCPhysAddrDataNextPage = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase) + PAGE_SIZE;
4441 /* Difference from the buffer start to the next page boundary. */
4442 uint32_t u32GCPhysAddrDiff = GCPhysAddrDataNextPage - GCPhysAddrDataBase;
4443
4444 if (u32GCPhysAddrDiff % 512 != 0)
4445 {
4446 if (!fUnaligned)
4447 {
4448 /* We are not in an unaligned buffer but this is the first unaligned one. */
4449 fUnaligned = true;
4450 cbUnaligned = cbDataToTransfer;
4451 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4452 cSGEntriesR3++;
4453 cUnaligned = 1;
4454 ahciLog(("%s: Guest segment is sector aligned but crosses a page boundary cb=%d\n", __FUNCTION__, cbDataToTransfer));
4455 }
4456 else
4457 {
4458 /* We are already in an unaligned buffer and this one is unaligned too. */
4459 cbUnaligned += cbDataToTransfer;
4460 cUnaligned++;
4461 }
4462
4463 cbUnalignedComplete += cbDataToTransfer;
4464 }
4465 else
4466 {
4467 ahciLog(("%s: Align page: GCPhysAddrDataBase=%RGp GCPhysAddrDataNextPage=%RGp\n",
4468 __FUNCTION__, GCPhysAddrDataBase, GCPhysAddrDataNextPage));
4469
4470 RTGCPHYS GCPhysBufferPageAligned = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase);
4471
4472 /* Check if the mapping ends at the page boundary and set segment size accordingly. */
4473 cbSegment = (cbDataToTransfer < u32GCPhysAddrDiff)
4474 ? cbDataToTransfer
4475 : u32GCPhysAddrDiff;
4476 /* Subtract size of the buffer in the actual page. */
4477 cbDataToTransfer -= cbSegment;
4478
4479 if (GCPhysBufferPageAlignedPrev != GCPhysBufferPageAligned)
4480 {
4481 /* We don't need to map the buffer if it is in the same page as the previous one. */
4482 if (fDoMapping)
4483 {
4484 uint8_t *pbMapping;
4485
4486 pSGInfoCurr->fGuestMemory = true;
4487
4488 /* Create the mapping. */
4489 if (fReadonly)
4490 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysBufferPageAligned,
4491 0, (const void **)&pbMapping,
4492 &pSGInfoCurr->u.direct.PageLock);
4493 else
4494 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysBufferPageAligned,
4495 0, (void **)&pbMapping,
4496 &pSGInfoCurr->u.direct.PageLock);
4497
4498 if (RT_FAILURE(rc))
4499 {
4500 /* Mapping failed. Fall back to a bounce buffer. */
4501 ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
4502 __FUNCTION__, GCPhysBufferPageAligned, rc));
4503
4504 return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
4505 cSGEntriesProcessed);
4506 }
4507
4508 if ((pbMapping + (GCPhysAddrDataBase - GCPhysBufferPageAligned) == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryCurr->cbSeg)))
4509 {
4510 pSGEntryPrev->cbSeg += cbSegment;
4511 ahciLog(("%s: Merged mapping pbMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4512 __FUNCTION__, pbMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4513 }
4514 else
4515 {
4516 pSGEntryCurr->cbSeg = cbSegment;
4517
4518 /* Let pvBuf point to the start of the buffer in the page. */
4519 pSGEntryCurr->pvSeg = pbMapping
4520 + (GCPhysAddrDataBase - GCPhysBufferPageAligned);
4521
4522 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4523 pSGEntryCurr->pvSeg,
4524 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4525
4526 pSGEntryPrev = pSGEntryCurr;
4527 pSGEntryCurr++;
4528 pAhciPortTaskState->cSGListUsed++;
4529 }
4530
4531 pSGInfoPrev = pSGInfoCurr;
4532 pSGInfoCurr++;
4533 cSGEntriesProcessed++;
4534 }
4535 else
4536 cSGEntriesR3++;
4537 }
4538 else if (fDoMapping)
4539 {
4540 pSGEntryPrev->cbSeg += cbSegment;
4541 ahciLog(("%s: Buffer is already in previous mapping pvSeg=%#p. New size is cbSeg=%d\n",
4542 __FUNCTION__, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4543 }
4544
4545 /* Let physical address point to the next page in the buffer. */
4546 GCPhysAddrDataBase = GCPhysAddrDataNextPage;
4547 GCPhysBufferPageAlignedPrev = GCPhysBufferPageAligned;
4548 }
4549 }
4550
4551 if (!fUnaligned)
4552 {
4553 /* The address is now page aligned. */
4554 while (cbDataToTransfer)
4555 {
4556 ahciLog(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u cSGEntriesR3=%u\n",
4557 __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer, cSGEntriesR3));
4558
4559 /* Check if this is the last page the buffer is in. */
4560 cbSegment = (cbDataToTransfer < PAGE_SIZE) ? cbDataToTransfer : PAGE_SIZE;
4561 cbDataToTransfer -= cbSegment;
4562
4563 if (fDoMapping)
4564 {
4565 void *pvMapping;
4566
4567 pSGInfoCurr->fGuestMemory = true;
4568
4569 /* Create the mapping. */
4570 if (fReadonly)
4571 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysAddrDataBase, 0, (const void **)&pvMapping, &pSGInfoCurr->u.direct.PageLock);
4572 else
4573 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrDataBase, 0, &pvMapping, &pSGInfoCurr->u.direct.PageLock);
4574
4575 if (RT_FAILURE(rc))
4576 {
4577 /* Mapping failed. Fall back to a bounce buffer. */
4578 ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
4579 __FUNCTION__, GCPhysAddrDataBase, rc));
4580
4581 return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
4582 cSGEntriesProcessed);
4583 }
4584
4585 /* Check for adjacent mappings. */
4586 if (pvMapping == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryPrev->cbSeg)
4587 && (pSGInfoPrev->fGuestMemory == true))
4588 {
4589 /* Yes they are adjacent. Just add the size of this mapping to the previous segment. */
4590 pSGEntryPrev->cbSeg += cbSegment;
4591 ahciLog(("%s: Merged mapping pvMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4592 __FUNCTION__, pvMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4593 }
4594 else
4595 {
4596 /* No they are not. Use a new sg entry. */
4597 pSGEntryCurr->cbSeg = cbSegment;
4598 pSGEntryCurr->pvSeg = pvMapping;
4599 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4600 pSGEntryCurr->pvSeg,
4601 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4602 pSGEntryPrev = pSGEntryCurr;
4603 pSGEntryCurr++;
4604 pAhciPortTaskState->cSGListUsed++;
4605 }
4606
4607 pSGInfoPrev = pSGInfoCurr;
4608 pSGInfoCurr++;
4609 cSGEntriesProcessed++;
4610 }
4611 else
4612 cSGEntriesR3++;
4613
4614 GCPhysBufferPageAlignedPrev = GCPhysAddrDataBase;
4615
4616 /* Go to the next page. */
4617 GCPhysAddrDataBase += PAGE_SIZE;
4618 }
4619 } /* if (!fUnaligned) */
4620 } /* if !fUnaligned */
4621 } /* if guest segment is sector aligned. */
4622 } /* for SGEntries read */
4623
4624 /* Set address to the next entries to read. */
4625 GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
4626
4627 } while (cSGLEntriesGCLeft);
4628
4629 fDoMapping = true;
4630
4631 } /* for passes */
4632
4633 /* Check if the last processed segment was unaligned. We need to add it now. */
4634 if (fUnaligned)
4635 {
4636 /* Set up the entry. */
4637 AssertMsg(!(cbUnaligned % 512), ("Buffer is not sector aligned\n"));
4638 pSGInfoCurr->fGuestMemory = false;
4639 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4640 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4641 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4642
4643 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4644 pSGEntryCurr->cbSeg = cbUnaligned;
4645 pAhciPortTaskState->cSGListUsed++;
4646
4647 /*
4648 * If the transfer is to the device we need to copy the content of the not mapped guest
4649 * segments into the temporary buffer.
4650 */
4651 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4652 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4653 }
4654
4655 STAM_PROFILE_STOP(&pAhciPort->StatProfileMapIntoR3, a);
4656
4657 return rc;
4658}
4659
4660/**
4661 * Destroy a scatter gather list and free all occupied resources (mappings, etc.)
4662 *
4663 * @returns VBox status code.
4664 * @param pAhciPort The ahci port.
4665 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4666 */
4667static int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4668{
4669 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4670 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4671
4672 STAM_PROFILE_START(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4673
4674 if (pAhciPortTaskState->pfnPostProcess)
4675 {
4676 int rc;
4677 rc = pAhciPortTaskState->pfnPostProcess(pAhciPortTaskState);
4678 AssertRC(rc);
4679
4680 pAhciPortTaskState->pfnPostProcess = NULL;
4681
4682 /* Free the buffer holding the unprocessed data. They are not needed anymore. */
4683 RTMemFree(pAhciPortTaskState->pSGListHead[0].pvSeg);
4684 }
4685
4686 for (unsigned cActualSGEntry = 0; cActualSGEntry < pAhciPortTaskState->cSGEntries; cActualSGEntry++)
4687 {
4688 if (pSGInfoCurr->fGuestMemory)
4689 {
4690 /* Release the lock. */
4691 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4692 }
4693 else if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4694 {
4695 /* Copy the data into the guest segments now. */
4696 ahciCopyFromBufferIntoSGList(pDevIns, pSGInfoCurr);
4697 }
4698
4699 /* Go to the next entry. */
4700 pSGInfoCurr++;
4701 }
4702
4703 /* Free allocated memory if the list was too big too many times. */
4704 if (pAhciPortTaskState->cSGListTooBig >= AHCI_NR_OF_ALLOWED_BIGGER_LISTS)
4705 {
4706 RTMemFree(pAhciPortTaskState->pSGListHead);
4707 RTMemFree(pAhciPortTaskState->paSGEntries);
4708 if (pAhciPortTaskState->pvBufferUnaligned)
4709 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4710 pAhciPortTaskState->cSGListSize = 0;
4711 pAhciPortTaskState->cSGListTooBig = 0;
4712 pAhciPortTaskState->pSGListHead = NULL;
4713 pAhciPortTaskState->paSGEntries = NULL;
4714 pAhciPortTaskState->pvBufferUnaligned = NULL;
4715 pAhciPortTaskState->cbBufferUnaligned = 0;
4716 }
4717
4718 STAM_PROFILE_STOP(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4719
4720 return VINF_SUCCESS;
4721}
4722
4723/**
4724 * Copy a temporary buffer into a part of the guest scatter gather list
4725 * described by the given descriptor entry.
4726 *
4727 * @returns nothing.
4728 * @param pDevIns Pointer to the device instance data.
4729 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4730 * to write to which are unaligned.
4731 */
4732static void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4733{
4734 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4735 SGLEntry aSGLEntries[5];
4736 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4737 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4738
4739 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4740
4741 do
4742 {
4743 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4744 ? cSGEntriesLeft
4745 : RT_ELEMENTS(aSGLEntries);
4746
4747 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4748
4749 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4750 {
4751 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4752 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4753
4754 /* Copy into SG entry. */
4755 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4756
4757 pu8Buf += cbCopied;
4758 }
4759
4760 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4761 cSGEntriesLeft -= cSGEntriesRead;
4762 } while (cSGEntriesLeft);
4763}
4764
4765/**
4766 * Copy a part of the guest scatter gather list into a temporary buffer.
4767 *
4768 * @returns nothing.
4769 * @param pDevIns Pointer to the device instance data.
4770 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4771 * to read from which are unaligned.
4772 */
4773static void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4774{
4775 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4776 SGLEntry aSGLEntries[5];
4777 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4778 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4779
4780 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4781
4782 do
4783 {
4784 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4785 ? cSGEntriesLeft
4786 : RT_ELEMENTS(aSGLEntries);
4787
4788 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4789
4790 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4791 {
4792 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4793 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4794
4795 /* Copy into buffer. */
4796 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4797
4798 pu8Buf += cbCopied;
4799 }
4800
4801 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4802 cSGEntriesLeft -= cSGEntriesRead;
4803 } while (cSGEntriesLeft);
4804}
4805
4806
4807/**
4808 * Copy the content of a buffer to a scatter gather list.
4809 *
4810 * @returns Number of bytes transfered.
4811 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4812 * @param pvBuf Pointer to the buffer which should be copied.
4813 * @param cbBuf Size of the buffer.
4814 */
4815static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf)
4816{
4817 unsigned cSGEntry = 0;
4818 int cbCopied = 0;
4819 PPDMDATASEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
4820 uint8_t *pu8Buf = (uint8_t *)pvBuf;
4821
4822 while (cSGEntry < pAhciPortTaskState->cSGEntries)
4823 {
4824 size_t cbToCopy = RT_MIN(cbBuf, pSGEntry->cbSeg);
4825
4826 memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
4827
4828 cbBuf -= cbToCopy;
4829 cbCopied += cbToCopy;
4830
4831 /* We finished. */
4832 if (!cbBuf)
4833 break;
4834
4835 /* Advance the buffer. */
4836 pu8Buf += cbToCopy;
4837
4838 /* Go to the next entry in the list. */
4839 pSGEntry++;
4840 cSGEntry++;
4841 }
4842
4843 LogFlow(("%s: Copied %d bytes\n", __FUNCTION__, cbCopied));
4844 return cbCopied;
4845}
4846
4847/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
4848
4849/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
4850#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
4851
4852/**
4853 * Complete a data transfer task by freeing all occupied ressources
4854 * and notifying the guest.
4855 *
4856 * @returns VBox status code
4857 *
4858 * @param pAhciPort Pointer to the port where to request completed.
4859 * @param pAhciPortTaskState Pointer to the task which finished.
4860 */
4861static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4862{
4863 /* Free system resources occupied by the scatter gather list. */
4864 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4865
4866 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4867
4868 pAhciPortTaskState->uATARegError = 0;
4869 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4870 /* Write updated command header into memory of the guest. */
4871 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4872 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4873
4874 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4875 {
4876 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
4877 pAhciPort->Led.Actual.s.fReading = 0;
4878 }
4879 else
4880 {
4881 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
4882 pAhciPort->Led.Actual.s.fWriting = 0;
4883 }
4884
4885 if (pAhciPortTaskState->fQueued)
4886 {
4887 uint32_t cOutstandingTasks;
4888
4889 ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
4890 cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
4891 ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
4892 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
4893
4894 if (!cOutstandingTasks)
4895 ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
4896 }
4897 else
4898 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
4899
4900 /* Add the task to the cache. */
4901 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
4902
4903 return VINF_SUCCESS;
4904}
4905
4906/**
4907 * Notification callback for a completed transfer.
4908 *
4909 * @returns VBox status code.
4910 * @param pInterface Pointer to the interface.
4911 * @param pvUser User data.
4912 */
4913static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
4914{
4915 PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
4916 PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
4917
4918 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
4919 __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
4920
4921 int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
4922
4923 if (pAhciPort->uActTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
4924 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
4925 return rc;
4926}
4927
4928/**
4929 * Process an non read/write ATA command.
4930 *
4931 * @returns The direction of the data transfer
4932 * @param pCmdHdr Pointer to the command header.
4933 */
4934static int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
4935{
4936 int rc = PDMBLOCKTXDIR_NONE;
4937 bool fLBA48 = false;
4938 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4939
4940 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
4941
4942 pAhciPortTaskState->cbTransfer = 0;
4943
4944 switch (pCmdFis[AHCI_CMDFIS_CMD])
4945 {
4946 case ATA_IDENTIFY_DEVICE:
4947 {
4948 if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
4949 {
4950 uint16_t u16Temp[256];
4951
4952 /* Fill the buffer. */
4953 ahciIdentifySS(pAhciPort, u16Temp);
4954
4955 /* Create scatter gather list. */
4956 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
4957 if (RT_FAILURE(rc))
4958 AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
4959
4960 /* Copy the buffer. */
4961 pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
4962
4963 /* Destroy list. */
4964 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4965 if (RT_FAILURE(rc))
4966 AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
4967
4968 pAhciPortTaskState->uATARegError = 0;
4969 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4970
4971 /* Write updated command header into memory of the guest. */
4972 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
4973 }
4974 else
4975 {
4976 pAhciPortTaskState->uATARegError = ABRT_ERR;
4977 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4978 }
4979 break;
4980 }
4981 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
4982 case ATA_READ_NATIVE_MAX_ADDRESS:
4983 break;
4984 case ATA_SET_FEATURES:
4985 {
4986 switch (pCmdFis[AHCI_CMDFIS_FET])
4987 {
4988 case 0x02: /* write cache enable */
4989 case 0xaa: /* read look-ahead enable */
4990 case 0x55: /* read look-ahead disable */
4991 case 0xcc: /* reverting to power-on defaults enable */
4992 case 0x66: /* reverting to power-on defaults disable */
4993 pAhciPortTaskState->uATARegError = 0;
4994 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4995 break;
4996 case 0x82: /* write cache disable */
4997 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4998 pAhciPortTaskState->uATARegError = 0;
4999 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5000 break;
5001 case 0x03:
5002 { /* set transfer mode */
5003 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
5004 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
5005 {
5006 case 0x00: /* PIO default */
5007 case 0x08: /* PIO mode */
5008 break;
5009 case ATA_MODE_MDMA: /* MDMA mode */
5010 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
5011 break;
5012 case ATA_MODE_UDMA: /* UDMA mode */
5013 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
5014 break;
5015 }
5016 break;
5017 }
5018 default:
5019 pAhciPortTaskState->uATARegError = ABRT_ERR;
5020 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5021 }
5022 break;
5023 }
5024 case ATA_FLUSH_CACHE_EXT:
5025 case ATA_FLUSH_CACHE:
5026 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
5027 pAhciPortTaskState->uATARegError = 0;
5028 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5029 break;
5030 case ATA_PACKET:
5031 if (!pAhciPort->fATAPI)
5032 {
5033 pAhciPortTaskState->uATARegError = ABRT_ERR;
5034 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5035 }
5036 else
5037 {
5038 rc = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
5039 }
5040 break;
5041 case ATA_IDENTIFY_PACKET_DEVICE:
5042 if (!pAhciPort->fATAPI)
5043 {
5044 pAhciPortTaskState->uATARegError = ABRT_ERR;
5045 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5046 }
5047 else
5048 {
5049 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_IDENTIFY);
5050
5051 pAhciPortTaskState->uATARegError = 0;
5052 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5053 }
5054 break;
5055 case ATA_SET_MULTIPLE_MODE:
5056 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
5057 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
5058 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
5059 {
5060 pAhciPortTaskState->uATARegError = ABRT_ERR;
5061 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5062 }
5063 else
5064 {
5065 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
5066 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
5067 pAhciPortTaskState->uATARegError = 0;
5068 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5069 }
5070 break;
5071 case ATA_STANDBY_IMMEDIATE:
5072 break; /* Do nothing. */
5073 case ATA_CHECK_POWER_MODE:
5074 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
5075 /* fall through */
5076 case ATA_INITIALIZE_DEVICE_PARAMETERS:
5077 case ATA_IDLE_IMMEDIATE:
5078 case ATA_RECALIBRATE:
5079 case ATA_NOP:
5080 case ATA_READ_VERIFY_SECTORS_EXT:
5081 case ATA_READ_VERIFY_SECTORS:
5082 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
5083 pAhciPortTaskState->uATARegError = 0;
5084 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5085 break;
5086 case ATA_READ_DMA_EXT:
5087 fLBA48 = true;
5088 case ATA_READ_DMA:
5089 {
5090 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5091 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5092 rc = PDMBLOCKTXDIR_FROM_DEVICE;
5093 break;
5094 }
5095 case ATA_WRITE_DMA_EXT:
5096 fLBA48 = true;
5097 case ATA_WRITE_DMA:
5098 {
5099 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5100 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5101 rc = PDMBLOCKTXDIR_TO_DEVICE;
5102 break;
5103 }
5104 case ATA_READ_FPDMA_QUEUED:
5105 {
5106 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5107 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5108 rc = PDMBLOCKTXDIR_FROM_DEVICE;
5109 break;
5110 }
5111 case ATA_WRITE_FPDMA_QUEUED:
5112 {
5113 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5114 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5115 rc = PDMBLOCKTXDIR_TO_DEVICE;
5116 break;
5117 }
5118 /* All not implemented commands go below. */
5119 case ATA_SECURITY_FREEZE_LOCK:
5120 case ATA_SMART:
5121 case ATA_NV_CACHE:
5122 case ATA_SLEEP: /* Powermanagement not supported. */
5123 pAhciPortTaskState->uATARegError = ABRT_ERR;
5124 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5125 break;
5126 default: /* For debugging purposes. */
5127 AssertMsgFailed(("Unknown command issued\n"));
5128 pAhciPortTaskState->uATARegError = ABRT_ERR;
5129 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5130 }
5131
5132 return rc;
5133}
5134
5135/**
5136 * Retrieve a command FIS from guest memory.
5137 *
5138 * @returns nothing
5139 * @param pAhciPortTaskState The state of the actual task.
5140 */
5141static void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
5142{
5143 RTGCPHYS GCPhysAddrCmdTbl;
5144
5145 AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
5146
5147 /*
5148 * First we are reading the command header pointed to by regCLB.
5149 * From this we get the address of the command table which we are reading too.
5150 * We can process the Command FIS afterwards.
5151 */
5152 pAhciPortTaskState->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciPortTaskState->uTag * sizeof(CmdHdr);
5153 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
5154 pAhciPortTaskState->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
5155 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5156
5157#ifdef DEBUG
5158 /* Print some infos about the command header. */
5159 ahciDumpCmdHdrInfo(pAhciPort, &pAhciPortTaskState->cmdHdr);
5160#endif
5161
5162 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr);
5163
5164 AssertMsg((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
5165 ("This is not a command FIS!!\n"));
5166
5167 /* Read the command Fis. */
5168 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
5169 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
5170
5171 /* Set transfer direction. */
5172 pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
5173
5174 /* If this is an ATAPI command read the atapi command. */
5175 if (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
5176 {
5177 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
5178 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->aATAPICmd[0], ATAPI_PACKET_SIZE);
5179 }
5180
5181 /* We "received" the FIS. Clear the BSY bit in regTFD. */
5182 if ((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciPortTaskState->fQueued))
5183 {
5184 /*
5185 * 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.
5186 * but this FIS does not assert an interrupt
5187 */
5188 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, false);
5189 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
5190 }
5191
5192#ifdef DEBUG
5193 /* Print some infos about the FIS. */
5194 ahciDumpFisInfo(pAhciPort, &pAhciPortTaskState->cmdFis[0]);
5195
5196 /* Print the PRDT */
5197 RTGCPHYS GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
5198
5199 ahciLog(("PRDT address %RGp number of entries %u\n", GCPhysAddrPRDTLEntryStart, AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf)));
5200
5201 for (unsigned i = 0; i < AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf); i++)
5202 {
5203 SGLEntry SGEntry;
5204
5205 ahciLog(("Entry %u at address %RGp\n", i, GCPhysAddrPRDTLEntryStart));
5206 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrPRDTLEntryStart, &SGEntry, sizeof(SGLEntry));
5207
5208 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
5209 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
5210
5211 GCPhysAddrPRDTLEntryStart += sizeof(SGLEntry);
5212 }
5213#endif
5214}
5215
5216/**
5217 * Transmit queue consumer
5218 * Queue a new async task.
5219 *
5220 * @returns Success indicator.
5221 * If false the item will not be removed and the flushing will stop.
5222 * @param pDevIns The device instance.
5223 * @param pItem The item to consume. Upon return this item will be freed.
5224 */
5225static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5226{
5227 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
5228 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5229 PAHCIPort pAhciPort = &pAhci->ahciPort[pNotifierItem->iPort];
5230 int rc = VINF_SUCCESS;
5231
5232 if (!pAhciPort->fAsyncInterface)
5233 {
5234 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
5235 /* Notify the async IO thread. */
5236 rc = RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5237 AssertRC(rc);
5238 }
5239 else
5240 {
5241 int iTxDir;
5242 PAHCIPORTTASKSTATE pAhciPortTaskState;
5243
5244 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
5245
5246 /* Check if there is already an allocated task struct in the cache.
5247 * Allocate a new task otherwise.
5248 */
5249 if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
5250 {
5251 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5252 AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
5253 }
5254 else
5255 {
5256 pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
5257 }
5258
5259 /** Set current command slot */
5260 pAhciPortTaskState->uTag = pNotifierItem->iTask;
5261 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5262
5263 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5264
5265 /* 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. */
5266 if (pNotifierItem->fQueued)
5267 {
5268 pAhciPortTaskState->fQueued = true;
5269 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5270 }
5271 else
5272 pAhciPortTaskState->fQueued = false;
5273
5274 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5275 {
5276 /* If the reset bit is set put the device into reset state. */
5277 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5278 {
5279 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5280 pAhciPort->fResetDevice = true;
5281 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
5282 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5283 return true;
5284 }
5285 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5286 {
5287 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5288 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5289 return true;
5290 }
5291 else /* We are not in a reset state update the control registers. */
5292 {
5293 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
5294 }
5295 }
5296
5297 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5298
5299 if (iTxDir != PDMBLOCKTXDIR_NONE)
5300 {
5301 if (pAhciPortTaskState->fQueued)
5302 {
5303 ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5304 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
5305 ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5306 }
5307
5308 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5309
5310 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5311 if (RT_FAILURE(rc))
5312 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5313
5314 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5315 {
5316 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5317 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5318 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
5319 pAhciPortTaskState->cbTransfer,
5320 pAhciPortTaskState);
5321 }
5322 else
5323 {
5324 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5325 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5326 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
5327 pAhciPortTaskState->cbTransfer,
5328 pAhciPortTaskState);
5329 }
5330 if (rc == VINF_VD_ASYNC_IO_FINISHED)
5331 rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
5332
5333 if (RT_FAILURE(rc))
5334 AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
5335 }
5336 else
5337 {
5338 /* There is nothing left to do. Notify the guest. */
5339 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5340 /* Add the task to the cache. */
5341 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
5342 }
5343 }
5344
5345 return true;
5346}
5347
5348/* The async IO thread for one port. */
5349static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5350{
5351 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5352 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5353 PAHCIPORTTASKSTATE pAhciPortTaskState;
5354 int rc = VINF_SUCCESS;
5355 uint64_t u64StartTime = 0;
5356 uint64_t u64StopTime = 0;
5357 uint32_t uIORequestsProcessed = 0;
5358 uint32_t uIOsPerSec = 0;
5359
5360 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
5361
5362 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
5363 return VINF_SUCCESS;
5364
5365 /* We use only one task structure. */
5366 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5367 if (!pAhciPortTaskState)
5368 {
5369 AssertMsgFailed(("Failed to allocate task state memory\n"));
5370 return VERR_NO_MEMORY;
5371 }
5372
5373 while(pThread->enmState == PDMTHREADSTATE_RUNNING)
5374 {
5375 uint32_t uQueuedTasksFinished = 0;
5376
5377 /* New run to get number of I/O requests per second?. */
5378 if (!u64StartTime)
5379 u64StartTime = RTTimeMilliTS();
5380
5381 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
5382 if (pAhci->fSignalIdle)
5383 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
5384
5385 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
5386 if (rc == VERR_TIMEOUT)
5387 {
5388 /* No I/O requests inbetween. Reset statistics and wait again. */
5389 pAhciPort->StatIORequestsPerSecond.c = 0;
5390 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
5391 }
5392
5393 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
5394 break;
5395
5396 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
5397
5398 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
5399
5400 /*
5401 * To maximize the throughput of the controller we try to minimize the
5402 * number of world switches during interrupts by grouping as many
5403 * I/O requests together as possible.
5404 * On the other side we want to get minimal latency if the I/O load is low.
5405 * Thatswhy the number of I/O requests per second is measured and if it is over
5406 * a threshold the thread waits for other requests from the guest.
5407 */
5408 if (uIOsPerSec >= pAhci->cHighIOThreshold)
5409 {
5410 uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
5411
5412 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
5413
5414 do
5415 {
5416 /* Sleep some time. */
5417 RTThreadSleep(pAhci->cMillisToSleep);
5418 /* Check if we got some new requests inbetween. */
5419 if (uActWritePosPrev != pAhciPort->uActWritePos)
5420 {
5421 uActWritePosPrev = pAhciPort->uActWritePos;
5422 /*
5423 * Check if the queue is full. If that is the case
5424 * there is no point waiting another round.
5425 */
5426 if ( ( (pAhciPort->uActReadPos < uActWritePosPrev)
5427 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
5428 || ( (pAhciPort->uActReadPos > uActWritePosPrev)
5429 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) )
5430 {
5431 Log(("%s: Queue full -> leaving\n", __FUNCTION__));
5432 break;
5433 }
5434 Log(("%s: Another round\n", __FUNCTION__));
5435 }
5436 else /* No change break out of the loop. */
5437 {
5438#ifdef DEBUG
5439 uint8_t uQueuedTasks;
5440 if (pAhciPort->uActReadPos < uActWritePosPrev)
5441 uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
5442 else
5443 uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
5444
5445 Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
5446#endif
5447 break;
5448 }
5449 } while (true);
5450 }
5451
5452 ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
5453
5454 uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5455
5456 ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
5457
5458 /* Process commands. */
5459 while ( (cTasksToProcess > 0)
5460 && RT_LIKELY(!pAhciPort->fPortReset))
5461 {
5462 int iTxDir;
5463 uint8_t uActTag;
5464
5465 STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
5466
5467 ahciLog(("%s: uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
5468 ahciLog(("%s: Before uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5469
5470 pAhciPortTaskState->uATARegStatus = 0;
5471 pAhciPortTaskState->uATARegError = 0;
5472 uActTag = pAhciPort->ahciIOTasks[pAhciPort->uActReadPos];
5473
5474 pAhciPortTaskState->uTag = AHCI_TASK_GET_TAG(uActTag);
5475 AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number!!\n", __FUNCTION__));
5476
5477 /** Set current command slot */
5478 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5479
5480 /* 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. */
5481 if (AHCI_TASK_IS_QUEUED(uActTag))
5482 {
5483 pAhciPortTaskState->fQueued = true;
5484 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5485 }
5486 else
5487 {
5488 pAhciPortTaskState->fQueued = false;
5489 }
5490
5491 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5492
5493 ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciPortTaskState->uTag));
5494
5495 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5496 {
5497 /* If the reset bit is set put the device into reset state. */
5498 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5499 {
5500 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5501 pAhciPort->fResetDevice = true;
5502 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5503 }
5504 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5505 {
5506 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5507 }
5508 /* TODO: We are not in a reset state update the control registers. */
5509 }
5510 else
5511 {
5512 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5513
5514 if (iTxDir != PDMBLOCKTXDIR_NONE)
5515 {
5516 uint64_t uOffset;
5517 size_t cbTransfer;
5518 PPDMDATASEG pSegCurr;
5519 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
5520
5521 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5522 if (RT_FAILURE(rc))
5523 AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
5524
5525 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5526
5527 /* Initialize all values. */
5528 uOffset = pAhciPortTaskState->uOffset;
5529 cbTransfer = pAhciPortTaskState->cbTransfer;
5530 pSegCurr = &pAhciPortTaskState->pSGListHead[0];
5531 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
5532
5533 STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, a);
5534
5535 while (cbTransfer)
5536 {
5537 size_t cbProcess = (cbTransfer < pSegCurr->cbSeg) ? cbTransfer : pSegCurr->cbSeg;
5538
5539 AssertMsg(!(pSegCurr->cbSeg % 512), ("Buffer is not sector aligned cbSeg=%d\n", pSegCurr->cbSeg));
5540 AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
5541 AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
5542
5543 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5544 {
5545 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5546 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
5547 pSegCurr->pvSeg, cbProcess);
5548 pAhciPort->Led.Actual.s.fReading = 0;
5549 if (RT_FAILURE(rc))
5550 AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
5551
5552 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
5553 }
5554 else
5555 {
5556 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5557 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
5558 pSegCurr->pvSeg, cbProcess);
5559 pAhciPort->Led.Actual.s.fWriting = 0;
5560 if (RT_FAILURE(rc))
5561 AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
5562
5563 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbProcess);
5564 }
5565
5566 /* Go to the next entry. */
5567 uOffset += cbProcess;
5568 cbTransfer -= cbProcess;
5569 pSegCurr++;
5570 pSGInfoCurr++;
5571 }
5572
5573 STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
5574
5575 /* Cleanup. */
5576 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5577 if (RT_FAILURE(rc))
5578 AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
5579
5580 if (RT_LIKELY(!pAhciPort->fPortReset))
5581 {
5582 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
5583 pAhciPortTaskState->uATARegError = 0;
5584 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5585 /* Write updated command header into memory of the guest. */
5586 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
5587 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5588
5589 if (pAhciPortTaskState->fQueued)
5590 uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
5591 else
5592 {
5593 /* Task is not queued send D2H FIS */
5594 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5595 }
5596
5597 uIORequestsProcessed++;
5598 }
5599 }
5600 else
5601 {
5602 /* Nothing left to do. Notify the guest. */
5603 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5604 }
5605
5606 STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
5607 }
5608
5609#ifdef DEBUG
5610 /* Be paranoid. */
5611 memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
5612 memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
5613 pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
5614 pAhciPortTaskState->uOffset = 0;
5615 pAhciPortTaskState->cbTransfer = 0;
5616 /* Make the port number invalid making it easier to track down bugs. */
5617 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
5618#endif
5619
5620 pAhciPort->uActReadPos++;
5621 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
5622 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5623 cTasksToProcess--;
5624 if (!cTasksToProcess)
5625 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5626 }
5627
5628 if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5629 ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, true);
5630
5631 uQueuedTasksFinished = 0;
5632
5633 u64StopTime = RTTimeMilliTS();
5634 /* Check if one second has passed. */
5635 if (u64StopTime - u64StartTime >= 1000)
5636 {
5637 /* Calculate number of I/O requests per second. */
5638 uIOsPerSec = uIORequestsProcessed / ((u64StopTime - u64StartTime) / 1000);
5639 ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
5640 u64StartTime = 0;
5641 uIORequestsProcessed = 0;
5642 /* For the release statistics. There is no macro to set the counter to a specific value. */
5643 pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
5644 }
5645 }
5646
5647 if (pAhci->fSignalIdle)
5648 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
5649
5650 /* Free task state memory */
5651 if (pAhciPortTaskState->pSGListHead)
5652 RTMemFree(pAhciPortTaskState->pSGListHead);
5653 if (pAhciPortTaskState->paSGEntries)
5654 RTMemFree(pAhciPortTaskState->paSGEntries);
5655 if (pAhciPortTaskState->pvBufferUnaligned)
5656 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
5657 RTMemFree(pAhciPortTaskState);
5658
5659 ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
5660 return rc;
5661}
5662
5663/**
5664 * Unblock the async I/O thread so it can respond to a state change.
5665 *
5666 * @returns VBox status code.
5667 * @param pDevIns The pcnet device instance.
5668 * @param pThread The send thread.
5669 */
5670static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5671{
5672 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5673 return RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5674}
5675
5676/**
5677 * Called when a media is mounted.
5678 *
5679 * @param pInterface Pointer to the interface structure containing the called function pointer.
5680 */
5681static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
5682{
5683 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5684 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
5685
5686 /* Ignore the call if we're called while being attached. */
5687 if (!pAhciPort->pDrvBlock)
5688 return;
5689
5690 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5691
5692 /*
5693 * Initialize registers
5694 */
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/**
5703 * Called when a media is unmounted
5704 * @param pInterface Pointer to the interface structure containing the called function pointer.
5705 */
5706static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
5707{
5708 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5709 Log(("%s:\n", __FUNCTION__));
5710
5711 pAhciPort->cTotalSectors = 0;
5712
5713 /*
5714 * Inform the guest about the removed device.
5715 */
5716 pAhciPort->regSSTS = 0;
5717 pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
5718 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
5719 pAhciPort->regSERR |= AHCI_PORT_SERR_N;
5720 if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5721 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
5722}
5723
5724/**
5725 * Destroy a driver instance.
5726 *
5727 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5728 * resources can be freed correctly.
5729 *
5730 * @param pDevIns The device instance data.
5731 */
5732static DECLCALLBACK(int) ahciDestruct(PPDMDEVINS pDevIns)
5733{
5734 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5735 int rc = VINF_SUCCESS;
5736 unsigned iActPort = 0;
5737
5738 /*
5739 * At this point the async I/O thread is suspended and will not enter
5740 * this module again. So, no coordination is needed here and PDM
5741 * will take care of terminating and cleaning up the thread.
5742 */
5743 if (PDMCritSectIsInitialized(&pAhci->lock))
5744 {
5745 TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
5746
5747 Log(("%s: Destruct every port\n", __FUNCTION__));
5748 for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
5749 {
5750 PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
5751
5752 if (pAhciPort->pAsyncIOThread)
5753 {
5754 /* Destroy the event semaphore. */
5755 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
5756 if (RT_FAILURE(rc))
5757 {
5758 Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
5759 }
5760 }
5761
5762 /* Free all cached tasks. */
5763 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
5764 {
5765 if (pAhciPort->aCachedTasks[i])
5766 {
5767 if (pAhciPort->aCachedTasks[i]->pSGListHead)
5768 RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
5769 if (pAhciPort->aCachedTasks[i]->paSGEntries)
5770 RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
5771
5772 RTMemFree(pAhciPort->aCachedTasks[i]);
5773 }
5774 }
5775 }
5776
5777 /* Destroy emulated ATA controllers. */
5778 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5779 ataControllerDestroy(&pAhci->aCts[i]);
5780
5781 PDMR3CritSectDelete(&pAhci->lock);
5782 }
5783
5784 return rc;
5785}
5786
5787/**
5788 * Configure the attached device for a port.
5789 *
5790 * @returns VBox status code
5791 * @param pDevIns The device instance data.
5792 * @param pAhciPort The port for which the device is to be configured.
5793 */
5794static int ahciConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
5795{
5796 int rc = VINF_SUCCESS;
5797 PDMBLOCKTYPE enmType;
5798
5799 /*
5800 * Query the block and blockbios interfaces.
5801 */
5802 pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
5803 if (!pAhciPort->pDrvBlock)
5804 {
5805 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
5806 return VERR_PDM_MISSING_INTERFACE;
5807 }
5808 pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
5809 if (!pAhciPort->pDrvBlockBios)
5810 {
5811 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
5812 return VERR_PDM_MISSING_INTERFACE;
5813 }
5814
5815 pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
5816
5817 /* Try to get the optional async block interface. */
5818 pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
5819
5820 /*
5821 * Validate type.
5822 */
5823 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
5824
5825 if ( enmType != PDMBLOCKTYPE_HARD_DISK
5826 && enmType != PDMBLOCKTYPE_CDROM
5827 && enmType != PDMBLOCKTYPE_DVD)
5828 {
5829 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
5830 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
5831 }
5832
5833 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
5834 && !pAhciPort->pDrvMount)
5835 {
5836 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
5837 return VERR_INTERNAL_ERROR;
5838 }
5839 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
5840
5841 if (pAhciPort->fATAPI)
5842 {
5843 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
5844 pAhciPort->PCHSGeometry.cCylinders = 0;
5845 pAhciPort->PCHSGeometry.cHeads = 0;
5846 pAhciPort->PCHSGeometry.cSectors = 0;
5847 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
5848 }
5849 else
5850 {
5851 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5852 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
5853 &pAhciPort->PCHSGeometry);
5854 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
5855 {
5856 pAhciPort->PCHSGeometry.cCylinders = 0;
5857 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
5858 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
5859 }
5860 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
5861 {
5862 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
5863 rc = VINF_SUCCESS;
5864 }
5865 AssertRC(rc);
5866
5867 if ( pAhciPort->PCHSGeometry.cCylinders == 0
5868 || pAhciPort->PCHSGeometry.cHeads == 0
5869 || pAhciPort->PCHSGeometry.cSectors == 0)
5870 {
5871 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
5872 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
5873 pAhciPort->PCHSGeometry.cHeads = 16;
5874 pAhciPort->PCHSGeometry.cSectors = 63;
5875 /* Set the disk geometry information. Ignore errors. */
5876 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
5877 &pAhciPort->PCHSGeometry);
5878 rc = VINF_SUCCESS;
5879 }
5880 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
5881 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
5882 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
5883 pAhciPort->cTotalSectors));
5884 }
5885 return rc;
5886}
5887
5888/**
5889 * Checks if all asynchronous I/O is finished.
5890 *
5891 * @returns true if quiesced, false if busy.
5892 * @param pDevIns The device instance.
5893 */
5894static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
5895{
5896 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
5897
5898 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
5899 {
5900 PAHCIPort pThisPort = &pThis->ahciPort[i];
5901 if (pThisPort->pDrvBase)
5902 {
5903 bool fFinished;
5904 if (pThisPort->fAsyncInterface)
5905 fFinished = (pThisPort->uActTasksActive == 0);
5906 else
5907 fFinished = ((pThisPort->uActTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
5908 if (!fFinished)
5909 return false;
5910 }
5911 }
5912 return true;
5913}
5914
5915static DECLCALLBACK(int) ahciSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5916{
5917 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5918
5919 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
5920
5921 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5922 {
5923 int rc;
5924
5925 rc = ataControllerSavePrep(&pAhci->aCts[i], pSSM);
5926 if (RT_FAILURE(rc))
5927 return rc;
5928 }
5929
5930 return VINF_SUCCESS;
5931}
5932
5933static DECLCALLBACK(int) ahciLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5934{
5935 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5936
5937 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5938 {
5939 int rc;
5940
5941 rc = ataControllerLoadPrep(&pAhci->aCts[i], pSSM);
5942 if (RT_FAILURE(rc))
5943 return rc;
5944 }
5945
5946 return VINF_SUCCESS;
5947}
5948
5949/**
5950 * Callback employed by ataSuspend and ataR3PowerOff.
5951 *
5952 * @returns true if we've quiesced, false if we're still working.
5953 * @param pDevIns The device instance.
5954 */
5955static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
5956{
5957 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5958 return false;
5959
5960 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
5961 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5962 return true;
5963}
5964
5965/**
5966 * Common worker for ataSuspend and ataR3PowerOff.
5967 */
5968static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
5969{
5970 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
5971
5972 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
5973 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
5974 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
5975 else
5976 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5977}
5978
5979/**
5980 * Suspend notification.
5981 *
5982 * @returns VBox status.
5983 * @param pDevIns The device instance data.
5984 */
5985static DECLCALLBACK(void) ahciSuspend(PPDMDEVINS pDevIns)
5986{
5987 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5988 Log(("%s:\n", __FUNCTION__));
5989
5990 ahciR3SuspendOrPowerOff(pDevIns);
5991
5992 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5993 ataControllerSuspend(&pAhci->aCts[i]);
5994}
5995
5996/**
5997 * Resume notification.
5998 *
5999 * @param pDevIns The device instance data.
6000 */
6001static DECLCALLBACK(void) ahciResume(PPDMDEVINS pDevIns)
6002{
6003 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6004
6005 Log(("%s:\n", __FUNCTION__));
6006 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6007 ataControllerResume(&pAhci->aCts[i]);
6008 return;
6009}
6010
6011/**
6012 * @copydoc FNDEVSSMLIVEEXEC
6013 */
6014static DECLCALLBACK(int) ahciLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6015{
6016 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6017
6018 /* config. */
6019 SSMR3PutU32(pSSM, pThis->cPortsImpl);
6020 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6021 {
6022 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
6023 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6024 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6025 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6026 }
6027
6028 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6029 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6030 {
6031 uint32_t iPort;
6032 int rc = CFGMR3QueryU32Def(pDevIns->pCfgHandle, s_apszIdeEmuPortNames[i], &iPort, i);
6033 AssertRCReturn(rc, rc);
6034 SSMR3PutU32(pSSM, iPort);
6035 }
6036
6037 return VINF_SSM_DONT_CALL_AGAIN;
6038}
6039
6040/**
6041 * @copydoc FNDEVSSMSAVEEXEC
6042 */
6043static DECLCALLBACK(int) ahciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6044{
6045 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6046 uint32_t i;
6047 int rc;
6048
6049 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6050
6051 /* The config */
6052 rc = ahciLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6053 AssertRCReturn(rc, rc);
6054
6055 /* The main device structure. */
6056 SSMR3PutU32(pSSM, pThis->regHbaCap);
6057 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
6058 SSMR3PutU32(pSSM, pThis->regHbaIs);
6059 SSMR3PutU32(pSSM, pThis->regHbaPi);
6060 SSMR3PutU32(pSSM, pThis->regHbaVs);
6061 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
6062 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
6063 SSMR3PutU8(pSSM, pThis->uCccPortNr);
6064 SSMR3PutU64(pSSM, pThis->uCccTimeout);
6065 SSMR3PutU32(pSSM, pThis->uCccNr);
6066 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
6067 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
6068 SSMR3PutBool(pSSM, pThis->fReset);
6069 SSMR3PutBool(pSSM, pThis->f64BitAddr);
6070 SSMR3PutBool(pSSM, pThis->fR0Enabled);
6071 SSMR3PutBool(pSSM, pThis->fGCEnabled);
6072
6073 /* Now every port. */
6074 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6075 {
6076 Assert(pThis->ahciPort[i].uActTasksActive == 0);
6077 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
6078 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
6079 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
6080 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
6081 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6082 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6083 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
6084 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
6085 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
6086 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
6087 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
6088 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
6089 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
6090 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
6091 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
6092 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
6093 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
6094 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
6095 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
6096 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
6097 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
6098 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
6099 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
6100
6101 /* No need to save */
6102 SSMR3PutU8(pSSM, pThis->ahciPort[i].uActWritePos);
6103 SSMR3PutU8(pSSM, pThis->ahciPort[i].uActReadPos);
6104 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
6105 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
6106 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
6107 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
6108 }
6109
6110 /* Now the emulated ata controllers. */
6111 for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6112 {
6113 rc = ataControllerSaveExec(&pThis->aCts[i], pSSM);
6114 if (RT_FAILURE(rc))
6115 return rc;
6116 }
6117
6118 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
6119}
6120
6121/**
6122 * Loads a saved AHCI device state.
6123 *
6124 * @returns VBox status code.
6125 * @param pDevIns The device instance.
6126 * @param pSSM The handle to the saved state.
6127 * @param uVersion The data unit version number.
6128 * @param uPass The data pass.
6129 */
6130static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
6131{
6132 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6133 uint32_t u32;
6134 uint32_t i;
6135 int rc;
6136
6137 if ( uVersion != AHCI_SAVED_STATE_VERSION
6138 && uVersion != AHCI_SAVED_STATE_VERSION_VBOX_30)
6139 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6140
6141 /* Verify config. */
6142 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
6143 {
6144 rc = SSMR3GetU32(pSSM, &u32);
6145 AssertRCReturn(rc, rc);
6146 if (u32 != pThis->cPortsImpl)
6147 {
6148 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
6149 if ( u32 < pThis->cPortsImpl
6150 || u32 > AHCI_MAX_NR_PORTS_IMPL)
6151 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
6152 u32, pThis->cPortsImpl);
6153 }
6154
6155 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6156 {
6157 bool fInUse;
6158 rc = SSMR3GetBool(pSSM, &fInUse);
6159 AssertRCReturn(rc, rc);
6160 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
6161 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
6162 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
6163 fInUse ? "target" : "source", i );
6164
6165 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
6166 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
6167 AssertRCReturn(rc, rc);
6168 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
6169 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
6170 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
6171
6172 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
6173 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
6174 AssertRCReturn(rc, rc);
6175 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
6176 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
6177 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
6178
6179 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
6180 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
6181 AssertRCReturn(rc, rc);
6182 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
6183 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
6184 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
6185 }
6186
6187 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6188 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6189 {
6190 uint32_t iPort;
6191 rc = CFGMR3QueryU32Def(pDevIns->pCfgHandle, s_apszIdeEmuPortNames[i], &iPort, i);
6192 AssertRCReturn(rc, rc);
6193
6194 uint32_t iPortSaved;
6195 rc = SSMR3GetU32(pSSM, &iPortSaved);
6196 AssertRCReturn(rc, rc);
6197
6198 if (iPortSaved != iPort)
6199 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
6200 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
6201 }
6202 }
6203
6204 if (uPass == SSM_PASS_FINAL)
6205 {
6206 /* Restore data. */
6207
6208 /* The main device structure. */
6209 SSMR3GetU32(pSSM, &pThis->regHbaCap);
6210 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
6211 SSMR3GetU32(pSSM, &pThis->regHbaIs);
6212 SSMR3GetU32(pSSM, &pThis->regHbaPi);
6213 SSMR3GetU32(pSSM, &pThis->regHbaVs);
6214 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
6215 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
6216 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
6217 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
6218 SSMR3GetU32(pSSM, &pThis->uCccNr);
6219 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
6220
6221 SSMR3GetU32(pSSM, &pThis->u32PortsInterrupted);
6222 SSMR3GetBool(pSSM, &pThis->fReset);
6223 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
6224 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
6225 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
6226
6227 /* Now every port. */
6228 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6229 {
6230 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
6231 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
6232 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
6233 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
6234 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
6235 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
6236 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
6237 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
6238 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
6239 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
6240 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
6241 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
6242 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
6243 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
6244 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
6245 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
6246 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
6247 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
6248 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
6249 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
6250 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
6251 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
6252 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
6253
6254 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
6255 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
6256
6257 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActWritePos);
6258 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActReadPos);
6259 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
6260 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
6261 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
6262 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
6263 }
6264
6265 /* Now the emulated ata controllers. */
6266 for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6267 {
6268 rc = ataControllerLoadExec(&pThis->aCts[i], pSSM);
6269 if (RT_FAILURE(rc))
6270 return rc;
6271 }
6272
6273 rc = SSMR3GetU32(pSSM, &u32);
6274 if (RT_FAILURE(rc))
6275 return rc;
6276 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
6277 }
6278
6279 return VINF_SUCCESS;
6280}
6281
6282/**
6283 * Detach notification.
6284 *
6285 * One harddisk at one port has been unplugged.
6286 * The VM is suspended at this point.
6287 *
6288 * @param pDevIns The device instance.
6289 * @param iLUN The logical unit which is being detached.
6290 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
6291 */
6292static DECLCALLBACK(void) ahciDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
6293{
6294 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6295 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
6296 int rc = VINF_SUCCESS;
6297
6298 Log(("%s:\n", __FUNCTION__));
6299
6300 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
6301
6302 if (!pAhciPort->fAsyncInterface)
6303 {
6304 int rcThread;
6305 /* Destroy the thread. */
6306 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
6307 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
6308 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
6309
6310 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
6311 if (RT_FAILURE(rc))
6312 AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
6313 }
6314
6315 /*
6316 * Zero some important members.
6317 */
6318 pAhciPort->pDrvBase = NULL;
6319 pAhciPort->pDrvBlock = NULL;
6320 pAhciPort->pDrvBlockAsync = NULL;
6321 pAhciPort->pDrvBlockBios = NULL;
6322}
6323
6324/**
6325 * Attach command.
6326 *
6327 * This is called when we change block driver for one port.
6328 * The VM is suspended at this point.
6329 *
6330 * @returns VBox status code.
6331 * @param pDevIns The device instance.
6332 * @param iLUN The logical unit which is being detached.
6333 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
6334 */
6335static DECLCALLBACK(int) ahciAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
6336{
6337 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6338 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
6339 int rc;
6340
6341 Log(("%s:\n", __FUNCTION__));
6342
6343 /* the usual paranoia */
6344 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
6345 AssertRelease(!pAhciPort->pDrvBase);
6346 AssertRelease(!pAhciPort->pDrvBlock);
6347 AssertRelease(!pAhciPort->pDrvBlockAsync);
6348 Assert(pAhciPort->iLUN == iLUN);
6349
6350 /*
6351 * Try attach the block device and get the interfaces,
6352 * required as well as optional.
6353 */
6354 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
6355 if (RT_SUCCESS(rc))
6356 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6357 else
6358 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
6359
6360 if (RT_FAILURE(rc))
6361 {
6362 pAhciPort->pDrvBase = NULL;
6363 pAhciPort->pDrvBlock = NULL;
6364 }
6365 else
6366 {
6367 char szName[24];
6368 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
6369
6370 if (pAhciPort->pDrvBlockAsync)
6371 {
6372 pAhciPort->fAsyncInterface = true;
6373 }
6374 else
6375 {
6376 pAhciPort->fAsyncInterface = false;
6377
6378 /* Create event semaphore. */
6379 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6380 if (RT_FAILURE(rc))
6381 {
6382 Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
6383 return rc;
6384 }
6385
6386 /* Create the async IO thread. */
6387 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6388 RTTHREADTYPE_IO, szName);
6389 if (RT_FAILURE(rc))
6390 {
6391 AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
6392 return rc;
6393 }
6394 }
6395 }
6396
6397 return rc;
6398}
6399
6400/**
6401 * Common reset worker.
6402 *
6403 * @param pDevIns The device instance data.
6404 */
6405static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
6406{
6407 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6408
6409 ahciHBAReset(pAhci);
6410
6411 /* Hardware reset for the ports. */
6412 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
6413 ahciPortHwReset(&pAhci->ahciPort[i]);
6414
6415 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6416 ataControllerReset(&pAhci->aCts[i]);
6417 return VINF_SUCCESS;
6418}
6419
6420/**
6421 * Callback employed by ahciReset.
6422 *
6423 * @returns true if we've quiesced, false if we're still working.
6424 * @param pDevIns The device instance.
6425 */
6426static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
6427{
6428 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6429
6430 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
6431 return false;
6432 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
6433
6434 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
6435 return true;
6436}
6437
6438/**
6439 * Reset notification.
6440 *
6441 * @param pDevIns The device instance data.
6442 */
6443static DECLCALLBACK(void) ahciReset(PPDMDEVINS pDevIns)
6444{
6445 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6446
6447 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
6448 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
6449 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
6450 else
6451 {
6452 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
6453 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
6454 }
6455}
6456
6457/**
6458 * Poweroff notification.
6459 *
6460 * @returns nothing
6461 * @param pDevIns Pointer to the device instance
6462 */
6463static DECLCALLBACK(void) ahciPowerOff(PPDMDEVINS pDevIns)
6464{
6465 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6466
6467 ahciR3SuspendOrPowerOff(pDevIns);
6468
6469 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6470 ataControllerPowerOff(&pAhci->aCts[i]);
6471}
6472
6473/**
6474 * Construct a device instance for a VM.
6475 *
6476 * @returns VBox status.
6477 * @param pDevIns The device instance data.
6478 * If the registration structure is needed, pDevIns->pDevReg points to it.
6479 * @param iInstance Instance number. Use this to figure out which registers and such to use.
6480 * The device number is also found in pDevIns->iInstance, but since it's
6481 * likely to be freqently used PDM passes it as parameter.
6482 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
6483 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
6484 * iInstance it's expected to be used a bit in this function.
6485 */
6486static DECLCALLBACK(int) ahciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
6487{
6488 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6489 PPDMIBASE pBase;
6490 int rc = VINF_SUCCESS;
6491 unsigned i = 0;
6492 bool fGCEnabled = false;
6493 bool fR0Enabled = false;
6494 uint32_t cbTotalBufferSize = 0;
6495
6496 /*
6497 * Validate and read configuration.
6498 */
6499 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0"
6500 "R0Enabled\0"
6501 "PrimaryMaster\0"
6502 "PrimarySlave\0"
6503 "SecondaryMaster\0"
6504 "SecondarySlave\0"
6505 "PortCount\0"
6506 "UseAsyncInterfaceIfAvailable\0"
6507 "HighIOThreshold\0"
6508 "MillisToSleep\0"))
6509 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6510 N_("AHCI configuration error: unknown option specified"));
6511
6512 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
6513 if (RT_FAILURE(rc))
6514 return PDMDEV_SET_ERROR(pDevIns, rc,
6515 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
6516 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
6517
6518 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
6519 if (RT_FAILURE(rc))
6520 return PDMDEV_SET_ERROR(pDevIns, rc,
6521 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
6522 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
6523
6524 rc = CFGMR3QueryU32Def(pCfgHandle, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6525 if (RT_FAILURE(rc))
6526 return PDMDEV_SET_ERROR(pDevIns, rc,
6527 N_("AHCI configuration error: failed to read PortCount as integer"));
6528 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
6529 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
6530 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6531 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
6532 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6533 if (pThis->cPortsImpl < 1)
6534 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6535 N_("AHCI configuration error: PortCount=%u should be at least 1"),
6536 pThis->cPortsImpl);
6537
6538 rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6539 if (RT_FAILURE(rc))
6540 return PDMDEV_SET_ERROR(pDevIns, rc,
6541 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6542 rc = CFGMR3QueryU32Def(pCfgHandle, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6543 if (RT_FAILURE(rc))
6544 return PDMDEV_SET_ERROR(pDevIns, rc,
6545 N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
6546 rc = CFGMR3QueryU32Def(pCfgHandle, "MillisToSleep", &pThis->cMillisToSleep, 0);
6547 if (RT_FAILURE(rc))
6548 return PDMDEV_SET_ERROR(pDevIns, rc,
6549 N_("AHCI configuration error: failed to read MillisToSleep as integer"));
6550
6551 pThis->fR0Enabled = fR0Enabled;
6552 pThis->fGCEnabled = fGCEnabled;
6553 pThis->pDevInsR3 = pDevIns;
6554 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6555 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6556
6557 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
6558 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
6559 PCIDevSetCommand (&pThis->dev, 0x0000);
6560 PCIDevSetRevisionId (&pThis->dev, 0x02);
6561 PCIDevSetClassProg (&pThis->dev, 0x01);
6562 PCIDevSetClassSub (&pThis->dev, 0x06);
6563 PCIDevSetClassBase (&pThis->dev, 0x01);
6564 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
6565
6566 pThis->dev.config[0x34] = 0x80; /* Capability pointer. */
6567
6568 PCIDevSetInterruptLine(&pThis->dev, 0x00);
6569 PCIDevSetInterruptPin (&pThis->dev, 0x01);
6570
6571 pThis->dev.config[0x70] = 0x01; /* Capability ID: PCI Power Management Interface */
6572 pThis->dev.config[0x71] = 0x00;
6573 pThis->dev.config[0x72] = 0x03;
6574
6575 pThis->dev.config[0x80] = 0x05; /* Capability ID: Message Signaled Interrupts. Disabled. */
6576 pThis->dev.config[0x81] = 0x70; /* next. */
6577
6578 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
6579 pThis->dev.config[0x92] = 0x3f;
6580 pThis->dev.config[0x94] = 0x80;
6581 pThis->dev.config[0x95] = 0x01;
6582 pThis->dev.config[0x97] = 0x78;
6583
6584 /*
6585 * Register the PCI device, it's I/O regions.
6586 */
6587 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
6588 if (RT_FAILURE(rc))
6589 return rc;
6590
6591 /*
6592 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
6593 * IDE registers are not available.
6594 * We set up "fake" entries in the PCI configuration register.
6595 * That means they are available but read and writes from/to them have no effect.
6596 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
6597 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
6598 * to switch to it which also changes device Id and other things in the PCI configuration space).
6599 */
6600 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6601 if (RT_FAILURE(rc))
6602 return PDMDEV_SET_ERROR(pDevIns, rc,
6603 N_("AHCI cannot register PCI I/O region"));
6604
6605 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6606 if (RT_FAILURE(rc))
6607 return PDMDEV_SET_ERROR(pDevIns, rc,
6608 N_("AHCI cannot register PCI I/O region"));
6609
6610 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6611 if (RT_FAILURE(rc))
6612 return PDMDEV_SET_ERROR(pDevIns, rc,
6613 N_("AHCI cannot register PCI I/O region"));
6614
6615 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6616 if (RT_FAILURE(rc))
6617 return PDMDEV_SET_ERROR(pDevIns, rc,
6618 N_("AHCI cannot register PCI I/O region"));
6619
6620 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6621 if (RT_FAILURE(rc))
6622 return PDMDEV_SET_ERROR(pDevIns, rc,
6623 N_("AHCI cannot register PCI I/O region for BMDMA"));
6624
6625 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciMMIOMap);
6626 if (RT_FAILURE(rc))
6627 return PDMDEV_SET_ERROR(pDevIns, rc,
6628 N_("AHCI cannot register PCI memory region for registers"));
6629
6630 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, "AHCI");
6631 if (RT_FAILURE(rc))
6632 {
6633 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6634 return rc;
6635 }
6636
6637 /* Create the timer for command completion coalescing feature. */
6638 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ahciCccTimer, pThis,
6639 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
6640 if (RT_FAILURE(rc))
6641 {
6642 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
6643 return rc;
6644 }
6645 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
6646 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
6647
6648 /* Status LUN. */
6649 pThis->IBase.pfnQueryInterface = ahciStatus_QueryInterface;
6650 pThis->ILeds.pfnQueryStatusLed = ahciStatus_QueryStatusLed;
6651
6652 /*
6653 * Create the transmit queue.
6654 */
6655 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6656 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6657 if (RT_FAILURE(rc))
6658 return rc;
6659 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
6660 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
6661
6662 /* Initialize static members on every port. */
6663 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6664 {
6665 /*
6666 * Init members of the port.
6667 */
6668 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6669 pAhciPort->pDevInsR3 = pDevIns;
6670 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6671 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6672 pAhciPort->iLUN = i;
6673 pAhciPort->pAhciR3 = pThis;
6674 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
6675 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
6676 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
6677 pAhciPort->pDrvBase = NULL;
6678
6679 /* Register statistics counter. */
6680 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6681 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
6682 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6683 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
6684 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6685 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
6686 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6687 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
6688#ifdef VBOX_WITH_STATISTICS
6689 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6690 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
6691 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6692 "Amount of time to map the guest buffers into R3.", "/Devices/SATA%d/Port%d/ProfileMapIntoR3", iInstance, i);
6693 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6694 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
6695 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6696 "Amount of time to destroy the scatter gather list and free associated ressources.", "/Devices/SATA%d/Port%d/ProfileDestroyScatterGatherList", iInstance, i);
6697#endif
6698
6699 ahciPortHwReset(pAhciPort);
6700 }
6701
6702 /* Attach drivers to every available port. */
6703 for (i = 0; i < pThis->cPortsImpl; i++)
6704 {
6705 char szName[24];
6706 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
6707
6708 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6709 /*
6710 * Init interfaces.
6711 */
6712 pAhciPort->IBase.pfnQueryInterface = ahciPortQueryInterface;
6713 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciTransferCompleteNotify;
6714 pAhciPort->IMountNotify.pfnMountNotify = ahciMountNotify;
6715 pAhciPort->IMountNotify.pfnUnmountNotify = ahciUnmountNotify;
6716 pAhciPort->fAsyncIOThreadIdle = true;
6717
6718 /*
6719 * Attach the block driver
6720 */
6721 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
6722 if (RT_SUCCESS(rc))
6723 {
6724 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6725 if (RT_FAILURE(rc))
6726 {
6727 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
6728 return rc;
6729 }
6730
6731 /* Mark that a device is present on that port */
6732 if (i < 6)
6733 pThis->dev.config[0x93] |= (1 << i);
6734
6735 /*
6736 * Init vendor product data.
6737 */
6738 /* Generate a default serial number. */
6739 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
6740 RTUUID Uuid;
6741 if (pAhciPort->pDrvBlock)
6742 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
6743 else
6744 RTUuidClear(&Uuid);
6745
6746 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
6747 {
6748 /* Generate a predictable serial for drives which don't have a UUID. */
6749 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
6750 pAhciPort->iLUN);
6751 }
6752 else
6753 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
6754
6755 /* Get user config if present using defaults otherwise. */
6756 PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, szName);
6757 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
6758 szSerial);
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: \"SerialNumber\" is longer than 20 bytes"));
6764 return PDMDEV_SET_ERROR(pDevIns, rc,
6765 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
6766 }
6767
6768 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
6769 "1.0");
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: \"FirmwareRevision\" is longer than 8 bytes"));
6775 return PDMDEV_SET_ERROR(pDevIns, rc,
6776 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
6777 }
6778
6779 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
6780 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
6781 if (RT_FAILURE(rc))
6782 {
6783 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6784 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6785 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
6786 return PDMDEV_SET_ERROR(pDevIns, rc,
6787 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
6788 }
6789
6790 /* There are three other identification strings for CD drives used for INQUIRY */
6791 if (pAhciPort->fATAPI)
6792 {
6793 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
6794 "VBOX");
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: \"ATAPIVendorId\" is longer than 16 bytes"));
6800 return PDMDEV_SET_ERROR(pDevIns, rc,
6801 N_("PIIX3 configuration error: failed to read \"ATAPIVendorId\" as string"));
6802 }
6803
6804 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
6805 "CD-ROM");
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: \"ATAPIProductId\" is longer than 16 bytes"));
6811 return PDMDEV_SET_ERROR(pDevIns, rc,
6812 N_("PIIX3 configuration error: failed to read \"ATAPIProductId\" as string"));
6813 }
6814
6815 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
6816 "1.0");
6817 if (RT_FAILURE(rc))
6818 {
6819 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6820 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6821 N_("PIIX3 configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
6822 return PDMDEV_SET_ERROR(pDevIns, rc,
6823 N_("PIIX3 configuration error: failed to read \"ATAPIRevision\" as string"));
6824 }
6825 }
6826
6827 /*
6828 * If the new async interface is available we use a PDMQueue to transmit
6829 * the requests into R3.
6830 * Otherwise we use a event semaphore and a async I/O thread which processes them.
6831 */
6832 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
6833 {
6834 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
6835 pAhciPort->fAsyncInterface = true;
6836 }
6837 else
6838 {
6839 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
6840 pAhciPort->fAsyncInterface = false;
6841
6842 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6843 AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
6844
6845
6846 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6847 RTTHREADTYPE_IO, szName);
6848 AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
6849 }
6850 }
6851 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
6852 {
6853 pAhciPort->pDrvBase = NULL;
6854 rc = VINF_SUCCESS;
6855 LogRel(("%s: no driver attached\n", szName));
6856 }
6857 else
6858 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6859 N_("AHCI: Failed to attach drive to %s"), szName);
6860
6861#ifdef DEBUG
6862 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
6863 pAhciPort->ahciIOTasks[i] = 0xff;
6864#endif
6865 }
6866
6867 /*
6868 * Attach status driver (optional).
6869 */
6870 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
6871 if (RT_SUCCESS(rc))
6872 pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
6873 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
6874 {
6875 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
6876 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
6877 }
6878
6879 /*
6880 * Setup IDE emulation.
6881 * We only emulate the I/O ports but not bus master DMA.
6882 * If the configuration values are not found the setup of the ports is as follows:
6883 * Primary Master: Port 0
6884 * Primary Slave: Port 1
6885 * Secondary Master: Port 2
6886 * Secondary Slave: Port 3
6887 */
6888
6889 /*
6890 * Setup I/O ports for the PCI device.
6891 */
6892 pThis->aCts[0].irq = 12;
6893 pThis->aCts[0].IOPortBase1 = 0x1e8;
6894 pThis->aCts[0].IOPortBase2 = 0x3e6;
6895 pThis->aCts[1].irq = 11;
6896 pThis->aCts[1].IOPortBase1 = 0x168;
6897 pThis->aCts[1].IOPortBase2 = 0x366;
6898
6899 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6900 {
6901 PAHCIATACONTROLLER pCtl = &pThis->aCts[i];
6902 uint32_t iPortMaster, iPortSlave;
6903 uint32_t cbSSMState = 0;
6904 static const char *s_apszDescs[RT_ELEMENTS(pThis->aCts)][RT_ELEMENTS(pCtl->aIfs)] =
6905 {
6906 { "PrimaryMaster", "PrimarySlave" },
6907 { "SecondaryMaster", "SecondarySlave" }
6908 };
6909
6910 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][0], &iPortMaster, 2 * i);
6911 if (RT_FAILURE(rc))
6912 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6913 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
6914
6915 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
6916 if (RT_FAILURE(rc))
6917 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6918 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);
6919
6920 char szName[24];
6921 RTStrPrintf(szName, sizeof(szName), "EmulatedATA%d", i);
6922 rc = ataControllerInit(pDevIns, pCtl, pThis->ahciPort[iPortMaster].pDrvBase, pThis->ahciPort[iPortSlave].pDrvBase,
6923 &cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led, &pThis->ahciPort[iPortMaster].StatBytesRead,
6924 &pThis->ahciPort[iPortMaster].StatBytesWritten);
6925 if (RT_FAILURE(rc))
6926 return rc;
6927
6928 cbTotalBufferSize += cbSSMState;
6929
6930 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase1, 8, (RTHCPTR)i,
6931 ahciIOPortWrite1, ahciIOPortRead1, ahciIOPortWriteStr1, ahciIOPortReadStr1, "AHCI");
6932 if (RT_FAILURE(rc))
6933 return rc;
6934
6935 if (pThis->fR0Enabled)
6936 {
6937 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase1, 8, (RTR0PTR)i,
6938 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI R0");
6939 if (RT_FAILURE(rc))
6940 return rc;
6941 }
6942
6943 if (pThis->fGCEnabled)
6944 {
6945 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
6946 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI GC");
6947 if (RT_FAILURE(rc))
6948 return rc;
6949 }
6950
6951 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase2, 1, (RTHCPTR)i,
6952 ahciIOPortWrite2, ahciIOPortRead2, NULL, NULL, "AHCI");
6953 if (RT_FAILURE(rc))
6954 return rc;
6955
6956 if (pThis->fR0Enabled)
6957 {
6958 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase2, 1, (RTR0PTR)i,
6959 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI R0");
6960 if (RT_FAILURE(rc))
6961 return rc;
6962 }
6963
6964 if (pThis->fGCEnabled)
6965 {
6966 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
6967 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI GC");
6968 if (RT_FAILURE(rc))
6969 return rc;
6970 }
6971 }
6972
6973 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
6974 NULL, ahciLiveExec, NULL,
6975 ahciSavePrep, ahciSaveExec, NULL,
6976 ahciLoadPrep, ahciLoadExec, NULL);
6977 if (RT_FAILURE(rc))
6978 return rc;
6979
6980 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
6981}
6982
6983/**
6984 * The device registration structure.
6985 */
6986const PDMDEVREG g_DeviceAHCI =
6987{
6988 /* u32Version */
6989 PDM_DEVREG_VERSION,
6990 /* szDeviceName */
6991 "ahci",
6992 /* szRCMod */
6993 "VBoxDDGC.gc",
6994 /* szR0Mod */
6995 "VBoxDDR0.r0",
6996 /* pszDescription */
6997 "Intel AHCI controller.\n",
6998 /* fFlags */
6999 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
7000 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
7001 /* fClass */
7002 PDM_DEVREG_CLASS_STORAGE,
7003 /* cMaxInstances */
7004 ~0,
7005 /* cbInstance */
7006 sizeof(AHCI),
7007 /* pfnConstruct */
7008 ahciConstruct,
7009 /* pfnDestruct */
7010 ahciDestruct,
7011 /* pfnRelocate */
7012 ahciRelocate,
7013 /* pfnIOCtl */
7014 NULL,
7015 /* pfnPowerOn */
7016 NULL,
7017 /* pfnReset */
7018 ahciReset,
7019 /* pfnSuspend */
7020 ahciSuspend,
7021 /* pfnResume */
7022 ahciResume,
7023 /* pfnAttach */
7024 ahciAttach,
7025 /* pfnDetach */
7026 ahciDetach,
7027 /* pfnQueryInterface. */
7028 NULL,
7029 /* pfnInitComplete */
7030 NULL,
7031 /* pfnPowerOff */
7032 ahciPowerOff,
7033 /* pfnSoftReset */
7034 NULL,
7035 /* u32VersionEnd */
7036 PDM_DEVREG_VERSION
7037};
7038
7039#endif /* IN_RING3 */
7040#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