VirtualBox

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

Last change on this file since 38969 was 38969, checked in by vboxsync, 13 years ago

AHCI: Log HBA and port resets to the release log

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

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