VirtualBox

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

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

AHCI: Add additional VPD keys

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