VirtualBox

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

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

AHCI: fix race condition resulting in hanging I/O

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

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