VirtualBox

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

Last change on this file since 46757 was 46738, checked in by vboxsync, 12 years ago

AHCI: Consistent logging prefix

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