VirtualBox

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

Last change on this file since 63676 was 63562, checked in by vboxsync, 8 years ago

scm: cleaning up todos

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 329.0 KB
Line 
1/* $Id: DevAHCI.cpp 63562 2016-08-16 14:04:03Z vboxsync $ */
2/** @file
3 * DevAHCI - AHCI controller device (disk and cdrom).
4 *
5 * Implements the AHCI standard 1.1
6 */
7
8/*
9 * Copyright (C) 2006-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
2551static DECLCALLBACK(int)
2552ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2553{
2554 RT_NOREF(iRegion, enmType);
2555 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2556 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2557 int rc = VINF_SUCCESS;
2558
2559 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2560
2561 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2562 Assert(cb >= 4352);
2563
2564 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2565 /** @todo change this to IOMMMIO_FLAGS_WRITE_ONLY_DWORD once EM/IOM starts
2566 * handling 2nd DWORD failures on split accesses correctly. */
2567 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
2568 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
2569 ahciMMIOWrite, ahciMMIORead, "AHCI");
2570 if (RT_FAILURE(rc))
2571 return rc;
2572
2573 if (pThis->fR0Enabled)
2574 {
2575 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2576 if (RT_FAILURE(rc))
2577 return rc;
2578 }
2579
2580 if (pThis->fGCEnabled)
2581 {
2582 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
2583 if (RT_FAILURE(rc))
2584 return rc;
2585 }
2586
2587 pThis->MMIOBase = GCPhysAddress;
2588 return rc;
2589}
2590
2591/**
2592 * Map the legacy I/O port ranges to make Solaris work with the controller.
2593 */
2594static DECLCALLBACK(int)
2595ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2596{
2597 RT_NOREF(iRegion, enmType);
2598 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2599 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2600 int rc = VINF_SUCCESS;
2601
2602 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2603
2604 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2605
2606 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2607 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2608 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2609 if (RT_FAILURE(rc))
2610 return rc;
2611
2612 if (pThis->fR0Enabled)
2613 {
2614 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2615 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2616 if (RT_FAILURE(rc))
2617 return rc;
2618 }
2619
2620 if (pThis->fGCEnabled)
2621 {
2622 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2623 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2624 if (RT_FAILURE(rc))
2625 return rc;
2626 }
2627
2628 return rc;
2629}
2630
2631/**
2632 * Map the BMDMA I/O port range (used for the Index/Data pair register access)
2633 */
2634static DECLCALLBACK(int)
2635ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2636{
2637 RT_NOREF(iRegion, enmType);
2638 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2639 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2640 int rc = VINF_SUCCESS;
2641
2642 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2643
2644 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2645
2646 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2647 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2648 ahciIdxDataWrite, ahciIdxDataRead, NULL, NULL, "AHCI IDX/DATA");
2649 if (RT_FAILURE(rc))
2650 return rc;
2651
2652 if (pThis->fR0Enabled)
2653 {
2654 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2655 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2656 if (RT_FAILURE(rc))
2657 return rc;
2658 }
2659
2660 if (pThis->fGCEnabled)
2661 {
2662 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2663 "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
2664 if (RT_FAILURE(rc))
2665 return rc;
2666 }
2667
2668 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
2669 return rc;
2670}
2671
2672/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2673
2674/**
2675 * Gets the pointer to the status LED of a unit.
2676 *
2677 * @returns VBox status code.
2678 * @param pInterface Pointer to the interface structure containing the called function pointer.
2679 * @param iLUN The unit which status LED we desire.
2680 * @param ppLed Where to store the LED pointer.
2681 */
2682static DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2683{
2684 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2685 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2686 {
2687 *ppLed = &pAhci->ahciPort[iLUN].Led;
2688 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2689 return VINF_SUCCESS;
2690 }
2691 return VERR_PDM_LUN_NOT_FOUND;
2692}
2693
2694/**
2695 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2696 */
2697static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2698{
2699 PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
2700 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2701 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
2702 return NULL;
2703}
2704
2705/**
2706 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2707 */
2708static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2709{
2710 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2711 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
2712 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pAhciPort->IPort);
2713 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pAhciPort->IPortAsync);
2714 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
2715 return NULL;
2716}
2717
2718/**
2719 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2720 */
2721static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2722 uint32_t *piInstance, uint32_t *piLUN)
2723{
2724 PAHCIPort pAhciPort = PDMIMEDIAPORT_2_PAHCIPORT(pInterface);
2725 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
2726
2727 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2728 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2729 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2730
2731 *ppcszController = pDevIns->pReg->szName;
2732 *piInstance = pDevIns->iInstance;
2733 *piLUN = pAhciPort->iLUN;
2734
2735 return VINF_SUCCESS;
2736}
2737
2738#ifdef LOG_ENABLED
2739
2740/**
2741 * Dump info about the FIS
2742 *
2743 * @returns nothing
2744 * @param pAhciPort The port the command FIS was read from.
2745 * @param cmdFis The FIS to print info from.
2746 */
2747static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2748{
2749 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2750 /* Print FIS type. */
2751 switch (cmdFis[AHCI_CMDFIS_TYPE])
2752 {
2753 case AHCI_CMDFIS_TYPE_H2D:
2754 {
2755 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2756 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2757 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2758 ahciLog(("%s: Command register update\n", __FUNCTION__));
2759 else
2760 ahciLog(("%s: Control register update\n", __FUNCTION__));
2761 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2762 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2763 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2764 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2765 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2766 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2767
2768 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2769 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2770 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2771 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2772
2773 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2774 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2775 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2776 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2777 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2778 break;
2779 }
2780 case AHCI_CMDFIS_TYPE_D2H:
2781 {
2782 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2783 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2784 break;
2785 }
2786 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2787 {
2788 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2789 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2790 break;
2791 }
2792 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2793 {
2794 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2795 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2796 break;
2797 }
2798 case AHCI_CMDFIS_TYPE_DMASETUP:
2799 {
2800 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2801 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2802 break;
2803 }
2804 case AHCI_CMDFIS_TYPE_PIOSETUP:
2805 {
2806 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2807 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2808 break;
2809 }
2810 case AHCI_CMDFIS_TYPE_DATA:
2811 {
2812 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2813 break;
2814 }
2815 default:
2816 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2817 break;
2818 }
2819 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2820}
2821
2822/**
2823 * Dump info about the command header
2824 *
2825 * @returns nothing
2826 * @param pAhciPort Pointer to the port the command header was read from.
2827 * @param pCmdHdr The command header to print info from.
2828 */
2829static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2830{
2831 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2832 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2833 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2834 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2835 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2836 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2837 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2838 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2839 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2840 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2841 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2842 ahciLog(("%s: Device write\n", __FUNCTION__));
2843 else
2844 ahciLog(("%s: Device read\n", __FUNCTION__));
2845 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2846 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2847 else
2848 ahciLog(("%s: ATA command\n", __FUNCTION__));
2849
2850 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2851 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2852}
2853
2854#endif /* LOG_ENABLED */
2855
2856/**
2857 * Post the first D2H FIS from the device into guest memory.
2858 *
2859 * @returns nothing
2860 * @param pAhciPort Pointer to the port which "receives" the FIS.
2861 */
2862static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2863{
2864 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2865
2866 pAhciPort->fFirstD2HFisSend = true;
2867
2868 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2869 memset(&d2hFis[0], 0, sizeof(d2hFis));
2870 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2871 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2872
2873 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2874
2875 /* Set the signature based on the device type. */
2876 if (pAhciPort->fATAPI)
2877 {
2878 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2879 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2880 }
2881 else
2882 {
2883 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2884 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2885 }
2886
2887 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2888 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2889 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2890
2891 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2892 if (!pAhciPort->fATAPI)
2893 pAhciPort->regTFD |= ATA_STAT_READY;
2894
2895 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2896}
2897
2898/**
2899 * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
2900 *
2901 * @returns VBox status code
2902 * @param pAhciPort The port which "receives" the FIS.
2903 * @param uFisType The type of the FIS.
2904 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2905 */
2906static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2907{
2908 int rc = VINF_SUCCESS;
2909 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2910 unsigned cbFis = 0;
2911
2912 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2913
2914 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2915 {
2916 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2917
2918 /* Determine the offset and size of the FIS based on uFisType. */
2919 switch (uFisType)
2920 {
2921 case AHCI_CMDFIS_TYPE_D2H:
2922 {
2923 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2924 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2925 break;
2926 }
2927 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2928 {
2929 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2930 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2931 break;
2932 }
2933 case AHCI_CMDFIS_TYPE_DMASETUP:
2934 {
2935 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2936 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2937 break;
2938 }
2939 case AHCI_CMDFIS_TYPE_PIOSETUP:
2940 {
2941 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2942 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2943 break;
2944 }
2945 default:
2946 /*
2947 * We should post the unknown FIS into memory too but this never happens because
2948 * we know which FIS types we generate. ;)
2949 */
2950 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2951 }
2952
2953 /* Post the FIS into memory. */
2954 ahciLog(("%s: PDMDevHlpPCIPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2955 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2956 }
2957
2958 return rc;
2959}
2960
2961DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2962{
2963 pbBuf[0] = val >> 8;
2964 pbBuf[1] = val;
2965}
2966
2967
2968DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2969{
2970 pbBuf[0] = val >> 16;
2971 pbBuf[1] = val >> 8;
2972 pbBuf[2] = val;
2973}
2974
2975
2976DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2977{
2978 pbBuf[0] = val >> 24;
2979 pbBuf[1] = val >> 16;
2980 pbBuf[2] = val >> 8;
2981 pbBuf[3] = val;
2982}
2983
2984
2985DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2986{
2987 return (pbBuf[0] << 8) | pbBuf[1];
2988}
2989
2990
2991DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2992{
2993 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2994}
2995
2996
2997DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2998{
2999 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
3000}
3001
3002
3003DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
3004{
3005 iATAPILBA += 150;
3006 pbBuf[0] = (iATAPILBA / 75) / 60;
3007 pbBuf[1] = (iATAPILBA / 75) % 60;
3008 pbBuf[2] = iATAPILBA % 75;
3009}
3010
3011
3012DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
3013{
3014 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
3015}
3016
3017static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
3018{
3019 pAhciReq->uATARegError = 0;
3020 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
3021 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
3022 | ((pAhciReq->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
3023 | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
3024 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
3025 pAhciPort->abATAPISense[0] = 0x70;
3026 pAhciPort->abATAPISense[7] = 10;
3027}
3028
3029static void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
3030{
3031 Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
3032 pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
3033 pAhciReq->uATARegError = pabATAPISense[2] << 4;
3034 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
3035 pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
3036 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
3037 memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
3038 memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
3039}
3040
3041/** @todo deprecated function - doesn't provide enough info. Replace by direct
3042 * calls to atapiCmdError() with full data. */
3043static void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
3044{
3045 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
3046 memset(abATAPISense, '\0', sizeof(abATAPISense));
3047 abATAPISense[0] = 0x70 | (1 << 7);
3048 abATAPISense[2] = uATAPISenseKey & 0x0f;
3049 abATAPISense[7] = 10;
3050 abATAPISense[12] = uATAPIASC;
3051 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
3052}
3053
3054static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3055{
3056 for (uint32_t i = 0; i < cbSize; i++)
3057 {
3058 if (*pbSrc)
3059 pbDst[i] = *pbSrc++;
3060 else
3061 pbDst[i] = ' ';
3062 }
3063}
3064
3065static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
3066{
3067 for (uint32_t i = 0; i < cbSize; i++)
3068 {
3069 if (*pbSrc)
3070 pbDst[i ^ 1] = *pbSrc++;
3071 else
3072 pbDst[i ^ 1] = ' ';
3073 }
3074}
3075
3076static uint32_t ataChecksum(void* ptr, size_t count)
3077{
3078 uint8_t u8Sum = 0xa5, *p = (uint8_t*)ptr;
3079 size_t i;
3080
3081 for (i = 0; i < count; i++)
3082 {
3083 u8Sum += *p++;
3084 }
3085
3086 return (uint8_t)-(int32_t)u8Sum;
3087}
3088
3089static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
3090{
3091 uint16_t *p = (uint16_t *)pvBuf;
3092 memset(p, 0, 512);
3093 p[0] = RT_H2LE_U16(0x0040);
3094 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3095 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3096 /* Block size; obsolete, but required for the BIOS. */
3097 p[5] = RT_H2LE_U16(512);
3098 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3099 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3100 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3101 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3102 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
3103 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3104 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3105#if ATA_MAX_MULT_SECTORS > 1
3106 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
3107#endif
3108 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
3109 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3110 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3111 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3112 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3113 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
3114 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
3115 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
3116 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
3117 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
3118 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
3119 if (pAhciPort->cMultSectors)
3120 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
3121 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
3122 {
3123 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3124 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3125 }
3126 else
3127 {
3128 /* Report maximum number of sectors possible with LBA28 */
3129 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
3130 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
3131 }
3132 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3133 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3134 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3135 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3136 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3137 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3138 if ( pAhciPort->pDrvMedia->pfnDiscard
3139 || ( pAhciPort->fAsyncInterface
3140 && pAhciPort->pDrvMediaAsync->pfnStartDiscard)
3141 || pAhciPort->cbSector != 512
3142 || pAhciPort->fNonRotational)
3143 {
3144 p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
3145 p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
3146 }
3147 else
3148 {
3149 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3150 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3151 }
3152 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
3153 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3154 p[84] = RT_H2LE_U16(1 << 14);
3155 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
3156 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3157 p[87] = RT_H2LE_U16(1 << 14);
3158 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3159 p[93] = RT_H2LE_U16(0x00);
3160 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
3161 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
3162 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
3163 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
3164
3165 /* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
3166 if (pAhciPort->cLogSectorsPerPhysicalExp)
3167 p[106] = RT_H2LE_U16(RT_BIT(14) | RT_BIT(13) | pAhciPort->cLogSectorsPerPhysicalExp);
3168
3169 if (pAhciPort->cbSector != 512)
3170 {
3171 uint32_t cSectorSizeInWords = pAhciPort->cbSector / sizeof(uint16_t);
3172 /* Enable reporting of logical sector size. */
3173 p[106] |= RT_H2LE_U16(RT_BIT(12) | RT_BIT(14));
3174 p[117] = RT_H2LE_U16(cSectorSizeInWords);
3175 p[118] = RT_H2LE_U16(cSectorSizeInWords >> 16);
3176 }
3177
3178 if (pAhciPort->fNonRotational)
3179 p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
3180
3181 if ( pAhciPort->pDrvMedia->pfnDiscard
3182 || ( pAhciPort->fAsyncInterface
3183 && pAhciPort->pDrvMediaAsync->pfnStartDiscard)) /** @todo Set bit 14 in word 69 too? (Deterministic read after TRIM). */
3184 p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
3185
3186 /* The following are SATA specific */
3187 p[75] = RT_H2LE_U16(pAhciPort->CTX_SUFF(pAhci)->cCmdSlotsAvail-1); /* Number of commands we support, 0's based */
3188 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3189
3190 uint32_t uCsum = ataChecksum(p, 510);
3191 p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
3192
3193 return VINF_SUCCESS;
3194}
3195
3196typedef int (*PAtapiFunc)(PAHCIREQ, PAHCIPort, size_t, size_t *);
3197
3198static int atapiGetConfigurationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3199static int atapiGetEventStatusNotificationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3200static int atapiIdentifySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3201static int atapiInquirySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3202static int atapiMechanismStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3203static int atapiModeSenseErrorRecoverySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3204static int atapiModeSenseCDStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3205static int atapiReadCapacitySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3206static int atapiReadDiscInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3207static int atapiReadTOCNormalSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3208static int atapiReadTOCMultiSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3209static int atapiReadTOCRawSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3210static int atapiReadTrackInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3211static int atapiRequestSenseSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3212static int atapiPassthroughSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3213static int atapiReadDVDStructureSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
3214
3215/**
3216 * Source/sink function indexes for g_apfnAtapiFuncs.
3217 */
3218typedef enum ATAPIFN
3219{
3220 ATAFN_SS_NULL = 0,
3221 ATAFN_SS_ATAPI_GET_CONFIGURATION,
3222 ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION,
3223 ATAFN_SS_ATAPI_IDENTIFY,
3224 ATAFN_SS_ATAPI_INQUIRY,
3225 ATAFN_SS_ATAPI_MECHANISM_STATUS,
3226 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
3227 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
3228 ATAFN_SS_ATAPI_READ_CAPACITY,
3229 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
3230 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
3231 ATAFN_SS_ATAPI_READ_TOC_MULTI,
3232 ATAFN_SS_ATAPI_READ_TOC_RAW,
3233 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
3234 ATAFN_SS_ATAPI_REQUEST_SENSE,
3235 ATAFN_SS_ATAPI_PASSTHROUGH,
3236 ATAFN_SS_ATAPI_READ_DVD_STRUCTURE,
3237 ATAFN_SS_MAX
3238} ATAPIFN;
3239
3240/**
3241 * Array of source/sink functions, the index is ATAFNSS.
3242 * Make sure ATAFNSS and this array match!
3243 */
3244static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
3245{
3246 NULL,
3247 atapiGetConfigurationSS,
3248 atapiGetEventStatusNotificationSS,
3249 atapiIdentifySS,
3250 atapiInquirySS,
3251 atapiMechanismStatusSS,
3252 atapiModeSenseErrorRecoverySS,
3253 atapiModeSenseCDStatusSS,
3254 atapiReadCapacitySS,
3255 atapiReadDiscInformationSS,
3256 atapiReadTOCNormalSS,
3257 atapiReadTOCMultiSS,
3258 atapiReadTOCRawSS,
3259 atapiReadTrackInformationSS,
3260 atapiRequestSenseSS,
3261 atapiPassthroughSS,
3262 atapiReadDVDStructureSS
3263};
3264
3265static int atapiIdentifySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3266{
3267 uint16_t p[256];
3268
3269 memset(p, 0, 512);
3270 /* Removable CDROM, 50us response, 12 byte packets */
3271 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
3272 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
3273 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
3274 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
3275 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
3276 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
3277 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
3278 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
3279 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
3280 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
3281 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
3282 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
3283 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
3284 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
3285 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
3286 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
3287 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
3288 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
3289 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
3290 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
3291 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
3292 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
3293 p[83] = RT_H2LE_U16(1 << 14);
3294 p[84] = RT_H2LE_U16(1 << 14);
3295 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
3296 p[86] = RT_H2LE_U16(0);
3297 p[87] = RT_H2LE_U16(1 << 14);
3298 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
3299 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
3300
3301 /* The following are SATA specific */
3302 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
3303 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
3304
3305 /* Copy the buffer in to the scatter gather list. */
3306 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&p[0], RT_MIN(cbData, sizeof(p)));
3307
3308 atapiCmdOK(pAhciPort, pAhciReq);
3309 return VINF_SUCCESS;
3310}
3311
3312static int atapiReadCapacitySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3313{
3314 uint8_t aBuf[8];
3315
3316 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
3317 ataH2BE_U32(aBuf + 4, 2048);
3318
3319 /* Copy the buffer in to the scatter gather list. */
3320 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3321
3322 atapiCmdOK(pAhciPort, pAhciReq);
3323 return VINF_SUCCESS;
3324}
3325
3326
3327static int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3328{
3329 uint8_t aBuf[34];
3330
3331 memset(aBuf, '\0', 34);
3332 ataH2BE_U16(aBuf, 32);
3333 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
3334 aBuf[3] = 1; /* number of first track */
3335 aBuf[4] = 1; /* number of sessions (LSB) */
3336 aBuf[5] = 1; /* first track number in last session (LSB) */
3337 aBuf[6] = 1; /* last track number in last session (LSB) */
3338 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 */
3339 aBuf[8] = 0; /* disc type = CD-ROM */
3340 aBuf[9] = 0; /* number of sessions (MSB) */
3341 aBuf[10] = 0; /* number of sessions (MSB) */
3342 aBuf[11] = 0; /* number of sessions (MSB) */
3343 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
3344 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
3345
3346 /* Copy the buffer in to the scatter gather list. */
3347 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3348
3349 atapiCmdOK(pAhciPort, pAhciReq);
3350 return VINF_SUCCESS;
3351}
3352
3353
3354static int atapiReadTrackInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3355{
3356 uint8_t aBuf[36];
3357
3358 /* Accept address/number type of 1 only, and only track 1 exists. */
3359 if ((pAhciReq->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciReq->aATAPICmd[2]) != 1)
3360 {
3361 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3362 return VINF_SUCCESS;
3363 }
3364 memset(aBuf, '\0', 36);
3365 ataH2BE_U16(aBuf, 34);
3366 aBuf[2] = 1; /* track number (LSB) */
3367 aBuf[3] = 1; /* session number (LSB) */
3368 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
3369 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 */
3370 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
3371 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
3372 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
3373 aBuf[32] = 0; /* track number (MSB) */
3374 aBuf[33] = 0; /* session number (MSB) */
3375
3376 /* Copy the buffer in to the scatter gather list. */
3377 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3378
3379 atapiCmdOK(pAhciPort, pAhciReq);
3380 return VINF_SUCCESS;
3381}
3382
3383static size_t atapiGetConfigurationFillFeatureListProfiles(uint8_t *pbBuf, size_t cbBuf)
3384{
3385 if (cbBuf < 3*4)
3386 return 0;
3387
3388 ataH2BE_U16(pbBuf, 0x0); /* feature 0: list of profiles supported */
3389 pbBuf[2] = (0 << 2) | (1 << 1) | (1 << 0); /* version 0, persistent, current */
3390 pbBuf[3] = 8; /* additional bytes for profiles */
3391 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3392 * before CD-ROM read capability. */
3393 ataH2BE_U16(pbBuf + 4, 0x10); /* profile: read-only DVD */
3394 pbBuf[6] = (0 << 0); /* NOT current profile */
3395 ataH2BE_U16(pbBuf + 8, 0x08); /* profile: read only CD */
3396 pbBuf[10] = (1 << 0); /* current profile */
3397
3398 return 3*4; /* Header + 2 profiles entries */
3399}
3400
3401static size_t atapiGetConfigurationFillFeatureCore(uint8_t *pbBuf, size_t cbBuf)
3402{
3403 if (cbBuf < 12)
3404 return 0;
3405
3406 ataH2BE_U16(pbBuf, 0x1); /* feature 0001h: Core Feature */
3407 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3408 pbBuf[3] = 8; /* Additional length */
3409 ataH2BE_U16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
3410 pbBuf[8] = RT_BIT(0); /* DBE */
3411 /* Rest is reserved. */
3412
3413 return 12;
3414}
3415
3416static size_t atapiGetConfigurationFillFeatureMorphing(uint8_t *pbBuf, size_t cbBuf)
3417{
3418 if (cbBuf < 8)
3419 return 0;
3420
3421 ataH2BE_U16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
3422 pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3423 pbBuf[3] = 4; /* Additional length */
3424 pbBuf[4] = RT_BIT(1) | 0x0; /* OCEvent | !ASYNC */
3425 /* Rest is reserved. */
3426
3427 return 8;
3428}
3429
3430static size_t atapiGetConfigurationFillFeatureRemovableMedium(uint8_t *pbBuf, size_t cbBuf)
3431{
3432 if (cbBuf < 8)
3433 return 0;
3434
3435 ataH2BE_U16(pbBuf, 0x3); /* feature 0003h: Removable Medium Feature */
3436 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3437 pbBuf[3] = 4; /* Additional length */
3438 /* Tray type loading | Load | Eject | !Pvnt Jmpr | !DBML | Lock */
3439 pbBuf[4] = (0x2 << 5) | RT_BIT(4) | RT_BIT(3) | (0x0 << 2) | (0x0 << 1) | RT_BIT(0);
3440 /* Rest is reserved. */
3441
3442 return 8;
3443}
3444
3445static size_t atapiGetConfigurationFillFeatureRandomReadable(uint8_t *pbBuf, size_t cbBuf)
3446{
3447 if (cbBuf < 12)
3448 return 0;
3449
3450 ataH2BE_U16(pbBuf, 0x10); /* feature 0010h: Random Readable Feature */
3451 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3452 pbBuf[3] = 8; /* Additional length */
3453 ataH2BE_U32(pbBuf + 4, 2048); /* Logical block size. */
3454 ataH2BE_U16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
3455 pbBuf[10] = 0; /* PP not present */
3456 /* Rest is reserved. */
3457
3458 return 12;
3459}
3460
3461static size_t atapiGetConfigurationFillFeatureCDRead(uint8_t *pbBuf, size_t cbBuf)
3462{
3463 if (cbBuf < 8)
3464 return 0;
3465
3466 ataH2BE_U16(pbBuf, 0x1e); /* feature 001Eh: CD Read Feature */
3467 pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3468 pbBuf[3] = 0; /* Additional length */
3469 pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
3470 /* Rest is reserved. */
3471
3472 return 8;
3473}
3474
3475static size_t atapiGetConfigurationFillFeaturePowerManagement(uint8_t *pbBuf, size_t cbBuf)
3476{
3477 if (cbBuf < 4)
3478 return 0;
3479
3480 ataH2BE_U16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
3481 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3482 pbBuf[3] = 0; /* Additional length */
3483
3484 return 4;
3485}
3486
3487static size_t atapiGetConfigurationFillFeatureTimeout(uint8_t *pbBuf, size_t cbBuf)
3488{
3489 if (cbBuf < 8)
3490 return 0;
3491
3492 ataH2BE_U16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
3493 pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
3494 pbBuf[3] = 4; /* Additional length */
3495 pbBuf[4] = 0x0; /* !Group3 */
3496
3497 return 8;
3498}
3499
3500static int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3501{
3502 uint8_t aBuf[80];
3503 uint8_t *pbBuf = &aBuf[0];
3504 size_t cbBuf = sizeof(aBuf);
3505 size_t cbCopied = 0;
3506
3507 /* Accept valid request types only, and only starting feature 0. */
3508 if ((pAhciReq->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciReq->aATAPICmd[2]) != 0)
3509 {
3510 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3511 return VINF_SUCCESS;
3512 }
3513 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3514 * way to differentiate them right now is based on the image size). */
3515 if (pAhciPort->cTotalSectors)
3516 ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
3517 else
3518 ataH2BE_U16(pbBuf + 6, 0x00); /* current profile: none -> no media */
3519 cbBuf -= 8;
3520 pbBuf += 8;
3521
3522 cbCopied = atapiGetConfigurationFillFeatureListProfiles(pbBuf, cbBuf);
3523 cbBuf -= cbCopied;
3524 pbBuf += cbCopied;
3525
3526 cbCopied = atapiGetConfigurationFillFeatureCore(pbBuf, cbBuf);
3527 cbBuf -= cbCopied;
3528 pbBuf += cbCopied;
3529
3530 cbCopied = atapiGetConfigurationFillFeatureMorphing(pbBuf, cbBuf);
3531 cbBuf -= cbCopied;
3532 pbBuf += cbCopied;
3533
3534 cbCopied = atapiGetConfigurationFillFeatureRemovableMedium(pbBuf, cbBuf);
3535 cbBuf -= cbCopied;
3536 pbBuf += cbCopied;
3537
3538 cbCopied = atapiGetConfigurationFillFeatureRandomReadable(pbBuf, cbBuf);
3539 cbBuf -= cbCopied;
3540 pbBuf += cbCopied;
3541
3542 cbCopied = atapiGetConfigurationFillFeatureCDRead(pbBuf, cbBuf);
3543 cbBuf -= cbCopied;
3544 pbBuf += cbCopied;
3545
3546 cbCopied = atapiGetConfigurationFillFeaturePowerManagement(pbBuf, cbBuf);
3547 cbBuf -= cbCopied;
3548 pbBuf += cbCopied;
3549
3550 cbCopied = atapiGetConfigurationFillFeatureTimeout(pbBuf, cbBuf);
3551 cbBuf -= cbCopied;
3552 pbBuf += cbCopied;
3553
3554 /* Set data length now. */
3555 ataH2BE_U32(&aBuf[0], (uint32_t)(sizeof(aBuf) - cbBuf));
3556
3557 /* Copy the buffer in to the scatter gather list. */
3558 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3559
3560 atapiCmdOK(pAhciPort, pAhciReq);
3561 return VINF_SUCCESS;
3562}
3563
3564
3565static int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3566{
3567 uint8_t abBuf[8];
3568
3569 Assert(pAhciReq->enmTxDir == AHCITXDIR_READ);
3570 Assert(pAhciReq->cbTransfer <= 8);
3571
3572 if (!(pAhciReq->aATAPICmd[1] & 1))
3573 {
3574 /* no asynchronous operation supported */
3575 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3576 return VINF_SUCCESS;
3577 }
3578
3579 uint32_t OldStatus, NewStatus;
3580 do
3581 {
3582 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
3583 NewStatus = ATA_EVENT_STATUS_UNCHANGED;
3584 switch (OldStatus)
3585 {
3586 case ATA_EVENT_STATUS_MEDIA_NEW:
3587 /* mount */
3588 ataH2BE_U16(abBuf + 0, 6);
3589 abBuf[2] = 0x04; /* media */
3590 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3591 abBuf[4] = 0x02; /* new medium */
3592 abBuf[5] = 0x02; /* medium present / door closed */
3593 abBuf[6] = 0x00;
3594 abBuf[7] = 0x00;
3595 break;
3596
3597 case ATA_EVENT_STATUS_MEDIA_CHANGED:
3598 case ATA_EVENT_STATUS_MEDIA_REMOVED:
3599 /* umount */
3600 ataH2BE_U16(abBuf + 0, 6);
3601 abBuf[2] = 0x04; /* media */
3602 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3603 abBuf[4] = 0x03; /* media removal */
3604 abBuf[5] = 0x00; /* medium absent / door closed */
3605 abBuf[6] = 0x00;
3606 abBuf[7] = 0x00;
3607 if (OldStatus == ATA_EVENT_STATUS_MEDIA_CHANGED)
3608 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
3609 break;
3610
3611 case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
3612 ataH2BE_U16(abBuf + 0, 6);
3613 abBuf[2] = 0x04; /* media */
3614 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3615 abBuf[4] = 0x01; /* eject requested (eject button pressed) */
3616 abBuf[5] = 0x02; /* medium present / door closed */
3617 abBuf[6] = 0x00;
3618 abBuf[7] = 0x00;
3619 break;
3620
3621 case ATA_EVENT_STATUS_UNCHANGED:
3622 default:
3623 ataH2BE_U16(abBuf + 0, 6);
3624 abBuf[2] = 0x01; /* operational change request / notification */
3625 abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
3626 abBuf[4] = 0x00;
3627 abBuf[5] = 0x00;
3628 abBuf[6] = 0x00;
3629 abBuf[7] = 0x00;
3630 break;
3631 }
3632 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
3633
3634 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&abBuf[0], RT_MIN(cbData, sizeof(abBuf)));
3635
3636 atapiCmdOK(pAhciPort, pAhciReq);
3637 return VINF_SUCCESS;
3638}
3639
3640
3641static int atapiInquirySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3642{
3643 uint8_t aBuf[36];
3644
3645 aBuf[0] = 0x05; /* CD-ROM */
3646 aBuf[1] = 0x80; /* removable */
3647 aBuf[2] = 0x00; /* ISO */
3648 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3649 aBuf[4] = 31; /* additional length */
3650 aBuf[5] = 0; /* reserved */
3651 aBuf[6] = 0; /* reserved */
3652 aBuf[7] = 0; /* reserved */
3653 ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
3654 ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
3655 ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
3656
3657 /* Copy the buffer in to the scatter gather list. */
3658 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3659
3660 atapiCmdOK(pAhciPort, pAhciReq);
3661 return VINF_SUCCESS;
3662}
3663
3664
3665static int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3666{
3667 uint8_t aBuf[16];
3668
3669 ataH2BE_U16(&aBuf[0], 16 + 6);
3670 aBuf[2] = 0x70;
3671 aBuf[3] = 0;
3672 aBuf[4] = 0;
3673 aBuf[5] = 0;
3674 aBuf[6] = 0;
3675 aBuf[7] = 0;
3676
3677 aBuf[8] = 0x01;
3678 aBuf[9] = 0x06;
3679 aBuf[10] = 0x00;
3680 aBuf[11] = 0x05;
3681 aBuf[12] = 0x00;
3682 aBuf[13] = 0x00;
3683 aBuf[14] = 0x00;
3684 aBuf[15] = 0x00;
3685
3686 /* Copy the buffer in to the scatter gather list. */
3687 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3688
3689 atapiCmdOK(pAhciPort, pAhciReq);
3690 return VINF_SUCCESS;
3691}
3692
3693
3694static int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3695{
3696 uint8_t aBuf[40];
3697
3698 ataH2BE_U16(&aBuf[0], 38);
3699 aBuf[2] = 0x70;
3700 aBuf[3] = 0;
3701 aBuf[4] = 0;
3702 aBuf[5] = 0;
3703 aBuf[6] = 0;
3704 aBuf[7] = 0;
3705
3706 aBuf[8] = 0x2a;
3707 aBuf[9] = 30; /* page length */
3708 aBuf[10] = 0x08; /* DVD-ROM read support */
3709 aBuf[11] = 0x00; /* no write support */
3710 /* The following claims we support audio play. This is obviously false,
3711 * but the Linux generic CDROM support makes many features depend on this
3712 * capability. If it's not set, this causes many things to be disabled. */
3713 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3714 aBuf[13] = 0x00; /* no subchannel reads supported */
3715 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3716 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3717 aBuf[14] |= 1 << 1; /* report lock state */
3718 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3719 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3720 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3721 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3722 Just write the value DevATA is using. */
3723 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3724 aBuf[24] = 0; /* reserved */
3725 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3726 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3727 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3728 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3729 aBuf[32] = 0; /* reserved */
3730 aBuf[33] = 0; /* reserved */
3731 aBuf[34] = 0; /* reserved */
3732 aBuf[35] = 1; /* rotation control CAV */
3733 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3734 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3735
3736 /* Copy the buffer in to the scatter gather list. */
3737 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3738
3739 atapiCmdOK(pAhciPort, pAhciReq);
3740 return VINF_SUCCESS;
3741}
3742
3743
3744static int atapiRequestSenseSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3745{
3746 /* Copy the buffer in to the scatter gather list. */
3747 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
3748 pAhciPort->abATAPISense, RT_MIN(cbData, sizeof(pAhciPort->abATAPISense)));
3749
3750 atapiCmdOK(pAhciPort, pAhciReq);
3751 return VINF_SUCCESS;
3752}
3753
3754
3755static int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3756{
3757 uint8_t aBuf[8];
3758
3759 ataH2BE_U16(&aBuf[0], 0);
3760 /* no current LBA */
3761 aBuf[2] = 0;
3762 aBuf[3] = 0;
3763 aBuf[4] = 0;
3764 aBuf[5] = 1;
3765 ataH2BE_U16(aBuf + 6, 0);
3766
3767 /* Copy the buffer in to the scatter gather list. */
3768 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3769
3770 atapiCmdOK(pAhciPort, pAhciReq);
3771 return VINF_SUCCESS;
3772}
3773
3774
3775static int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3776{
3777 uint8_t aBuf[20], *q, iStartTrack;
3778 bool fMSF;
3779 uint32_t cbSize;
3780
3781 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3782 iStartTrack = pAhciReq->aATAPICmd[6];
3783 if (iStartTrack > 1 && iStartTrack != 0xaa)
3784 {
3785 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3786 return VINF_SUCCESS;
3787 }
3788 q = aBuf + 2;
3789 *q++ = 1; /* first session */
3790 *q++ = 1; /* last session */
3791 if (iStartTrack <= 1)
3792 {
3793 *q++ = 0; /* reserved */
3794 *q++ = 0x14; /* ADR, control */
3795 *q++ = 1; /* track number */
3796 *q++ = 0; /* reserved */
3797 if (fMSF)
3798 {
3799 *q++ = 0; /* reserved */
3800 ataLBA2MSF(q, 0);
3801 q += 3;
3802 }
3803 else
3804 {
3805 /* sector 0 */
3806 ataH2BE_U32(q, 0);
3807 q += 4;
3808 }
3809 }
3810 /* lead out track */
3811 *q++ = 0; /* reserved */
3812 *q++ = 0x14; /* ADR, control */
3813 *q++ = 0xaa; /* track number */
3814 *q++ = 0; /* reserved */
3815 if (fMSF)
3816 {
3817 *q++ = 0; /* reserved */
3818 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3819 q += 3;
3820 }
3821 else
3822 {
3823 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3824 q += 4;
3825 }
3826 cbSize = q - aBuf;
3827 ataH2BE_U16(aBuf, cbSize - 2);
3828
3829 /* Copy the buffer in to the scatter gather list. */
3830 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, cbSize));
3831
3832 atapiCmdOK(pAhciPort, pAhciReq);
3833 return VINF_SUCCESS;
3834}
3835
3836
3837static int atapiReadTOCMultiSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3838{
3839 uint8_t aBuf[12];
3840 bool fMSF;
3841
3842 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3843 /* multi session: only a single session defined */
3844/** @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. */
3845 memset(aBuf, 0, 12);
3846 aBuf[1] = 0x0a;
3847 aBuf[2] = 0x01;
3848 aBuf[3] = 0x01;
3849 aBuf[5] = 0x14; /* ADR, control */
3850 aBuf[6] = 1; /* first track in last complete session */
3851 if (fMSF)
3852 {
3853 aBuf[8] = 0; /* reserved */
3854 ataLBA2MSF(&aBuf[9], 0);
3855 }
3856 else
3857 {
3858 /* sector 0 */
3859 ataH2BE_U32(aBuf + 8, 0);
3860 }
3861
3862 /* Copy the buffer in to the scatter gather list. */
3863 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, sizeof(aBuf)));
3864
3865 atapiCmdOK(pAhciPort, pAhciReq);
3866 return VINF_SUCCESS;
3867}
3868
3869
3870static int atapiReadTOCRawSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3871{
3872 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3873 uint8_t *q, iStartTrack;
3874 bool fMSF;
3875 uint32_t cbSize;
3876
3877 fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
3878 iStartTrack = pAhciReq->aATAPICmd[6];
3879
3880 q = aBuf + 2;
3881 *q++ = 1; /* first session */
3882 *q++ = 1; /* last session */
3883
3884 *q++ = 1; /* session number */
3885 *q++ = 0x14; /* data track */
3886 *q++ = 0; /* track number */
3887 *q++ = 0xa0; /* first track in program area */
3888 *q++ = 0; /* min */
3889 *q++ = 0; /* sec */
3890 *q++ = 0; /* frame */
3891 *q++ = 0;
3892 *q++ = 1; /* first track */
3893 *q++ = 0x00; /* disk type CD-DA or CD data */
3894 *q++ = 0;
3895
3896 *q++ = 1; /* session number */
3897 *q++ = 0x14; /* data track */
3898 *q++ = 0; /* track number */
3899 *q++ = 0xa1; /* last track in program area */
3900 *q++ = 0; /* min */
3901 *q++ = 0; /* sec */
3902 *q++ = 0; /* frame */
3903 *q++ = 0;
3904 *q++ = 1; /* last track */
3905 *q++ = 0;
3906 *q++ = 0;
3907
3908 *q++ = 1; /* session number */
3909 *q++ = 0x14; /* data track */
3910 *q++ = 0; /* track number */
3911 *q++ = 0xa2; /* lead-out */
3912 *q++ = 0; /* min */
3913 *q++ = 0; /* sec */
3914 *q++ = 0; /* frame */
3915 if (fMSF)
3916 {
3917 *q++ = 0; /* reserved */
3918 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3919 q += 3;
3920 }
3921 else
3922 {
3923 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3924 q += 4;
3925 }
3926
3927 *q++ = 1; /* session number */
3928 *q++ = 0x14; /* ADR, control */
3929 *q++ = 0; /* track number */
3930 *q++ = 1; /* point */
3931 *q++ = 0; /* min */
3932 *q++ = 0; /* sec */
3933 *q++ = 0; /* frame */
3934 if (fMSF)
3935 {
3936 *q++ = 0; /* reserved */
3937 ataLBA2MSF(q, 0);
3938 q += 3;
3939 }
3940 else
3941 {
3942 /* sector 0 */
3943 ataH2BE_U32(q, 0);
3944 q += 4;
3945 }
3946
3947 cbSize = q - aBuf;
3948 ataH2BE_U16(aBuf, cbSize - 2);
3949
3950 /* Copy the buffer in to the scatter gather list. */
3951 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, cbSize));
3952
3953 atapiCmdOK(pAhciPort, pAhciReq);
3954 return VINF_SUCCESS;
3955}
3956
3957/**
3958 * Sets the given media track type.
3959 */
3960static uint32_t ahciMediumTypeSet(PAHCIPort pAhciPort, uint32_t MediaTrackType)
3961{
3962 return ASMAtomicXchgU32(&pAhciPort->MediaTrackType, MediaTrackType);
3963}
3964
3965static int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
3966{
3967 RT_NOREF(cbData);
3968 int rc = VINF_SUCCESS;
3969 uint8_t abATAPISense[ATAPI_SENSE_SIZE];
3970 uint32_t cbTransfer;
3971 void *pvBuf = NULL;
3972
3973 cbTransfer = pAhciReq->cbTransfer;
3974
3975 if (cbTransfer)
3976 {
3977 pvBuf = (uint8_t *)RTMemAlloc(cbTransfer);
3978 if (!pvBuf)
3979 return VERR_NO_MEMORY;
3980
3981 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
3982 {
3983 ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf, cbTransfer);
3984 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
3985 return VINF_SUCCESS;
3986 }
3987 }
3988
3989 /* Simple heuristics: if there is at least one sector of data
3990 * to transfer, it's worth updating the LEDs. */
3991 if (cbTransfer >= 2048)
3992 {
3993 if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
3994 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
3995 else
3996 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
3997 }
3998
3999 if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
4000 {
4001 /* Linux accepts commands with up to 100KB of data, but expects
4002 * us to handle commands with up to 128KB of data. The usual
4003 * imbalance of powers. */
4004 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
4005 uint32_t iATAPILBA, cSectors;
4006 uint8_t *pbBuf = (uint8_t *)pvBuf;
4007
4008 switch (pAhciReq->aATAPICmd[0])
4009 {
4010 case SCSI_READ_10:
4011 case SCSI_WRITE_10:
4012 case SCSI_WRITE_AND_VERIFY_10:
4013 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
4014 cSectors = ataBE2H_U16(pAhciReq->aATAPICmd + 7);
4015 break;
4016 case SCSI_READ_12:
4017 case SCSI_WRITE_12:
4018 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
4019 cSectors = ataBE2H_U32(pAhciReq->aATAPICmd + 6);
4020 break;
4021 case SCSI_READ_CD:
4022 iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
4023 cSectors = ataBE2H_U24(pAhciReq->aATAPICmd + 6);
4024 break;
4025 case SCSI_READ_CD_MSF:
4026 iATAPILBA = ataMSF2LBA(pAhciReq->aATAPICmd + 3);
4027 cSectors = ataMSF2LBA(pAhciReq->aATAPICmd + 6) - iATAPILBA;
4028 break;
4029 default:
4030 AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciReq->aATAPICmd[0]));
4031 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4032 LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
4033 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4034 RTMemFree(pvBuf);
4035 return VINF_SUCCESS;
4036 }
4037 memcpy(aATAPICmd, pAhciReq->aATAPICmd, ATAPI_PACKET_SIZE);
4038 uint32_t cReqSectors = 0;
4039 for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
4040 {
4041 if (i * pAhciReq->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
4042 cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciReq->cbATAPISector;
4043 else
4044 cReqSectors = i;
4045 uint32_t cbCurrTX = pAhciReq->cbATAPISector * cReqSectors;
4046 switch (pAhciReq->aATAPICmd[0])
4047 {
4048 case SCSI_READ_10:
4049 case SCSI_WRITE_10:
4050 case SCSI_WRITE_AND_VERIFY_10:
4051 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4052 ataH2BE_U16(aATAPICmd + 7, cReqSectors);
4053 break;
4054 case SCSI_READ_12:
4055 case SCSI_WRITE_12:
4056 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4057 ataH2BE_U32(aATAPICmd + 6, cReqSectors);
4058 break;
4059 case SCSI_READ_CD:
4060 ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
4061 ataH2BE_U24(aATAPICmd + 6, cReqSectors);
4062 break;
4063 case SCSI_READ_CD_MSF:
4064 ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
4065 ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
4066 break;
4067 }
4068 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4069 aATAPICmd,
4070 pAhciReq->enmTxDir == AHCITXDIR_READ
4071 ? PDMMEDIATXDIR_FROM_DEVICE
4072 : PDMMEDIATXDIR_TO_DEVICE,
4073 pbBuf,
4074 &cbCurrTX,
4075 abATAPISense,
4076 sizeof(abATAPISense),
4077 30000 /**< @todo timeout */);
4078 if (rc != VINF_SUCCESS)
4079 break;
4080 iATAPILBA += cReqSectors;
4081 pbBuf += pAhciReq->cbATAPISector * cReqSectors;
4082 }
4083 }
4084 else
4085 {
4086 PDMMEDIATXDIR enmBlockTxDir = PDMMEDIATXDIR_NONE;
4087
4088 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
4089 enmBlockTxDir = PDMMEDIATXDIR_FROM_DEVICE;
4090 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
4091 enmBlockTxDir = PDMMEDIATXDIR_TO_DEVICE;
4092 else if (pAhciReq->enmTxDir == AHCITXDIR_NONE)
4093 enmBlockTxDir = PDMMEDIATXDIR_NONE;
4094 else
4095 AssertMsgFailed(("Invalid transfer direction %d\n", pAhciReq->enmTxDir));
4096
4097 rc = pAhciPort->pDrvMedia->pfnSendCmd(pAhciPort->pDrvMedia,
4098 pAhciReq->aATAPICmd,
4099 enmBlockTxDir,
4100 pvBuf,
4101 &cbTransfer,
4102 abATAPISense,
4103 sizeof(abATAPISense),
4104 30000 /**< @todo timeout */);
4105 }
4106
4107 /* Update the LEDs and the read/write statistics. */
4108 if (cbTransfer >= 2048)
4109 {
4110 if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
4111 {
4112 pAhciPort->Led.Actual.s.fReading = 0;
4113 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
4114 }
4115 else
4116 {
4117 pAhciPort->Led.Actual.s.fWriting = 0;
4118 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
4119 }
4120 }
4121
4122 if (RT_SUCCESS(rc))
4123 {
4124 /* Do post processing for certain commands. */
4125 switch (pAhciReq->aATAPICmd[0])
4126 {
4127 case SCSI_SEND_CUE_SHEET:
4128 case SCSI_READ_TOC_PMA_ATIP:
4129 {
4130 if (!pAhciPort->pTrackList)
4131 rc = ATAPIPassthroughTrackListCreateEmpty(&pAhciPort->pTrackList);
4132
4133 if (RT_SUCCESS(rc))
4134 rc = ATAPIPassthroughTrackListUpdate(pAhciPort->pTrackList, pAhciReq->aATAPICmd, pvBuf);
4135
4136 if ( RT_FAILURE(rc)
4137 && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4138 LogRel(("AHCI: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n",
4139 rc, pAhciReq->aATAPICmd[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP"));
4140 break;
4141 }
4142 case SCSI_SYNCHRONIZE_CACHE:
4143 {
4144 if (pAhciPort->pTrackList)
4145 ATAPIPassthroughTrackListClear(pAhciPort->pTrackList);
4146 break;
4147 }
4148 }
4149
4150 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
4151 {
4152 Assert(cbTransfer <= pAhciReq->cbTransfer);
4153
4154 if (pAhciReq->aATAPICmd[0] == SCSI_INQUIRY)
4155 {
4156 /* Make sure that the real drive cannot be identified.
4157 * Motivation: changing the VM configuration should be as
4158 * invisible as possible to the guest. */
4159 if (cbTransfer >= 8 + 8)
4160 ataSCSIPadStr((uint8_t *)pvBuf + 8, "VBOX", 8);
4161 if (cbTransfer >= 16 + 16)
4162 ataSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
4163 if (cbTransfer >= 32 + 4)
4164 ataSCSIPadStr((uint8_t *)pvBuf + 32, "1.0", 4);
4165 }
4166
4167 if (cbTransfer)
4168 {
4169 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
4170
4171 /* Reply with the same amount of data as the real drive. */
4172 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf, cbTransfer);
4173 }
4174 else
4175 *pcbData = 0;
4176 }
4177 else
4178 *pcbData = cbTransfer;
4179 atapiCmdOK(pAhciPort, pAhciReq);
4180 }
4181 else
4182 {
4183 if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
4184 {
4185 uint8_t u8Cmd = pAhciReq->aATAPICmd[0];
4186 do
4187 {
4188 /* don't log superfluous errors */
4189 if ( rc == VERR_DEV_IO_ERROR
4190 && ( u8Cmd == SCSI_TEST_UNIT_READY
4191 || u8Cmd == SCSI_READ_CAPACITY
4192 || u8Cmd == SCSI_READ_DVD_STRUCTURE
4193 || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
4194 break;
4195 pAhciPort->cErrors++;
4196 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
4197 pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
4198 } while (0);
4199 }
4200 atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
4201 }
4202
4203 if (pvBuf)
4204 RTMemFree(pvBuf);
4205
4206 return VINF_SUCCESS;
4207}
4208
4209/** @todo Revise ASAP. */
4210/* Keep in sync with DevATA.cpp! */
4211static int atapiReadDVDStructureSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
4212{
4213 uint8_t aBuf[25]; /* Counted a maximum of 20 bytes but better be on the safe side. */
4214 uint8_t *buf = aBuf;
4215 int media = pAhciReq->aATAPICmd[1];
4216 int format = pAhciReq->aATAPICmd[7];
4217
4218 uint16_t max_len = RT_MIN(ataBE2H_U16(&pAhciReq->aATAPICmd[8]), sizeof(aBuf));
4219
4220 memset(buf, 0, max_len);
4221
4222 switch (format) {
4223 case 0x00:
4224 case 0x01:
4225 case 0x02:
4226 case 0x03:
4227 case 0x04:
4228 case 0x05:
4229 case 0x06:
4230 case 0x07:
4231 case 0x08:
4232 case 0x09:
4233 case 0x0a:
4234 case 0x0b:
4235 case 0x0c:
4236 case 0x0d:
4237 case 0x0e:
4238 case 0x0f:
4239 case 0x10:
4240 case 0x11:
4241 case 0x30:
4242 case 0x31:
4243 case 0xff:
4244 if (media == 0)
4245 {
4246 int uASC = SCSI_ASC_NONE;
4247
4248 switch (format)
4249 {
4250 case 0x0: /* Physical format information */
4251 {
4252 int layer = pAhciReq->aATAPICmd[6];
4253 uint64_t total_sectors;
4254
4255 if (layer != 0)
4256 {
4257 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4258 break;
4259 }
4260
4261 total_sectors = pAhciPort->cTotalSectors;
4262 total_sectors >>= 2;
4263 if (total_sectors == 0)
4264 {
4265 uASC = -SCSI_ASC_MEDIUM_NOT_PRESENT;
4266 break;
4267 }
4268
4269 buf[4] = 1; /* DVD-ROM, part version 1 */
4270 buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
4271 buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
4272 buf[7] = 0; /* default densities */
4273
4274 /* FIXME: 0x30000 per spec? */
4275 ataH2BE_U32(buf + 8, 0); /* start sector */
4276 ataH2BE_U32(buf + 12, total_sectors - 1); /* end sector */
4277 ataH2BE_U32(buf + 16, total_sectors - 1); /* l0 end sector */
4278
4279 /* Size of buffer, not including 2 byte size field */
4280 ataH2BE_U32(&buf[0], 2048 + 2);
4281
4282 /* 2k data + 4 byte header */
4283 uASC = (2048 + 4);
4284 break;
4285 }
4286 case 0x01: /* DVD copyright information */
4287 buf[4] = 0; /* no copyright data */
4288 buf[5] = 0; /* no region restrictions */
4289
4290 /* Size of buffer, not including 2 byte size field */
4291 ataH2BE_U16(buf, 4 + 2);
4292
4293 /* 4 byte header + 4 byte data */
4294 uASC = (4 + 4);
4295 break;
4296
4297 case 0x03: /* BCA information - invalid field for no BCA info */
4298 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4299 break;
4300
4301 case 0x04: /* DVD disc manufacturing information */
4302 /* Size of buffer, not including 2 byte size field */
4303 ataH2BE_U16(buf, 2048 + 2);
4304
4305 /* 2k data + 4 byte header */
4306 uASC = (2048 + 4);
4307 break;
4308 case 0xff:
4309 /*
4310 * This lists all the command capabilities above. Add new ones
4311 * in order and update the length and buffer return values.
4312 */
4313
4314 buf[4] = 0x00; /* Physical format */
4315 buf[5] = 0x40; /* Not writable, is readable */
4316 ataH2BE_U16((buf + 6), 2048 + 4);
4317
4318 buf[8] = 0x01; /* Copyright info */
4319 buf[9] = 0x40; /* Not writable, is readable */
4320 ataH2BE_U16((buf + 10), 4 + 4);
4321
4322 buf[12] = 0x03; /* BCA info */
4323 buf[13] = 0x40; /* Not writable, is readable */
4324 ataH2BE_U16((buf + 14), 188 + 4);
4325
4326 buf[16] = 0x04; /* Manufacturing info */
4327 buf[17] = 0x40; /* Not writable, is readable */
4328 ataH2BE_U16((buf + 18), 2048 + 4);
4329
4330 /* Size of buffer, not including 2 byte size field */
4331 ataH2BE_U16(buf, 16 + 2);
4332
4333 /* data written + 4 byte header */
4334 uASC = (16 + 4);
4335 break;
4336 default: /** @todo formats beyond DVD-ROM requires */
4337 uASC = -SCSI_ASC_INV_FIELD_IN_CMD_PACKET;
4338 }
4339
4340 if (uASC < 0)
4341 {
4342 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, -uASC);
4343 return false;
4344 }
4345 break;
4346 }
4347 /** @todo BD support, fall through for now */
4348
4349 /* Generic disk structures */
4350 case 0x80: /** @todo AACS volume identifier */
4351 case 0x81: /** @todo AACS media serial number */
4352 case 0x82: /** @todo AACS media identifier */
4353 case 0x83: /** @todo AACS media key block */
4354 case 0x90: /** @todo List of recognized format layers */
4355 case 0xc0: /** @todo Write protection status */
4356 default:
4357 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST,
4358 SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4359 return false;
4360 }
4361
4362 /* Copy the buffer into the scatter gather list. */
4363 *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0], RT_MIN(cbData, max_len));
4364
4365 atapiCmdOK(pAhciPort, pAhciReq);
4366 return false;
4367}
4368
4369static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
4370{
4371 size_t cbTransfered = 0;
4372 int rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax, &cbTransfered);
4373
4374 pAhciReq->cmdHdr.u32PRDBC = (uint32_t)cbTransfered;
4375 pAhciReq->cbTransfer = (uint32_t)cbTransfered;
4376 Assert(pAhciReq->cbTransfer == cbTransfered);
4377
4378 LogFlow(("cbTransfered=%d\n", cbTransfered));
4379
4380 /* Write updated command header into memory of the guest. */
4381 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
4382
4383 return rcSourceSink;
4384}
4385
4386static DECLCALLBACK(int) atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc)
4387{
4388 uint8_t *pbBuf = NULL;
4389 uint32_t cSectors = pAhciReq->cbTransfer / 2048;
4390 uint32_t iATAPILBA = pAhciReq->uOffset / 2048;
4391 uint8_t *pbBufDst;
4392 uint8_t *pbBufSrc = (uint8_t *)pAhciReq->u.Io.DataSeg.pvSeg;
4393 size_t cbAlloc = pAhciReq->cbTransfer + cSectors * (1 + 11 + 3 + 1 + 288); /* Per sector data like ECC. */
4394
4395 pbBuf = (uint8_t *)RTMemAlloc(cbAlloc);
4396 if (RT_UNLIKELY(!pbBuf))
4397 return VERR_NO_MEMORY;
4398
4399 pbBufDst = pbBuf;
4400
4401 for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4402 {
4403 /* sync bytes */
4404 *pbBufDst++ = 0x00;
4405 memset(pbBufDst, 0xff, 11);
4406 pbBufDst += 11;
4407 /* MSF */
4408 ataLBA2MSF(pbBufDst, i);
4409 pbBufDst += 3;
4410 *pbBufDst++ = 0x01; /* mode 1 data */
4411 /* data */
4412 memcpy(pbBufDst, pbBufSrc, 2048);
4413 pbBufDst += 2048;
4414 pbBufSrc += 2048;
4415 /* ECC */
4416 memset(pbBufDst, 0, 288);
4417 pbBufDst += 288;
4418 }
4419
4420 *ppvProc = pbBuf;
4421 *pcbProc = cbAlloc;
4422
4423 return VINF_SUCCESS;
4424}
4425
4426static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
4427{
4428 RT_NOREF(pAhciPort);
4429 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
4430
4431 switch (cbSector)
4432 {
4433 case 2048:
4434 pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
4435 pAhciReq->cbTransfer = cSectors * cbSector;
4436 break;
4437 case 2352:
4438 {
4439 pAhciReq->u.Io.pfnPostProcess = atapiReadSectors2352PostProcess;
4440 pAhciReq->uOffset = (uint64_t)iATAPILBA * 2048;
4441 pAhciReq->cbTransfer = cSectors * 2048;
4442 break;
4443 }
4444 default:
4445 AssertMsgFailed(("Unsupported sectors size\n"));
4446 break;
4447 }
4448
4449 return VINF_SUCCESS;
4450}
4451
4452static AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4453{
4454 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4455 const uint8_t *pbPacket;
4456 uint32_t cbMax;
4457
4458 pbPacket = pAhciReq->aATAPICmd;
4459
4460 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
4461
4462 switch (pbPacket[0])
4463 {
4464 case SCSI_TEST_UNIT_READY:
4465 if (pAhciPort->cNotifiedMediaChange > 0)
4466 {
4467 if (pAhciPort->cNotifiedMediaChange-- > 2)
4468 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4469 else
4470 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4471 }
4472 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4473 atapiCmdOK(pAhciPort, pAhciReq);
4474 else
4475 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4476 break;
4477 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4478 cbMax = ataBE2H_U16(pbPacket + 7);
4479 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4480 break;
4481 case SCSI_MODE_SENSE_10:
4482 {
4483 uint8_t uPageControl, uPageCode;
4484 cbMax = ataBE2H_U16(pbPacket + 7);
4485 uPageControl = pbPacket[2] >> 6;
4486 uPageCode = pbPacket[2] & 0x3f;
4487 switch (uPageControl)
4488 {
4489 case SCSI_PAGECONTROL_CURRENT:
4490 switch (uPageCode)
4491 {
4492 case SCSI_MODEPAGE_ERROR_RECOVERY:
4493 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
4494 break;
4495 case SCSI_MODEPAGE_CD_STATUS:
4496 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
4497 break;
4498 default:
4499 goto error_cmd;
4500 }
4501 break;
4502 case SCSI_PAGECONTROL_CHANGEABLE:
4503 goto error_cmd;
4504 case SCSI_PAGECONTROL_DEFAULT:
4505 goto error_cmd;
4506 default:
4507 case SCSI_PAGECONTROL_SAVED:
4508 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
4509 break;
4510 }
4511 break;
4512 }
4513 case SCSI_REQUEST_SENSE:
4514 cbMax = pbPacket[4];
4515 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
4516 break;
4517 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4518 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4519 {
4520 if (pbPacket[4] & 1)
4521 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
4522 else
4523 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
4524 atapiCmdOK(pAhciPort, pAhciReq);
4525 }
4526 else
4527 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4528 break;
4529 case SCSI_READ_10:
4530 case SCSI_READ_12:
4531 {
4532 uint32_t cSectors, iATAPILBA;
4533
4534 if (pAhciPort->cNotifiedMediaChange > 0)
4535 {
4536 pAhciPort->cNotifiedMediaChange-- ;
4537 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4538 break;
4539 }
4540 if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4541 {
4542 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4543 break;
4544 }
4545 if (pbPacket[0] == SCSI_READ_10)
4546 cSectors = ataBE2H_U16(pbPacket + 7);
4547 else
4548 cSectors = ataBE2H_U32(pbPacket + 6);
4549 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4550 if (cSectors == 0)
4551 {
4552 atapiCmdOK(pAhciPort, pAhciReq);
4553 break;
4554 }
4555 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4556 {
4557 /* Rate limited logging, one log line per second. For
4558 * guests that insist on reading from places outside the
4559 * valid area this often generates too many release log
4560 * entries otherwise. */
4561 static uint64_t s_uLastLogTS = 0;
4562 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4563 {
4564 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4565 s_uLastLogTS = RTTimeMilliTS();
4566 }
4567 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4568 break;
4569 }
4570 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4571 enmTxDir = AHCITXDIR_READ;
4572 break;
4573 }
4574 case SCSI_READ_CD:
4575 {
4576 uint32_t cSectors, iATAPILBA;
4577
4578 if (pAhciPort->cNotifiedMediaChange > 0)
4579 {
4580 pAhciPort->cNotifiedMediaChange-- ;
4581 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4582 break;
4583 }
4584 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4585 {
4586 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4587 break;
4588 }
4589 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
4590 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4591 if (cSectors == 0)
4592 {
4593 atapiCmdOK(pAhciPort, pAhciReq);
4594 break;
4595 }
4596 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
4597 {
4598 /* Rate limited logging, one log line per second. For
4599 * guests that insist on reading from places outside the
4600 * valid area this often generates too many release log
4601 * entries otherwise. */
4602 static uint64_t s_uLastLogTS = 0;
4603 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4604 {
4605 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
4606 s_uLastLogTS = RTTimeMilliTS();
4607 }
4608 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4609 break;
4610 }
4611 switch (pbPacket[9] & 0xf8)
4612 {
4613 case 0x00:
4614 /* nothing */
4615 atapiCmdOK(pAhciPort, pAhciReq);
4616 break;
4617 case 0x10:
4618 /* normal read */
4619 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
4620 enmTxDir = AHCITXDIR_READ;
4621 break;
4622 case 0xf8:
4623 /* read all data */
4624 atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
4625 enmTxDir = AHCITXDIR_READ;
4626 break;
4627 default:
4628 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
4629 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4630 break;
4631 }
4632 break;
4633 }
4634 case SCSI_SEEK_10:
4635 {
4636 uint32_t iATAPILBA;
4637 if (pAhciPort->cNotifiedMediaChange > 0)
4638 {
4639 pAhciPort->cNotifiedMediaChange-- ;
4640 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4641 break;
4642 }
4643 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4644 {
4645 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4646 break;
4647 }
4648 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4649 if (iATAPILBA > pAhciPort->cTotalSectors)
4650 {
4651 /* Rate limited logging, one log line per second. For
4652 * guests that insist on seeking to places outside the
4653 * valid area this often generates too many release log
4654 * entries otherwise. */
4655 static uint64_t s_uLastLogTS = 0;
4656 if (RTTimeMilliTS() >= s_uLastLogTS + 1000)
4657 {
4658 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
4659 s_uLastLogTS = RTTimeMilliTS();
4660 }
4661 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
4662 break;
4663 }
4664 atapiCmdOK(pAhciPort, pAhciReq);
4665 pAhciReq->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
4666 break;
4667 }
4668 case SCSI_START_STOP_UNIT:
4669 {
4670 int rc = VINF_SUCCESS;
4671 switch (pbPacket[4] & 3)
4672 {
4673 case 0: /* 00 - Stop motor */
4674 case 1: /* 01 - Start motor */
4675 break;
4676 case 2: /* 10 - Eject media */
4677 {
4678 /* This must be done from EMT. */
4679 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
4680 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
4681
4682 /*
4683 * Free the I/O memory of all cached tasks of this port
4684 * because the driver providing I/O memory allocation interface
4685 * is about to be destroyed.
4686 */
4687 ahciR3PortCachedReqsFree(pAhciPort);
4688
4689 /*
4690 * Also make sure that the current request has no memory allocated
4691 * from the driver below us. We don't require it here anyway.
4692 */
4693 ahciReqMemFree(pAhciPort, pAhciReq, true /* fForceFree */);
4694
4695 rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4696 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
4697 pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
4698 Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
4699 if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
4700 {
4701 rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4702 (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
4703 pAhci->pMediaNotify, pAhciPort->iLUN);
4704 AssertRC(rc);
4705 }
4706 break;
4707 }
4708 case 3: /* 11 - Load media */
4709 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
4710 break;
4711 }
4712 if (RT_SUCCESS(rc))
4713 atapiCmdOK(pAhciPort, pAhciReq);
4714 else
4715 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
4716 break;
4717 }
4718 case SCSI_MECHANISM_STATUS:
4719 {
4720 cbMax = ataBE2H_U16(pbPacket + 8);
4721 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
4722 break;
4723 }
4724 case SCSI_READ_TOC_PMA_ATIP:
4725 {
4726 uint8_t format;
4727
4728 if (pAhciPort->cNotifiedMediaChange > 0)
4729 {
4730 pAhciPort->cNotifiedMediaChange-- ;
4731 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4732 break;
4733 }
4734 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4735 {
4736 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4737 break;
4738 }
4739 cbMax = ataBE2H_U16(pbPacket + 7);
4740 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
4741 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
4742 * the other field is clear... */
4743 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
4744 switch (format)
4745 {
4746 case 0:
4747 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
4748 break;
4749 case 1:
4750 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
4751 break;
4752 case 2:
4753 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
4754 break;
4755 default:
4756 error_cmd:
4757 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
4758 break;
4759 }
4760 break;
4761 }
4762 case SCSI_READ_CAPACITY:
4763 if (pAhciPort->cNotifiedMediaChange > 0)
4764 {
4765 pAhciPort->cNotifiedMediaChange-- ;
4766 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4767 break;
4768 }
4769 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4770 {
4771 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4772 break;
4773 }
4774 atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
4775 break;
4776 case SCSI_READ_DISC_INFORMATION:
4777 if (pAhciPort->cNotifiedMediaChange > 0)
4778 {
4779 pAhciPort->cNotifiedMediaChange-- ;
4780 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4781 break;
4782 }
4783 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4784 {
4785 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4786 break;
4787 }
4788 cbMax = ataBE2H_U16(pbPacket + 7);
4789 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
4790 break;
4791 case SCSI_READ_TRACK_INFORMATION:
4792 if (pAhciPort->cNotifiedMediaChange > 0)
4793 {
4794 pAhciPort->cNotifiedMediaChange-- ;
4795 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
4796 break;
4797 }
4798 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
4799 {
4800 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
4801 break;
4802 }
4803 cbMax = ataBE2H_U16(pbPacket + 7);
4804 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
4805 break;
4806 case SCSI_GET_CONFIGURATION:
4807 /* No media change stuff here, it can confuse Linux guests. */
4808 cbMax = ataBE2H_U16(pbPacket + 7);
4809 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
4810 break;
4811 case SCSI_INQUIRY:
4812 cbMax = pbPacket[4];
4813 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
4814 break;
4815 case SCSI_READ_DVD_STRUCTURE:
4816 cbMax = ataBE2H_U16(pbPacket + 8);
4817 atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DVD_STRUCTURE);
4818 break;
4819 default:
4820 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4821 break;
4822 }
4823
4824 return enmTxDir;
4825}
4826
4827/*
4828 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
4829 */
4830static AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
4831{
4832 const uint8_t *pbPacket;
4833 uint32_t cSectors, iATAPILBA;
4834 uint32_t cbTransfer = 0;
4835 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
4836
4837 pbPacket = pAhciReq->aATAPICmd;
4838 switch (pbPacket[0])
4839 {
4840 case SCSI_BLANK:
4841 goto sendcmd;
4842 case SCSI_CLOSE_TRACK_SESSION:
4843 goto sendcmd;
4844 case SCSI_ERASE_10:
4845 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4846 cbTransfer = ataBE2H_U16(pbPacket + 7);
4847 Log2(("ATAPI PT: lba %d\n", iATAPILBA));
4848 enmTxDir = AHCITXDIR_WRITE;
4849 goto sendcmd;
4850 case SCSI_FORMAT_UNIT:
4851 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4852 enmTxDir = AHCITXDIR_WRITE;
4853 goto sendcmd;
4854 case SCSI_GET_CONFIGURATION:
4855 cbTransfer = ataBE2H_U16(pbPacket + 7);
4856 enmTxDir = AHCITXDIR_READ;
4857 goto sendcmd;
4858 case SCSI_GET_EVENT_STATUS_NOTIFICATION:
4859 cbTransfer = ataBE2H_U16(pbPacket + 7);
4860 if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
4861 {
4862 pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
4863 atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
4864 break;
4865 }
4866 enmTxDir = AHCITXDIR_READ;
4867 goto sendcmd;
4868 case SCSI_GET_PERFORMANCE:
4869 cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
4870 enmTxDir = AHCITXDIR_READ;
4871 goto sendcmd;
4872 case SCSI_INQUIRY:
4873 cbTransfer = ataBE2H_U16(pbPacket + 3);
4874 enmTxDir = AHCITXDIR_READ;
4875 goto sendcmd;
4876 case SCSI_LOAD_UNLOAD_MEDIUM:
4877 goto sendcmd;
4878 case SCSI_MECHANISM_STATUS:
4879 cbTransfer = ataBE2H_U16(pbPacket + 8);
4880 enmTxDir = AHCITXDIR_READ;
4881 goto sendcmd;
4882 case SCSI_MODE_SELECT_10:
4883 cbTransfer = ataBE2H_U16(pbPacket + 7);
4884 enmTxDir = AHCITXDIR_WRITE;
4885 goto sendcmd;
4886 case SCSI_MODE_SENSE_10:
4887 cbTransfer = ataBE2H_U16(pbPacket + 7);
4888 enmTxDir = AHCITXDIR_READ;
4889 goto sendcmd;
4890 case SCSI_PAUSE_RESUME:
4891 goto sendcmd;
4892 case SCSI_PLAY_AUDIO_10:
4893 goto sendcmd;
4894 case SCSI_PLAY_AUDIO_12:
4895 goto sendcmd;
4896 case SCSI_PLAY_AUDIO_MSF:
4897 goto sendcmd;
4898 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
4899 /** @todo do not forget to unlock when a VM is shut down */
4900 goto sendcmd;
4901 case SCSI_READ_10:
4902 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4903 cSectors = ataBE2H_U16(pbPacket + 7);
4904 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4905 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4906 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4907 enmTxDir = AHCITXDIR_READ;
4908 goto sendcmd;
4909 case SCSI_READ_12:
4910 iATAPILBA = ataBE2H_U32(pbPacket + 2);
4911 cSectors = ataBE2H_U32(pbPacket + 6);
4912 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
4913 pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
4914 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4915 enmTxDir = AHCITXDIR_READ;
4916 goto sendcmd;
4917 case SCSI_READ_BUFFER:
4918 cbTransfer = ataBE2H_U24(pbPacket + 6);
4919 enmTxDir = AHCITXDIR_READ;
4920 goto sendcmd;
4921 case SCSI_READ_BUFFER_CAPACITY:
4922 cbTransfer = ataBE2H_U16(pbPacket + 7);
4923 enmTxDir = AHCITXDIR_READ;
4924 goto sendcmd;
4925 case SCSI_READ_CAPACITY:
4926 cbTransfer = 8;
4927 enmTxDir = AHCITXDIR_READ;
4928 goto sendcmd;
4929 case SCSI_READ_CD:
4930 case SCSI_READ_CD_MSF:
4931 {
4932 /* Get sector size based on the expected sector type field. */
4933 switch ((pbPacket[1] >> 2) & 0x7)
4934 {
4935 case 0x0: /* All types. */
4936 {
4937 uint32_t iLbaStart;
4938
4939 if (pbPacket[0] == SCSI_READ_CD)
4940 iLbaStart = ataBE2H_U32(&pbPacket[2]);
4941 else
4942 iLbaStart = ataMSF2LBA(&pbPacket[3]);
4943
4944 if (pAhciPort->pTrackList)
4945 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
4946 else
4947 pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
4948 break;
4949 }
4950 case 0x1: /* CD-DA */
4951 pAhciReq->cbATAPISector = 2352;
4952 break;
4953 case 0x2: /* Mode 1 */
4954 pAhciReq->cbATAPISector = 2048;
4955 break;
4956 case 0x3: /* Mode 2 formless */
4957 pAhciReq->cbATAPISector = 2336;
4958 break;
4959 case 0x4: /* Mode 2 form 1 */
4960 pAhciReq->cbATAPISector = 2048;
4961 break;
4962 case 0x5: /* Mode 2 form 2 */
4963 pAhciReq->cbATAPISector = 2324;
4964 break;
4965 default: /* Reserved */
4966 AssertMsgFailed(("Unknown sector type\n"));
4967 pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
4968 }
4969
4970 if (pbPacket[0] == SCSI_READ_CD)
4971 cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
4972 else /* SCSI_READ_MSF */
4973 {
4974 cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
4975 if (cSectors > 32)
4976 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
4977 cbTransfer = cSectors * pAhciReq->cbATAPISector;
4978 }
4979 enmTxDir = AHCITXDIR_READ;
4980 goto sendcmd;
4981 }
4982 case SCSI_READ_DISC_INFORMATION:
4983 cbTransfer = ataBE2H_U16(pbPacket + 7);
4984 enmTxDir = AHCITXDIR_READ;
4985 goto sendcmd;
4986 case SCSI_READ_DVD_STRUCTURE:
4987 cbTransfer = ataBE2H_U16(pbPacket + 8);
4988 enmTxDir = AHCITXDIR_READ;
4989 goto sendcmd;
4990 case SCSI_READ_FORMAT_CAPACITIES:
4991 cbTransfer = ataBE2H_U16(pbPacket + 7);
4992 enmTxDir = AHCITXDIR_READ;
4993 goto sendcmd;
4994 case SCSI_READ_SUBCHANNEL:
4995 cbTransfer = ataBE2H_U16(pbPacket + 7);
4996 enmTxDir = AHCITXDIR_READ;
4997 goto sendcmd;
4998 case SCSI_READ_TOC_PMA_ATIP:
4999 cbTransfer = ataBE2H_U16(pbPacket + 7);
5000 enmTxDir = AHCITXDIR_READ;
5001 goto sendcmd;
5002 case SCSI_READ_TRACK_INFORMATION:
5003 cbTransfer = ataBE2H_U16(pbPacket + 7);
5004 enmTxDir = AHCITXDIR_READ;
5005 goto sendcmd;
5006 case SCSI_REPAIR_TRACK:
5007 goto sendcmd;
5008 case SCSI_REPORT_KEY:
5009 cbTransfer = ataBE2H_U16(pbPacket + 8);
5010 enmTxDir = AHCITXDIR_READ;
5011 goto sendcmd;
5012 case SCSI_REQUEST_SENSE:
5013 cbTransfer = pbPacket[4];
5014 if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
5015 {
5016 pAhciReq->cbTransfer = cbTransfer;
5017 pAhciReq->enmTxDir = AHCITXDIR_READ;
5018 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
5019 break;
5020 }
5021 enmTxDir = AHCITXDIR_READ;
5022 goto sendcmd;
5023 case SCSI_RESERVE_TRACK:
5024 goto sendcmd;
5025 case SCSI_SCAN:
5026 goto sendcmd;
5027 case SCSI_SEEK_10:
5028 goto sendcmd;
5029 case SCSI_SEND_CUE_SHEET:
5030 cbTransfer = ataBE2H_U24(pbPacket + 6);
5031 enmTxDir = AHCITXDIR_WRITE;
5032 goto sendcmd;
5033 case SCSI_SEND_DVD_STRUCTURE:
5034 cbTransfer = ataBE2H_U16(pbPacket + 8);
5035 enmTxDir = AHCITXDIR_WRITE;
5036 goto sendcmd;
5037 case SCSI_SEND_EVENT:
5038 cbTransfer = ataBE2H_U16(pbPacket + 8);
5039 enmTxDir = AHCITXDIR_WRITE;
5040 goto sendcmd;
5041 case SCSI_SEND_KEY:
5042 cbTransfer = ataBE2H_U16(pbPacket + 8);
5043 enmTxDir = AHCITXDIR_WRITE;
5044 goto sendcmd;
5045 case SCSI_SEND_OPC_INFORMATION:
5046 cbTransfer = ataBE2H_U16(pbPacket + 7);
5047 enmTxDir = AHCITXDIR_WRITE;
5048 goto sendcmd;
5049 case SCSI_SET_CD_SPEED:
5050 goto sendcmd;
5051 case SCSI_SET_READ_AHEAD:
5052 goto sendcmd;
5053 case SCSI_SET_STREAMING:
5054 cbTransfer = ataBE2H_U16(pbPacket + 9);
5055 enmTxDir = AHCITXDIR_WRITE;
5056 goto sendcmd;
5057 case SCSI_START_STOP_UNIT:
5058 goto sendcmd;
5059 case SCSI_STOP_PLAY_SCAN:
5060 goto sendcmd;
5061 case SCSI_SYNCHRONIZE_CACHE:
5062 goto sendcmd;
5063 case SCSI_TEST_UNIT_READY:
5064 goto sendcmd;
5065 case SCSI_VERIFY_10:
5066 goto sendcmd;
5067 case SCSI_WRITE_10:
5068 case SCSI_WRITE_AND_VERIFY_10:
5069 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5070 cSectors = ataBE2H_U16(pbPacket + 7);
5071 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5072 if (pAhciPort->pTrackList)
5073 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5074 else
5075 pAhciReq->cbATAPISector = 2048;
5076 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5077 enmTxDir = AHCITXDIR_WRITE;
5078 goto sendcmd;
5079 case SCSI_WRITE_12:
5080 iATAPILBA = ataBE2H_U32(pbPacket + 2);
5081 cSectors = ataBE2H_U32(pbPacket + 6);
5082 Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
5083 if (pAhciPort->pTrackList)
5084 pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
5085 else
5086 pAhciReq->cbATAPISector = 2048;
5087 cbTransfer = cSectors * pAhciReq->cbATAPISector;
5088 enmTxDir = AHCITXDIR_WRITE;
5089 goto sendcmd;
5090 case SCSI_WRITE_BUFFER:
5091 switch (pbPacket[1] & 0x1f)
5092 {
5093 case 0x04: /* download microcode */
5094 case 0x05: /* download microcode and save */
5095 case 0x06: /* download microcode with offsets */
5096 case 0x07: /* download microcode with offsets and save */
5097 case 0x0e: /* download microcode with offsets and defer activation */
5098 case 0x0f: /* activate deferred microcode */
5099 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
5100 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
5101 break;
5102 default:
5103 cbTransfer = ataBE2H_U16(pbPacket + 6);
5104 enmTxDir = AHCITXDIR_WRITE;
5105 goto sendcmd;
5106 }
5107 break;
5108 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
5109 cbTransfer = ataBE2H_U32(pbPacket + 6);
5110 enmTxDir = AHCITXDIR_READ;
5111 goto sendcmd;
5112 case SCSI_REZERO_UNIT:
5113 /* Obsolete command used by cdrecord. What else would one expect?
5114 * This command is not sent to the drive, it is handled internally,
5115 * as the Linux kernel doesn't like it (message "scsi: unknown
5116 * opcode 0x01" in syslog) and replies with a sense code of 0,
5117 * which sends cdrecord to an endless loop. */
5118 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5119 break;
5120 default:
5121 LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
5122 atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5123 break;
5124 sendcmd:
5125 /* Send a command to the drive, passing data in/out as required. */
5126 Log2(("ATAPI PT: max size %d\n", cbTransfer));
5127 if (cbTransfer == 0)
5128 enmTxDir = AHCITXDIR_NONE;
5129 pAhciReq->enmTxDir = enmTxDir;
5130 pAhciReq->cbTransfer = cbTransfer;
5131 atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
5132 }
5133
5134 return AHCITXDIR_NONE;
5135}
5136
5137static AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5138{
5139 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
5140 const uint8_t *pbPacket;
5141
5142 pbPacket = pAhciReq->aATAPICmd;
5143 Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
5144 Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
5145
5146 if (pAhciPort->fATAPIPassthrough)
5147 enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
5148 else
5149 enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
5150
5151 return enmTxDir;
5152}
5153
5154/**
5155 * Reset all values after a reset of the attached storage device.
5156 *
5157 * @returns nothing
5158 * @param pAhciPort The port the device is attached to.
5159 * @param pAhciReq The state to get the tag number from.
5160 */
5161static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5162{
5163 int rc;
5164
5165 /* Send a status good D2H FIS. */
5166 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
5167 pAhciPort->fResetDevice = false;
5168 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5169 ahciPostFirstD2HFisIntoMemory(pAhciPort);
5170
5171 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
5172 if (pAhciPort->fATAPI)
5173 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
5174 else
5175 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
5176 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5177
5178 rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
5179 AssertRC(rc);
5180}
5181
5182/**
5183 * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
5184 *
5185 * @returns nothing.
5186 * @param pAhciPort The device to reset.
5187 * @param pAhciReq The task state.
5188 */
5189static void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5190{
5191 ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
5192
5193 /*
5194 * Because this ATAPI only and ATAPI can't have
5195 * more than one command active at a time the task counter should be 0
5196 * and it is possible to finish the reset now.
5197 */
5198 Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
5199 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
5200}
5201
5202/**
5203 * Create a PIO setup FIS and post it into the memory area of the guest.
5204 *
5205 * @returns nothing.
5206 * @param pAhciPort The port of the SATA controller.
5207 * @param pAhciReq The state of the task.
5208 * @param pCmdFis Pointer to the command FIS from the guest.
5209 * @param fInterrupt If an interrupt should be send to the guest.
5210 */
5211static void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
5212 bool fInterrupt)
5213{
5214 uint8_t abPioSetupFis[20];
5215 bool fAssertIntr = false;
5216 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5217
5218 ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
5219
5220 AssertMsg( pAhciReq->cbTransfer > 0
5221 && pAhciReq->cbTransfer <= 65534,
5222 ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
5223
5224 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5225 {
5226 memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
5227 abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
5228 abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5229 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
5230 abPioSetupFis[AHCI_CMDFIS_BITS] |= AHCI_CMDFIS_D;
5231 abPioSetupFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5232 abPioSetupFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5233 abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5234 abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5235 abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5236 abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5237 abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5238 abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5239 abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5240 abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5241 abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5242
5243 /* Set transfer count. */
5244 abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
5245 abPioSetupFis[17] = pAhciReq->cbTransfer & 0xff;
5246
5247 /* Update registers. */
5248 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5249
5250 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
5251
5252 if (fInterrupt)
5253 {
5254 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
5255 /* Check if we should assert an interrupt */
5256 if (pAhciPort->regIE & AHCI_PORT_IE_PSE)
5257 fAssertIntr = true;
5258 }
5259
5260 if (fAssertIntr)
5261 {
5262 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5263 AssertRC(rc);
5264 }
5265 }
5266}
5267
5268/**
5269 * Build a D2H FIS and post into the memory area of the guest.
5270 *
5271 * @returns Nothing
5272 * @param pAhciPort The port of the SATA controller.
5273 * @param pAhciReq The state of the task.
5274 * @param pCmdFis Pointer to the command FIS from the guest.
5275 * @param fInterrupt If an interrupt should be send to the guest.
5276 */
5277static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
5278{
5279 uint8_t d2hFis[20];
5280 bool fAssertIntr = false;
5281 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5282
5283 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
5284
5285 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5286 {
5287 memset(&d2hFis[0], 0, sizeof(d2hFis));
5288 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
5289 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
5290 d2hFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
5291 d2hFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
5292 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
5293 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
5294 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
5295 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
5296 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
5297 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
5298 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
5299 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
5300 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
5301
5302 /* Update registers. */
5303 pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
5304
5305 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
5306
5307 if (pAhciReq->uATARegStatus & ATA_STAT_ERR)
5308 {
5309 /* Error bit is set. */
5310 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5311 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5312 fAssertIntr = true;
5313 /*
5314 * Don't mark the command slot as completed because the guest
5315 * needs it to identify the failed command.
5316 */
5317 }
5318 else if (fInterrupt)
5319 {
5320 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
5321 /* Check if we should assert an interrupt */
5322 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
5323 fAssertIntr = true;
5324
5325 /* Mark command as completed. */
5326 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
5327 }
5328
5329 if (fAssertIntr)
5330 {
5331 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5332 AssertRC(rc);
5333 }
5334 }
5335}
5336
5337/**
5338 * Build a SDB Fis and post it into the memory area of the guest.
5339 *
5340 * @returns Nothing
5341 * @param pAhciPort The port for which the SDB Fis is send.
5342 * @param uFinishedTasks Bitmask of finished tasks.
5343 * @param fInterrupt If an interrupt should be asserted.
5344 */
5345static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
5346{
5347 uint32_t sdbFis[2];
5348 bool fAssertIntr = false;
5349 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5350 PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
5351
5352 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
5353
5354 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
5355 {
5356 memset(&sdbFis[0], 0, sizeof(sdbFis));
5357 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
5358 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
5359 if (RT_UNLIKELY(pTaskErr))
5360 {
5361 sdbFis[0] = pTaskErr->uATARegError;
5362 sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
5363
5364 /* Update registers. */
5365 pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
5366 }
5367 else
5368 {
5369 sdbFis[0] = 0;
5370 sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
5371 pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
5372 }
5373
5374 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
5375
5376 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
5377
5378 if (RT_UNLIKELY(pTaskErr))
5379 {
5380 /* Error bit is set. */
5381 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
5382 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
5383 fAssertIntr = true;
5384 }
5385
5386 if (fInterrupt)
5387 {
5388 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
5389 /* Check if we should assert an interrupt */
5390 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
5391 fAssertIntr = true;
5392 }
5393
5394 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
5395
5396 if (fAssertIntr)
5397 {
5398 int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
5399 AssertRC(rc);
5400 }
5401 }
5402}
5403
5404static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
5405{
5406 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
5407 if (fLBA48)
5408 {
5409 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
5410 return 65536;
5411 else
5412 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
5413 }
5414 else
5415 {
5416 if (!pCmdFis[AHCI_CMDFIS_SECTC])
5417 return 256;
5418 else
5419 return pCmdFis[AHCI_CMDFIS_SECTC];
5420 }
5421}
5422
5423static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
5424{
5425 uint64_t iLBA;
5426 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
5427 {
5428 /* any LBA variant */
5429 if (fLBA48)
5430 {
5431 /* LBA48 */
5432 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5433 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5434 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5435 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5436 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5437 pCmdFis[AHCI_CMDFIS_SECTN];
5438 }
5439 else
5440 {
5441 /* LBA */
5442 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5443 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
5444 }
5445 }
5446 else
5447 {
5448 /* CHS */
5449 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
5450 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
5451 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
5452 }
5453 return iLBA;
5454}
5455
5456static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
5457{
5458 uint64_t uLBA;
5459
5460 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
5461 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
5462 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
5463 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
5464 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
5465 pCmdFis[AHCI_CMDFIS_SECTN];
5466
5467 return uLBA;
5468}
5469
5470DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
5471{
5472 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
5473 return 65536;
5474 else
5475 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
5476}
5477
5478#if 0 /* unused */
5479DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
5480{
5481 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
5482}
5483#endif /* unused */
5484
5485/**
5486 * Allocates memory for the given request using already allocated memory if possible.
5487 *
5488 * @returns Pointer to the memory or NULL on failure
5489 * @param pAhciPort The AHCI port.
5490 * @param pAhciReq The request to allocate memory for.
5491 * @param cb The amount of memory to allocate.
5492 */
5493static void *ahciReqMemAlloc(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cb)
5494{
5495 if (pAhciReq->cbAlloc > cb)
5496 {
5497 pAhciReq->cAllocTooMuch++;
5498 }
5499 else if (pAhciReq->cbAlloc < cb)
5500 {
5501 if (pAhciReq->cbAlloc)
5502 pAhciPort->pDrvMedia->pfnIoBufFree(pAhciPort->pDrvMedia, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5503
5504 pAhciReq->pvAlloc = NULL;
5505 pAhciReq->cbAlloc = RT_ALIGN_Z(cb, _4K);
5506 int rc = pAhciPort->pDrvMedia->pfnIoBufAlloc(pAhciPort->pDrvMedia, pAhciReq->cbAlloc, &pAhciReq->pvAlloc);
5507 if (RT_FAILURE(rc))
5508 pAhciReq->pvAlloc = NULL;
5509
5510 pAhciReq->cAllocTooMuch = 0;
5511 if (RT_UNLIKELY(!pAhciReq->pvAlloc))
5512 pAhciReq->cbAlloc = 0;
5513 }
5514
5515 return pAhciReq->pvAlloc;
5516}
5517
5518/**
5519 * Frees memory allocated for the given request.
5520 *
5521 * @returns nothing.
5522 * @param pAhciPort The AHCI port.
5523 * @param pAhciReq The request.
5524 * @param fForceFree Flag whether to force a free
5525 */
5526static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree)
5527{
5528 if ( pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH
5529 || fForceFree)
5530 {
5531 if (pAhciReq->cbAlloc)
5532 {
5533 pAhciPort->pDrvMedia->pfnIoBufFree(pAhciPort->pDrvMedia, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
5534 pAhciReq->cbAlloc = 0;
5535 pAhciReq->cAllocTooMuch = 0;
5536 }
5537 }
5538}
5539
5540/**
5541 * Copies a data buffer into the S/G buffer set up by the guest.
5542 *
5543 * @returns Amount of bytes copied to the PRDTL.
5544 * @param pDevIns Pointer to the device instance data.
5545 * @param pAhciReq AHCI request structure.
5546 * @param pvBuf The buffer to copy from.
5547 * @param cbBuf The size of the buffer.
5548 */
5549static uint32_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, void const *pvBuf, size_t cbBuf)
5550{
5551 uint8_t const *pbBuf = (uint8_t const *)pvBuf;
5552 SGLEntry aPrdtlEntries[32];
5553 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5554 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5555 uint32_t cbCopied = 0;
5556
5557 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5558
5559 do
5560 {
5561 uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
5562 ? cPrdtlEntries
5563 : RT_ELEMENTS(aPrdtlEntries);
5564
5565 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5566
5567 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5568 {
5569 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5570 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5571
5572 cbThisCopy = (uint32_t)RT_MIN(cbThisCopy, cbBuf);
5573
5574 /* Copy into SG entry. */
5575 PDMDevHlpPCIPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5576
5577 pbBuf += cbThisCopy;
5578 cbBuf -= cbThisCopy;
5579 cbCopied += cbThisCopy;
5580 }
5581
5582 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5583 cPrdtlEntries -= cPrdtlEntriesRead;
5584 } while (cPrdtlEntries && cbBuf);
5585
5586 if (cbCopied < cbBuf)
5587 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5588
5589 return cbCopied;
5590}
5591
5592/**
5593 * Copies the S/G buffer into a data buffer.
5594 *
5595 * @returns Amount of bytes copied to the PRDTL.
5596 * @param pDevIns Pointer to the device instance data.
5597 * @param pAhciReq AHCI request structure.
5598 * @param pvBuf The buffer to copy to.
5599 * @param cbBuf The size of the buffer.
5600 */
5601static size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
5602 void *pvBuf, size_t cbBuf)
5603{
5604 uint8_t *pbBuf = (uint8_t *)pvBuf;
5605 SGLEntry aPrdtlEntries[32];
5606 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5607 unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
5608 size_t cbCopied = 0;
5609
5610 AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
5611
5612 do
5613 {
5614 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5615 ? cPrdtlEntries
5616 : RT_ELEMENTS(aPrdtlEntries);
5617
5618 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5619
5620 for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
5621 {
5622 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5623 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5624
5625 cbThisCopy = (uint32_t)RT_MIN(cbThisCopy, cbBuf);
5626
5627 /* Copy into buffer. */
5628 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
5629
5630 pbBuf += cbThisCopy;
5631 cbBuf -= cbThisCopy;
5632 cbCopied += cbThisCopy;
5633 }
5634
5635 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5636 cPrdtlEntries -= cPrdtlEntriesRead;
5637 } while (cPrdtlEntries && cbBuf);
5638
5639 if (cbCopied < cbBuf)
5640 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5641
5642 return cbCopied;
5643}
5644
5645/**
5646 * Allocate I/O memory and copies the guest buffer for writes.
5647 *
5648 * @returns VBox status code.
5649 * @param pAhciPort The AHCI port.
5650 * @param pAhciReq The request state.
5651 * @param cbTransfer Amount of bytes to allocate.
5652 */
5653static int ahciIoBufAllocate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbTransfer)
5654{
5655 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5656 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5657 ("Allocating I/O memory for a non I/O request is not allowed\n"));
5658
5659 pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciPort, pAhciReq, cbTransfer);
5660 if (!pAhciReq->u.Io.DataSeg.pvSeg)
5661 return VERR_NO_MEMORY;
5662
5663 pAhciReq->u.Io.DataSeg.cbSeg = cbTransfer;
5664 if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
5665 {
5666 ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq,
5667 pAhciReq->u.Io.DataSeg.pvSeg,
5668 cbTransfer);
5669 }
5670 return VINF_SUCCESS;
5671}
5672
5673/**
5674 * Frees the I/O memory of the given request and updates the guest buffer if necessary.
5675 *
5676 * @returns nothing.
5677 * @param pAhciPort The AHCI port.
5678 * @param pAhciReq The request state.
5679 * @param fCopyToGuest Flag whether to update the guest buffer if necessary.
5680 * Nothing is copied if false even if the request was a read.
5681 */
5682static void ahciIoBufFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq,
5683 bool fCopyToGuest)
5684{
5685 AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
5686 || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
5687 ("Freeing I/O memory for a non I/O request is not allowed\n"));
5688
5689 if ( pAhciReq->enmTxDir == AHCITXDIR_READ
5690 && fCopyToGuest)
5691 {
5692 if (pAhciReq->u.Io.pfnPostProcess)
5693 {
5694 void *pv = NULL;
5695 size_t cb = 0;
5696 int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
5697
5698 if (RT_SUCCESS(rc))
5699 {
5700 pAhciReq->cbTransfer = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pv, cb);
5701 RTMemFree(pv);
5702 }
5703 }
5704 else
5705 ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->u.Io.DataSeg.pvSeg, pAhciReq->u.Io.DataSeg.cbSeg);
5706 }
5707
5708 ahciReqMemFree(pAhciPort, pAhciReq, false /* fForceFree */);
5709 pAhciReq->u.Io.DataSeg.pvSeg = NULL;
5710 pAhciReq->u.Io.DataSeg.cbSeg = 0;
5711}
5712
5713
5714/**
5715 * Free all cached tasks on the given port.
5716 *
5717 * @returns nothing.
5718 * @param pAhciPort The AHCI port.
5719 */
5720static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort)
5721{
5722 if (pAhciPort->pListReqsFree)
5723 {
5724 PAHCIREQ pReq = NULL;
5725 PAHCIREQ pReqNext = NULL;
5726
5727 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
5728 RTListForEachSafe(pAhciPort->pListReqsFree, pReq, pReqNext, AHCIREQ, NodeList)
5729 {
5730 RTListNodeRemove(&pReq->NodeList);
5731 ahciReqMemFree(pAhciPort, pReq, true /* fForceFree */);
5732 RTMemFree(pReq);
5733 }
5734 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
5735 }
5736}
5737
5738/**
5739 * Cancels all active tasks on the port.
5740 *
5741 * @returns Whether all active tasks were canceled.
5742 * @param pAhciPort The AHCI port.
5743 * @param pAhciReqExcept The given request is excepted from the cancelling
5744 * (used for error page reading).
5745 */
5746static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept)
5747{
5748 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aActiveTasks); i++)
5749 {
5750 PAHCIREQ pAhciReq = ASMAtomicReadPtrT(&pAhciPort->aActiveTasks[i], PAHCIREQ);
5751 if (pAhciReq != pAhciReqExcept)
5752 {
5753 pAhciReq = (PAHCIREQ)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->aActiveTasks[i], NULL);
5754
5755 if (VALID_PTR(pAhciReq))
5756 {
5757 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
5758 if (fXchg)
5759 {
5760 /* Task is active and was canceled. */
5761 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
5762 ("Task was canceled but none is active\n"));
5763 ASMAtomicDecU32(&pAhciPort->cTasksActive);
5764
5765 /*
5766 * Clear the pointer in the cached array. The controller will allocate a
5767 * a new task structure for this tag.
5768 */
5769 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[i]);
5770 LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
5771 pAhciPort->iLUN, pAhciReq->uTag));
5772 }
5773 else
5774 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
5775 ("Invalid task state, must be free!\n"));
5776 }
5777 }
5778 }
5779
5780 return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
5781}
5782
5783/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
5784
5785/** Makes a PAHCIPort out of a PPDMIMEDIAASYNCPORT. */
5786#define PDMIMEDIAASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
5787
5788static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
5789{
5790 int rc;
5791 LogRel(("AHCI: Host disk full\n"));
5792 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
5793 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
5794 AssertRC(rc);
5795}
5796
5797static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
5798{
5799 int rc;
5800 LogRel(("AHCI: File too big\n"));
5801 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
5802 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"));
5803 AssertRC(rc);
5804}
5805
5806static void ahciWarningISCSI(PPDMDEVINS pDevIns)
5807{
5808 int rc;
5809 LogRel(("AHCI: iSCSI target unavailable\n"));
5810 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
5811 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
5812 AssertRC(rc);
5813}
5814
5815bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
5816{
5817 if (rc == VERR_DISK_FULL)
5818 {
5819 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5820 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
5821 return true;
5822 }
5823 if (rc == VERR_FILE_TOO_BIG)
5824 {
5825 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5826 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
5827 return true;
5828 }
5829 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
5830 {
5831 /* iSCSI connection abort (first error) or failure to reestablish
5832 * connection (second error). Pause VM. On resume we'll retry. */
5833 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
5834 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
5835 return true;
5836 }
5837 if (rc == VERR_VD_DEK_MISSING)
5838 {
5839 /* Error message already set. */
5840 ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false);
5841 return true;
5842 }
5843
5844 return false;
5845}
5846
5847/**
5848 * Creates the array of ranges to trim.
5849 *
5850 * @returns VBox status code.
5851 * @param pAhciPort AHCI port state.
5852 * @param pAhciReq The request handling the TRIM request.
5853 */
5854static int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
5855{
5856 SGLEntry aPrdtlEntries[32];
5857 uint64_t aRanges[64];
5858 unsigned cRangesMax;
5859 unsigned cRanges = 0;
5860 uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
5861 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5862 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
5863 int rc = VINF_SUCCESS;
5864
5865 LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
5866
5867 AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
5868
5869 /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
5870 if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
5871 cRangesMax = 65536 * 512 / 8;
5872 else
5873 cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
5874
5875 if (!cPrdtlEntries)
5876 {
5877 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
5878 return VINF_SUCCESS;
5879 }
5880
5881 do
5882 {
5883 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5884 ? cPrdtlEntries
5885 : RT_ELEMENTS(aPrdtlEntries);
5886
5887 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5888
5889 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5890 {
5891 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5892 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5893
5894 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5895
5896 /* Copy into buffer. */
5897 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5898
5899 for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
5900 {
5901 aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
5902 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRange]) != 0)
5903 cRanges++;
5904 else
5905 break;
5906 }
5907 }
5908
5909 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5910 cPrdtlEntries -= cPrdtlEntriesRead;
5911 } while (cPrdtlEntries);
5912
5913 if (RT_UNLIKELY(!cRanges))
5914 {
5915 return VERR_BUFFER_OVERFLOW;
5916 }
5917
5918 pAhciReq->u.Trim.cRanges = cRanges;
5919 pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
5920 if (pAhciReq->u.Trim.paRanges)
5921 {
5922 uint32_t idxRange = 0;
5923
5924 cPrdtlEntries = pAhciReq->cPrdtlEntries;
5925 GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
5926
5927 /* Convert the ranges from the guest to our format. */
5928 do
5929 {
5930 uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
5931 ? cPrdtlEntries
5932 : RT_ELEMENTS(aPrdtlEntries);
5933
5934 PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
5935
5936 for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
5937 {
5938 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
5939 uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
5940
5941 cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
5942
5943 /* Copy into buffer. */
5944 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
5945
5946 for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
5947 {
5948 aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
5949 if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
5950 {
5951 pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
5952 pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
5953 idxRange++;
5954 }
5955 else
5956 break;
5957 }
5958 }
5959
5960 GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
5961 cPrdtlEntries -= cPrdtlEntriesRead;
5962 } while (idxRange < cRanges);
5963 }
5964 else
5965 rc = VERR_NO_MEMORY;
5966
5967 LogFlowFunc(("returns rc=%Rrc\n", rc));
5968 return rc;
5969}
5970
5971/**
5972 * Destroy the trim range list.
5973 *
5974 * @returns nothing.
5975 * @param pAhciReq The task state.
5976 */
5977static void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
5978{
5979 AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
5980 RTMemFree(pAhciReq->u.Trim.paRanges);
5981}
5982
5983/**
5984 * Allocates a new AHCI request.
5985 *
5986 * @returns A new AHCI request structure or NULL if out of memory.
5987 * @param pAhciPort The AHCI port.
5988 */
5989static PAHCIREQ ahciR3ReqAlloc(PAHCIPort pAhciPort)
5990{
5991 PAHCIREQ pAhciReq = NULL;
5992
5993 /* Check the global free list first. */
5994 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
5995 pAhciReq = RTListGetFirst(pAhciPort->pListReqsFree, AHCIREQ, NodeList);
5996 if (pAhciReq)
5997 {
5998 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE, ("Should be free!\n"));
5999 RTListNodeRemove(&pAhciReq->NodeList);
6000 }
6001 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
6002
6003 if (!pAhciReq)
6004 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6005
6006 pAhciReq->enmTxState = AHCITXSTATE_ACTIVE;
6007 return pAhciReq;
6008}
6009
6010/**
6011 * Frees a given AHCI request structure.
6012 *
6013 * @returns nothing.
6014 * @param pAhciPort The AHCI port.
6015 */
6016static void ahciR3ReqFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6017{
6018 AssertMsg(pAhciReq->enmTxState != AHCITXSTATE_FREE, ("Double free!\n"));
6019 pAhciReq->enmTxState = AHCITXSTATE_FREE;
6020
6021 RTCritSectEnter(&pAhciPort->CritSectReqsFree);
6022 RTListAppend(pAhciPort->pListReqsFree, &pAhciReq->NodeList);
6023 RTCritSectLeave(&pAhciPort->CritSectReqsFree);
6024}
6025
6026/**
6027 * Complete a data transfer task by freeing all occupied resources
6028 * and notifying the guest.
6029 *
6030 * @returns Flag whether the given request was canceled inbetween;
6031 *
6032 * @param pAhciPort Pointer to the port where to request completed.
6033 * @param pAhciReq Pointer to the task which finished.
6034 * @param rcReq IPRT status code of the completed request.
6035 */
6036static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq)
6037{
6038 bool fRedo = false;
6039 bool fCanceled = false;
6040 uint64_t tsNow = RTTimeMilliTS();
6041 AHCITXSTATE enmTxState = AHCITXSTATE_INVALID;
6042
6043 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d\n",
6044 pAhciPort, pAhciReq, rcReq));
6045
6046 enmTxState = (AHCITXSTATE)ASMAtomicReadU32((volatile uint32_t *)&pAhciReq->enmTxState);
6047 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, enmTxState, pAhciReq->uOffset, pAhciReq->cbTransfer);
6048 VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(pAhciReq, tsNow);
6049
6050 /*
6051 * Clear the request structure from the active request list first so it doesn't get cancelled
6052 * while we complete it. If the request is not in the active list anymore it was already canceled
6053 * and we have to make sure to not copy anything to guest memory because the guest might use it
6054 * for other things already.
6055 */
6056 bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset);
6057 bool fXchg = ASMAtomicCmpXchgPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL, pAhciReq);
6058 bool fReqErrSaved = false;
6059
6060 /*
6061 * Leave a release log entry if the request was active for more than 25 seconds
6062 * (30 seconds is the timeout of the guest).
6063 */
6064 if (tsNow - pAhciReq->tsStart >= 25 * 1000)
6065 {
6066 const char *pcszReq = NULL;
6067
6068 switch (pAhciReq->enmTxDir)
6069 {
6070 case AHCITXDIR_READ:
6071 pcszReq = "Read";
6072 break;
6073 case AHCITXDIR_WRITE:
6074 pcszReq = "Write";
6075 break;
6076 case AHCITXDIR_FLUSH:
6077 pcszReq = "Flush";
6078 break;
6079 case AHCITXDIR_TRIM:
6080 pcszReq = "Trim";
6081 break;
6082 default:
6083 pcszReq = "<Invalid>";
6084 }
6085
6086 LogRel(("AHCI#%uP%u: %s request was active for %llu seconds\n",
6087 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, pcszReq, (tsNow - pAhciReq->tsStart) / 1000));
6088 }
6089
6090 if (fXchg && !fPortReset)
6091 {
6092 if (pAhciReq->enmTxDir == AHCITXDIR_READ)
6093 {
6094 ahciIoBufFree(pAhciPort, pAhciReq, true /* fCopyToGuest */);
6095 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
6096 pAhciPort->Led.Actual.s.fReading = 0;
6097 }
6098 else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
6099 {
6100 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6101 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
6102 pAhciPort->Led.Actual.s.fWriting = 0;
6103 }
6104 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6105 {
6106 ahciTrimRangesDestroy(pAhciReq);
6107 pAhciPort->Led.Actual.s.fWriting = 0;
6108 }
6109
6110 if (RT_FAILURE(rcReq))
6111 {
6112 /* Log the error. */
6113 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6114 {
6115 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6116 LogRel(("AHCI#%uP%u: Flush returned rc=%Rrc\n",
6117 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6118 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6119 LogRel(("AHCI#%uP%u: Trim returned rc=%Rrc\n",
6120 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6121 else
6122 LogRel(("AHCI#%uP%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6123 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6124 pAhciReq->enmTxDir == AHCITXDIR_READ
6125 ? "Read"
6126 : "Write",
6127 pAhciReq->uOffset,
6128 pAhciReq->cbTransfer, rcReq));
6129 }
6130
6131 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
6132 if (!fRedo)
6133 {
6134 pAhciReq->cmdHdr.u32PRDBC = 0;
6135 pAhciReq->uATARegError = ID_ERR;
6136 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6137 fReqErrSaved = ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
6138 }
6139 else
6140 ASMAtomicOrU32(&pAhciPort->u32TasksRedo, RT_BIT_32(pAhciReq->uTag));
6141 }
6142 else
6143 {
6144 pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer;
6145
6146 /* Status will be set already for non I/O requests. */
6147 if (pAhciReq->enmTxDir != AHCITXDIR_NONE)
6148 {
6149 pAhciReq->uATARegError = 0;
6150 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6151 }
6152
6153 /* Write updated command header into memory of the guest. */
6154 PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6155
6156 if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
6157 {
6158 /*
6159 * The guest tried to transfer more data than there is space in the buffer.
6160 * Terminate task and set the overflow bit.
6161 */
6162 /* Notify the guest. */
6163 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
6164 if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
6165 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
6166 }
6167 }
6168
6169 if (!fRedo)
6170 {
6171
6172 /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
6173 if (pAhciReq->fFlags & AHCI_REQ_PIO_DATA)
6174 ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
6175
6176 if (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT)
6177 {
6178 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
6179 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
6180 }
6181
6182 if (pAhciReq->fFlags & AHCI_REQ_IS_QUEUED)
6183 {
6184 /*
6185 * Always raise an interrupt after task completion; delaying
6186 * this (interrupt coalescing) increases latency and has a significant
6187 * impact on performance (see @bugref{5071})
6188 */
6189 ahciSendSDBFis(pAhciPort, 0, true);
6190 }
6191 else
6192 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6193 }
6194 }
6195 else
6196 {
6197 /*
6198 * Task was canceled, do the cleanup but DO NOT access the guest memory!
6199 * The guest might use it for other things now because it doesn't know about that task anymore.
6200 */
6201 AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_CANCELED || fPortReset,
6202 ("Task is not active but wasn't canceled and no port reset is active!\n"));
6203
6204 fCanceled = true;
6205
6206 if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6207 ahciTrimRangesDestroy(pAhciReq);
6208 else if (pAhciReq->enmTxDir != AHCITXDIR_FLUSH)
6209 ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6210
6211 /* Leave a log message about the canceled request. */
6212 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
6213 {
6214 if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
6215 LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
6216 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
6217 else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6218 LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
6219 pAhciPort->CTX_SUFF(pDevIns)->iInstance,pAhciPort->iLUN, rcReq));
6220 else
6221 LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
6222 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6223 pAhciReq->enmTxDir == AHCITXDIR_READ
6224 ? "read"
6225 : "write",
6226 pAhciReq->uOffset,
6227 pAhciReq->cbTransfer, rcReq));
6228 }
6229 }
6230
6231 /*
6232 * Decrement the active task counter as the last step or we might run into a
6233 * hang during power off otherwise (see @bugref{7859}).
6234 * Before it could happen that we signal PDM that we are done while we still have to
6235 * copy the data to the guest but EMT might be busy destroying the driver chains
6236 * below us while we have to delegate copying data to EMT instead of doing it
6237 * on this thread.
6238 */
6239 if (fXchg)
6240 {
6241 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
6242 ("Inconsistent request counter\n"));
6243 ASMAtomicDecU32(&pAhciPort->cTasksActive);
6244 }
6245
6246 if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
6247 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6248
6249 /* Don't free the request yet when it is saved for the error log page. */
6250 if ( pAhciReq
6251 && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK)
6252 && !fReqErrSaved)
6253 ahciR3ReqFree(pAhciPort, pAhciReq);
6254 return fCanceled;
6255}
6256
6257/**
6258 * Notification callback for a completed transfer.
6259 *
6260 * @returns VBox status code.
6261 * @param pInterface Pointer to the interface.
6262 * @param pvUser User data.
6263 * @param rcReq IPRT Status code of the completed request.
6264 */
6265static DECLCALLBACK(int) ahciR3TransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
6266{
6267 PAHCIPort pAhciPort = PDMIMEDIAASYNCPORT_2_PAHCIPORT(pInterface);
6268 PAHCIREQ pAhciReq = (PAHCIREQ)pvUser;
6269
6270 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
6271 __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
6272
6273 ahciTransferComplete(pAhciPort, pAhciReq, rcReq);
6274
6275 return VINF_SUCCESS;
6276}
6277
6278/**
6279 * Process an non read/write ATA command.
6280 *
6281 * @returns The direction of the data transfer
6282 * @param pCmdHdr Pointer to the command header.
6283 */
6284static AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
6285{
6286 AHCITXDIR enmTxDir = AHCITXDIR_NONE;
6287 bool fLBA48 = false;
6288
6289 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
6290
6291 pAhciReq->cbTransfer = 0;
6292
6293 switch (pCmdFis[AHCI_CMDFIS_CMD])
6294 {
6295 case ATA_IDENTIFY_DEVICE:
6296 {
6297 if (pAhciPort->pDrvMedia && !pAhciPort->fATAPI)
6298 {
6299 uint16_t u16Temp[256];
6300
6301 /* Fill the buffer. */
6302 ahciIdentifySS(pAhciPort, u16Temp);
6303
6304 /* Copy the buffer. */
6305 uint32_t cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, &u16Temp[0], sizeof(u16Temp));
6306
6307 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6308 pAhciReq->cbTransfer = cbCopied;
6309 }
6310 else
6311 {
6312 pAhciReq->uATARegError = ABRT_ERR;
6313 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
6314 }
6315 break;
6316 }
6317 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
6318 case ATA_READ_NATIVE_MAX_ADDRESS:
6319 break;
6320 case ATA_SET_FEATURES:
6321 {
6322 switch (pCmdFis[AHCI_CMDFIS_FET])
6323 {
6324 case 0x02: /* write cache enable */
6325 case 0xaa: /* read look-ahead enable */
6326 case 0x55: /* read look-ahead disable */
6327 case 0xcc: /* reverting to power-on defaults enable */
6328 case 0x66: /* reverting to power-on defaults disable */
6329 pAhciReq->uATARegError = 0;
6330 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6331 break;
6332 case 0x82: /* write cache disable */
6333 enmTxDir = AHCITXDIR_FLUSH;
6334 break;
6335 case 0x03:
6336 {
6337 /* set transfer mode */
6338 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6339 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
6340 {
6341 case 0x00: /* PIO default */
6342 case 0x08: /* PIO mode */
6343 break;
6344 case ATA_MODE_MDMA: /* MDMA mode */
6345 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
6346 break;
6347 case ATA_MODE_UDMA: /* UDMA mode */
6348 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6349 break;
6350 }
6351 break;
6352 }
6353 default:
6354 pAhciReq->uATARegError = ABRT_ERR;
6355 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6356 }
6357 break;
6358 }
6359 case ATA_DEVICE_RESET:
6360 {
6361 if (!pAhciPort->fATAPI)
6362 {
6363 pAhciReq->uATARegError = ABRT_ERR;
6364 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6365 }
6366 else
6367 {
6368 /* Reset the device. */
6369 ahciDeviceReset(pAhciPort, pAhciReq);
6370 }
6371 break;
6372 }
6373 case ATA_FLUSH_CACHE_EXT:
6374 case ATA_FLUSH_CACHE:
6375 enmTxDir = AHCITXDIR_FLUSH;
6376 break;
6377 case ATA_PACKET:
6378 if (!pAhciPort->fATAPI)
6379 {
6380 pAhciReq->uATARegError = ABRT_ERR;
6381 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6382 }
6383 else
6384 enmTxDir = atapiParseCmd(pAhciPort, pAhciReq);
6385 break;
6386 case ATA_IDENTIFY_PACKET_DEVICE:
6387 if (!pAhciPort->fATAPI)
6388 {
6389 pAhciReq->uATARegError = ABRT_ERR;
6390 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6391 }
6392 else
6393 {
6394 atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6395
6396 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6397 pAhciReq->uATARegError = 0;
6398 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6399 }
6400 break;
6401 case ATA_SET_MULTIPLE_MODE:
6402 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
6403 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
6404 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6405 {
6406 pAhciReq->uATARegError = ABRT_ERR;
6407 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6408 }
6409 else
6410 {
6411 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
6412 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6413 pAhciReq->uATARegError = 0;
6414 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6415 }
6416 break;
6417 case ATA_STANDBY_IMMEDIATE:
6418 break; /* Do nothing. */
6419 case ATA_CHECK_POWER_MODE:
6420 pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
6421 /* fall through */
6422 case ATA_INITIALIZE_DEVICE_PARAMETERS:
6423 case ATA_IDLE_IMMEDIATE:
6424 case ATA_RECALIBRATE:
6425 case ATA_NOP:
6426 case ATA_READ_VERIFY_SECTORS_EXT:
6427 case ATA_READ_VERIFY_SECTORS:
6428 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
6429 case ATA_SLEEP:
6430 pAhciReq->uATARegError = 0;
6431 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6432 break;
6433 case ATA_READ_DMA_EXT:
6434 fLBA48 = true;
6435 case ATA_READ_DMA:
6436 {
6437 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6438 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6439 enmTxDir = AHCITXDIR_READ;
6440 break;
6441 }
6442 case ATA_WRITE_DMA_EXT:
6443 fLBA48 = true;
6444 case ATA_WRITE_DMA:
6445 {
6446 pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
6447 pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
6448 enmTxDir = AHCITXDIR_WRITE;
6449 break;
6450 }
6451 case ATA_READ_FPDMA_QUEUED:
6452 {
6453 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6454 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6455 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6456 enmTxDir = AHCITXDIR_READ;
6457 break;
6458 }
6459 case ATA_WRITE_FPDMA_QUEUED:
6460 {
6461 pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
6462 pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6463 pAhciReq->fFlags |= AHCI_REQ_IS_QUEUED;
6464 enmTxDir = AHCITXDIR_WRITE;
6465 break;
6466 }
6467 case ATA_READ_LOG_EXT:
6468 {
6469 size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6470 unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6471 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6472
6473 LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6474
6475 uint8_t aBuf[512];
6476
6477 memset(aBuf, 0, sizeof(aBuf));
6478
6479 if (offLogRead + cbLogRead <= sizeof(aBuf))
6480 {
6481 switch (iPage)
6482 {
6483 case 0x10:
6484 {
6485 LogFlow(("Reading error page\n"));
6486 PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6487 if (pTaskErr)
6488 {
6489 aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6490 aBuf[2] = pTaskErr->uATARegStatus;
6491 aBuf[3] = pTaskErr->uATARegError;
6492 aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6493 aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6494 aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6495 aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6496 aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6497 aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6498 aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6499 aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6500 aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6501
6502 /* Calculate checksum */
6503 uint8_t uChkSum = 0;
6504 for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6505 uChkSum += aBuf[i];
6506
6507 aBuf[511] = (uint8_t)-(int8_t)uChkSum;
6508
6509 if (pTaskErr->enmTxDir == AHCITXDIR_TRIM)
6510 ahciTrimRangesDestroy(pTaskErr);
6511 else if (pTaskErr->enmTxDir != AHCITXDIR_FLUSH)
6512 ahciReqMemFree(pAhciPort, pTaskErr, true /* fForceFree */);
6513
6514 /* Finally free the error task state structure because it is completely unused now. */
6515 RTMemFree(pTaskErr);
6516 }
6517
6518 /*
6519 * Reading this log page results in an abort of all outstanding commands
6520 * and clearing the SActive register and TaskFile register.
6521 *
6522 * See SATA2 1.2 spec chapter 4.2.3.4
6523 */
6524 bool fAbortedAll = ahciCancelActiveTasks(pAhciPort, pAhciReq);
6525 Assert(fAbortedAll); NOREF(fAbortedAll);
6526 ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6527
6528 break;
6529 }
6530 }
6531
6532 /* Copy the buffer. */
6533 uint32_t cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, &aBuf[offLogRead], cbLogRead);
6534
6535 pAhciReq->fFlags |= AHCI_REQ_PIO_DATA;
6536 pAhciReq->cbTransfer = cbCopied;
6537 }
6538
6539 break;
6540 }
6541 case ATA_DATA_SET_MANAGEMENT:
6542 {
6543 if ( ( !pAhciPort->fAsyncInterface
6544 && pAhciPort->pDrvMedia->pfnDiscard)
6545 || ( pAhciPort->fAsyncInterface
6546 && pAhciPort->pDrvMediaAsync->pfnStartDiscard))
6547 {
6548 /* Check that the trim bit is set and all other bits are 0. */
6549 if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6550 || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6551 {
6552 pAhciReq->uATARegError = ABRT_ERR;
6553 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6554 }
6555 else
6556 enmTxDir = AHCITXDIR_TRIM;
6557 break;
6558 }
6559 /* else: fall through and report error to the guest. */
6560 }
6561 /* All not implemented commands go below. */
6562 case ATA_SECURITY_FREEZE_LOCK:
6563 case ATA_SMART:
6564 case ATA_NV_CACHE:
6565 case ATA_IDLE:
6566 case ATA_TRUSTED_RECEIVE_DMA: /* Windows 8+ */
6567 pAhciReq->uATARegError = ABRT_ERR;
6568 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6569 break;
6570 default: /* For debugging purposes. */
6571 AssertMsgFailed(("Unknown command issued (%#x)\n", pCmdFis[AHCI_CMDFIS_CMD]));
6572 pAhciReq->uATARegError = ABRT_ERR;
6573 pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6574 }
6575
6576 return enmTxDir;
6577}
6578
6579/**
6580 * Retrieve a command FIS from guest memory.
6581 *
6582 * @returns whether the H2D FIS was successfully read from the guest memory.
6583 * @param pAhciReq The state of the actual task.
6584 */
6585static bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6586{
6587 RTGCPHYS GCPhysAddrCmdTbl;
6588
6589 AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
6590 ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
6591 false);
6592
6593 /*
6594 * First we are reading the command header pointed to by regCLB.
6595 * From this we get the address of the command table which we are reading too.
6596 * We can process the Command FIS afterwards.
6597 */
6598 pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
6599 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6600 pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6601 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6602
6603#ifdef LOG_ENABLED
6604 /* Print some infos about the command header. */
6605 ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
6606#endif
6607
6608 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
6609
6610 AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
6611 ("This is not a command FIS!!\n"),
6612 false);
6613
6614 /* Read the command Fis. */
6615 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6616 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
6617
6618 AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
6619 ("This is not a command FIS\n"),
6620 false);
6621
6622 /* Set transfer direction. */
6623 pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
6624
6625 /* If this is an ATAPI command read the atapi command. */
6626 if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
6627 {
6628 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6629 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
6630 }
6631
6632 /* We "received" the FIS. Clear the BSY bit in regTFD. */
6633 if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
6634 {
6635 /*
6636 * 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.
6637 * but this FIS does not assert an interrupt
6638 */
6639 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6640 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
6641 }
6642
6643 pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6644 pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
6645
6646#ifdef LOG_ENABLED
6647 /* Print some infos about the FIS. */
6648 ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
6649
6650 /* Print the PRDT */
6651 ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6652 RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6653
6654 for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6655 {
6656 SGLEntry SGEntry;
6657
6658 ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6659 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
6660
6661 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
6662 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
6663
6664 GCPhysPrdtl += sizeof(SGLEntry);
6665 }
6666#endif
6667
6668 return true;
6669}
6670
6671/**
6672 * Submits a given request for execution.
6673 *
6674 * @returns Flag whether the request was canceled inbetween.
6675 * @param pAhciPort The port the request is for.
6676 * @param pAhciReq The request to submit.
6677 * @param enmTxDir The request type.
6678 */
6679static bool ahciR3ReqSubmit(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, AHCITXDIR enmTxDir)
6680{
6681 int rc = VINF_SUCCESS;
6682 bool fReqCanceled = false;
6683
6684 if (pAhciPort->fAsyncInterface)
6685 {
6686 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, pAhciReq->enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);
6687 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);
6688 if (enmTxDir == AHCITXDIR_FLUSH)
6689 {
6690 rc = pAhciPort->pDrvMediaAsync->pfnStartFlush(pAhciPort->pDrvMediaAsync,
6691 pAhciReq);
6692 }
6693 else if (enmTxDir == AHCITXDIR_TRIM)
6694 {
6695 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6696 if (RT_SUCCESS(rc))
6697 {
6698 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6699 rc = pAhciPort->pDrvMediaAsync->pfnStartDiscard(pAhciPort->pDrvMediaAsync, pAhciReq->u.Trim.paRanges,
6700 pAhciReq->u.Trim.cRanges, pAhciReq);
6701 }
6702 }
6703 else if (enmTxDir == AHCITXDIR_READ)
6704 {
6705 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6706 rc = pAhciPort->pDrvMediaAsync->pfnStartRead(pAhciPort->pDrvMediaAsync, pAhciReq->uOffset,
6707 &pAhciReq->u.Io.DataSeg, 1,
6708 pAhciReq->cbTransfer,
6709 pAhciReq);
6710 }
6711 else
6712 {
6713 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6714 rc = pAhciPort->pDrvMediaAsync->pfnStartWrite(pAhciPort->pDrvMediaAsync, pAhciReq->uOffset,
6715 &pAhciReq->u.Io.DataSeg, 1,
6716 pAhciReq->cbTransfer,
6717 pAhciReq);
6718 }
6719 if (rc == VINF_VD_ASYNC_IO_FINISHED)
6720 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6721 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6722 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc);
6723 }
6724 else
6725 {
6726 if (enmTxDir == AHCITXDIR_FLUSH)
6727 rc = pAhciPort->pDrvMedia->pfnFlush(pAhciPort->pDrvMedia);
6728 else if (enmTxDir == AHCITXDIR_TRIM)
6729 {
6730 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
6731 if (RT_SUCCESS(rc))
6732 {
6733 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6734 rc = pAhciPort->pDrvMedia->pfnDiscard(pAhciPort->pDrvMedia, pAhciReq->u.Trim.paRanges,
6735 pAhciReq->u.Trim.cRanges);
6736 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6737 }
6738 }
6739 else if (enmTxDir == AHCITXDIR_READ)
6740 {
6741 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6742 rc = pAhciPort->pDrvMedia->pfnRead(pAhciPort->pDrvMedia, pAhciReq->uOffset,
6743 pAhciReq->u.Io.DataSeg.pvSeg,
6744 pAhciReq->cbTransfer);
6745 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;
6746 }
6747 else
6748 {
6749 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6750 rc = pAhciPort->pDrvMedia->pfnWrite(pAhciPort->pDrvMedia, pAhciReq->uOffset,
6751 pAhciReq->u.Io.DataSeg.pvSeg,
6752 pAhciReq->cbTransfer);
6753 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
6754 }
6755 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc);
6756 }
6757
6758 return fReqCanceled;
6759}
6760
6761/**
6762 * Prepares the command for execution coping it from guest memory and doing a few
6763 * validation checks on it.
6764 *
6765 * @returns Whether the command was successfully fetched from guest memory and
6766 * can be continued.
6767 * @param pAhciPort The AHCI port the request is for.
6768 * @param pAhciReq Request structure to copy the command to.
6769 */
6770static bool ahciR3CmdPrepare(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6771{
6772 pAhciReq->tsStart = RTTimeMilliTS();
6773 pAhciReq->uATARegStatus = 0;
6774 pAhciReq->uATARegError = 0;
6775
6776 /* Set current command slot */
6777 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
6778 ASMAtomicWritePtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], pAhciReq);
6779
6780 bool fContinue = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
6781 if (fContinue)
6782 {
6783 /* 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. */
6784 if (pAhciPort->regSACT & RT_BIT_32(pAhciReq->uTag))
6785 {
6786 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT;
6787 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(pAhciReq->uTag));
6788 }
6789
6790 if (pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
6791 {
6792 /*
6793 * It is possible that the request counter can get one higher than the maximum because
6794 * the request counter is decremented after the guest was notified about the completed
6795 * request (see @bugref{7859}). If the completing thread is preempted in between the
6796 * guest might already issue another request before the request counter is decremented
6797 * which would trigger the following assertion incorrectly in the past.
6798 */
6799 AssertLogRelMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) <= AHCI_NR_COMMAND_SLOTS,
6800 ("AHCI#%uP%u: There are more than %u (+1) requests active",
6801 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6802 AHCI_NR_COMMAND_SLOTS));
6803 ASMAtomicIncU32(&pAhciPort->cTasksActive);
6804 }
6805 else
6806 {
6807 /* If the reset bit is set put the device into reset state. */
6808 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6809 {
6810 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6811 pAhciPort->fResetDevice = true;
6812 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
6813 }
6814 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
6815 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
6816 else /* We are not in a reset state update the control registers. */
6817 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
6818
6819 fContinue = false;
6820 }
6821 }
6822 else
6823 {
6824 /*
6825 * Couldn't find anything in either the AHCI or SATA spec which
6826 * indicates what should be done if the FIS is not read successfully.
6827 * The closest thing is in the state machine, stating that the device
6828 * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
6829 * Do the same here and ignore any corrupt FIS types, after all
6830 * the guest messed up everything and this behavior is undefined.
6831 */
6832 fContinue = false;
6833 }
6834
6835 return fContinue;
6836}
6837
6838/**
6839 * Transmit queue consumer
6840 * Queue a new async task.
6841 *
6842 * @returns Success indicator.
6843 * If false the item will not be removed and the flushing will stop.
6844 * @param pDevIns The device instance.
6845 * @param pItem The item to consume. Upon return this item will be freed.
6846 */
6847static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
6848{
6849 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
6850 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6851 PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
6852 int rc = VINF_SUCCESS;
6853
6854 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
6855 /* Notify the async IO thread. */
6856 rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6857 AssertRC(rc);
6858
6859 return true;
6860}
6861
6862/* The async IO thread for one port. */
6863static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
6864{
6865 RT_NOREF(pDevIns);
6866 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
6867 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6868 int rc = VINF_SUCCESS;
6869
6870 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
6871
6872 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
6873 return VINF_SUCCESS;
6874
6875 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
6876 {
6877 unsigned idx = 0;
6878 uint32_t u32Tasks = 0;
6879 uint32_t u32RegHbaCtrl = 0;
6880
6881 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
6882 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6883 if (!u32Tasks)
6884 {
6885 Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
6886 rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
6887 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
6888 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
6889 break;
6890 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
6891 u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
6892 }
6893
6894 ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
6895 ASMAtomicIncU32(&pAhci->cThreadsActive);
6896
6897 /* Check whether the thread should be suspended. */
6898 if (pAhci->fSignalIdle)
6899 {
6900 if (!ASMAtomicDecU32(&pAhci->cThreadsActive))
6901 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6902 continue;
6903 }
6904
6905 /*
6906 * Check whether the global host controller bit is set and go to sleep immediately again
6907 * if it is set.
6908 */
6909 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
6910 if ( u32RegHbaCtrl & AHCI_HBA_CTRL_HR
6911 && !ASMAtomicDecU32(&pAhci->cThreadsActive))
6912 {
6913 ahciHBAReset(pAhci);
6914 if (pAhci->fSignalIdle)
6915 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
6916 continue;
6917 }
6918
6919 idx = ASMBitFirstSetU32(u32Tasks);
6920 while ( idx
6921 && !pAhciPort->fPortReset)
6922 {
6923 bool fReqCanceled = false;
6924 AHCITXDIR enmTxDir;
6925 PAHCIREQ pAhciReq;
6926
6927 /* Decrement to get the slot number. */
6928 idx--;
6929 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
6930
6931 /* Check whether the request is already active and ignore. */
6932 if (ASMAtomicReadPtr((void * volatile *)&pAhciPort->aActiveTasks[idx]))
6933 {
6934 ahciLog(("%s: Ignoring command at slot %d because it is already active\n", __FUNCTION__, idx));
6935 continue;
6936 }
6937
6938 pAhciReq = ahciR3ReqAlloc(pAhciPort);
6939 if (RT_LIKELY(pAhciReq))
6940 {
6941 pAhciReq->uTag = idx;
6942 pAhciReq->fFlags = 0;
6943
6944 bool fContinue = ahciR3CmdPrepare(pAhciPort, pAhciReq);
6945 if (fContinue)
6946 {
6947 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6948 pAhciReq->enmTxDir = enmTxDir;
6949
6950 if (enmTxDir != AHCITXDIR_NONE)
6951 {
6952 if ( enmTxDir != AHCITXDIR_FLUSH
6953 && enmTxDir != AHCITXDIR_TRIM)
6954 {
6955 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
6956
6957 rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
6958 if (RT_FAILURE(rc))
6959 {
6960 /* In case we can't allocate enough memory fail the request with an overflow error. */
6961 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
6962 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
6963 }
6964 }
6965
6966 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
6967 fReqCanceled = ahciR3ReqSubmit(pAhciPort, pAhciReq, enmTxDir);
6968 else /* Overflow is handled in completion routine. */
6969 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6970 }
6971 else
6972 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS);
6973 } /* Command */
6974 else
6975 {
6976 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag]);
6977 ahciR3ReqFree(pAhciPort, pAhciReq);
6978 }
6979 }
6980 else /* !Request allocated, use on stack variant to signal the error. */
6981 {
6982 AHCIREQ Req;
6983 Req.uTag = idx;
6984 Req.fFlags = AHCI_REQ_IS_ON_STACK;
6985
6986 bool fContinue = ahciR3CmdPrepare(pAhciPort, &Req);
6987 if (fContinue)
6988 fReqCanceled = ahciTransferComplete(pAhciPort, &Req, VERR_NO_MEMORY);
6989 }
6990
6991 /*
6992 * Don't process other requests if the last one was canceled,
6993 * the others are not valid anymore.
6994 */
6995 if (fReqCanceled)
6996 break;
6997
6998 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
6999 idx = ASMBitFirstSetU32(u32Tasks);
7000 } /* while tasks available */
7001
7002 /* Check whether a port reset was active. */
7003 if ( ASMAtomicReadBool(&pAhciPort->fPortReset)
7004 && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
7005 ahciPortResetFinish(pAhciPort);
7006
7007 /*
7008 * Check whether a host controller reset is pending and execute the reset
7009 * if this is the last active thread.
7010 */
7011 u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
7012 uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
7013 if ( (u32RegHbaCtrl & AHCI_HBA_CTRL_HR)
7014 && !cThreadsActive)
7015 ahciHBAReset(pAhci);
7016
7017 if (!cThreadsActive && pAhci->fSignalIdle)
7018 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
7019 } /* While running */
7020
7021 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
7022 return VINF_SUCCESS;
7023}
7024
7025/**
7026 * Unblock the async I/O thread so it can respond to a state change.
7027 *
7028 * @returns VBox status code.
7029 * @param pDevIns The device instance.
7030 * @param pThread The send thread.
7031 */
7032static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
7033{
7034 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7035 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
7036 return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
7037}
7038
7039/* -=-=-=-=- DBGF -=-=-=-=- */
7040
7041/**
7042 * AHCI status info callback.
7043 *
7044 * @param pDevIns The device instance.
7045 * @param pHlp The output helpers.
7046 * @param pszArgs The arguments.
7047 */
7048static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
7049{
7050 RT_NOREF(pszArgs);
7051 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7052
7053 /*
7054 * Show info.
7055 */
7056 pHlp->pfnPrintf(pHlp,
7057 "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
7058 pDevIns->pReg->szName,
7059 pDevIns->iInstance,
7060 pThis->MMIOBase,
7061 pThis->cPortsImpl,
7062 pThis->fGCEnabled ? true : false,
7063 pThis->fR0Enabled ? true : false);
7064
7065 /*
7066 * Show global registers.
7067 */
7068 pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
7069 pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
7070 pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
7071 pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
7072 pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
7073 pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
7074 pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
7075 pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
7076
7077 /*
7078 * Per port data.
7079 */
7080 for (unsigned i = 0; i < pThis->cPortsImpl; i++)
7081 {
7082 PAHCIPort pThisPort = &pThis->ahciPort[i];
7083
7084 pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
7085 pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
7086 pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
7087 pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
7088 pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
7089 pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
7090 pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
7091 pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
7092 pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
7093 pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
7094 pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
7095 pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
7096 pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
7097 pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
7098 pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
7099 pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
7100 pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
7101 pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
7102 pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
7103 pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
7104 pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
7105 pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
7106 pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
7107 pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
7108 pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
7109 pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
7110 pHlp->pfnPrintf(pHlp, "\n");
7111 }
7112}
7113
7114/* -=-=-=-=- Helper -=-=-=-=- */
7115
7116/**
7117 * Checks if all asynchronous I/O is finished, both AHCI and IDE.
7118 *
7119 * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
7120 * use of it in strict builds (which is why it's up here).
7121 *
7122 * @returns true if quiesced, false if busy.
7123 * @param pDevIns The device instance.
7124 */
7125static bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
7126{
7127 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7128
7129 if (pThis->cThreadsActive)
7130 return false;
7131
7132 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
7133 {
7134 PAHCIPort pThisPort = &pThis->ahciPort[i];
7135 if (pThisPort->pDrvBase)
7136 {
7137 if ( (pThisPort->cTasksActive != 0)
7138 || (pThisPort->u32TasksNew != 0))
7139 return false;
7140 }
7141 }
7142 return true;
7143}
7144
7145/* -=-=-=-=- Saved State -=-=-=-=- */
7146
7147/**
7148 * @callback_method_impl{FNSSMDEVSAVEPREP}
7149 */
7150static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7151{
7152 RT_NOREF(pDevIns, pSSM);
7153 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
7154 return VINF_SUCCESS;
7155}
7156
7157/**
7158 * @callback_method_impl{FNSSMDEVLOADPREP}
7159 */
7160static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7161{
7162 RT_NOREF(pDevIns, pSSM);
7163 Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
7164 return VINF_SUCCESS;
7165}
7166
7167/**
7168 * @callback_method_impl{FNSSMDEVLIVEEXEC}
7169 */
7170static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
7171{
7172 RT_NOREF(uPass);
7173 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7174
7175 /* config. */
7176 SSMR3PutU32(pSSM, pThis->cPortsImpl);
7177 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7178 {
7179 SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
7180 SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
7181 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
7182 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
7183 SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
7184 }
7185
7186 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7187 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7188 {
7189 uint32_t iPort;
7190 int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7191 AssertRCReturn(rc, rc);
7192 SSMR3PutU32(pSSM, iPort);
7193 }
7194
7195 return VINF_SSM_DONT_CALL_AGAIN;
7196}
7197
7198/**
7199 * @callback_method_impl{FNSSMDEVSAVEEXEC}
7200 */
7201static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
7202{
7203 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7204 uint32_t i;
7205 int rc;
7206
7207 Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
7208
7209 /* The config */
7210 rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
7211 AssertRCReturn(rc, rc);
7212
7213 /* The main device structure. */
7214 SSMR3PutU32(pSSM, pThis->regHbaCap);
7215 SSMR3PutU32(pSSM, pThis->regHbaCtrl);
7216 SSMR3PutU32(pSSM, pThis->regHbaIs);
7217 SSMR3PutU32(pSSM, pThis->regHbaPi);
7218 SSMR3PutU32(pSSM, pThis->regHbaVs);
7219 SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
7220 SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
7221 SSMR3PutU8(pSSM, pThis->uCccPortNr);
7222 SSMR3PutU64(pSSM, pThis->uCccTimeout);
7223 SSMR3PutU32(pSSM, pThis->uCccNr);
7224 SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
7225 SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
7226 SSMR3PutBool(pSSM, pThis->fReset);
7227 SSMR3PutBool(pSSM, pThis->f64BitAddr);
7228 SSMR3PutBool(pSSM, pThis->fR0Enabled);
7229 SSMR3PutBool(pSSM, pThis->fGCEnabled);
7230 SSMR3PutBool(pSSM, pThis->fLegacyPortResetMethod);
7231
7232 /* Now every port. */
7233 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7234 {
7235 Assert(pThis->ahciPort[i].cTasksActive == 0);
7236 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
7237 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
7238 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
7239 SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
7240 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
7241 SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
7242 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
7243 SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
7244 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
7245 SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
7246 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
7247 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
7248 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
7249 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
7250 SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
7251 SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
7252 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
7253 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
7254 SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
7255 SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
7256 SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
7257 SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
7258 SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
7259 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
7260 SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
7261 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
7262 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
7263 SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
7264
7265 /* ATAPI saved state. */
7266 SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
7267 SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
7268 SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
7269 SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
7270 }
7271
7272 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
7273}
7274
7275/**
7276 * Loads a saved legacy ATA emulated device state.
7277 *
7278 * @returns VBox status code.
7279 * @param pSSM The handle to the saved state.
7280 */
7281static int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
7282{
7283 int rc;
7284 uint32_t u32Version;
7285 uint32_t u32;
7286 uint32_t u32IOBuffer;
7287
7288 /* Test for correct version. */
7289 rc = SSMR3GetU32(pSSM, &u32Version);
7290 AssertRCReturn(rc, rc);
7291 LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
7292
7293 if ( u32Version != ATA_CTL_SAVED_STATE_VERSION
7294 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
7295 && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7296 {
7297 AssertMsgFailed(("u32Version=%d\n", u32Version));
7298 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7299 }
7300
7301 SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
7302
7303 for (uint32_t j = 0; j < 2; j++)
7304 {
7305 SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
7306
7307 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
7308 SSMR3Skip(pSSM, 64);
7309 else
7310 SSMR3Skip(pSSM, 2);
7311 /** @todo triple-check this hack after passthrough is working */
7312 SSMR3Skip(pSSM, 1);
7313
7314 if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
7315 SSMR3Skip(pSSM, 4);
7316
7317 SSMR3Skip(pSSM, sizeof(PDMLED));
7318 SSMR3GetU32(pSSM, &u32IOBuffer);
7319 if (u32IOBuffer)
7320 SSMR3Skip(pSSM, u32IOBuffer);
7321 }
7322
7323 rc = SSMR3GetU32(pSSM, &u32);
7324 if (RT_FAILURE(rc))
7325 return rc;
7326 if (u32 != ~0U)
7327 {
7328 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
7329 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
7330 return rc;
7331 }
7332
7333 return VINF_SUCCESS;
7334}
7335
7336/**
7337 * @callback_method_impl{FNSSMDEVLOADEXEC}
7338 */
7339static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
7340{
7341 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7342 uint32_t u32;
7343 int rc;
7344
7345 if ( uVersion > AHCI_SAVED_STATE_VERSION
7346 || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
7347 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
7348
7349 /* Deal with the priod after removing the saved IDE bits where the saved
7350 state version remained unchanged. */
7351 if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
7352 && SSMR3HandleRevision(pSSM) >= 79045
7353 && SSMR3HandleRevision(pSSM) < 79201)
7354 uVersion++;
7355
7356 /*
7357 * Check whether we have to resort to the legacy port reset method to
7358 * prevent older BIOS versions from failing after a reset.
7359 */
7360 if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7361 pThis->fLegacyPortResetMethod = true;
7362
7363 /* Verify config. */
7364 if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
7365 {
7366 rc = SSMR3GetU32(pSSM, &u32);
7367 AssertRCReturn(rc, rc);
7368 if (u32 != pThis->cPortsImpl)
7369 {
7370 LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
7371 if ( u32 < pThis->cPortsImpl
7372 || u32 > AHCI_MAX_NR_PORTS_IMPL)
7373 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
7374 u32, pThis->cPortsImpl);
7375 }
7376
7377 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7378 {
7379 bool fInUse;
7380 rc = SSMR3GetBool(pSSM, &fInUse);
7381 AssertRCReturn(rc, rc);
7382 if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
7383 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7384 N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
7385 fInUse ? "target" : "source", i );
7386
7387 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
7388 {
7389 bool fHotpluggable;
7390 rc = SSMR3GetBool(pSSM, &fHotpluggable);
7391 AssertRCReturn(rc, rc);
7392 if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
7393 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
7394 N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
7395 i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
7396 }
7397 else
7398 Assert(pThis->ahciPort[i].fHotpluggable);
7399
7400 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
7401 rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
7402 AssertRCReturn(rc, rc);
7403 if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
7404 LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
7405 i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
7406
7407 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
7408 rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
7409 AssertRCReturn(rc, rc);
7410 if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
7411 LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
7412 i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
7413
7414 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
7415 rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
7416 AssertRCReturn(rc, rc);
7417 if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
7418 LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
7419 i, szModelNumber, pThis->ahciPort[i].szModelNumber));
7420 }
7421
7422 static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
7423 for (uint32_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
7424 {
7425 uint32_t iPort;
7426 rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
7427 AssertRCReturn(rc, rc);
7428
7429 uint32_t iPortSaved;
7430 rc = SSMR3GetU32(pSSM, &iPortSaved);
7431 AssertRCReturn(rc, rc);
7432
7433 if (iPortSaved != iPort)
7434 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
7435 s_apszIdeEmuPortNames[i], iPortSaved, iPort);
7436 }
7437 }
7438
7439 if (uPass == SSM_PASS_FINAL)
7440 {
7441 /* Restore data. */
7442
7443 /* The main device structure. */
7444 SSMR3GetU32(pSSM, &pThis->regHbaCap);
7445 SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
7446 SSMR3GetU32(pSSM, &pThis->regHbaIs);
7447 SSMR3GetU32(pSSM, &pThis->regHbaPi);
7448 SSMR3GetU32(pSSM, &pThis->regHbaVs);
7449 SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
7450 SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
7451 SSMR3GetU8(pSSM, &pThis->uCccPortNr);
7452 SSMR3GetU64(pSSM, &pThis->uCccTimeout);
7453 SSMR3GetU32(pSSM, &pThis->uCccNr);
7454 SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
7455
7456 SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
7457 SSMR3GetBool(pSSM, &pThis->fReset);
7458 SSMR3GetBool(pSSM, &pThis->f64BitAddr);
7459 SSMR3GetBool(pSSM, &pThis->fR0Enabled);
7460 SSMR3GetBool(pSSM, &pThis->fGCEnabled);
7461 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
7462 SSMR3GetBool(pSSM, &pThis->fLegacyPortResetMethod);
7463
7464 /* Now every port. */
7465 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
7466 {
7467 PAHCIPort pAhciPort = &pThis->ahciPort[i];
7468
7469 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
7470 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
7471 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
7472 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
7473 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
7474 SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
7475 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
7476 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regIE);
7477 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
7478 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
7479 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
7480 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
7481 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
7482 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
7483 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
7484 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
7485 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
7486 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
7487 SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
7488 SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
7489 SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
7490 SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
7491 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
7492
7493 if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
7494 SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
7495
7496 if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7497 {
7498 /* The old positions in the FIFO, not required. */
7499 SSMR3Skip(pSSM, 2*sizeof(uint8_t));
7500 }
7501 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
7502 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
7503 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
7504 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
7505
7506 if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7507 SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
7508
7509 if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
7510 {
7511 SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
7512 SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
7513 SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
7514 SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
7515 }
7516 else if (pThis->ahciPort[i].fATAPI)
7517 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=false config=true"));
7518
7519 /* Check if we have tasks pending. */
7520 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
7521 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
7522
7523 pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
7524
7525 if (pAhciPort->u32TasksNew)
7526 {
7527 /*
7528 * There are tasks pending. The VM was saved after a task failed
7529 * because of non-fatal error. Set the redo flag.
7530 */
7531 pAhciPort->fRedo = true;
7532 }
7533 }
7534
7535 if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
7536 {
7537 for (uint32_t i = 0; i < 2; i++)
7538 {
7539 rc = ahciR3LoadLegacyEmulationState(pSSM);
7540 if(RT_FAILURE(rc))
7541 return rc;
7542 }
7543 }
7544
7545 rc = SSMR3GetU32(pSSM, &u32);
7546 if (RT_FAILURE(rc))
7547 return rc;
7548 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
7549 }
7550
7551 return VINF_SUCCESS;
7552}
7553
7554/* -=-=-=-=- device PDM interface -=-=-=-=- */
7555
7556static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
7557{
7558 uint32_t i;
7559 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7560
7561 pAhci->pDevInsRC += offDelta;
7562 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
7563 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
7564
7565 /* Relocate every port. */
7566 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7567 {
7568 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7569 pAhciPort->pAhciRC += offDelta;
7570 pAhciPort->pDevInsRC += offDelta;
7571 }
7572}
7573
7574/**
7575 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
7576 * from now on, regardless if there was a medium inserted or not.
7577 */
7578static void ahciMediumRemoved(PAHCIPort pAhciPort)
7579{
7580 ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
7581}
7582
7583/**
7584 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
7585 * there was already a medium inserted, don't forget to send the "medium
7586 * removed" event first.
7587 */
7588static void ahciMediumInserted(PAHCIPort pAhciPort)
7589{
7590 uint32_t OldStatus, NewStatus;
7591 do
7592 {
7593 OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
7594 switch (OldStatus)
7595 {
7596 case ATA_EVENT_STATUS_MEDIA_CHANGED:
7597 case ATA_EVENT_STATUS_MEDIA_REMOVED:
7598 /* no change, we will send "medium removed" + "medium inserted" */
7599 NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
7600 break;
7601 default:
7602 NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
7603 break;
7604 }
7605 } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
7606}
7607
7608/**
7609 * Called when a media is mounted.
7610 *
7611 * @param pInterface Pointer to the interface structure containing the called function pointer.
7612 */
7613static DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
7614{
7615 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7616 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
7617
7618 /* Ignore the call if we're called while being attached. */
7619 if (!pAhciPort->pDrvMedia)
7620 return;
7621
7622 if (pAhciPort->fATAPI)
7623 {
7624 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7625
7626 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
7627
7628 /* Report media changed in TEST UNIT and other (probably incorrect) places. */
7629 if (pAhciPort->cNotifiedMediaChange < 2)
7630 pAhciPort->cNotifiedMediaChange = 2;
7631 ahciMediumInserted(pAhciPort);
7632 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7633 }
7634 else
7635 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7636}
7637
7638/**
7639 * Called when a media is unmounted
7640 * @param pInterface Pointer to the interface structure containing the called function pointer.
7641 */
7642static DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
7643{
7644 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
7645 Log(("%s:\n", __FUNCTION__));
7646
7647 /* Free all cached I/O tasks. */
7648 ahciR3PortCachedReqsFree(pAhciPort);
7649
7650 pAhciPort->cTotalSectors = 0;
7651
7652 if (pAhciPort->fATAPI)
7653 {
7654 /*
7655 * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
7656 * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
7657 * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
7658 * present and 2 in which it is changed.
7659 */
7660 pAhciPort->cNotifiedMediaChange = 4;
7661 ahciMediumRemoved(pAhciPort);
7662 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
7663 }
7664 else
7665 AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
7666}
7667
7668/**
7669 * Configure the attached device for a port.
7670 *
7671 * Used by ahciR3Construct and ahciR3Attach.
7672 *
7673 * @returns VBox status code
7674 * @param pDevIns The device instance data.
7675 * @param pAhciPort The port for which the device is to be configured.
7676 */
7677static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
7678{
7679 int rc = VINF_SUCCESS;
7680 PDMMEDIATYPE enmType;
7681
7682 /*
7683 * Query the block and blockbios interfaces.
7684 */
7685 pAhciPort->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIA);
7686 if (!pAhciPort->pDrvMedia)
7687 {
7688 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
7689 return VERR_PDM_MISSING_INTERFACE;
7690 }
7691
7692 pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
7693
7694 /* Try to get the optional async block interface. */
7695 pAhciPort->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMEDIAASYNC);
7696
7697 /*
7698 * Validate type.
7699 */
7700 enmType = pAhciPort->pDrvMedia->pfnGetType(pAhciPort->pDrvMedia);
7701
7702 if ( enmType != PDMMEDIATYPE_HARD_DISK
7703 && enmType != PDMMEDIATYPE_CDROM
7704 && enmType != PDMMEDIATYPE_DVD)
7705 {
7706 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
7707 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
7708 }
7709
7710 if ( (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
7711 && !pAhciPort->pDrvMount)
7712 {
7713 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
7714 return VERR_INTERNAL_ERROR;
7715 }
7716 pAhciPort->fATAPI = (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD);
7717 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvMedia->pfnSendCmd != NULL) : false;
7718
7719 rc = RTCritSectInit(&pAhciPort->CritSectReqsFree);
7720 if (RT_FAILURE(rc))
7721 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
7722 N_("AHCI initialisation error: Failed to create critical section for free request list"));
7723
7724 pAhciPort->pListReqsFree = (PRTLISTANCHOR)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(RTLISTANCHOR));
7725 if (!pAhciPort->pListReqsFree)
7726 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
7727 N_("AHCI initialisation error: Failed to allocate memory for free request list"));
7728
7729 RTListInit(pAhciPort->pListReqsFree);
7730
7731 if (pAhciPort->fATAPI)
7732 {
7733 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / 2048;
7734 pAhciPort->PCHSGeometry.cCylinders = 0;
7735 pAhciPort->PCHSGeometry.cHeads = 0;
7736 pAhciPort->PCHSGeometry.cSectors = 0;
7737 LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN,
7738 pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
7739 }
7740 else
7741 {
7742 pAhciPort->cbSector = pAhciPort->pDrvMedia->pfnGetSectorSize(pAhciPort->pDrvMedia);
7743 pAhciPort->cTotalSectors = pAhciPort->pDrvMedia->pfnGetSize(pAhciPort->pDrvMedia) / pAhciPort->cbSector;
7744 rc = pAhciPort->pDrvMedia->pfnBiosGetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7745 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
7746 {
7747 pAhciPort->PCHSGeometry.cCylinders = 0;
7748 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
7749 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
7750 }
7751 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
7752 {
7753 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
7754 rc = VINF_SUCCESS;
7755 }
7756 AssertRC(rc);
7757
7758 if ( pAhciPort->PCHSGeometry.cCylinders == 0
7759 || pAhciPort->PCHSGeometry.cHeads == 0
7760 || pAhciPort->PCHSGeometry.cSectors == 0)
7761 {
7762 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
7763 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
7764 pAhciPort->PCHSGeometry.cHeads = 16;
7765 pAhciPort->PCHSGeometry.cSectors = 63;
7766 /* Set the disk geometry information. Ignore errors. */
7767 pAhciPort->pDrvMedia->pfnBiosSetPCHSGeometry(pAhciPort->pDrvMedia, &pAhciPort->PCHSGeometry);
7768 rc = VINF_SUCCESS;
7769 }
7770 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
7771 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
7772 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
7773 pAhciPort->cTotalSectors));
7774 if (pAhciPort->pDrvMedia->pfnDiscard)
7775 LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
7776 }
7777 return rc;
7778}
7779
7780/**
7781 * Callback employed by ahciR3Suspend and ahciR3PowerOff..
7782 *
7783 * @returns true if we've quiesced, false if we're still working.
7784 * @param pDevIns The device instance.
7785 */
7786static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
7787{
7788 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7789 return false;
7790
7791 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7792 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7793 /*
7794 * Free all cached tasks here, not possible on destruct because the driver
7795 * is destroyed before us.
7796 */
7797 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7798 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7799 return true;
7800}
7801
7802/**
7803 * Common worker for ahciR3Suspend and ahciR3PowerOff.
7804 */
7805static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
7806{
7807 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
7808
7809 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
7810 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
7811 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
7812 else
7813 {
7814 /*
7815 * Free all cached tasks here, not possible on destruct because the driver
7816 * is destroyed before us.
7817 */
7818 for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
7819 ahciR3PortCachedReqsFree(&pThis->ahciPort[iPort]);
7820
7821 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
7822 }
7823}
7824
7825/**
7826 * Suspend notification.
7827 *
7828 * @param pDevIns The device instance data.
7829 */
7830static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
7831{
7832 Log(("ahciR3Suspend\n"));
7833 ahciR3SuspendOrPowerOff(pDevIns);
7834}
7835
7836/**
7837 * Resume notification.
7838 *
7839 * @param pDevIns The device instance data.
7840 */
7841static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
7842{
7843 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
7844
7845 /*
7846 * Check if one of the ports has pending tasks.
7847 * Queue a notification item again in this case.
7848 */
7849 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
7850 {
7851 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
7852
7853 if (pAhciPort->u32TasksRedo)
7854 {
7855 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
7856 AssertMsg(pItem, ("Allocating item for queue failed\n"));
7857
7858 pAhciPort->u32TasksNew |= pAhciPort->u32TasksRedo;
7859 pAhciPort->u32TasksRedo = 0;
7860
7861 Assert(pAhciPort->fRedo);
7862 pAhciPort->fRedo = false;
7863
7864 pItem->iPort = pAhci->ahciPort[i].iLUN;
7865 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
7866 }
7867 }
7868
7869 Log(("%s:\n", __FUNCTION__));
7870}
7871
7872/**
7873 * Initializes the VPD data of a attached device.
7874 *
7875 * @returns VBox status code.
7876 * @param pDevIns The device instance.
7877 * @param pAhciPort The attached device.
7878 * @param szName Name of the port to get the CFGM node.
7879 */
7880static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
7881{
7882
7883 /* Generate a default serial number. */
7884 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
7885 RTUUID Uuid;
7886
7887 int rc = VINF_SUCCESS;
7888 if (pAhciPort->pDrvMedia)
7889 rc = pAhciPort->pDrvMedia->pfnGetUuid(pAhciPort->pDrvMedia, &Uuid);
7890 else
7891 RTUuidClear(&Uuid);
7892
7893 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
7894 {
7895 /* Generate a predictable serial for drives which don't have a UUID. */
7896 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
7897 pAhciPort->iLUN);
7898 }
7899 else
7900 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
7901
7902 /* Get user config if present using defaults otherwise. */
7903 PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
7904 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
7905 szSerial);
7906 if (RT_FAILURE(rc))
7907 {
7908 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7909 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7910 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
7911 return PDMDEV_SET_ERROR(pDevIns, rc,
7912 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
7913 }
7914
7915 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
7916 "1.0");
7917 if (RT_FAILURE(rc))
7918 {
7919 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7920 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7921 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
7922 return PDMDEV_SET_ERROR(pDevIns, rc,
7923 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
7924 }
7925
7926 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
7927 pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
7928 if (RT_FAILURE(rc))
7929 {
7930 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7931 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7932 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
7933 return PDMDEV_SET_ERROR(pDevIns, rc,
7934 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
7935 }
7936
7937 rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
7938 if (RT_FAILURE(rc))
7939 return PDMDEV_SET_ERROR(pDevIns, rc,
7940 N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
7941
7942 rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
7943 if (RT_FAILURE(rc))
7944 return PDMDEV_SET_ERROR(pDevIns, rc,
7945 N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
7946 if (pAhciPort->cLogSectorsPerPhysicalExp >= 16)
7947 return PDMDEV_SET_ERROR(pDevIns, rc,
7948 N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
7949
7950 /* There are three other identification strings for CD drives used for INQUIRY */
7951 if (pAhciPort->fATAPI)
7952 {
7953 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
7954 "VBOX");
7955 if (RT_FAILURE(rc))
7956 {
7957 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7958 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7959 N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
7960 return PDMDEV_SET_ERROR(pDevIns, rc,
7961 N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
7962 }
7963
7964 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
7965 "CD-ROM");
7966 if (RT_FAILURE(rc))
7967 {
7968 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7969 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7970 N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
7971 return PDMDEV_SET_ERROR(pDevIns, rc,
7972 N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
7973 }
7974
7975 rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
7976 "1.0");
7977 if (RT_FAILURE(rc))
7978 {
7979 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
7980 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
7981 N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
7982 return PDMDEV_SET_ERROR(pDevIns, rc,
7983 N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
7984 }
7985 }
7986
7987 return rc;
7988}
7989
7990
7991/**
7992 * Detach notification.
7993 *
7994 * One harddisk at one port has been unplugged.
7995 * The VM is suspended at this point.
7996 *
7997 * @param pDevIns The device instance.
7998 * @param iLUN The logical unit which is being detached.
7999 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
8000 */
8001static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
8002{
8003 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
8004 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
8005 int rc = VINF_SUCCESS;
8006
8007 Log(("%s:\n", __FUNCTION__));
8008
8009 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
8010 AssertMsgReturnVoid( pAhciPort->fHotpluggable
8011 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
8012 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
8013
8014
8015 if (pAhciPort->pAsyncIOThread)
8016 {
8017 int rcThread;
8018 /* Destroy the thread. */
8019 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
8020 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
8021 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
8022
8023 pAhciPort->pAsyncIOThread = NULL;
8024 pAhciPort->fWrkThreadSleeping = true;
8025 }
8026
8027 if (pAhciPort->fATAPI)
8028 ahciMediumRemoved(pAhciPort);
8029
8030 /* Free all cached I/O tasks. */
8031 ahciR3PortCachedReqsFree(pAhciPort);
8032
8033 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree))
8034 RTCritSectDelete(&pAhciPort->CritSectReqsFree);
8035
8036 if (pAhciPort->pListReqsFree)
8037 MMR3HeapFree(pAhciPort->pListReqsFree);
8038
8039 pAhciPort->pListReqsFree = NULL;
8040
8041 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
8042 {
8043 /*
8044 * Inform the guest about the removed device.
8045 */
8046 pAhciPort->regSSTS = 0;
8047 pAhciPort->regSIG = 0;
8048 /*
8049 * Clear CR bit too to prevent submission of new commands when CI is written
8050 * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
8051 */
8052 ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
8053 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
8054 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
8055 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
8056 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
8057 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
8058 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
8059 }
8060
8061 /*
8062 * Zero some important members.
8063 */
8064 pAhciPort->pDrvBase = NULL;
8065 pAhciPort->pDrvMedia = NULL;
8066 pAhciPort->pDrvMediaAsync = NULL;
8067}
8068
8069/**
8070 * Attach command.
8071 *
8072 * This is called when we change block driver for one port.
8073 * The VM is suspended at this point.
8074 *
8075 * @returns VBox status code.
8076 * @param pDevIns The device instance.
8077 * @param iLUN The logical unit which is being detached.
8078 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
8079 */
8080static DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
8081{
8082 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8083 PAHCIPort pAhciPort = &pThis->ahciPort[iLUN];
8084 int rc;
8085
8086 Log(("%s:\n", __FUNCTION__));
8087
8088 /* the usual paranoia */
8089 AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
8090 AssertRelease(!pAhciPort->pDrvBase);
8091 AssertRelease(!pAhciPort->pDrvMedia);
8092 AssertRelease(!pAhciPort->pDrvMediaAsync);
8093 Assert(pAhciPort->iLUN == iLUN);
8094
8095 AssertMsgReturn( pAhciPort->fHotpluggable
8096 || (fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
8097 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
8098 VERR_INVALID_PARAMETER);
8099
8100 /*
8101 * Try attach the block device and get the interfaces,
8102 * required as well as optional.
8103 */
8104 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
8105 if (RT_SUCCESS(rc))
8106 {
8107 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8108
8109 /*
8110 * In case there is a medium inserted.
8111 */
8112 ahciMediumInserted(pAhciPort);
8113 ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
8114 }
8115 else
8116 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
8117
8118 if (RT_FAILURE(rc))
8119 {
8120 pAhciPort->pDrvBase = NULL;
8121 pAhciPort->pDrvMedia = NULL;
8122 }
8123 else
8124 {
8125 char szName[24];
8126 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
8127
8128 if ( pAhciPort->pDrvMediaAsync
8129 && !pAhciPort->fATAPI)
8130 pAhciPort->fAsyncInterface = true;
8131 else
8132 pAhciPort->fAsyncInterface = false;
8133
8134 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8135 if (RT_FAILURE(rc))
8136 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8137 N_("AHCI: Failed to create SUP event semaphore"));
8138
8139 /* Create the async IO thread. */
8140 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
8141 RTTHREADTYPE_IO, szName);
8142 if (RT_FAILURE(rc))
8143 return rc;
8144
8145 /*
8146 * Init vendor product data.
8147 */
8148 if (RT_SUCCESS(rc))
8149 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8150
8151 /* Inform the guest about the added device in case of hotplugging. */
8152 if ( RT_SUCCESS(rc)
8153 && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
8154 {
8155 AssertMsgReturn(pAhciPort->fHotpluggable,
8156 ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
8157 VERR_NOT_SUPPORTED);
8158
8159 /*
8160 * Initialize registers
8161 */
8162 ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
8163 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
8164 ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
8165
8166 if (pAhciPort->fATAPI)
8167 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
8168 else
8169 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
8170 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
8171 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
8172 (0x03 << 0); /* Device detected and communication established. */
8173
8174 if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
8175 || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
8176 || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
8177 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
8178 }
8179
8180 }
8181
8182 return rc;
8183}
8184
8185/**
8186 * Common reset worker.
8187 *
8188 * @param pDevIns The device instance data.
8189 */
8190static int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
8191{
8192 RT_NOREF(fConstructor);
8193 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
8194
8195 ahciHBAReset(pAhci);
8196
8197 /* Hardware reset for the ports. */
8198 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
8199 ahciPortHwReset(&pAhci->ahciPort[i]);
8200 return VINF_SUCCESS;
8201}
8202
8203/**
8204 * Callback employed by ahciR3Reset.
8205 *
8206 * @returns true if we've quiesced, false if we're still working.
8207 * @param pDevIns The device instance.
8208 */
8209static DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
8210{
8211 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8212
8213 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8214 return false;
8215 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8216
8217 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8218 return true;
8219}
8220
8221/**
8222 * Reset notification.
8223 *
8224 * @param pDevIns The device instance data.
8225 */
8226static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
8227{
8228 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8229
8230 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
8231 if (!ahciR3AllAsyncIOIsFinished(pDevIns))
8232 PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
8233 else
8234 {
8235 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
8236 ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
8237 }
8238}
8239
8240/**
8241 * Poweroff notification.
8242 *
8243 * @param pDevIns Pointer to the device instance
8244 */
8245static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
8246{
8247 Log(("achiR3PowerOff\n"));
8248 ahciR3SuspendOrPowerOff(pDevIns);
8249}
8250
8251/**
8252 * Destroy a driver instance.
8253 *
8254 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
8255 * resources can be freed correctly.
8256 *
8257 * @param pDevIns The device instance data.
8258 */
8259static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
8260{
8261 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8262 int rc = VINF_SUCCESS;
8263 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
8264
8265 /*
8266 * At this point the async I/O thread is suspended and will not enter
8267 * this module again. So, no coordination is needed here and PDM
8268 * will take care of terminating and cleaning up the thread.
8269 */
8270 if (PDMCritSectIsInitialized(&pThis->lock))
8271 {
8272 TMR3TimerDestroy(pThis->CTX_SUFF(pHbaCccTimer));
8273 pThis->CTX_SUFF(pHbaCccTimer) = NULL;
8274
8275 Log(("%s: Destruct every port\n", __FUNCTION__));
8276 for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
8277 {
8278 PAHCIPort pAhciPort = &pThis->ahciPort[iActPort];
8279
8280 if (pAhciPort->hEvtProcess != NIL_SUPSEMEVENT)
8281 {
8282 SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
8283 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8284 }
8285
8286 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree))
8287 RTCritSectDelete(&pAhciPort->CritSectReqsFree);
8288
8289#ifdef VBOX_STRICT
8290 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
8291 Assert(!pAhciPort->aActiveTasks[i]);
8292#endif
8293 }
8294
8295 PDMR3CritSectDelete(&pThis->lock);
8296 }
8297
8298 return rc;
8299}
8300
8301/**
8302 * @interface_method_impl{PDMDEVREG,pfnConstruct}
8303 */
8304static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
8305{
8306 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
8307 PPDMIBASE pBase;
8308 int rc = VINF_SUCCESS;
8309 unsigned i = 0;
8310 bool fGCEnabled = false;
8311 bool fR0Enabled = false;
8312 uint32_t cbTotalBufferSize = 0;
8313 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
8314
8315 LogFlowFunc(("pThis=%#p\n", pThis));
8316
8317 /*
8318 * Validate and read configuration.
8319 */
8320 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
8321 "R0Enabled\0"
8322 "PrimaryMaster\0"
8323 "PrimarySlave\0"
8324 "SecondaryMaster\0"
8325 "SecondarySlave\0"
8326 "PortCount\0"
8327 "UseAsyncInterfaceIfAvailable\0"
8328 "Bootable\0"
8329 "CmdSlotsAvail\0"))
8330 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
8331 N_("AHCI configuration error: unknown option specified"));
8332
8333 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
8334 if (RT_FAILURE(rc))
8335 return PDMDEV_SET_ERROR(pDevIns, rc,
8336 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
8337 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
8338
8339 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
8340 if (RT_FAILURE(rc))
8341 return PDMDEV_SET_ERROR(pDevIns, rc,
8342 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
8343 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
8344
8345 rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8346 if (RT_FAILURE(rc))
8347 return PDMDEV_SET_ERROR(pDevIns, rc,
8348 N_("AHCI configuration error: failed to read PortCount as integer"));
8349 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
8350 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
8351 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8352 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
8353 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
8354 if (pThis->cPortsImpl < 1)
8355 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8356 N_("AHCI configuration error: PortCount=%u should be at least 1"),
8357 pThis->cPortsImpl);
8358
8359 rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
8360 if (RT_FAILURE(rc))
8361 return PDMDEV_SET_ERROR(pDevIns, rc,
8362 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
8363
8364 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
8365 if (RT_FAILURE(rc))
8366 return PDMDEV_SET_ERROR(pDevIns, rc,
8367 N_("AHCI configuration error: failed to read Bootable as boolean"));
8368
8369 rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
8370 if (RT_FAILURE(rc))
8371 return PDMDEV_SET_ERROR(pDevIns, rc,
8372 N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
8373 Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
8374 if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
8375 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8376 N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
8377 pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
8378 if (pThis->cCmdSlotsAvail < 1)
8379 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
8380 N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
8381 pThis->cCmdSlotsAvail);
8382
8383 /*
8384 * Initialize the instance data (everything touched by the destructor need
8385 * to be initialized here!).
8386 */
8387 pThis->fR0Enabled = fR0Enabled;
8388 pThis->fGCEnabled = fGCEnabled;
8389 pThis->pDevInsR3 = pDevIns;
8390 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8391 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8392 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
8393
8394 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
8395 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
8396 PCIDevSetCommand (&pThis->dev, 0x0000);
8397#ifdef VBOX_WITH_MSI_DEVICES
8398 PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8399 PCIDevSetCapabilityList(&pThis->dev, 0x80);
8400#else
8401 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8402#endif
8403 PCIDevSetRevisionId (&pThis->dev, 0x02);
8404 PCIDevSetClassProg (&pThis->dev, 0x01);
8405 PCIDevSetClassSub (&pThis->dev, 0x06);
8406 PCIDevSetClassBase (&pThis->dev, 0x01);
8407 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
8408
8409 PCIDevSetInterruptLine(&pThis->dev, 0x00);
8410 PCIDevSetInterruptPin (&pThis->dev, 0x01);
8411
8412 pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
8413 pThis->dev.config[0x71] = 0xa8; /* next */
8414 pThis->dev.config[0x72] = 0x03; /* version ? */
8415
8416 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
8417 pThis->dev.config[0x92] = 0x3f;
8418 pThis->dev.config[0x94] = 0x80;
8419 pThis->dev.config[0x95] = 0x01;
8420 pThis->dev.config[0x97] = 0x78;
8421
8422 pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
8423 pThis->dev.config[0xa9] = 0x00; /* next */
8424 PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
8425 PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
8426
8427 pThis->cThreadsActive = 0;
8428
8429 /* Initialize port members. */
8430 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8431 {
8432 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8433 pAhciPort->pDevInsR3 = pDevIns;
8434 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
8435 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
8436 pAhciPort->iLUN = i;
8437 pAhciPort->pAhciR3 = pThis;
8438 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
8439 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
8440 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
8441 pAhciPort->pDrvBase = NULL;
8442 pAhciPort->pAsyncIOThread = NULL;
8443 pAhciPort->hEvtProcess = NIL_SUPSEMEVENT;
8444 pAhciPort->fHotpluggable = true;
8445 }
8446
8447 /*
8448 * Init locks, using explicit locking where necessary.
8449 */
8450 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
8451 if (RT_FAILURE(rc))
8452 return rc;
8453
8454 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
8455 if (RT_FAILURE(rc))
8456 {
8457 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
8458 return rc;
8459 }
8460
8461 /*
8462 * Register the PCI device, it's I/O regions.
8463 */
8464 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
8465 if (RT_FAILURE(rc))
8466 return rc;
8467
8468#ifdef VBOX_WITH_MSI_DEVICES
8469 PDMMSIREG MsiReg;
8470 RT_ZERO(MsiReg);
8471 MsiReg.cMsiVectors = 1;
8472 MsiReg.iMsiCapOffset = 0x80;
8473 MsiReg.iMsiNextOffset = 0x70;
8474 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
8475 if (RT_FAILURE(rc))
8476 {
8477 PCIDevSetCapabilityList(&pThis->dev, 0x70);
8478 /* That's OK, we can work without MSI */
8479 }
8480#endif
8481
8482 /*
8483 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
8484 * IDE registers are not available.
8485 * We set up "fake" entries in the PCI configuration register.
8486 * That means they are available but read and writes from/to them have no effect.
8487 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
8488 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
8489 * to switch to it which also changes device Id and other things in the PCI configuration space).
8490 */
8491 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8492 if (RT_FAILURE(rc))
8493 return PDMDEV_SET_ERROR(pDevIns, rc,
8494 N_("AHCI cannot register PCI I/O region"));
8495
8496 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8497 if (RT_FAILURE(rc))
8498 return PDMDEV_SET_ERROR(pDevIns, rc,
8499 N_("AHCI cannot register PCI I/O region"));
8500
8501 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8502 if (RT_FAILURE(rc))
8503 return PDMDEV_SET_ERROR(pDevIns, rc,
8504 N_("AHCI cannot register PCI I/O region"));
8505
8506 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
8507 if (RT_FAILURE(rc))
8508 return PDMDEV_SET_ERROR(pDevIns, rc,
8509 N_("AHCI cannot register PCI I/O region"));
8510
8511 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
8512 if (RT_FAILURE(rc))
8513 return PDMDEV_SET_ERROR(pDevIns, rc,
8514 N_("AHCI cannot register PCI I/O region for BMDMA"));
8515
8516 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
8517 if (RT_FAILURE(rc))
8518 return PDMDEV_SET_ERROR(pDevIns, rc,
8519 N_("AHCI cannot register PCI memory region for registers"));
8520
8521 /* Create the timer for command completion coalescing feature. */
8522 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
8523 TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
8524 if (RT_FAILURE(rc))
8525 {
8526 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
8527 return rc;
8528 }
8529 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
8530 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
8531
8532 /* Status LUN. */
8533 pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
8534 pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
8535
8536 /*
8537 * Create the notification queue.
8538 *
8539 * We need 2 items for every port because of SMP races.
8540 */
8541 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8542 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
8543 if (RT_FAILURE(rc))
8544 return rc;
8545 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
8546 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
8547
8548 /* Initialize static members on every port. */
8549 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
8550 {
8551 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8552
8553 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8554 "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
8555 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8556 "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
8557 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
8558 "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
8559 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
8560 "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
8561#ifdef VBOX_WITH_STATISTICS
8562 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8563 "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
8564 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
8565 "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
8566#endif
8567
8568 ahciPortHwReset(pAhciPort);
8569 }
8570
8571 /* Attach drivers to every available port. */
8572 for (i = 0; i < pThis->cPortsImpl; i++)
8573 {
8574 char szName[24];
8575 RTStrPrintf(szName, sizeof(szName), "Port%u", i);
8576
8577 PAHCIPort pAhciPort = &pThis->ahciPort[i];
8578 /*
8579 * Init interfaces.
8580 */
8581 pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
8582 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciR3TransferCompleteNotify;
8583 pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
8584 pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
8585 pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
8586 pAhciPort->fWrkThreadSleeping = true;
8587
8588 /* Query per port configuration options if available. */
8589 PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
8590 if (pCfgPort)
8591 {
8592 rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
8593 if (RT_FAILURE(rc))
8594 return PDMDEV_SET_ERROR(pDevIns, rc,
8595 N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
8596 }
8597
8598 /*
8599 * Attach the block driver
8600 */
8601 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
8602 if (RT_SUCCESS(rc))
8603 {
8604 rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
8605 if (RT_FAILURE(rc))
8606 {
8607 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
8608 return rc;
8609 }
8610
8611 /* Mark that a device is present on that port */
8612 if (i < 6)
8613 pThis->dev.config[0x93] |= (1 << i);
8614
8615 /*
8616 * Init vendor product data.
8617 */
8618 rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
8619 if (RT_FAILURE(rc))
8620 return rc;
8621
8622 /*
8623 * If the new async interface is available we use a PDMQueue to transmit
8624 * the requests into R3.
8625 * Otherwise we use a event semaphore and a async I/O thread which processes them.
8626 */
8627 if (pAhciPort->pDrvMediaAsync && pThis->fUseAsyncInterfaceIfAvailable)
8628 {
8629 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
8630 pAhciPort->fAsyncInterface = true;
8631 }
8632 else
8633 {
8634 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
8635 pAhciPort->fAsyncInterface = false;
8636 }
8637
8638 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
8639 if (RT_FAILURE(rc))
8640 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8641 N_("AHCI: Failed to create SUP event semaphore"));
8642
8643 rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
8644 ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
8645 if (RT_FAILURE(rc))
8646 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8647 N_("AHCI: Failed to create worker thread %s"), szName);
8648 }
8649 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
8650 {
8651 pAhciPort->pDrvBase = NULL;
8652 rc = VINF_SUCCESS;
8653 LogRel(("AHCI: %s: No driver attached\n", szName));
8654 }
8655 else
8656 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
8657 N_("AHCI: Failed to attach drive to %s"), szName);
8658 }
8659
8660 /*
8661 * Attach status driver (optional).
8662 */
8663 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
8664 if (RT_SUCCESS(rc))
8665 {
8666 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
8667 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
8668 }
8669 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
8670 {
8671 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
8672 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
8673 }
8674 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
8675 NULL, ahciR3LiveExec, NULL,
8676 ahciR3SavePrep, ahciR3SaveExec, NULL,
8677 ahciR3LoadPrep, ahciR3LoadExec, NULL);
8678 if (RT_FAILURE(rc))
8679 return rc;
8680
8681 /*
8682 * Register the info item.
8683 */
8684 char szTmp[128];
8685 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
8686 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
8687
8688 return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
8689}
8690
8691/**
8692 * The device registration structure.
8693 */
8694const PDMDEVREG g_DeviceAHCI =
8695{
8696 /* u32Version */
8697 PDM_DEVREG_VERSION,
8698 /* szName */
8699 "ahci",
8700 /* szRCMod */
8701 "VBoxDDRC.rc",
8702 /* szR0Mod */
8703 "VBoxDDR0.r0",
8704 /* pszDescription */
8705 "Intel AHCI controller.\n",
8706 /* fFlags */
8707 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
8708 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
8709 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
8710 /* fClass */
8711 PDM_DEVREG_CLASS_STORAGE,
8712 /* cMaxInstances */
8713 ~0U,
8714 /* cbInstance */
8715 sizeof(AHCI),
8716 /* pfnConstruct */
8717 ahciR3Construct,
8718 /* pfnDestruct */
8719 ahciR3Destruct,
8720 /* pfnRelocate */
8721 ahciR3Relocate,
8722 /* pfnMemSetup */
8723 NULL,
8724 /* pfnPowerOn */
8725 NULL,
8726 /* pfnReset */
8727 ahciR3Reset,
8728 /* pfnSuspend */
8729 ahciR3Suspend,
8730 /* pfnResume */
8731 ahciR3Resume,
8732 /* pfnAttach */
8733 ahciR3Attach,
8734 /* pfnDetach */
8735 ahciR3Detach,
8736 /* pfnQueryInterface. */
8737 NULL,
8738 /* pfnInitComplete */
8739 NULL,
8740 /* pfnPowerOff */
8741 ahciR3PowerOff,
8742 /* pfnSoftReset */
8743 NULL,
8744 /* u32VersionEnd */
8745 PDM_DEVREG_VERSION
8746};
8747
8748#endif /* IN_RING3 */
8749#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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