VirtualBox

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

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

one more

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

© 2023 Oracle
ContactPrivacy policyTerms of Use