VirtualBox

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

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

Storage/DevATA+DevAHCI+ATAController: make assertion less strict, locked media and double unmount are harmless

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

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