VirtualBox

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

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

Storage/ATA+AHCI: support the non-rotational medium flag

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