VirtualBox

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

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

Storage/AHCI: check the correct return code when unmounting a SATA CDROM; coding style

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