VirtualBox

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

Last change on this file since 34142 was 34142, checked in by vboxsync, 14 years ago

AHCI: Better fix for r67808. Don't ignore the return values for R3 usage and use better status code for rcBusy

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

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