VirtualBox

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

Last change on this file since 55705 was 54960, checked in by vboxsync, 10 years ago

DevAHCI/DevATA: Typo to make some compilers happy. No change in generated code. Thank you Jung-uk Kim.

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

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