VirtualBox

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

最後變更 在這個檔案從43596是 43596,由 vboxsync 提交於 12 年 前

AHCI: Use new code for ATAPI passthrough

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

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