VirtualBox

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

Last change on this file since 42401 was 42393, checked in by vboxsync, 13 years ago

AHCI: Post a PIO setup FIS for PIO data commands

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