VirtualBox

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

Last change on this file since 63933 was 63909, checked in by vboxsync, 9 years ago

AHCI: Get rid of goto

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

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