VirtualBox

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

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

Misaligned critical section

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

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