VirtualBox

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

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

Add new flag to notify devices during a reset first to make sure there is no I/O pending (see #6434)

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