VirtualBox

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

最後變更 在這個檔案從36663是 36383,由 vboxsync 提交於 14 年 前

AHCI+ATAController: Port r70670 + r70674 (Signal no current profile if no medium is loaded and add mandatory features to the GET CONFIGURATION reply)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette