VirtualBox

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

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

AHCI: Implement suspend on error for the async I/O path

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