VirtualBox

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

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

AHCI: Fix 64bit build

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