VirtualBox

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

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

Storage/DevAHCI: Remvove complete dependency on ATAController.

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