VirtualBox

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

Last change on this file since 62956 was 62632, checked in by vboxsync, 8 years ago

Devices: unused parameter warnings.

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