VirtualBox

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

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

Devices: more -Wshadow

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