VirtualBox

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

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

DevAHCI: Do not let the guest trash PxCMD.CCS bits. Fixes XP SATA CD-ROMs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 318.0 KB
Line 
1/* $Id: DevAHCI.cpp 50037 2014-01-09 13:38:27Z 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 }
4178 break;
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 rc = 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 }
4406 break;
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 rc = AHCITXDIR_READ;
4466 }
4467 break;
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 rc = AHCITXDIR_READ;
4515 break;
4516 case 0xf8:
4517 /* read all data */
4518 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
4519 rc = 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 }
4527 break;
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 }
4561 break;
4562 case SCSI_START_STOP_UNIT:
4563 {
4564 int rc2 = 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 rc2 = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4577 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4578 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4579 Assert(RT_SUCCESS(rc2) || (rc2 == VERR_PDM_MEDIA_LOCKED) || (rc2 = VERR_PDM_MEDIA_NOT_MOUNTED));
4580 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4581 {
4582 rc2 = 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(rc2))
4594 atapiCmdOK(pAhciPort, pAhciReq);
4595 else
4596 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4597 }
4598 break;
4599 case SCSI_MECHANISM_STATUS:
4600 {
4601 cbMax = ataBE2H_U16(pbPacket + 8);
4602 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4603 }
4604 break;
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 }
4642 break;
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 rc;
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 rc = 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 rc = AHCITXDIR_FLUSH;
6113 break;
6114 case 0x03:
6115 { /* set transfer mode */
6116 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6117 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
6118 {
6119 case 0x00: /* PIO default */
6120 case 0x08: /* PIO mode */
6121 break;
6122 case ATA_MODE_MDMA: /* MDMA mode */
6123 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
6124 break;
6125 case ATA_MODE_UDMA: /* UDMA mode */
6126 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6127 break;
6128 }
6129 break;
6130 }
6131 default:
6132 pAhciReq->uATARegError = ABRT_ERR;
6133 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6134 }
6135 break;
6136 }
6137 case ATA_DEVICE_RESET:
6138 {
6139 if (!pAhciPort->fATAPI)
6140 {
6141 pAhciReq->uATARegError = ABRT_ERR;
6142 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6143 }
6144 else
6145 {
6146 /* Reset the device. */
6147 ahciDeviceReset(pAhciPort, pAhciReq);
6148 }
6149 break;
6150 }
6151 case ATA_FLUSH_CACHE_EXT:
6152 case ATA_FLUSH_CACHE:
6153 rc = AHCITXDIR_FLUSH;
6154 break;
6155 case ATA_PACKET:
6156 if (!pAhciPort->fATAPI)
6157 {
6158 pAhciReq->uATARegError = ABRT_ERR;
6159 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6160 }
6161 else
6162 rc = atapiParseCmd(pAhciPort, pAhciReq);
6163 break;
6164 case ATA_IDENTIFY_PACKET_DEVICE:
6165 if (!pAhciPort->fATAPI)
6166 {
6167 pAhciReq->uATARegError = ABRT_ERR;
6168 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6169 }
6170 else
6171 {
6172 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6173
6174 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6175 pAhciReq->uATARegError = 0;
6176 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6177 }
6178 break;
6179 case ATA_SET_MULTIPLE_MODE:
6180 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
6181 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
6182 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6183 {
6184 pAhciReq->uATARegError = ABRT_ERR;
6185 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6186 }
6187 else
6188 {
6189 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6190 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6191 pAhciReq->uATARegError = 0;
6192 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6193 }
6194 break;
6195 case ATA_STANDBY_IMMEDIATE:
6196 break; /* Do nothing. */
6197 case ATA_CHECK_POWER_MODE:
6198 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
6199 /* fall through */
6200 case ATA_INITIALIZE_DEVICE_PARAMETERS:
6201 case ATA_IDLE_IMMEDIATE:
6202 case ATA_RECALIBRATE:
6203 case ATA_NOP:
6204 case ATA_READ_VERIFY_SECTORS_EXT:
6205 case ATA_READ_VERIFY_SECTORS:
6206 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
6207 case ATA_SLEEP:
6208 pAhciReq->uATARegError = 0;
6209 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6210 break;
6211 case ATA_READ_DMA_EXT:
6212 fLBA48 = true;
6213 case ATA_READ_DMA:
6214 {
6215 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6216 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6217 rc = AHCITXDIR_READ;
6218 break;
6219 }
6220 case ATA_WRITE_DMA_EXT:
6221 fLBA48 = true;
6222 case ATA_WRITE_DMA:
6223 {
6224 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6225 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6226 rc = AHCITXDIR_WRITE;
6227 break;
6228 }
6229 case ATA_READ_FPDMA_QUEUED:
6230 {
6231 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6232 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6233 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6234 rc = AHCITXDIR_READ;
6235 break;
6236 }
6237 case ATA_WRITE_FPDMA_QUEUED:
6238 {
6239 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6240 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6241 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6242 rc = AHCITXDIR_WRITE;
6243 break;
6244 }
6245 case ATA_READ_LOG_EXT:
6246 {
6247 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6248 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6249 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6250 size_t cbCopied;
6251
6252 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6253
6254 uint8_t aBuf[512];
6255
6256 memset(aBuf, 0, sizeof(aBuf));
6257
6258 if (offLogRead + cbLogRead <= sizeof(aBuf))
6259 {
6260 switch (iPage)
6261 {
6262 case 0x10:
6263 {
6264 LogFlow(("Reading error page\n"));
6265 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6266 if (pTaskErr)
6267 {
6268 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6269 aBuf[2] = pTaskErr->uATARegStatus;
6270 aBuf[3] = pTaskErr->uATARegError;
6271 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6272 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6273 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6274 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6275 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6276 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6277 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6278 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6279 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6280
6281 /* Calculate checksum */
6282 uint8_t uChkSum = 0;
6283 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6284 uChkSum += aBuf[i];
6285
6286 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6287
6288 /*
6289 * Reading this log page results in an abort of all outstanding commands
6290 * and clearing the SActive register and TaskFile register.
6291 */
6292 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6293 }
6294 break;
6295 }
6296 }
6297
6298 /* Copy the buffer. */
6299 cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6300 &aBuf[offLogRead], cbLogRead);
6301
6302 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6303 pAhciReq->cbTransfer = cbCopied;
6304 }
6305
6306 break;
6307 }
6308 case ATA_DATA_SET_MANAGEMENT:
6309 {
6310 if ( ( !pAhciPort->fAsyncInterface
6311 && pAhciPort->pDrvBlock->pfnDiscard)
6312 || ( pAhciPort->fAsyncInterface
6313 && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
6314 {
6315 /* Check that the trim bit is set and all other bits are 0. */
6316 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6317 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6318 {
6319 pAhciReq->uATARegError = ABRT_ERR;
6320 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6321 }
6322 else
6323 rc = AHCITXDIR_TRIM;
6324 break;
6325 }
6326 /* else: fall through and report error to the guest. */
6327 }
6328 /* All not implemented commands go below. */
6329 case ATA_SECURITY_FREEZE_LOCK:
6330 case ATA_SMART:
6331 case ATA_NV_CACHE:
6332 case ATA_IDLE:
6333 pAhciReq->uATARegError = ABRT_ERR;
6334 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6335 break;
6336 default: /* For debugging purposes. */
6337 AssertMsgFailed(("Unknown command issued\n"));
6338 pAhciReq->uATARegError = ABRT_ERR;
6339 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6340 }
6341
6342 return rc;
6343}
6344
6345/**
6346 * Retrieve a command FIS from guest memory.
6347 *
6348 * @returns whether the H2D FIS was successfully read from the guest memory.
6349 * @param pAhciReq The state of the actual task.
6350 */
6351static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6352{
6353 RTGCPHYS GCPhysAddrCmdTbl;
6354
6355 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
6356 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
6357 false);
6358
6359 /*
6360 * First we are reading the command header pointed to by regCLB.
6361 * From this we get the address of the command table which we are reading too.
6362 * We can process the Command FIS afterwards.
6363 */
6364 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6365 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6366 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6367 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6368
6369#ifdef LOG_ENABLED
6370 /* Print some infos about the command header. */
6371 ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
6372#endif
6373
6374 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
6375
6376 AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6377 ("This is not a command FIS!!\n"),
6378 false);
6379
6380 /* Read the command Fis. */
6381 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6382 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6383
6384 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
6385 ("This is not a command FIS\n"),
6386 false);
6387
6388 /* Set transfer direction. */
6389 pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
6390
6391 /* If this is an ATAPI command read the atapi command. */
6392 if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6393 {
6394 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6395 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6396 }
6397
6398 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6399 if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6400 {
6401 /*
6402 * 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.
6403 * but this FIS does not assert an interrupt
6404 */
6405 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6406 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6407 }
6408
6409 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6410 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
6411
6412#ifdef LOG_ENABLED
6413 /* Print some infos about the FIS. */
6414 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6415
6416 /* Print the PRDT */
6417 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6418 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6419
6420 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6421 {
6422 SGLEntry SGEntry;
6423
6424 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6425 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6426
6427 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6428 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6429
6430 GCPhysPrdtl += sizeof(SGLEntry);
6431 }
6432#endif
6433
6434 return true;
6435}
6436
6437/**
6438 * Transmit queue consumer
6439 * Queue a new async task.
6440 *
6441 * @returns Success indicator.
6442 * If false the item will not be removed and the flushing will stop.
6443 * @param pDevIns The device instance.
6444 * @param pItem The item to consume. Upon return this item will be freed.
6445 */
6446static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6447{
6448 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6449 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6450 PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
6451 int rc = VINF_SUCCESS;
6452
6453 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6454 /* Notify the async IO thread. */
6455 rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6456 AssertRC(rc);
6457
6458 return true;
6459}
6460
6461/* The async IO thread for one port. */
6462static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6463{
6464 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6465 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6466 int rc = VINF_SUCCESS;
6467 uint64_t u64StartTime = 0;
6468 uint64_t u64StopTime = 0;
6469 uint32_t uIORequestsProcessed = 0;
6470 uint32_t uIOsPerSec = 0;
6471 uint32_t fTasksToProcess = 0;
6472
6473 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6474
6475 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6476 return VINF_SUCCESS;
6477
6478 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6479 {
6480 unsigned idx = 0;
6481 uint32_t u32Tasks = 0;
6482 uint32_t u32RegHbaCtrl = 0;
6483
6484 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
6485 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6486 if (!u32Tasks)
6487 {
6488 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
6489 rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
6490 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
6491 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
6492 break;
6493 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
6494 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6495 }
6496
6497 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
6498 ASMAtomicIncU32(&pAhci->cThreadsActive);
6499
6500 /*
6501 * Check whether the global host controller bit is set and go to sleep immediately again
6502 * if it is set.
6503 */
6504 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6505 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
6506 && !ASMAtomicDecU32(&pAhci->cThreadsActive))
6507 {
6508 ahciHBAReset(pAhci);
6509 continue;
6510 }
6511
6512 idx = ASMBitFirstSetU32(u32Tasks);
6513 while (idx)
6514 {
6515 AHCITXDIR enmTxDir;
6516 PAHCIREQ pAhciReq;
6517
6518 /* Decrement to get the slot number. */
6519 idx--;
6520 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6521
6522 /*
6523 * Check if there is already an allocated task struct in the cache.
6524 * Allocate a new task otherwise.
6525 */
6526 if (!pAhciPort->aCachedTasks[idx])
6527 {
6528 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6529 AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n"));
6530 pAhciReq->enmTxState = AHCITXSTATE_FREE;
6531 pAhciPort->aCachedTasks[idx] = pAhciReq;
6532 }
6533 else
6534 pAhciReq = pAhciPort->aCachedTasks[idx];
6535
6536 bool fXchg;
6537 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE, fXchg);
6538 AssertMsg(fXchg, ("Task is already active\n"));
6539
6540 pAhciReq->tsStart = RTTimeMilliTS();
6541 pAhciReq->uATARegStatus = 0;
6542 pAhciReq->uATARegError = 0;
6543 pAhciReq->fFlags = 0;
6544
6545 /* Set current command slot */
6546 pAhciReq->uTag = idx;
6547 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6548
6549 bool fFisRead = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6550 if (RT_UNLIKELY(!fFisRead))
6551 {
6552 /*
6553 * Couldn't find anything in either the AHCI or SATA spec which
6554 * indicates what should be done if the FIS is not read successfully.
6555 * The closest thing is in the state machine, stating that the device
6556 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
6557 * Do the same here and ignore any corrupt FIS types, after all
6558 * the guest messed up everything and this behavior is undefined.
6559 */
6560 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6561 Assert(fXchg);
6562 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6563 idx = ASMBitFirstSetU32(u32Tasks);
6564 continue;
6565 }
6566
6567 /* 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. */
6568 if (pAhciPort->regSACT & (1 << idx))
6569 {
6570 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6571 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
6572 }
6573
6574 if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
6575 {
6576 /* If the reset bit is set put the device into reset state. */
6577 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6578 {
6579 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6580 pAhciPort->fResetDevice = true;
6581 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6582 }
6583 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6584 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6585 else /* We are not in a reset state update the control registers. */
6586 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6587
6588 ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6589 AssertMsg(fXchg, ("Task is not active\n"));
6590 break;
6591 }
6592 else
6593 {
6594 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
6595 ("There are more than 32 requests active"));
6596 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6597
6598 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6599 pAhciReq->enmTxDir = enmTxDir;
6600
6601 if (enmTxDir != AHCITXDIR_NONE)
6602 {
6603 if ( enmTxDir != AHCITXDIR_FLUSH
6604 && enmTxDir != AHCITXDIR_TRIM)
6605 {
6606 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6607
6608 rc = ahciIoBufAllocate(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->cbTransfer);
6609 if (RT_FAILURE(rc))
6610 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
6611 }
6612
6613 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6614 {
6615 if (pAhciPort->fAsyncInterface)
6616 {
6617 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);
6618 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);
6619 if (enmTxDir == AHCITXDIR_FLUSH)
6620 {
6621 rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
6622 pAhciReq);
6623 }
6624 else if (enmTxDir == AHCITXDIR_TRIM)
6625 {
6626 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6627 if (RT_SUCCESS(rc))
6628 {
6629 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6630 rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
6631 pAhciReq->u.Trim.cRanges, pAhciReq);
6632 }
6633 }
6634 else if (enmTxDir == AHCITXDIR_READ)
6635 {
6636 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6637 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6638 &pAhciReq->u.Io.DataSeg, 1,
6639 pAhciReq->cbTransfer,
6640 pAhciReq);
6641 }
6642 else
6643 {
6644 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6645 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6646 &pAhciReq->u.Io.DataSeg, 1,
6647 pAhciReq->cbTransfer,
6648 pAhciReq);
6649 }
6650 if (rc == VINF_VD_ASYNC_IO_FINISHED)
6651 rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6652 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6653 rc = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
6654 }
6655 else
6656 {
6657 if (enmTxDir == AHCITXDIR_FLUSH)
6658 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
6659 else if (enmTxDir == AHCITXDIR_TRIM)
6660 {
6661 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6662 if (RT_SUCCESS(rc))
6663 {
6664 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6665 rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock, pAhciReq->u.Trim.paRanges,
6666 pAhciReq->u.Trim.cRanges);
6667 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6668 }
6669 }
6670 else if (enmTxDir == AHCITXDIR_READ)
6671 {
6672 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6673 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, pAhciReq->uOffset,
6674 pAhciReq->u.Io.DataSeg.pvSeg,
6675 pAhciReq->cbTransfer);
6676 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;
6677 }
6678 else
6679 {
6680 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6681 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, pAhciReq->uOffset,
6682 pAhciReq->u.Io.DataSeg.pvSeg,
6683 pAhciReq->cbTransfer);
6684 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6685 }
6686 rc = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
6687 }
6688 }
6689 }
6690 else
6691 rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
6692 } /* Command */
6693
6694 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6695 idx = ASMBitFirstSetU32(u32Tasks);
6696 } /* while tasks available */
6697
6698 /*
6699 * Check whether a host controller reset is pending and execute the reset
6700 * if this is the last active thread.
6701 */
6702 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6703 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
6704 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
6705 && !cThreadsActive)
6706 ahciHBAReset(pAhci);
6707 } /* While running */
6708
6709 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
6710 return VINF_SUCCESS;
6711}
6712
6713/**
6714 * Unblock the async I/O thread so it can respond to a state change.
6715 *
6716 * @returns VBox status code.
6717 * @param pDevIns The device instance.
6718 * @param pThread The send thread.
6719 */
6720static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6721{
6722 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6723 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6724 return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6725}
6726
6727/* -=-=-=-=- DBGF -=-=-=-=- */
6728
6729/**
6730 * AHCI status info callback.
6731 *
6732 * @param pDevIns The device instance.
6733 * @param pHlp The output helpers.
6734 * @param pszArgs The arguments.
6735 */
6736static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
6737{
6738 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6739
6740 /*
6741 * Show info.
6742 */
6743 pHlp->pfnPrintf(pHlp,
6744 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
6745 pDevIns->pReg->szName,
6746 pDevIns->iInstance,
6747 pThis->MMIOBase,
6748 pThis->cPortsImpl,
6749 pThis->fGCEnabled ? true : false,
6750 pThis->fR0Enabled ? true : false);
6751
6752 /*
6753 * Show global registers.
6754 */
6755 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
6756 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
6757 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
6758 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
6759 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
6760 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
6761 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
6762 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
6763
6764 /*
6765 * Per port data.
6766 */
6767 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
6768 {
6769 PAHCIPort pThisPort = &pThis->ahciPort[i];
6770
6771 pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
6772 pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
6773 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
6774 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
6775 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
6776 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
6777 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
6778 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
6779 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
6780 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
6781 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
6782 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
6783 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
6784 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
6785 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
6786 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
6787 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
6788 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
6789 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
6790 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
6791 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
6792 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
6793 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
6794 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
6795 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
6796 pHlp->pfnPrintf(pHlp, "\n");
6797 }
6798}
6799
6800/* -=-=-=-=- Helper -=-=-=-=- */
6801
6802/**
6803 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
6804 *
6805 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
6806 * use of it in strict builds (which is why it's up here).
6807 *
6808 * @returns true if quiesced, false if busy.
6809 * @param pDevIns The device instance.
6810 */
6811static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
6812{
6813 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6814
6815 if (pThis->cThreadsActive)
6816 return false;
6817
6818 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
6819 {
6820 PAHCIPort pThisPort = &pThis->ahciPort[i];
6821 if (pThisPort->pDrvBase)
6822 {
6823 if ( (pThisPort->cTasksActive != 0)
6824 || (pThisPort->u32TasksNew != 0))
6825 return false;
6826 }
6827 }
6828 return true;
6829}
6830
6831/* -=-=-=-=- Saved State -=-=-=-=- */
6832
6833/**
6834 * @copydoc FNDEVSSMSAVEPREP
6835 */
6836static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6837{
6838 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6839 return VINF_SUCCESS;
6840}
6841
6842/**
6843 * @copydoc FNDEVSSMLOADPREP
6844 */
6845static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6846{
6847 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
6848 return VINF_SUCCESS;
6849}
6850
6851/**
6852 * @copydoc FNDEVSSMLIVEEXEC
6853 */
6854static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6855{
6856 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6857
6858 /* config. */
6859 SSMR3PutU32(pSSM, pThis->cPortsImpl);
6860 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6861 {
6862 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
6863 SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
6864 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6865 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6866 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6867 }
6868
6869 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6870 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6871 {
6872 uint32_t iPort;
6873 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6874 AssertRCReturn(rc, rc);
6875 SSMR3PutU32(pSSM, iPort);
6876 }
6877
6878 return VINF_SSM_DONT_CALL_AGAIN;
6879}
6880
6881/**
6882 * @copydoc FNDEVSSMSAVEEXEC
6883 */
6884static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6885{
6886 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6887 uint32_t i;
6888 int rc;
6889
6890 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6891
6892 /* The config */
6893 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6894 AssertRCReturn(rc, rc);
6895
6896 /* The main device structure. */
6897 SSMR3PutU32(pSSM, pThis->regHbaCap);
6898 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
6899 SSMR3PutU32(pSSM, pThis->regHbaIs);
6900 SSMR3PutU32(pSSM, pThis->regHbaPi);
6901 SSMR3PutU32(pSSM, pThis->regHbaVs);
6902 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
6903 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
6904 SSMR3PutU8(pSSM, pThis->uCccPortNr);
6905 SSMR3PutU64(pSSM, pThis->uCccTimeout);
6906 SSMR3PutU32(pSSM, pThis->uCccNr);
6907 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
6908 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
6909 SSMR3PutBool(pSSM, pThis->fReset);
6910 SSMR3PutBool(pSSM, pThis->f64BitAddr);
6911 SSMR3PutBool(pSSM, pThis->fR0Enabled);
6912 SSMR3PutBool(pSSM, pThis->fGCEnabled);
6913
6914 /* Now every port. */
6915 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6916 {
6917 Assert(pThis->ahciPort[i].cTasksActive == 0);
6918 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
6919 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
6920 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
6921 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
6922 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6923 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6924 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
6925 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
6926 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
6927 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
6928 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
6929 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
6930 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
6931 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
6932 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
6933 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
6934 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
6935 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
6936 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
6937 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
6938 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
6939 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
6940 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
6941 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
6942 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
6943 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
6944 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
6945 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
6946
6947 /* ATAPI saved state. */
6948 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
6949 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
6950 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
6951 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
6952 }
6953
6954 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
6955}
6956
6957/**
6958 * Loads a saved legacy ATA emulated device state.
6959 *
6960 * @returns VBox status code.
6961 * @param pSSM The handle to the saved state.
6962 */
6963static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
6964{
6965 int rc;
6966 uint32_t u32Version;
6967 uint32_t u32;
6968 uint32_t u32IOBuffer;
6969
6970 /* Test for correct version. */
6971 rc = SSMR3GetU32(pSSM, &u32Version);
6972 AssertRCReturn(rc, rc);
6973 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
6974
6975 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
6976 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
6977 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
6978 {
6979 AssertMsgFailed(("u32Version=%d\n", u32Version));
6980 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
6981 }
6982
6983 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
6984
6985 for (uint32_t j = 0; j < 2; j++)
6986 {
6987 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
6988
6989 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
6990 SSMR3Skip(pSSM, 64);
6991 else
6992 SSMR3Skip(pSSM, 2);
6993 /** @todo triple-check this hack after passthrough is working */
6994 SSMR3Skip(pSSM, 1);
6995
6996 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
6997 SSMR3Skip(pSSM, 4);
6998
6999 SSMR3Skip(pSSM, sizeof(PDMLED));
7000 SSMR3GetU32(pSSM, &u32IOBuffer);
7001 if (u32IOBuffer)
7002 SSMR3Skip(pSSM, u32IOBuffer);
7003 }
7004
7005 rc = SSMR3GetU32(pSSM, &u32);
7006 if (RT_FAILURE(rc))
7007 return rc;
7008 if (u32 != ~0U)
7009 {
7010 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
7011 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
7012 return rc;
7013 }
7014
7015 return VINF_SUCCESS;
7016}
7017
7018/**
7019 * Loads a saved AHCI device state.
7020 *
7021 * @returns VBox status code.
7022 * @param pDevIns The device instance.
7023 * @param pSSM The handle to the saved state.
7024 * @param uVersion The data unit version number.
7025 * @param uPass The data pass.
7026 */
7027static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
7028{
7029 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7030 uint32_t u32;
7031 int rc;
7032
7033 if ( uVersion > AHCI_SAVED_STATE_VERSION
7034 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
7035 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7036
7037 /* Deal with the priod after removing the saved IDE bits where the saved
7038 state version remained unchanged. */
7039 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
7040 && SSMR3HandleRevision(pSSM) >= 79045
7041 && SSMR3HandleRevision(pSSM) < 79201)
7042 uVersion++;
7043
7044 /* Verify config. */
7045 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
7046 {
7047 rc = SSMR3GetU32(pSSM, &u32);
7048 AssertRCReturn(rc, rc);
7049 if (u32 != pThis->cPortsImpl)
7050 {
7051 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
7052 if ( u32 < pThis->cPortsImpl
7053 || u32 > AHCI_MAX_NR_PORTS_IMPL)
7054 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
7055 u32, pThis->cPortsImpl);
7056 }
7057
7058 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7059 {
7060 bool fInUse;
7061 rc = SSMR3GetBool(pSSM, &fInUse);
7062 AssertRCReturn(rc, rc);
7063 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
7064 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7065 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
7066 fInUse ? "target" : "source", i );
7067
7068 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
7069 {
7070 bool fHotpluggable;
7071 rc = SSMR3GetBool(pSSM, &fHotpluggable);
7072 AssertRCReturn(rc, rc);
7073 if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
7074 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7075 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
7076 i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
7077 }
7078 else
7079 Assert(pThis->ahciPort[i].fHotpluggable);
7080
7081 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
7082 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
7083 AssertRCReturn(rc, rc);
7084 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
7085 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
7086 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
7087
7088 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
7089 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
7090 AssertRCReturn(rc, rc);
7091 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
7092 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
7093 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
7094
7095 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
7096 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
7097 AssertRCReturn(rc, rc);
7098 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
7099 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
7100 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
7101 }
7102
7103 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7104 for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7105 {
7106 uint32_t iPort;
7107 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7108 AssertRCReturn(rc, rc);
7109
7110 uint32_t iPortSaved;
7111 rc = SSMR3GetU32(pSSM, &iPortSaved);
7112 AssertRCReturn(rc, rc);
7113
7114 if (iPortSaved != iPort)
7115 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
7116 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
7117 }
7118 }
7119
7120 if (uPass == SSM_PASS_FINAL)
7121 {
7122 /* Restore data. */
7123
7124 /* The main device structure. */
7125 SSMR3GetU32(pSSM, &pThis->regHbaCap);
7126 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
7127 SSMR3GetU32(pSSM, &pThis->regHbaIs);
7128 SSMR3GetU32(pSSM, &pThis->regHbaPi);
7129 SSMR3GetU32(pSSM, &pThis->regHbaVs);
7130 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
7131 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
7132 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
7133 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
7134 SSMR3GetU32(pSSM, &pThis->uCccNr);
7135 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
7136
7137 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
7138 SSMR3GetBool(pSSM, &pThis->fReset);
7139 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
7140 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
7141 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
7142
7143 /* Now every port. */
7144 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7145 {
7146 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7147
7148 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
7149 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
7150 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
7151 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
7152 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
7153 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
7154 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
7155 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
7156 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
7157 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
7158 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
7159 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
7160 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
7161 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
7162 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
7163 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
7164 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
7165 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
7166 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
7167 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
7168 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
7169 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7170 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7171
7172 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7173 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7174
7175 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7176 {
7177 /* The old positions in the FIFO, not required. */
7178 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7179 }
7180 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7181 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7182 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7183 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7184
7185 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7186 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7187
7188 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7189 {
7190 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7191 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7192 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7193 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7194 }
7195 else if (pThis->ahciPort[i].fATAPI)
7196 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
7197
7198 /* Check if we have tasks pending. */
7199 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7200 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7201
7202 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7203
7204 if (pAhciPort->u32TasksNew)
7205 {
7206 /*
7207 * There are tasks pending. The VM was saved after a task failed
7208 * because of non-fatal error. Set the redo flag.
7209 */
7210 pAhciPort->fRedo = true;
7211 }
7212 }
7213
7214 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7215 {
7216 for (uint32_t i = 0; i < 2; i++)
7217 {
7218 rc = ahciR3LoadLegacyEmulationState(pSSM);
7219 if(RT_FAILURE(rc))
7220 return rc;
7221 }
7222 }
7223
7224 rc = SSMR3GetU32(pSSM, &u32);
7225 if (RT_FAILURE(rc))
7226 return rc;
7227 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7228 }
7229
7230 return VINF_SUCCESS;
7231}
7232
7233/* -=-=-=-=- device PDM interface -=-=-=-=- */
7234
7235static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7236{
7237 uint32_t i;
7238 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7239
7240 pAhci->pDevInsRC += offDelta;
7241 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7242 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7243
7244 /* Relocate every port. */
7245 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7246 {
7247 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7248 pAhciPort->pAhciRC += offDelta;
7249 pAhciPort->pDevInsRC += offDelta;
7250 }
7251}
7252
7253/**
7254 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7255 * from now on, regardless if there was a medium inserted or not.
7256 */
7257static void ahciMediumRemoved(PAHCIPort pAhciPort)
7258{
7259 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7260}
7261
7262/**
7263 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7264 * there was already a medium inserted, don't forget to send the "medium
7265 * removed" event first.
7266 */
7267static void ahciMediumInserted(PAHCIPort pAhciPort)
7268{
7269 uint32_t OldStatus, NewStatus;
7270 do
7271 {
7272 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7273 switch (OldStatus)
7274 {
7275 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7276 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7277 /* no change, we will send "medium removed" + "medium inserted" */
7278 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7279 break;
7280 default:
7281 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7282 break;
7283 }
7284 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7285}
7286
7287/**
7288 * Called when a media is mounted.
7289 *
7290 * @param pInterface Pointer to the interface structure containing the called function pointer.
7291 */
7292static DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
7293{
7294 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7295 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7296
7297 /* Ignore the call if we're called while being attached. */
7298 if (!pAhciPort->pDrvBlock)
7299 return;
7300
7301 if (pAhciPort->fATAPI)
7302 {
7303 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7304
7305 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7306
7307 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7308 if (pAhciPort->cNotifiedMediaChange < 2)
7309 pAhciPort->cNotifiedMediaChange = 2;
7310 ahciMediumInserted(pAhciPort);
7311 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7312 }
7313 else
7314 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7315}
7316
7317/**
7318 * Called when a media is unmounted
7319 * @param pInterface Pointer to the interface structure containing the called function pointer.
7320 */
7321static DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7322{
7323 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7324 Log(("%s:\n", __FUNCTION__));
7325
7326 pAhciPort->cTotalSectors = 0;
7327
7328 if (pAhciPort->fATAPI)
7329 {
7330 /*
7331 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7332 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7333 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7334 * present and 2 in which it is changed.
7335 */
7336 pAhciPort->cNotifiedMediaChange = 4;
7337 ahciMediumRemoved(pAhciPort);
7338 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7339 }
7340 else
7341 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7342}
7343
7344/**
7345 * Configure the attached device for a port.
7346 *
7347 * Used by ahciR3Construct and ahciR3Attach.
7348 *
7349 * @returns VBox status code
7350 * @param pDevIns The device instance data.
7351 * @param pAhciPort The port for which the device is to be configured.
7352 */
7353static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7354{
7355 int rc = VINF_SUCCESS;
7356 PDMBLOCKTYPE enmType;
7357
7358 /*
7359 * Query the block and blockbios interfaces.
7360 */
7361 pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
7362 if (!pAhciPort->pDrvBlock)
7363 {
7364 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
7365 return VERR_PDM_MISSING_INTERFACE;
7366 }
7367 pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
7368 if (!pAhciPort->pDrvBlockBios)
7369 {
7370 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
7371 return VERR_PDM_MISSING_INTERFACE;
7372 }
7373
7374 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7375
7376 /* Try to get the optional async block interface. */
7377 pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
7378
7379 /*
7380 * Validate type.
7381 */
7382 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
7383
7384 if ( enmType != PDMBLOCKTYPE_HARD_DISK
7385 && enmType != PDMBLOCKTYPE_CDROM
7386 && enmType != PDMBLOCKTYPE_DVD)
7387 {
7388 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
7389 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
7390 }
7391
7392 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
7393 && !pAhciPort->pDrvMount)
7394 {
7395 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
7396 return VERR_INTERNAL_ERROR;
7397 }
7398 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
7399 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
7400
7401 if (pAhciPort->fATAPI)
7402 {
7403 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
7404 pAhciPort->PCHSGeometry.cCylinders = 0;
7405 pAhciPort->PCHSGeometry.cHeads = 0;
7406 pAhciPort->PCHSGeometry.cSectors = 0;
7407 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7408 }
7409 else
7410 {
7411 pAhciPort->cbSector = pAhciPort->pDrvBlock->pfnGetSectorSize(pAhciPort->pDrvBlock);
7412 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / pAhciPort->cbSector;
7413 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
7414 &pAhciPort->PCHSGeometry);
7415 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7416 {
7417 pAhciPort->PCHSGeometry.cCylinders = 0;
7418 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7419 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7420 }
7421 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7422 {
7423 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7424 rc = VINF_SUCCESS;
7425 }
7426 AssertRC(rc);
7427
7428 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7429 || pAhciPort->PCHSGeometry.cHeads == 0
7430 || pAhciPort->PCHSGeometry.cSectors == 0)
7431 {
7432 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7433 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7434 pAhciPort->PCHSGeometry.cHeads = 16;
7435 pAhciPort->PCHSGeometry.cSectors = 63;
7436 /* Set the disk geometry information. Ignore errors. */
7437 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
7438 &pAhciPort->PCHSGeometry);
7439 rc = VINF_SUCCESS;
7440 }
7441 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7442 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7443 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7444 pAhciPort->cTotalSectors));
7445 if (pAhciPort->pDrvBlock->pfnDiscard)
7446 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7447 }
7448 return rc;
7449}
7450
7451/**
7452 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7453 *
7454 * @returns true if we've quiesced, false if we're still working.
7455 * @param pDevIns The device instance.
7456 */
7457static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7458{
7459 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7460 return false;
7461
7462 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7463 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7464 return true;
7465}
7466
7467/**
7468 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7469 */
7470static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7471{
7472 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7473
7474 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7475 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7476 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7477 else
7478 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7479}
7480
7481/**
7482 * Suspend notification.
7483 *
7484 * @param pDevIns The device instance data.
7485 */
7486static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7487{
7488 Log(("ahciR3Suspend\n"));
7489 ahciR3SuspendOrPowerOff(pDevIns);
7490}
7491
7492/**
7493 * Resume notification.
7494 *
7495 * @param pDevIns The device instance data.
7496 */
7497static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7498{
7499 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7500
7501 /*
7502 * Check if one of the ports has pending tasks.
7503 * Queue a notification item again in this case.
7504 */
7505 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7506 {
7507 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7508
7509 if (pAhciPort->u32TasksRedo)
7510 {
7511 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7512 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7513
7514 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
7515 pAhciPort->u32TasksRedo = 0;
7516
7517 Assert(pAhciPort->fRedo);
7518 pAhciPort->fRedo = false;
7519
7520 pItem->iPort = pAhci->ahciPort[i].iLUN;
7521 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7522 }
7523 }
7524
7525 Log(("%s:\n", __FUNCTION__));
7526}
7527
7528/**
7529 * Initializes the VPD data of a attached device.
7530 *
7531 * @returns VBox status code.
7532 * @param pDevIns The device instance.
7533 * @param pAhciPort The attached device.
7534 * @param szName Name of the port to get the CFGM node.
7535 */
7536static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7537{
7538 int rc = VINF_SUCCESS;
7539 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7540
7541 /* Generate a default serial number. */
7542 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7543 RTUUID Uuid;
7544
7545 if (pAhciPort->pDrvBlock)
7546 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
7547 else
7548 RTUuidClear(&Uuid);
7549
7550 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7551 {
7552 /* Generate a predictable serial for drives which don't have a UUID. */
7553 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7554 pAhciPort->iLUN);
7555 }
7556 else
7557 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7558
7559 /* Get user config if present using defaults otherwise. */
7560 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7561 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7562 szSerial);
7563 if (RT_FAILURE(rc))
7564 {
7565 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7566 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7567 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7568 return PDMDEV_SET_ERROR(pDevIns, rc,
7569 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7570 }
7571
7572 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7573 "1.0");
7574 if (RT_FAILURE(rc))
7575 {
7576 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7577 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7578 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7579 return PDMDEV_SET_ERROR(pDevIns, rc,
7580 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7581 }
7582
7583 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7584 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7585 if (RT_FAILURE(rc))
7586 {
7587 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7588 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7589 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7590 return PDMDEV_SET_ERROR(pDevIns, rc,
7591 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7592 }
7593
7594 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7595 if (RT_FAILURE(rc))
7596 return PDMDEV_SET_ERROR(pDevIns, rc,
7597 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7598
7599 rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
7600 if (RT_FAILURE(rc))
7601 return PDMDEV_SET_ERROR(pDevIns, rc,
7602 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
7603 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
7604 return PDMDEV_SET_ERROR(pDevIns, rc,
7605 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
7606
7607 /* There are three other identification strings for CD drives used for INQUIRY */
7608 if (pAhciPort->fATAPI)
7609 {
7610 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7611 "VBOX");
7612 if (RT_FAILURE(rc))
7613 {
7614 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7615 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7616 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7617 return PDMDEV_SET_ERROR(pDevIns, rc,
7618 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7619 }
7620
7621 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7622 "CD-ROM");
7623 if (RT_FAILURE(rc))
7624 {
7625 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7626 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7627 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7628 return PDMDEV_SET_ERROR(pDevIns, rc,
7629 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7630 }
7631
7632 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7633 "1.0");
7634 if (RT_FAILURE(rc))
7635 {
7636 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7637 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7638 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7639 return PDMDEV_SET_ERROR(pDevIns, rc,
7640 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7641 }
7642 }
7643
7644 return rc;
7645}
7646
7647
7648/**
7649 * Detach notification.
7650 *
7651 * One harddisk at one port has been unplugged.
7652 * The VM is suspended at this point.
7653 *
7654 * @param pDevIns The device instance.
7655 * @param iLUN The logical unit which is being detached.
7656 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7657 */
7658static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7659{
7660 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7661 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
7662 int rc = VINF_SUCCESS;
7663
7664 Log(("%s:\n", __FUNCTION__));
7665
7666 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
7667 AssertMsgReturnVoid( pAhciPort->fHotpluggable
7668 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7669 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
7670
7671
7672 if (pAhciPort->pAsyncIOThread)
7673 {
7674 int rcThread;
7675 /* Destroy the thread. */
7676 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
7677 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
7678 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
7679
7680 pAhciPort->pAsyncIOThread = NULL;
7681 }
7682
7683 if (pAhciPort->fATAPI)
7684 ahciMediumRemoved(pAhciPort);
7685
7686 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7687 {
7688 /*
7689 * Inform the guest about the removed device.
7690 */
7691 pAhciPort->regSSTS = 0;
7692 /*
7693 * Clear CR bit too to prevent submission of new commands when CI is written
7694 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
7695 */
7696 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
7697 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
7698 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_N);
7699 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7700 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7701 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7702 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7703 }
7704
7705 /*
7706 * Zero some important members.
7707 */
7708 pAhciPort->pDrvBase = NULL;
7709 pAhciPort->pDrvBlock = NULL;
7710 pAhciPort->pDrvBlockAsync = NULL;
7711 pAhciPort->pDrvBlockBios = NULL;
7712}
7713
7714/**
7715 * Attach command.
7716 *
7717 * This is called when we change block driver for one port.
7718 * The VM is suspended at this point.
7719 *
7720 * @returns VBox status code.
7721 * @param pDevIns The device instance.
7722 * @param iLUN The logical unit which is being detached.
7723 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
7724 */
7725static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
7726{
7727 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7728 PAHCIPort pAhciPort = &pThis->ahciPort[iLUN];
7729 int rc;
7730
7731 Log(("%s:\n", __FUNCTION__));
7732
7733 /* the usual paranoia */
7734 AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
7735 AssertRelease(!pAhciPort->pDrvBase);
7736 AssertRelease(!pAhciPort->pDrvBlock);
7737 AssertRelease(!pAhciPort->pDrvBlockAsync);
7738 Assert(pAhciPort->iLUN == iLUN);
7739
7740 AssertMsgReturn( pAhciPort->fHotpluggable
7741 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
7742 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7743 VERR_INVALID_PARAMETER);
7744
7745 /*
7746 * Try attach the block device and get the interfaces,
7747 * required as well as optional.
7748 */
7749 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
7750 if (RT_SUCCESS(rc))
7751 {
7752 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
7753
7754 /*
7755 * In case there is a medium inserted.
7756 */
7757 ahciMediumInserted(pAhciPort);
7758 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7759 }
7760 else
7761 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
7762
7763 if (RT_FAILURE(rc))
7764 {
7765 pAhciPort->pDrvBase = NULL;
7766 pAhciPort->pDrvBlock = NULL;
7767 }
7768 else
7769 {
7770 char szName[24];
7771 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
7772
7773 if ( pAhciPort->pDrvBlockAsync
7774 && !pAhciPort->fATAPI)
7775 pAhciPort->fAsyncInterface = true;
7776 else
7777 pAhciPort->fAsyncInterface = false;
7778
7779 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
7780 if (RT_FAILURE(rc))
7781 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7782 N_("AHCI: Failed to create SUP event semaphore"));
7783
7784 /* Create the async IO thread. */
7785 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
7786 RTTHREADTYPE_IO, szName);
7787 if (RT_FAILURE(rc))
7788 return rc;
7789
7790 /*
7791 * Init vendor product data.
7792 */
7793 if (RT_SUCCESS(rc))
7794 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
7795
7796 /* Inform the guest about the added device in case of hotplugging. */
7797 if ( RT_SUCCESS(rc)
7798 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
7799 {
7800 AssertMsgReturn(pAhciPort->fHotpluggable,
7801 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
7802 VERR_NOT_SUPPORTED);
7803
7804 /*
7805 * Initialize registers
7806 */
7807 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
7808 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
7809 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
7810
7811 if (pAhciPort->fATAPI)
7812 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
7813 else
7814 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
7815 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
7816 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
7817 (0x03 << 0); /* Device detected and communication established. */
7818
7819 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
7820 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
7821 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
7822 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
7823 }
7824
7825 }
7826
7827 return rc;
7828}
7829
7830/**
7831 * Common reset worker.
7832 *
7833 * @param pDevIns The device instance data.
7834 */
7835static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
7836{
7837 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7838
7839 ahciHBAReset(pAhci);
7840
7841 /* Hardware reset for the ports. */
7842 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7843 ahciPortHwReset(&pAhci->ahciPort[i]);
7844 return VINF_SUCCESS;
7845}
7846
7847/**
7848 * Callback employed by ahciR3Reset.
7849 *
7850 * @returns true if we've quiesced, false if we're still working.
7851 * @param pDevIns The device instance.
7852 */
7853static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
7854{
7855 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7856
7857 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7858 return false;
7859 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7860
7861 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7862 return true;
7863}
7864
7865/**
7866 * Reset notification.
7867 *
7868 * @param pDevIns The device instance data.
7869 */
7870static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
7871{
7872 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7873
7874 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7875 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7876 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
7877 else
7878 {
7879 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7880 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
7881 }
7882}
7883
7884/**
7885 * Poweroff notification.
7886 *
7887 * @param pDevIns Pointer to the device instance
7888 */
7889static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
7890{
7891 Log(("achiR3PowerOff\n"));
7892 ahciR3SuspendOrPowerOff(pDevIns);
7893}
7894
7895/**
7896 * Destroy a driver instance.
7897 *
7898 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
7899 * resources can be freed correctly.
7900 *
7901 * @param pDevIns The device instance data.
7902 */
7903static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
7904{
7905 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7906 int rc = VINF_SUCCESS;
7907 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
7908
7909 /*
7910 * At this point the async I/O thread is suspended and will not enter
7911 * this module again. So, no coordination is needed here and PDM
7912 * will take care of terminating and cleaning up the thread.
7913 */
7914 if (PDMCritSectIsInitialized(&pThis->lock))
7915 {
7916 TMR3TimerDestroy(pThis->CTX_SUFF(pHbaCccTimer));
7917 pThis->CTX_SUFF(pHbaCccTimer) = NULL;
7918
7919 Log(("%s: Destruct every port\n", __FUNCTION__));
7920 for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
7921 {
7922 PAHCIPort pAhciPort = &pThis->ahciPort[iActPort];
7923
7924 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
7925 {
7926 SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
7927 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
7928 }
7929
7930 /* Free all cached tasks. */
7931 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
7932 if (pAhciPort->aCachedTasks[i])
7933 {
7934 RTMemFree(pAhciPort->aCachedTasks[i]);
7935 pAhciPort->aCachedTasks[i] = NULL;
7936 }
7937 }
7938
7939 PDMR3CritSectDelete(&pThis->lock);
7940 }
7941
7942 return rc;
7943}
7944
7945/**
7946 * @interface_method_impl{PDMDEVREG,pfnConstruct}
7947 */
7948static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
7949{
7950 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7951 PPDMIBASE pBase;
7952 int rc = VINF_SUCCESS;
7953 unsigned i = 0;
7954 bool fGCEnabled = false;
7955 bool fR0Enabled = false;
7956 uint32_t cbTotalBufferSize = 0;
7957 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
7958
7959 LogFlowFunc(("pThis=%#p\n", pThis));
7960
7961 /*
7962 * Validate and read configuration.
7963 */
7964 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
7965 "R0Enabled\0"
7966 "PrimaryMaster\0"
7967 "PrimarySlave\0"
7968 "SecondaryMaster\0"
7969 "SecondarySlave\0"
7970 "PortCount\0"
7971 "UseAsyncInterfaceIfAvailable\0"
7972 "Bootable\0"
7973 "CmdSlotsAvail\0"))
7974 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
7975 N_("AHCI configuration error: unknown option specified"));
7976
7977 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
7978 if (RT_FAILURE(rc))
7979 return PDMDEV_SET_ERROR(pDevIns, rc,
7980 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
7981 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
7982
7983 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
7984 if (RT_FAILURE(rc))
7985 return PDMDEV_SET_ERROR(pDevIns, rc,
7986 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
7987 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
7988
7989 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
7990 if (RT_FAILURE(rc))
7991 return PDMDEV_SET_ERROR(pDevIns, rc,
7992 N_("AHCI configuration error: failed to read PortCount as integer"));
7993 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
7994 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
7995 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
7996 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
7997 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
7998 if (pThis->cPortsImpl < 1)
7999 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8000 N_("AHCI configuration error: PortCount=%u should be at least 1"),
8001 pThis->cPortsImpl);
8002
8003 rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
8004 if (RT_FAILURE(rc))
8005 return PDMDEV_SET_ERROR(pDevIns, rc,
8006 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
8007
8008 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
8009 if (RT_FAILURE(rc))
8010 return PDMDEV_SET_ERROR(pDevIns, rc,
8011 N_("AHCI configuration error: failed to read Bootable as boolean"));
8012
8013 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
8014 if (RT_FAILURE(rc))
8015 return PDMDEV_SET_ERROR(pDevIns, rc,
8016 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
8017 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
8018 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
8019 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8020 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
8021 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
8022 if (pThis->cCmdSlotsAvail < 1)
8023 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8024 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
8025 pThis->cCmdSlotsAvail);
8026
8027 /*
8028 * Initialize the instance data (everything touched by the destructor need
8029 * to be initialized here!).
8030 */
8031 pThis->fR0Enabled = fR0Enabled;
8032 pThis->fGCEnabled = fGCEnabled;
8033 pThis->pDevInsR3 = pDevIns;
8034 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8035 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8036 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
8037
8038 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
8039 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
8040 PCIDevSetCommand (&pThis->dev, 0x0000);
8041#ifdef VBOX_WITH_MSI_DEVICES
8042 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8043 PCIDevSetCapabilityList(&pThis->dev, 0x80);
8044#else
8045 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8046#endif
8047 PCIDevSetRevisionId (&pThis->dev, 0x02);
8048 PCIDevSetClassProg (&pThis->dev, 0x01);
8049 PCIDevSetClassSub (&pThis->dev, 0x06);
8050 PCIDevSetClassBase (&pThis->dev, 0x01);
8051 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
8052
8053 PCIDevSetInterruptLine(&pThis->dev, 0x00);
8054 PCIDevSetInterruptPin (&pThis->dev, 0x01);
8055
8056 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
8057 pThis->dev.config[0x71] = 0xa8; /* next */
8058 pThis->dev.config[0x72] = 0x03; /* version ? */
8059
8060 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
8061 pThis->dev.config[0x92] = 0x3f;
8062 pThis->dev.config[0x94] = 0x80;
8063 pThis->dev.config[0x95] = 0x01;
8064 pThis->dev.config[0x97] = 0x78;
8065
8066 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
8067 pThis->dev.config[0xa9] = 0x00; /* next */
8068 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
8069 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
8070
8071 pThis->cThreadsActive = 0;
8072
8073 /* Initialize port members. */
8074 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8075 {
8076 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8077 pAhciPort->pDevInsR3 = pDevIns;
8078 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8079 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8080 pAhciPort->iLUN = i;
8081 pAhciPort->pAhciR3 = pThis;
8082 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
8083 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
8084 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
8085 pAhciPort->pDrvBase = NULL;
8086 pAhciPort->pAsyncIOThread = NULL;
8087 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8088 pAhciPort->fHotpluggable = true;
8089 }
8090
8091 /*
8092 * Init locks, using explicit locking where necessary.
8093 */
8094 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
8095 if (RT_FAILURE(rc))
8096 return rc;
8097
8098 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
8099 if (RT_FAILURE(rc))
8100 {
8101 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
8102 return rc;
8103 }
8104
8105 /*
8106 * Register the PCI device, it's I/O regions.
8107 */
8108 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
8109 if (RT_FAILURE(rc))
8110 return rc;
8111
8112#ifdef VBOX_WITH_MSI_DEVICES
8113 PDMMSIREG MsiReg;
8114 RT_ZERO(MsiReg);
8115 MsiReg.cMsiVectors = 1;
8116 MsiReg.iMsiCapOffset = 0x80;
8117 MsiReg.iMsiNextOffset = 0x70;
8118 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
8119 if (RT_FAILURE(rc))
8120 {
8121 LogRel(("Chipset cannot do MSI: %Rrc\n", rc));
8122 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8123 /* That's OK, we can work without MSI */
8124 }
8125#endif
8126
8127 /*
8128 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
8129 * IDE registers are not available.
8130 * We set up "fake" entries in the PCI configuration register.
8131 * That means they are available but read and writes from/to them have no effect.
8132 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
8133 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
8134 * to switch to it which also changes device Id and other things in the PCI configuration space).
8135 */
8136 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8137 if (RT_FAILURE(rc))
8138 return PDMDEV_SET_ERROR(pDevIns, rc,
8139 N_("AHCI cannot register PCI I/O region"));
8140
8141 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8142 if (RT_FAILURE(rc))
8143 return PDMDEV_SET_ERROR(pDevIns, rc,
8144 N_("AHCI cannot register PCI I/O region"));
8145
8146 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8147 if (RT_FAILURE(rc))
8148 return PDMDEV_SET_ERROR(pDevIns, rc,
8149 N_("AHCI cannot register PCI I/O region"));
8150
8151 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8152 if (RT_FAILURE(rc))
8153 return PDMDEV_SET_ERROR(pDevIns, rc,
8154 N_("AHCI cannot register PCI I/O region"));
8155
8156 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
8157 if (RT_FAILURE(rc))
8158 return PDMDEV_SET_ERROR(pDevIns, rc,
8159 N_("AHCI cannot register PCI I/O region for BMDMA"));
8160
8161 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
8162 if (RT_FAILURE(rc))
8163 return PDMDEV_SET_ERROR(pDevIns, rc,
8164 N_("AHCI cannot register PCI memory region for registers"));
8165
8166 /* Create the timer for command completion coalescing feature. */
8167 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
8168 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
8169 if (RT_FAILURE(rc))
8170 {
8171 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
8172 return rc;
8173 }
8174 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
8175 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
8176
8177 /* Status LUN. */
8178 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
8179 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
8180
8181 /*
8182 * Create the notification queue.
8183 *
8184 * We need 2 items for every port because of SMP races.
8185 */
8186 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8187 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
8188 if (RT_FAILURE(rc))
8189 return rc;
8190 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
8191 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
8192
8193 /* Initialize static members on every port. */
8194 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8195 {
8196 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8197
8198 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8199 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
8200 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8201 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
8202 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8203 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
8204 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8205 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8206#ifdef VBOX_WITH_STATISTICS
8207 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8208 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8209 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8210 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8211#endif
8212
8213 ahciPortHwReset(pAhciPort);
8214 }
8215
8216 /* Attach drivers to every available port. */
8217 for (i = 0; i < pThis->cPortsImpl; i++)
8218 {
8219 char szName[24];
8220 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8221
8222 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8223 /*
8224 * Init interfaces.
8225 */
8226 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8227 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciR3TransferCompleteNotify;
8228 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8229 pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
8230 pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
8231
8232 /* Query per port configuration options if available. */
8233 PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
8234 if (pCfgPort)
8235 {
8236 rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
8237 if (RT_FAILURE(rc))
8238 return PDMDEV_SET_ERROR(pDevIns, rc,
8239 N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
8240 }
8241
8242 /*
8243 * Attach the block driver
8244 */
8245 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8246 if (RT_SUCCESS(rc))
8247 {
8248 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8249 if (RT_FAILURE(rc))
8250 {
8251 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8252 return rc;
8253 }
8254
8255 /* Mark that a device is present on that port */
8256 if (i < 6)
8257 pThis->dev.config[0x93] |= (1 << i);
8258
8259 /*
8260 * Init vendor product data.
8261 */
8262 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8263 if (RT_FAILURE(rc))
8264 return rc;
8265
8266 /*
8267 * If the new async interface is available we use a PDMQueue to transmit
8268 * the requests into R3.
8269 * Otherwise we use a event semaphore and a async I/O thread which processes them.
8270 */
8271 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
8272 {
8273 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
8274 pAhciPort->fAsyncInterface = true;
8275 }
8276 else
8277 {
8278 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
8279 pAhciPort->fAsyncInterface = false;
8280 }
8281
8282 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8283 if (RT_FAILURE(rc))
8284 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8285 N_("AHCI: Failed to create SUP event semaphore"));
8286
8287 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
8288 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
8289 if (RT_FAILURE(rc))
8290 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8291 N_("AHCI: Failed to create worker thread %s"), szName);
8292 }
8293 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8294 {
8295 pAhciPort->pDrvBase = NULL;
8296 rc = VINF_SUCCESS;
8297 LogRel(("%s: no driver attached\n", szName));
8298 }
8299 else
8300 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8301 N_("AHCI: Failed to attach drive to %s"), szName);
8302 }
8303
8304 /*
8305 * Attach status driver (optional).
8306 */
8307 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8308 if (RT_SUCCESS(rc))
8309 {
8310 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8311 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8312 }
8313 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8314 {
8315 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8316 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8317 }
8318 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
8319 NULL, ahciR3LiveExec, NULL,
8320 ahciR3SavePrep, ahciR3SaveExec, NULL,
8321 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8322 if (RT_FAILURE(rc))
8323 return rc;
8324
8325 /*
8326 * Register the info item.
8327 */
8328 char szTmp[128];
8329 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8330 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8331
8332 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8333}
8334
8335/**
8336 * The device registration structure.
8337 */
8338const PDMDEVREG g_DeviceAHCI =
8339{
8340 /* u32Version */
8341 PDM_DEVREG_VERSION,
8342 /* szName */
8343 "ahci",
8344 /* szRCMod */
8345 "VBoxDDGC.gc",
8346 /* szR0Mod */
8347 "VBoxDDR0.r0",
8348 /* pszDescription */
8349 "Intel AHCI controller.\n",
8350 /* fFlags */
8351 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8352 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
8353 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
8354 /* fClass */
8355 PDM_DEVREG_CLASS_STORAGE,
8356 /* cMaxInstances */
8357 ~0U,
8358 /* cbInstance */
8359 sizeof(AHCI),
8360 /* pfnConstruct */
8361 ahciR3Construct,
8362 /* pfnDestruct */
8363 ahciR3Destruct,
8364 /* pfnRelocate */
8365 ahciR3Relocate,
8366 /* pfnMemSetup */
8367 NULL,
8368 /* pfnPowerOn */
8369 NULL,
8370 /* pfnReset */
8371 ahciR3Reset,
8372 /* pfnSuspend */
8373 ahciR3Suspend,
8374 /* pfnResume */
8375 ahciR3Resume,
8376 /* pfnAttach */
8377 ahciR3Attach,
8378 /* pfnDetach */
8379 ahciR3Detach,
8380 /* pfnQueryInterface. */
8381 NULL,
8382 /* pfnInitComplete */
8383 NULL,
8384 /* pfnPowerOff */
8385 ahciR3PowerOff,
8386 /* pfnSoftReset */
8387 NULL,
8388 /* u32VersionEnd */
8389 PDM_DEVREG_VERSION
8390};
8391
8392#endif /* IN_RING3 */
8393#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