VirtualBox

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

最後變更 在這個檔案從23913是 23469,由 vboxsync 提交於 15 年 前

AHCI: Add the instance number to the statistics path

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette