VirtualBox

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

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

AHCI: Fixes for hotplugging

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