VirtualBox

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

Last change on this file since 60404 was 59252, checked in by vboxsync, 8 years ago

pdmifs.h: Move the storage related interfaces (PDMIMEDIA, PDMIMOUNT, PDMISCSICONNECTOR, etc.) into a separate header to reduce the overall size of the header a bit

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

© 2023 Oracle
ContactPrivacy policyTerms of Use