VirtualBox

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

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

Update PDMDEVREG initialization comment so they refer to pfnMemSetup instead of pfnIOCtl.

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