VirtualBox

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

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

Devices/Storage: Introduce Bootable CFGM key to enable BIOS access

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