VirtualBox

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

Last change on this file since 33214 was 33214, checked in by vboxsync, 14 years ago

AHCI: put MSI in place which allows to avoid conflicts

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