VirtualBox

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

Last change on this file since 51342 was 51342, checked in by vboxsync, 11 years ago

Main,DrvVD: Interface to pass the keys to the disk encryption module from Main

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