VirtualBox

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

最後變更 在這個檔案從23012是 23012,由 vboxsync 提交於 16 年 前

VMM,Devices,Main: VMR3ReqCall w/ RT_INDEFINITE_WAIT -> VMR3ReqCallWait.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 263.5 KB
 
1/* $Id: DevAHCI.cpp 23012 2009-09-14 16:38:13Z 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.alldomusa.eu.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 = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
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 = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, 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 = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
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 = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, 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) && (i < AHCI_MAX_NR_PORTS_IMPL))
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
1820 if (pAhciPort->fPoweredOn)
1821 {
1822 /*
1823 * Set states in the Port Signature and SStatus registers.
1824 */
1825 pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
1826 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1827 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1828 (0x03 << 0); /* Device detected and communication established. */
1829 }
1830 }
1831}
1832
1833#ifdef IN_RING3
1834/**
1835 * Hardware reset used for machine power on and reset.
1836 *
1837 * @param pAhciport The port to reset.
1838 */
1839static void ahciPortHwReset(PAHCIPort pAhciPort)
1840{
1841 /* Reset the address registers. */
1842 pAhciPort->regCLB = 0;
1843 pAhciPort->regCLBU = 0;
1844 pAhciPort->regFB = 0;
1845 pAhciPort->regFBU = 0;
1846
1847 /* Reset calculated addresses. */
1848 pAhciPort->GCPhysAddrClb = 0;
1849 pAhciPort->GCPhysAddrFb = 0;
1850}
1851#endif
1852
1853/**
1854 * Create implemented ports bitmap.
1855 *
1856 * @returns 32bit bitmask with a bit set for every implemented port.
1857 * @param cPorts Number of ports.
1858 */
1859static uint32_t ahciGetPortsImplemented(unsigned cPorts)
1860{
1861 uint32_t uPortsImplemented = 0;
1862
1863 for (unsigned i = 0; i < cPorts; i++)
1864 uPortsImplemented |= (1 << i);
1865
1866 return uPortsImplemented;
1867}
1868
1869/**
1870 * Reset the entire HBA.
1871 *
1872 * @param pThis The HBA state.
1873 */
1874static void ahciHBAReset(PAHCI pThis)
1875{
1876 unsigned i;
1877 int rc = VINF_SUCCESS;
1878
1879 LogFlow(("Reset the HBA controller\n"));
1880
1881 /* Stop the CCC timer. */
1882 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
1883 {
1884 rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
1885 if (RT_FAILURE(rc))
1886 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
1887 }
1888
1889 /* Reset every port */
1890 for (i = 0; i < pThis->cPortsImpl; i++)
1891 {
1892 PAHCIPort pAhciPort = &pThis->ahciPort[i];
1893
1894 pAhciPort->iLUN = i;
1895 ahciPortSwReset(pAhciPort);
1896 }
1897
1898 /* Init Global registers */
1899 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
1900 AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
1901 AHCI_HBA_CAP_SAM | /* AHCI mode only */
1902 AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
1903 AHCI_HBA_CAP_SSS | /* Staggered spin up */
1904 AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
1905 AHCI_HBA_CAP_NCS_SET(AHCI_NR_COMMAND_SLOTS) | /* Number of command slots we support */
1906 AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
1907 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
1908 pThis->regHbaIs = 0;
1909 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
1910 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
1911 pThis->regHbaCccCtl = 0;
1912 pThis->regHbaCccPorts = 0;
1913 pThis->uCccTimeout = 0;
1914 pThis->uCccPortNr = 0;
1915 pThis->uCccNr = 0;
1916
1917 pThis->f64BitAddr = false;
1918 pThis->u32PortsInterrupted = 0;
1919 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
1920 /* Clear the HBA Reset bit */
1921 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
1922}
1923
1924/**
1925 * Memory mapped I/O Handler for read operations.
1926 *
1927 * @returns VBox status code.
1928 *
1929 * @param pDevIns The device instance.
1930 * @param pvUser User argument.
1931 * @param GCPhysAddr Physical address (in GC) where the read starts.
1932 * @param pv Where to store the result.
1933 * @param cb Number of bytes read.
1934 */
1935PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1936{
1937 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
1938 int rc = VINF_SUCCESS;
1939
1940 /* Break up 64 bits reads into two dword reads. */
1941 if (cb == 8)
1942 {
1943 rc = ahciMMIORead(pDevIns, pvUser, GCPhysAddr, pv, 4);
1944 if (RT_FAILURE(rc))
1945 return rc;
1946
1947 return ahciMMIORead(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
1948 }
1949
1950 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
1951 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
1952
1953 /*
1954 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
1955 * Otherwise it accesses the registers of a port.
1956 */
1957 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
1958 uint32_t iReg;
1959
1960 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
1961 {
1962 iReg = uOffset >> 2;
1963 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
1964 if (iReg < RT_ELEMENTS(g_aOpRegs))
1965 {
1966 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
1967 rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
1968 }
1969 else
1970 {
1971 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
1972 *(uint32_t *)pv = 0;
1973 }
1974 }
1975 else
1976 {
1977 uint32_t iRegOffset;
1978 uint32_t iPort;
1979
1980 /* Calculate accessed port. */
1981 uOffset -= AHCI_HBA_GLOBAL_SIZE;
1982 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
1983 iRegOffset = (uOffset % AHCI_PORT_REGISTER_SIZE);
1984 iReg = iRegOffset >> 2;
1985
1986 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
1987
1988 if (RT_LIKELY( iPort < pAhci->cPortsImpl
1989 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
1990 {
1991 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
1992 rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
1993 }
1994 else
1995 {
1996 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
1997 rc = VINF_IOM_MMIO_UNUSED_00;
1998 }
1999
2000 /*
2001 * Windows Vista tries to read one byte from some registers instead of four.
2002 * Correct the value according to the read size.
2003 */
2004 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2005 {
2006 switch (cb)
2007 {
2008 case 1:
2009 {
2010 uint8_t uNewValue;
2011 uint8_t *p = (uint8_t *)pv;
2012
2013 iRegOffset &= 3;
2014 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2015 uNewValue = p[iRegOffset];
2016 /* Clear old value */
2017 *(uint32_t *)pv = 0;
2018 *(uint8_t *)pv = uNewValue;
2019 break;
2020 }
2021 default:
2022 AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
2023 }
2024 }
2025 }
2026
2027 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
2028 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
2029 return rc;
2030}
2031
2032
2033/**
2034 * Memory mapped I/O Handler for write operations.
2035 *
2036 * @returns VBox status code.
2037 *
2038 * @param pDevIns The device instance.
2039 * @param pvUser User argument.
2040 * @param GCPhysAddr Physical address (in GC) where the read starts.
2041 * @param pv Where to fetch the result.
2042 * @param cb Number of bytes to write.
2043 */
2044PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2045{
2046 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2047 int rc = VINF_SUCCESS;
2048
2049 /* Break up 64 bits writes into two dword writes. */
2050 if (cb == 8)
2051 {
2052 /*
2053 * Only write the first 4 bytes if they weren't already.
2054 * It is possible that the last write to the register caused a world
2055 * switch and we entered this function again.
2056 * Writing the first 4 bytes again could cause indeterminate behavior
2057 * which can cause errors in the guest.
2058 */
2059 if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
2060 {
2061 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
2062 if (rc != VINF_SUCCESS)
2063 return rc;
2064
2065 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
2066 }
2067
2068 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
2069 /*
2070 * Reset flag again so that the first 4 bytes are written again on the next
2071 * 8byte MMIO access.
2072 */
2073 if (rc == VINF_SUCCESS)
2074 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
2075
2076 return rc;
2077 }
2078
2079 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
2080 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2081
2082 /* Validate access. */
2083 if (cb != sizeof(uint32_t))
2084 {
2085 Log2(("%s: Bad write size!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2086 return VINF_SUCCESS;
2087 }
2088 if (GCPhysAddr & 0x3)
2089 {
2090 Log2(("%s: Unaligned write!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2091 return VINF_SUCCESS;
2092 }
2093
2094 /*
2095 * If the access offset is smaller than 100h the guest accesses the global registers.
2096 * Otherwise it accesses the registers of a port.
2097 */
2098 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
2099 uint32_t iReg;
2100 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
2101 {
2102 Log3(("Write global HBA register\n"));
2103 iReg = uOffset >> 2;
2104 if (iReg < RT_ELEMENTS(g_aOpRegs))
2105 {
2106 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2107 rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
2108 }
2109 else
2110 {
2111 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2112 rc = VINF_SUCCESS;
2113 }
2114 }
2115 else
2116 {
2117 uint32_t iPort;
2118 Log3(("Write Port register\n"));
2119 /* Calculate accessed port. */
2120 uOffset -= AHCI_HBA_GLOBAL_SIZE;
2121 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
2122 iReg = (uOffset % AHCI_PORT_REGISTER_SIZE) >> 2;
2123 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2124 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2125 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2126 {
2127 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2128 rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
2129 }
2130 else
2131 {
2132 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2133 rc = VINF_SUCCESS;
2134 }
2135 }
2136
2137 return rc;
2138}
2139
2140PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2141{
2142 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2143 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2144 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2145
2146 Assert(iChannel < 2);
2147
2148 return ataControllerIOPortWrite1(pCtl, Port, u32, cb);
2149}
2150
2151PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2152{
2153 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2154 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2155 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2156
2157 Assert(iChannel < 2);
2158
2159 return ataControllerIOPortRead1(pCtl, Port, pu32, cb);
2160}
2161
2162PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2163{
2164 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2165 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2166 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2167
2168 Assert(iChannel < 2);
2169
2170 return ataControllerIOPortWrite2(pCtl, Port, u32, cb);
2171}
2172
2173PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2174{
2175 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2176 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2177 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2178
2179 Assert(iChannel < 2);
2180
2181 return ataControllerIOPortRead2(pCtl, Port, pu32, cb);
2182}
2183
2184PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2185{
2186 AssertMsgFailed(("Should not happen\n"));
2187 return VINF_SUCCESS;
2188}
2189
2190PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2191{
2192 AssertMsgFailed(("Should not happen\n"));
2193 return VINF_SUCCESS;
2194}
2195
2196#ifndef IN_RING0
2197/**
2198 * Port I/O Handler for primary port range IN string operations.
2199 * @see FNIOMIOPORTINSTRING for details.
2200 */
2201PDMBOTHCBDECL(int) ahciIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
2202{
2203 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2204 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2205 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2206
2207 Assert(iChannel < 2);
2208
2209 return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrDst, pcTransfer, cb);
2210}
2211
2212
2213/**
2214 * Port I/O Handler for primary port range OUT string operations.
2215 * @see FNIOMIOPORTOUTSTRING for details.
2216 */
2217PDMBOTHCBDECL(int) ahciIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
2218{
2219 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2220 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2221 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2222
2223 Assert(iChannel < 2);
2224
2225 return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrSrc, pcTransfer, cb);
2226}
2227#endif /* !IN_RING0 */
2228
2229#ifdef IN_RING3
2230
2231static DECLCALLBACK(int) ahciMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2232{
2233 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2234 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2235 int rc = VINF_SUCCESS;
2236
2237 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2238
2239 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2240 Assert(cb >= 4352);
2241
2242 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2243 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
2244 ahciMMIOWrite, ahciMMIORead, NULL, "AHCI");
2245 if (RT_FAILURE(rc))
2246 return rc;
2247
2248 if (pThis->fR0Enabled)
2249 {
2250 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
2251 "ahciMMIOWrite", "ahciMMIORead", NULL);
2252 if (RT_FAILURE(rc))
2253 return rc;
2254 }
2255
2256 if (pThis->fGCEnabled)
2257 {
2258 rc = PDMDevHlpMMIORegisterGC(pDevIns, GCPhysAddress, cb, 0,
2259 "ahciMMIOWrite", "ahciMMIORead", NULL);
2260 if (RT_FAILURE(rc))
2261 return rc;
2262 }
2263
2264 pThis->MMIOBase = GCPhysAddress;
2265 return rc;
2266}
2267
2268/**
2269 * Map the legacy I/O port ranges to make Solaris work with the controller.
2270 */
2271static DECLCALLBACK(int) ahciLegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2272{
2273 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2274 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2275 int rc = VINF_SUCCESS;
2276
2277 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2278
2279 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2280
2281 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2282 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2283 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2284 if (RT_FAILURE(rc))
2285 return rc;
2286
2287 if (pThis->fR0Enabled)
2288 {
2289 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2290 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2291 if (RT_FAILURE(rc))
2292 return rc;
2293 }
2294
2295 if (pThis->fGCEnabled)
2296 {
2297 rc = PDMDevHlpIOPortRegisterGC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2298 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2299 if (RT_FAILURE(rc))
2300 return rc;
2301 }
2302
2303 return rc;
2304}
2305
2306/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2307
2308/**
2309 * Gets the pointer to the status LED of a unit.
2310 *
2311 * @returns VBox status code.
2312 * @param pInterface Pointer to the interface structure containing the called function pointer.
2313 * @param iLUN The unit which status LED we desire.
2314 * @param ppLed Where to store the LED pointer.
2315 */
2316static DECLCALLBACK(int) ahciStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2317{
2318 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2319 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2320 {
2321 *ppLed = &pAhci->ahciPort[iLUN].Led;
2322 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2323 return VINF_SUCCESS;
2324 }
2325 return VERR_PDM_LUN_NOT_FOUND;
2326}
2327
2328/**
2329 * Queries an interface to the driver.
2330 *
2331 * @returns Pointer to interface.
2332 * @returns NULL if the interface was not supported by the device.
2333 * @param pInterface Pointer to ATADevState::IBase.
2334 * @param enmInterface The requested interface identification.
2335 */
2336static DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2337{
2338 PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
2339 switch (enmInterface)
2340 {
2341 case PDMINTERFACE_BASE:
2342 return &pAhci->IBase;
2343 case PDMINTERFACE_LED_PORTS:
2344 return &pAhci->ILeds;
2345 default:
2346 return NULL;
2347 }
2348}
2349
2350/**
2351 * Query interface method for the AHCI port.
2352 */
2353static DECLCALLBACK(void *) ahciPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2354{
2355 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2356 switch (enmInterface)
2357 {
2358 case PDMINTERFACE_BASE:
2359 return &pAhciPort->IBase;
2360 case PDMINTERFACE_BLOCK_PORT:
2361 return &pAhciPort->IPort;
2362 case PDMINTERFACE_BLOCK_ASYNC_PORT:
2363 return &pAhciPort->IPortAsync;
2364 case PDMINTERFACE_MOUNT_NOTIFY:
2365 return &pAhciPort->IMountNotify;
2366 default:
2367 return NULL;
2368 }
2369}
2370
2371static DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2372{
2373 uint32_t i;
2374 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2375
2376 pAhci->pDevInsRC += offDelta;
2377 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
2378 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
2379
2380 /* Relocate every port. */
2381 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
2382 {
2383 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
2384 pAhciPort->pAhciRC += offDelta;
2385 pAhciPort->pDevInsRC += offDelta;
2386 }
2387
2388 /* Relocate emulated ATA controllers. */
2389 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
2390 ataControllerRelocate(&pAhci->aCts[i], offDelta);
2391}
2392
2393#ifdef DEBUG
2394
2395/**
2396 * Dump info about the FIS
2397 *
2398 * @returns nothing
2399 * @param pAhciPort The port the command FIS was read from.
2400 * @param cmdFis The FIS to print info from.
2401 */
2402static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2403{
2404 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2405 /* Print FIS type. */
2406 switch (cmdFis[AHCI_CMDFIS_TYPE])
2407 {
2408 case AHCI_CMDFIS_TYPE_H2D:
2409 {
2410 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2411 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2412 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2413 {
2414 ahciLog(("%s: Command register update\n", __FUNCTION__));
2415 }
2416 else
2417 {
2418 ahciLog(("%s: Control register update\n", __FUNCTION__));
2419 }
2420 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2421 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2422 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2423 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2424 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2425 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2426
2427 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2428 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2429 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2430 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2431
2432 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2433 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2434 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2435 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2436 {
2437 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2438 }
2439 }
2440 break;
2441 case AHCI_CMDFIS_TYPE_D2H:
2442 {
2443 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2444 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2445 }
2446 break;
2447 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2448 {
2449 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2450 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2451 }
2452 break;
2453 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2454 {
2455 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2456 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2457 }
2458 break;
2459 case AHCI_CMDFIS_TYPE_DMASETUP:
2460 {
2461 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2462 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2463 }
2464 break;
2465 case AHCI_CMDFIS_TYPE_PIOSETUP:
2466 {
2467 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2468 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2469 }
2470 break;
2471 case AHCI_CMDFIS_TYPE_DATA:
2472 {
2473 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2474 }
2475 break;
2476 default:
2477 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2478 break;
2479 }
2480 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2481}
2482
2483/**
2484 * Dump info about the command header
2485 *
2486 * @returns nothing
2487 * @param pAhciPort Poitner to the port the command header was read from.
2488 * @param pCmdHdr The command header to print info from.
2489 */
2490static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2491{
2492 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2493 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2494 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2495 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2496 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2497 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2498 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2499 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2500 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2501 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2502 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2503 ahciLog(("%s: Device write\n", __FUNCTION__));
2504 else
2505 ahciLog(("%s: Device read\n", __FUNCTION__));
2506 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2507 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2508 else
2509 ahciLog(("%s: ATA command\n", __FUNCTION__));
2510
2511 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2512 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2513}
2514#endif /* DEBUG */
2515
2516/**
2517 * Post the first D2H FIS from the device into guest memory.
2518 *
2519 * @returns nothing
2520 * @param pAhciPort Pointer to the port which "receives" the FIS.
2521 */
2522static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2523{
2524 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2525
2526 pAhciPort->fFirstD2HFisSend = true;
2527
2528 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2529 memset(&d2hFis[0], 0, sizeof(d2hFis));
2530 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2531 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2532
2533 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2534
2535 /* Set the signature based on the device type. */
2536 if (pAhciPort->fATAPI)
2537 {
2538 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2539 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2540 }
2541 else
2542 {
2543 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2544 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2545 }
2546
2547 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2548 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2549 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2550
2551 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2552
2553 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2554}
2555
2556/**
2557 * Post the FIS in the memory area allocated by the guest and set interrupt if neccessary.
2558 *
2559 * @returns VBox status code
2560 * @param pAhciPort The port which "receives" the FIS.
2561 * @param uFisType The type of the FIS.
2562 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2563 */
2564static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2565{
2566 int rc = VINF_SUCCESS;
2567 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2568 unsigned cbFis = 0;
2569
2570 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2571
2572 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2573 {
2574 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2575
2576 /* Determine the offset and size of the FIS based on uFisType. */
2577 switch (uFisType)
2578 {
2579 case AHCI_CMDFIS_TYPE_D2H:
2580 {
2581 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2582 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2583 }
2584 break;
2585 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2586 {
2587 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2588 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2589 }
2590 break;
2591 case AHCI_CMDFIS_TYPE_DMASETUP:
2592 {
2593 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2594 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2595 }
2596 break;
2597 case AHCI_CMDFIS_TYPE_PIOSETUP:
2598 {
2599 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2600 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2601 }
2602 break;
2603 default:
2604 /*
2605 * We should post the unknown FIS into memory too but this never happens because
2606 * we know which FIS types we generate. ;)
2607 */
2608 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2609 }
2610
2611 /* Post the FIS into memory. */
2612 ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2613 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2614 }
2615
2616 return rc;
2617}
2618
2619DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2620{
2621 pbBuf[0] = val >> 8;
2622 pbBuf[1] = val;
2623}
2624
2625
2626DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2627{
2628 pbBuf[0] = val >> 16;
2629 pbBuf[1] = val >> 8;
2630 pbBuf[2] = val;
2631}
2632
2633
2634DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2635{
2636 pbBuf[0] = val >> 24;
2637 pbBuf[1] = val >> 16;
2638 pbBuf[2] = val >> 8;
2639 pbBuf[3] = val;
2640}
2641
2642
2643DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2644{
2645 return (pbBuf[0] << 8) | pbBuf[1];
2646}
2647
2648
2649DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2650{
2651 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2652}
2653
2654
2655DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2656{
2657 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2658}
2659
2660
2661DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2662{
2663 iATAPILBA += 150;
2664 pbBuf[0] = (iATAPILBA / 75) / 60;
2665 pbBuf[1] = (iATAPILBA / 75) % 60;
2666 pbBuf[2] = iATAPILBA % 75;
2667}
2668
2669
2670DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2671{
2672 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2673}
2674
2675static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
2676{
2677 pAhciPortTaskState->uATARegError = 0;
2678 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2679 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2680 | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
2681 | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2682 pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
2683 pAhciPort->uATAPIASC = SCSI_ASC_NONE;
2684}
2685
2686
2687static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
2688{
2689 pAhciPortTaskState->uATARegError = uATAPISenseKey << 4;
2690 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
2691 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2692 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2693 pAhciPort->uATAPISenseKey = uATAPISenseKey;
2694 pAhciPort->uATAPIASC = uATAPIASC;
2695}
2696
2697static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2698{
2699 for (uint32_t i = 0; i < cbSize; i++)
2700 {
2701 if (*pbSrc)
2702 pbDst[i] = *pbSrc++;
2703 else
2704 pbDst[i] = ' ';
2705 }
2706}
2707
2708static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2709{
2710 for (uint32_t i = 0; i < cbSize; i++)
2711 {
2712 if (*pbSrc)
2713 pbDst[i ^ 1] = *pbSrc++;
2714 else
2715 pbDst[i ^ 1] = ' ';
2716 }
2717}
2718
2719static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
2720{
2721 uint16_t *p;
2722 int rc = VINF_SUCCESS;
2723
2724 p = (uint16_t *)pvBuf;
2725 memset(p, 0, 512);
2726 p[0] = RT_H2LE_U16(0x0040);
2727 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2728 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2729 /* Block size; obsolete, but required for the BIOS. */
2730 p[5] = RT_H2LE_U16(512);
2731 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2732 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2733 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2734 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2735 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
2736 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2737 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2738#if ATA_MAX_MULT_SECTORS > 1
2739 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
2740#endif
2741 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
2742 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2743 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2744 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2745 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2746 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
2747 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2748 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2749 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2750 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
2751 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
2752 if (pAhciPort->cMultSectors)
2753 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
2754 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
2755 {
2756 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2757 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2758 }
2759 else
2760 {
2761 /* Report maximum number of sectors possible with LBA28 */
2762 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
2763 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
2764 }
2765 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2766 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2767 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2768 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2769 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2770 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2771 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2772 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2773 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
2774 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2775 p[84] = RT_H2LE_U16(1 << 14);
2776 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
2777 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2778 p[87] = RT_H2LE_U16(1 << 14);
2779 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2780 p[93] = RT_H2LE_U16(0x00);
2781 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2782 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2783 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
2784 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
2785
2786 /* The following are SATA specific */
2787 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2788 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2789
2790 return VINF_SUCCESS;
2791}
2792
2793typedef int (*PAtapiFunc)(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2794
2795static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2796static int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2797static int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2798static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2799static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2800static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2801static int atapiReadCapacitySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2802static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2803static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2804static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2805static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2806static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2807static int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2808//static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2809
2810/**
2811 * Source/sink function indexes for g_apfnAtapiFuncs.
2812 */
2813typedef enum ATAPIFN
2814{
2815 ATAFN_SS_NULL = 0,
2816 ATAFN_SS_ATAPI_GET_CONFIGURATION,
2817 ATAFN_SS_ATAPI_IDENTIFY,
2818 ATAFN_SS_ATAPI_INQUIRY,
2819 ATAFN_SS_ATAPI_MECHANISM_STATUS,
2820 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
2821 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
2822 ATAFN_SS_ATAPI_READ_CAPACITY,
2823 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
2824 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
2825 ATAFN_SS_ATAPI_READ_TOC_MULTI,
2826 ATAFN_SS_ATAPI_READ_TOC_RAW,
2827 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
2828 ATAFN_SS_ATAPI_REQUEST_SENSE,
2829 //ATAFN_SS_ATAPI_PASSTHROUGH,
2830 ATAFN_SS_MAX
2831} ATAPIFN;
2832
2833/**
2834 * Array of source/sink functions, the index is ATAFNSS.
2835 * Make sure ATAFNSS and this array match!
2836 */
2837static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
2838{
2839 NULL,
2840 atapiGetConfigurationSS,
2841 atapiIdentifySS,
2842 atapiInquirySS,
2843 atapiMechanismStatusSS,
2844 atapiModeSenseErrorRecoverySS,
2845 atapiModeSenseCDStatusSS,
2846 atapiReadCapacitySS,
2847 atapiReadDiscInformationSS,
2848 atapiReadTOCNormalSS,
2849 atapiReadTOCMultiSS,
2850 atapiReadTOCRawSS,
2851 atapiReadTrackInformationSS,
2852 atapiRequestSenseSS
2853 //atapiPassthroughSS
2854};
2855
2856static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2857{
2858 uint16_t p[256];
2859 char aSerial[20];
2860 RTUUID Uuid;
2861 int rc;
2862
2863 rc = pAhciPort->pDrvBlock ? pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
2864 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
2865 {
2866 /* Generate a predictable serial for drives which don't have a UUID. */
2867 RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-1a2b3c4d",
2868 pAhciPort->iLUN);
2869 }
2870 else
2871 RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
2872
2873 memset(p, 0, 512);
2874 /* Removable CDROM, 50us response, 12 byte packets */
2875 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
2876 ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
2877 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2878 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2879 ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
2880 ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
2881 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2882 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2883 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2884 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2885 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
2886 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2887 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2888 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2889 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2890 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2891 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2892 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
2893 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
2894 p[75] = RT_H2LE_U16(1); /* queue depth 1 */
2895 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2896 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2897 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
2898 p[83] = RT_H2LE_U16(1 << 14);
2899 p[84] = RT_H2LE_U16(1 << 14);
2900 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
2901 p[86] = RT_H2LE_U16(0);
2902 p[87] = RT_H2LE_U16(1 << 14);
2903 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2904 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
2905
2906 /* The following are SATA specific */
2907 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2908 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2909
2910 /* Copy the buffer in to the scatter gather list. */
2911 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
2912 *pcbData = sizeof(p);
2913
2914 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2915 return VINF_SUCCESS;
2916}
2917
2918static int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2919{
2920 uint8_t aBuf[8];
2921
2922 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
2923 ataH2BE_U32(aBuf + 4, 2048);
2924
2925 /* Copy the buffer in to the scatter gather list. */
2926 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2927 *pcbData = sizeof(aBuf);
2928
2929 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2930 return VINF_SUCCESS;
2931}
2932
2933
2934static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2935{
2936 uint8_t aBuf[34];
2937
2938 memset(aBuf, '\0', 34);
2939 ataH2BE_U16(aBuf, 32);
2940 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
2941 aBuf[3] = 1; /* number of first track */
2942 aBuf[4] = 1; /* number of sessions (LSB) */
2943 aBuf[5] = 1; /* first track number in last session (LSB) */
2944 aBuf[6] = 1; /* last track number in last session (LSB) */
2945 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 */
2946 aBuf[8] = 0; /* disc type = CD-ROM */
2947 aBuf[9] = 0; /* number of sessions (MSB) */
2948 aBuf[10] = 0; /* number of sessions (MSB) */
2949 aBuf[11] = 0; /* number of sessions (MSB) */
2950 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
2951 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
2952
2953 /* Copy the buffer in to the scatter gather list. */
2954 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2955 *pcbData = sizeof(aBuf);
2956
2957 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2958 return VINF_SUCCESS;
2959}
2960
2961
2962static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2963{
2964 uint8_t aBuf[36];
2965
2966 /* Accept address/number type of 1 only, and only track 1 exists. */
2967 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
2968 {
2969 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2970 return VINF_SUCCESS;
2971 }
2972 memset(aBuf, '\0', 36);
2973 ataH2BE_U16(aBuf, 34);
2974 aBuf[2] = 1; /* track number (LSB) */
2975 aBuf[3] = 1; /* session number (LSB) */
2976 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
2977 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 */
2978 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
2979 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
2980 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
2981 aBuf[32] = 0; /* track number (MSB) */
2982 aBuf[33] = 0; /* session number (MSB) */
2983
2984 /* Copy the buffer in to the scatter gather list. */
2985 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2986 *pcbData = sizeof(aBuf);
2987
2988 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2989 return VINF_SUCCESS;
2990}
2991
2992
2993static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2994{
2995 uint8_t aBuf[32];
2996
2997 /* Accept valid request types only, and only starting feature 0. */
2998 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
2999 {
3000 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3001 return VINF_SUCCESS;
3002 }
3003 memset(aBuf, '\0', 32);
3004 ataH2BE_U32(aBuf, 16);
3005 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3006 * way to differentiate them right now is based on the image size). Also
3007 * implement signalling "no current profile" if no medium is loaded. */
3008 ataH2BE_U16(aBuf + 6, 0x08); /* current profile: read-only CD */
3009
3010 ataH2BE_U16(aBuf + 8, 0); /* feature 0: list of profiles supported */
3011 aBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
3012 aBuf[11] = 8; /* additional bytes for profiles */
3013 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3014 * before CD-ROM read capability. */
3015 ataH2BE_U16(aBuf + 12, 0x10); /* profile: read-only DVD */
3016 aBuf[14] = (0 << 0); /* NOT current profile */
3017 ataH2BE_U16(aBuf + 16, 0x08); /* profile: read only CD */
3018 aBuf[18] = (1 << 0); /* current profile */
3019
3020 /* Copy the buffer in to the scatter gather list. */
3021 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3022 *pcbData = sizeof(aBuf);
3023
3024 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3025 return VINF_SUCCESS;
3026}
3027
3028
3029static int atapiInquirySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3030{
3031 uint8_t aBuf[36];
3032
3033 aBuf[0] = 0x05; /* CD-ROM */
3034 aBuf[1] = 0x80; /* removable */
3035 aBuf[2] = 0x00; /* ISO */
3036 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3037 aBuf[4] = 31; /* additional length */
3038 aBuf[5] = 0; /* reserved */
3039 aBuf[6] = 0; /* reserved */
3040 aBuf[7] = 0; /* reserved */
3041 ataSCSIPadStr(aBuf + 8, "VBOX", 8);
3042 ataSCSIPadStr(aBuf + 16, "CD-ROM", 16);
3043 ataSCSIPadStr(aBuf + 32, "1.0", 4);
3044
3045 /* Copy the buffer in to the scatter gather list. */
3046 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3047 *pcbData = sizeof(aBuf);
3048
3049 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3050 return VINF_SUCCESS;
3051}
3052
3053
3054static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3055{
3056 uint8_t aBuf[16];
3057
3058 ataH2BE_U16(&aBuf[0], 16 + 6);
3059 aBuf[2] = 0x70;
3060 aBuf[3] = 0;
3061 aBuf[4] = 0;
3062 aBuf[5] = 0;
3063 aBuf[6] = 0;
3064 aBuf[7] = 0;
3065
3066 aBuf[8] = 0x01;
3067 aBuf[9] = 0x06;
3068 aBuf[10] = 0x00;
3069 aBuf[11] = 0x05;
3070 aBuf[12] = 0x00;
3071 aBuf[13] = 0x00;
3072 aBuf[14] = 0x00;
3073 aBuf[15] = 0x00;
3074
3075 /* Copy the buffer in to the scatter gather list. */
3076 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3077 *pcbData = sizeof(aBuf);
3078
3079 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3080 return VINF_SUCCESS;
3081}
3082
3083
3084static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3085{
3086 uint8_t aBuf[40];
3087
3088 ataH2BE_U16(&aBuf[0], 38);
3089 aBuf[2] = 0x70;
3090 aBuf[3] = 0;
3091 aBuf[4] = 0;
3092 aBuf[5] = 0;
3093 aBuf[6] = 0;
3094 aBuf[7] = 0;
3095
3096 aBuf[8] = 0x2a;
3097 aBuf[9] = 30; /* page length */
3098 aBuf[10] = 0x08; /* DVD-ROM read support */
3099 aBuf[11] = 0x00; /* no write support */
3100 /* The following claims we support audio play. This is obviously false,
3101 * but the Linux generic CDROM support makes many features depend on this
3102 * capability. If it's not set, this causes many things to be disabled. */
3103 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3104 aBuf[13] = 0x00; /* no subchannel reads supported */
3105 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3106 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3107 aBuf[14] |= 1 << 1; /* report lock state */
3108 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3109 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3110 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3111 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3112 Just write the value DevATA is using. */
3113 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3114 aBuf[24] = 0; /* reserved */
3115 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3116 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3117 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3118 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3119 aBuf[32] = 0; /* reserved */
3120 aBuf[33] = 0; /* reserved */
3121 aBuf[34] = 0; /* reserved */
3122 aBuf[35] = 1; /* rotation control CAV */
3123 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3124 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3125
3126 /* Copy the buffer in to the scatter gather list. */
3127 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3128 *pcbData = sizeof(aBuf);
3129
3130 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3131 return VINF_SUCCESS;
3132}
3133
3134
3135static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3136{
3137 uint8_t aBuf[18];
3138
3139 memset(&aBuf[0], 0, 18);
3140 aBuf[0] = 0x70 | (1 << 7);
3141 aBuf[2] = pAhciPort->uATAPISenseKey;
3142 aBuf[7] = 10;
3143 aBuf[12] = pAhciPort->uATAPIASC;
3144
3145 /* Copy the buffer in to the scatter gather list. */
3146 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3147 *pcbData = sizeof(aBuf);
3148
3149 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3150 return VINF_SUCCESS;
3151}
3152
3153
3154static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3155{
3156 uint8_t aBuf[8];
3157
3158 ataH2BE_U16(&aBuf[0], 0);
3159 /* no current LBA */
3160 aBuf[2] = 0;
3161 aBuf[3] = 0;
3162 aBuf[4] = 0;
3163 aBuf[5] = 1;
3164 ataH2BE_U16(aBuf + 6, 0);
3165
3166 /* Copy the buffer in to the scatter gather list. */
3167 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3168 *pcbData = sizeof(aBuf);
3169
3170 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3171 return VINF_SUCCESS;
3172}
3173
3174
3175static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3176{
3177 uint8_t aBuf[20], *q, iStartTrack;
3178 bool fMSF;
3179 uint32_t cbSize;
3180
3181 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3182 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3183 if (iStartTrack > 1 && iStartTrack != 0xaa)
3184 {
3185 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3186 return VINF_SUCCESS;
3187 }
3188 q = aBuf + 2;
3189 *q++ = 1; /* first session */
3190 *q++ = 1; /* last session */
3191 if (iStartTrack <= 1)
3192 {
3193 *q++ = 0; /* reserved */
3194 *q++ = 0x14; /* ADR, control */
3195 *q++ = 1; /* track number */
3196 *q++ = 0; /* reserved */
3197 if (fMSF)
3198 {
3199 *q++ = 0; /* reserved */
3200 ataLBA2MSF(q, 0);
3201 q += 3;
3202 }
3203 else
3204 {
3205 /* sector 0 */
3206 ataH2BE_U32(q, 0);
3207 q += 4;
3208 }
3209 }
3210 /* lead out track */
3211 *q++ = 0; /* reserved */
3212 *q++ = 0x14; /* ADR, control */
3213 *q++ = 0xaa; /* track number */
3214 *q++ = 0; /* reserved */
3215 if (fMSF)
3216 {
3217 *q++ = 0; /* reserved */
3218 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3219 q += 3;
3220 }
3221 else
3222 {
3223 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3224 q += 4;
3225 }
3226 cbSize = q - aBuf;
3227 ataH2BE_U16(aBuf, cbSize - 2);
3228
3229 /* Copy the buffer in to the scatter gather list. */
3230 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3231 *pcbData = cbSize;
3232
3233 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3234 return VINF_SUCCESS;
3235}
3236
3237
3238static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3239{
3240 uint8_t aBuf[12];
3241 bool fMSF;
3242
3243 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3244 /* multi session: only a single session defined */
3245/** @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. */
3246 memset(aBuf, 0, 12);
3247 aBuf[1] = 0x0a;
3248 aBuf[2] = 0x01;
3249 aBuf[3] = 0x01;
3250 aBuf[5] = 0x14; /* ADR, control */
3251 aBuf[6] = 1; /* first track in last complete session */
3252 if (fMSF)
3253 {
3254 aBuf[8] = 0; /* reserved */
3255 ataLBA2MSF(&aBuf[9], 0);
3256 }
3257 else
3258 {
3259 /* sector 0 */
3260 ataH2BE_U32(aBuf + 8, 0);
3261 }
3262
3263 /* Copy the buffer in to the scatter gather list. */
3264 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3265 *pcbData = sizeof(aBuf);
3266
3267 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3268 return VINF_SUCCESS;
3269}
3270
3271
3272static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3273{
3274 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3275 uint8_t *q, iStartTrack;
3276 bool fMSF;
3277 uint32_t cbSize;
3278
3279 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3280 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3281
3282 q = aBuf + 2;
3283 *q++ = 1; /* first session */
3284 *q++ = 1; /* last session */
3285
3286 *q++ = 1; /* session number */
3287 *q++ = 0x14; /* data track */
3288 *q++ = 0; /* track number */
3289 *q++ = 0xa0; /* first track in program area */
3290 *q++ = 0; /* min */
3291 *q++ = 0; /* sec */
3292 *q++ = 0; /* frame */
3293 *q++ = 0;
3294 *q++ = 1; /* first track */
3295 *q++ = 0x00; /* disk type CD-DA or CD data */
3296 *q++ = 0;
3297
3298 *q++ = 1; /* session number */
3299 *q++ = 0x14; /* data track */
3300 *q++ = 0; /* track number */
3301 *q++ = 0xa1; /* last track in program area */
3302 *q++ = 0; /* min */
3303 *q++ = 0; /* sec */
3304 *q++ = 0; /* frame */
3305 *q++ = 0;
3306 *q++ = 1; /* last track */
3307 *q++ = 0;
3308 *q++ = 0;
3309
3310 *q++ = 1; /* session number */
3311 *q++ = 0x14; /* data track */
3312 *q++ = 0; /* track number */
3313 *q++ = 0xa2; /* lead-out */
3314 *q++ = 0; /* min */
3315 *q++ = 0; /* sec */
3316 *q++ = 0; /* frame */
3317 if (fMSF)
3318 {
3319 *q++ = 0; /* reserved */
3320 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3321 q += 3;
3322 }
3323 else
3324 {
3325 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3326 q += 4;
3327 }
3328
3329 *q++ = 1; /* session number */
3330 *q++ = 0x14; /* ADR, control */
3331 *q++ = 0; /* track number */
3332 *q++ = 1; /* point */
3333 *q++ = 0; /* min */
3334 *q++ = 0; /* sec */
3335 *q++ = 0; /* frame */
3336 if (fMSF)
3337 {
3338 *q++ = 0; /* reserved */
3339 ataLBA2MSF(q, 0);
3340 q += 3;
3341 }
3342 else
3343 {
3344 /* sector 0 */
3345 ataH2BE_U32(q, 0);
3346 q += 4;
3347 }
3348
3349 cbSize = q - aBuf;
3350 ataH2BE_U16(aBuf, cbSize - 2);
3351
3352 /* Copy the buffer in to the scatter gather list. */
3353 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3354 *pcbData = cbSize;
3355
3356 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3357 return VINF_SUCCESS;
3358}
3359
3360static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
3361{
3362 int cbTransfered;
3363 int rc, rcSourceSink;
3364
3365 /* Create scatter gather list. */
3366 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
3367 if (RT_FAILURE(rc))
3368 AssertMsgFailed(("Getting number of list elements failed rc=%Rrc\n", rc));
3369
3370 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
3371
3372 pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
3373
3374 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
3375 if (RT_FAILURE(rc))
3376 AssertMsgFailed(("Destroying list failed rc=%Rrc\n", rc));
3377
3378 /* Write updated command header into memory of the guest. */
3379 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
3380
3381 return rcSourceSink;
3382}
3383
3384static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
3385{
3386 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
3387
3388 switch (cbSector)
3389 {
3390 case 2048:
3391 pAhciPortTaskState->uOffset = iATAPILBA * cbSector;
3392 pAhciPortTaskState->cbTransfer = cSectors * cbSector;
3393 break;
3394 case 2352:
3395 {
3396 AssertMsgFailed(("2352 read\n"));
3397 /* @todo: This is quite difficult as the data transfer is not handled here
3398 We need to add the sync bytes etc. here and modify the pointers
3399 and size of the sg entries. */
3400#if 0
3401 uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
3402
3403 for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
3404 {
3405 /* sync bytes */
3406 *pbBuf++ = 0x00;
3407 memset(pbBuf, 0xff, 11);
3408 pbBuf += 11;
3409 /* MSF */
3410 ataLBA2MSF(pbBuf, i);
3411 pbBuf += 3;
3412 *pbBuf++ = 0x01; /* mode 1 data */
3413 /* data */
3414 rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
3415 if (RT_FAILURE(rc))
3416 break;
3417 pbBuf += 2048;
3418 /* ECC */
3419 memset(pbBuf, 0, 288);
3420 pbBuf += 288;
3421 }
3422#endif
3423 pAhciPortTaskState->uOffset = iATAPILBA * 2048;
3424 pAhciPortTaskState->cbTransfer = cSectors * 2048;
3425 }
3426 break;
3427 default:
3428 AssertMsgFailed(("Unsupported sectors size\n"));
3429 break;
3430 }
3431
3432 return VINF_SUCCESS;
3433}
3434
3435static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3436{
3437 int rc = PDMBLOCKTXDIR_NONE;
3438 const uint8_t *pbPacket;
3439 uint32_t cbMax;
3440
3441 pbPacket = pAhciPortTaskState->aATAPICmd;
3442
3443 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
3444
3445 switch (pbPacket[0])
3446 {
3447 case SCSI_TEST_UNIT_READY:
3448 if (pAhciPort->cNotifiedMediaChange > 0)
3449 {
3450 if (pAhciPort->cNotifiedMediaChange-- > 2)
3451 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3452 else
3453 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3454 }
3455 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3456 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3457 else
3458 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3459 break;
3460 case SCSI_MODE_SENSE_10:
3461 {
3462 uint8_t uPageControl, uPageCode;
3463 cbMax = ataBE2H_U16(pbPacket + 7);
3464 uPageControl = pbPacket[2] >> 6;
3465 uPageCode = pbPacket[2] & 0x3f;
3466 switch (uPageControl)
3467 {
3468 case SCSI_PAGECONTROL_CURRENT:
3469 switch (uPageCode)
3470 {
3471 case SCSI_MODEPAGE_ERROR_RECOVERY:
3472 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
3473 break;
3474 case SCSI_MODEPAGE_CD_STATUS:
3475 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
3476 break;
3477 default:
3478 goto error_cmd;
3479 }
3480 break;
3481 case SCSI_PAGECONTROL_CHANGEABLE:
3482 goto error_cmd;
3483 case SCSI_PAGECONTROL_DEFAULT:
3484 goto error_cmd;
3485 default:
3486 case SCSI_PAGECONTROL_SAVED:
3487 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
3488 break;
3489 }
3490 }
3491 break;
3492 case SCSI_REQUEST_SENSE:
3493 cbMax = pbPacket[4];
3494 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_REQUEST_SENSE);
3495 break;
3496 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
3497 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3498 {
3499 if (pbPacket[4] & 1)
3500 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
3501 else
3502 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
3503 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3504 }
3505 else
3506 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3507 break;
3508 case SCSI_READ_10:
3509 case SCSI_READ_12:
3510 {
3511 uint32_t cSectors, iATAPILBA;
3512
3513 if (pAhciPort->cNotifiedMediaChange > 0)
3514 {
3515 pAhciPort->cNotifiedMediaChange-- ;
3516 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3517 break;
3518 }
3519 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3520 {
3521 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3522 break;
3523 }
3524 if (pbPacket[0] == SCSI_READ_10)
3525 cSectors = ataBE2H_U16(pbPacket + 7);
3526 else
3527 cSectors = ataBE2H_U32(pbPacket + 6);
3528 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3529 if (cSectors == 0)
3530 {
3531 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3532 break;
3533 }
3534 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3535 {
3536 /* Rate limited logging, one log line per second. For
3537 * guests that insist on reading from places outside the
3538 * valid area this often generates too many release log
3539 * entries otherwise. */
3540 static uint64_t uLastLogTS = 0;
3541 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3542 {
3543 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3544 uLastLogTS = RTTimeMilliTS();
3545 }
3546 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3547 break;
3548 }
3549 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3550 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3551 }
3552 break;
3553 case SCSI_READ_CD:
3554 {
3555 uint32_t cSectors, iATAPILBA;
3556
3557 if (pAhciPort->cNotifiedMediaChange > 0)
3558 {
3559 pAhciPort->cNotifiedMediaChange-- ;
3560 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3561 break;
3562 }
3563 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3564 {
3565 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3566 break;
3567 }
3568 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
3569 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3570 if (cSectors == 0)
3571 {
3572 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3573 break;
3574 }
3575 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3576 {
3577 /* Rate limited logging, one log line per second. For
3578 * guests that insist on reading from places outside the
3579 * valid area this often generates too many release log
3580 * entries otherwise. */
3581 static uint64_t uLastLogTS = 0;
3582 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3583 {
3584 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3585 uLastLogTS = RTTimeMilliTS();
3586 }
3587 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3588 break;
3589 }
3590 switch (pbPacket[9] & 0xf8)
3591 {
3592 case 0x00:
3593 /* nothing */
3594 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3595 break;
3596 case 0x10:
3597 /* normal read */
3598 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3599 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3600 break;
3601 case 0xf8:
3602 /* read all data */
3603 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
3604 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3605 break;
3606 default:
3607 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
3608 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3609 break;
3610 }
3611 }
3612 break;
3613 case SCSI_SEEK_10:
3614 {
3615 uint32_t iATAPILBA;
3616 if (pAhciPort->cNotifiedMediaChange > 0)
3617 {
3618 pAhciPort->cNotifiedMediaChange-- ;
3619 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3620 break;
3621 }
3622 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3623 {
3624 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3625 break;
3626 }
3627 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3628 if (iATAPILBA > pAhciPort->cTotalSectors)
3629 {
3630 /* Rate limited logging, one log line per second. For
3631 * guests that insist on seeking to places outside the
3632 * valid area this often generates too many release log
3633 * entries otherwise. */
3634 static uint64_t uLastLogTS = 0;
3635 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3636 {
3637 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
3638 uLastLogTS = RTTimeMilliTS();
3639 }
3640 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3641 break;
3642 }
3643 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3644 pAhciPortTaskState->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
3645 }
3646 break;
3647 case SCSI_START_STOP_UNIT:
3648 {
3649 int rc = VINF_SUCCESS;
3650 switch (pbPacket[4] & 3)
3651 {
3652 case 0: /* 00 - Stop motor */
3653 case 1: /* 01 - Start motor */
3654 break;
3655 case 2: /* 10 - Eject media */
3656 /* This must be done from EMT. */
3657 {
3658 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3659 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
3660
3661 rc = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
3662 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
3663 AssertReleaseRC(rc);
3664 }
3665 break;
3666 case 3: /* 11 - Load media */
3667 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
3668 break;
3669 }
3670 if (RT_SUCCESS(rc))
3671 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3672 else
3673 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
3674 }
3675 break;
3676 case SCSI_MECHANISM_STATUS:
3677 {
3678 cbMax = ataBE2H_U16(pbPacket + 8);
3679 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MECHANISM_STATUS);
3680 }
3681 break;
3682 case SCSI_READ_TOC_PMA_ATIP:
3683 {
3684 uint8_t format;
3685
3686 if (pAhciPort->cNotifiedMediaChange > 0)
3687 {
3688 pAhciPort->cNotifiedMediaChange-- ;
3689 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3690 break;
3691 }
3692 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3693 {
3694 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3695 break;
3696 }
3697 cbMax = ataBE2H_U16(pbPacket + 7);
3698 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
3699 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
3700 * the other field is clear... */
3701 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
3702 switch (format)
3703 {
3704 case 0:
3705 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
3706 break;
3707 case 1:
3708 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_MULTI);
3709 break;
3710 case 2:
3711 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_RAW);
3712 break;
3713 default:
3714 error_cmd:
3715 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3716 break;
3717 }
3718 }
3719 break;
3720 case SCSI_READ_CAPACITY:
3721 if (pAhciPort->cNotifiedMediaChange > 0)
3722 {
3723 pAhciPort->cNotifiedMediaChange-- ;
3724 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3725 break;
3726 }
3727 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3728 {
3729 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3730 break;
3731 }
3732 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_CAPACITY);
3733 break;
3734 case SCSI_READ_DISC_INFORMATION:
3735 if (pAhciPort->cNotifiedMediaChange > 0)
3736 {
3737 pAhciPort->cNotifiedMediaChange-- ;
3738 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3739 break;
3740 }
3741 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3742 {
3743 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3744 break;
3745 }
3746 cbMax = ataBE2H_U16(pbPacket + 7);
3747 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
3748 break;
3749 case SCSI_READ_TRACK_INFORMATION:
3750 if (pAhciPort->cNotifiedMediaChange > 0)
3751 {
3752 pAhciPort->cNotifiedMediaChange-- ;
3753 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3754 break;
3755 }
3756 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3757 {
3758 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3759 break;
3760 }
3761 cbMax = ataBE2H_U16(pbPacket + 7);
3762 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
3763 break;
3764 case SCSI_GET_CONFIGURATION:
3765 /* No media change stuff here, it can confuse Linux guests. */
3766 cbMax = ataBE2H_U16(pbPacket + 7);
3767 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_CONFIGURATION);
3768 break;
3769 case SCSI_INQUIRY:
3770 cbMax = pbPacket[4];
3771 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_INQUIRY);
3772 break;
3773 default:
3774 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
3775 break;
3776 }
3777
3778 return rc;
3779}
3780
3781/**
3782 * Reset all values after a reset of the attached storage device.
3783 *
3784 * @returns nothing
3785 * @param pAhciPort The port the device is attached to.
3786 * @param pAhciPortTaskState The state to get the tag number from.
3787 */
3788static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3789{
3790 /* Send a status good D2H FIS. */
3791 pAhciPort->fResetDevice = false;
3792 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3793 ahciPostFirstD2HFisIntoMemory(pAhciPort);
3794
3795 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
3796 pAhciPort->regSIG = 0x101;
3797 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3798
3799 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
3800}
3801
3802/**
3803 * Build a D2H FIS and post into the memory area of the guest.
3804 *
3805 * @returns Nothing
3806 * @param pAhciPort The port of the SATA controller.
3807 * @param pAhciPortTaskState The state of the task.
3808 * @param pCmdFis Pointer to the command FIS from the guest.
3809 * @param fInterrupt If an interrupt should be send to the guest.
3810 */
3811static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis, bool fInterrupt)
3812{
3813 uint8_t d2hFis[20];
3814 bool fAssertIntr = false;
3815 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3816
3817 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
3818
3819 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3820 {
3821 memset(&d2hFis[0], 0, sizeof(d2hFis));
3822 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
3823 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3824 d2hFis[AHCI_CMDFIS_STS] = pAhciPortTaskState->uATARegStatus;
3825 d2hFis[AHCI_CMDFIS_ERR] = pAhciPortTaskState->uATARegError;
3826 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3827 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3828 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3829 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3830 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3831 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3832 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3833 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3834 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3835
3836 /* Update registers. */
3837 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3838
3839 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
3840
3841 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3842 {
3843 /* Error bit is set. */
3844 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3845 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3846 fAssertIntr = true;
3847 }
3848
3849 if (fInterrupt)
3850 {
3851 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
3852 /* Check if we should assert an interrupt */
3853 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
3854 fAssertIntr = true;
3855 }
3856
3857 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3858
3859 if (fAssertIntr)
3860 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3861 }
3862}
3863
3864/**
3865 * Build a SDB Fis and post it into the memory area of the guest.
3866 *
3867 * @returns Nothing
3868 * @param pAhciPort The port for which the SDB Fis is send.
3869 * @param uFinishedTasks Bitmask of finished tasks.
3870 * @param pAhciPortTaskState The state of the last task.
3871 * @param fInterrupt If an interrupt should be asserted.
3872 */
3873static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
3874{
3875 uint32_t sdbFis[2];
3876 bool fAssertIntr = false;
3877 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3878
3879 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3880
3881 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3882 {
3883 memset(&sdbFis[0], 0, sizeof(sdbFis));
3884 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3885 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3886 sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3887 sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3888 sdbFis[1] = uFinishedTasks;
3889
3890 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3891
3892 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3893 {
3894 /* Error bit is set. */
3895 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3896 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3897 fAssertIntr = true;
3898 }
3899
3900 if (fInterrupt)
3901 {
3902 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
3903 /* Check if we should assert an interrupt */
3904 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
3905 fAssertIntr = true;
3906 }
3907
3908 /* Update registers. */
3909 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3910
3911 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3912
3913 if (fAssertIntr)
3914 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3915 }
3916}
3917
3918static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
3919{
3920 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
3921 if (fLBA48)
3922 {
3923 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
3924 return 65536;
3925 else
3926 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
3927 }
3928 else
3929 {
3930 if (!pCmdFis[AHCI_CMDFIS_SECTC])
3931 return 256;
3932 else
3933 return pCmdFis[AHCI_CMDFIS_SECTC];
3934 }
3935}
3936
3937static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
3938{
3939 uint64_t iLBA;
3940 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
3941 {
3942 /* any LBA variant */
3943 if (fLBA48)
3944 {
3945 /* LBA48 */
3946 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3947 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3948 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3949 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3950 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3951 pCmdFis[AHCI_CMDFIS_SECTN];
3952 }
3953 else
3954 {
3955 /* LBA */
3956 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3957 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
3958 }
3959 }
3960 else
3961 {
3962 /* CHS */
3963 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
3964 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
3965 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
3966 }
3967 return iLBA;
3968}
3969
3970static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
3971{
3972 uint64_t uLBA;
3973
3974 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3975 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3976 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3977 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3978 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3979 pCmdFis[AHCI_CMDFIS_SECTN];
3980
3981 return uLBA;
3982}
3983
3984DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
3985{
3986 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
3987 return 65536;
3988 else
3989 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
3990}
3991
3992DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
3993{
3994 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
3995}
3996
3997static int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
3998{
3999 if (pAhciPortTaskState->cSGListSize < cSGList)
4000 {
4001 /* The entries are not allocated yet or the number is too small. */
4002 if (pAhciPortTaskState->cSGListSize)
4003 {
4004 RTMemFree(pAhciPortTaskState->pSGListHead);
4005 RTMemFree(pAhciPortTaskState->paSGEntries);
4006 }
4007
4008 /* Allocate R3 scatter gather list. */
4009 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
4010 if (!pAhciPortTaskState->pSGListHead)
4011 return VERR_NO_MEMORY;
4012
4013 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
4014 if (!pAhciPortTaskState->paSGEntries)
4015 return VERR_NO_MEMORY;
4016
4017 /* Reset usage statistics. */
4018 pAhciPortTaskState->cSGListSize = cSGList;
4019 pAhciPortTaskState->cSGListTooBig = 0;
4020 }
4021 else if (pAhciPortTaskState->cSGListSize > cSGList)
4022 {
4023 /*
4024 * The list is too big. Increment counter.
4025 * So that the destroying function can free
4026 * the list if it is too big too many times
4027 * in a row.
4028 */
4029 pAhciPortTaskState->cSGListTooBig++;
4030 }
4031 else
4032 {
4033 /*
4034 * Needed entries matches current size.
4035 * Reset counter.
4036 */
4037 pAhciPortTaskState->cSGListTooBig = 0;
4038 }
4039
4040 pAhciPortTaskState->cSGEntries = cSGList;
4041
4042 if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4043 {
4044 if (pAhciPortTaskState->pvBufferUnaligned)
4045 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4046
4047 Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4048
4049 pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
4050 if (!pAhciPortTaskState->pvBufferUnaligned)
4051 return VERR_NO_MEMORY;
4052
4053 pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
4054 }
4055
4056 /* Make debugging easier. */
4057#ifdef DEBUG
4058 memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
4059 memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4060 if (pAhciPortTaskState->pvBufferUnaligned)
4061 memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4062#endif
4063
4064 return VINF_SUCCESS;
4065}
4066
4067/**
4068 * Fallback scatter gather list creator.
4069 * Used if the normal one fails in PDMDevHlpPhysGCPhys2CCPtr() or
4070 * PDMDevHlpPhysGCPhys2CCPtrReadonly()
4071 *
4072 * returns VBox status code.
4073 * @param pAhciPort The ahci port.
4074 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4075 * @param fReadonly If the mappings should be readonly.
4076 * @param cSGEntriesProcessed Number of entries the normal creator procecssed
4077 * before an error occurred. Used to free
4078 * any ressources allocated before.
4079 * @thread EMT
4080 */
4081static int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
4082 bool fReadonly, unsigned cSGEntriesProcessed)
4083{
4084 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4085 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4086 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4087
4088 AssertPtr(pAhciPortTaskState->pSGListHead);
4089 AssertPtr(pAhciPortTaskState->paSGEntries);
4090
4091 for (unsigned cSGEntryCurr = 0; cSGEntryCurr < cSGEntriesProcessed; cSGEntryCurr++)
4092 {
4093 if (pSGInfoCurr->fGuestMemory)
4094 {
4095 /* Release the lock. */
4096 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4097 }
4098
4099 /* Go to the next entry. */
4100 pSGInfoCurr++;
4101 }
4102
4103 if (pAhciPortTaskState->pvBufferUnaligned)
4104 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4105
4106 pAhciPortTaskState->cSGListTooBig = 0;
4107
4108 RTMemFree(pAhciPortTaskState->pSGListHead);
4109 RTMemFree(pAhciPortTaskState->paSGEntries);
4110 pAhciPortTaskState->cSGEntries = 1;
4111 pAhciPortTaskState->cSGListSize = 1;
4112 pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbTransfer;
4113
4114 /* Allocate new buffers and SG lists. */
4115 pAhciPortTaskState->pvBufferUnaligned = RTMemAlloc(pAhciPortTaskState->cbTransfer);
4116 if (!pAhciPortTaskState->pvBufferUnaligned)
4117 return VERR_NO_MEMORY;
4118
4119 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(1 * sizeof(PDMDATASEG));
4120 if (!pAhciPortTaskState->pSGListHead)
4121 {
4122 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4123 return VERR_NO_MEMORY;
4124 }
4125
4126 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
4127 if (!pAhciPortTaskState->paSGEntries)
4128 {
4129 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4130 RTMemFree(pAhciPortTaskState->pSGListHead);
4131 return VERR_NO_MEMORY;
4132 }
4133
4134 /* Set pointers. */
4135 pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbTransfer;
4136 pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4137
4138 pAhciPortTaskState->paSGEntries[0].fGuestMemory = false;
4139 pAhciPortTaskState->paSGEntries[0].u.temp.cUnaligned = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4140 pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4141 pAhciPortTaskState->paSGEntries[0].u.temp.pvBuf = pAhciPortTaskState->pvBufferUnaligned;
4142
4143 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4144 ahciCopyFromSGListIntoBuffer(pDevIns, &pAhciPortTaskState->paSGEntries[0]);
4145
4146 return VINF_SUCCESS;
4147}
4148
4149/**
4150 * Create scatter gather list descriptors.
4151 *
4152 * @returns VBox status code.
4153 * @param pAhciPort The ahci port.
4154 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4155 * @param fReadonly If the mappings should be readonly.
4156 * @thread EMT
4157 */
4158static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly)
4159{
4160 int rc = VINF_SUCCESS;
4161 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4162 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4163 unsigned cActualSGEntry;
4164 unsigned cSGEntriesR3 = 0; /* Needed scatter gather list entries in R3. */
4165 unsigned cSGEntriesProcessed = 0; /* Number of SG entries procesed. */
4166 SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
4167 unsigned cSGLEntriesGCRead;
4168 unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
4169 RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
4170 uint32_t cbSegment; /* Size of the current segments in bytes. */
4171 bool fUnaligned; /* Flag whether the current buffer is unaligned. */
4172 uint32_t cbUnaligned; /* Size of the unaligned buffers. */
4173 uint32_t cUnaligned;
4174 bool fDoMapping = false;
4175 RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
4176 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
4177 PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
4178 PPDMDATASEG pSGEntryCurr = NULL;
4179 PPDMDATASEG pSGEntryPrev = NULL;
4180 RTGCPHYS GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4181 uint8_t *pu8BufferUnalignedPos = NULL;
4182 uint32_t cbUnalignedComplete = 0;
4183
4184 STAM_PROFILE_START(&pAhciPort->StatProfileMapIntoR3, a);
4185
4186 /*
4187 * 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
4188 * page aligned. Hence the number of SG list entries in the guest can differ from the ones we need
4189 * because PDMDevHlpPhysGCPhys2CCPtr works only on a page base.
4190 * In the first pass we calculate the number of segments in R3 and in the second pass we map the guest segments into R3.
4191 */
4192 for (int i = 0; i < 2; i++)
4193 {
4194 cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4195 ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
4196
4197 /* Set start address of the entries. */
4198 GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4199 fUnaligned = false;
4200 cbUnaligned = 0;
4201 cUnaligned = 0;
4202 GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4203
4204 if (fDoMapping)
4205 {
4206 ahciLog(("%s: cSGEntriesR3=%u\n", __FUNCTION__, cSGEntriesR3));
4207 /* The number of needed SG entries in R3 is known. Allocate needed memory. */
4208 rc = ahciScatterGatherListAllocate(pAhciPortTaskState, cSGEntriesR3, cbUnalignedComplete);
4209 AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc));
4210
4211 /* We are now able to map the pages into R3. */
4212 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4213 pSGEntryCurr = pAhciPortTaskState->pSGListHead;
4214 pSGEntryPrev = pSGEntryCurr;
4215 pSGInfoPrev = pSGInfoCurr;
4216 /* Initialize first segment to remove the need for additional if checks later in the code. */
4217 pSGEntryCurr->pvSeg = NULL;
4218 pSGEntryCurr->cbSeg = 0;
4219 pSGInfoCurr->fGuestMemory= false;
4220 pu8BufferUnalignedPos = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
4221 }
4222
4223 do
4224 {
4225 cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
4226 cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4227
4228 /* Read the SG entries. */
4229 PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4230
4231 for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
4232 {
4233 RTGCPHYS GCPhysAddrDataBase;
4234 uint32_t cbDataToTransfer;
4235
4236 ahciLog(("%s: cActualSGEntry=%u cSGEntriesR3=%u\n", __FUNCTION__, cActualSGEntry, cSGEntriesR3));
4237
4238 cbDataToTransfer = (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4239 ahciLog(("%s: cbDataToTransfer=%u\n", __FUNCTION__, cbDataToTransfer));
4240
4241 /* Check if the buffer is sector aligned. */
4242 if (cbDataToTransfer % 512 != 0)
4243 {
4244 if (!fUnaligned)
4245 {
4246 /* We are not in an unaligned buffer but this is the first unaligned one. */
4247 fUnaligned = true;
4248 cbUnaligned = cbDataToTransfer;
4249 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4250 cSGEntriesR3++;
4251 cUnaligned = 1;
4252 ahciLog(("%s: Unaligned buffer found cb=%d\n", __FUNCTION__, cbDataToTransfer));
4253 }
4254 else
4255 {
4256 /* We are already in an unaligned buffer and this one is unaligned too. */
4257 cbUnaligned += cbDataToTransfer;
4258 cUnaligned++;
4259 }
4260
4261 cbUnalignedComplete += cbDataToTransfer;
4262 }
4263 else /* Guest segment size is sector aligned. */
4264 {
4265 if (fUnaligned)
4266 {
4267 if (cbUnaligned % 512 == 0)
4268 {
4269 /*
4270 * The last buffer started at an offset
4271 * not aligned to a sector boundary but this buffer
4272 * is sector aligned. Check if the current size of all
4273 * unaligned segments is a multiple of a sector.
4274 * If that's the case we can now map the segments again into R3.
4275 */
4276 fUnaligned = false;
4277
4278 if (fDoMapping)
4279 {
4280 /* Set up the entry. */
4281 pSGInfoCurr->fGuestMemory = false;
4282 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4283 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4284 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4285
4286 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4287 pSGEntryCurr->cbSeg = cbUnaligned;
4288 pu8BufferUnalignedPos += cbUnaligned;
4289
4290 /*
4291 * If the transfer is to the device we need to copy the content of the not mapped guest
4292 * segments into the temporary buffer.
4293 */
4294 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4295 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4296
4297 /* Advance to next entry saving the pointers to the current ones. */
4298 pSGEntryPrev = pSGEntryCurr;
4299 pSGInfoPrev = pSGInfoCurr;
4300 pSGInfoCurr++;
4301 pSGEntryCurr++;
4302 cSGEntriesProcessed++;
4303 }
4304 }
4305 else
4306 {
4307 cbUnaligned += cbDataToTransfer;
4308 cbUnalignedComplete += cbDataToTransfer;
4309 cUnaligned++;
4310 }
4311 }
4312 else
4313 {
4314 /*
4315 * The size of the guest segment is sector aligned but it is possible that the segment crosses
4316 * a page boundary in a way splitting the segment into parts which are not sector aligned.
4317 * We have to treat them like unaligned guest segments then.
4318 */
4319 GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntry[cActualSGEntry].u32DBAUp, aSGLEntry[cActualSGEntry].u32DBA);
4320
4321 ahciLog(("%s: GCPhysAddrDataBase=%RGp\n", __FUNCTION__, GCPhysAddrDataBase));
4322
4323 /*
4324 * Check if the physical address is page aligned.
4325 */
4326 if (GCPhysAddrDataBase & PAGE_OFFSET_MASK)
4327 {
4328 RTGCPHYS GCPhysAddrDataNextPage = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase) + PAGE_SIZE;
4329 /* Difference from the buffer start to the next page boundary. */
4330 uint32_t u32GCPhysAddrDiff = GCPhysAddrDataNextPage - GCPhysAddrDataBase;
4331
4332 if (u32GCPhysAddrDiff % 512 != 0)
4333 {
4334 if (!fUnaligned)
4335 {
4336 /* We are not in an unaligned buffer but this is the first unaligned one. */
4337 fUnaligned = true;
4338 cbUnaligned = cbDataToTransfer;
4339 GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
4340 cSGEntriesR3++;
4341 cUnaligned = 1;
4342 ahciLog(("%s: Guest segment is sector aligned but crosses a page boundary cb=%d\n", __FUNCTION__, cbDataToTransfer));
4343 }
4344 else
4345 {
4346 /* We are already in an unaligned buffer and this one is unaligned too. */
4347 cbUnaligned += cbDataToTransfer;
4348 cUnaligned++;
4349 }
4350
4351 cbUnalignedComplete += cbDataToTransfer;
4352 }
4353 else
4354 {
4355 ahciLog(("%s: Align page: GCPhysAddrDataBase=%RGp GCPhysAddrDataNextPage=%RGp\n",
4356 __FUNCTION__, GCPhysAddrDataBase, GCPhysAddrDataNextPage));
4357
4358 RTGCPHYS GCPhysBufferPageAligned = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase);
4359
4360 /* Check if the mapping ends at the page boundary and set segment size accordingly. */
4361 cbSegment = (cbDataToTransfer < u32GCPhysAddrDiff)
4362 ? cbDataToTransfer
4363 : u32GCPhysAddrDiff;
4364 /* Subtract size of the buffer in the actual page. */
4365 cbDataToTransfer -= cbSegment;
4366
4367 if (GCPhysBufferPageAlignedPrev != GCPhysBufferPageAligned)
4368 {
4369 /* We don't need to map the buffer if it is in the same page as the previous one. */
4370 if (fDoMapping)
4371 {
4372 uint8_t *pbMapping;
4373
4374 pSGInfoCurr->fGuestMemory = true;
4375
4376 /* Create the mapping. */
4377 if (fReadonly)
4378 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysBufferPageAligned,
4379 0, (const void **)&pbMapping,
4380 &pSGInfoCurr->u.direct.PageLock);
4381 else
4382 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysBufferPageAligned,
4383 0, (void **)&pbMapping,
4384 &pSGInfoCurr->u.direct.PageLock);
4385
4386 if (RT_FAILURE(rc))
4387 {
4388 /* Mapping failed. Fall back to a bounce buffer. */
4389 ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
4390 __FUNCTION__, GCPhysBufferPageAligned, rc));
4391
4392 return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
4393 cSGEntriesProcessed);
4394 }
4395
4396 if ((pbMapping + (GCPhysAddrDataBase - GCPhysBufferPageAligned) == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryCurr->cbSeg)))
4397 {
4398 pSGEntryPrev->cbSeg += cbSegment;
4399 ahciLog(("%s: Merged mapping pbMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4400 __FUNCTION__, pbMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4401 }
4402 else
4403 {
4404 pSGEntryCurr->cbSeg = cbSegment;
4405
4406 /* Let pvBuf point to the start of the buffer in the page. */
4407 pSGEntryCurr->pvSeg = pbMapping
4408 + (GCPhysAddrDataBase - GCPhysBufferPageAligned);
4409
4410 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4411 pSGEntryCurr->pvSeg,
4412 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4413
4414 pSGEntryPrev = pSGEntryCurr;
4415 pSGEntryCurr++;
4416 }
4417
4418 pSGInfoPrev = pSGInfoCurr;
4419 pSGInfoCurr++;
4420 cSGEntriesProcessed++;
4421 }
4422 else
4423 cSGEntriesR3++;
4424 }
4425 else if (fDoMapping)
4426 {
4427 pSGEntryPrev->cbSeg += cbSegment;
4428 ahciLog(("%s: Buffer is already in previous mapping pvSeg=%#p. New size is cbSeg=%d\n",
4429 __FUNCTION__, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4430 }
4431
4432 /* Let physical address point to the next page in the buffer. */
4433 GCPhysAddrDataBase = GCPhysAddrDataNextPage;
4434 GCPhysBufferPageAlignedPrev = GCPhysBufferPageAligned;
4435 }
4436 }
4437
4438 if (!fUnaligned)
4439 {
4440 /* The address is now page aligned. */
4441 while (cbDataToTransfer)
4442 {
4443 ahciLog(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u cSGEntriesR3=%u\n",
4444 __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer, cSGEntriesR3));
4445
4446 /* Check if this is the last page the buffer is in. */
4447 cbSegment = (cbDataToTransfer < PAGE_SIZE) ? cbDataToTransfer : PAGE_SIZE;
4448 cbDataToTransfer -= cbSegment;
4449
4450 if (fDoMapping)
4451 {
4452 void *pvMapping;
4453
4454 pSGInfoCurr->fGuestMemory = true;
4455
4456 /* Create the mapping. */
4457 if (fReadonly)
4458 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysAddrDataBase, 0, (const void **)&pvMapping, &pSGInfoCurr->u.direct.PageLock);
4459 else
4460 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrDataBase, 0, &pvMapping, &pSGInfoCurr->u.direct.PageLock);
4461
4462 if (RT_FAILURE(rc))
4463 {
4464 /* Mapping failed. Fall back to a bounce buffer. */
4465 ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
4466 __FUNCTION__, GCPhysAddrDataBase, rc));
4467
4468 return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
4469 cSGEntriesProcessed);
4470 }
4471
4472 /* Check for adjacent mappings. */
4473 if (pvMapping == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryPrev->cbSeg)
4474 && (pSGInfoPrev->fGuestMemory == true))
4475 {
4476 /* Yes they are adjacent. Just add the size of this mapping to the previous segment. */
4477 pSGEntryPrev->cbSeg += cbSegment;
4478 ahciLog(("%s: Merged mapping pvMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
4479 __FUNCTION__, pvMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
4480 }
4481 else
4482 {
4483 /* No they are not. Use a new sg entry. */
4484 pSGEntryCurr->cbSeg = cbSegment;
4485 pSGEntryCurr->pvSeg = pvMapping;
4486 ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
4487 pSGEntryCurr->pvSeg,
4488 (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
4489 pSGEntryPrev = pSGEntryCurr;
4490 pSGEntryCurr++;
4491 }
4492
4493 pSGInfoPrev = pSGInfoCurr;
4494 pSGInfoCurr++;
4495 cSGEntriesProcessed++;
4496 }
4497 else
4498 cSGEntriesR3++;
4499
4500 GCPhysBufferPageAlignedPrev = GCPhysAddrDataBase;
4501
4502 /* Go to the next page. */
4503 GCPhysAddrDataBase += PAGE_SIZE;
4504 }
4505 } /* if (!fUnaligned) */
4506 } /* if !fUnaligned */
4507 } /* if guest segment is sector aligned. */
4508 } /* for SGEntries read */
4509
4510 /* Set address to the next entries to read. */
4511 GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
4512
4513 } while (cSGLEntriesGCLeft);
4514
4515 fDoMapping = true;
4516
4517 } /* for passes */
4518
4519 /* Check if the last processed segment was unaligned. We need to add it now. */
4520 if (fUnaligned)
4521 {
4522 /* Set up the entry. */
4523 AssertMsg(!(cbUnaligned % 512), ("Buffer is not sector aligned\n"));
4524 pSGInfoCurr->fGuestMemory = false;
4525 pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
4526 pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
4527 pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
4528
4529 pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
4530 pSGEntryCurr->cbSeg = cbUnaligned;
4531
4532 /*
4533 * If the transfer is to the device we need to copy the content of the not mapped guest
4534 * segments into the temporary buffer.
4535 */
4536 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
4537 ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
4538 }
4539
4540 STAM_PROFILE_STOP(&pAhciPort->StatProfileMapIntoR3, a);
4541
4542 return rc;
4543}
4544
4545/**
4546 * Destroy a scatter gather list and free all occupied resources (mappings, etc.)
4547 *
4548 * @returns VBox status code.
4549 * @param pAhciPort The ahci port.
4550 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4551 */
4552static int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4553{
4554 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4555 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4556
4557 STAM_PROFILE_START(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4558
4559 for (unsigned cActualSGEntry = 0; cActualSGEntry < pAhciPortTaskState->cSGEntries; cActualSGEntry++)
4560 {
4561 if (pSGInfoCurr->fGuestMemory)
4562 {
4563 /* Release the lock. */
4564 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4565 }
4566 else if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4567 {
4568 /* Copy the data into the guest segments now. */
4569 ahciCopyFromBufferIntoSGList(pDevIns, pSGInfoCurr);
4570 }
4571
4572 /* Go to the next entry. */
4573 pSGInfoCurr++;
4574 }
4575
4576 /* Free allocated memory if the list was too big too many times. */
4577 if (pAhciPortTaskState->cSGListTooBig >= AHCI_NR_OF_ALLOWED_BIGGER_LISTS)
4578 {
4579 RTMemFree(pAhciPortTaskState->pSGListHead);
4580 RTMemFree(pAhciPortTaskState->paSGEntries);
4581 if (pAhciPortTaskState->pvBufferUnaligned)
4582 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4583 pAhciPortTaskState->cSGListSize = 0;
4584 pAhciPortTaskState->cSGListTooBig = 0;
4585 pAhciPortTaskState->pSGListHead = NULL;
4586 pAhciPortTaskState->paSGEntries = NULL;
4587 pAhciPortTaskState->pvBufferUnaligned = NULL;
4588 pAhciPortTaskState->cbBufferUnaligned = 0;
4589 }
4590
4591 STAM_PROFILE_STOP(&pAhciPort->StatProfileDestroyScatterGatherList, a);
4592
4593 return VINF_SUCCESS;
4594}
4595
4596/**
4597 * Copy a temporary buffer into a part of the guest scatter gather list
4598 * described by the given descriptor entry.
4599 *
4600 * @returns nothing.
4601 * @param pDevIns Pointer to the device instance data.
4602 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4603 * to write to which are unaligned.
4604 */
4605static void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4606{
4607 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4608 SGLEntry aSGLEntries[5];
4609 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4610 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4611
4612 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4613
4614 do
4615 {
4616 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4617 ? cSGEntriesLeft
4618 : RT_ELEMENTS(aSGLEntries);
4619
4620 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4621
4622 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4623 {
4624 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4625 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4626
4627 /* Copy into SG entry. */
4628 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4629
4630 pu8Buf += cbCopied;
4631 }
4632
4633 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4634 cSGEntriesLeft -= cSGEntriesRead;
4635 } while (cSGEntriesLeft);
4636}
4637
4638/**
4639 * Copy a part of the guest scatter gather list into a temporary buffer.
4640 *
4641 * @returns nothing.
4642 * @param pDevIns Pointer to the device instance data.
4643 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
4644 * to read from which are unaligned.
4645 */
4646static void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
4647{
4648 uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
4649 SGLEntry aSGLEntries[5];
4650 uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
4651 RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
4652
4653 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
4654
4655 do
4656 {
4657 uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
4658 ? cSGEntriesLeft
4659 : RT_ELEMENTS(aSGLEntries);
4660
4661 PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
4662
4663 for (uint32_t i = 0; i < cSGEntriesRead; i++)
4664 {
4665 RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
4666 uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4667
4668 /* Copy into buffer. */
4669 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
4670
4671 pu8Buf += cbCopied;
4672 }
4673
4674 GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
4675 cSGEntriesLeft -= cSGEntriesRead;
4676 } while (cSGEntriesLeft);
4677}
4678
4679
4680/**
4681 * Copy the content of a buffer to a scatter gather list.
4682 *
4683 * @returns VBox status code.
4684 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4685 * @param pvBuf Pointer to the buffer which should be copied.
4686 * @param cbBuf Size of the buffer.
4687 */
4688static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf)
4689{
4690 unsigned cSGEntry = 0;
4691 PPDMDATASEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
4692 uint8_t *pu8Buf = (uint8_t *)pvBuf;
4693
4694 while (cSGEntry < pAhciPortTaskState->cSGEntries)
4695 {
4696 size_t cbToCopy = (cbBuf < pSGEntry->cbSeg) ? cbBuf : pSGEntry->cbSeg;
4697
4698 memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
4699
4700 cbBuf -= cbToCopy;
4701 /* We finished. */
4702 if (!cbBuf)
4703 break;
4704
4705 /* Advance the buffer. */
4706 pu8Buf += cbToCopy;
4707
4708 /* Go to the next entry in the list. */
4709 pSGEntry++;
4710 cSGEntry++;
4711 }
4712
4713#if 0
4714 if (!pAhciPort->fATAPI)
4715 AssertMsg(!cbBuf, ("There is still data in the buffer\n"));
4716#endif
4717 return VINF_SUCCESS;
4718}
4719
4720/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
4721
4722/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
4723#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
4724
4725/**
4726 * Complete a data transfer task by freeing all occupied ressources
4727 * and notifying the guest.
4728 *
4729 * @returns VBox status code
4730 *
4731 * @param pAhciPort Pointer to the port where to request completed.
4732 * @param pAhciPortTaskState Pointer to the task which finished.
4733 */
4734static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4735{
4736 /* Free system resources occupied by the scatter gather list. */
4737 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4738
4739 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4740
4741 pAhciPortTaskState->uATARegError = 0;
4742 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4743 /* Write updated command header into memory of the guest. */
4744 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4745 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4746
4747 if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4748 {
4749 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
4750 pAhciPort->Led.Actual.s.fReading = 0;
4751 }
4752 else
4753 {
4754 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
4755 pAhciPort->Led.Actual.s.fWriting = 0;
4756 }
4757
4758 if (pAhciPortTaskState->fQueued)
4759 {
4760 uint32_t cOutstandingTasks;
4761
4762 ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
4763 cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
4764 ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
4765 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
4766
4767 if (!cOutstandingTasks)
4768 ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
4769 }
4770 else
4771 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
4772
4773 /* Add the task to the cache. */
4774 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
4775
4776 return VINF_SUCCESS;
4777}
4778
4779/**
4780 * Notification callback for a completed transfer.
4781 *
4782 * @returns VBox status code.
4783 * @param pInterface Pointer to the interface.
4784 * @param pvUser User data.
4785 */
4786static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
4787{
4788 PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
4789 PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
4790
4791 ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
4792 __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
4793
4794 return ahciTransferComplete(pAhciPort, pAhciPortTaskState);
4795}
4796
4797/**
4798 * Process an non read/write ATA command.
4799 *
4800 * @returns The direction of the data transfer
4801 * @param pCmdHdr Pointer to the command header.
4802 */
4803static int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
4804{
4805 int rc = PDMBLOCKTXDIR_NONE;
4806 bool fLBA48 = false;
4807 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4808
4809 AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
4810
4811 switch (pCmdFis[AHCI_CMDFIS_CMD])
4812 {
4813 case ATA_IDENTIFY_DEVICE:
4814 {
4815 if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
4816 {
4817 uint16_t u16Temp[256];
4818
4819 /* Fill the buffer. */
4820 ahciIdentifySS(pAhciPort, u16Temp);
4821
4822 /* Create scatter gather list. */
4823 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
4824 if (RT_FAILURE(rc))
4825 AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
4826
4827 /* Copy the buffer. */
4828 rc = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
4829 if (RT_FAILURE(rc))
4830 AssertMsgFailed(("Copying failed rc=%Rrc\n", rc));
4831
4832 /* Destroy list. */
4833 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4834 if (RT_FAILURE(rc))
4835 AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
4836
4837 pAhciPortTaskState->uATARegError = 0;
4838 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4839 pCmdHdr->u32PRDBC = sizeof(u16Temp);
4840
4841 /* Write updated command header into memory of the guest. */
4842 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
4843 }
4844 else
4845 {
4846 pAhciPortTaskState->uATARegError = ABRT_ERR;
4847 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4848 }
4849 break;
4850 }
4851 case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
4852 case ATA_READ_NATIVE_MAX_ADDRESS:
4853 break;
4854 case ATA_SET_FEATURES:
4855 {
4856 switch (pCmdFis[AHCI_CMDFIS_FET])
4857 {
4858 case 0x02: /* write cache enable */
4859 case 0xaa: /* read look-ahead enable */
4860 case 0x55: /* read look-ahead disable */
4861 case 0xcc: /* reverting to power-on defaults enable */
4862 case 0x66: /* reverting to power-on defaults disable */
4863 pAhciPortTaskState->uATARegError = 0;
4864 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4865 break;
4866 case 0x82: /* write cache disable */
4867 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4868 pAhciPortTaskState->uATARegError = 0;
4869 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4870 break;
4871 case 0x03:
4872 { /* set transfer mode */
4873 Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4874 switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
4875 {
4876 case 0x00: /* PIO default */
4877 case 0x08: /* PIO mode */
4878 break;
4879 case ATA_MODE_MDMA: /* MDMA mode */
4880 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
4881 break;
4882 case ATA_MODE_UDMA: /* UDMA mode */
4883 pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
4884 break;
4885 }
4886 break;
4887 }
4888 default:
4889 pAhciPortTaskState->uATARegError = ABRT_ERR;
4890 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4891 }
4892 break;
4893 }
4894 case ATA_FLUSH_CACHE_EXT:
4895 case ATA_FLUSH_CACHE:
4896 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
4897 pAhciPortTaskState->uATARegError = 0;
4898 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4899 break;
4900 case ATA_PACKET:
4901 if (!pAhciPort->fATAPI)
4902 {
4903 pAhciPortTaskState->uATARegError = ABRT_ERR;
4904 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4905 }
4906 else
4907 {
4908 rc = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
4909 }
4910 break;
4911 case ATA_IDENTIFY_PACKET_DEVICE:
4912 if (!pAhciPort->fATAPI)
4913 {
4914 pAhciPortTaskState->uATARegError = ABRT_ERR;
4915 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4916 }
4917 else
4918 {
4919 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_IDENTIFY);
4920
4921 pAhciPortTaskState->uATARegError = 0;
4922 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4923 }
4924 break;
4925 case ATA_SET_MULTIPLE_MODE:
4926 if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
4927 && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
4928 || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
4929 {
4930 pAhciPortTaskState->uATARegError = ABRT_ERR;
4931 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4932 }
4933 else
4934 {
4935 Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
4936 pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
4937 pAhciPortTaskState->uATARegError = 0;
4938 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4939 }
4940 break;
4941 case ATA_STANDBY_IMMEDIATE:
4942 break; /* Do nothing. */
4943 case ATA_CHECK_POWER_MODE:
4944 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
4945 /* fall through */
4946 case ATA_INITIALIZE_DEVICE_PARAMETERS:
4947 case ATA_IDLE_IMMEDIATE:
4948 case ATA_RECALIBRATE:
4949 case ATA_NOP:
4950 case ATA_READ_VERIFY_SECTORS_EXT:
4951 case ATA_READ_VERIFY_SECTORS:
4952 case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
4953 pAhciPortTaskState->uATARegError = 0;
4954 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4955 break;
4956 case ATA_READ_DMA_EXT:
4957 fLBA48 = true;
4958 case ATA_READ_DMA:
4959 {
4960 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
4961 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
4962 rc = PDMBLOCKTXDIR_FROM_DEVICE;
4963 break;
4964 }
4965 case ATA_WRITE_DMA_EXT:
4966 fLBA48 = true;
4967 case ATA_WRITE_DMA:
4968 {
4969 pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
4970 pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
4971 rc = PDMBLOCKTXDIR_TO_DEVICE;
4972 break;
4973 }
4974 case ATA_READ_FPDMA_QUEUED:
4975 {
4976 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
4977 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
4978 rc = PDMBLOCKTXDIR_FROM_DEVICE;
4979 break;
4980 }
4981 case ATA_WRITE_FPDMA_QUEUED:
4982 {
4983 pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
4984 pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
4985 rc = PDMBLOCKTXDIR_TO_DEVICE;
4986 break;
4987 }
4988 /* All not implemented commands go below. */
4989 case ATA_SECURITY_FREEZE_LOCK:
4990 case ATA_SMART:
4991 case ATA_NV_CACHE:
4992 case ATA_SLEEP: /* Powermanagement not supported. */
4993 pAhciPortTaskState->uATARegError = ABRT_ERR;
4994 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4995 break;
4996 default: /* For debugging purposes. */
4997 AssertMsgFailed(("Unknown command issued\n"));
4998 pAhciPortTaskState->uATARegError = ABRT_ERR;
4999 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5000 }
5001
5002 return rc;
5003}
5004
5005/**
5006 * Retrieve a command FIS from guest memory.
5007 *
5008 * @returns nothing
5009 * @param pAhciPortTaskState The state of the actual task.
5010 */
5011static void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
5012{
5013 RTGCPHYS GCPhysAddrCmdTbl;
5014
5015 AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
5016
5017 /*
5018 * First we are reading the command header pointed to by regCLB.
5019 * From this we get the address of the command table which we are reading too.
5020 * We can process the Command FIS afterwards.
5021 */
5022 pAhciPortTaskState->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciPortTaskState->uTag * sizeof(CmdHdr);
5023 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
5024 pAhciPortTaskState->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
5025 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5026
5027#ifdef DEBUG
5028 /* Print some infos about the command header. */
5029 ahciDumpCmdHdrInfo(pAhciPort, &pAhciPortTaskState->cmdHdr);
5030#endif
5031
5032 GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr);
5033
5034 AssertMsg((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
5035 ("This is not a command FIS!!\n"));
5036
5037 /* Read the command Fis. */
5038 LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
5039 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
5040
5041 /* Set transfer direction. */
5042 pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
5043
5044 /* If this is an ATAPI command read the atapi command. */
5045 if (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
5046 {
5047 GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
5048 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->aATAPICmd[0], ATAPI_PACKET_SIZE);
5049 }
5050
5051 /* We "received" the FIS. Clear the BSY bit in regTFD. */
5052 if ((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciPortTaskState->fQueued))
5053 {
5054 /*
5055 * 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.
5056 * but this FIS does not assert an interrupt
5057 */
5058 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, false);
5059 pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
5060 }
5061
5062#ifdef DEBUG
5063 /* Print some infos about the FIS. */
5064 ahciDumpFisInfo(pAhciPort, &pAhciPortTaskState->cmdFis[0]);
5065
5066 /* Print the PRDT */
5067 RTGCPHYS GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
5068
5069 ahciLog(("PRDT address %RGp number of entries %u\n", GCPhysAddrPRDTLEntryStart, AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf)));
5070
5071 for (unsigned i = 0; i < AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf); i++)
5072 {
5073 SGLEntry SGEntry;
5074
5075 ahciLog(("Entry %u at address %RGp\n", i, GCPhysAddrPRDTLEntryStart));
5076 PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrPRDTLEntryStart, &SGEntry, sizeof(SGLEntry));
5077
5078 RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
5079 ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
5080
5081 GCPhysAddrPRDTLEntryStart += sizeof(SGLEntry);
5082 }
5083#endif
5084}
5085
5086/**
5087 * Transmit queue consumer
5088 * Queue a new async task.
5089 *
5090 * @returns Success indicator.
5091 * If false the item will not be removed and the flushing will stop.
5092 * @param pDevIns The device instance.
5093 * @param pItem The item to consume. Upon return this item will be freed.
5094 */
5095static DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
5096{
5097 PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
5098 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5099 PAHCIPort pAhciPort = &pAhci->ahciPort[pNotifierItem->iPort];
5100 int rc = VINF_SUCCESS;
5101
5102 if (!pAhciPort->fAsyncInterface)
5103 {
5104 ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
5105 /* Notify the async IO thread. */
5106 rc = RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5107 AssertRC(rc);
5108 }
5109 else
5110 {
5111 int iTxDir;
5112 PAHCIPORTTASKSTATE pAhciPortTaskState;
5113
5114 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
5115
5116 /* Check if there is already an allocated task struct in the cache.
5117 * Allocate a new task otherwise.
5118 */
5119 if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
5120 {
5121 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5122 AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
5123 }
5124 else
5125 {
5126 pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
5127 }
5128
5129 /** Set current command slot */
5130 pAhciPortTaskState->uTag = pNotifierItem->iTask;
5131 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5132
5133 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5134
5135 /* 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. */
5136 if (pNotifierItem->fQueued)
5137 {
5138 pAhciPortTaskState->fQueued = true;
5139 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5140 }
5141 else
5142 pAhciPortTaskState->fQueued = false;
5143
5144 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5145 {
5146 /* If the reset bit is set put the device into reset state. */
5147 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5148 {
5149 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5150 pAhciPort->fResetDevice = true;
5151 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
5152 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5153 return true;
5154 }
5155 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5156 {
5157 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5158 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5159 return true;
5160 }
5161 else /* We are not in a reset state update the control registers. */
5162 {
5163 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
5164 }
5165 }
5166
5167 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5168
5169 if (iTxDir != PDMBLOCKTXDIR_NONE)
5170 {
5171 if (pAhciPortTaskState->fQueued)
5172 {
5173 ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5174 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
5175 ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5176 }
5177
5178 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5179
5180 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5181 if (RT_FAILURE(rc))
5182 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5183
5184 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5185 {
5186 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5187 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5188 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
5189 pAhciPortTaskState->cbTransfer,
5190 pAhciPortTaskState);
5191 }
5192 else
5193 {
5194 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5195 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5196 pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
5197 pAhciPortTaskState->cbTransfer,
5198 pAhciPortTaskState);
5199 }
5200 if (rc == VINF_VD_ASYNC_IO_FINISHED)
5201 rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
5202
5203 if (RT_FAILURE(rc))
5204 AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
5205 }
5206 else
5207 {
5208 /* There is nothing left to do. Notify the guest. */
5209 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5210 /* Add the task to the cache. */
5211 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
5212 }
5213 }
5214
5215 return true;
5216}
5217
5218/* The async IO thread for one port. */
5219static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5220{
5221 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5222 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
5223 PAHCIPORTTASKSTATE pAhciPortTaskState;
5224 int rc = VINF_SUCCESS;
5225 uint64_t u64StartTime = 0;
5226 uint64_t u64StopTime = 0;
5227 uint32_t uIORequestsProcessed = 0;
5228 uint32_t uIOsPerSec = 0;
5229
5230 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
5231
5232 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
5233 return VINF_SUCCESS;
5234
5235 /* We use only one task structure. */
5236 pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
5237 if (!pAhciPortTaskState)
5238 {
5239 AssertMsgFailed(("Failed to allocate task state memory\n"));
5240 return VERR_NO_MEMORY;
5241 }
5242
5243 while(pThread->enmState == PDMTHREADSTATE_RUNNING)
5244 {
5245 uint32_t uQueuedTasksFinished = 0;
5246
5247 /* New run to get number of I/O requests per second?. */
5248 if (!u64StartTime)
5249 u64StartTime = RTTimeMilliTS();
5250
5251 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
5252
5253 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
5254 if (rc == VERR_TIMEOUT)
5255 {
5256 /* No I/O requests inbetween. Reset statistics and wait again. */
5257 pAhciPort->StatIORequestsPerSecond.c = 0;
5258 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
5259 }
5260
5261 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
5262 break;
5263
5264 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
5265
5266 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
5267
5268 /*
5269 * To maximize the throughput of the controller we try to minimize the
5270 * number of world switches during interrupts by grouping as many
5271 * I/O requests together as possible.
5272 * On the other side we want to get minimal latency if the I/O load is low.
5273 * Thatswhy the number of I/O requests per second is measured and if it is over
5274 * a threshold the thread waits for other requests from the guest.
5275 */
5276 if (uIOsPerSec >= pAhci->cHighIOThreshold)
5277 {
5278 uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
5279
5280 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
5281
5282 do
5283 {
5284 /* Sleep some time. */
5285 RTThreadSleep(pAhci->cMillisToSleep);
5286 /* Check if we got some new requests inbetween. */
5287 if (uActWritePosPrev != pAhciPort->uActWritePos)
5288 {
5289 uActWritePosPrev = pAhciPort->uActWritePos;
5290 /*
5291 * Check if the queue is full. If that is the case
5292 * there is no point waiting another round.
5293 */
5294 if ( ( (pAhciPort->uActReadPos < uActWritePosPrev)
5295 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
5296 || ( (pAhciPort->uActReadPos > uActWritePosPrev)
5297 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) )
5298 {
5299 Log(("%s: Queue full -> leaving\n", __FUNCTION__));
5300 break;
5301 }
5302 Log(("%s: Another round\n", __FUNCTION__));
5303 }
5304 else /* No change break out of the loop. */
5305 {
5306#ifdef DEBUG
5307 uint8_t uQueuedTasks;
5308 if (pAhciPort->uActReadPos < uActWritePosPrev)
5309 uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
5310 else
5311 uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
5312
5313 Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
5314#endif
5315 break;
5316 }
5317 } while (true);
5318 }
5319
5320 ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
5321
5322 uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5323
5324 ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
5325
5326 /* Process commands. */
5327 while ( (cTasksToProcess > 0)
5328 && RT_LIKELY(!pAhciPort->fPortReset))
5329 {
5330 int iTxDir;
5331 uint8_t uActTag;
5332
5333 STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
5334
5335 ahciLog(("%s: uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
5336 ahciLog(("%s: Before uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5337
5338 pAhciPortTaskState->uATARegStatus = 0;
5339 pAhciPortTaskState->uATARegError = 0;
5340 uActTag = pAhciPort->ahciIOTasks[pAhciPort->uActReadPos];
5341
5342 pAhciPortTaskState->uTag = AHCI_TASK_GET_TAG(uActTag);
5343 AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number!!\n", __FUNCTION__));
5344
5345 /** Set current command slot */
5346 pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
5347
5348 /* 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. */
5349 if (AHCI_TASK_IS_QUEUED(uActTag))
5350 {
5351 pAhciPortTaskState->fQueued = true;
5352 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
5353 }
5354 else
5355 {
5356 pAhciPortTaskState->fQueued = false;
5357 }
5358
5359 ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
5360
5361 ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciPortTaskState->uTag));
5362
5363 if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
5364 {
5365 /* If the reset bit is set put the device into reset state. */
5366 if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
5367 {
5368 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
5369 pAhciPort->fResetDevice = true;
5370 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5371 }
5372 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5373 {
5374 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5375 }
5376 /* TODO: We are not in a reset state update the control registers. */
5377 }
5378 else
5379 {
5380 iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5381
5382 if (iTxDir != PDMBLOCKTXDIR_NONE)
5383 {
5384 uint64_t uOffset;
5385 size_t cbTransfer;
5386 PPDMDATASEG pSegCurr;
5387 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
5388
5389 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5390 if (RT_FAILURE(rc))
5391 AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
5392
5393 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5394
5395 /* Initialize all values. */
5396 uOffset = pAhciPortTaskState->uOffset;
5397 cbTransfer = pAhciPortTaskState->cbTransfer;
5398 pSegCurr = &pAhciPortTaskState->pSGListHead[0];
5399 pSGInfoCurr = pAhciPortTaskState->paSGEntries;
5400
5401 STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, a);
5402
5403 while(cbTransfer)
5404 {
5405 size_t cbProcess = (cbTransfer < pSegCurr->cbSeg) ? cbTransfer : pSegCurr->cbSeg;
5406
5407 AssertMsg(!(pSegCurr->cbSeg % 512), ("Buffer is not sector aligned cbSeg=%d\n", pSegCurr->cbSeg));
5408 AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
5409 AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
5410
5411 if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5412 {
5413 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5414 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
5415 pSegCurr->pvSeg, cbProcess);
5416 pAhciPort->Led.Actual.s.fReading = 0;
5417 if (RT_FAILURE(rc))
5418 AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
5419
5420 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
5421 }
5422 else
5423 {
5424 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
5425 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
5426 pSegCurr->pvSeg, cbProcess);
5427 pAhciPort->Led.Actual.s.fWriting = 0;
5428 if (RT_FAILURE(rc))
5429 AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
5430
5431 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbProcess);
5432 }
5433
5434 /* Go to the next entry. */
5435 uOffset += cbProcess;
5436 cbTransfer -= cbProcess;
5437 pSegCurr++;
5438 pSGInfoCurr++;
5439 }
5440
5441 STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
5442
5443 /* Cleanup. */
5444 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5445 if (RT_FAILURE(rc))
5446 AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
5447
5448 if (RT_LIKELY(!pAhciPort->fPortReset))
5449 {
5450 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
5451 pAhciPortTaskState->uATARegError = 0;
5452 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5453 /* Write updated command header into memory of the guest. */
5454 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
5455 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5456
5457 if (pAhciPortTaskState->fQueued)
5458 uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
5459 else
5460 {
5461 /* Task is not queued send D2H FIS */
5462 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5463 }
5464
5465 uIORequestsProcessed++;
5466 }
5467 }
5468 else
5469 {
5470 /* Nothing left to do. Notify the guest. */
5471 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5472 }
5473
5474 STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
5475 }
5476
5477#ifdef DEBUG
5478 /* Be paranoid. */
5479 memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
5480 memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
5481 pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
5482 pAhciPortTaskState->uOffset = 0;
5483 pAhciPortTaskState->cbTransfer = 0;
5484 /* Make the port number invalid making it easier to track down bugs. */
5485 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
5486#endif
5487
5488 pAhciPort->uActReadPos++;
5489 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
5490 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5491 cTasksToProcess--;
5492 if (!cTasksToProcess)
5493 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5494 }
5495
5496 if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5497 ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, true);
5498
5499 uQueuedTasksFinished = 0;
5500
5501 u64StopTime = RTTimeMilliTS();
5502 /* Check if one second has passed. */
5503 if (u64StopTime - u64StartTime >= 1000)
5504 {
5505 /* Calculate number of I/O requests per second. */
5506 uIOsPerSec = uIORequestsProcessed / ((u64StopTime - u64StartTime) / 1000);
5507 ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
5508 u64StartTime = 0;
5509 uIORequestsProcessed = 0;
5510 /* For the release statistics. There is no macro to set the counter to a specific value. */
5511 pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
5512 }
5513 }
5514
5515 /* Free task state memory */
5516 if (pAhciPortTaskState->pSGListHead)
5517 RTMemFree(pAhciPortTaskState->pSGListHead);
5518 if (pAhciPortTaskState->paSGEntries)
5519 RTMemFree(pAhciPortTaskState->paSGEntries);
5520 if (pAhciPortTaskState->pvBufferUnaligned)
5521 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
5522 RTMemFree(pAhciPortTaskState);
5523
5524 ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
5525 return rc;
5526}
5527
5528/**
5529 * Unblock the async I/O thread so it can respond to a state change.
5530 *
5531 * @returns VBox status code.
5532 * @param pDevIns The pcnet device instance.
5533 * @param pThread The send thread.
5534 */
5535static DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
5536{
5537 PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
5538 return RTSemEventSignal(pAhciPort->AsyncIORequestSem);
5539}
5540
5541/**
5542 * Called when a media is mounted.
5543 *
5544 * @param pInterface Pointer to the interface structure containing the called function pointer.
5545 */
5546static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
5547{
5548 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5549 Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
5550
5551 /* Ignore the call if we're called while being attached. */
5552 if (!pAhciPort->pDrvBlock)
5553 return;
5554
5555 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5556
5557 /*
5558 * Initialize registers
5559 */
5560 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS;
5561 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
5562 pAhciPort->regSERR |= AHCI_PORT_SERR_N;
5563 if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5564 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
5565}
5566
5567/**
5568 * Called when a media is unmounted
5569 * @param pInterface Pointer to the interface structure containing the called function pointer.
5570 */
5571static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
5572{
5573 PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
5574 Log(("%s:\n", __FUNCTION__));
5575
5576 pAhciPort->cTotalSectors = 0;
5577
5578 /*
5579 * Inform the guest about the removed device.
5580 */
5581 pAhciPort->regSSTS = 0;
5582 pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
5583 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
5584 pAhciPort->regSERR |= AHCI_PORT_SERR_N;
5585 if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
5586 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
5587}
5588
5589/**
5590 * Destroy a driver instance.
5591 *
5592 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
5593 * resources can be freed correctly.
5594 *
5595 * @param pDevIns The device instance data.
5596 */
5597static DECLCALLBACK(int) ahciDestruct(PPDMDEVINS pDevIns)
5598{
5599 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5600 int rc = VINF_SUCCESS;
5601 unsigned iActPort = 0;
5602
5603 /*
5604 * At this point the async I/O thread is suspended and will not enter
5605 * this module again. So, no coordination is needed here and PDM
5606 * will take care of terminating and cleaning up the thread.
5607 */
5608 if (PDMCritSectIsInitialized(&pAhci->lock))
5609 {
5610 TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
5611
5612 Log(("%s: Destruct every port\n", __FUNCTION__));
5613 for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
5614 {
5615 PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
5616
5617 if (pAhciPort->pAsyncIOThread)
5618 {
5619 /* Destroy the event semaphore. */
5620 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
5621 if (RT_FAILURE(rc))
5622 {
5623 Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
5624 }
5625 }
5626
5627 /* Free all cached tasks. */
5628 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
5629 {
5630 if (pAhciPort->aCachedTasks[i])
5631 {
5632 if (pAhciPort->aCachedTasks[i]->pSGListHead)
5633 RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
5634 if (pAhciPort->aCachedTasks[i]->paSGEntries)
5635 RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
5636
5637 RTMemFree(pAhciPort->aCachedTasks[i]);
5638 }
5639 }
5640 }
5641
5642 /* Destroy emulated ATA controllers. */
5643 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5644 ataControllerDestroy(&pAhci->aCts[i]);
5645
5646 PDMR3CritSectDelete(&pAhci->lock);
5647 }
5648
5649 return rc;
5650}
5651
5652/**
5653 * Configure the attached device for a port.
5654 *
5655 * @returns VBox status code
5656 * @param pDevIns The device instance data.
5657 * @param pAhciPort The port for which the device is to be configured.
5658 */
5659static int ahciConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
5660{
5661 int rc = VINF_SUCCESS;
5662 PDMBLOCKTYPE enmType;
5663
5664 /*
5665 * Query the block and blockbios interfaces.
5666 */
5667 pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
5668 if (!pAhciPort->pDrvBlock)
5669 {
5670 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
5671 return VERR_PDM_MISSING_INTERFACE;
5672 }
5673 pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
5674 if (!pAhciPort->pDrvBlockBios)
5675 {
5676 AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
5677 return VERR_PDM_MISSING_INTERFACE;
5678 }
5679
5680 pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
5681
5682 /* Try to get the optional async block interface. */
5683 pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
5684
5685 /*
5686 * Validate type.
5687 */
5688 enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
5689
5690 if ( enmType != PDMBLOCKTYPE_HARD_DISK
5691 && enmType != PDMBLOCKTYPE_CDROM
5692 && enmType != PDMBLOCKTYPE_DVD)
5693 {
5694 AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
5695 return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
5696 }
5697
5698 if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
5699 && !pAhciPort->pDrvMount)
5700 {
5701 AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
5702 return VERR_INTERNAL_ERROR;
5703 }
5704 pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
5705
5706 if (pAhciPort->fATAPI)
5707 {
5708 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
5709 pAhciPort->PCHSGeometry.cCylinders = 0;
5710 pAhciPort->PCHSGeometry.cHeads = 0;
5711 pAhciPort->PCHSGeometry.cSectors = 0;
5712 LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
5713 }
5714 else
5715 {
5716 pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
5717 rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
5718 &pAhciPort->PCHSGeometry);
5719 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
5720 {
5721 pAhciPort->PCHSGeometry.cCylinders = 0;
5722 pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
5723 pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
5724 }
5725 else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
5726 {
5727 pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
5728 rc = VINF_SUCCESS;
5729 }
5730 AssertRC(rc);
5731
5732 if ( pAhciPort->PCHSGeometry.cCylinders == 0
5733 || pAhciPort->PCHSGeometry.cHeads == 0
5734 || pAhciPort->PCHSGeometry.cSectors == 0)
5735 {
5736 uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
5737 pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
5738 pAhciPort->PCHSGeometry.cHeads = 16;
5739 pAhciPort->PCHSGeometry.cSectors = 63;
5740 /* Set the disk geometry information. Ignore errors. */
5741 pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
5742 &pAhciPort->PCHSGeometry);
5743 rc = VINF_SUCCESS;
5744 }
5745 LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
5746 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
5747 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
5748 pAhciPort->cTotalSectors));
5749 }
5750 return rc;
5751}
5752
5753static bool ahciWaitForAllAsyncIOIsFinished(PPDMDEVINS pDevIns, unsigned cMillies)
5754{
5755 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5756 uint64_t u64Start;
5757 PAHCIPort pAhciPort;
5758 bool fAllFinished;
5759
5760 u64Start = RTTimeMilliTS();
5761 for (;;)
5762 {
5763 fAllFinished = true;
5764 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
5765 {
5766 pAhciPort = &pAhci->ahciPort[i];
5767
5768 if (pAhciPort->pDrvBase)
5769 {
5770 if (pAhciPort->fAsyncInterface)
5771 fAllFinished &= (pAhciPort->uActTasksActive == 0);
5772 else
5773 fAllFinished &= ((pAhciPort->uActTasksActive == 0) && (pAhciPort->fAsyncIOThreadIdle));
5774
5775 if (!fAllFinished)
5776 break;
5777 }
5778 }
5779 if ( fAllFinished
5780 || RTTimeMilliTS() - u64Start >= cMillies)
5781 break;
5782
5783 /* Sleep a bit. */
5784 RTThreadSleep(100);
5785 }
5786 return fAllFinished;
5787}
5788
5789static DECLCALLBACK(int) ahciSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5790{
5791 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5792
5793 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
5794 AssertMsgFailed(("One port is still active\n"));
5795
5796 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5797 {
5798 int rc;
5799
5800 rc = ataControllerSavePrep(&pAhci->aCts[i], pSSM);
5801 if (RT_FAILURE(rc))
5802 return rc;
5803 }
5804
5805 return VINF_SUCCESS;
5806}
5807
5808static DECLCALLBACK(int) ahciLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
5809{
5810 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5811
5812 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5813 {
5814 int rc;
5815
5816 rc = ataControllerLoadPrep(&pAhci->aCts[i], pSSM);
5817 if (RT_FAILURE(rc))
5818 return rc;
5819 }
5820
5821 return VINF_SUCCESS;
5822}
5823
5824/**
5825 * Suspend notification.
5826 *
5827 * @returns VBox status.
5828 * @param pDevIns The device instance data.
5829 */
5830static DECLCALLBACK(void) ahciSuspend(PPDMDEVINS pDevIns)
5831{
5832 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5833
5834 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
5835 AssertMsgFailed(("AHCI: One port is still active\n"));
5836
5837 Log(("%s:\n", __FUNCTION__));
5838 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5839 {
5840 ataControllerSuspend(&pAhci->aCts[i]);
5841 }
5842 return;
5843}
5844
5845
5846/**
5847 * Resume notification.
5848 *
5849 * @returns VBox status.
5850 * @param pDevIns The device instance data.
5851 */
5852static DECLCALLBACK(void) ahciResume(PPDMDEVINS pDevIns)
5853{
5854 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5855
5856 Log(("%s:\n", __FUNCTION__));
5857 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5858 {
5859 ataControllerResume(&pAhci->aCts[i]);
5860 }
5861 return;
5862}
5863
5864/**
5865 * Saves a state of the AHCI device.
5866 *
5867 * @returns VBox status code.
5868 * @param pDevIns The device instance.
5869 * @param pSSMHandle The handle to save the state to.
5870 */
5871static DECLCALLBACK(int) ahciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
5872{
5873 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5874 uint32_t i;
5875
5876 Assert(!pAhci->f8ByteMMIO4BytesWrittenSuccessfully);
5877
5878 /* First the main device structure. */
5879 SSMR3PutU32(pSSMHandle, pAhci->regHbaCap);
5880 SSMR3PutU32(pSSMHandle, pAhci->regHbaCtrl);
5881 SSMR3PutU32(pSSMHandle, pAhci->regHbaIs);
5882 SSMR3PutU32(pSSMHandle, pAhci->regHbaPi);
5883 SSMR3PutU32(pSSMHandle, pAhci->regHbaVs);
5884 SSMR3PutU32(pSSMHandle, pAhci->regHbaCccCtl);
5885 SSMR3PutU32(pSSMHandle, pAhci->regHbaCccPorts);
5886 SSMR3PutU8(pSSMHandle, pAhci->uCccPortNr);
5887 SSMR3PutU64(pSSMHandle, pAhci->uCccTimeout);
5888 SSMR3PutU32(pSSMHandle, pAhci->uCccNr);
5889 SSMR3PutU32(pSSMHandle, pAhci->uCccCurrentNr);
5890 SSMR3PutU32(pSSMHandle, pAhci->u32PortsInterrupted);
5891 SSMR3PutBool(pSSMHandle, pAhci->fReset);
5892 SSMR3PutBool(pSSMHandle, pAhci->f64BitAddr);
5893 SSMR3PutBool(pSSMHandle, pAhci->fR0Enabled);
5894 SSMR3PutBool(pSSMHandle, pAhci->fGCEnabled);
5895
5896 /* Now every port. */
5897 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5898 {
5899 Assert(pAhci->ahciPort[i].uActTasksActive == 0);
5900 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLB);
5901 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLBU);
5902 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFB);
5903 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFBU);
5904 SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrClb);
5905 SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrFb);
5906 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIS);
5907 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIE);
5908 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCMD);
5909 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regTFD);
5910 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSIG);
5911 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSSTS);
5912 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSCTL);
5913 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSERR);
5914 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSACT);
5915 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCI);
5916 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cCylinders);
5917 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cHeads);
5918 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cSectors);
5919 SSMR3PutU64(pSSMHandle, pAhci->ahciPort[i].cTotalSectors);
5920 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].cMultSectors);
5921 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uATATransferMode);
5922 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fResetDevice);
5923
5924 for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
5925 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].ahciIOTasks[uActTask]);
5926
5927 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActWritePos);
5928 SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActReadPos);
5929 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fPoweredOn);
5930 SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fSpunUp);
5931 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32TasksFinished);
5932 SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32QueuedTasksFinished);
5933 }
5934
5935 /* Now the emulated ata controllers. */
5936 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
5937 {
5938 int rc;
5939
5940 rc = ataControllerSaveExec(&pAhci->aCts[i], pSSMHandle);
5941 if (RT_FAILURE(rc))
5942 return rc;
5943 }
5944
5945 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
5946}
5947
5948/**
5949 * Loads a saved AHCI device state.
5950 *
5951 * @returns VBox status code.
5952 * @param pDevIns The device instance.
5953 * @param pSSMHandle The handle to the saved state.
5954 * @param uVersion The data unit version number.
5955 * @param uPass The data pass.
5956 */
5957static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
5958{
5959 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
5960 uint32_t u32;
5961 uint32_t i;
5962
5963 if (uVersion != AHCI_SAVED_STATE_VERSION)
5964 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
5965 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
5966
5967 /* Restore data. */
5968
5969 /* First the main device structure. */
5970 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCap);
5971 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCtrl);
5972 SSMR3GetU32(pSSMHandle, &pAhci->regHbaIs);
5973 SSMR3GetU32(pSSMHandle, &pAhci->regHbaPi);
5974 SSMR3GetU32(pSSMHandle, &pAhci->regHbaVs);
5975 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccCtl);
5976 SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccPorts);
5977 SSMR3GetU8(pSSMHandle, &pAhci->uCccPortNr);
5978 SSMR3GetU64(pSSMHandle, &pAhci->uCccTimeout);
5979 SSMR3GetU32(pSSMHandle, &pAhci->uCccNr);
5980 SSMR3GetU32(pSSMHandle, &pAhci->uCccCurrentNr);
5981
5982 SSMR3GetU32(pSSMHandle, &pAhci->u32PortsInterrupted);
5983 SSMR3GetBool(pSSMHandle, &pAhci->fReset);
5984 SSMR3GetBool(pSSMHandle, &pAhci->f64BitAddr);
5985 SSMR3GetBool(pSSMHandle, &pAhci->fR0Enabled);
5986 SSMR3GetBool(pSSMHandle, &pAhci->fGCEnabled);
5987
5988 /* Now every port. */
5989 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
5990 {
5991 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLB);
5992 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLBU);
5993 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFB);
5994 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFBU);
5995 SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrClb);
5996 SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrFb);
5997 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regIS);
5998 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regIE);
5999 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCMD);
6000 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regTFD);
6001 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSIG);
6002 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSSTS);
6003 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSCTL);
6004 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSERR);
6005 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regSACT);
6006 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regCI);
6007 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cCylinders);
6008 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cHeads);
6009 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cSectors);
6010 SSMR3GetU64(pSSMHandle, &pAhci->ahciPort[i].cTotalSectors);
6011 SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].cMultSectors);
6012 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uATATransferMode);
6013 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fResetDevice);
6014
6015 for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
6016 SSMR3GetU8(pSSMHandle, (uint8_t *)&pAhci->ahciPort[i].ahciIOTasks[uActTask]);
6017
6018 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActWritePos);
6019 SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActReadPos);
6020 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fPoweredOn);
6021 SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fSpunUp);
6022 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32TasksFinished);
6023 SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32QueuedTasksFinished);
6024 }
6025
6026 /* Now the emulated ata controllers. */
6027 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6028 {
6029 int rc = ataControllerLoadExec(&pAhci->aCts[i], pSSMHandle);
6030 if (RT_FAILURE(rc))
6031 return rc;
6032 }
6033
6034 int rc = SSMR3GetU32(pSSMHandle, &u32);
6035 if (RT_FAILURE(rc))
6036 return rc;
6037 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
6038
6039 return VINF_SUCCESS;
6040}
6041
6042/**
6043 * Detach notification.
6044 *
6045 * One harddisk at one port has been unplugged.
6046 * The VM is suspended at this point.
6047 *
6048 * @param pDevIns The device instance.
6049 * @param iLUN The logical unit which is being detached.
6050 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
6051 */
6052static DECLCALLBACK(void) ahciDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
6053{
6054 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6055 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
6056 int rc = VINF_SUCCESS;
6057
6058 Log(("%s:\n", __FUNCTION__));
6059
6060 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
6061
6062 if (!pAhciPort->fAsyncInterface)
6063 {
6064 int rcThread;
6065 /* Destroy the thread. */
6066 rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
6067 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
6068 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
6069
6070 rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
6071 if (RT_FAILURE(rc))
6072 AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
6073 }
6074
6075 /*
6076 * Zero some important members.
6077 */
6078 pAhciPort->pDrvBase = NULL;
6079 pAhciPort->pDrvBlock = NULL;
6080 pAhciPort->pDrvBlockAsync = NULL;
6081 pAhciPort->pDrvBlockBios = NULL;
6082}
6083
6084/**
6085 * Attach command.
6086 *
6087 * This is called when we change block driver for one port.
6088 * The VM is suspended at this point.
6089 *
6090 * @returns VBox status code.
6091 * @param pDevIns The device instance.
6092 * @param iLUN The logical unit which is being detached.
6093 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
6094 */
6095static DECLCALLBACK(int) ahciAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
6096{
6097 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6098 PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
6099 int rc;
6100
6101 Log(("%s:\n", __FUNCTION__));
6102
6103 /* the usual paranoia */
6104 AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
6105 AssertRelease(!pAhciPort->pDrvBase);
6106 AssertRelease(!pAhciPort->pDrvBlock);
6107 AssertRelease(!pAhciPort->pDrvBlockAsync);
6108 Assert(pAhciPort->iLUN == iLUN);
6109
6110 /*
6111 * Try attach the block device and get the interfaces,
6112 * required as well as optional.
6113 */
6114 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
6115 if (RT_SUCCESS(rc))
6116 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6117 else
6118 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
6119
6120 if (RT_FAILURE(rc))
6121 {
6122 pAhciPort->pDrvBase = NULL;
6123 pAhciPort->pDrvBlock = NULL;
6124 }
6125 else
6126 {
6127 char szName[24];
6128 RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
6129
6130 if (pAhciPort->pDrvBlockAsync)
6131 {
6132 pAhciPort->fAsyncInterface = true;
6133 }
6134 else
6135 {
6136 pAhciPort->fAsyncInterface = false;
6137
6138 /* Create event semaphore. */
6139 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6140 if (RT_FAILURE(rc))
6141 {
6142 Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
6143 return rc;
6144 }
6145
6146 /* Create the async IO thread. */
6147 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6148 RTTHREADTYPE_IO, szName);
6149 if (RT_FAILURE(rc))
6150 {
6151 AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
6152 return rc;
6153 }
6154 }
6155 }
6156
6157 return rc;
6158}
6159
6160/**
6161 * Reset notification.
6162 *
6163 * @returns VBox status.
6164 * @param pDevIns The device instance data.
6165 */
6166static DECLCALLBACK(void) ahciReset(PPDMDEVINS pDevIns)
6167{
6168 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6169
6170 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
6171 AssertMsgFailed(("AHCI: One port is still active\n"));
6172
6173 ahciHBAReset(pAhci);
6174
6175 /* Hardware reset for the ports. */
6176 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
6177 ahciPortHwReset(&pAhci->ahciPort[i]);
6178
6179 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6180 ataControllerReset(&pAhci->aCts[i]);
6181}
6182
6183/**
6184 * Poweroff notification.
6185 *
6186 * @returns nothing
6187 * @param pDevIns Pointer to the device instance
6188 */
6189static DECLCALLBACK(void) ahciPowerOff(PPDMDEVINS pDevIns)
6190{
6191 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
6192
6193 if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
6194 AssertMsgFailed(("AHCI: One port is still active\n"));
6195
6196 for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
6197 ataControllerPowerOff(&pAhci->aCts[i]);
6198}
6199
6200/**
6201 * Construct a device instance for a VM.
6202 *
6203 * @returns VBox status.
6204 * @param pDevIns The device instance data.
6205 * If the registration structure is needed, pDevIns->pDevReg points to it.
6206 * @param iInstance Instance number. Use this to figure out which registers and such to use.
6207 * The device number is also found in pDevIns->iInstance, but since it's
6208 * likely to be freqently used PDM passes it as parameter.
6209 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
6210 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
6211 * iInstance it's expected to be used a bit in this function.
6212 */
6213static DECLCALLBACK(int) ahciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
6214{
6215 PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6216 PPDMIBASE pBase;
6217 int rc = VINF_SUCCESS;
6218 unsigned i = 0;
6219 bool fGCEnabled = false;
6220 bool fR0Enabled = false;
6221 uint32_t cbTotalBufferSize = 0;
6222
6223 /*
6224 * Validate and read configuration.
6225 */
6226 rc = CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0"
6227 "R0Enabled\0"
6228 "PrimaryMaster\0"
6229 "PrimarySlave\0"
6230 "SecondaryMaster\0"
6231 "SecondarySlave\0"
6232 "PortCount\0"
6233 "UseAsyncInterfaceIfAvailable\0");
6234 if (RT_FAILURE(rc))
6235 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6236 N_("AHCI configuration error: unknown option specified"));
6237
6238 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
6239 if (RT_FAILURE(rc))
6240 return PDMDEV_SET_ERROR(pDevIns, rc,
6241 N_("AHCI configuration error: failed to read GCEnabled as boolean"));
6242 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
6243
6244 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
6245 if (RT_FAILURE(rc))
6246 return PDMDEV_SET_ERROR(pDevIns, rc,
6247 N_("AHCI configuration error: failed to read R0Enabled as boolean"));
6248 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
6249
6250 rc = CFGMR3QueryU32Def(pCfgHandle, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6251 if (RT_FAILURE(rc))
6252 return PDMDEV_SET_ERROR(pDevIns, rc,
6253 N_("AHCI configuration error: failed to read PortCount as integer"));
6254 Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
6255 if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
6256 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6257 N_("AHCI configuration error: PortCount=%u should not exceed %u"),
6258 pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6259 if (pThis->cPortsImpl < 1)
6260 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
6261 N_("AHCI configuration error: PortCount=%u should be at least 1"),
6262 pThis->cPortsImpl);
6263
6264 rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6265 if (RT_FAILURE(rc))
6266 return PDMDEV_SET_ERROR(pDevIns, rc,
6267 N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6268 rc = CFGMR3QueryU32Def(pCfgHandle, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6269 if (RT_FAILURE(rc))
6270 return PDMDEV_SET_ERROR(pDevIns, rc,
6271 N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
6272 rc = CFGMR3QueryU32Def(pCfgHandle, "MillisToSleep", &pThis->cMillisToSleep, 0);
6273 if (RT_FAILURE(rc))
6274 return PDMDEV_SET_ERROR(pDevIns, rc,
6275 N_("AHCI configuration error: failed to read MillisToSleep as integer"));
6276
6277 pThis->fR0Enabled = fR0Enabled;
6278 pThis->fGCEnabled = fGCEnabled;
6279 pThis->pDevInsR3 = pDevIns;
6280 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6281 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6282
6283 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
6284 PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
6285 PCIDevSetCommand (&pThis->dev, 0x0000);
6286 PCIDevSetRevisionId (&pThis->dev, 0x02);
6287 PCIDevSetClassProg (&pThis->dev, 0x01);
6288 PCIDevSetClassSub (&pThis->dev, 0x06);
6289 PCIDevSetClassBase (&pThis->dev, 0x01);
6290 PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
6291
6292 pThis->dev.config[0x34] = 0x80; /* Capability pointer. */
6293
6294 PCIDevSetInterruptLine(&pThis->dev, 0x00);
6295 PCIDevSetInterruptPin (&pThis->dev, 0x01);
6296
6297 pThis->dev.config[0x70] = 0x01; /* Capability ID: PCI Power Management Interface */
6298 pThis->dev.config[0x71] = 0x00;
6299 pThis->dev.config[0x72] = 0x03;
6300
6301 pThis->dev.config[0x80] = 0x05; /* Capability ID: Message Signaled Interrupts. Disabled. */
6302 pThis->dev.config[0x81] = 0x70; /* next. */
6303
6304 pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
6305 pThis->dev.config[0x92] = 0x3f;
6306 pThis->dev.config[0x94] = 0x80;
6307 pThis->dev.config[0x95] = 0x01;
6308 pThis->dev.config[0x97] = 0x78;
6309
6310 /*
6311 * Register the PCI device, it's I/O regions.
6312 */
6313 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
6314 if (RT_FAILURE(rc))
6315 return rc;
6316
6317 /*
6318 * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
6319 * IDE registers are not available.
6320 * We set up "fake" entries in the PCI configuration register.
6321 * That means they are available but read and writes from/to them have no effect.
6322 * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
6323 * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
6324 * to switch to it which also changes device Id and other things in the PCI configuration space).
6325 */
6326 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6327 if (RT_FAILURE(rc))
6328 return PDMDEV_SET_ERROR(pDevIns, rc,
6329 N_("AHCI cannot register PCI I/O region"));
6330
6331 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6332 if (RT_FAILURE(rc))
6333 return PDMDEV_SET_ERROR(pDevIns, rc,
6334 N_("AHCI cannot register PCI I/O region"));
6335
6336 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6337 if (RT_FAILURE(rc))
6338 return PDMDEV_SET_ERROR(pDevIns, rc,
6339 N_("AHCI cannot register PCI I/O region"));
6340
6341 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6342 if (RT_FAILURE(rc))
6343 return PDMDEV_SET_ERROR(pDevIns, rc,
6344 N_("AHCI cannot register PCI I/O region"));
6345
6346 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
6347 if (RT_FAILURE(rc))
6348 return PDMDEV_SET_ERROR(pDevIns, rc,
6349 N_("AHCI cannot register PCI I/O region for BMDMA"));
6350
6351 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciMMIOMap);
6352 if (RT_FAILURE(rc))
6353 return PDMDEV_SET_ERROR(pDevIns, rc,
6354 N_("AHCI cannot register PCI memory region for registers"));
6355
6356 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, "AHCI");
6357 if (RT_FAILURE(rc))
6358 {
6359 Log(("%s: Failed to create critical section.\n", __FUNCTION__));
6360 return rc;
6361 }
6362
6363 /* Create the timer for command completion coalescing feature. */
6364 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ahciCccTimer, pThis,
6365 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
6366 if (RT_FAILURE(rc))
6367 {
6368 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
6369 return rc;
6370 }
6371 pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
6372 pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
6373
6374 /* Status LUN. */
6375 pThis->IBase.pfnQueryInterface = ahciStatus_QueryInterface;
6376 pThis->ILeds.pfnQueryStatusLed = ahciStatus_QueryStatusLed;
6377
6378 /*
6379 * Create the transmit queue.
6380 */
6381 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6382 ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6383 if (RT_FAILURE(rc))
6384 return rc;
6385 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
6386 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
6387
6388 /* Initialize static members on every port. */
6389 for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6390 {
6391 /*
6392 * Init members of the port.
6393 */
6394 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6395 pAhciPort->pDevInsR3 = pDevIns;
6396 pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
6397 pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
6398 pAhciPort->iLUN = i;
6399 pAhciPort->pAhciR3 = pThis;
6400 pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
6401 pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
6402 pAhciPort->Led.u32Magic = PDMLED_MAGIC;
6403 pAhciPort->pDrvBase = NULL;
6404
6405 /* Register statistics counter. */
6406 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6407 "Number of DMA transfers.", "/Devices/SATA/Port%d/DMA", i);
6408 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6409 "Amount of data read.", "/Devices/SATA/Port%d/ReadBytes", i);
6410 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
6411 "Amount of data written.", "/Devices/SATA/Port%d/WrittenBytes", i);
6412 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
6413 "Number of processed I/O requests per second.", "/Devices/SATA/Port%d/IORequestsPerSecond", i);
6414#ifdef VBOX_WITH_STATISTICS
6415 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6416 "Amount of time to process one request.", "/Devices/SATA/Port%d/ProfileProcessTime", i);
6417 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6418 "Amount of time to map the guest buffers into R3.", "/Devices/SATA/Port%d/ProfileMapIntoR3", i);
6419 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6420 "Amount of time for the read/write operation to complete.", "/Devices/SATA/Port%d/ProfileReadWrite", i);
6421 PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
6422 "Amount of time to destroy the scatter gather list and free associated ressources.", "/Devices/SATA/Port%d/ProfileDestroyScatterGatherList", i);
6423#endif
6424
6425 ahciPortHwReset(pAhciPort);
6426 }
6427
6428 /* Attach drivers to every available port. */
6429 for (i = 0; i < pThis->cPortsImpl; i++)
6430 {
6431 char szName[24];
6432 RTStrPrintf(szName, sizeof(szName), "Port%d", i);
6433
6434 PAHCIPort pAhciPort = &pThis->ahciPort[i];
6435 /*
6436 * Init interfaces.
6437 */
6438 pAhciPort->IBase.pfnQueryInterface = ahciPortQueryInterface;
6439 pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciTransferCompleteNotify;
6440 pAhciPort->IMountNotify.pfnMountNotify = ahciMountNotify;
6441 pAhciPort->IMountNotify.pfnUnmountNotify = ahciUnmountNotify;
6442 pAhciPort->fAsyncIOThreadIdle = true;
6443
6444 /*
6445 * Attach the block driver
6446 */
6447 rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
6448 if (RT_SUCCESS(rc))
6449 {
6450 rc = ahciConfigureLUN(pDevIns, pAhciPort);
6451 if (RT_FAILURE(rc))
6452 {
6453 Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
6454 return rc;
6455 }
6456
6457 /* Mark that a device is present on that port */
6458 if (i < 6)
6459 pThis->dev.config[0x93] |= (1 << i);
6460
6461 /*
6462 * Init vendor product data.
6463 */
6464 /* Generate a default serial number. */
6465 char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
6466 RTUUID Uuid;
6467 if (pAhciPort->pDrvBlock)
6468 rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
6469 else
6470 RTUuidClear(&Uuid);
6471
6472 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
6473 {
6474 /* Generate a predictable serial for drives which don't have a UUID. */
6475 RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
6476 pAhciPort->iLUN);
6477 }
6478 else
6479 RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
6480
6481 /* Get user config if present using defaults otherwise. */
6482 PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, szName);
6483 rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
6484 szSerial);
6485 if (RT_FAILURE(rc))
6486 {
6487 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6488 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6489 N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
6490 return PDMDEV_SET_ERROR(pDevIns, rc,
6491 N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
6492 }
6493
6494 rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
6495 "1.0");
6496 if (RT_FAILURE(rc))
6497 {
6498 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6499 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6500 N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
6501 return PDMDEV_SET_ERROR(pDevIns, rc,
6502 N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
6503 }
6504
6505 rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
6506 "VBOX HARDDISK");
6507 if (RT_FAILURE(rc))
6508 {
6509 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
6510 return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
6511 N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
6512 return PDMDEV_SET_ERROR(pDevIns, rc,
6513 N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
6514 }
6515
6516 /*
6517 * If the new async interface is available we use a PDMQueue to transmit
6518 * the requests into R3.
6519 * Otherwise we use a event semaphore and a async I/O thread which processes them.
6520 */
6521 if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
6522 {
6523 LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
6524 pAhciPort->fAsyncInterface = true;
6525 }
6526 else
6527 {
6528 LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
6529 pAhciPort->fAsyncInterface = false;
6530
6531 rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
6532 AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
6533
6534
6535 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6536 RTTHREADTYPE_IO, szName);
6537 AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
6538 }
6539 }
6540 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
6541 {
6542 pAhciPort->pDrvBase = NULL;
6543 rc = VINF_SUCCESS;
6544 LogRel(("%s: no driver attached\n", szName));
6545 }
6546 else
6547 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6548 N_("AHCI: Failed to attach drive to %s"), szName);
6549
6550#ifdef DEBUG
6551 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
6552 pAhciPort->ahciIOTasks[i] = 0xff;
6553#endif
6554 }
6555
6556 /*
6557 * Attach status driver (optional).
6558 */
6559 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
6560 if (RT_SUCCESS(rc))
6561 pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
6562 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
6563 {
6564 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
6565 return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
6566 }
6567
6568 /*
6569 * Setup IDE emulation.
6570 * We only emulate the I/O ports but not bus master DMA.
6571 * If the configuration values are not found the setup of the ports is as follows:
6572 * Primary Master: Port 0
6573 * Primary Slave: Port 1
6574 * Secondary Master: Port 2
6575 * Secondary Slave: Port 3
6576 */
6577
6578 /*
6579 * Setup I/O ports for the PCI device.
6580 */
6581 pThis->aCts[0].irq = 12;
6582 pThis->aCts[0].IOPortBase1 = 0x1e8;
6583 pThis->aCts[0].IOPortBase2 = 0x3e6;
6584 pThis->aCts[1].irq = 11;
6585 pThis->aCts[1].IOPortBase1 = 0x168;
6586 pThis->aCts[1].IOPortBase2 = 0x366;
6587
6588 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6589 {
6590 PAHCIATACONTROLLER pCtl = &pThis->aCts[i];
6591 uint32_t iPortMaster, iPortSlave;
6592 uint32_t cbSSMState = 0;
6593 static const char *s_apszDescs[RT_ELEMENTS(pThis->aCts)][RT_ELEMENTS(pCtl->aIfs)] =
6594 {
6595 { "PrimaryMaster", "PrimarySlave" },
6596 { "SecondaryMaster", "SecondarySlave" }
6597 };
6598
6599 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][0], &iPortMaster, 2 * i);
6600 if (RT_FAILURE(rc))
6601 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6602 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
6603
6604 rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
6605 if (RT_FAILURE(rc))
6606 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6607 N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);
6608
6609 char szName[24];
6610 RTStrPrintf(szName, sizeof(szName), "EmulatedATA%d", i);
6611 rc = ataControllerInit(pDevIns, pCtl, pThis->ahciPort[iPortMaster].pDrvBase, pThis->ahciPort[iPortSlave].pDrvBase,
6612 &cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led, &pThis->ahciPort[iPortMaster].StatBytesRead,
6613 &pThis->ahciPort[iPortMaster].StatBytesWritten);
6614 if (RT_FAILURE(rc))
6615 return rc;
6616
6617 cbTotalBufferSize += cbSSMState;
6618
6619 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase1, 8, (RTHCPTR)i,
6620 ahciIOPortWrite1, ahciIOPortRead1, ahciIOPortWriteStr1, ahciIOPortReadStr1, "AHCI");
6621 if (RT_FAILURE(rc))
6622 return rc;
6623
6624 if (pThis->fR0Enabled)
6625 {
6626 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase1, 8, (RTR0PTR)i,
6627 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI R0");
6628 if (RT_FAILURE(rc))
6629 return rc;
6630 }
6631
6632 if (pThis->fGCEnabled)
6633 {
6634 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
6635 "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI GC");
6636 if (RT_FAILURE(rc))
6637 return rc;
6638 }
6639
6640 rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase2, 1, (RTHCPTR)i,
6641 ahciIOPortWrite2, ahciIOPortRead2, NULL, NULL, "AHCI");
6642 if (RT_FAILURE(rc))
6643 return rc;
6644
6645 if (pThis->fR0Enabled)
6646 {
6647 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase2, 1, (RTR0PTR)i,
6648 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI R0");
6649 if (RT_FAILURE(rc))
6650 return rc;
6651 }
6652
6653 if (pThis->fGCEnabled)
6654 {
6655 rc = PDMDevHlpIOPortRegisterGC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
6656 "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI GC");
6657 if (RT_FAILURE(rc))
6658 return rc;
6659 }
6660 }
6661
6662 rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
6663 NULL, NULL, NULL,
6664 ahciSavePrep, ahciSaveExec, NULL,
6665 ahciLoadPrep, ahciLoadExec, NULL);
6666 if (RT_FAILURE(rc))
6667 return rc;
6668
6669 ahciReset(pDevIns);
6670
6671 return rc;
6672}
6673
6674/**
6675 * The device registration structure.
6676 */
6677const PDMDEVREG g_DeviceAHCI =
6678{
6679 /* u32Version */
6680 PDM_DEVREG_VERSION,
6681 /* szDeviceName */
6682 "ahci",
6683 /* szRCMod */
6684 "VBoxDDGC.gc",
6685 /* szR0Mod */
6686 "VBoxDDR0.r0",
6687 /* pszDescription */
6688 "Intel AHCI controller.\n",
6689 /* fFlags */
6690 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
6691 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
6692 /* fClass */
6693 PDM_DEVREG_CLASS_STORAGE,
6694 /* cMaxInstances */
6695 ~0,
6696 /* cbInstance */
6697 sizeof(AHCI),
6698 /* pfnConstruct */
6699 ahciConstruct,
6700 /* pfnDestruct */
6701 ahciDestruct,
6702 /* pfnRelocate */
6703 ahciRelocate,
6704 /* pfnIOCtl */
6705 NULL,
6706 /* pfnPowerOn */
6707 NULL,
6708 /* pfnReset */
6709 ahciReset,
6710 /* pfnSuspend */
6711 ahciSuspend,
6712 /* pfnResume */
6713 ahciResume,
6714 /* pfnAttach */
6715 ahciAttach,
6716 /* pfnDetach */
6717 ahciDetach,
6718 /* pfnQueryInterface. */
6719 NULL,
6720 /* pfnInitComplete */
6721 NULL,
6722 /* pfnPowerOff */
6723 ahciPowerOff,
6724 /* pfnSoftReset */
6725 NULL,
6726 /* u32VersionEnd */
6727 PDM_DEVREG_VERSION
6728};
6729
6730#endif /* IN_RING3 */
6731#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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