VirtualBox

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

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

AHCI: Long overdue code cleanup, removes over 800 lines of unused or duplicated code and unifies the code path between async and non aasync I/O where possible

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