VirtualBox

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

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

Storage/AHCI: Make sure all threads are idling before finishing the controller reset, don't process garbage FIS structures

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