VirtualBox

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

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

AHCI: Support access through the index/data register pair from the I/O port space (as described in 10.14 of the AHCI 1.2 spec). Required for the BIOS driver

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