VirtualBox

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

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

AHCI: Error reporting fix

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

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