VirtualBox

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

Last change on this file since 63767 was 63690, checked in by vboxsync, 8 years ago

PCI,Devices: Changed range size in FNPCIIOREGIONMAP from uint32_t to RTGCPHYS.

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