VirtualBox

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

Last change on this file since 46155 was 45649, checked in by vboxsync, 11 years ago

Eliminated leftover variable.

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

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