VirtualBox

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

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

AHCI: Clear SActive register when the command list engine is stopped. Might fix some HSM violation error messages during error recovery with Linux guests

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