VirtualBox

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

Last change on this file since 21910 was 21910, checked in by vboxsync, 15 years ago

AHCI: Remove flags indicating hotplug support. We don't support that yet.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 259.0 KB
Line 
1/* $Id: DevAHCI.cpp 21910 2009-07-31 10:08:02Z vboxsync $ */
2/** @file
3 *
4 * VBox storage devices:
5 * AHCI controller device (disk).
6 * Implements the AHCI standard 1.1
7 */
8
9/*
10 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
26 *
27 * This component implements an AHCI SATA controller.
28 * The device is split into two parts. The first part implements the
29 * register interface for the guest and the second one does the data transfer.
30 *
31 * The guest can access the controller in two ways. The first one is the native
32 * way implementing the registers described in the AHCI specification and is
33 * the preferred one.
34 * The second implements the I/O ports used for booting from the hard disk
35 * and for guests which don't have an AHCI SATA driver.
36 *
37 * The data is transfered in an asychronous way using one thread per implemented
38 * port or using the new async completion interface which is still under development.
39 *
40 */
41
42/*******************************************************************************
43* Header Files *
44*******************************************************************************/
45//#define DEBUG
46#define LOG_GROUP LOG_GROUP_DEV_AHCI
47#include <VBox/pdmdev.h>
48#include <VBox/pdmqueue.h>
49#include <VBox/pdmthread.h>
50#include <VBox/pdmcritsect.h>
51#include <VBox/scsi.h>
52#include <iprt/assert.h>
53#include <iprt/asm.h>
54#include <iprt/string.h>
55#ifdef IN_RING3
56# include <iprt/param.h>
57# include <iprt/thread.h>
58# include <iprt/semaphore.h>
59# include <iprt/alloc.h>
60# include <iprt/uuid.h>
61# include <iprt/time.h>
62#endif
63
64#include "ide.h"
65#include "ATAController.h"
66#include "../Builtins.h"
67
68#define AHCI_MAX_NR_PORTS_IMPL 30
69#define AHCI_NR_COMMAND_SLOTS 32
70#define AHCI_SAVED_STATE_VERSION 2
71#define AHCI_NR_OF_ALLOWED_BIGGER_LISTS 100
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
101/* Command Header. */
102typedef struct
103{
104 /** Description Information. */
105 uint32_t u32DescInf;
106 /** Command status. */
107 uint32_t u32PRDBC;
108 /** Command Table Base Address. */
109 uint32_t u32CmdTblAddr;
110 /** Command Table Base Address - upper 32-bits. */
111 uint32_t u32CmdTblAddrUp;
112 /** Reserved */
113 uint32_t u32Reserved[4];
114} CmdHdr;
115AssertCompileSize(CmdHdr, 32);
116
117/* Defines for the command header. */
118#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
119#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
120#define AHCI_CMDHDR_C RT_BIT(10)
121#define AHCI_CMDHDR_B RT_BIT(9)
122#define AHCI_CMDHDR_R RT_BIT(8)
123#define AHCI_CMDHDR_P RT_BIT(7)
124#define AHCI_CMDHDR_W RT_BIT(6)
125#define AHCI_CMDHDR_A RT_BIT(5)
126#define AHCI_CMDHDR_CFL_MASK 0x1f
127
128#define AHCI_CMDHDR_PRDT_OFFSET 0x80
129#define AHCI_CMDHDR_ACMD_OFFSET 0x40
130
131/* Defines for the command FIS. */
132/* Defines that are used in the first double word. */
133#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
134# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
135# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
136# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
137# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
138# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
139# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
140# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
141# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
142# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
143# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
144# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
145# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
146# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
147
148#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
149#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
150#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
151
152#define AHCI_CMDFIS_CMD 2
153#define AHCI_CMDFIS_FET 3
154
155#define AHCI_CMDFIS_SECTN 4
156#define AHCI_CMDFIS_CYLL 5
157#define AHCI_CMDFIS_CYLH 6
158#define AHCI_CMDFIS_HEAD 7
159
160#define AHCI_CMDFIS_SECTNEXP 8
161#define AHCI_CMDFIS_CYLLEXP 9
162#define AHCI_CMDFIS_CYLHEXP 10
163#define AHCI_CMDFIS_FETEXP 11
164
165#define AHCI_CMDFIS_SECTC 12
166#define AHCI_CMDFIS_SECTCEXP 13
167#define AHCI_CMDFIS_CTL 15
168# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
169# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
170
171/* For D2H FIS */
172#define AHCI_CMDFIS_STS 2
173#define AHCI_CMDFIS_ERR 3
174
175/**
176 * Scatter gather list entry data.
177 */
178typedef struct AHCIPORTTASKSTATESGENTRY
179{
180 /** Flag whether the buffer in the list is from the guest or an
181 * allocated temporary buffer because the segments in the guest
182 * are not sector aligned.
183 */
184 bool fGuestMemory;
185 /** Flag dependent data. */
186 union
187 {
188 /** Data to handle direct mappings of guest buffers. */
189 struct
190 {
191 /** The page lock. */
192 PGMPAGEMAPLOCK PageLock;
193 } direct;
194 /** Data to handle temporary buffers. */
195 struct
196 {
197 /** The first segment in the guest which is not sector aligned. */
198 RTGCPHYS GCPhysAddrBaseFirstUnaligned;
199 /** Number of unaligned buffers in the guest. */
200 uint32_t cUnaligned;
201 /** Pointer to the start of the buffer. */
202 void *pvBuf;
203 } temp;
204 } u;
205} AHCIPORTTASKSTATESGENTRY, *PAHCIPORTTASKSTATESGENTRY;
206
207/** Pointer to a pointer of a scatter gather list entry. */
208typedef PAHCIPORTTASKSTATESGENTRY *PPAHCIPORTTASKSTATESGENTRY;
209
210/**
211 * A task state.
212 */
213typedef struct AHCIPORTTASKSTATE
214{
215 /** Tag of the task. */
216 uint32_t uTag;
217 /** Command is queued. */
218 bool fQueued;
219 /** The command header for this task. */
220 CmdHdr cmdHdr;
221 /** The command Fis for this task. */
222 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
223 /** The ATAPI comnmand data. */
224 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
225 /** Physical address of the command header. - GC */
226 RTGCPHYS GCPhysCmdHdrAddr;
227 /** Data direction. */
228 uint8_t uTxDir;
229 /** Start offset. */
230 uint64_t uOffset;
231 /** Number of bytes to transfer. */
232 uint32_t cbTransfer;
233 /** ATA error register */
234 uint8_t uATARegError;
235 /** ATA status register */
236 uint8_t uATARegStatus;
237 /** Number of scatter gather list entries. */
238 uint32_t cSGEntries;
239 /** How many entries would fit into the sg list. */
240 uint32_t cSGListSize;
241 /** Pointer to the first entry of the scatter gather list. */
242 PPDMDATASEG pSGListHead;
243 /** Pointer to the first mapping information entry. */
244 PAHCIPORTTASKSTATESGENTRY paSGEntries;
245 /** Size of the temporary buffer for unaligned guest segments. */
246 uint32_t cbBufferUnaligned;
247 /** Pointer to the temporary buffer. */
248 void *pvBufferUnaligned;
249 /** Number of times in a row the scatter gather list was too big. */
250 uint32_t cSGListTooBig;
251} AHCIPORTTASKSTATE, *PAHCIPORTTASKSTATE;
252
253/**
254 * Notifier queue item.
255 */
256typedef struct DEVPORTNOTIFIERQUEUEITEM
257{
258 /** The core part owned by the queue manager. */
259 PDMQUEUEITEMCORE Core;
260 /** On which port the async io thread should be put into action. */
261 uint8_t iPort;
262 /** Which task to process. */
263 uint8_t iTask;
264 /** Flag whether the task is queued. */
265 uint8_t fQueued;
266} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
267
268typedef struct AHCIPort
269{
270 /** Pointer to the device instance - HC ptr */
271 PPDMDEVINSR3 pDevInsR3;
272 /** Pointer to the device instance - R0 ptr */
273 PPDMDEVINSR0 pDevInsR0;
274 /** Pointer to the device instance - RC ptr. */
275 PPDMDEVINSRC pDevInsRC;
276
277#if HC_ARCH_BITS == 64
278 uint32_t Alignment0;
279#endif
280
281 /** Pointer to the parent AHCI structure - R3 ptr. */
282 R3PTRTYPE(struct AHCI *) pAhciR3;
283 /** Pointer to the parent AHCI structure - R0 ptr. */
284 R0PTRTYPE(struct AHCI *) pAhciR0;
285 /** Pointer to the parent AHCI structure - RC ptr. */
286 RCPTRTYPE(struct AHCI *) pAhciRC;
287 /** Command List Base Address. */
288 uint32_t regCLB;
289 /** Command List Base Address upper bits. */
290 uint32_t regCLBU;
291 /** FIS Base Address. */
292 uint32_t regFB;
293 /** FIS Base Address upper bits. */
294 uint32_t regFBU;
295 /** Interrupt Status. */
296 volatile uint32_t regIS;
297 /** Interrupt Enable. */
298 uint32_t regIE;
299 /** Command. */
300 uint32_t regCMD;
301 /** Task File Data. */
302 uint32_t regTFD;
303 /** Signature */
304 uint32_t regSIG;
305 /** Serial ATA Status. */
306 uint32_t regSSTS;
307 /** Serial ATA Control. */
308 uint32_t regSCTL;
309 /** Serial ATA Error. */
310 uint32_t regSERR;
311 /** Serial ATA Active. */
312 uint32_t regSACT;
313 /** Command Issue. */
314 uint32_t regCI;
315
316#if HC_ARCH_BITS == 64
317 uint32_t Alignment1;
318#endif
319
320 /** Command List Base Address */
321 volatile RTGCPHYS GCPhysAddrClb;
322 /** FIS Base Address */
323 volatile RTGCPHYS GCPhysAddrFb;
324
325 /** If we use the new async interface. */
326 bool fAsyncInterface;
327
328#if HC_ARCH_BITS == 64
329 uint32_t Alignment2;
330#endif
331
332 /** Async IO Thread. */
333 PPDMTHREAD pAsyncIOThread;
334 /** Request semaphore. */
335 RTSEMEVENT AsyncIORequestSem;
336
337 /** Task queue. */
338 volatile uint8_t ahciIOTasks[2*AHCI_NR_COMMAND_SLOTS];
339 /** Actual write position. */
340 uint8_t uActWritePos;
341 /** Actual read position. */
342 uint8_t uActReadPos;
343 /** Actual number of active tasks. */
344 volatile uint32_t uActTasksActive;
345
346 /** Device is powered on. */
347 bool fPoweredOn;
348 /** Device has spun up. */
349 bool fSpunUp;
350 /** First D2H FIS was send. */
351 bool fFirstD2HFisSend;
352 /** Attached device is a CD/DVD drive. */
353 bool fATAPI;
354
355#if HC_ARCH_BITS == 64
356 uint32_t Alignment3;
357#endif
358
359 /** Device specific settings. */
360 /** Pointer to the attached driver's base interface. */
361 R3PTRTYPE(PPDMIBASE) pDrvBase;
362 /** Pointer to the attached driver's block interface. */
363 R3PTRTYPE(PPDMIBLOCK) pDrvBlock;
364 /** Pointer to the attached driver's async block interface. */
365 R3PTRTYPE(PPDMIBLOCKASYNC) pDrvBlockAsync;
366 /** Pointer to the attached driver's block bios interface. */
367 R3PTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
368 /** Pointer to the attached driver's mount interface. */
369 R3PTRTYPE(PPDMIMOUNT) pDrvMount;
370 /** The base interface. */
371 PDMIBASE IBase;
372 /** The block port interface. */
373 PDMIBLOCKPORT IPort;
374 /** The optional block async port interface. */
375 PDMIBLOCKASYNCPORT IPortAsync;
376 /** The mount notify interface. */
377 PDMIMOUNTNOTIFY IMountNotify;
378 /** Physical geometry of this image. */
379 PDMMEDIAGEOMETRY PCHSGeometry;
380 /** The status LED state for this drive. */
381 PDMLED Led;
382
383#if HC_ARCH_BITS == 64
384 uint32_t Alignment4;
385#endif
386
387 /** Number of total sectors. */
388 uint64_t cTotalSectors;
389 /** Currently configured number of sectors in a multi-sector transfer. */
390 uint32_t cMultSectors;
391 /** Currently active transfer mode (MDMA/UDMA) and speed. */
392 uint8_t uATATransferMode;
393 /** ATAPI sense key. */
394 uint8_t uATAPISenseKey;
395 /** ATAPI additional sens code. */
396 uint8_t uATAPIASC;
397 /** HACK: Countdown till we report a newly unmounted drive as mounted. */
398 uint8_t cNotifiedMediaChange;
399
400 /** The LUN. */
401 RTUINT iLUN;
402 /** Flag if we are in a device reset. */
403 bool fResetDevice;
404
405 /** Bitmask for finished tasks. */
406 volatile uint32_t u32TasksFinished;
407 /** Bitmask for finished queued tasks. */
408 volatile uint32_t u32QueuedTasksFinished;
409
410 /**
411 * Array of cached tasks. The tag number is the index value.
412 * Only used with the async interface.
413 */
414 R3PTRTYPE(PAHCIPORTTASKSTATE) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
415
416 /** Release statistics: number of DMA commands. */
417 STAMCOUNTER StatDMA;
418 /** Release statistics: number of bytes written. */
419 STAMCOUNTER StatBytesWritten;
420 /** Release statistics: number of bytes read. */
421 STAMCOUNTER StatBytesRead;
422 /** Release statistics: Number of I/O requests processed per second. */
423 STAMCOUNTER StatIORequestsPerSecond;
424#ifdef VBOX_WITH_STATISTICS
425 /** Statistics: Time to complete one request. */
426 STAMPROFILE StatProfileProcessTime;
427 /** Statistics: Time to map requests into R3. */
428 STAMPROFILE StatProfileMapIntoR3;
429 /** Statistics: Amount of time to read/write data. */
430 STAMPROFILE StatProfileReadWrite;
431 /** Statistics: Amount of time to destroy a list. */
432 STAMPROFILE StatProfileDestroyScatterGatherList;
433#endif /* VBOX_WITH_STATISTICS */
434 /** Flag whether a notification was already send to R3. */
435 volatile bool fNotificationSend;
436 /** Flag whether this port is in a reset state. */
437 volatile bool fPortReset;
438 /** Flag whether the I/O thread idles. */
439 volatile bool fAsyncIOThreadIdle;
440
441 /** The serial numnber to use for IDENTIFY DEVICE commands. */
442 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
443 /** The firmware revision to use for IDENTIFY DEVICE commands. */
444 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
445 /** The model number to use for IDENTIFY DEVICE commands. */
446 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
447
448#if HC_ARCH_BITS == 64
449 uint32_t Alignment5;
450#endif
451
452} AHCIPort, *PAHCIPort;
453
454/*
455 * Main AHCI device state.
456 */
457typedef struct AHCI
458{
459 /** The PCI device structure. */
460 PCIDEVICE dev;
461 /** Pointer to the device instance - R3 ptr */
462 PPDMDEVINSR3 pDevInsR3;
463 /** Pointer to the device instance - R0 ptr */
464 PPDMDEVINSR0 pDevInsR0;
465 /** Pointer to the device instance - RC ptr. */
466 PPDMDEVINSRC pDevInsRC;
467
468#if HC_ARCH_BITS == 64
469 uint32_t Alignment0;
470#endif
471
472 /** The base interface */
473 PDMIBASE IBase;
474 /** Status Port - Leds interface. */
475 PDMILEDPORTS ILeds;
476 /** Partner of ILeds. */
477 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
478
479#if HC_ARCH_BITS == 64
480 uint32_t Alignment1[2];
481#endif
482
483 /** Base address of the MMIO region. */
484 RTGCPHYS MMIOBase;
485
486 /** Global Host Control register of the HBA */
487
488 /** HBA Capabilities - Readonly */
489 uint32_t regHbaCap;
490 /** HBA Control */
491 uint32_t regHbaCtrl;
492 /** Interrupt Status */
493 uint32_t regHbaIs;
494 /** Ports Implemented - Readonly */
495 uint32_t regHbaPi;
496 /** AHCI Version - Readonly */
497 uint32_t regHbaVs;
498 /** Command completion coalescing control */
499 uint32_t regHbaCccCtl;
500 /** Command completion coalescing ports */
501 uint32_t regHbaCccPorts;
502
503#if HC_ARCH_BITS == 64
504 uint32_t Alignment3;
505#endif
506
507 /** Countdown timer for command completion coalescing - R3 ptr */
508 PTMTIMERR3 pHbaCccTimerR3;
509 /** Countdown timer for command completion coalescing - R0 ptr */
510 PTMTIMERR0 pHbaCccTimerR0;
511 /** Countdown timer for command completion coalescing - RC ptr */
512 PTMTIMERRC pHbaCccTimerRC;
513
514#if HC_ARCH_BITS == 64
515 uint32_t Alignment4;
516#endif
517
518 /** Queue to send tasks to R3. - HC ptr */
519 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
520 /** Queue to send tasks to R3. - HC ptr */
521 R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
522 /** Queue to send tasks to R3. - RC ptr */
523 RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
524
525#if HC_ARCH_BITS == 64
526 uint32_t Alignment5;
527#endif
528
529
530 /** Which port number is used to mark an CCC interrupt */
531 uint8_t uCccPortNr;
532
533#if HC_ARCH_BITS == 64
534 uint32_t Alignment6;
535#endif
536
537 /** Timeout value */
538 uint64_t uCccTimeout;
539 /** Number of completions used to assert an interrupt */
540 uint32_t uCccNr;
541 /** Current number of completed commands */
542 uint32_t uCccCurrentNr;
543
544 /** Register structure per port */
545 AHCIPort ahciPort[AHCI_MAX_NR_PORTS_IMPL];
546
547 /** Needed values for the emulated ide channels. */
548 AHCIATACONTROLLER aCts[2];
549
550 /** Bitmask of ports which asserted an interrupt. */
551 uint32_t u32PortsInterrupted;
552 /** Device is in a reset state. */
553 bool fReset;
554 /** Supports 64bit addressing */
555 bool f64BitAddr;
556 /** GC enabled. */
557 bool fGCEnabled;
558 /** R0 enabled. */
559 bool fR0Enabled;
560 /** If the new async interface is used if available. */
561 bool fUseAsyncInterfaceIfAvailable;
562 /** The critical section. */
563 PDMCRITSECT lock;
564
565 /** Number of usable ports on this controller. */
566 uint32_t cPortsImpl;
567
568#if HC_ARCH_BITS == 64
569 uint32_t Alignment7;
570#endif
571
572 /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
573 volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
574 /** At which number of I/O requests per second we consider having high I/O load. */
575 uint32_t cHighIOThreshold;
576 /** How many milliseconds to sleep. */
577 uint32_t cMillisToSleep;
578
579} AHCI, *PAHCI;
580
581/* Scatter gather list entry. */
582typedef struct
583{
584 /** Data Base Address. */
585 uint32_t u32DBA;
586 /** Data Base Address - Upper 32-bits. */
587 uint32_t u32DBAUp;
588 /** Reserved */
589 uint32_t u32Reserved;
590 /** Description information. */
591 uint32_t u32DescInf;
592} SGLEntry;
593AssertCompileSize(SGLEntry, 16);
594
595/** Defines for a scatter gather list entry. */
596#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
597#define SGLENTRY_DESCINF_I RT_BIT(31)
598#define SGLENTRY_DESCINF_DBC 0x3fffff
599#define SGLENTRY_DESCINF_READONLY 0x803fffff
600
601/* Defines for the global host control registers for the HBA. */
602
603#define AHCI_HBA_GLOBAL_SIZE 0x100
604
605/* Defines for the HBA Capabilities - Readonly */
606#define AHCI_HBA_CAP_S64A RT_BIT(31)
607#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
608#define AHCI_HBA_CAP_SIS RT_BIT(28)
609#define AHCI_HBA_CAP_SSS RT_BIT(27)
610#define AHCI_HBA_CAP_SALP RT_BIT(26)
611#define AHCI_HBA_CAP_SAL RT_BIT(25)
612#define AHCI_HBA_CAP_SCLO RT_BIT(24)
613#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
614# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
615# define AHCI_HBA_CAP_ISS_GEN1 RT_BIT(0)
616# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
617#define AHCI_HBA_CAP_SNZO RT_BIT(19)
618#define AHCI_HBA_CAP_SAM RT_BIT(18)
619#define AHCI_HBA_CAP_SPM RT_BIT(17)
620#define AHCI_HBA_CAP_PMD RT_BIT(15)
621#define AHCI_HBA_CAP_SSC RT_BIT(14)
622#define AHCI_HBA_CAP_PSC RT_BIT(13)
623#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
624#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
625#define AHCI_HBA_CAP_CCCS RT_BIT(7)
626#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
627#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
628
629/* Defines for the HBA Control register - Read/Write */
630#define AHCI_HBA_CTRL_AE RT_BIT(31)
631#define AHCI_HBA_CTRL_IE RT_BIT(1)
632#define AHCI_HBA_CTRL_HR RT_BIT(0)
633#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
634
635/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
636#define AHCI_HBA_VS_MJR (1 << 16)
637#define AHCI_HBA_VS_MNR 0x100
638
639/* Defines for the command completion coalescing control register */
640#define AHCI_HBA_CCC_CTL_TV 0xffff0000
641#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
642#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
643
644#define AHCI_HBA_CCC_CTL_CC 0xff00
645#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
646#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
647
648#define AHCI_HBA_CCC_CTL_INT 0xf8
649#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
650#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
651
652#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
653
654/* Defines for the port registers. */
655
656#define AHCI_PORT_REGISTER_SIZE 0x80
657
658#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
659
660#define AHCI_PORT_FB_RESERVED 0x7fffff00 /* For masking out the reserved bits. */
661
662#define AHCI_PORT_IS_CPDS RT_BIT(31)
663#define AHCI_PORT_IS_TFES RT_BIT(30)
664#define AHCI_PORT_IS_HBFS RT_BIT(29)
665#define AHCI_PORT_IS_HBDS RT_BIT(28)
666#define AHCI_PORT_IS_IFS RT_BIT(27)
667#define AHCI_PORT_IS_INFS RT_BIT(26)
668#define AHCI_PORT_IS_OFS RT_BIT(24)
669#define AHCI_PORT_IS_IPMS RT_BIT(23)
670#define AHCI_PORT_IS_PRCS RT_BIT(22)
671#define AHCI_PORT_IS_DIS RT_BIT(7)
672#define AHCI_PORT_IS_PCS RT_BIT(6)
673#define AHCI_PORT_IS_DPS RT_BIT(5)
674#define AHCI_PORT_IS_UFS RT_BIT(4)
675#define AHCI_PORT_IS_SDBS RT_BIT(3)
676#define AHCI_PORT_IS_DSS RT_BIT(2)
677#define AHCI_PORT_IS_PSS RT_BIT(1)
678#define AHCI_PORT_IS_DHRS RT_BIT(0)
679#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
680
681#define AHCI_PORT_IE_CPDE RT_BIT(31)
682#define AHCI_PORT_IE_TFEE RT_BIT(30)
683#define AHCI_PORT_IE_HBFE RT_BIT(29)
684#define AHCI_PORT_IE_HBDE RT_BIT(28)
685#define AHCI_PORT_IE_IFE RT_BIT(27)
686#define AHCI_PORT_IE_INFE RT_BIT(26)
687#define AHCI_PORT_IE_OFE RT_BIT(24)
688#define AHCI_PORT_IE_IPME RT_BIT(23)
689#define AHCI_PORT_IE_PRCE RT_BIT(22)
690#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
691#define AHCI_PORT_IE_PCE RT_BIT(6)
692#define AHCI_PORT_IE_DPE RT_BIT(5)
693#define AHCI_PORT_IE_UFE RT_BIT(4)
694#define AHCI_PORT_IE_SDBE RT_BIT(3)
695#define AHCI_PORT_IE_DSE RT_BIT(2)
696#define AHCI_PORT_IE_PSE RT_BIT(1)
697#define AHCI_PORT_IE_DHRE RT_BIT(0)
698#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
699
700#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
701#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
702# define AHCI_PORT_CMD_ICC_IDLE 0x0
703# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
704# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
705# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
706#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
707#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
708#define AHCI_PORT_CMD_DLAE RT_BIT(25)
709#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
710#define AHCI_PORT_CMD_CPD RT_BIT(20)
711#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
712#define AHCI_PORT_CMD_HPCP RT_BIT(18)
713#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
714#define AHCI_PORT_CMD_CPS RT_BIT(16)
715#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
716#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
717#define AHCI_PORT_CMD_ISS RT_BIT(13) /* Readonly */
718#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
719#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
720#define AHCI_PORT_CMD_FRE RT_BIT(4)
721#define AHCI_PORT_CMD_CLO RT_BIT(3)
722#define AHCI_PORT_CMD_POD RT_BIT(2)
723#define AHCI_PORT_CMD_SUD RT_BIT(1)
724#define AHCI_PORT_CMD_ST RT_BIT(0)
725#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
726
727#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
728#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
729#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
730#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
731#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
732#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
733#define AHCI_PORT_SCTL_DET_NINIT 0
734#define AHCI_PORT_SCTL_DET_INIT 1
735#define AHCI_PORT_SCTL_DET_OFFLINE 4
736#define AHCI_PORT_SCTL_READONLY 0xfff
737
738#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
739#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
740#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
741#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
742#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
743#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
744
745#define AHCI_PORT_TFD_BSY RT_BIT(7)
746#define AHCI_PORT_TFD_DRQ RT_BIT(3)
747#define AHCI_PORT_TFD_ERR RT_BIT(0)
748
749#define AHCI_PORT_SERR_X RT_BIT(26)
750#define AHCI_PORT_SERR_W RT_BIT(18)
751#define AHCI_PORT_SERR_N RT_BIT(16)
752
753/* Signatures for attached storage devices. */
754#define AHCI_PORT_SIG_DISK 0x00000101
755#define AHCI_PORT_SIG_ATAPI 0xeb140101
756
757/*
758 * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
759 * regFB points to the base of this area.
760 * Every FIS type has an offset where it is posted in this area.
761 */
762#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
763#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
764#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
765#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
766#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
767
768#define AHCI_TASK_IS_QUEUED(x) ((x) & 0x1)
769#define AHCI_TASK_GET_TAG(x) ((x) >> 1)
770#define AHCI_TASK_SET(tag, queued) (((tag) << 1) | (queued))
771
772/**
773 * AHCI register operator.
774 */
775typedef struct ahci_opreg
776{
777 const char *pszName;
778 int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
779 int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
780} AHCIOPREG;
781
782/**
783 * AHCI port register operator.
784 */
785typedef struct pAhciPort_opreg
786{
787 const char *pszName;
788 int (*pfnRead )(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
789 int (*pfnWrite)(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
790} AHCIPORTOPREG;
791
792#ifndef VBOX_DEVICE_STRUCT_TESTCASE
793RT_C_DECLS_BEGIN
794PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
795PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
796static void ahciHBAReset(PAHCI pThis);
797PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
798PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
799PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
800PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
801PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
802PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
803#ifdef IN_RING3
804static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
805static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
806static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf);
807static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly);
808static int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
809static void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
810static void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
811#endif
812RT_C_DECLS_END
813
814#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
815#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
816#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
817#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
818#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
819#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
820
821#if 1
822#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
823#else
824#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)(Lo) )
825#endif
826
827#ifdef IN_RING3
828
829# ifdef LOG_USE_C99
830# define ahciLog(a) \
831 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
832# else
833# define ahciLog(a) \
834 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
835# endif
836
837#elif IN_RING0
838
839# ifdef LOG_USE_C99
840# define ahciLog(a) \
841 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
842# else
843# define ahciLog(a) \
844 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
845# endif
846
847#elif IN_RC
848
849# ifdef LOG_USE_C99
850# define ahciLog(a) \
851 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
852# else
853# define ahciLog(a) \
854 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
855# endif
856
857#endif
858
859/**
860 * Update PCI IRQ levels
861 */
862static void ahciHbaClearInterrupt(PAHCI pAhci)
863{
864 Log(("%s: Clearing interrupt\n", __FUNCTION__));
865 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 0);
866}
867
868/**
869 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
870 */
871static void ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort)
872{
873 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
874
875 PDMCritSectEnter(&pAhci->lock, VINF_SUCCESS);
876
877 if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
878 {
879 if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
880 {
881 pAhci->uCccCurrentNr++;
882 if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
883 {
884 /* Reset command completion coalescing state. */
885 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
886 pAhci->uCccCurrentNr = 0;
887
888 pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
889 if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
890 {
891 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
892 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
893 }
894 }
895 }
896 else
897 {
898 /* If only the bit of the actual port is set assert an interrupt
899 * because the interrupt status register was already read by the guest
900 * and we need to send a new notification.
901 * Otherwise an interrupt is still pending.
902 */
903 ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
904 if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
905 {
906 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
907 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
908 }
909 }
910 }
911
912 PDMCritSectLeave(&pAhci->lock);
913}
914
915#ifdef IN_RING3
916/*
917 * Assert irq when an CCC timeout occurs
918 */
919DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
920{
921 PAHCI pAhci = (PAHCI)pvUser;
922
923 ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr);
924}
925#endif
926
927static int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
928{
929 uint32_t uCIValue;
930
931 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
932
933 /* Update the CI register first. */
934 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
935 pAhciPort->regCI &= ~uCIValue;
936
937
938 if ((pAhciPort->regCMD & AHCI_PORT_CMD_ST) && (u32Value > 0))
939 {
940 PDEVPORTNOTIFIERQUEUEITEM pItem;
941
942 /* Mark the tasks set in the value as used. */
943 for (uint8_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
944 {
945 /* Queue task if bit is set in written value and not already in progress. */
946 if (((u32Value >> i) & 0x01) && !(pAhciPort->regCI & (1 << i)))
947 {
948 if (!pAhciPort->fAsyncInterface)
949 {
950 /* Put the tag number of the task into the FIFO. */
951 uint8_t uTag = AHCI_TASK_SET(i, ((pAhciPort->regSACT & (1 << i)) ? 1 : 0));
952 ASMAtomicWriteU8(&pAhciPort->ahciIOTasks[pAhciPort->uActWritePos], uTag);
953 ahciLog(("%s: Before uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
954 pAhciPort->uActWritePos++;
955 pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
956 ahciLog(("%s: After uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
957
958 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
959
960 bool fNotificationSend = ASMAtomicXchgBool(&pAhciPort->fNotificationSend, true);
961 if (!fNotificationSend)
962 {
963 /* Send new notification. */
964 pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
965 AssertMsg(pItem, ("Allocating item for queue failed\n"));
966
967 pItem->iPort = pAhciPort->iLUN;
968 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
969 }
970 }
971 else
972 {
973 pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
974 AssertMsg(pItem, ("Allocating item for queue failed\n"));
975
976 pItem->iPort = pAhciPort->iLUN;
977 pItem->iTask = i;
978 pItem->fQueued = !!(pAhciPort->regSACT & (1 << i)); /* Mark if the task is queued. */
979 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
980 }
981 }
982 }
983 }
984
985 pAhciPort->regCI |= u32Value;
986
987 return VINF_SUCCESS;
988}
989
990static int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
991{
992 uint32_t uCIValue = 0;
993
994 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
995
996 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
997
998 pAhciPort->regCI &= ~uCIValue;
999
1000 *pu32Value = pAhciPort->regCI;
1001
1002 return VINF_SUCCESS;
1003}
1004
1005static int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1006{
1007 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1008
1009 pAhciPort->regSACT |= u32Value;
1010
1011 return VINF_SUCCESS;
1012}
1013
1014static int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1015{
1016 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1017
1018 pAhciPort->regSACT &= ~u32TasksFinished;
1019
1020 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1021 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1022
1023 *pu32Value = pAhciPort->regSACT;
1024
1025 return VINF_SUCCESS;
1026}
1027
1028static int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1029{
1030 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1031
1032 if ( (u32Value & AHCI_PORT_SERR_X)
1033 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1034 {
1035 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1036 pAhciPort->regTFD |= ATA_STAT_ERR;
1037 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1038 }
1039
1040 pAhciPort->regSERR &= ~u32Value;
1041
1042 return VINF_SUCCESS;
1043}
1044
1045static int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1046{
1047 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1048 *pu32Value = pAhciPort->regSERR;
1049 return VINF_SUCCESS;
1050}
1051
1052static int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1053{
1054 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1055 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1056 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1057
1058 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1059 {
1060 ASMAtomicXchgBool(&pAhciPort->fPortReset, true);
1061 pAhciPort->regSSTS = 0;
1062 pAhciPort->regSIG = ~0;
1063 pAhciPort->regTFD = 0x7f;
1064 pAhciPort->fFirstD2HFisSend = false;
1065 }
1066 else if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT && pAhciPort->pDrvBase &&
1067 (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1068 {
1069#ifndef IN_RING3
1070 return VINF_IOM_HC_MMIO_WRITE;
1071#else
1072 if (pAhciPort->pDrvBase)
1073 {
1074 /* Reset queue. */
1075 pAhciPort->uActWritePos = 0;
1076 pAhciPort->uActReadPos = 0;
1077 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1078
1079 /* Signature for SATA device. */
1080 if (pAhciPort->fATAPI)
1081 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1082 else
1083 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1084
1085 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1086 (0x03 << 0); /* Device detected and communication established. */
1087
1088 /*
1089 * Use the maximum allowed speed.
1090 * (Not that it changes anything really)
1091 */
1092 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1093 {
1094 case 0x01:
1095 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1096 break;
1097 case 0x02:
1098 case 0x00:
1099 default:
1100 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1101 break;
1102 }
1103
1104 /* We received a COMINIT from the device. Tell the guest. */
1105 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
1106 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1107 pAhciPort->regTFD |= ATA_STAT_BUSY;
1108
1109 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
1110 {
1111 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1112 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1113
1114 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1115 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
1116 }
1117 }
1118#endif
1119 }
1120
1121 pAhciPort->regSCTL = u32Value;
1122
1123 return VINF_SUCCESS;
1124}
1125
1126static int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1127{
1128 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1129 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1130 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1131 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1132
1133 *pu32Value = pAhciPort->regSCTL;
1134 return VINF_SUCCESS;
1135}
1136
1137static int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1138{
1139 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1140 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1141 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1142 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1143
1144 *pu32Value = pAhciPort->regSSTS;
1145 return VINF_SUCCESS;
1146}
1147
1148static int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1149{
1150 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1151 *pu32Value = pAhciPort->regSIG;
1152 return VINF_SUCCESS;
1153}
1154
1155static int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1156{
1157 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1158 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1159 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1160 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1161 *pu32Value = pAhciPort->regTFD;
1162 return VINF_SUCCESS;
1163}
1164
1165/**
1166 * Read from the port command register.
1167 */
1168static int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1169{
1170 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD));
1171 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",
1172 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1173 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1174 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1175 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1176 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1177 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1178 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, (pAhciPort->regCMD & AHCI_PORT_CMD_CCS) >> 8,
1179 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1180 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1181 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1182 *pu32Value = pAhciPort->regCMD;
1183 return VINF_SUCCESS;
1184}
1185
1186/**
1187 * Write to the port command register.
1188 * This is the register where all the data transfer is started
1189 */
1190static int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1191{
1192 int rc = VINF_SUCCESS;
1193 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1194 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",
1195 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1196 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1197 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1198 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1199 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1200 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1201 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1202 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1203 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1204 (u32Value & AHCI_PORT_CMD_ST)));
1205
1206 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1207 {
1208 if (u32Value & AHCI_PORT_CMD_CLO)
1209 {
1210 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1211 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1212 /* Clear the CLO bit. */
1213 u32Value &= ~(AHCI_PORT_CMD_CLO);
1214 }
1215
1216 if (u32Value & AHCI_PORT_CMD_ST)
1217 {
1218 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1219
1220 /** Set engine state to running. */
1221 u32Value |= AHCI_PORT_CMD_CR;
1222 }
1223 else
1224 {
1225 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1226 /* Clear command issue register. */
1227 pAhciPort->regCI = 0;
1228 /** Clear current command slot. */
1229 u32Value &= ~(AHCI_PORT_CMD_CCS_SHIFT(0xff));
1230 u32Value &= ~AHCI_PORT_CMD_CR;
1231 }
1232 }
1233 else if (pAhciPort->pDrvBase)
1234 {
1235 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1236 {
1237 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1238 pAhciPort->fPoweredOn = true;
1239
1240 /*
1241 * Set states in the Port Signature and SStatus registers.
1242 */
1243 pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
1244 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1245 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1246 (0x03 << 0); /* Device detected and communication established. */
1247
1248 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1249 {
1250#ifndef IN_RING3
1251 return VINF_IOM_HC_MMIO_WRITE;
1252#else
1253 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1254 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1255
1256 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1257 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
1258#endif
1259 }
1260 }
1261
1262 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1263 {
1264 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1265 pAhciPort->fSpunUp = true;
1266 }
1267 }
1268
1269 if (u32Value & AHCI_PORT_CMD_FRE)
1270 {
1271 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1272
1273 u32Value |= AHCI_PORT_CMD_FR;
1274
1275 /* Send the first D2H FIS only if it wasn't already send. */
1276 if (!pAhciPort->fFirstD2HFisSend)
1277 {
1278#ifndef IN_RING3
1279 return VINF_IOM_HC_MMIO_WRITE;
1280#else
1281 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1282 pAhciPort->fFirstD2HFisSend = true;
1283#endif
1284 }
1285 }
1286 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1287 {
1288 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1289 u32Value &= ~AHCI_PORT_CMD_FR;
1290 }
1291
1292 pAhciPort->regCMD = u32Value;
1293
1294 return rc;
1295}
1296
1297/**
1298 * Read from the port interrupt enable register.
1299 */
1300static int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1301{
1302 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1303 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",
1304 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1305 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1306 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1307 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1308 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1309 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1310 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1311 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1312 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1313 *pu32Value = pAhciPort->regIE;
1314 return VINF_SUCCESS;
1315}
1316
1317/**
1318 * Write to the port interrupt enable register.
1319 */
1320static int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1321{
1322 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1323 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",
1324 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1325 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1326 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1327 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1328 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1329 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1330 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1331 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1332 (u32Value & AHCI_PORT_IE_DHRE)));
1333
1334 pAhciPort->regIE = (u32Value & AHCI_PORT_IE_READONLY);
1335
1336 /* Check if some a interrupt status bit changed*/
1337 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1338
1339 if (pAhciPort->regIE & u32IntrStatus)
1340 ahciHbaSetInterrupt(ahci, pAhciPort->iLUN);
1341
1342 return VINF_SUCCESS;
1343}
1344
1345/**
1346 * Read from the port interrupt status register.
1347 */
1348static int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1349{
1350 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1351 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",
1352 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1353 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1354 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1355 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1356 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1357 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1358 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1359 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1360 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1361 *pu32Value = pAhciPort->regIS;
1362 return VINF_SUCCESS;
1363}
1364
1365/**
1366 * Write to the port interrupt status register.
1367 */
1368static int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1369{
1370 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1371 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1372
1373 return VINF_SUCCESS;
1374}
1375
1376/**
1377 * Read from the port FIS base address upper 32bit register.
1378 */
1379static int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1380{
1381 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1382 *pu32Value = pAhciPort->regFBU;
1383 return VINF_SUCCESS;
1384}
1385
1386/**
1387 * Write to the port FIS base address upper 32bit register.
1388 */
1389static int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1390{
1391 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1392
1393 pAhciPort->regFBU = u32Value;
1394 pAhciPort->GCPhysAddrFb |= ((RTGCPHYS)pAhciPort->regFBU) << 32;
1395
1396 return VINF_SUCCESS;
1397}
1398
1399/**
1400 * Read from the port FIS base address register.
1401 */
1402static int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1403{
1404 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1405 *pu32Value = pAhciPort->regFB;
1406 return VINF_SUCCESS;
1407}
1408
1409/**
1410 * Write to the port FIS base address register.
1411 */
1412static int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1413{
1414 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1415
1416 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1417 pAhciPort->GCPhysAddrFb |= pAhciPort->regFB;
1418
1419 return VINF_SUCCESS;
1420}
1421
1422/**
1423 * Write to the port command list base address upper 32bit register.
1424 */
1425static int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1426{
1427 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1428
1429 pAhciPort->regCLBU = u32Value;
1430 pAhciPort->GCPhysAddrClb |= ((RTGCPHYS)pAhciPort->regCLBU) << 32;
1431
1432 return VINF_SUCCESS;
1433}
1434
1435/**
1436 * Read from the port command list base address upper 32bit register.
1437 */
1438static int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1439{
1440 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1441 *pu32Value = pAhciPort->regCLBU;
1442 return VINF_SUCCESS;
1443}
1444
1445/**
1446 * Read from the port command list base address register.
1447 */
1448static int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1449{
1450 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1451 *pu32Value = pAhciPort->regCLB;
1452 return VINF_SUCCESS;
1453}
1454
1455/**
1456 * Write to the port command list base address register.
1457 */
1458static int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1459{
1460 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1461
1462 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1463 pAhciPort->GCPhysAddrClb |= pAhciPort->regCLB;
1464
1465 return VINF_SUCCESS;
1466}
1467
1468/**
1469 * Read from the global Version register.
1470 */
1471static int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1472{
1473 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
1474 *pu32Value = ahci->regHbaVs;
1475 return VINF_SUCCESS;
1476}
1477
1478/**
1479 * Read from the global Ports implemented register.
1480 */
1481static int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1482{
1483 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
1484 *pu32Value = ahci->regHbaPi;
1485 return VINF_SUCCESS;
1486}
1487
1488/**
1489 * Write to the global interrupt status register.
1490 */
1491static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1492{
1493 int rc;
1494 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1495
1496 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_MMIO_WRITE);
1497 if (rc != VINF_SUCCESS)
1498 return rc;
1499
1500 if (u32Value > 0)
1501 {
1502 /*
1503 * Clear the interrupt only if no port has signalled
1504 * an interrupt and the guest has cleared all set interrupt
1505 * notification bits.
1506 */
1507 bool fClear = true;
1508
1509 ahci->regHbaIs &= ~(u32Value);
1510
1511 fClear = (!ahci->u32PortsInterrupted) && (!ahci->regHbaIs);
1512 if (fClear)
1513 {
1514 unsigned i = 0;
1515
1516 /* Check if the cleared ports have a interrupt status bit set. */
1517 while (u32Value > 0)
1518 {
1519 if (u32Value & 0x01)
1520 {
1521 PAHCIPort pAhciPort = &ahci->ahciPort[i];
1522
1523 if (pAhciPort->regIE & pAhciPort->regIS)
1524 {
1525 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1526 ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
1527 fClear = false;
1528 break;
1529 }
1530 }
1531 u32Value = u32Value >> 1;
1532 i++;
1533 }
1534 }
1535
1536 if (fClear)
1537 ahciHbaClearInterrupt(ahci);
1538 else
1539 {
1540 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
1541 /*
1542 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1543 * line is still high.
1544 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1545 */
1546 PDMDevHlpPCISetIrqNoWait(ahci->CTX_SUFF(pDevIns), 0, 0);
1547 PDMDevHlpPCISetIrqNoWait(ahci->CTX_SUFF(pDevIns), 0, 1);
1548 }
1549 }
1550
1551 PDMCritSectLeave(&ahci->lock);
1552 return VINF_SUCCESS;
1553}
1554
1555/**
1556 * Read from the global interrupt status register.
1557 */
1558static int HbaInterruptStatus_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1559{
1560 uint32_t u32PortsInterrupted;
1561 int rc;
1562
1563 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_MMIO_READ);
1564 if (rc != VINF_SUCCESS)
1565 return rc;
1566
1567 u32PortsInterrupted = ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
1568
1569 PDMCritSectLeave(&ahci->lock);
1570 Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
1571
1572 ahci->regHbaIs |= u32PortsInterrupted;
1573
1574#ifdef LOG_ENABLED
1575 Log(("%s:", __FUNCTION__));
1576 unsigned i;
1577 for (i = 0; i < ahci->cPortsImpl; i++)
1578 {
1579 if ((ahci->regHbaIs >> i) & 0x01)
1580 Log((" P%d", i));
1581 }
1582 Log(("\n"));
1583#endif
1584
1585 *pu32Value = ahci->regHbaIs;
1586
1587 return VINF_SUCCESS;
1588}
1589
1590/**
1591 * Write to the global control register.
1592 */
1593static int HbaControl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1594{
1595 Log(("%s: write u32Value=%#010x\n"
1596 "%s: AE=%d IE=%d HR=%d\n",
1597 __FUNCTION__, u32Value,
1598 __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
1599 (u32Value & AHCI_HBA_CTRL_HR)));
1600
1601 ahci->regHbaCtrl = (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE;
1602 if (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)
1603 ahciHBAReset(ahci);
1604 return VINF_SUCCESS;
1605}
1606
1607/**
1608 * Read the global control register.
1609 */
1610static int HbaControl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1611{
1612 Log(("%s: read regHbaCtrl=%#010x\n"
1613 "%s: AE=%d IE=%d HR=%d\n",
1614 __FUNCTION__, ahci->regHbaCtrl,
1615 __FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
1616 (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)));
1617 *pu32Value = ahci->regHbaCtrl;
1618 return VINF_SUCCESS;
1619}
1620
1621/**
1622 * Read the global capabilities register.
1623 */
1624static int HbaCapabilities_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1625{
1626 Log(("%s: read regHbaCap=%#010x\n"
1627 "%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",
1628 __FUNCTION__, ahci->regHbaCap,
1629 __FUNCTION__, (ahci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (ahci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
1630 (ahci->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (ahci->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
1631 (ahci->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (ahci->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
1632 (ahci->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (ahci->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
1633 (ahci->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (ahci->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
1634 (ahci->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (ahci->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
1635 (ahci->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (ahci->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
1636 (ahci->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (ahci->regHbaCap & AHCI_HBA_CAP_NP)));
1637 *pu32Value = ahci->regHbaCap;
1638 return VINF_SUCCESS;
1639}
1640
1641/**
1642 * Write to the global command completion coalescing control register.
1643 */
1644static int HbaCccCtl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1645{
1646 Log(("%s: write u32Value=%#010x\n"
1647 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1648 __FUNCTION__, u32Value,
1649 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
1650 AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
1651
1652 ahci->regHbaCccCtl = u32Value;
1653 ahci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
1654 ahci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
1655 ahci->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
1656
1657 if (u32Value & AHCI_HBA_CCC_CTL_EN)
1658 {
1659 /* Arm the timer */
1660 TMTimerSetMillies(ahci->CTX_SUFF(pHbaCccTimer), ahci->uCccTimeout);
1661 }
1662 else
1663 {
1664 TMTimerStop(ahci->CTX_SUFF(pHbaCccTimer));
1665 }
1666
1667 return VINF_SUCCESS;
1668}
1669
1670/**
1671 * Read the global command completion coalescing control register.
1672 */
1673static int HbaCccCtl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1674{
1675 Log(("%s: read regHbaCccCtl=%#010x\n"
1676 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1677 __FUNCTION__, ahci->regHbaCccCtl,
1678 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(ahci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(ahci->regHbaCccCtl),
1679 AHCI_HBA_CCC_CTL_INT_GET(ahci->regHbaCccCtl), (ahci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
1680 *pu32Value = ahci->regHbaCccCtl;
1681 return VINF_SUCCESS;
1682}
1683
1684/**
1685 * Write to the global command completion coalescing ports register.
1686 */
1687static int HbaCccPorts_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1688{
1689 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1690
1691 ahci->regHbaCccPorts = u32Value;
1692
1693 return VINF_SUCCESS;
1694}
1695
1696/**
1697 * Read the global command completion coalescing ports register.
1698 */
1699static int HbaCccPorts_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1700{
1701 Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, ahci->regHbaCccPorts));
1702
1703#ifdef LOG_ENABLED
1704 Log(("%s:", __FUNCTION__));
1705 unsigned i;
1706 for (i = 0; i < ahci->cPortsImpl; i++)
1707 {
1708 if ((ahci->regHbaCccPorts >> i) & 0x01)
1709 Log((" P%d", i));
1710 }
1711 Log(("\n"));
1712#endif
1713
1714 *pu32Value = ahci->regHbaCccPorts;
1715 return VINF_SUCCESS;
1716}
1717
1718/**
1719 * Invalid write to global register
1720 */
1721static int HbaInvalid_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1722{
1723 Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1724 return VINF_SUCCESS;
1725}
1726
1727/**
1728 * Invalid Port write.
1729 */
1730static int PortInvalid_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1731{
1732 ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1733 return VINF_SUCCESS;
1734}
1735
1736/**
1737 * Invalid Port read.
1738 */
1739static int PortInvalid_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1740{
1741 ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
1742 return VINF_SUCCESS;
1743}
1744
1745/**
1746 * Register descriptor table for global HBA registers
1747 */
1748static const AHCIOPREG g_aOpRegs[] =
1749{
1750 {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
1751 {"HbaControl" , HbaControl_r, HbaControl_w},
1752 {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
1753 {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
1754 {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
1755 {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
1756 {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
1757};
1758
1759/**
1760 * Register descriptor table for port registers
1761 */
1762static const AHCIPORTOPREG g_aPortOpRegs[] =
1763{
1764 {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
1765 {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
1766 {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
1767 {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
1768 {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
1769 {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
1770 {"PortCmd", PortCmd_r, PortCmd_w},
1771 {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
1772 {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
1773 {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
1774 {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
1775 {"PortSControl", PortSControl_r, PortSControl_w},
1776 {"PortSError", PortSError_r, PortSError_w},
1777 {"PortSActive", PortSActive_r, PortSActive_w},
1778 {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
1779 {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
1780};
1781
1782/**
1783 * Reset initiated by system software for one port.
1784 *
1785 * @param pAhciPort The port to reset.
1786 */
1787static void ahciPortSwReset(PAHCIPort pAhciPort)
1788{
1789 pAhciPort->regIS = 0;
1790 pAhciPort->regIE = 0;
1791 pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
1792 AHCI_PORT_CMD_SUD | /* Device has spun up. */
1793 AHCI_PORT_CMD_POD; /* Port is powered on. */
1794 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
1795 pAhciPort->regSIG = ~0;
1796 pAhciPort->regSSTS = 0;
1797 pAhciPort->regSCTL = 0;
1798 pAhciPort->regSERR = 0;
1799 pAhciPort->regSACT = 0;
1800 pAhciPort->regCI = 0;
1801
1802 pAhciPort->fResetDevice = false;
1803 pAhciPort->fPoweredOn = true;
1804 pAhciPort->fSpunUp = true;
1805 pAhciPort->fNotificationSend = false;
1806 pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
1807 pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
1808
1809 pAhciPort->u32TasksFinished = 0;
1810 pAhciPort->u32QueuedTasksFinished = 0;
1811
1812 pAhciPort->uActWritePos = 0;
1813 pAhciPort->uActReadPos = 0;
1814 pAhciPort->uActTasksActive = 0;
1815
1816 if (pAhciPort->pDrvBase)
1817 {
1818 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
1819 /* We received a COMINIT signal */
1820 pAhciPort->regTFD |= ATA_STAT_BUSY;
1821
1822 if (pAhciPort->fPoweredOn)
1823 {
1824 /*
1825 * Set states in the Port Signature and SStatus registers.
1826 */
1827 pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
1828 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1829 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1830 (0x03 << 0); /* Device detected and communication established. */
1831 }
1832 }
1833}
1834
1835#ifdef IN_RING3
1836/**
1837 * Hardware reset used for machine power on and reset.
1838 *
1839 * @param pAhciport The port to reset.
1840 */
1841static void ahciPortHwReset(PAHCIPort pAhciPort)
1842{
1843 /* Reset the address registers. */
1844 pAhciPort->regCLB = 0;
1845 pAhciPort->regCLBU = 0;
1846 pAhciPort->regFB = 0;
1847 pAhciPort->regFBU = 0;
1848
1849 /* Reset calculated addresses. */
1850 pAhciPort->GCPhysAddrClb = 0;
1851 pAhciPort->GCPhysAddrFb = 0;
1852}
1853#endif
1854
1855/**
1856 * Create implemented ports bitmap.
1857 *
1858 * @returns 32bit bitmask with a bit set for every implemented port.
1859 * @param cPorts Number of ports.
1860 */
1861static uint32_t ahciGetPortsImplemented(unsigned cPorts)
1862{
1863 uint32_t uPortsImplemented = 0;
1864
1865 for (unsigned i = 0; i < cPorts; i++)
1866 uPortsImplemented |= (1 << i);
1867
1868 return uPortsImplemented;
1869}
1870
1871/**
1872 * Reset the entire HBA.
1873 *
1874 * @param pThis The HBA state.
1875 */
1876static void ahciHBAReset(PAHCI pThis)
1877{
1878 unsigned i;
1879 int rc = VINF_SUCCESS;
1880
1881 LogFlow(("Reset the HBA controller\n"));
1882
1883 /* Stop the CCC timer. */
1884 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
1885 {
1886 rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
1887 if (RT_FAILURE(rc))
1888 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
1889 }
1890
1891 /* Reset every port */
1892 for (i = 0; i < pThis->cPortsImpl; i++)
1893 {
1894 PAHCIPort pAhciPort = &pThis->ahciPort[i];
1895
1896 pAhciPort->iLUN = i;
1897 ahciPortSwReset(pAhciPort);
1898 }
1899
1900 /* Init Global registers */
1901 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
1902 AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
1903 AHCI_HBA_CAP_SAM | /* AHCI mode only */
1904 AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
1905 AHCI_HBA_CAP_SSS | /* Staggered spin up */
1906 AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
1907 AHCI_HBA_CAP_NCS_SET(AHCI_NR_COMMAND_SLOTS) | /* Number of command slots we support */
1908 AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
1909 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
1910 pThis->regHbaIs = 0;
1911 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
1912 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
1913 pThis->regHbaCccCtl = 0;
1914 pThis->regHbaCccPorts = 0;
1915 pThis->uCccTimeout = 0;
1916 pThis->uCccPortNr = 0;
1917 pThis->uCccNr = 0;
1918
1919 pThis->f64BitAddr = false;
1920 pThis->u32PortsInterrupted = 0;
1921 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
1922 /* Clear the HBA Reset bit */
1923 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
1924}
1925
1926/**
1927 * Memory mapped I/O Handler for read operations.
1928 *
1929 * @returns VBox status code.
1930 *
1931 * @param pDevIns The device instance.
1932 * @param pvUser User argument.
1933 * @param GCPhysAddr Physical address (in GC) where the read starts.
1934 * @param pv Where to store the result.
1935 * @param cb Number of bytes read.
1936 */
1937PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1938{
1939 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
1940 int rc = VINF_SUCCESS;
1941
1942 /* Break up 64 bits reads into two dword reads. */
1943 if (cb == 8)
1944 {
1945 rc = ahciMMIORead(pDevIns, pvUser, GCPhysAddr, pv, 4);
1946 if (RT_FAILURE(rc))
1947 return rc;
1948
1949 return ahciMMIORead(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
1950 }
1951
1952 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
1953 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
1954
1955 /*
1956 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
1957 * Otherwise it accesses the registers of a port.
1958 */
1959 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
1960 uint32_t iReg;
1961
1962 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
1963 {
1964 iReg = uOffset >> 2;
1965 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
1966 if (iReg < RT_ELEMENTS(g_aOpRegs))
1967 {
1968 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
1969 rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
1970 }
1971 else
1972 {
1973 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
1974 *(uint32_t *)pv = 0;
1975 }
1976 }
1977 else
1978 {
1979 uint32_t iRegOffset;
1980 uint32_t iPort;
1981
1982 /* Calculate accessed port. */
1983 uOffset -= AHCI_HBA_GLOBAL_SIZE;
1984 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
1985 iRegOffset = (uOffset % AHCI_PORT_REGISTER_SIZE);
1986 iReg = iRegOffset >> 2;
1987
1988 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
1989
1990 if (RT_LIKELY( iPort < pAhci->cPortsImpl
1991 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
1992 {
1993 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
1994 rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
1995 }
1996 else
1997 {
1998 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
1999 rc = VINF_IOM_MMIO_UNUSED_00;
2000 }
2001
2002 /*
2003 * Windows Vista tries to read one byte from some registers instead of four.
2004 * Correct the value according to the read size.
2005 */
2006 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2007 {
2008 switch (cb)
2009 {
2010 case 1:
2011 {
2012 uint8_t uNewValue;
2013 uint8_t *p = (uint8_t *)pv;
2014
2015 iRegOffset &= 3;
2016 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2017 uNewValue = p[iRegOffset];
2018 /* Clear old value */
2019 *(uint32_t *)pv = 0;
2020 *(uint8_t *)pv = uNewValue;
2021 break;
2022 }
2023 default:
2024 AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
2025 }
2026 }
2027 }
2028
2029 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
2030 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
2031 return rc;
2032}
2033
2034
2035/**
2036 * Memory mapped I/O Handler for write operations.
2037 *
2038 * @returns VBox status code.
2039 *
2040 * @param pDevIns The device instance.
2041 * @param pvUser User argument.
2042 * @param GCPhysAddr Physical address (in GC) where the read starts.
2043 * @param pv Where to fetch the result.
2044 * @param cb Number of bytes to write.
2045 */
2046PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2047{
2048 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2049 int rc = VINF_SUCCESS;
2050
2051 /* Break up 64 bits writes into two dword writes. */
2052 if (cb == 8)
2053 {
2054 /*
2055 * Only write the first 4 bytes if they weren't already.
2056 * It is possible that the last write to the register caused a world
2057 * switch and we entered this function again.
2058 * Writing the first 4 bytes again could cause indeterminate behavior
2059 * which can cause errors in the guest.
2060 */
2061 if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
2062 {
2063 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
2064 if (rc != VINF_SUCCESS)
2065 return rc;
2066
2067 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
2068 }
2069
2070 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
2071 /*
2072 * Reset flag again so that the first 4 bytes are written again on the next
2073 * 8byte MMIO access.
2074 */
2075 if (rc == VINF_SUCCESS)
2076 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
2077
2078 return rc;
2079 }
2080
2081 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
2082 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2083
2084 /* Validate access. */
2085 if (cb != sizeof(uint32_t))
2086 {
2087 Log2(("%s: Bad write size!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2088 return VINF_SUCCESS;
2089 }
2090 if (GCPhysAddr & 0x3)
2091 {
2092 Log2(("%s: Unaligned write!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2093 return VINF_SUCCESS;
2094 }
2095
2096 /*
2097 * If the access offset is smaller than 100h the guest accesses the global registers.
2098 * Otherwise it accesses the registers of a port.
2099 */
2100 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
2101 uint32_t iReg;
2102 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
2103 {
2104 Log3(("Write global HBA register\n"));
2105 iReg = uOffset >> 2;
2106 if (iReg < RT_ELEMENTS(g_aOpRegs))
2107 {
2108 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2109 rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
2110 }
2111 else
2112 {
2113 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2114 rc = VINF_SUCCESS;
2115 }
2116 }
2117 else
2118 {
2119 uint32_t iPort;
2120 Log3(("Write Port register\n"));
2121 /* Calculate accessed port. */
2122 uOffset -= AHCI_HBA_GLOBAL_SIZE;
2123 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
2124 iReg = (uOffset % AHCI_PORT_REGISTER_SIZE) >> 2;
2125 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2126 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2127 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2128 {
2129 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2130 rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
2131 }
2132 else
2133 {
2134 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2135 rc = VINF_SUCCESS;
2136 }
2137 }
2138
2139 return rc;
2140}
2141
2142PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2143{
2144 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2145 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2146 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2147
2148 Assert(iChannel < 2);
2149
2150 return ataControllerIOPortWrite1(pCtl, Port, u32, cb);
2151}
2152
2153PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2154{
2155 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2156 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2157 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2158
2159 Assert(iChannel < 2);
2160
2161 return ataControllerIOPortRead1(pCtl, Port, pu32, cb);
2162}
2163
2164PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2165{
2166 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2167 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2168 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2169
2170 Assert(iChannel < 2);
2171
2172 return ataControllerIOPortWrite2(pCtl, Port, u32, cb);
2173}
2174
2175PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2176{
2177 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2178 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2179 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2180
2181 Assert(iChannel < 2);
2182
2183 return ataControllerIOPortRead2(pCtl, Port, pu32, cb);
2184}
2185
2186PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2187{
2188 AssertMsgFailed(("Should not happen\n"));
2189 return VINF_SUCCESS;
2190}
2191
2192PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2193{
2194 AssertMsgFailed(("Should not happen\n"));
2195 return VINF_SUCCESS;
2196}
2197
2198#ifndef IN_RING0
2199/**
2200 * Port I/O Handler for primary port range IN string operations.
2201 * @see FNIOMIOPORTINSTRING for details.
2202 */
2203PDMBOTHCBDECL(int) ahciIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
2204{
2205 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2206 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2207 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2208
2209 Assert(iChannel < 2);
2210
2211 return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrDst, pcTransfer, cb);
2212}
2213
2214
2215/**
2216 * Port I/O Handler for primary port range OUT string operations.
2217 * @see FNIOMIOPORTOUTSTRING for details.
2218 */
2219PDMBOTHCBDECL(int) ahciIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, 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 ataControllerIOPortReadStr1(pCtl, Port, pGCPtrSrc, pcTransfer, cb);
2228}
2229#endif /* !IN_RING0 */
2230
2231#ifdef IN_RING3
2232
2233static DECLCALLBACK(int) ahciMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2234{
2235 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2236 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2237 int rc = VINF_SUCCESS;
2238
2239 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2240
2241 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2242 Assert(cb >= 4352);
2243
2244 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2245 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
2246 ahciMMIOWrite, ahciMMIORead, NULL, "AHCI");
2247 if (RT_FAILURE(rc))
2248 return rc;
2249
2250 if (pThis->fR0Enabled)
2251 {
2252 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
2253 "ahciMMIOWrite", "ahciMMIORead", NULL);
2254 if (RT_FAILURE(rc))
2255 return rc;
2256 }
2257
2258 if (pThis->fGCEnabled)
2259 {
2260 rc = PDMDevHlpMMIORegisterGC(pDevIns, GCPhysAddress, cb, 0,
2261 "ahciMMIOWrite", "ahciMMIORead", NULL);
2262 if (RT_FAILURE(rc))
2263 return rc;
2264 }
2265
2266 pThis->MMIOBase = GCPhysAddress;
2267 return rc;
2268}
2269
2270/**
2271 * Map the legacy I/O port ranges to make Solaris work with the controller.
2272 */
2273static DECLCALLBACK(int) ahciLegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2274{
2275 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2276 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2277 int rc = VINF_SUCCESS;
2278
2279 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2280
2281 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2282
2283 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2284 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2285 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2286 if (RT_FAILURE(rc))
2287 return rc;
2288
2289 if (pThis->fR0Enabled)
2290 {
2291 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2292 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2293 if (RT_FAILURE(rc))
2294 return rc;
2295 }
2296
2297 if (pThis->fGCEnabled)
2298 {
2299 rc = PDMDevHlpIOPortRegisterGC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2300 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2301 if (RT_FAILURE(rc))
2302 return rc;
2303 }
2304
2305 return rc;
2306}
2307
2308/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2309
2310/**
2311 * Gets the pointer to the status LED of a unit.
2312 *
2313 * @returns VBox status code.
2314 * @param pInterface Pointer to the interface structure containing the called function pointer.
2315 * @param iLUN The unit which status LED we desire.
2316 * @param ppLed Where to store the LED pointer.
2317 */
2318static DECLCALLBACK(int) ahciStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2319{
2320 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2321 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2322 {
2323 *ppLed = &pAhci->ahciPort[iLUN].Led;
2324 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2325 return VINF_SUCCESS;
2326 }
2327 return VERR_PDM_LUN_NOT_FOUND;
2328}
2329
2330/**
2331 * Queries an interface to the driver.
2332 *
2333 * @returns Pointer to interface.
2334 * @returns NULL if the interface was not supported by the device.
2335 * @param pInterface Pointer to ATADevState::IBase.
2336 * @param enmInterface The requested interface identification.
2337 */
2338static DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2339{
2340 PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
2341 switch (enmInterface)
2342 {
2343 case PDMINTERFACE_BASE:
2344 return &pAhci->IBase;
2345 case PDMINTERFACE_LED_PORTS:
2346 return &pAhci->ILeds;
2347 default:
2348 return NULL;
2349 }
2350}
2351
2352/**
2353 * Query interface method for the AHCI port.
2354 */
2355static DECLCALLBACK(void *) ahciPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2356{
2357 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2358 switch (enmInterface)
2359 {
2360 case PDMINTERFACE_BASE:
2361 return &pAhciPort->IBase;
2362 case PDMINTERFACE_BLOCK_PORT:
2363 return &pAhciPort->IPort;
2364 case PDMINTERFACE_BLOCK_ASYNC_PORT:
2365 return &pAhciPort->IPortAsync;
2366 case PDMINTERFACE_MOUNT_NOTIFY:
2367 return &pAhciPort->IMountNotify;
2368 default:
2369 return NULL;
2370 }
2371}
2372
2373static DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2374{
2375 uint32_t i;
2376 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2377
2378 pAhci->pDevInsRC += offDelta;
2379 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
2380 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
2381
2382 /* Relocate every port. */
2383 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
2384 {
2385 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
2386 pAhciPort->pAhciRC += offDelta;
2387 pAhciPort->pDevInsRC += offDelta;
2388 }
2389
2390 /* Relocate emulated ATA controllers. */
2391 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
2392 ataControllerRelocate(&pAhci->aCts[i], offDelta);
2393}
2394
2395#ifdef DEBUG
2396
2397/**
2398 * Dump info about the FIS
2399 *
2400 * @returns nothing
2401 * @param pAhciPort The port the command FIS was read from.
2402 * @param cmdFis The FIS to print info from.
2403 */
2404static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2405{
2406 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2407 /* Print FIS type. */
2408 switch (cmdFis[AHCI_CMDFIS_TYPE])
2409 {
2410 case AHCI_CMDFIS_TYPE_H2D:
2411 {
2412 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2413 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2414 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2415 {
2416 ahciLog(("%s: Command register update\n", __FUNCTION__));
2417 }
2418 else
2419 {
2420 ahciLog(("%s: Control register update\n", __FUNCTION__));
2421 }
2422 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2423 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2424 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2425 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2426 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2427 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2428
2429 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2430 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2431 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2432 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2433
2434 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2435 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2436 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2437 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2438 {
2439 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2440 }
2441 }
2442 break;
2443 case AHCI_CMDFIS_TYPE_D2H:
2444 {
2445 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2446 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2447 }
2448 break;
2449 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2450 {
2451 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2452 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2453 }
2454 break;
2455 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2456 {
2457 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2458 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2459 }
2460 break;
2461 case AHCI_CMDFIS_TYPE_DMASETUP:
2462 {
2463 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2464 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2465 }
2466 break;
2467 case AHCI_CMDFIS_TYPE_PIOSETUP:
2468 {
2469 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2470 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2471 }
2472 break;
2473 case AHCI_CMDFIS_TYPE_DATA:
2474 {
2475 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2476 }
2477 break;
2478 default:
2479 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2480 break;
2481 }
2482 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2483}
2484
2485/**
2486 * Dump info about the command header
2487 *
2488 * @returns nothing
2489 * @param pAhciPort Poitner to the port the command header was read from.
2490 * @param pCmdHdr The command header to print info from.
2491 */
2492static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2493{
2494 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2495 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2496 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2497 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2498 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2499 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2500 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2501 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2502 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2503 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2504 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2505 ahciLog(("%s: Device write\n", __FUNCTION__));
2506 else
2507 ahciLog(("%s: Device read\n", __FUNCTION__));
2508 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2509 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2510 else
2511 ahciLog(("%s: ATA command\n", __FUNCTION__));
2512
2513 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2514 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2515}
2516#endif /* DEBUG */
2517
2518/**
2519 * Post the first D2H FIS from the device into guest memory.
2520 *
2521 * @returns nothing
2522 * @param pAhciPort Pointer to the port which "receives" the FIS.
2523 */
2524static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2525{
2526 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2527
2528 pAhciPort->fFirstD2HFisSend = true;
2529
2530 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2531 memset(&d2hFis[0], 0, sizeof(d2hFis));
2532 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2533 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2534
2535 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2536
2537 /* Set the signature based on the device type. */
2538 if (pAhciPort->fATAPI)
2539 {
2540 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2541 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2542 }
2543 else
2544 {
2545 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2546 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2547 }
2548
2549 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2550 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2551 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2552
2553 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2554
2555 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2556}
2557
2558/**
2559 * Post the FIS in the memory area allocated by the guest and set interrupt if neccessary.
2560 *
2561 * @returns VBox status code
2562 * @param pAhciPort The port which "receives" the FIS.
2563 * @param uFisType The type of the FIS.
2564 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2565 */
2566static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2567{
2568 int rc = VINF_SUCCESS;
2569 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2570 unsigned cbFis = 0;
2571
2572 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2573
2574 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2575 {
2576 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2577
2578 /* Determine the offset and size of the FIS based on uFisType. */
2579 switch (uFisType)
2580 {
2581 case AHCI_CMDFIS_TYPE_D2H:
2582 {
2583 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2584 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2585 }
2586 break;
2587 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2588 {
2589 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2590 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2591 }
2592 break;
2593 case AHCI_CMDFIS_TYPE_DMASETUP:
2594 {
2595 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2596 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2597 }
2598 break;
2599 case AHCI_CMDFIS_TYPE_PIOSETUP:
2600 {
2601 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2602 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2603 }
2604 break;
2605 default:
2606 /*
2607 * We should post the unknown FIS into memory too but this never happens because
2608 * we know which FIS types we generate. ;)
2609 */
2610 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2611 }
2612
2613 /* Post the FIS into memory. */
2614 ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2615 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2616 }
2617
2618 return rc;
2619}
2620
2621DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2622{
2623 pbBuf[0] = val >> 8;
2624 pbBuf[1] = val;
2625}
2626
2627
2628DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2629{
2630 pbBuf[0] = val >> 16;
2631 pbBuf[1] = val >> 8;
2632 pbBuf[2] = val;
2633}
2634
2635
2636DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2637{
2638 pbBuf[0] = val >> 24;
2639 pbBuf[1] = val >> 16;
2640 pbBuf[2] = val >> 8;
2641 pbBuf[3] = val;
2642}
2643
2644
2645DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2646{
2647 return (pbBuf[0] << 8) | pbBuf[1];
2648}
2649
2650
2651DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2652{
2653 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2654}
2655
2656
2657DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2658{
2659 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2660}
2661
2662
2663DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2664{
2665 iATAPILBA += 150;
2666 pbBuf[0] = (iATAPILBA / 75) / 60;
2667 pbBuf[1] = (iATAPILBA / 75) % 60;
2668 pbBuf[2] = iATAPILBA % 75;
2669}
2670
2671
2672DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2673{
2674 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2675}
2676
2677static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
2678{
2679 pAhciPortTaskState->uATARegError = 0;
2680 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2681 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2682 | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
2683 | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2684 pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
2685 pAhciPort->uATAPIASC = SCSI_ASC_NONE;
2686}
2687
2688
2689static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
2690{
2691 pAhciPortTaskState->uATARegError = uATAPISenseKey << 4;
2692 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
2693 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2694 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2695 pAhciPort->uATAPISenseKey = uATAPISenseKey;
2696 pAhciPort->uATAPIASC = uATAPIASC;
2697}
2698
2699static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2700{
2701 for (uint32_t i = 0; i < cbSize; i++)
2702 {
2703 if (*pbSrc)
2704 pbDst[i] = *pbSrc++;
2705 else
2706 pbDst[i] = ' ';
2707 }
2708}
2709
2710static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2711{
2712 for (uint32_t i = 0; i < cbSize; i++)
2713 {
2714 if (*pbSrc)
2715 pbDst[i ^ 1] = *pbSrc++;
2716 else
2717 pbDst[i ^ 1] = ' ';
2718 }
2719}
2720
2721static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
2722{
2723 uint16_t *p;
2724 int rc = VINF_SUCCESS;
2725
2726 p = (uint16_t *)pvBuf;
2727 memset(p, 0, 512);
2728 p[0] = RT_H2LE_U16(0x0040);
2729 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2730 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2731 /* Block size; obsolete, but required for the BIOS. */
2732 p[5] = RT_H2LE_U16(512);
2733 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2734 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2735 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2736 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2737 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
2738 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2739 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2740#if ATA_MAX_MULT_SECTORS > 1
2741 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
2742#endif
2743 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
2744 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2745 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2746 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2747 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2748 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
2749 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2750 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2751 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2752 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
2753 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
2754 if (pAhciPort->cMultSectors)
2755 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
2756 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
2757 {
2758 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2759 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2760 }
2761 else
2762 {
2763 /* Report maximum number of sectors possible with LBA28 */
2764 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
2765 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
2766 }
2767 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2768 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2769 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2770 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2771 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2772 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2773 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2774 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2775 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
2776 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2777 p[84] = RT_H2LE_U16(1 << 14);
2778 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
2779 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2780 p[87] = RT_H2LE_U16(1 << 14);
2781 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2782 p[93] = RT_H2LE_U16(0x00);
2783 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2784 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2785 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
2786 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
2787
2788 /* The following are SATA specific */
2789 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2790 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2791
2792 return VINF_SUCCESS;
2793}
2794
2795typedef int (*PAtapiFunc)(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2796
2797static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2798static int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2799static int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2800static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2801static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2802static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2803static int atapiReadCapacitySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2804static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2805static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2806static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2807static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2808static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2809static int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2810//static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2811
2812/**
2813 * Source/sink function indexes for g_apfnAtapiFuncs.
2814 */
2815typedef enum ATAPIFN
2816{
2817 ATAFN_SS_NULL = 0,
2818 ATAFN_SS_ATAPI_GET_CONFIGURATION,
2819 ATAFN_SS_ATAPI_IDENTIFY,
2820 ATAFN_SS_ATAPI_INQUIRY,
2821 ATAFN_SS_ATAPI_MECHANISM_STATUS,
2822 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
2823 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
2824 ATAFN_SS_ATAPI_READ_CAPACITY,
2825 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
2826 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
2827 ATAFN_SS_ATAPI_READ_TOC_MULTI,
2828 ATAFN_SS_ATAPI_READ_TOC_RAW,
2829 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
2830 ATAFN_SS_ATAPI_REQUEST_SENSE,
2831 //ATAFN_SS_ATAPI_PASSTHROUGH,
2832 ATAFN_SS_MAX
2833} ATAPIFN;
2834
2835/**
2836 * Array of source/sink functions, the index is ATAFNSS.
2837 * Make sure ATAFNSS and this array match!
2838 */
2839static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
2840{
2841 NULL,
2842 atapiGetConfigurationSS,
2843 atapiIdentifySS,
2844 atapiInquirySS,
2845 atapiMechanismStatusSS,
2846 atapiModeSenseErrorRecoverySS,
2847 atapiModeSenseCDStatusSS,
2848 atapiReadCapacitySS,
2849 atapiReadDiscInformationSS,
2850 atapiReadTOCNormalSS,
2851 atapiReadTOCMultiSS,
2852 atapiReadTOCRawSS,
2853 atapiReadTrackInformationSS,
2854 atapiRequestSenseSS
2855 //atapiPassthroughSS
2856};
2857
2858static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2859{
2860 uint16_t p[256];
2861 char aSerial[20];
2862 RTUUID Uuid;
2863 int rc;
2864
2865 rc = pAhciPort->pDrvBlock ? pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
2866 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
2867 {
2868 /* Generate a predictable serial for drives which don't have a UUID. */
2869 RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-1a2b3c4d",
2870 pAhciPort->iLUN);
2871 }
2872 else
2873 RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
2874
2875 memset(p, 0, 512);
2876 /* Removable CDROM, 50us response, 12 byte packets */
2877 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
2878 ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
2879 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2880 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2881 ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
2882 ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
2883 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2884 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2885 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2886 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2887 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
2888 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2889 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2890 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2891 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2892 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2893 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2894 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
2895 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
2896 p[75] = RT_H2LE_U16(1); /* queue depth 1 */
2897 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2898 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2899 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
2900 p[83] = RT_H2LE_U16(1 << 14);
2901 p[84] = RT_H2LE_U16(1 << 14);
2902 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
2903 p[86] = RT_H2LE_U16(0);
2904 p[87] = RT_H2LE_U16(1 << 14);
2905 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2906 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
2907
2908 /* The following are SATA specific */
2909 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2910 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2911
2912 /* Copy the buffer in to the scatter gather list. */
2913 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
2914 *pcbData = sizeof(p);
2915
2916 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2917 return VINF_SUCCESS;
2918}
2919
2920static int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2921{
2922 uint8_t aBuf[8];
2923
2924 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
2925 ataH2BE_U32(aBuf + 4, 2048);
2926
2927 /* Copy the buffer in to the scatter gather list. */
2928 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2929 *pcbData = sizeof(aBuf);
2930
2931 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2932 return VINF_SUCCESS;
2933}
2934
2935
2936static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2937{
2938 uint8_t aBuf[34];
2939
2940 memset(aBuf, '\0', 34);
2941 ataH2BE_U16(aBuf, 32);
2942 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
2943 aBuf[3] = 1; /* number of first track */
2944 aBuf[4] = 1; /* number of sessions (LSB) */
2945 aBuf[5] = 1; /* first track number in last session (LSB) */
2946 aBuf[6] = 1; /* last track number in last session (LSB) */
2947 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 */
2948 aBuf[8] = 0; /* disc type = CD-ROM */
2949 aBuf[9] = 0; /* number of sessions (MSB) */
2950 aBuf[10] = 0; /* number of sessions (MSB) */
2951 aBuf[11] = 0; /* number of sessions (MSB) */
2952 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
2953 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
2954
2955 /* Copy the buffer in to the scatter gather list. */
2956 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2957 *pcbData = sizeof(aBuf);
2958
2959 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2960 return VINF_SUCCESS;
2961}
2962
2963
2964static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2965{
2966 uint8_t aBuf[36];
2967
2968 /* Accept address/number type of 1 only, and only track 1 exists. */
2969 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
2970 {
2971 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2972 return VINF_SUCCESS;
2973 }
2974 memset(aBuf, '\0', 36);
2975 ataH2BE_U16(aBuf, 34);
2976 aBuf[2] = 1; /* track number (LSB) */
2977 aBuf[3] = 1; /* session number (LSB) */
2978 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
2979 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 */
2980 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
2981 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
2982 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
2983 aBuf[32] = 0; /* track number (MSB) */
2984 aBuf[33] = 0; /* session number (MSB) */
2985
2986 /* Copy the buffer in to the scatter gather list. */
2987 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2988 *pcbData = sizeof(aBuf);
2989
2990 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2991 return VINF_SUCCESS;
2992}
2993
2994
2995static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2996{
2997 uint8_t aBuf[32];
2998
2999 /* Accept valid request types only, and only starting feature 0. */
3000 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
3001 {
3002 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3003 return VINF_SUCCESS;
3004 }
3005 memset(aBuf, '\0', 32);
3006 ataH2BE_U32(aBuf, 16);
3007 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3008 * way to differentiate them right now is based on the image size). Also
3009 * implement signalling "no current profile" if no medium is loaded. */
3010 ataH2BE_U16(aBuf + 6, 0x08); /* current profile: read-only CD */
3011
3012 ataH2BE_U16(aBuf + 8, 0); /* feature 0: list of profiles supported */
3013 aBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
3014 aBuf[11] = 8; /* additional bytes for profiles */
3015 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3016 * before CD-ROM read capability. */
3017 ataH2BE_U16(aBuf + 12, 0x10); /* profile: read-only DVD */
3018 aBuf[14] = (0 << 0); /* NOT current profile */
3019 ataH2BE_U16(aBuf + 16, 0x08); /* profile: read only CD */
3020 aBuf[18] = (1 << 0); /* current profile */
3021
3022 /* Copy the buffer in to the scatter gather list. */
3023 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3024 *pcbData = sizeof(aBuf);
3025
3026 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3027 return VINF_SUCCESS;
3028}
3029
3030
3031static int atapiInquirySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3032{
3033 uint8_t aBuf[36];
3034
3035 aBuf[0] = 0x05; /* CD-ROM */
3036 aBuf[1] = 0x80; /* removable */
3037 aBuf[2] = 0x00; /* ISO */
3038 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3039 aBuf[4] = 31; /* additional length */
3040 aBuf[5] = 0; /* reserved */
3041 aBuf[6] = 0; /* reserved */
3042 aBuf[7] = 0; /* reserved */
3043 ataSCSIPadStr(aBuf + 8, "VBOX", 8);
3044 ataSCSIPadStr(aBuf + 16, "CD-ROM", 16);
3045 ataSCSIPadStr(aBuf + 32, "1.0", 4);
3046
3047 /* Copy the buffer in to the scatter gather list. */
3048 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3049 *pcbData = sizeof(aBuf);
3050
3051 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3052 return VINF_SUCCESS;
3053}
3054
3055
3056static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3057{
3058 uint8_t aBuf[16];
3059
3060 ataH2BE_U16(&aBuf[0], 16 + 6);
3061 aBuf[2] = 0x70;
3062 aBuf[3] = 0;
3063 aBuf[4] = 0;
3064 aBuf[5] = 0;
3065 aBuf[6] = 0;
3066 aBuf[7] = 0;
3067
3068 aBuf[8] = 0x01;
3069 aBuf[9] = 0x06;
3070 aBuf[10] = 0x00;
3071 aBuf[11] = 0x05;
3072 aBuf[12] = 0x00;
3073 aBuf[13] = 0x00;
3074 aBuf[14] = 0x00;
3075 aBuf[15] = 0x00;
3076
3077 /* Copy the buffer in to the scatter gather list. */
3078 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3079 *pcbData = sizeof(aBuf);
3080
3081 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3082 return VINF_SUCCESS;
3083}
3084
3085
3086static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3087{
3088 uint8_t aBuf[40];
3089
3090 ataH2BE_U16(&aBuf[0], 38);
3091 aBuf[2] = 0x70;
3092 aBuf[3] = 0;
3093 aBuf[4] = 0;
3094 aBuf[5] = 0;
3095 aBuf[6] = 0;
3096 aBuf[7] = 0;
3097
3098 aBuf[8] = 0x2a;
3099 aBuf[9] = 30; /* page length */
3100 aBuf[10] = 0x08; /* DVD-ROM read support */
3101 aBuf[11] = 0x00; /* no write support */
3102 /* The following claims we support audio play. This is obviously false,
3103 * but the Linux generic CDROM support makes many features depend on this
3104 * capability. If it's not set, this causes many things to be disabled. */
3105 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3106 aBuf[13] = 0x00; /* no subchannel reads supported */
3107 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3108 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3109 aBuf[14] |= 1 << 1; /* report lock state */
3110 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3111 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3112 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3113 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3114 Just write the value DevATA is using. */
3115 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3116 aBuf[24] = 0; /* reserved */
3117 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3118 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3119 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3120 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3121 aBuf[32] = 0; /* reserved */
3122 aBuf[33] = 0; /* reserved */
3123 aBuf[34] = 0; /* reserved */
3124 aBuf[35] = 1; /* rotation control CAV */
3125 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3126 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3127
3128 /* Copy the buffer in to the scatter gather list. */
3129 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3130 *pcbData = sizeof(aBuf);
3131
3132 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3133 return VINF_SUCCESS;
3134}
3135
3136
3137static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3138{
3139 uint8_t aBuf[18];
3140
3141 memset(&aBuf[0], 0, 18);
3142 aBuf[0] = 0x70 | (1 << 7);
3143 aBuf[2] = pAhciPort->uATAPISenseKey;
3144 aBuf[7] = 10;
3145 aBuf[12] = pAhciPort->uATAPIASC;
3146
3147 /* Copy the buffer in to the scatter gather list. */
3148 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3149 *pcbData = sizeof(aBuf);
3150
3151 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3152 return VINF_SUCCESS;
3153}
3154
3155
3156static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3157{
3158 uint8_t aBuf[8];
3159
3160 ataH2BE_U16(&aBuf[0], 0);
3161 /* no current LBA */
3162 aBuf[2] = 0;
3163 aBuf[3] = 0;
3164 aBuf[4] = 0;
3165 aBuf[5] = 1;
3166 ataH2BE_U16(aBuf + 6, 0);
3167
3168 /* Copy the buffer in to the scatter gather list. */
3169 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3170 *pcbData = sizeof(aBuf);
3171
3172 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3173 return VINF_SUCCESS;
3174}
3175
3176
3177static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3178{
3179 uint8_t aBuf[20], *q, iStartTrack;
3180 bool fMSF;
3181 uint32_t cbSize;
3182
3183 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3184 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3185 if (iStartTrack > 1 && iStartTrack != 0xaa)
3186 {
3187 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3188 return VINF_SUCCESS;
3189 }
3190 q = aBuf + 2;
3191 *q++ = 1; /* first session */
3192 *q++ = 1; /* last session */
3193 if (iStartTrack <= 1)
3194 {
3195 *q++ = 0; /* reserved */
3196 *q++ = 0x14; /* ADR, control */
3197 *q++ = 1; /* track number */
3198 *q++ = 0; /* reserved */
3199 if (fMSF)
3200 {
3201 *q++ = 0; /* reserved */
3202 ataLBA2MSF(q, 0);
3203 q += 3;
3204 }
3205 else
3206 {
3207 /* sector 0 */
3208 ataH2BE_U32(q, 0);
3209 q += 4;
3210 }
3211 }
3212 /* lead out track */
3213 *q++ = 0; /* reserved */
3214 *q++ = 0x14; /* ADR, control */
3215 *q++ = 0xaa; /* track number */
3216 *q++ = 0; /* reserved */
3217 if (fMSF)
3218 {
3219 *q++ = 0; /* reserved */
3220 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3221 q += 3;
3222 }
3223 else
3224 {
3225 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3226 q += 4;
3227 }
3228 cbSize = q - aBuf;
3229 ataH2BE_U16(aBuf, cbSize - 2);
3230
3231 /* Copy the buffer in to the scatter gather list. */
3232 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3233 *pcbData = cbSize;
3234
3235 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3236 return VINF_SUCCESS;
3237}
3238
3239
3240static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3241{
3242 uint8_t aBuf[12];
3243 bool fMSF;
3244
3245 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3246 /* multi session: only a single session defined */
3247/** @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. */
3248 memset(aBuf, 0, 12);
3249 aBuf[1] = 0x0a;
3250 aBuf[2] = 0x01;
3251 aBuf[3] = 0x01;
3252 aBuf[5] = 0x14; /* ADR, control */
3253 aBuf[6] = 1; /* first track in last complete session */
3254 if (fMSF)
3255 {
3256 aBuf[8] = 0; /* reserved */
3257 ataLBA2MSF(&aBuf[9], 0);
3258 }
3259 else
3260 {
3261 /* sector 0 */
3262 ataH2BE_U32(aBuf + 8, 0);
3263 }
3264
3265 /* Copy the buffer in to the scatter gather list. */
3266 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3267 *pcbData = sizeof(aBuf);
3268
3269 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3270 return VINF_SUCCESS;
3271}
3272
3273
3274static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3275{
3276 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3277 uint8_t *q, iStartTrack;
3278 bool fMSF;
3279 uint32_t cbSize;
3280
3281 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3282 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3283
3284 q = aBuf + 2;
3285 *q++ = 1; /* first session */
3286 *q++ = 1; /* last session */
3287
3288 *q++ = 1; /* session number */
3289 *q++ = 0x14; /* data track */
3290 *q++ = 0; /* track number */
3291 *q++ = 0xa0; /* first track in program area */
3292 *q++ = 0; /* min */
3293 *q++ = 0; /* sec */
3294 *q++ = 0; /* frame */
3295 *q++ = 0;
3296 *q++ = 1; /* first track */
3297 *q++ = 0x00; /* disk type CD-DA or CD data */
3298 *q++ = 0;
3299
3300 *q++ = 1; /* session number */
3301 *q++ = 0x14; /* data track */
3302 *q++ = 0; /* track number */
3303 *q++ = 0xa1; /* last track in program area */
3304 *q++ = 0; /* min */
3305 *q++ = 0; /* sec */
3306 *q++ = 0; /* frame */
3307 *q++ = 0;
3308 *q++ = 1; /* last track */
3309 *q++ = 0;
3310 *q++ = 0;
3311
3312 *q++ = 1; /* session number */
3313 *q++ = 0x14; /* data track */
3314 *q++ = 0; /* track number */
3315 *q++ = 0xa2; /* lead-out */
3316 *q++ = 0; /* min */
3317 *q++ = 0; /* sec */
3318 *q++ = 0; /* frame */
3319 if (fMSF)
3320 {
3321 *q++ = 0; /* reserved */
3322 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3323 q += 3;
3324 }
3325 else
3326 {
3327 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3328 q += 4;
3329 }
3330
3331 *q++ = 1; /* session number */
3332 *q++ = 0x14; /* ADR, control */
3333 *q++ = 0; /* track number */
3334 *q++ = 1; /* point */
3335 *q++ = 0; /* min */
3336 *q++ = 0; /* sec */
3337 *q++ = 0; /* frame */
3338 if (fMSF)
3339 {
3340 *q++ = 0; /* reserved */
3341 ataLBA2MSF(q, 0);
3342 q += 3;
3343 }
3344 else
3345 {
3346 /* sector 0 */
3347 ataH2BE_U32(q, 0);
3348 q += 4;
3349 }
3350
3351 cbSize = q - aBuf;
3352 ataH2BE_U16(aBuf, cbSize - 2);
3353
3354 /* Copy the buffer in to the scatter gather list. */
3355 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3356 *pcbData = cbSize;
3357
3358 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3359 return VINF_SUCCESS;
3360}
3361
3362static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
3363{
3364 int cbTransfered;
3365 int rc, rcSourceSink;
3366
3367 /* Create scatter gather list. */
3368 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
3369 if (RT_FAILURE(rc))
3370 AssertMsgFailed(("Getting number of list elements failed rc=%Rrc\n", rc));
3371
3372 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
3373
3374 pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
3375
3376 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
3377 if (RT_FAILURE(rc))
3378 AssertMsgFailed(("Destroying list failed rc=%Rrc\n", rc));
3379
3380 /* Write updated command header into memory of the guest. */
3381 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
3382
3383 return rcSourceSink;
3384}
3385
3386static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
3387{
3388 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
3389
3390 switch (cbSector)
3391 {
3392 case 2048:
3393 pAhciPortTaskState->uOffset = iATAPILBA * cbSector;
3394 pAhciPortTaskState->cbTransfer = cSectors * cbSector;
3395 break;
3396 case 2352:
3397 {
3398 AssertMsgFailed(("2352 read\n"));
3399 /* @todo: This is quite difficult as the data transfer is not handled here
3400 We need to add the sync bytes etc. here and modify the pointers
3401 and size of the sg entries. */
3402#if 0
3403 uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
3404
3405 for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
3406 {
3407 /* sync bytes */
3408 *pbBuf++ = 0x00;
3409 memset(pbBuf, 0xff, 11);
3410 pbBuf += 11;
3411 /* MSF */
3412 ataLBA2MSF(pbBuf, i);
3413 pbBuf += 3;
3414 *pbBuf++ = 0x01; /* mode 1 data */
3415 /* data */
3416 rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
3417 if (RT_FAILURE(rc))
3418 break;
3419 pbBuf += 2048;
3420 /* ECC */
3421 memset(pbBuf, 0, 288);
3422 pbBuf += 288;
3423 }
3424#endif
3425 pAhciPortTaskState->uOffset = iATAPILBA * 2048;
3426 pAhciPortTaskState->cbTransfer = cSectors * 2048;
3427 }
3428 break;
3429 default:
3430 AssertMsgFailed(("Unsupported sectors size\n"));
3431 break;
3432 }
3433
3434 return VINF_SUCCESS;
3435}
3436
3437static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3438{
3439 int rc = PDMBLOCKTXDIR_NONE;
3440 const uint8_t *pbPacket;
3441 uint32_t cbMax;
3442
3443 pbPacket = pAhciPortTaskState->aATAPICmd;
3444
3445 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
3446
3447 switch (pbPacket[0])
3448 {
3449 case SCSI_TEST_UNIT_READY:
3450 if (pAhciPort->cNotifiedMediaChange > 0)
3451 {
3452 if (pAhciPort->cNotifiedMediaChange-- > 2)
3453 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3454 else
3455 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3456 }
3457 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3458 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3459 else
3460 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3461 break;
3462 case SCSI_MODE_SENSE_10:
3463 {
3464 uint8_t uPageControl, uPageCode;
3465 cbMax = ataBE2H_U16(pbPacket + 7);
3466 uPageControl = pbPacket[2] >> 6;
3467 uPageCode = pbPacket[2] & 0x3f;
3468 switch (uPageControl)
3469 {
3470 case SCSI_PAGECONTROL_CURRENT:
3471 switch (uPageCode)
3472 {
3473 case SCSI_MODEPAGE_ERROR_RECOVERY:
3474 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
3475 break;
3476 case SCSI_MODEPAGE_CD_STATUS:
3477 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
3478 break;
3479 default:
3480 goto error_cmd;
3481 }
3482 break;
3483 case SCSI_PAGECONTROL_CHANGEABLE:
3484 goto error_cmd;
3485 case SCSI_PAGECONTROL_DEFAULT:
3486 goto error_cmd;
3487 default:
3488 case SCSI_PAGECONTROL_SAVED:
3489 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
3490 break;
3491 }
3492 }
3493 break;
3494 case SCSI_REQUEST_SENSE:
3495 cbMax = pbPacket[4];
3496 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_REQUEST_SENSE);
3497 break;
3498 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
3499 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3500 {
3501 if (pbPacket[4] & 1)
3502 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
3503 else
3504 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
3505 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3506 }
3507 else
3508 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3509 break;
3510 case SCSI_READ_10:
3511 case SCSI_READ_12:
3512 {
3513 uint32_t cSectors, iATAPILBA;
3514
3515 if (pAhciPort->cNotifiedMediaChange > 0)
3516 {
3517 pAhciPort->cNotifiedMediaChange-- ;
3518 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3519 break;
3520 }
3521 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3522 {
3523 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3524 break;
3525 }
3526 if (pbPacket[0] == SCSI_READ_10)
3527 cSectors = ataBE2H_U16(pbPacket + 7);
3528 else
3529 cSectors = ataBE2H_U32(pbPacket + 6);
3530 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3531 if (cSectors == 0)
3532 {
3533 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3534 break;
3535 }
3536 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3537 {
3538 /* Rate limited logging, one log line per second. For
3539 * guests that insist on reading from places outside the
3540 * valid area this often generates too many release log
3541 * entries otherwise. */
3542 static uint64_t uLastLogTS = 0;
3543 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3544 {
3545 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3546 uLastLogTS = RTTimeMilliTS();
3547 }
3548 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3549 break;
3550 }
3551 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3552 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3553 }
3554 break;
3555 case SCSI_READ_CD:
3556 {
3557 uint32_t cSectors, iATAPILBA;
3558
3559 if (pAhciPort->cNotifiedMediaChange > 0)
3560 {
3561 pAhciPort->cNotifiedMediaChange-- ;
3562 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3563 break;
3564 }
3565 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3566 {
3567 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3568 break;
3569 }
3570 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
3571 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3572 if (cSectors == 0)
3573 {
3574 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3575 break;
3576 }
3577 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3578 {
3579 /* Rate limited logging, one log line per second. For
3580 * guests that insist on reading from places outside the
3581 * valid area this often generates too many release log
3582 * entries otherwise. */
3583 static uint64_t uLastLogTS = 0;
3584 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3585 {
3586 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3587 uLastLogTS = RTTimeMilliTS();
3588 }
3589 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3590 break;
3591 }
3592 switch (pbPacket[9] & 0xf8)
3593 {
3594 case 0x00:
3595 /* nothing */
3596 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3597 break;
3598 case 0x10:
3599 /* normal read */
3600 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3601 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3602 break;
3603 case 0xf8:
3604 /* read all data */
3605 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
3606 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3607 break;
3608 default:
3609 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
3610 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3611 break;
3612 }
3613 }
3614 break;
3615 case SCSI_SEEK_10:
3616 {
3617 uint32_t iATAPILBA;
3618 if (pAhciPort->cNotifiedMediaChange > 0)
3619 {
3620 pAhciPort->cNotifiedMediaChange-- ;
3621 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3622 break;
3623 }
3624 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3625 {
3626 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3627 break;
3628 }
3629 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3630 if (iATAPILBA > pAhciPort->cTotalSectors)
3631 {
3632 /* Rate limited logging, one log line per second. For
3633 * guests that insist on seeking to places outside the
3634 * valid area this often generates too many release log
3635 * entries otherwise. */
3636 static uint64_t uLastLogTS = 0;
3637 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3638 {
3639 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
3640 uLastLogTS = RTTimeMilliTS();
3641 }
3642 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3643 break;
3644 }
3645 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3646 pAhciPortTaskState->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
3647 }
3648 break;
3649 case SCSI_START_STOP_UNIT:
3650 {
3651 int rc = VINF_SUCCESS;
3652 switch (pbPacket[4] & 3)
3653 {
3654 case 0: /* 00 - Stop motor */
3655 case 1: /* 01 - Start motor */
3656 break;
3657 case 2: /* 10 - Eject media */
3658 /* This must be done from EMT. */
3659 {
3660 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3661 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
3662 PVMREQ pReq;
3663
3664 rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
3665 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
3666 AssertReleaseRC(rc);
3667 VMR3ReqFree(pReq);
3668 }
3669 break;
3670 case 3: /* 11 - Load media */
3671 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
3672 break;
3673 }
3674 if (RT_SUCCESS(rc))
3675 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3676 else
3677 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
3678 }
3679 break;
3680 case SCSI_MECHANISM_STATUS:
3681 {
3682 cbMax = ataBE2H_U16(pbPacket + 8);
3683 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MECHANISM_STATUS);
3684 }
3685 break;
3686 case SCSI_READ_TOC_PMA_ATIP:
3687 {
3688 uint8_t format;
3689
3690 if (pAhciPort->cNotifiedMediaChange > 0)
3691 {
3692 pAhciPort->cNotifiedMediaChange-- ;
3693 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3694 break;
3695 }
3696 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3697 {
3698 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3699 break;
3700 }
3701 cbMax = ataBE2H_U16(pbPacket + 7);
3702 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
3703 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
3704 * the other field is clear... */
3705 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
3706 switch (format)
3707 {
3708 case 0:
3709 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
3710 break;
3711 case 1:
3712 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_MULTI);
3713 break;
3714 case 2:
3715 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_RAW);
3716 break;
3717 default:
3718 error_cmd:
3719 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3720 break;
3721 }
3722 }
3723 break;
3724 case SCSI_READ_CAPACITY:
3725 if (pAhciPort->cNotifiedMediaChange > 0)
3726 {
3727 pAhciPort->cNotifiedMediaChange-- ;
3728 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3729 break;
3730 }
3731 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3732 {
3733 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3734 break;
3735 }
3736 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_CAPACITY);
3737 break;
3738 case SCSI_READ_DISC_INFORMATION:
3739 if (pAhciPort->cNotifiedMediaChange > 0)
3740 {
3741 pAhciPort->cNotifiedMediaChange-- ;
3742 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3743 break;
3744 }
3745 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3746 {
3747 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3748 break;
3749 }
3750 cbMax = ataBE2H_U16(pbPacket + 7);
3751 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
3752 break;
3753 case SCSI_READ_TRACK_INFORMATION:
3754 if (pAhciPort->cNotifiedMediaChange > 0)
3755 {
3756 pAhciPort->cNotifiedMediaChange-- ;
3757 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3758 break;
3759 }
3760 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3761 {
3762 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3763 break;
3764 }
3765 cbMax = ataBE2H_U16(pbPacket + 7);
3766 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
3767 break;
3768 case SCSI_GET_CONFIGURATION:
3769 /* No media change stuff here, it can confuse Linux guests. */
3770 cbMax = ataBE2H_U16(pbPacket + 7);
3771 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_CONFIGURATION);
3772 break;
3773 case SCSI_INQUIRY:
3774 cbMax = pbPacket[4];
3775 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_INQUIRY);
3776 break;
3777 default:
3778 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
3779 break;
3780 }
3781
3782 return rc;
3783}
3784
3785/**
3786 * Reset all values after a reset of the attached storage device.
3787 *
3788 * @returns nothing
3789 * @param pAhciPort The port the device is attached to.
3790 * @param pAhciPortTaskState The state to get the tag number from.
3791 */
3792static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3793{
3794 /* Send a status good D2H FIS. */
3795 pAhciPort->fResetDevice = false;
3796 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3797 ahciPostFirstD2HFisIntoMemory(pAhciPort);
3798
3799 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
3800 pAhciPort->regSIG = 0x101;
3801 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3802
3803 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
3804}
3805
3806/**
3807 * Build a D2H FIS and post into the memory area of the guest.
3808 *
3809 * @returns Nothing
3810 * @param pAhciPort The port of the SATA controller.
3811 * @param pAhciPortTaskState The state of the task.
3812 * @param pCmdFis Pointer to the command FIS from the guest.
3813 * @param fInterrupt If an interrupt should be send to the guest.
3814 */
3815static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis, bool fInterrupt)
3816{
3817 uint8_t d2hFis[20];
3818 bool fAssertIntr = false;
3819 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3820
3821 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
3822
3823 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3824 {
3825 memset(&d2hFis[0], 0, sizeof(d2hFis));
3826 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
3827 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3828 d2hFis[AHCI_CMDFIS_STS] = pAhciPortTaskState->uATARegStatus;
3829 d2hFis[AHCI_CMDFIS_ERR] = pAhciPortTaskState->uATARegError;
3830 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3831 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3832 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3833 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3834 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3835 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3836 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3837 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3838 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3839
3840 /* Update registers. */
3841 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3842
3843 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
3844
3845 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3846 {
3847 /* Error bit is set. */
3848 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3849 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3850 fAssertIntr = true;
3851 }
3852
3853 if (fInterrupt)
3854 {
3855 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
3856 /* Check if we should assert an interrupt */
3857 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
3858 fAssertIntr = true;
3859 }
3860
3861 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3862
3863 if (fAssertIntr)
3864 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3865 }
3866}
3867
3868/**
3869 * Build a SDB Fis and post it into the memory area of the guest.
3870 *
3871 * @returns Nothing
3872 * @param pAhciPort The port for which the SDB Fis is send.
3873 * @param uFinishedTasks Bitmask of finished tasks.
3874 * @param pAhciPortTaskState The state of the last task.
3875 * @param fInterrupt If an interrupt should be asserted.
3876 */
3877static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
3878{
3879 uint32_t sdbFis[2];
3880 bool fAssertIntr = false;
3881 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3882
3883 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3884
3885 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3886 {
3887 memset(&sdbFis[0], 0, sizeof(sdbFis));
3888 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3889 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3890 sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3891 sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3892 sdbFis[1] = uFinishedTasks;
3893
3894 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3895
3896 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3897 {
3898 /* Error bit is set. */
3899 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3900 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3901 fAssertIntr = true;
3902 }
3903
3904 if (fInterrupt)
3905 {
3906 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
3907 /* Check if we should assert an interrupt */
3908 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
3909 fAssertIntr = true;
3910 }
3911
3912 /* Update registers. */
3913 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3914
3915 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3916
3917 if (fAssertIntr)
3918 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3919 }
3920}
3921
3922static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
3923{
3924 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
3925 if (fLBA48)
3926 {
3927 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
3928 return 65536;
3929 else
3930 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
3931 }
3932 else
3933 {
3934 if (!pCmdFis[AHCI_CMDFIS_SECTC])
3935 return 256;
3936 else
3937 return pCmdFis[AHCI_CMDFIS_SECTC];
3938 }
3939}
3940
3941static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
3942{
3943 uint64_t iLBA;
3944 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
3945 {
3946 /* any LBA variant */
3947 if (fLBA48)
3948 {
3949 /* LBA48 */
3950 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3951 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3952 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3953 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3954 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3955 pCmdFis[AHCI_CMDFIS_SECTN];
3956 }
3957 else
3958 {
3959 /* LBA */
3960 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3961 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
3962 }
3963 }
3964 else
3965 {
3966 /* CHS */
3967 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
3968 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
3969 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
3970 }
3971 return iLBA;
3972}
3973
3974static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
3975{
3976 uint64_t uLBA;
3977
3978 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3979 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3980 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3981 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3982 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3983 pCmdFis[AHCI_CMDFIS_SECTN];
3984
3985 return uLBA;
3986}
3987
3988DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
3989{
3990 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
3991 return 65536;
3992 else
3993 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
3994}
3995
3996DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
3997{
3998 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
3999}
4000
4001static int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
4002{
4003 if (pAhciPortTaskState->cSGListSize < cSGList)
4004 {
4005 /* The entries are not allocated yet or the number is too small. */
4006 if (pAhciPortTaskState->cSGListSize)
4007 {
4008 RTMemFree(pAhciPortTaskState->pSGListHead);
4009 RTMemFree(pAhciPortTaskState->paSGEntries);
4010 }
4011
4012 /* Allocate R3 scatter gather list. */
4013 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
4014 if (!pAhciPortTaskState->pSGListHead)
4015 return VERR_NO_MEMORY;
4016
4017 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
4018 if (!pAhciPortTaskState->paSGEntries)
4019 return VERR_NO_MEMORY;
4020
4021 /* Reset usage statistics. */
4022 pAhciPortTaskState->cSGListSize = cSGList;
4023 pAhciPortTaskState->cSGListTooBig = 0;
4024 }
4025 else if (pAhciPortTaskState->cSGListSize > cSGList)
4026 {
4027 /*
4028 * The list is too big. Increment counter.
4029 * So that the destroying function can free
4030 * the list if it is too big too many times
4031 * in a row.
4032 */
4033 pAhciPortTaskState->cSGListTooBig++;
4034 }
4035 else
4036 {
4037 /*
4038 * Needed entries matches current size.
4039 * Reset counter.
4040 */
4041 pAhciPortTaskState->cSGListTooBig = 0;
4042 }
4043
4044 pAhciPortTaskState->cSGEntries = cSGList;
4045
4046 if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4047 {
4048 if (pAhciPortTaskState->pvBufferUnaligned)
4049 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4050
4051 Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4052
4053 pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
4054 if (!pAhciPortTaskState->pvBufferUnaligned)
4055 return VERR_NO_MEMORY;
4056
4057 pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
4058 }
4059
4060 /* Make debugging easier. */
4061#ifdef DEBUG
4062 memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
4063 memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4064 if (pAhciPortTaskState->pvBufferUnaligned)
4065 memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4066#endif
4067
4068 return VINF_SUCCESS;
4069}
4070
4071/**
4072 * Create scatter gather list descriptors.
4073 *
4074 * @returns VBox status code.
4075 * @param pAhciPort The ahci port.
4076 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4077 * @param fReadonly If the mappings should be readonly.
4078 * @thread EMT
4079 */
4080static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly)
4081{
4082 int rc = VINF_SUCCESS;
4083 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4084 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4085 unsigned cActualSGEntry;
4086 unsigned cSGEntriesR3 = 0; /* Needed scatter gather list entries in R3. */
4087 SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
4088 unsigned cSGLEntriesGCRead;
4089 unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
4090 RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
4091 uint32_t cbSegment; /* Size of the current segments in bytes. */
4092 bool fUnaligned; /* Flag whether the current buffer is unaligned. */
4093 uint32_t cbUnaligned; /* Size of the unaligned buffers. */
4094 uint32_t cUnaligned;
4095 bool fDoMapping = false;
4096 RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
4097 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
4098 PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
4099 PPDMDATASEG pSGEntryCurr = NULL;
4100 PPDMDATASEG pSGEntryPrev = NULL;
4101 RTGCPHYS GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4102 uint8_t *pu8BufferUnalignedPos = NULL;
4103 uint32_t cbUnalignedComplete = 0;
4104
4105 STAM_PROFILE_START(&pAhciPort->StatProfileMapIntoR3, a);
4106
4107 /*
4108 * 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
4109 * page aligned. Hence the number of SG list entries in the guest can differ from the ones we need
4110 * because PDMDevHlpPhysGCPhys2CCPtr works only on a page base.
4111 * In the first pass we calculate the number of segments in R3 and in the second pass we map the guest segments into R3.
4112 */
4113 for (int i = 0; i < 2; i++)
4114 {
4115 cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4116 ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
4117
4118 /* Set start address of the entries. */
4119 GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4120 fUnaligned = false;
4121 cbUnaligned = 0;
4122 cUnaligned = 0;
4123 GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4124
4125 if (fDoMapping)
4126 {
4127 ahciLog(("%s: cSGEntriesR3=%u\n", __FUNCTION__, cSGEntriesR3));
4128 /* The number of needed SG entries in R3 is known. Allocate needed memory. */
4129 rc = ahciScatterGatherListAllocate(pAhciPortTaskState, cSGEntriesR3, cbUnalignedComplete);
4130 AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc));
4131
4132 /* We are now able to map the pages into R3. */
4133 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4134 pSGEntryCurr = pAhciPortTaskState->pSGListHead;
4135 pSGEntryPrev = pSGEntryCurr;
4136 pSGInfoPrev = pSGInfoCurr;
4137 /* Initialize first segment to remove the need for additional if checks later in the code. */
4138 pSGEntryCurr->pvSeg = NULL;
4139 pSGEntryCurr->cbSeg = 0;
4140 pSGInfoCurr->fGuestMemory= false;
4141 pu8BufferUnalignedPos = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
4142 }
4143
4144 do
4145 {
4146 cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
4147 cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4148
4149 /* Read the SG entries. */
4150 PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4151
4152 for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
4153 {
4154 RTGCPHYS GCPhysAddrDataBase;
4155 uint32_t cbDataToTransfer;
4156
4157 ahciLog(("%s: cActualSGEntry=%u cSGEntriesR3=%u\n", __FUNCTION__, cActualSGEntry, cSGEntriesR3));
4158
4159 cbDataToTransfer = (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4160 ahciLog(("%s: cbDataToTransfer=%u\n", __FUNCTION__, cbDataToTransfer));
4161
4162 /* Check if the buffer is sector aligned. */
4163 if (cbDataToTransfer % 512 != 0)
4164 {
4165 if (!fUnaligned)
4166 {
4167 /* We are not in an unaligned buffer but this is the first unaligned one. */
4168 fUnaligned = true;
4169 cbUnaligned = cbDataToTransfer;
4170 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4171 cSGEntriesR3++;
4172 cUnaligned = 1;
4173 ahciLog(("%s: Unaligned buffer found cb=%d\n", __FUNCTION__, cbDataToTransfer));
4174 }
4175 else
4176 {
4177 /* We are already in an unaligned buffer and this one is unaligned too. */
4178 cbUnaligned += cbDataToTransfer;
4179 cUnaligned++;
4180 }
4181
4182 cbUnalignedComplete += cbDataToTransfer;
4183 }
4184 else /* Guest segment size is sector aligned. */
4185 {
4186 if (fUnaligned)
4187 {
4188 if (cbUnaligned % 512 == 0)
4189 {
4190 /*
4191 * The last buffer started at an offset
4192 * not aligned to a sector boundary but this buffer
4193 * is sector aligned. Check if the current size of all
4194 * unaligned segments is a multiple of a sector.
4195 * If that's the case we can now map the segments again into R3.
4196 */
4197 fUnaligned = false;
4198
4199 if (fDoMapping)
4200 {
4201 /* Set up the entry. */
4202 pSGInfoCurr->fGuestMemory = false;
4203 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4204 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4205 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4206
4207 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4208 pSGEntryCurr->cbSeg = cbUnaligned;
4209 pu8BufferUnalignedPos += cbUnaligned;
4210
4211 /*
4212 * If the transfer is to the device we need to copy the content of the not mapped guest
4213 * segments into the temporary buffer.
4214 */
4215 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4216 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4217
4218 /* Advance to next entry saving the pointers to the current ones. */
4219 pSGEntryPrev = pSGEntryCurr;
4220 pSGInfoPrev = pSGInfoCurr;
4221 pSGInfoCurr++;
4222 pSGEntryCurr++;
4223 }
4224 }
4225 else
4226 {
4227 cbUnaligned += cbDataToTransfer;
4228 cbUnalignedComplete += cbDataToTransfer;
4229 cUnaligned++;
4230 }
4231 }
4232 else
4233 {
4234 /*
4235 * The size of the guest segment is sector aligned but it is possible that the segment crosses
4236 * a page boundary in a way splitting the segment into parts which are not sector aligned.
4237 * We have to treat them like unaligned guest segments then.
4238 */
4239 GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntry[cActualSGEntry].u32DBAUp, aSGLEntry[cActualSGEntry].u32DBA);
4240
4241 ahciLog(("%s: GCPhysAddrDataBase=%RGp\n", __FUNCTION__, GCPhysAddrDataBase));
4242
4243 /*
4244 * Check if the physical address is page aligned.
4245 */
4246 if (GCPhysAddrDataBase & PAGE_OFFSET_MASK)
4247 {
4248 RTGCPHYS GCPhysAddrDataNextPage = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase) + PAGE_SIZE;
4249 /* Difference from the buffer start to the next page boundary. */
4250 uint32_t u32GCPhysAddrDiff = GCPhysAddrDataNextPage - GCPhysAddrDataBase;
4251
4252 if (u32GCPhysAddrDiff % 512 != 0)
4253 {
4254 if (!fUnaligned)
4255 {
4256 /* We are not in an unaligned buffer but this is the first unaligned one. */
4257 fUnaligned = true;
4258 cbUnaligned = cbDataToTransfer;
4259 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4260 cSGEntriesR3++;
4261 cUnaligned = 1;
4262 ahciLog(("%s: Guest segment is sector aligned but crosses a page boundary cb=%d\n", __FUNCTION__, cbDataToTransfer));
4263 }
4264 else
4265 {
4266 /* We are already in an unaligned buffer and this one is unaligned too. */
4267 cbUnaligned += cbDataToTransfer;
4268 cUnaligned++;
4269 }
4270
4271 cbUnalignedComplete += cbDataToTransfer;
4272 }
4273 else
4274 {
4275 ahciLog(("%s: Align page: GCPhysAddrDataBase=%RGp GCPhysAddrDataNextPage=%RGp\n",
4276 __FUNCTION__, GCPhysAddrDataBase, GCPhysAddrDataNextPage));
4277
4278 RTGCPHYS GCPhysBufferPageAligned = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase);
4279
4280 /* Check if the mapping ends at the page boundary and set segment size accordingly. */
4281 cbSegment = (cbDataToTransfer < u32GCPhysAddrDiff)
4282 ? cbDataToTransfer
4283 : u32GCPhysAddrDiff;
4284 /* Subtract size of the buffer in the actual page. */
4285 cbDataToTransfer -= cbSegment;
4286
4287 if (GCPhysBufferPageAlignedPrev != GCPhysBufferPageAligned)
4288 {
4289 /* We don't need to map the buffer if it is in the same page as the previous one. */
4290 if (fDoMapping)
4291 {
4292 uint8_t *pbMapping;
4293
4294 pSGInfoCurr->fGuestMemory = true;
4295
4296 /* Create the mapping. */
4297 if (fReadonly)
4298 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysBufferPageAligned,
4299 0, (const void **)&pbMapping,
4300 &pSGInfoCurr->u.direct.PageLock);
4301 else
4302 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysBufferPageAligned,
4303 0, (void **)&pbMapping,
4304 &pSGInfoCurr->u.direct.PageLock);
4305
4306 if (RT_FAILURE(rc))
4307 AssertMsgFailed(("Creating mapping failed rc=%Rrc\n", rc));
4308
4309 if ((pbMapping + (GCPhysAddrDataBase - GCPhysBufferPageAligned) == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryCurr->cbSeg)))
4310 {
4311 pSGEntryPrev->cbSeg += cbSegment;
4312 ahciLog(("%s: Merged mapping pbMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4313 __FUNCTION__, pbMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4314 }
4315 else
4316 {
4317 pSGEntryCurr->cbSeg = cbSegment;
4318
4319 /* Let pvBuf point to the start of the buffer in the page. */
4320 pSGEntryCurr->pvSeg = pbMapping
4321 + (GCPhysAddrDataBase - GCPhysBufferPageAligned);
4322
4323 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4324 pSGEntryCurr->pvSeg,
4325 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4326
4327 pSGEntryPrev = pSGEntryCurr;
4328 pSGEntryCurr++;
4329 }
4330
4331 pSGInfoPrev = pSGInfoCurr;
4332 pSGInfoCurr++;
4333 }
4334 else
4335 cSGEntriesR3++;
4336 }
4337 else if (fDoMapping)
4338 {
4339 pSGEntryPrev->cbSeg += cbSegment;
4340 ahciLog(("%s: Buffer is already in previous mapping pvSeg=%#p. New size is cbSeg=%d\n",
4341 __FUNCTION__, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4342 }
4343
4344 /* Let physical address point to the next page in the buffer. */
4345 GCPhysAddrDataBase = GCPhysAddrDataNextPage;
4346 GCPhysBufferPageAlignedPrev = GCPhysBufferPageAligned;
4347 }
4348 }
4349
4350 if (!fUnaligned)
4351 {
4352 /* The address is now page aligned. */
4353 while (cbDataToTransfer)
4354 {
4355 ahciLog(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u cSGEntriesR3=%u\n",
4356 __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer, cSGEntriesR3));
4357
4358 /* Check if this is the last page the buffer is in. */
4359 cbSegment = (cbDataToTransfer < PAGE_SIZE) ? cbDataToTransfer : PAGE_SIZE;
4360 cbDataToTransfer -= cbSegment;
4361
4362 if (fDoMapping)
4363 {
4364 void *pvMapping;
4365
4366 pSGInfoCurr->fGuestMemory = true;
4367
4368 /* Create the mapping. */
4369 if (fReadonly)
4370 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysAddrDataBase, 0, (const void **)&pvMapping, &pSGInfoCurr->u.direct.PageLock);
4371 else
4372 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrDataBase, 0, &pvMapping, &pSGInfoCurr->u.direct.PageLock);
4373
4374 if (RT_FAILURE(rc))
4375 AssertMsgFailed(("Creating mapping failed rc=%Rrc\n", rc));
4376
4377 /* Check for adjacent mappings. */
4378 if (pvMapping == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryPrev->cbSeg)
4379 && (pSGInfoPrev->fGuestMemory == true))
4380 {
4381 /* Yes they are adjacent. Just add the size of this mapping to the previous segment. */
4382 pSGEntryPrev->cbSeg += cbSegment;
4383 ahciLog(("%s: Merged mapping pvMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4384 __FUNCTION__, pvMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4385 }
4386 else
4387 {
4388 /* No they are not. Use a new sg entry. */
4389 pSGEntryCurr->cbSeg = cbSegment;
4390 pSGEntryCurr->pvSeg = pvMapping;
4391 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4392 pSGEntryCurr->pvSeg,
4393 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4394 pSGEntryPrev = pSGEntryCurr;
4395 pSGEntryCurr++;
4396 }
4397
4398 pSGInfoPrev = pSGInfoCurr;
4399 pSGInfoCurr++;
4400 }
4401 else
4402 cSGEntriesR3++;
4403
4404 GCPhysBufferPageAlignedPrev = GCPhysAddrDataBase;
4405
4406 /* Go to the next page. */
4407 GCPhysAddrDataBase += PAGE_SIZE;
4408 }
4409 } /* if (!fUnaligned) */
4410 } /* if !fUnaligned */
4411 } /* if guest segment is sector aligned. */
4412 } /* for SGEntries read */
4413
4414 /* Set address to the next entries to read. */
4415 GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
4416
4417 } while (cSGLEntriesGCLeft);
4418
4419 fDoMapping = true;
4420
4421 } /* for passes */
4422
4423 /* Check if the last processed segment was unaligned. We need to add it now. */
4424 if (fUnaligned)
4425 {
4426 /* Set up the entry. */
4427 AssertMsg(!(cbUnaligned % 512), ("Buffer is not sector aligned\n"));
4428 pSGInfoCurr->fGuestMemory = false;
4429 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4430 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4431 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4432
4433 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4434 pSGEntryCurr->cbSeg = cbUnaligned;
4435
4436 /*
4437 * If the transfer is to the device we need to copy the content of the not mapped guest
4438 * segments into the temporary buffer.
4439 */
4440 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4441 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4442 }
4443
4444 STAM_PROFILE_STOP(&pAhciPort->StatProfileMapIntoR3, a);
4445
4446 return rc;
4447}
4448
4449/**
4450 * Destroy a scatter gather list and free all occupied resources (mappings, etc.)
4451 *
4452 * @returns VBox status code.
4453 * @param pAhciPort The ahci port.
4454 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4455 */
4456static int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4457{
4458 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4459 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4460
4461 STAM_PROFILE_START(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4462
4463 for (unsigned cActualSGEntry = 0; cActualSGEntry < pAhciPortTaskState->cSGEntries; cActualSGEntry++)
4464 {
4465 if (pSGInfoCurr->fGuestMemory)
4466 {
4467 /* Release the lock. */
4468 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4469 }
4470 else if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4471 {
4472 /* Copy the data into the guest segments now. */
4473 ahciCopyFromBufferIntoSGList(pDevIns, pSGInfoCurr);
4474 }
4475
4476 /* Go to the next entry. */
4477 pSGInfoCurr++;
4478 }
4479
4480 /* Free allocated memory if the list was too big too many times. */
4481 if (pAhciPortTaskState->cSGListTooBig >= AHCI_NR_OF_ALLOWED_BIGGER_LISTS)
4482 {
4483 RTMemFree(pAhciPortTaskState->pSGListHead);
4484 RTMemFree(pAhciPortTaskState->paSGEntries);
4485 if (pAhciPortTaskState->pvBufferUnaligned)
4486 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4487 pAhciPortTaskState->cSGListSize = 0;
4488 pAhciPortTaskState->cSGListTooBig = 0;
4489 pAhciPortTaskState->pSGListHead = NULL;
4490 pAhciPortTaskState->paSGEntries = NULL;
4491 pAhciPortTaskState->pvBufferUnaligned = NULL;
4492 pAhciPortTaskState->cbBufferUnaligned = 0;
4493 }
4494
4495 STAM_PROFILE_STOP(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4496
4497 return VINF_SUCCESS;
4498}
4499
4500/**
4501 * Copy a temporary buffer into a part of the guest scatter gather list
4502 * described by the given descriptor entry.
4503 *
4504 * @returns nothing.
4505 * @param pDevIns Pointer to the device instance data.
4506 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4507 * to write to which are unaligned.
4508 */
4509static void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4510{
4511 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4512 SGLEntry aSGLEntries[5];
4513 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4514 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4515
4516 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4517
4518 do
4519 {
4520 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4521 ? cSGEntriesLeft
4522 : RT_ELEMENTS(aSGLEntries);
4523
4524 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4525
4526 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4527 {
4528 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4529 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4530
4531 /* Copy into SG entry. */
4532 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4533
4534 pu8Buf += cbCopied;
4535 }
4536
4537 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4538 cSGEntriesLeft -= cSGEntriesRead;
4539 } while (cSGEntriesLeft);
4540}
4541
4542/**
4543 * Copy a part of the guest scatter gather list into a temporary buffer.
4544 *
4545 * @returns nothing.
4546 * @param pDevIns Pointer to the device instance data.
4547 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4548 * to read from which are unaligned.
4549 */
4550static void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4551{
4552 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4553 SGLEntry aSGLEntries[5];
4554 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4555 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4556
4557 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4558
4559 do
4560 {
4561 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4562 ? cSGEntriesLeft
4563 : RT_ELEMENTS(aSGLEntries);
4564
4565 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4566
4567 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4568 {
4569 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4570 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4571
4572 /* Copy into buffer. */
4573 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4574
4575 pu8Buf += cbCopied;
4576 }
4577
4578 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4579 cSGEntriesLeft -= cSGEntriesRead;
4580 } while (cSGEntriesLeft);
4581}
4582
4583
4584/**
4585 * Copy the content of a buffer to a scatter gather list.
4586 *
4587 * @returns VBox status code.
4588 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4589 * @param pvBuf Pointer to the buffer which should be copied.
4590 * @param cbBuf Size of the buffer.
4591 */
4592static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf)
4593{
4594 unsigned cSGEntry = 0;
4595 PPDMDATASEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
4596 uint8_t *pu8Buf = (uint8_t *)pvBuf;
4597
4598 while (cSGEntry < pAhciPortTaskState->cSGEntries)
4599 {
4600 size_t cbToCopy = (cbBuf < pSGEntry->cbSeg) ? cbBuf : pSGEntry->cbSeg;
4601
4602 memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
4603
4604 cbBuf -= cbToCopy;
4605 /* We finished. */
4606 if (!cbBuf)
4607 break;
4608
4609 /* Advance the buffer. */
4610 pu8Buf += cbToCopy;
4611
4612 /* Go to the next entry in the list. */
4613 pSGEntry++;
4614 cSGEntry++;
4615 }
4616
4617#if 0
4618 if (!pAhciPort->fATAPI)
4619 AssertMsg(!cbBuf, ("There is still data in the buffer\n"));
4620#endif
4621 return VINF_SUCCESS;
4622}
4623
4624/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
4625
4626/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
4627#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
4628
4629/**
4630 * Complete a data transfer task by freeing all occupied ressources
4631 * and notifying the guest.
4632 *
4633 * @returns VBox status code
4634 *
4635 * @param pAhciPort Pointer to the port where to request completed.
4636 * @param pAhciPortTaskState Pointer to the task which finished.
4637 */
4638static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4639{
4640 /* Free system resources occupied by the scatter gather list. */
4641 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4642
4643 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4644
4645 pAhciPortTaskState->uATARegError = 0;
4646 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4647 /* Write updated command header into memory of the guest. */
4648 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4649 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4650
4651 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4652 {
4653 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
4654 pAhciPort->Led.Actual.s.fReading = 0;
4655 }
4656 else
4657 {
4658 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
4659 pAhciPort->Led.Actual.s.fWriting = 0;
4660 }
4661
4662 if (pAhciPortTaskState->fQueued)
4663 {
4664 uint32_t cOutstandingTasks;
4665
4666 ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
4667 cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
4668 ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
4669 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
4670
4671 if (!cOutstandingTasks)
4672 ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
4673 }
4674 else
4675 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
4676
4677 /* Add the task to the cache. */
4678 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
4679
4680 return VINF_SUCCESS;
4681}
4682
4683/**
4684 * Notification callback for a completed transfer.
4685 *
4686 * @returns VBox status code.
4687 * @param pInterface Pointer to the interface.
4688 * @param pvUser User data.
4689 */
4690static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
4691{
4692 PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
4693 PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
4694
4695 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
4696 __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
4697
4698 return ahciTransferComplete(pAhciPort, pAhciPortTaskState);
4699}
4700
4701/**
4702 * Process an non read/write ATA command.
4703 *
4704 * @returns The direction of the data transfer
4705 * @param pCmdHdr Pointer to the command header.
4706 */
4707static int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
4708{
4709 int rc = PDMBLOCKTXDIR_NONE;
4710 bool fLBA48 = false;
4711 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4712
4713 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
4714
4715 switch (pCmdFis[AHCI_CMDFIS_CMD])
4716 {
4717 case ATA_IDENTIFY_DEVICE:
4718 {
4719 if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
4720 {
4721 uint16_t u16Temp[256];
4722
4723 /* Fill the buffer. */
4724 ahciIdentifySS(pAhciPort, u16Temp);
4725
4726 /* Create scatter gather list. */
4727 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
4728 if (RT_FAILURE(rc))
4729 AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
4730
4731 /* Copy the buffer. */
4732 rc = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
4733 if (RT_FAILURE(rc))
4734 AssertMsgFailed(("Copying failed rc=%Rrc\n", rc));
4735
4736 /* Destroy list. */
4737 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4738 if (RT_FAILURE(rc))
4739 AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
4740
4741 pAhciPortTaskState->uATARegError = 0;
4742 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4743 pCmdHdr->u32PRDBC = sizeof(u16Temp);
4744
4745 /* Write updated command header into memory of the guest. */
4746 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
4747 }
4748 else
4749 {
4750 pAhciPortTaskState->uATARegError = ABRT_ERR;
4751 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4752 }
4753 break;
4754 }
4755 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
4756 case ATA_READ_NATIVE_MAX_ADDRESS:
4757 break;
4758 case ATA_SET_FEATURES:
4759 {
4760 switch (pCmdFis[AHCI_CMDFIS_FET])
4761 {
4762 case 0x02: /* write cache enable */
4763 case 0xaa: /* read look-ahead enable */
4764 case 0x55: /* read look-ahead disable */
4765 case 0xcc: /* reverting to power-on defaults enable */
4766 case 0x66: /* reverting to power-on defaults disable */
4767 pAhciPortTaskState->uATARegError = 0;
4768 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4769 break;
4770 case 0x82: /* write cache disable */
4771 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4772 pAhciPortTaskState->uATARegError = 0;
4773 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4774 break;
4775 case 0x03:
4776 { /* set transfer mode */
4777 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4778 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
4779 {
4780 case 0x00: /* PIO default */
4781 case 0x08: /* PIO mode */
4782 break;
4783 case ATA_MODE_MDMA: /* MDMA mode */
4784 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
4785 break;
4786 case ATA_MODE_UDMA: /* UDMA mode */
4787 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
4788 break;
4789 }
4790 break;
4791 }
4792 default:
4793 pAhciPortTaskState->uATARegError = ABRT_ERR;
4794 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4795 }
4796 break;
4797 }
4798 case ATA_FLUSH_CACHE_EXT:
4799 case ATA_FLUSH_CACHE:
4800 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4801 pAhciPortTaskState->uATARegError = 0;
4802 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4803 break;
4804 case ATA_PACKET:
4805 if (!pAhciPort->fATAPI)
4806 {
4807 pAhciPortTaskState->uATARegError = ABRT_ERR;
4808 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4809 }
4810 else
4811 {
4812 rc = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
4813 }
4814 break;
4815 case ATA_IDENTIFY_PACKET_DEVICE:
4816 if (!pAhciPort->fATAPI)
4817 {
4818 pAhciPortTaskState->uATARegError = ABRT_ERR;
4819 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4820 }
4821 else
4822 {
4823 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_IDENTIFY);
4824
4825 pAhciPortTaskState->uATARegError = 0;
4826 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4827 }
4828 break;
4829 case ATA_SET_MULTIPLE_MODE:
4830 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
4831 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
4832 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
4833 {
4834 pAhciPortTaskState->uATARegError = ABRT_ERR;
4835 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4836 }
4837 else
4838 {
4839 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4840 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
4841 pAhciPortTaskState->uATARegError = 0;
4842 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4843 }
4844 break;
4845 case ATA_STANDBY_IMMEDIATE:
4846 break; /* Do nothing. */
4847 case ATA_CHECK_POWER_MODE:
4848 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
4849 /* fall through */
4850 case ATA_INITIALIZE_DEVICE_PARAMETERS:
4851 case ATA_IDLE_IMMEDIATE:
4852 case ATA_RECALIBRATE:
4853 case ATA_NOP:
4854 case ATA_READ_VERIFY_SECTORS_EXT:
4855 case ATA_READ_VERIFY_SECTORS:
4856 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
4857 pAhciPortTaskState->uATARegError = 0;
4858 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4859 break;
4860 case ATA_READ_DMA_EXT:
4861 fLBA48 = true;
4862 case ATA_READ_DMA:
4863 {
4864 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
4865 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
4866 rc = PDMBLOCKTXDIR_FROM_DEVICE;
4867 break;
4868 }
4869 case ATA_WRITE_DMA_EXT:
4870 fLBA48 = true;
4871 case ATA_WRITE_DMA:
4872 {
4873 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
4874 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
4875 rc = PDMBLOCKTXDIR_TO_DEVICE;
4876 break;
4877 }
4878 case ATA_READ_FPDMA_QUEUED:
4879 {
4880 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
4881 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
4882 rc = PDMBLOCKTXDIR_FROM_DEVICE;
4883 break;
4884 }
4885 case ATA_WRITE_FPDMA_QUEUED:
4886 {
4887 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
4888 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
4889 rc = PDMBLOCKTXDIR_TO_DEVICE;
4890 break;
4891 }
4892 /* All not implemented commands go below. */
4893 case ATA_SECURITY_FREEZE_LOCK:
4894 case ATA_SMART:
4895 case ATA_NV_CACHE:
4896 case ATA_SLEEP: /* Powermanagement not supported. */
4897 pAhciPortTaskState->uATARegError = ABRT_ERR;
4898 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4899 break;
4900 default: /* For debugging purposes. */
4901 AssertMsgFailed(("Unknown command issued\n"));
4902 pAhciPortTaskState->uATARegError = ABRT_ERR;
4903 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4904 }
4905
4906 return rc;
4907}
4908
4909/**
4910 * Retrieve a command FIS from guest memory.
4911 *
4912 * @returns nothing
4913 * @param pAhciPortTaskState The state of the actual task.
4914 */
4915static void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4916{
4917 RTGCPHYS GCPhysAddrCmdTbl;
4918
4919 AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
4920
4921 /*
4922 * First we are reading the command header pointed to by regCLB.
4923 * From this we get the address of the command table which we are reading too.
4924 * We can process the Command FIS afterwards.
4925 */
4926 pAhciPortTaskState->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciPortTaskState->uTag * sizeof(CmdHdr);
4927 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
4928 pAhciPortTaskState->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
4929 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4930
4931#ifdef DEBUG
4932 /* Print some infos about the command header. */
4933 ahciDumpCmdHdrInfo(pAhciPort, &pAhciPortTaskState->cmdHdr);
4934#endif
4935
4936 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr);
4937
4938 AssertMsg((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
4939 ("This is not a command FIS!!\n"));
4940
4941 /* Read the command Fis. */
4942 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
4943 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
4944
4945 /* Set transfer direction. */
4946 pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
4947
4948 /* If this is an ATAPI command read the atapi command. */
4949 if (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
4950 {
4951 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
4952 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->aATAPICmd[0], ATAPI_PACKET_SIZE);
4953 }
4954
4955 /* We "received" the FIS. Clear the BSY bit in regTFD. */
4956 if ((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciPortTaskState->fQueued))
4957 {
4958 /*
4959 * 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.
4960 * but this FIS does not assert an interrupt
4961 */
4962 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, false);
4963 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
4964 }
4965
4966#ifdef DEBUG
4967 /* Print some infos about the FIS. */
4968 ahciDumpFisInfo(pAhciPort, &pAhciPortTaskState->cmdFis[0]);
4969
4970 /* Print the PRDT */
4971 RTGCPHYS GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4972
4973 ahciLog(("PRDT address %RGp number of entries %u\n", GCPhysAddrPRDTLEntryStart, AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf)));
4974
4975 for (unsigned i = 0; i < AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf); i++)
4976 {
4977 SGLEntry SGEntry;
4978
4979 ahciLog(("Entry %u at address %RGp\n", i, GCPhysAddrPRDTLEntryStart));
4980 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrPRDTLEntryStart, &SGEntry, sizeof(SGLEntry));
4981
4982 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
4983 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
4984
4985 GCPhysAddrPRDTLEntryStart += sizeof(SGLEntry);
4986 }
4987#endif
4988}
4989
4990/**
4991 * Transmit queue consumer
4992 * Queue a new async task.
4993 *
4994 * @returns Success indicator.
4995 * If false the item will not be removed and the flushing will stop.
4996 * @param pDevIns The device instance.
4997 * @param pItem The item to consume. Upon return this item will be freed.
4998 */
4999static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5000{
5001 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
5002 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5003 PAHCIPort pAhciPort = &pAhci->ahciPort[pNotifierItem->iPort];
5004 int rc = VINF_SUCCESS;
5005
5006 if (!pAhciPort->fAsyncInterface)
5007 {
5008 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
5009 /* Notify the async IO thread. */
5010 rc = RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5011 AssertRC(rc);
5012 }
5013 else
5014 {
5015 int iTxDir;
5016 PAHCIPORTTASKSTATE pAhciPortTaskState;
5017
5018 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
5019
5020 /* Check if there is already an allocated task struct in the cache.
5021 * Allocate a new task otherwise.
5022 */
5023 if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
5024 {
5025 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5026 AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
5027 }
5028 else
5029 {
5030 pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
5031 }
5032
5033 /** Set current command slot */
5034 pAhciPortTaskState->uTag = pNotifierItem->iTask;
5035 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5036
5037 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5038
5039 /* 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. */
5040 if (pNotifierItem->fQueued)
5041 {
5042 pAhciPortTaskState->fQueued = true;
5043 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5044 }
5045 else
5046 pAhciPortTaskState->fQueued = false;
5047
5048 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5049 {
5050 /* If the reset bit is set put the device into reset state. */
5051 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5052 {
5053 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5054 pAhciPort->fResetDevice = true;
5055 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
5056 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5057 return true;
5058 }
5059 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5060 {
5061 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5062 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5063 return true;
5064 }
5065 else /* We are not in a reset state update the control registers. */
5066 {
5067 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
5068 }
5069 }
5070
5071 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5072
5073 if (iTxDir != PDMBLOCKTXDIR_NONE)
5074 {
5075 if (pAhciPortTaskState->fQueued)
5076 {
5077 ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5078 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
5079 ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5080 }
5081
5082 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5083
5084 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5085 if (RT_FAILURE(rc))
5086 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5087
5088 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5089 {
5090 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5091 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5092 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
5093 pAhciPortTaskState->cbTransfer,
5094 pAhciPortTaskState);
5095 }
5096 else
5097 {
5098 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5099 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5100 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
5101 pAhciPortTaskState->cbTransfer,
5102 pAhciPortTaskState);
5103 }
5104 if (rc == VINF_VD_ASYNC_IO_FINISHED)
5105 rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
5106
5107 if (RT_FAILURE(rc))
5108 AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
5109 }
5110 else
5111 {
5112 /* There is nothing left to do. Notify the guest. */
5113 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5114 /* Add the task to the cache. */
5115 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
5116 }
5117 }
5118
5119 return true;
5120}
5121
5122/* The async IO thread for one port. */
5123static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5124{
5125 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5126 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5127 PAHCIPORTTASKSTATE pAhciPortTaskState;
5128 int rc = VINF_SUCCESS;
5129 uint64_t u64StartTime = 0;
5130 uint64_t u64StopTime = 0;
5131 uint32_t uIORequestsProcessed = 0;
5132 uint32_t uIOsPerSec = 0;
5133
5134 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
5135
5136 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
5137 return VINF_SUCCESS;
5138
5139 /* We use only one task structure. */
5140 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5141 if (!pAhciPortTaskState)
5142 {
5143 AssertMsgFailed(("Failed to allocate task state memory\n"));
5144 return VERR_NO_MEMORY;
5145 }
5146
5147 while(pThread->enmState == PDMTHREADSTATE_RUNNING)
5148 {
5149 uint32_t uQueuedTasksFinished = 0;
5150
5151 /* New run to get number of I/O requests per second?. */
5152 if (!u64StartTime)
5153 u64StartTime = RTTimeMilliTS();
5154
5155 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
5156
5157 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
5158 if (rc == VERR_TIMEOUT)
5159 {
5160 /* No I/O requests inbetween. Reset statistics and wait again. */
5161 pAhciPort->StatIORequestsPerSecond.c = 0;
5162 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
5163 }
5164
5165 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
5166 break;
5167
5168 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
5169
5170 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
5171
5172 /*
5173 * To maximize the throughput of the controller we try to minimize the
5174 * number of world switches during interrupts by grouping as many
5175 * I/O requests together as possible.
5176 * On the other side we want to get minimal latency if the I/O load is low.
5177 * Thatswhy the number of I/O requests per second is measured and if it is over
5178 * a threshold the thread waits for other requests from the guest.
5179 */
5180 if (uIOsPerSec >= pAhci->cHighIOThreshold)
5181 {
5182 uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
5183
5184 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
5185
5186 do
5187 {
5188 /* Sleep some time. */
5189 RTThreadSleep(pAhci->cMillisToSleep);
5190 /* Check if we got some new requests inbetween. */
5191 if (uActWritePosPrev != pAhciPort->uActWritePos)
5192 {
5193 uActWritePosPrev = pAhciPort->uActWritePos;
5194 /*
5195 * Check if the queue is full. If that is the case
5196 * there is no point waiting another round.
5197 */
5198 if ( ( (pAhciPort->uActReadPos < uActWritePosPrev)
5199 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
5200 || ( (pAhciPort->uActReadPos > uActWritePosPrev)
5201 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) )
5202 {
5203 Log(("%s: Queue full -> leaving\n", __FUNCTION__));
5204 break;
5205 }
5206 Log(("%s: Another round\n", __FUNCTION__));
5207 }
5208 else /* No change break out of the loop. */
5209 {
5210#ifdef DEBUG
5211 uint8_t uQueuedTasks;
5212 if (pAhciPort->uActReadPos < uActWritePosPrev)
5213 uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
5214 else
5215 uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
5216
5217 Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
5218#endif
5219 break;
5220 }
5221 } while (true);
5222 }
5223
5224 ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
5225
5226 uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5227
5228 ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
5229
5230 /* Process commands. */
5231 while ( (cTasksToProcess > 0)
5232 && RT_LIKELY(!pAhciPort->fPortReset))
5233 {
5234 int iTxDir;
5235 uint8_t uActTag;
5236
5237 STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
5238
5239 ahciLog(("%s: uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
5240 ahciLog(("%s: Before uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5241
5242 pAhciPortTaskState->uATARegStatus = 0;
5243 pAhciPortTaskState->uATARegError = 0;
5244 uActTag = pAhciPort->ahciIOTasks[pAhciPort->uActReadPos];
5245
5246 pAhciPortTaskState->uTag = AHCI_TASK_GET_TAG(uActTag);
5247 AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number!!\n", __FUNCTION__));
5248
5249 /** Set current command slot */
5250 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5251
5252 /* 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. */
5253 if (AHCI_TASK_IS_QUEUED(uActTag))
5254 {
5255 pAhciPortTaskState->fQueued = true;
5256 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5257 }
5258 else
5259 {
5260 pAhciPortTaskState->fQueued = false;
5261 }
5262
5263 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5264
5265 ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciPortTaskState->uTag));
5266
5267 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5268 {
5269 /* If the reset bit is set put the device into reset state. */
5270 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5271 {
5272 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5273 pAhciPort->fResetDevice = true;
5274 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5275 }
5276 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5277 {
5278 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5279 }
5280 /* TODO: We are not in a reset state update the control registers. */
5281 }
5282 else
5283 {
5284 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5285
5286 if (iTxDir != PDMBLOCKTXDIR_NONE)
5287 {
5288 uint64_t uOffset;
5289 size_t cbTransfer;
5290 PPDMDATASEG pSegCurr;
5291 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
5292
5293 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5294 if (RT_FAILURE(rc))
5295 AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
5296
5297 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5298
5299 /* Initialize all values. */
5300 uOffset = pAhciPortTaskState->uOffset;
5301 cbTransfer = pAhciPortTaskState->cbTransfer;
5302 pSegCurr = &pAhciPortTaskState->pSGListHead[0];
5303 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
5304
5305 STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, a);
5306
5307 while(cbTransfer)
5308 {
5309 size_t cbProcess = (cbTransfer < pSegCurr->cbSeg) ? cbTransfer : pSegCurr->cbSeg;
5310
5311 AssertMsg(!(pSegCurr->cbSeg % 512), ("Buffer is not sector aligned cbSeg=%d\n", pSegCurr->cbSeg));
5312 AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
5313 AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
5314
5315 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5316 {
5317 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5318 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
5319 pSegCurr->pvSeg, cbProcess);
5320 pAhciPort->Led.Actual.s.fReading = 0;
5321 if (RT_FAILURE(rc))
5322 AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
5323
5324 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
5325 }
5326 else
5327 {
5328 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5329 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
5330 pSegCurr->pvSeg, cbProcess);
5331 pAhciPort->Led.Actual.s.fWriting = 0;
5332 if (RT_FAILURE(rc))
5333 AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
5334
5335 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbProcess);
5336 }
5337
5338 /* Go to the next entry. */
5339 uOffset += cbProcess;
5340 cbTransfer -= cbProcess;
5341 pSegCurr++;
5342 pSGInfoCurr++;
5343 }
5344
5345 STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
5346
5347 /* Cleanup. */
5348 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5349 if (RT_FAILURE(rc))
5350 AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
5351
5352 if (RT_LIKELY(!pAhciPort->fPortReset))
5353 {
5354 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
5355 pAhciPortTaskState->uATARegError = 0;
5356 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5357 /* Write updated command header into memory of the guest. */
5358 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
5359 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5360
5361 if (pAhciPortTaskState->fQueued)
5362 uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
5363 else
5364 {
5365 /* Task is not queued send D2H FIS */
5366 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5367 }
5368
5369 uIORequestsProcessed++;
5370 }
5371 }
5372 else
5373 {
5374 /* Nothing left to do. Notify the guest. */
5375 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5376 }
5377
5378 STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
5379 }
5380
5381#ifdef DEBUG
5382 /* Be paranoid. */
5383 memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
5384 memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
5385 pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
5386 pAhciPortTaskState->uOffset = 0;
5387 pAhciPortTaskState->cbTransfer = 0;
5388 /* Make the port number invalid making it easier to track down bugs. */
5389 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
5390#endif
5391
5392 pAhciPort->uActReadPos++;
5393 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
5394 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5395 cTasksToProcess--;
5396 if (!cTasksToProcess)
5397 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5398 }
5399
5400 if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5401 ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, true);
5402
5403 uQueuedTasksFinished = 0;
5404
5405 u64StopTime = RTTimeMilliTS();
5406 /* Check if one second has passed. */
5407 if (u64StopTime - u64StartTime >= 1000)
5408 {
5409 /* Calculate number of I/O requests per second. */
5410 uIOsPerSec = uIORequestsProcessed / ((u64StopTime - u64StartTime) / 1000);
5411 ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
5412 u64StartTime = 0;
5413 uIORequestsProcessed = 0;
5414 /* For the release statistics. There is no macro to set the counter to a specific value. */
5415 pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
5416 }
5417 }
5418
5419 /* Free task state memory */
5420 if (pAhciPortTaskState->pSGListHead)
5421 RTMemFree(pAhciPortTaskState->pSGListHead);
5422 if (pAhciPortTaskState->paSGEntries)
5423 RTMemFree(pAhciPortTaskState->paSGEntries);
5424 if (pAhciPortTaskState->pvBufferUnaligned)
5425 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
5426 RTMemFree(pAhciPortTaskState);
5427
5428 ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
5429 return rc;
5430}
5431
5432/**
5433 * Unblock the async I/O thread so it can respond to a state change.
5434 *
5435 * @returns VBox status code.
5436 * @param pDevIns The pcnet device instance.
5437 * @param pThread The send thread.
5438 */
5439static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5440{
5441 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5442 return RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5443}
5444
5445/**
5446 * Called when a media is mounted.
5447 *
5448 * @param pInterface Pointer to the interface structure containing the called function pointer.
5449 */
5450static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
5451{
5452 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5453 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
5454
5455 /* Ignore the call if we're called while being attached. */
5456 if (!pAhciPort->pDrvBlock)
5457 return;
5458
5459 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5460
5461 /*
5462 * Initialize registers
5463 */
5464 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS;
5465 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
5466 pAhciPort->regSERR |= AHCI_PORT_SERR_N;
5467 if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5468 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
5469}
5470
5471/**
5472 * Called when a media is unmounted
5473 * @param pInterface Pointer to the interface structure containing the called function pointer.
5474 */
5475static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
5476{
5477 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5478 Log(("%s:\n", __FUNCTION__));
5479
5480 pAhciPort->cTotalSectors = 0;
5481
5482 /*
5483 * Inform the guest about the removed device.
5484 */
5485 pAhciPort->regSSTS = 0;
5486 pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
5487 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
5488 pAhciPort->regSERR |= AHCI_PORT_SERR_N;
5489 if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5490 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
5491}
5492
5493/**
5494 * Destroy a driver instance.
5495 *
5496 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5497 * resources can be freed correctly.
5498 *
5499 * @param pDevIns The device instance data.
5500 */
5501static DECLCALLBACK(int) ahciDestruct(PPDMDEVINS pDevIns)
5502{
5503 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5504 int rc = VINF_SUCCESS;
5505 unsigned iActPort = 0;
5506
5507 /*
5508 * At this point the async I/O thread is suspended and will not enter
5509 * this module again. So, no coordination is needed here and PDM
5510 * will take care of terminating and cleaning up the thread.
5511 */
5512 if (PDMCritSectIsInitialized(&pAhci->lock))
5513 {
5514 TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
5515
5516 Log(("%s: Destruct every port\n", __FUNCTION__));
5517 for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
5518 {
5519 PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
5520
5521 if (pAhciPort->pAsyncIOThread)
5522 {
5523 /* Destroy the event semaphore. */
5524 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
5525 if (RT_FAILURE(rc))
5526 {
5527 Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
5528 }
5529 }
5530
5531 /* Free all cached tasks. */
5532 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
5533 {
5534 if (pAhciPort->aCachedTasks[i])
5535 {
5536 if (pAhciPort->aCachedTasks[i]->pSGListHead)
5537 RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
5538 if (pAhciPort->aCachedTasks[i]->paSGEntries)
5539 RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
5540
5541 RTMemFree(pAhciPort->aCachedTasks[i]);
5542 }
5543 }
5544 }
5545
5546 /* Destroy emulated ATA controllers. */
5547 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5548 ataControllerDestroy(&pAhci->aCts[i]);
5549
5550 PDMR3CritSectDelete(&pAhci->lock);
5551 }
5552
5553 return rc;
5554}
5555
5556/**
5557 * Configure the attached device for a port.
5558 *
5559 * @returns VBox status code
5560 * @param pDevIns The device instance data.
5561 * @param pAhciPort The port for which the device is to be configured.
5562 */
5563static int ahciConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
5564{
5565 int rc = VINF_SUCCESS;
5566 PDMBLOCKTYPE enmType;
5567
5568 /*
5569 * Query the block and blockbios interfaces.
5570 */
5571 pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
5572 if (!pAhciPort->pDrvBlock)
5573 {
5574 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
5575 return VERR_PDM_MISSING_INTERFACE;
5576 }
5577 pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
5578 if (!pAhciPort->pDrvBlockBios)
5579 {
5580 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
5581 return VERR_PDM_MISSING_INTERFACE;
5582 }
5583
5584 pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
5585
5586 /* Try to get the optional async block interface. */
5587 pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
5588
5589 /*
5590 * Validate type.
5591 */
5592 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
5593
5594 if ( enmType != PDMBLOCKTYPE_HARD_DISK
5595 && enmType != PDMBLOCKTYPE_CDROM
5596 && enmType != PDMBLOCKTYPE_DVD)
5597 {
5598 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
5599 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
5600 }
5601
5602 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
5603 && !pAhciPort->pDrvMount)
5604 {
5605 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
5606 return VERR_INTERNAL_ERROR;
5607 }
5608 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
5609
5610 if (pAhciPort->fATAPI)
5611 {
5612 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
5613 pAhciPort->PCHSGeometry.cCylinders = 0;
5614 pAhciPort->PCHSGeometry.cHeads = 0;
5615 pAhciPort->PCHSGeometry.cSectors = 0;
5616 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
5617 }
5618 else
5619 {
5620 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5621 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
5622 &pAhciPort->PCHSGeometry);
5623 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
5624 {
5625 pAhciPort->PCHSGeometry.cCylinders = 0;
5626 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
5627 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
5628 }
5629 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
5630 {
5631 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
5632 rc = VINF_SUCCESS;
5633 }
5634 AssertRC(rc);
5635
5636 if ( pAhciPort->PCHSGeometry.cCylinders == 0
5637 || pAhciPort->PCHSGeometry.cHeads == 0
5638 || pAhciPort->PCHSGeometry.cSectors == 0)
5639 {
5640 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
5641 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
5642 pAhciPort->PCHSGeometry.cHeads = 16;
5643 pAhciPort->PCHSGeometry.cSectors = 63;
5644 /* Set the disk geometry information. Ignore errors. */
5645 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
5646 &pAhciPort->PCHSGeometry);
5647 rc = VINF_SUCCESS;
5648 }
5649 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
5650 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
5651 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
5652 pAhciPort->cTotalSectors));
5653 }
5654 return rc;
5655}
5656
5657static bool ahciWaitForAllAsyncIOIsFinished(PPDMDEVINS pDevIns, unsigned cMillies)
5658{
5659 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5660 uint64_t u64Start;
5661 PAHCIPort pAhciPort;
5662 bool fAllFinished;
5663
5664 u64Start = RTTimeMilliTS();
5665 for (;;)
5666 {
5667 fAllFinished = true;
5668 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
5669 {
5670 pAhciPort = &pAhci->ahciPort[i];
5671
5672 if (pAhciPort->pDrvBase)
5673 {
5674 if (pAhciPort->fAsyncInterface)
5675 fAllFinished &= (pAhciPort->uActTasksActive == 0);
5676 else
5677 fAllFinished &= ((pAhciPort->uActTasksActive == 0) && (pAhciPort->fAsyncIOThreadIdle));
5678
5679 if (!fAllFinished)
5680 break;
5681 }
5682 }
5683 if ( fAllFinished
5684 || RTTimeMilliTS() - u64Start >= cMillies)
5685 break;
5686
5687 /* Sleep a bit. */
5688 RTThreadSleep(100);
5689 }
5690 return fAllFinished;
5691}
5692
5693static DECLCALLBACK(int) ahciSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5694{
5695 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5696
5697 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
5698 AssertMsgFailed(("One port is still active\n"));
5699
5700 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5701 {
5702 int rc;
5703
5704 rc = ataControllerSavePrep(&pAhci->aCts[i], pSSM);
5705 if (RT_FAILURE(rc))
5706 return rc;
5707 }
5708
5709 return VINF_SUCCESS;
5710}
5711
5712static DECLCALLBACK(int) ahciLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5713{
5714 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5715
5716 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5717 {
5718 int rc;
5719
5720 rc = ataControllerLoadPrep(&pAhci->aCts[i], pSSM);
5721 if (RT_FAILURE(rc))
5722 return rc;
5723 }
5724
5725 return VINF_SUCCESS;
5726}
5727
5728/**
5729 * Suspend notification.
5730 *
5731 * @returns VBox status.
5732 * @param pDevIns The device instance data.
5733 */
5734static DECLCALLBACK(void) ahciSuspend(PPDMDEVINS pDevIns)
5735{
5736 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5737
5738 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
5739 AssertMsgFailed(("AHCI: One port is still active\n"));
5740
5741 Log(("%s:\n", __FUNCTION__));
5742 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5743 {
5744 ataControllerSuspend(&pAhci->aCts[i]);
5745 }
5746 return;
5747}
5748
5749
5750/**
5751 * Resume notification.
5752 *
5753 * @returns VBox status.
5754 * @param pDevIns The device instance data.
5755 */
5756static DECLCALLBACK(void) ahciResume(PPDMDEVINS pDevIns)
5757{
5758 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5759
5760 Log(("%s:\n", __FUNCTION__));
5761 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5762 {
5763 ataControllerResume(&pAhci->aCts[i]);
5764 }
5765 return;
5766}
5767
5768/**
5769 * Saves a state of the AHCI device.
5770 *
5771 * @returns VBox status code.
5772 * @param pDevIns The device instance.
5773 * @param pSSMHandle The handle to save the state to.
5774 */
5775static DECLCALLBACK(int) ahciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
5776{
5777 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5778 uint32_t i;
5779
5780 Assert(!pAhci->f8ByteMMIO4BytesWrittenSuccessfully);
5781
5782 /* First the main device structure. */
5783 SSMR3PutU32(pSSMHandle, pAhci->regHbaCap);
5784 SSMR3PutU32(pSSMHandle, pAhci->regHbaCtrl);
5785 SSMR3PutU32(pSSMHandle, pAhci->regHbaIs);
5786 SSMR3PutU32(pSSMHandle, pAhci->regHbaPi);
5787 SSMR3PutU32(pSSMHandle, pAhci->regHbaVs);
5788 SSMR3PutU32(pSSMHandle, pAhci->regHbaCccCtl);
5789 SSMR3PutU32(pSSMHandle, pAhci->regHbaCccPorts);
5790 SSMR3PutU8(pSSMHandle, pAhci->uCccPortNr);
5791 SSMR3PutU64(pSSMHandle, pAhci->uCccTimeout);
5792 SSMR3PutU32(pSSMHandle, pAhci->uCccNr);
5793 SSMR3PutU32(pSSMHandle, pAhci->uCccCurrentNr);
5794 SSMR3PutU32(pSSMHandle, pAhci->u32PortsInterrupted);
5795 SSMR3PutBool(pSSMHandle, pAhci->fReset);
5796 SSMR3PutBool(pSSMHandle, pAhci->f64BitAddr);
5797 SSMR3PutBool(pSSMHandle, pAhci->fR0Enabled);
5798 SSMR3PutBool(pSSMHandle, pAhci->fGCEnabled);
5799
5800 /* Now every port. */
5801 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5802 {
5803 Assert(pAhci->ahciPort[i].uActTasksActive == 0);
5804 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLB);
5805 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLBU);
5806 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFB);
5807 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFBU);
5808 SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrClb);
5809 SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrFb);
5810 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIS);
5811 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIE);
5812 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCMD);
5813 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regTFD);
5814 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSIG);
5815 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSSTS);
5816 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSCTL);
5817 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSERR);
5818 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSACT);
5819 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCI);
5820 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cCylinders);
5821 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cHeads);
5822 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cSectors);
5823 SSMR3PutU64(pSSMHandle, pAhci->ahciPort[i].cTotalSectors);
5824 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].cMultSectors);
5825 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uATATransferMode);
5826 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fResetDevice);
5827
5828 for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
5829 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].ahciIOTasks[uActTask]);
5830
5831 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActWritePos);
5832 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActReadPos);
5833 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fPoweredOn);
5834 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fSpunUp);
5835 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32TasksFinished);
5836 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32QueuedTasksFinished);
5837 }
5838
5839 /* Now the emulated ata controllers. */
5840 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5841 {
5842 int rc;
5843
5844 rc = ataControllerSaveExec(&pAhci->aCts[i], pSSMHandle);
5845 if (RT_FAILURE(rc))
5846 return rc;
5847 }
5848
5849 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
5850}
5851
5852/**
5853 * Loads a saved AHCI device state.
5854 *
5855 * @returns VBox status code.
5856 * @param pDevIns The device instance.
5857 * @param pSSMHandle The handle to the saved state.
5858 * @param u32Version The data unit version number.
5859 */
5860static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
5861{
5862 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5863 uint32_t u32;
5864 uint32_t i;
5865 int rc = VINF_SUCCESS;
5866
5867 if (u32Version != AHCI_SAVED_STATE_VERSION)
5868 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5869
5870 /* Restore data. */
5871
5872 /* First the main device structure. */
5873 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCap);
5874 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCtrl);
5875 SSMR3GetU32(pSSMHandle, &pAhci->regHbaIs);
5876 SSMR3GetU32(pSSMHandle, &pAhci->regHbaPi);
5877 SSMR3GetU32(pSSMHandle, &pAhci->regHbaVs);
5878 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccCtl);
5879 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccPorts);
5880 SSMR3GetU8(pSSMHandle, &pAhci->uCccPortNr);
5881 SSMR3GetU64(pSSMHandle, &pAhci->uCccTimeout);
5882 SSMR3GetU32(pSSMHandle, &pAhci->uCccNr);
5883 SSMR3GetU32(pSSMHandle, &pAhci->uCccCurrentNr);
5884
5885 SSMR3GetU32(pSSMHandle, &pAhci->u32PortsInterrupted);
5886 SSMR3GetBool(pSSMHandle, &pAhci->fReset);
5887 SSMR3GetBool(pSSMHandle, &pAhci->f64BitAddr);
5888 SSMR3GetBool(pSSMHandle, &pAhci->fR0Enabled);
5889 SSMR3GetBool(pSSMHandle, &pAhci->fGCEnabled);
5890
5891 /* Now every port. */
5892 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5893 {
5894 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLB);
5895 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLBU);
5896 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFB);
5897 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFBU);
5898 SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrClb);
5899 SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrFb);
5900 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regIS);
5901 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regIE);
5902 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCMD);
5903 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regTFD);
5904 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSIG);
5905 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSSTS);
5906 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSCTL);
5907 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSERR);
5908 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regSACT);
5909 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regCI);
5910 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cCylinders);
5911 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cHeads);
5912 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cSectors);
5913 SSMR3GetU64(pSSMHandle, &pAhci->ahciPort[i].cTotalSectors);
5914 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].cMultSectors);
5915 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uATATransferMode);
5916 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fResetDevice);
5917
5918 for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
5919 SSMR3GetU8(pSSMHandle, (uint8_t *)&pAhci->ahciPort[i].ahciIOTasks[uActTask]);
5920
5921 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActWritePos);
5922 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActReadPos);
5923 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fPoweredOn);
5924 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fSpunUp);
5925 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32TasksFinished);
5926 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32QueuedTasksFinished);
5927 }
5928
5929 /* Now the emulated ata controllers. */
5930 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5931 {
5932 int rc;
5933
5934 rc = ataControllerLoadExec(&pAhci->aCts[i], pSSMHandle);
5935 if (RT_FAILURE(rc))
5936 return rc;
5937 }
5938
5939 rc = SSMR3GetU32(pSSMHandle, &u32);
5940 if (RT_FAILURE(rc))
5941 return rc;
5942 if (u32 != ~0U)
5943 {
5944 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
5945 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
5946 return rc;
5947 }
5948
5949 return VINF_SUCCESS;
5950}
5951
5952/**
5953 * Detach notification.
5954 *
5955 * One harddisk at one port has been unplugged.
5956 * The VM is suspended at this point.
5957 *
5958 * @param pDevIns The device instance.
5959 * @param iLUN The logical unit which is being detached.
5960 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
5961 */
5962static DECLCALLBACK(void) ahciDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5963{
5964 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5965 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
5966 int rc = VINF_SUCCESS;
5967
5968 Log(("%s:\n", __FUNCTION__));
5969
5970 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
5971
5972 if (!pAhciPort->fAsyncInterface)
5973 {
5974 int rcThread;
5975 /* Destroy the thread. */
5976 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
5977 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
5978 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
5979
5980 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
5981 if (RT_FAILURE(rc))
5982 AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
5983 }
5984
5985 /*
5986 * Zero some important members.
5987 */
5988 pAhciPort->pDrvBase = NULL;
5989 pAhciPort->pDrvBlock = NULL;
5990 pAhciPort->pDrvBlockAsync = NULL;
5991 pAhciPort->pDrvBlockBios = NULL;
5992}
5993
5994/**
5995 * Attach command.
5996 *
5997 * This is called when we change block driver for one port.
5998 * The VM is suspended at this point.
5999 *
6000 * @returns VBox status code.
6001 * @param pDevIns The device instance.
6002 * @param iLUN The logical unit which is being detached.
6003 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
6004 */
6005static DECLCALLBACK(int) ahciAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
6006{
6007 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6008 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
6009 int rc;
6010
6011 Log(("%s:\n", __FUNCTION__));
6012
6013 /* the usual paranoia */
6014 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
6015 AssertRelease(!pAhciPort->pDrvBase);
6016 AssertRelease(!pAhciPort->pDrvBlock);
6017 AssertRelease(!pAhciPort->pDrvBlockAsync);
6018 Assert(pAhciPort->iLUN == iLUN);
6019
6020 /*
6021 * Try attach the block device and get the interfaces,
6022 * required as well as optional.
6023 */
6024 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
6025 if (RT_SUCCESS(rc))
6026 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6027 else
6028 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
6029
6030 if (RT_FAILURE(rc))
6031 {
6032 pAhciPort->pDrvBase = NULL;
6033 pAhciPort->pDrvBlock = NULL;
6034 }
6035 else
6036 {
6037 char szName[24];
6038 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
6039
6040 if (pAhciPort->pDrvBlockAsync)
6041 {
6042 pAhciPort->fAsyncInterface = true;
6043 }
6044 else
6045 {
6046 pAhciPort->fAsyncInterface = false;
6047
6048 /* Create event semaphore. */
6049 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6050 if (RT_FAILURE(rc))
6051 {
6052 Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
6053 return rc;
6054 }
6055
6056 /* Create the async IO thread. */
6057 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6058 RTTHREADTYPE_IO, szName);
6059 if (RT_FAILURE(rc))
6060 {
6061 AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
6062 return rc;
6063 }
6064 }
6065 }
6066
6067 return rc;
6068}
6069
6070/**
6071 * Reset notification.
6072 *
6073 * @returns VBox status.
6074 * @param pDevIns The device instance data.
6075 */
6076static DECLCALLBACK(void) ahciReset(PPDMDEVINS pDevIns)
6077{
6078 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6079
6080 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
6081 AssertMsgFailed(("AHCI: One port is still active\n"));
6082
6083 ahciHBAReset(pAhci);
6084
6085 /* Hardware reset for the ports. */
6086 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
6087 ahciPortHwReset(&pAhci->ahciPort[i]);
6088
6089 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6090 ataControllerReset(&pAhci->aCts[i]);
6091}
6092
6093/**
6094 * Poweroff notification.
6095 *
6096 * @returns nothing
6097 * @param pDevIns Pointer to the device instance
6098 */
6099static DECLCALLBACK(void) ahciPowerOff(PPDMDEVINS pDevIns)
6100{
6101 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6102
6103 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
6104 AssertMsgFailed(("AHCI: One port is still active\n"));
6105
6106 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6107 ataControllerPowerOff(&pAhci->aCts[i]);
6108}
6109
6110/**
6111 * Construct a device instance for a VM.
6112 *
6113 * @returns VBox status.
6114 * @param pDevIns The device instance data.
6115 * If the registration structure is needed, pDevIns->pDevReg points to it.
6116 * @param iInstance Instance number. Use this to figure out which registers and such to use.
6117 * The device number is also found in pDevIns->iInstance, but since it's
6118 * likely to be freqently used PDM passes it as parameter.
6119 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
6120 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
6121 * iInstance it's expected to be used a bit in this function.
6122 */
6123static DECLCALLBACK(int) ahciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
6124{
6125 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6126 PPDMIBASE pBase;
6127 int rc = VINF_SUCCESS;
6128 unsigned i = 0;
6129 bool fGCEnabled = false;
6130 bool fR0Enabled = false;
6131 uint32_t cbTotalBufferSize = 0;
6132
6133 /*
6134 * Validate and read configuration.
6135 */
6136 rc = CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0"
6137 "R0Enabled\0"
6138 "PrimaryMaster\0"
6139 "PrimarySlave\0"
6140 "SecondaryMaster\0"
6141 "SecondarySlave\0"
6142 "PortCount\0"
6143 "UseAsyncInterfaceIfAvailable\0");
6144 if (RT_FAILURE(rc))
6145 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6146 N_("AHCI configuration error: unknown option specified"));
6147
6148 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
6149 if (RT_FAILURE(rc))
6150 return PDMDEV_SET_ERROR(pDevIns, rc,
6151 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
6152 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
6153
6154 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
6155 if (RT_FAILURE(rc))
6156 return PDMDEV_SET_ERROR(pDevIns, rc,
6157 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
6158 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
6159
6160 rc = CFGMR3QueryU32Def(pCfgHandle, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6161 if (RT_FAILURE(rc))
6162 return PDMDEV_SET_ERROR(pDevIns, rc,
6163 N_("AHCI configuration error: failed to read PortCount as integer"));
6164 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
6165 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
6166 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6167 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
6168 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6169 if (pThis->cPortsImpl < 1)
6170 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6171 N_("AHCI configuration error: PortCount=%u should be at least 1"),
6172 pThis->cPortsImpl);
6173
6174 rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6175 if (RT_FAILURE(rc))
6176 return PDMDEV_SET_ERROR(pDevIns, rc,
6177 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6178 rc = CFGMR3QueryU32Def(pCfgHandle, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6179 if (RT_FAILURE(rc))
6180 return PDMDEV_SET_ERROR(pDevIns, rc,
6181 N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
6182 rc = CFGMR3QueryU32Def(pCfgHandle, "MillisToSleep", &pThis->cMillisToSleep, 0);
6183 if (RT_FAILURE(rc))
6184 return PDMDEV_SET_ERROR(pDevIns, rc,
6185 N_("AHCI configuration error: failed to read MillisToSleep as integer"));
6186
6187 pThis->fR0Enabled = fR0Enabled;
6188 pThis->fGCEnabled = fGCEnabled;
6189 pThis->pDevInsR3 = pDevIns;
6190 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6191 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6192
6193 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
6194 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
6195 PCIDevSetCommand (&pThis->dev, 0x0000);
6196 PCIDevSetRevisionId (&pThis->dev, 0x02);
6197 PCIDevSetClassProg (&pThis->dev, 0x01);
6198 PCIDevSetClassSub (&pThis->dev, 0x06);
6199 PCIDevSetClassBase (&pThis->dev, 0x01);
6200 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
6201
6202 pThis->dev.config[0x34] = 0x80; /* Capability pointer. */
6203
6204 PCIDevSetInterruptLine(&pThis->dev, 0x00);
6205 PCIDevSetInterruptPin (&pThis->dev, 0x01);
6206
6207 pThis->dev.config[0x70] = 0x01; /* Capability ID: PCI Power Management Interface */
6208 pThis->dev.config[0x71] = 0x00;
6209 pThis->dev.config[0x72] = 0x03;
6210
6211 pThis->dev.config[0x80] = 0x05; /* Capability ID: Message Signaled Interrupts. Disabled. */
6212 pThis->dev.config[0x81] = 0x70; /* next. */
6213
6214 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
6215 pThis->dev.config[0x92] = 0x3f;
6216 pThis->dev.config[0x94] = 0x80;
6217 pThis->dev.config[0x95] = 0x01;
6218 pThis->dev.config[0x97] = 0x78;
6219
6220 /*
6221 * Register the PCI device, it's I/O regions.
6222 */
6223 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
6224 if (RT_FAILURE(rc))
6225 return rc;
6226
6227 /*
6228 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
6229 * IDE registers are not available.
6230 * We set up "fake" entries in the PCI configuration register.
6231 * That means they are available but read and writes from/to them have no effect.
6232 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
6233 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
6234 * to switch to it which also changes device Id and other things in the PCI configuration space).
6235 */
6236 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6237 if (RT_FAILURE(rc))
6238 return PDMDEV_SET_ERROR(pDevIns, rc,
6239 N_("AHCI cannot register PCI I/O region"));
6240
6241 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6242 if (RT_FAILURE(rc))
6243 return PDMDEV_SET_ERROR(pDevIns, rc,
6244 N_("AHCI cannot register PCI I/O region"));
6245
6246 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6247 if (RT_FAILURE(rc))
6248 return PDMDEV_SET_ERROR(pDevIns, rc,
6249 N_("AHCI cannot register PCI I/O region"));
6250
6251 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6252 if (RT_FAILURE(rc))
6253 return PDMDEV_SET_ERROR(pDevIns, rc,
6254 N_("AHCI cannot register PCI I/O region"));
6255
6256 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6257 if (RT_FAILURE(rc))
6258 return PDMDEV_SET_ERROR(pDevIns, rc,
6259 N_("AHCI cannot register PCI I/O region for BMDMA"));
6260
6261 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciMMIOMap);
6262 if (RT_FAILURE(rc))
6263 return PDMDEV_SET_ERROR(pDevIns, rc,
6264 N_("AHCI cannot register PCI memory region for registers"));
6265
6266 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, "AHCI");
6267 if (RT_FAILURE(rc))
6268 {
6269 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6270 return rc;
6271 }
6272
6273 /* Create the timer for command completion coalescing feature. */
6274 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ahciCccTimer, pThis,
6275 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
6276 if (RT_FAILURE(rc))
6277 {
6278 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
6279 return rc;
6280 }
6281 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
6282 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
6283
6284 /* Status LUN. */
6285 pThis->IBase.pfnQueryInterface = ahciStatus_QueryInterface;
6286 pThis->ILeds.pfnQueryStatusLed = ahciStatus_QueryStatusLed;
6287
6288 /*
6289 * Create the transmit queue.
6290 */
6291 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6292 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6293 if (RT_FAILURE(rc))
6294 return rc;
6295 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
6296 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
6297
6298 /* Initialize static members on every port. */
6299 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6300 {
6301 /*
6302 * Init members of the port.
6303 */
6304 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6305 pAhciPort->pDevInsR3 = pDevIns;
6306 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6307 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6308 pAhciPort->iLUN = i;
6309 pAhciPort->pAhciR3 = pThis;
6310 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
6311 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
6312 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
6313 pAhciPort->pDrvBase = NULL;
6314
6315 /* Register statistics counter. */
6316 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6317 "Number of DMA transfers.", "/Devices/SATA/Port%d/DMA", i);
6318 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6319 "Amount of data read.", "/Devices/SATA/Port%d/ReadBytes", i);
6320 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6321 "Amount of data written.", "/Devices/SATA/Port%d/WrittenBytes", i);
6322 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6323 "Number of processed I/O requests per second.", "/Devices/SATA/Port%d/IORequestsPerSecond", i);
6324#ifdef VBOX_WITH_STATISTICS
6325 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6326 "Amount of time to process one request.", "/Devices/SATA/Port%d/ProfileProcessTime", i);
6327 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6328 "Amount of time to map the guest buffers into R3.", "/Devices/SATA/Port%d/ProfileMapIntoR3", i);
6329 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6330 "Amount of time for the read/write operation to complete.", "/Devices/SATA/Port%d/ProfileReadWrite", i);
6331 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6332 "Amount of time to destroy the scatter gather list and free associated ressources.", "/Devices/SATA/Port%d/ProfileDestroyScatterGatherList", i);
6333#endif
6334
6335 ahciPortHwReset(pAhciPort);
6336 }
6337
6338 /* Attach drivers to every available port. */
6339 for (i = 0; i < pThis->cPortsImpl; i++)
6340 {
6341 char szName[24];
6342 RTStrPrintf(szName, sizeof(szName), "Port%d", i);
6343
6344 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6345 /*
6346 * Init interfaces.
6347 */
6348 pAhciPort->IBase.pfnQueryInterface = ahciPortQueryInterface;
6349 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciTransferCompleteNotify;
6350 pAhciPort->IMountNotify.pfnMountNotify = ahciMountNotify;
6351 pAhciPort->IMountNotify.pfnUnmountNotify = ahciUnmountNotify;
6352 pAhciPort->fAsyncIOThreadIdle = true;
6353
6354 /*
6355 * Attach the block driver
6356 */
6357 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
6358 if (RT_SUCCESS(rc))
6359 {
6360 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6361 if (RT_FAILURE(rc))
6362 {
6363 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
6364 return rc;
6365 }
6366
6367 /* Mark that a device is present on that port */
6368 if (i < 6)
6369 pThis->dev.config[0x93] |= (1 << i);
6370
6371 /*
6372 * Init vendor product data.
6373 */
6374 /* Generate a default serial number. */
6375 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
6376 RTUUID Uuid;
6377 if (pAhciPort->pDrvBlock)
6378 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
6379 else
6380 RTUuidClear(&Uuid);
6381
6382 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
6383 {
6384 /* Generate a predictable serial for drives which don't have a UUID. */
6385 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
6386 pAhciPort->iLUN);
6387 }
6388 else
6389 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
6390
6391 /* Get user config if present using defaults otherwise. */
6392 PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, szName);
6393 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
6394 szSerial);
6395 if (RT_FAILURE(rc))
6396 {
6397 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6398 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6399 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
6400 return PDMDEV_SET_ERROR(pDevIns, rc,
6401 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
6402 }
6403
6404 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
6405 "1.0");
6406 if (RT_FAILURE(rc))
6407 {
6408 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6409 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6410 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
6411 return PDMDEV_SET_ERROR(pDevIns, rc,
6412 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
6413 }
6414
6415 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
6416 "VBOX HARDDISK");
6417 if (RT_FAILURE(rc))
6418 {
6419 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6420 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6421 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
6422 return PDMDEV_SET_ERROR(pDevIns, rc,
6423 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
6424 }
6425
6426 /*
6427 * If the new async interface is available we use a PDMQueue to transmit
6428 * the requests into R3.
6429 * Otherwise we use a event semaphore and a async I/O thread which processes them.
6430 */
6431 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
6432 {
6433 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
6434 pAhciPort->fAsyncInterface = true;
6435 }
6436 else
6437 {
6438 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
6439 pAhciPort->fAsyncInterface = false;
6440
6441 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6442 AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
6443
6444
6445 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6446 RTTHREADTYPE_IO, szName);
6447 AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
6448 }
6449 }
6450 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
6451 {
6452 pAhciPort->pDrvBase = NULL;
6453 rc = VINF_SUCCESS;
6454 LogRel(("%s: no driver attached\n", szName));
6455 }
6456 else
6457 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6458 N_("AHCI: Failed to attach drive to %s"), szName);
6459
6460#ifdef DEBUG
6461 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
6462 pAhciPort->ahciIOTasks[i] = 0xff;
6463#endif
6464 }
6465
6466 /*
6467 * Attach status driver (optional).
6468 */
6469 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
6470 if (RT_SUCCESS(rc))
6471 pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
6472 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
6473 {
6474 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
6475 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
6476 }
6477
6478 /*
6479 * Setup IDE emulation.
6480 * We only emulate the I/O ports but not bus master DMA.
6481 * If the configuration values are not found the setup of the ports is as follows:
6482 * Primary Master: Port 0
6483 * Primary Slave: Port 1
6484 * Secondary Master: Port 2
6485 * Secondary Slave: Port 3
6486 */
6487
6488 /*
6489 * Setup I/O ports for the PCI device.
6490 */
6491 pThis->aCts[0].irq = 12;
6492 pThis->aCts[0].IOPortBase1 = 0x1e8;
6493 pThis->aCts[0].IOPortBase2 = 0x3e6;
6494 pThis->aCts[1].irq = 11;
6495 pThis->aCts[1].IOPortBase1 = 0x168;
6496 pThis->aCts[1].IOPortBase2 = 0x366;
6497
6498 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6499 {
6500 PAHCIATACONTROLLER pCtl = &pThis->aCts[i];
6501 uint32_t iPortMaster, iPortSlave;
6502 uint32_t cbSSMState = 0;
6503 static const char *s_apszDescs[RT_ELEMENTS(pThis->aCts)][RT_ELEMENTS(pCtl->aIfs)] =
6504 {
6505 { "PrimaryMaster", "PrimarySlave" },
6506 { "SecondaryMaster", "SecondarySlave" }
6507 };
6508
6509 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][0], &iPortMaster, 2 * i);
6510 if (RT_FAILURE(rc))
6511 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6512 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
6513
6514 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
6515 if (RT_FAILURE(rc))
6516 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6517 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);
6518
6519 char szName[24];
6520 RTStrPrintf(szName, sizeof(szName), "EmulatedATA%d", i);
6521 rc = ataControllerInit(pDevIns, pCtl, pThis->ahciPort[iPortMaster].pDrvBase, pThis->ahciPort[iPortSlave].pDrvBase,
6522 &cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led, &pThis->ahciPort[iPortMaster].StatBytesRead,
6523 &pThis->ahciPort[iPortMaster].StatBytesWritten);
6524 if (RT_FAILURE(rc))
6525 return rc;
6526
6527 cbTotalBufferSize += cbSSMState;
6528
6529 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase1, 8, (RTHCPTR)i,
6530 ahciIOPortWrite1, ahciIOPortRead1, ahciIOPortWriteStr1, ahciIOPortReadStr1, "AHCI");
6531 if (RT_FAILURE(rc))
6532 return rc;
6533
6534 if (pThis->fR0Enabled)
6535 {
6536 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase1, 8, (RTR0PTR)i,
6537 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI R0");
6538 if (RT_FAILURE(rc))
6539 return rc;
6540 }
6541
6542 if (pThis->fGCEnabled)
6543 {
6544 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
6545 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI GC");
6546 if (RT_FAILURE(rc))
6547 return rc;
6548 }
6549
6550 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase2, 1, (RTHCPTR)i,
6551 ahciIOPortWrite2, ahciIOPortRead2, NULL, NULL, "AHCI");
6552 if (RT_FAILURE(rc))
6553 return rc;
6554
6555 if (pThis->fR0Enabled)
6556 {
6557 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase2, 1, (RTR0PTR)i,
6558 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI R0");
6559 if (RT_FAILURE(rc))
6560 return rc;
6561 }
6562
6563 if (pThis->fGCEnabled)
6564 {
6565 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
6566 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI GC");
6567 if (RT_FAILURE(rc))
6568 return rc;
6569 }
6570 }
6571
6572 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
6573 AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize,
6574 ahciSavePrep, ahciSaveExec, NULL,
6575 ahciLoadPrep, ahciLoadExec, NULL);
6576 if (RT_FAILURE(rc))
6577 return rc;
6578
6579 ahciReset(pDevIns);
6580
6581 return rc;
6582}
6583
6584/**
6585 * The device registration structure.
6586 */
6587const PDMDEVREG g_DeviceAHCI =
6588{
6589 /* u32Version */
6590 PDM_DEVREG_VERSION,
6591 /* szDeviceName */
6592 "ahci",
6593 /* szRCMod */
6594 "VBoxDDGC.gc",
6595 /* szR0Mod */
6596 "VBoxDDR0.r0",
6597 /* pszDescription */
6598 "Intel AHCI controller.\n",
6599 /* fFlags */
6600 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
6601 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
6602 /* fClass */
6603 PDM_DEVREG_CLASS_STORAGE,
6604 /* cMaxInstances */
6605 ~0,
6606 /* cbInstance */
6607 sizeof(AHCI),
6608 /* pfnConstruct */
6609 ahciConstruct,
6610 /* pfnDestruct */
6611 ahciDestruct,
6612 /* pfnRelocate */
6613 ahciRelocate,
6614 /* pfnIOCtl */
6615 NULL,
6616 /* pfnPowerOn */
6617 NULL,
6618 /* pfnReset */
6619 ahciReset,
6620 /* pfnSuspend */
6621 ahciSuspend,
6622 /* pfnResume */
6623 ahciResume,
6624 /* pfnAttach */
6625 ahciAttach,
6626 /* pfnDetach */
6627 ahciDetach,
6628 /* pfnQueryInterface. */
6629 NULL,
6630 /* pfnInitComplete */
6631 NULL,
6632 /* pfnPowerOff */
6633 ahciPowerOff,
6634 /* pfnSoftReset */
6635 NULL,
6636 /* u32VersionEnd */
6637 PDM_DEVREG_VERSION
6638};
6639
6640#endif /* IN_RING3 */
6641#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