VirtualBox

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

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

Device/AHCI: 32bit alignment fixes

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