VirtualBox

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

Last change on this file since 42198 was 42198, checked in by vboxsync, 12 years ago

Devices/DevAHCI: indentation fixes.

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