VirtualBox

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

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

oops

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