VirtualBox

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

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

Storage/AHCI: Clear interrupt line on reset

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