VirtualBox

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

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

Changed FNIOMMMIOWRITE to take a const buffer pointer.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette