VirtualBox

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

Last change on this file since 22727 was 22727, checked in by vboxsync, 16 years ago

AHCI: Fallback to a safe method for processing the PRDTL if mapping guest RAM fails

  • 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 22727 2009-09-02 23:08:23Z vboxsync $ */
2/** @file
3 *
4 * VBox storage devices:
5 * AHCI controller device (disk).
6 * Implements the AHCI standard 1.1
7 */
8
9/*
10 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
26 *
27 * This component implements an AHCI SATA controller.
28 * The device is split into two parts. The first part implements the
29 * register interface for the guest and the second one does the data transfer.
30 *
31 * The guest can access the controller in two ways. The first one is the native
32 * way implementing the registers described in the AHCI specification and is
33 * the preferred one.
34 * The second implements the I/O ports used for booting from the hard disk
35 * and for guests which don't have an AHCI SATA driver.
36 *
37 * The data is transfered in an asychronous way using one thread per implemented
38 * port or using the new async completion interface which is still under development.
39 *
40 */
41
42/*******************************************************************************
43* Header Files *
44*******************************************************************************/
45//#define DEBUG
46#define LOG_GROUP LOG_GROUP_DEV_AHCI
47#include <VBox/pdmdev.h>
48#include <VBox/pdmqueue.h>
49#include <VBox/pdmthread.h>
50#include <VBox/pdmcritsect.h>
51#include <VBox/scsi.h>
52#include <iprt/assert.h>
53#include <iprt/asm.h>
54#include <iprt/string.h>
55#ifdef IN_RING3
56# include <iprt/param.h>
57# include <iprt/thread.h>
58# include <iprt/semaphore.h>
59# include <iprt/alloc.h>
60# include <iprt/uuid.h>
61# include <iprt/time.h>
62#endif
63
64#include "ide.h"
65#include "ATAController.h"
66#include "../Builtins.h"
67
68#define AHCI_MAX_NR_PORTS_IMPL 30
69#define AHCI_NR_COMMAND_SLOTS 32
70#define AHCI_SAVED_STATE_VERSION 2
71#define AHCI_NR_OF_ALLOWED_BIGGER_LISTS 100
72
73/**
74 * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
75 * Set to 1 to disable multi-sector read support. According to the ATA
76 * specification this must be a power of 2 and it must fit in an 8 bit
77 * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
78 */
79#define ATA_MAX_MULT_SECTORS 128
80
81/**
82 * Fastest PIO mode supported by the drive.
83 */
84#define ATA_PIO_MODE_MAX 4
85/**
86 * Fastest MDMA mode supported by the drive.
87 */
88#define ATA_MDMA_MODE_MAX 2
89/**
90 * Fastest UDMA mode supported by the drive.
91 */
92#define ATA_UDMA_MODE_MAX 6
93
94/**
95 * Length of the configurable VPD data (without termination)
96 */
97#define AHCI_SERIAL_NUMBER_LENGTH 20
98#define AHCI_FIRMWARE_REVISION_LENGTH 8
99#define AHCI_MODEL_NUMBER_LENGTH 40
100
101/* Command Header. */
102typedef struct
103{
104 /** Description Information. */
105 uint32_t u32DescInf;
106 /** Command status. */
107 uint32_t u32PRDBC;
108 /** Command Table Base Address. */
109 uint32_t u32CmdTblAddr;
110 /** Command Table Base Address - upper 32-bits. */
111 uint32_t u32CmdTblAddrUp;
112 /** Reserved */
113 uint32_t u32Reserved[4];
114} CmdHdr;
115AssertCompileSize(CmdHdr, 32);
116
117/* Defines for the command header. */
118#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
119#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
120#define AHCI_CMDHDR_C RT_BIT(10)
121#define AHCI_CMDHDR_B RT_BIT(9)
122#define AHCI_CMDHDR_R RT_BIT(8)
123#define AHCI_CMDHDR_P RT_BIT(7)
124#define AHCI_CMDHDR_W RT_BIT(6)
125#define AHCI_CMDHDR_A RT_BIT(5)
126#define AHCI_CMDHDR_CFL_MASK 0x1f
127
128#define AHCI_CMDHDR_PRDT_OFFSET 0x80
129#define AHCI_CMDHDR_ACMD_OFFSET 0x40
130
131/* Defines for the command FIS. */
132/* Defines that are used in the first double word. */
133#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
134# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
135# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
136# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
137# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
138# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
139# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
140# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
141# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
142# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
143# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
144# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
145# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
146# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
147
148#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
149#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
150#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
151
152#define AHCI_CMDFIS_CMD 2
153#define AHCI_CMDFIS_FET 3
154
155#define AHCI_CMDFIS_SECTN 4
156#define AHCI_CMDFIS_CYLL 5
157#define AHCI_CMDFIS_CYLH 6
158#define AHCI_CMDFIS_HEAD 7
159
160#define AHCI_CMDFIS_SECTNEXP 8
161#define AHCI_CMDFIS_CYLLEXP 9
162#define AHCI_CMDFIS_CYLHEXP 10
163#define AHCI_CMDFIS_FETEXP 11
164
165#define AHCI_CMDFIS_SECTC 12
166#define AHCI_CMDFIS_SECTCEXP 13
167#define AHCI_CMDFIS_CTL 15
168# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
169# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
170
171/* For D2H FIS */
172#define AHCI_CMDFIS_STS 2
173#define AHCI_CMDFIS_ERR 3
174
175/**
176 * Scatter gather list entry data.
177 */
178typedef struct AHCIPORTTASKSTATESGENTRY
179{
180 /** Flag whether the buffer in the list is from the guest or an
181 * allocated temporary buffer because the segments in the guest
182 * are not sector aligned.
183 */
184 bool fGuestMemory;
185 /** Flag dependent data. */
186 union
187 {
188 /** Data to handle direct mappings of guest buffers. */
189 struct
190 {
191 /** The page lock. */
192 PGMPAGEMAPLOCK PageLock;
193 } direct;
194 /** Data to handle temporary buffers. */
195 struct
196 {
197 /** The first segment in the guest which is not sector aligned. */
198 RTGCPHYS GCPhysAddrBaseFirstUnaligned;
199 /** Number of unaligned buffers in the guest. */
200 uint32_t cUnaligned;
201 /** Pointer to the start of the buffer. */
202 void *pvBuf;
203 } temp;
204 } u;
205} AHCIPORTTASKSTATESGENTRY, *PAHCIPORTTASKSTATESGENTRY;
206
207/** Pointer to a pointer of a scatter gather list entry. */
208typedef PAHCIPORTTASKSTATESGENTRY *PPAHCIPORTTASKSTATESGENTRY;
209
210/**
211 * A task state.
212 */
213typedef struct AHCIPORTTASKSTATE
214{
215 /** Tag of the task. */
216 uint32_t uTag;
217 /** Command is queued. */
218 bool fQueued;
219 /** The command header for this task. */
220 CmdHdr cmdHdr;
221 /** The command Fis for this task. */
222 uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
223 /** The ATAPI comnmand data. */
224 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
225 /** Physical address of the command header. - GC */
226 RTGCPHYS GCPhysCmdHdrAddr;
227 /** Data direction. */
228 uint8_t uTxDir;
229 /** Start offset. */
230 uint64_t uOffset;
231 /** Number of bytes to transfer. */
232 uint32_t cbTransfer;
233 /** ATA error register */
234 uint8_t uATARegError;
235 /** ATA status register */
236 uint8_t uATARegStatus;
237 /** Number of scatter gather list entries. */
238 uint32_t cSGEntries;
239 /** How many entries would fit into the sg list. */
240 uint32_t cSGListSize;
241 /** Pointer to the first entry of the scatter gather list. */
242 PPDMDATASEG pSGListHead;
243 /** Pointer to the first mapping information entry. */
244 PAHCIPORTTASKSTATESGENTRY paSGEntries;
245 /** Size of the temporary buffer for unaligned guest segments. */
246 uint32_t cbBufferUnaligned;
247 /** Pointer to the temporary buffer. */
248 void *pvBufferUnaligned;
249 /** Number of times in a row the scatter gather list was too big. */
250 uint32_t cSGListTooBig;
251} AHCIPORTTASKSTATE, *PAHCIPORTTASKSTATE;
252
253/**
254 * Notifier queue item.
255 */
256typedef struct DEVPORTNOTIFIERQUEUEITEM
257{
258 /** The core part owned by the queue manager. */
259 PDMQUEUEITEMCORE Core;
260 /** On which port the async io thread should be put into action. */
261 uint8_t iPort;
262 /** Which task to process. */
263 uint8_t iTask;
264 /** Flag whether the task is queued. */
265 uint8_t fQueued;
266} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
267
268typedef struct AHCIPort
269{
270 /** Pointer to the device instance - HC ptr */
271 PPDMDEVINSR3 pDevInsR3;
272 /** Pointer to the device instance - R0 ptr */
273 PPDMDEVINSR0 pDevInsR0;
274 /** Pointer to the device instance - RC ptr. */
275 PPDMDEVINSRC pDevInsRC;
276
277#if HC_ARCH_BITS == 64
278 uint32_t Alignment0;
279#endif
280
281 /** Pointer to the parent AHCI structure - R3 ptr. */
282 R3PTRTYPE(struct AHCI *) pAhciR3;
283 /** Pointer to the parent AHCI structure - R0 ptr. */
284 R0PTRTYPE(struct AHCI *) pAhciR0;
285 /** Pointer to the parent AHCI structure - RC ptr. */
286 RCPTRTYPE(struct AHCI *) pAhciRC;
287 /** Command List Base Address. */
288 uint32_t regCLB;
289 /** Command List Base Address upper bits. */
290 uint32_t regCLBU;
291 /** FIS Base Address. */
292 uint32_t regFB;
293 /** FIS Base Address upper bits. */
294 uint32_t regFBU;
295 /** Interrupt Status. */
296 volatile uint32_t regIS;
297 /** Interrupt Enable. */
298 uint32_t regIE;
299 /** Command. */
300 uint32_t regCMD;
301 /** Task File Data. */
302 uint32_t regTFD;
303 /** Signature */
304 uint32_t regSIG;
305 /** Serial ATA Status. */
306 uint32_t regSSTS;
307 /** Serial ATA Control. */
308 uint32_t regSCTL;
309 /** Serial ATA Error. */
310 uint32_t regSERR;
311 /** Serial ATA Active. */
312 uint32_t regSACT;
313 /** Command Issue. */
314 uint32_t regCI;
315
316#if HC_ARCH_BITS == 64
317 uint32_t Alignment1;
318#endif
319
320 /** Command List Base Address */
321 volatile RTGCPHYS GCPhysAddrClb;
322 /** FIS Base Address */
323 volatile RTGCPHYS GCPhysAddrFb;
324
325 /** If we use the new async interface. */
326 bool fAsyncInterface;
327
328#if HC_ARCH_BITS == 64
329 uint32_t Alignment2;
330#endif
331
332 /** Async IO Thread. */
333 PPDMTHREAD pAsyncIOThread;
334 /** Request semaphore. */
335 RTSEMEVENT AsyncIORequestSem;
336
337 /** Task queue. */
338 volatile uint8_t ahciIOTasks[2*AHCI_NR_COMMAND_SLOTS];
339 /** Actual write position. */
340 uint8_t uActWritePos;
341 /** Actual read position. */
342 uint8_t uActReadPos;
343 /** Actual number of active tasks. */
344 volatile uint32_t uActTasksActive;
345
346 /** Device is powered on. */
347 bool fPoweredOn;
348 /** Device has spun up. */
349 bool fSpunUp;
350 /** First D2H FIS was send. */
351 bool fFirstD2HFisSend;
352 /** Attached device is a CD/DVD drive. */
353 bool fATAPI;
354
355#if HC_ARCH_BITS == 64
356 uint32_t Alignment3;
357#endif
358
359 /** Device specific settings. */
360 /** Pointer to the attached driver's base interface. */
361 R3PTRTYPE(PPDMIBASE) pDrvBase;
362 /** Pointer to the attached driver's block interface. */
363 R3PTRTYPE(PPDMIBLOCK) pDrvBlock;
364 /** Pointer to the attached driver's async block interface. */
365 R3PTRTYPE(PPDMIBLOCKASYNC) pDrvBlockAsync;
366 /** Pointer to the attached driver's block bios interface. */
367 R3PTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
368 /** Pointer to the attached driver's mount interface. */
369 R3PTRTYPE(PPDMIMOUNT) pDrvMount;
370 /** The base interface. */
371 PDMIBASE IBase;
372 /** The block port interface. */
373 PDMIBLOCKPORT IPort;
374 /** The optional block async port interface. */
375 PDMIBLOCKASYNCPORT IPortAsync;
376 /** The mount notify interface. */
377 PDMIMOUNTNOTIFY IMountNotify;
378 /** Physical geometry of this image. */
379 PDMMEDIAGEOMETRY PCHSGeometry;
380 /** The status LED state for this drive. */
381 PDMLED Led;
382
383#if HC_ARCH_BITS == 64
384 uint32_t Alignment4;
385#endif
386
387 /** Number of total sectors. */
388 uint64_t cTotalSectors;
389 /** Currently configured number of sectors in a multi-sector transfer. */
390 uint32_t cMultSectors;
391 /** Currently active transfer mode (MDMA/UDMA) and speed. */
392 uint8_t uATATransferMode;
393 /** ATAPI sense key. */
394 uint8_t uATAPISenseKey;
395 /** ATAPI additional sens code. */
396 uint8_t uATAPIASC;
397 /** HACK: Countdown till we report a newly unmounted drive as mounted. */
398 uint8_t cNotifiedMediaChange;
399
400 /** The LUN. */
401 RTUINT iLUN;
402 /** Flag if we are in a device reset. */
403 bool fResetDevice;
404
405 /** Bitmask for finished tasks. */
406 volatile uint32_t u32TasksFinished;
407 /** Bitmask for finished queued tasks. */
408 volatile uint32_t u32QueuedTasksFinished;
409
410 /**
411 * Array of cached tasks. The tag number is the index value.
412 * Only used with the async interface.
413 */
414 R3PTRTYPE(PAHCIPORTTASKSTATE) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
415
416 /** Release statistics: number of DMA commands. */
417 STAMCOUNTER StatDMA;
418 /** Release statistics: number of bytes written. */
419 STAMCOUNTER StatBytesWritten;
420 /** Release statistics: number of bytes read. */
421 STAMCOUNTER StatBytesRead;
422 /** Release statistics: Number of I/O requests processed per second. */
423 STAMCOUNTER StatIORequestsPerSecond;
424#ifdef VBOX_WITH_STATISTICS
425 /** Statistics: Time to complete one request. */
426 STAMPROFILE StatProfileProcessTime;
427 /** Statistics: Time to map requests into R3. */
428 STAMPROFILE StatProfileMapIntoR3;
429 /** Statistics: Amount of time to read/write data. */
430 STAMPROFILE StatProfileReadWrite;
431 /** Statistics: Amount of time to destroy a list. */
432 STAMPROFILE StatProfileDestroyScatterGatherList;
433#endif /* VBOX_WITH_STATISTICS */
434 /** Flag whether a notification was already send to R3. */
435 volatile bool fNotificationSend;
436 /** Flag whether this port is in a reset state. */
437 volatile bool fPortReset;
438 /** Flag whether the I/O thread idles. */
439 volatile bool fAsyncIOThreadIdle;
440
441 /** The serial numnber to use for IDENTIFY DEVICE commands. */
442 char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
443 /** The firmware revision to use for IDENTIFY DEVICE commands. */
444 char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
445 /** The model number to use for IDENTIFY DEVICE commands. */
446 char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
447
448#if HC_ARCH_BITS == 64
449 uint32_t Alignment5;
450#endif
451
452} AHCIPort, *PAHCIPort;
453
454/*
455 * Main AHCI device state.
456 */
457typedef struct AHCI
458{
459 /** The PCI device structure. */
460 PCIDEVICE dev;
461 /** Pointer to the device instance - R3 ptr */
462 PPDMDEVINSR3 pDevInsR3;
463 /** Pointer to the device instance - R0 ptr */
464 PPDMDEVINSR0 pDevInsR0;
465 /** Pointer to the device instance - RC ptr. */
466 PPDMDEVINSRC pDevInsRC;
467
468#if HC_ARCH_BITS == 64
469 uint32_t Alignment0;
470#endif
471
472 /** The base interface */
473 PDMIBASE IBase;
474 /** Status Port - Leds interface. */
475 PDMILEDPORTS ILeds;
476 /** Partner of ILeds. */
477 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
478
479#if HC_ARCH_BITS == 64
480 uint32_t Alignment1[2];
481#endif
482
483 /** Base address of the MMIO region. */
484 RTGCPHYS MMIOBase;
485
486 /** Global Host Control register of the HBA */
487
488 /** HBA Capabilities - Readonly */
489 uint32_t regHbaCap;
490 /** HBA Control */
491 uint32_t regHbaCtrl;
492 /** Interrupt Status */
493 uint32_t regHbaIs;
494 /** Ports Implemented - Readonly */
495 uint32_t regHbaPi;
496 /** AHCI Version - Readonly */
497 uint32_t regHbaVs;
498 /** Command completion coalescing control */
499 uint32_t regHbaCccCtl;
500 /** Command completion coalescing ports */
501 uint32_t regHbaCccPorts;
502
503#if HC_ARCH_BITS == 64
504 uint32_t Alignment3;
505#endif
506
507 /** Countdown timer for command completion coalescing - R3 ptr */
508 PTMTIMERR3 pHbaCccTimerR3;
509 /** Countdown timer for command completion coalescing - R0 ptr */
510 PTMTIMERR0 pHbaCccTimerR0;
511 /** Countdown timer for command completion coalescing - RC ptr */
512 PTMTIMERRC pHbaCccTimerRC;
513
514#if HC_ARCH_BITS == 64
515 uint32_t Alignment4;
516#endif
517
518 /** Queue to send tasks to R3. - HC ptr */
519 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
520 /** Queue to send tasks to R3. - HC ptr */
521 R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
522 /** Queue to send tasks to R3. - RC ptr */
523 RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
524
525#if HC_ARCH_BITS == 64
526 uint32_t Alignment5;
527#endif
528
529
530 /** Which port number is used to mark an CCC interrupt */
531 uint8_t uCccPortNr;
532
533#if HC_ARCH_BITS == 64
534 uint32_t Alignment6;
535#endif
536
537 /** Timeout value */
538 uint64_t uCccTimeout;
539 /** Number of completions used to assert an interrupt */
540 uint32_t uCccNr;
541 /** Current number of completed commands */
542 uint32_t uCccCurrentNr;
543
544 /** Register structure per port */
545 AHCIPort ahciPort[AHCI_MAX_NR_PORTS_IMPL];
546
547 /** Needed values for the emulated ide channels. */
548 AHCIATACONTROLLER aCts[2];
549
550 /** Bitmask of ports which asserted an interrupt. */
551 uint32_t u32PortsInterrupted;
552 /** Device is in a reset state. */
553 bool fReset;
554 /** Supports 64bit addressing */
555 bool f64BitAddr;
556 /** GC enabled. */
557 bool fGCEnabled;
558 /** R0 enabled. */
559 bool fR0Enabled;
560 /** If the new async interface is used if available. */
561 bool fUseAsyncInterfaceIfAvailable;
562 /** The critical section. */
563 PDMCRITSECT lock;
564
565 /** Number of usable ports on this controller. */
566 uint32_t cPortsImpl;
567
568#if HC_ARCH_BITS == 64
569 uint32_t Alignment7;
570#endif
571
572 /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
573 volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
574 /** At which number of I/O requests per second we consider having high I/O load. */
575 uint32_t cHighIOThreshold;
576 /** How many milliseconds to sleep. */
577 uint32_t cMillisToSleep;
578
579} AHCI, *PAHCI;
580
581/* Scatter gather list entry. */
582typedef struct
583{
584 /** Data Base Address. */
585 uint32_t u32DBA;
586 /** Data Base Address - Upper 32-bits. */
587 uint32_t u32DBAUp;
588 /** Reserved */
589 uint32_t u32Reserved;
590 /** Description information. */
591 uint32_t u32DescInf;
592} SGLEntry;
593AssertCompileSize(SGLEntry, 16);
594
595/** Defines for a scatter gather list entry. */
596#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
597#define SGLENTRY_DESCINF_I RT_BIT(31)
598#define SGLENTRY_DESCINF_DBC 0x3fffff
599#define SGLENTRY_DESCINF_READONLY 0x803fffff
600
601/* Defines for the global host control registers for the HBA. */
602
603#define AHCI_HBA_GLOBAL_SIZE 0x100
604
605/* Defines for the HBA Capabilities - Readonly */
606#define AHCI_HBA_CAP_S64A RT_BIT(31)
607#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
608#define AHCI_HBA_CAP_SIS RT_BIT(28)
609#define AHCI_HBA_CAP_SSS RT_BIT(27)
610#define AHCI_HBA_CAP_SALP RT_BIT(26)
611#define AHCI_HBA_CAP_SAL RT_BIT(25)
612#define AHCI_HBA_CAP_SCLO RT_BIT(24)
613#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
614# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
615# define AHCI_HBA_CAP_ISS_GEN1 RT_BIT(0)
616# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
617#define AHCI_HBA_CAP_SNZO RT_BIT(19)
618#define AHCI_HBA_CAP_SAM RT_BIT(18)
619#define AHCI_HBA_CAP_SPM RT_BIT(17)
620#define AHCI_HBA_CAP_PMD RT_BIT(15)
621#define AHCI_HBA_CAP_SSC RT_BIT(14)
622#define AHCI_HBA_CAP_PSC RT_BIT(13)
623#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
624#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
625#define AHCI_HBA_CAP_CCCS RT_BIT(7)
626#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
627#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
628
629/* Defines for the HBA Control register - Read/Write */
630#define AHCI_HBA_CTRL_AE RT_BIT(31)
631#define AHCI_HBA_CTRL_IE RT_BIT(1)
632#define AHCI_HBA_CTRL_HR RT_BIT(0)
633#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
634
635/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
636#define AHCI_HBA_VS_MJR (1 << 16)
637#define AHCI_HBA_VS_MNR 0x100
638
639/* Defines for the command completion coalescing control register */
640#define AHCI_HBA_CCC_CTL_TV 0xffff0000
641#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
642#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
643
644#define AHCI_HBA_CCC_CTL_CC 0xff00
645#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
646#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
647
648#define AHCI_HBA_CCC_CTL_INT 0xf8
649#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
650#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
651
652#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
653
654/* Defines for the port registers. */
655
656#define AHCI_PORT_REGISTER_SIZE 0x80
657
658#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
659
660#define AHCI_PORT_FB_RESERVED 0x7fffff00 /* For masking out the reserved bits. */
661
662#define AHCI_PORT_IS_CPDS RT_BIT(31)
663#define AHCI_PORT_IS_TFES RT_BIT(30)
664#define AHCI_PORT_IS_HBFS RT_BIT(29)
665#define AHCI_PORT_IS_HBDS RT_BIT(28)
666#define AHCI_PORT_IS_IFS RT_BIT(27)
667#define AHCI_PORT_IS_INFS RT_BIT(26)
668#define AHCI_PORT_IS_OFS RT_BIT(24)
669#define AHCI_PORT_IS_IPMS RT_BIT(23)
670#define AHCI_PORT_IS_PRCS RT_BIT(22)
671#define AHCI_PORT_IS_DIS RT_BIT(7)
672#define AHCI_PORT_IS_PCS RT_BIT(6)
673#define AHCI_PORT_IS_DPS RT_BIT(5)
674#define AHCI_PORT_IS_UFS RT_BIT(4)
675#define AHCI_PORT_IS_SDBS RT_BIT(3)
676#define AHCI_PORT_IS_DSS RT_BIT(2)
677#define AHCI_PORT_IS_PSS RT_BIT(1)
678#define AHCI_PORT_IS_DHRS RT_BIT(0)
679#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
680
681#define AHCI_PORT_IE_CPDE RT_BIT(31)
682#define AHCI_PORT_IE_TFEE RT_BIT(30)
683#define AHCI_PORT_IE_HBFE RT_BIT(29)
684#define AHCI_PORT_IE_HBDE RT_BIT(28)
685#define AHCI_PORT_IE_IFE RT_BIT(27)
686#define AHCI_PORT_IE_INFE RT_BIT(26)
687#define AHCI_PORT_IE_OFE RT_BIT(24)
688#define AHCI_PORT_IE_IPME RT_BIT(23)
689#define AHCI_PORT_IE_PRCE RT_BIT(22)
690#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
691#define AHCI_PORT_IE_PCE RT_BIT(6)
692#define AHCI_PORT_IE_DPE RT_BIT(5)
693#define AHCI_PORT_IE_UFE RT_BIT(4)
694#define AHCI_PORT_IE_SDBE RT_BIT(3)
695#define AHCI_PORT_IE_DSE RT_BIT(2)
696#define AHCI_PORT_IE_PSE RT_BIT(1)
697#define AHCI_PORT_IE_DHRE RT_BIT(0)
698#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
699
700#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
701#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
702# define AHCI_PORT_CMD_ICC_IDLE 0x0
703# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
704# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
705# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
706#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
707#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
708#define AHCI_PORT_CMD_DLAE RT_BIT(25)
709#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
710#define AHCI_PORT_CMD_CPD RT_BIT(20)
711#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
712#define AHCI_PORT_CMD_HPCP RT_BIT(18)
713#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
714#define AHCI_PORT_CMD_CPS RT_BIT(16)
715#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
716#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
717#define AHCI_PORT_CMD_ISS RT_BIT(13) /* Readonly */
718#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
719#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
720#define AHCI_PORT_CMD_FRE RT_BIT(4)
721#define AHCI_PORT_CMD_CLO RT_BIT(3)
722#define AHCI_PORT_CMD_POD RT_BIT(2)
723#define AHCI_PORT_CMD_SUD RT_BIT(1)
724#define AHCI_PORT_CMD_ST RT_BIT(0)
725#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
726
727#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
728#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
729#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
730#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
731#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
732#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
733#define AHCI_PORT_SCTL_DET_NINIT 0
734#define AHCI_PORT_SCTL_DET_INIT 1
735#define AHCI_PORT_SCTL_DET_OFFLINE 4
736#define AHCI_PORT_SCTL_READONLY 0xfff
737
738#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
739#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
740#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
741#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
742#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
743#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
744
745#define AHCI_PORT_TFD_BSY RT_BIT(7)
746#define AHCI_PORT_TFD_DRQ RT_BIT(3)
747#define AHCI_PORT_TFD_ERR RT_BIT(0)
748
749#define AHCI_PORT_SERR_X RT_BIT(26)
750#define AHCI_PORT_SERR_W RT_BIT(18)
751#define AHCI_PORT_SERR_N RT_BIT(16)
752
753/* Signatures for attached storage devices. */
754#define AHCI_PORT_SIG_DISK 0x00000101
755#define AHCI_PORT_SIG_ATAPI 0xeb140101
756
757/*
758 * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
759 * regFB points to the base of this area.
760 * Every FIS type has an offset where it is posted in this area.
761 */
762#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
763#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
764#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
765#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
766#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
767
768#define AHCI_TASK_IS_QUEUED(x) ((x) & 0x1)
769#define AHCI_TASK_GET_TAG(x) ((x) >> 1)
770#define AHCI_TASK_SET(tag, queued) (((tag) << 1) | (queued))
771
772/**
773 * AHCI register operator.
774 */
775typedef struct ahci_opreg
776{
777 const char *pszName;
778 int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
779 int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
780} AHCIOPREG;
781
782/**
783 * AHCI port register operator.
784 */
785typedef struct pAhciPort_opreg
786{
787 const char *pszName;
788 int (*pfnRead )(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
789 int (*pfnWrite)(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
790} AHCIPORTOPREG;
791
792#ifndef VBOX_DEVICE_STRUCT_TESTCASE
793RT_C_DECLS_BEGIN
794PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
795PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
796static void ahciHBAReset(PAHCI pThis);
797PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
798PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
799PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
800PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
801PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
802PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
803#ifdef IN_RING3
804static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
805static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
806static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf);
807static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly);
808static int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
809static void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
810static void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
811#endif
812RT_C_DECLS_END
813
814#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
815#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
816#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
817#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
818#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
819#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
820
821#if 1
822#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
823#else
824#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)(Lo) )
825#endif
826
827#ifdef IN_RING3
828
829# ifdef LOG_USE_C99
830# define ahciLog(a) \
831 Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
832# else
833# define ahciLog(a) \
834 do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
835# endif
836
837#elif IN_RING0
838
839# ifdef LOG_USE_C99
840# define ahciLog(a) \
841 Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
842# else
843# define ahciLog(a) \
844 do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
845# endif
846
847#elif IN_RC
848
849# ifdef LOG_USE_C99
850# define ahciLog(a) \
851 Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
852# else
853# define ahciLog(a) \
854 do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
855# endif
856
857#endif
858
859/**
860 * Update PCI IRQ levels
861 */
862static void ahciHbaClearInterrupt(PAHCI pAhci)
863{
864 Log(("%s: Clearing interrupt\n", __FUNCTION__));
865 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 0);
866}
867
868/**
869 * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
870 */
871static void ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort)
872{
873 Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
874
875 PDMCritSectEnter(&pAhci->lock, VINF_SUCCESS);
876
877 if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
878 {
879 if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
880 {
881 pAhci->uCccCurrentNr++;
882 if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
883 {
884 /* Reset command completion coalescing state. */
885 TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
886 pAhci->uCccCurrentNr = 0;
887
888 pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
889 if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
890 {
891 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
892 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
893 }
894 }
895 }
896 else
897 {
898 /* If only the bit of the actual port is set assert an interrupt
899 * because the interrupt status register was already read by the guest
900 * and we need to send a new notification.
901 * Otherwise an interrupt is still pending.
902 */
903 ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
904 if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
905 {
906 Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
907 PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
908 }
909 }
910 }
911
912 PDMCritSectLeave(&pAhci->lock);
913}
914
915#ifdef IN_RING3
916/*
917 * Assert irq when an CCC timeout occurs
918 */
919DECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
920{
921 PAHCI pAhci = (PAHCI)pvUser;
922
923 ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr);
924}
925#endif
926
927static int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
928{
929 uint32_t uCIValue;
930
931 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
932
933 /* Update the CI register first. */
934 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
935 pAhciPort->regCI &= ~uCIValue;
936
937
938 if ((pAhciPort->regCMD & AHCI_PORT_CMD_ST) && (u32Value > 0))
939 {
940 PDEVPORTNOTIFIERQUEUEITEM pItem;
941
942 /* Mark the tasks set in the value as used. */
943 for (uint8_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
944 {
945 /* Queue task if bit is set in written value and not already in progress. */
946 if (((u32Value >> i) & 0x01) && !(pAhciPort->regCI & (1 << i)))
947 {
948 if (!pAhciPort->fAsyncInterface)
949 {
950 /* Put the tag number of the task into the FIFO. */
951 uint8_t uTag = AHCI_TASK_SET(i, ((pAhciPort->regSACT & (1 << i)) ? 1 : 0));
952 ASMAtomicWriteU8(&pAhciPort->ahciIOTasks[pAhciPort->uActWritePos], uTag);
953 ahciLog(("%s: Before uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
954 pAhciPort->uActWritePos++;
955 pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
956 ahciLog(("%s: After uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
957
958 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
959
960 bool fNotificationSend = ASMAtomicXchgBool(&pAhciPort->fNotificationSend, true);
961 if (!fNotificationSend)
962 {
963 /* Send new notification. */
964 pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
965 AssertMsg(pItem, ("Allocating item for queue failed\n"));
966
967 pItem->iPort = pAhciPort->iLUN;
968 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
969 }
970 }
971 else
972 {
973 pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
974 AssertMsg(pItem, ("Allocating item for queue failed\n"));
975
976 pItem->iPort = pAhciPort->iLUN;
977 pItem->iTask = i;
978 pItem->fQueued = !!(pAhciPort->regSACT & (1 << i)); /* Mark if the task is queued. */
979 PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
980 }
981 }
982 }
983 }
984
985 pAhciPort->regCI |= u32Value;
986
987 return VINF_SUCCESS;
988}
989
990static int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
991{
992 uint32_t uCIValue = 0;
993
994 uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
995
996 ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
997
998 pAhciPort->regCI &= ~uCIValue;
999
1000 *pu32Value = pAhciPort->regCI;
1001
1002 return VINF_SUCCESS;
1003}
1004
1005static int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1006{
1007 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1008
1009 pAhciPort->regSACT |= u32Value;
1010
1011 return VINF_SUCCESS;
1012}
1013
1014static int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1015{
1016 uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
1017
1018 pAhciPort->regSACT &= ~u32TasksFinished;
1019
1020 ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
1021 __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
1022
1023 *pu32Value = pAhciPort->regSACT;
1024
1025 return VINF_SUCCESS;
1026}
1027
1028static int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1029{
1030 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1031
1032 if ( (u32Value & AHCI_PORT_SERR_X)
1033 && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
1034 {
1035 ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
1036 pAhciPort->regTFD |= ATA_STAT_ERR;
1037 pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
1038 }
1039
1040 pAhciPort->regSERR &= ~u32Value;
1041
1042 return VINF_SUCCESS;
1043}
1044
1045static int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1046{
1047 ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
1048 *pu32Value = pAhciPort->regSERR;
1049 return VINF_SUCCESS;
1050}
1051
1052static int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1053{
1054 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1055 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1056 AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
1057
1058 if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1059 {
1060 ASMAtomicXchgBool(&pAhciPort->fPortReset, true);
1061 pAhciPort->regSSTS = 0;
1062 pAhciPort->regSIG = ~0;
1063 pAhciPort->regTFD = 0x7f;
1064 pAhciPort->fFirstD2HFisSend = false;
1065 }
1066 else if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT && pAhciPort->pDrvBase &&
1067 (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
1068 {
1069#ifndef IN_RING3
1070 return VINF_IOM_HC_MMIO_WRITE;
1071#else
1072 if (pAhciPort->pDrvBase)
1073 {
1074 /* Reset queue. */
1075 pAhciPort->uActWritePos = 0;
1076 pAhciPort->uActReadPos = 0;
1077 ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
1078
1079 /* Signature for SATA device. */
1080 if (pAhciPort->fATAPI)
1081 pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
1082 else
1083 pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
1084
1085 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1086 (0x03 << 0); /* Device detected and communication established. */
1087
1088 /*
1089 * Use the maximum allowed speed.
1090 * (Not that it changes anything really)
1091 */
1092 switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
1093 {
1094 case 0x01:
1095 pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
1096 break;
1097 case 0x02:
1098 case 0x00:
1099 default:
1100 pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
1101 break;
1102 }
1103
1104 /* We received a COMINIT from the device. Tell the guest. */
1105 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
1106 pAhciPort->regSERR |= AHCI_PORT_SERR_X;
1107 pAhciPort->regTFD |= ATA_STAT_BUSY;
1108
1109 if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
1110 {
1111 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1112 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1113
1114 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1115 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
1116 }
1117 }
1118#endif
1119 }
1120
1121 pAhciPort->regSCTL = u32Value;
1122
1123 return VINF_SUCCESS;
1124}
1125
1126static int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1127{
1128 ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
1129 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1130 AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
1131 AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
1132
1133 *pu32Value = pAhciPort->regSCTL;
1134 return VINF_SUCCESS;
1135}
1136
1137static int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1138{
1139 ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
1140 ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
1141 AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
1142 AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
1143
1144 *pu32Value = pAhciPort->regSSTS;
1145 return VINF_SUCCESS;
1146}
1147
1148static int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1149{
1150 ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
1151 *pu32Value = pAhciPort->regSIG;
1152 return VINF_SUCCESS;
1153}
1154
1155static int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1156{
1157 ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
1158 ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
1159 (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
1160 (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
1161 *pu32Value = pAhciPort->regTFD;
1162 return VINF_SUCCESS;
1163}
1164
1165/**
1166 * Read from the port command register.
1167 */
1168static int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1169{
1170 ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD));
1171 ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
1172 __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
1173 (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
1174 (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
1175 (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
1176 (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
1177 (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
1178 (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, (pAhciPort->regCMD & AHCI_PORT_CMD_CCS) >> 8,
1179 (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
1180 (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
1181 (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
1182 *pu32Value = pAhciPort->regCMD;
1183 return VINF_SUCCESS;
1184}
1185
1186/**
1187 * Write to the port command register.
1188 * This is the register where all the data transfer is started
1189 */
1190static int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1191{
1192 int rc = VINF_SUCCESS;
1193 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1194 ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
1195 __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
1196 (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
1197 (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
1198 (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
1199 (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
1200 (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
1201 (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
1202 (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
1203 (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
1204 (u32Value & AHCI_PORT_CMD_ST)));
1205
1206 if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
1207 {
1208 if (u32Value & AHCI_PORT_CMD_CLO)
1209 {
1210 ahciLog(("%s: Command list override requested\n", __FUNCTION__));
1211 u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
1212 /* Clear the CLO bit. */
1213 u32Value &= ~(AHCI_PORT_CMD_CLO);
1214 }
1215
1216 if (u32Value & AHCI_PORT_CMD_ST)
1217 {
1218 ahciLog(("%s: Engine starts\n", __FUNCTION__));
1219
1220 /** Set engine state to running. */
1221 u32Value |= AHCI_PORT_CMD_CR;
1222 }
1223 else
1224 {
1225 ahciLog(("%s: Engine stops\n", __FUNCTION__));
1226 /* Clear command issue register. */
1227 pAhciPort->regCI = 0;
1228 /** Clear current command slot. */
1229 u32Value &= ~(AHCI_PORT_CMD_CCS_SHIFT(0xff));
1230 u32Value &= ~AHCI_PORT_CMD_CR;
1231 }
1232 }
1233 else if (pAhciPort->pDrvBase)
1234 {
1235 if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
1236 {
1237 ahciLog(("%s: Power on the device\n", __FUNCTION__));
1238 pAhciPort->fPoweredOn = true;
1239
1240 /*
1241 * Set states in the Port Signature and SStatus registers.
1242 */
1243 pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
1244 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1245 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1246 (0x03 << 0); /* Device detected and communication established. */
1247
1248 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
1249 {
1250#ifndef IN_RING3
1251 return VINF_IOM_HC_MMIO_WRITE;
1252#else
1253 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1254 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
1255
1256 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
1257 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
1258#endif
1259 }
1260 }
1261
1262 if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
1263 {
1264 ahciLog(("%s: Spin up the device\n", __FUNCTION__));
1265 pAhciPort->fSpunUp = true;
1266 }
1267 }
1268
1269 if (u32Value & AHCI_PORT_CMD_FRE)
1270 {
1271 ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
1272
1273 u32Value |= AHCI_PORT_CMD_FR;
1274
1275 /* Send the first D2H FIS only if it wasn't already send. */
1276 if (!pAhciPort->fFirstD2HFisSend)
1277 {
1278#ifndef IN_RING3
1279 return VINF_IOM_HC_MMIO_WRITE;
1280#else
1281 ahciPostFirstD2HFisIntoMemory(pAhciPort);
1282 pAhciPort->fFirstD2HFisSend = true;
1283#endif
1284 }
1285 }
1286 else if (!(u32Value & AHCI_PORT_CMD_FRE))
1287 {
1288 ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
1289 u32Value &= ~AHCI_PORT_CMD_FR;
1290 }
1291
1292 pAhciPort->regCMD = u32Value;
1293
1294 return rc;
1295}
1296
1297/**
1298 * Read from the port interrupt enable register.
1299 */
1300static int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1301{
1302 ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
1303 ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
1304 __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
1305 (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
1306 (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
1307 (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
1308 (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
1309 (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
1310 (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
1311 (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
1312 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
1313 *pu32Value = pAhciPort->regIE;
1314 return VINF_SUCCESS;
1315}
1316
1317/**
1318 * Write to the port interrupt enable register.
1319 */
1320static int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1321{
1322 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1323 ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
1324 __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
1325 (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
1326 (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
1327 (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
1328 (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
1329 (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
1330 (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
1331 (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
1332 (u32Value & AHCI_PORT_IE_DHRE)));
1333
1334 pAhciPort->regIE = (u32Value & AHCI_PORT_IE_READONLY);
1335
1336 /* Check if some a interrupt status bit changed*/
1337 uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
1338
1339 if (pAhciPort->regIE & u32IntrStatus)
1340 ahciHbaSetInterrupt(ahci, pAhciPort->iLUN);
1341
1342 return VINF_SUCCESS;
1343}
1344
1345/**
1346 * Read from the port interrupt status register.
1347 */
1348static int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1349{
1350 ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
1351 ahciLog(("%s: CPDS=%d TFES=%d HBFS=%d HBDS=%d IFS=%d INFS=%d OFS=%d IPMS=%d PRCS=%d DIS=%d PCS=%d DPS=%d UFS=%d SDBS=%d DSS=%d PSS=%d DHRS=%d\n",
1352 __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
1353 (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
1354 (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
1355 (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
1356 (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
1357 (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
1358 (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
1359 (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
1360 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
1361 *pu32Value = pAhciPort->regIS;
1362 return VINF_SUCCESS;
1363}
1364
1365/**
1366 * Write to the port interrupt status register.
1367 */
1368static int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1369{
1370 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1371 ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
1372
1373 return VINF_SUCCESS;
1374}
1375
1376/**
1377 * Read from the port FIS base address upper 32bit register.
1378 */
1379static int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1380{
1381 ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
1382 *pu32Value = pAhciPort->regFBU;
1383 return VINF_SUCCESS;
1384}
1385
1386/**
1387 * Write to the port FIS base address upper 32bit register.
1388 */
1389static int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1390{
1391 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1392
1393 pAhciPort->regFBU = u32Value;
1394 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1395
1396 return VINF_SUCCESS;
1397}
1398
1399/**
1400 * Read from the port FIS base address register.
1401 */
1402static int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1403{
1404 ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
1405 *pu32Value = pAhciPort->regFB;
1406 return VINF_SUCCESS;
1407}
1408
1409/**
1410 * Write to the port FIS base address register.
1411 */
1412static int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1413{
1414 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1415
1416 pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
1417 pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
1418
1419 return VINF_SUCCESS;
1420}
1421
1422/**
1423 * Write to the port command list base address upper 32bit register.
1424 */
1425static int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1426{
1427 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1428
1429 pAhciPort->regCLBU = u32Value;
1430 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1431
1432 return VINF_SUCCESS;
1433}
1434
1435/**
1436 * Read from the port command list base address upper 32bit register.
1437 */
1438static int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1439{
1440 ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
1441 *pu32Value = pAhciPort->regCLBU;
1442 return VINF_SUCCESS;
1443}
1444
1445/**
1446 * Read from the port command list base address register.
1447 */
1448static int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1449{
1450 ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
1451 *pu32Value = pAhciPort->regCLB;
1452 return VINF_SUCCESS;
1453}
1454
1455/**
1456 * Write to the port command list base address register.
1457 */
1458static int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1459{
1460 ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1461
1462 pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
1463 pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
1464
1465 return VINF_SUCCESS;
1466}
1467
1468/**
1469 * Read from the global Version register.
1470 */
1471static int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1472{
1473 Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
1474 *pu32Value = ahci->regHbaVs;
1475 return VINF_SUCCESS;
1476}
1477
1478/**
1479 * Read from the global Ports implemented register.
1480 */
1481static int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1482{
1483 Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
1484 *pu32Value = ahci->regHbaPi;
1485 return VINF_SUCCESS;
1486}
1487
1488/**
1489 * Write to the global interrupt status register.
1490 */
1491static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1492{
1493 int rc;
1494 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1495
1496 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_MMIO_WRITE);
1497 if (rc != VINF_SUCCESS)
1498 return rc;
1499
1500 if (u32Value > 0)
1501 {
1502 /*
1503 * Clear the interrupt only if no port has signalled
1504 * an interrupt and the guest has cleared all set interrupt
1505 * notification bits.
1506 */
1507 bool fClear = true;
1508
1509 ahci->regHbaIs &= ~(u32Value);
1510
1511 fClear = (!ahci->u32PortsInterrupted) && (!ahci->regHbaIs);
1512 if (fClear)
1513 {
1514 unsigned i = 0;
1515
1516 /* Check if the cleared ports have a interrupt status bit set. */
1517 while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
1518 {
1519 if (u32Value & 0x01)
1520 {
1521 PAHCIPort pAhciPort = &ahci->ahciPort[i];
1522
1523 if (pAhciPort->regIE & pAhciPort->regIS)
1524 {
1525 Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
1526 ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
1527 fClear = false;
1528 break;
1529 }
1530 }
1531 u32Value = u32Value >> 1;
1532 i++;
1533 }
1534 }
1535
1536 if (fClear)
1537 ahciHbaClearInterrupt(ahci);
1538 else
1539 {
1540 Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
1541 /*
1542 * We need to set the interrupt again because the I/O APIC does not set it again even if the
1543 * line is still high.
1544 * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
1545 */
1546 PDMDevHlpPCISetIrqNoWait(ahci->CTX_SUFF(pDevIns), 0, 0);
1547 PDMDevHlpPCISetIrqNoWait(ahci->CTX_SUFF(pDevIns), 0, 1);
1548 }
1549 }
1550
1551 PDMCritSectLeave(&ahci->lock);
1552 return VINF_SUCCESS;
1553}
1554
1555/**
1556 * Read from the global interrupt status register.
1557 */
1558static int HbaInterruptStatus_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1559{
1560 uint32_t u32PortsInterrupted;
1561 int rc;
1562
1563 rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_MMIO_READ);
1564 if (rc != VINF_SUCCESS)
1565 return rc;
1566
1567 u32PortsInterrupted = ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
1568
1569 PDMCritSectLeave(&ahci->lock);
1570 Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
1571
1572 ahci->regHbaIs |= u32PortsInterrupted;
1573
1574#ifdef LOG_ENABLED
1575 Log(("%s:", __FUNCTION__));
1576 unsigned i;
1577 for (i = 0; i < ahci->cPortsImpl; i++)
1578 {
1579 if ((ahci->regHbaIs >> i) & 0x01)
1580 Log((" P%d", i));
1581 }
1582 Log(("\n"));
1583#endif
1584
1585 *pu32Value = ahci->regHbaIs;
1586
1587 return VINF_SUCCESS;
1588}
1589
1590/**
1591 * Write to the global control register.
1592 */
1593static int HbaControl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1594{
1595 Log(("%s: write u32Value=%#010x\n"
1596 "%s: AE=%d IE=%d HR=%d\n",
1597 __FUNCTION__, u32Value,
1598 __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
1599 (u32Value & AHCI_HBA_CTRL_HR)));
1600
1601 ahci->regHbaCtrl = (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE;
1602 if (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)
1603 ahciHBAReset(ahci);
1604 return VINF_SUCCESS;
1605}
1606
1607/**
1608 * Read the global control register.
1609 */
1610static int HbaControl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1611{
1612 Log(("%s: read regHbaCtrl=%#010x\n"
1613 "%s: AE=%d IE=%d HR=%d\n",
1614 __FUNCTION__, ahci->regHbaCtrl,
1615 __FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
1616 (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)));
1617 *pu32Value = ahci->regHbaCtrl;
1618 return VINF_SUCCESS;
1619}
1620
1621/**
1622 * Read the global capabilities register.
1623 */
1624static int HbaCapabilities_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1625{
1626 Log(("%s: read regHbaCap=%#010x\n"
1627 "%s: S64A=%d SNCQ=%d SIS=%d SSS=%d SALP=%d SAL=%d SCLO=%d ISS=%d SNZO=%d SAM=%d SPM=%d PMD=%d SSC=%d PSC=%d NCS=%d NP=%d\n",
1628 __FUNCTION__, ahci->regHbaCap,
1629 __FUNCTION__, (ahci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (ahci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
1630 (ahci->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (ahci->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
1631 (ahci->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (ahci->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
1632 (ahci->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (ahci->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
1633 (ahci->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (ahci->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
1634 (ahci->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (ahci->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
1635 (ahci->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (ahci->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
1636 (ahci->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (ahci->regHbaCap & AHCI_HBA_CAP_NP)));
1637 *pu32Value = ahci->regHbaCap;
1638 return VINF_SUCCESS;
1639}
1640
1641/**
1642 * Write to the global command completion coalescing control register.
1643 */
1644static int HbaCccCtl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1645{
1646 Log(("%s: write u32Value=%#010x\n"
1647 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1648 __FUNCTION__, u32Value,
1649 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
1650 AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
1651
1652 ahci->regHbaCccCtl = u32Value;
1653 ahci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
1654 ahci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
1655 ahci->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
1656
1657 if (u32Value & AHCI_HBA_CCC_CTL_EN)
1658 {
1659 /* Arm the timer */
1660 TMTimerSetMillies(ahci->CTX_SUFF(pHbaCccTimer), ahci->uCccTimeout);
1661 }
1662 else
1663 {
1664 TMTimerStop(ahci->CTX_SUFF(pHbaCccTimer));
1665 }
1666
1667 return VINF_SUCCESS;
1668}
1669
1670/**
1671 * Read the global command completion coalescing control register.
1672 */
1673static int HbaCccCtl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1674{
1675 Log(("%s: read regHbaCccCtl=%#010x\n"
1676 "%s: TV=%d CC=%d INT=%d EN=%d\n",
1677 __FUNCTION__, ahci->regHbaCccCtl,
1678 __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(ahci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(ahci->regHbaCccCtl),
1679 AHCI_HBA_CCC_CTL_INT_GET(ahci->regHbaCccCtl), (ahci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
1680 *pu32Value = ahci->regHbaCccCtl;
1681 return VINF_SUCCESS;
1682}
1683
1684/**
1685 * Write to the global command completion coalescing ports register.
1686 */
1687static int HbaCccPorts_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1688{
1689 Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
1690
1691 ahci->regHbaCccPorts = u32Value;
1692
1693 return VINF_SUCCESS;
1694}
1695
1696/**
1697 * Read the global command completion coalescing ports register.
1698 */
1699static int HbaCccPorts_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
1700{
1701 Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, ahci->regHbaCccPorts));
1702
1703#ifdef LOG_ENABLED
1704 Log(("%s:", __FUNCTION__));
1705 unsigned i;
1706 for (i = 0; i < ahci->cPortsImpl; i++)
1707 {
1708 if ((ahci->regHbaCccPorts >> i) & 0x01)
1709 Log((" P%d", i));
1710 }
1711 Log(("\n"));
1712#endif
1713
1714 *pu32Value = ahci->regHbaCccPorts;
1715 return VINF_SUCCESS;
1716}
1717
1718/**
1719 * Invalid write to global register
1720 */
1721static int HbaInvalid_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
1722{
1723 Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1724 return VINF_SUCCESS;
1725}
1726
1727/**
1728 * Invalid Port write.
1729 */
1730static int PortInvalid_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
1731{
1732 ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
1733 return VINF_SUCCESS;
1734}
1735
1736/**
1737 * Invalid Port read.
1738 */
1739static int PortInvalid_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
1740{
1741 ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
1742 return VINF_SUCCESS;
1743}
1744
1745/**
1746 * Register descriptor table for global HBA registers
1747 */
1748static const AHCIOPREG g_aOpRegs[] =
1749{
1750 {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
1751 {"HbaControl" , HbaControl_r, HbaControl_w},
1752 {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
1753 {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
1754 {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
1755 {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
1756 {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
1757};
1758
1759/**
1760 * Register descriptor table for port registers
1761 */
1762static const AHCIPORTOPREG g_aPortOpRegs[] =
1763{
1764 {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
1765 {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
1766 {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
1767 {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
1768 {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
1769 {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
1770 {"PortCmd", PortCmd_r, PortCmd_w},
1771 {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
1772 {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
1773 {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
1774 {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
1775 {"PortSControl", PortSControl_r, PortSControl_w},
1776 {"PortSError", PortSError_r, PortSError_w},
1777 {"PortSActive", PortSActive_r, PortSActive_w},
1778 {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
1779 {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
1780};
1781
1782/**
1783 * Reset initiated by system software for one port.
1784 *
1785 * @param pAhciPort The port to reset.
1786 */
1787static void ahciPortSwReset(PAHCIPort pAhciPort)
1788{
1789 pAhciPort->regIS = 0;
1790 pAhciPort->regIE = 0;
1791 pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
1792 AHCI_PORT_CMD_SUD | /* Device has spun up. */
1793 AHCI_PORT_CMD_POD; /* Port is powered on. */
1794 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
1795 pAhciPort->regSIG = ~0;
1796 pAhciPort->regSSTS = 0;
1797 pAhciPort->regSCTL = 0;
1798 pAhciPort->regSERR = 0;
1799 pAhciPort->regSACT = 0;
1800 pAhciPort->regCI = 0;
1801
1802 pAhciPort->fResetDevice = false;
1803 pAhciPort->fPoweredOn = true;
1804 pAhciPort->fSpunUp = true;
1805 pAhciPort->fNotificationSend = false;
1806 pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
1807 pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
1808
1809 pAhciPort->u32TasksFinished = 0;
1810 pAhciPort->u32QueuedTasksFinished = 0;
1811
1812 pAhciPort->uActWritePos = 0;
1813 pAhciPort->uActReadPos = 0;
1814 pAhciPort->uActTasksActive = 0;
1815
1816 if (pAhciPort->pDrvBase)
1817 {
1818 pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
1819
1820 if (pAhciPort->fPoweredOn)
1821 {
1822 /*
1823 * Set states in the Port Signature and SStatus registers.
1824 */
1825 pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
1826 pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
1827 (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
1828 (0x03 << 0); /* Device detected and communication established. */
1829 }
1830 }
1831}
1832
1833#ifdef IN_RING3
1834/**
1835 * Hardware reset used for machine power on and reset.
1836 *
1837 * @param pAhciport The port to reset.
1838 */
1839static void ahciPortHwReset(PAHCIPort pAhciPort)
1840{
1841 /* Reset the address registers. */
1842 pAhciPort->regCLB = 0;
1843 pAhciPort->regCLBU = 0;
1844 pAhciPort->regFB = 0;
1845 pAhciPort->regFBU = 0;
1846
1847 /* Reset calculated addresses. */
1848 pAhciPort->GCPhysAddrClb = 0;
1849 pAhciPort->GCPhysAddrFb = 0;
1850}
1851#endif
1852
1853/**
1854 * Create implemented ports bitmap.
1855 *
1856 * @returns 32bit bitmask with a bit set for every implemented port.
1857 * @param cPorts Number of ports.
1858 */
1859static uint32_t ahciGetPortsImplemented(unsigned cPorts)
1860{
1861 uint32_t uPortsImplemented = 0;
1862
1863 for (unsigned i = 0; i < cPorts; i++)
1864 uPortsImplemented |= (1 << i);
1865
1866 return uPortsImplemented;
1867}
1868
1869/**
1870 * Reset the entire HBA.
1871 *
1872 * @param pThis The HBA state.
1873 */
1874static void ahciHBAReset(PAHCI pThis)
1875{
1876 unsigned i;
1877 int rc = VINF_SUCCESS;
1878
1879 LogFlow(("Reset the HBA controller\n"));
1880
1881 /* Stop the CCC timer. */
1882 if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
1883 {
1884 rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
1885 if (RT_FAILURE(rc))
1886 AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
1887 }
1888
1889 /* Reset every port */
1890 for (i = 0; i < pThis->cPortsImpl; i++)
1891 {
1892 PAHCIPort pAhciPort = &pThis->ahciPort[i];
1893
1894 pAhciPort->iLUN = i;
1895 ahciPortSwReset(pAhciPort);
1896 }
1897
1898 /* Init Global registers */
1899 pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
1900 AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
1901 AHCI_HBA_CAP_SAM | /* AHCI mode only */
1902 AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
1903 AHCI_HBA_CAP_SSS | /* Staggered spin up */
1904 AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
1905 AHCI_HBA_CAP_NCS_SET(AHCI_NR_COMMAND_SLOTS) | /* Number of command slots we support */
1906 AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
1907 pThis->regHbaCtrl = AHCI_HBA_CTRL_AE;
1908 pThis->regHbaIs = 0;
1909 pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
1910 pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
1911 pThis->regHbaCccCtl = 0;
1912 pThis->regHbaCccPorts = 0;
1913 pThis->uCccTimeout = 0;
1914 pThis->uCccPortNr = 0;
1915 pThis->uCccNr = 0;
1916
1917 pThis->f64BitAddr = false;
1918 pThis->u32PortsInterrupted = 0;
1919 pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
1920 /* Clear the HBA Reset bit */
1921 pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
1922}
1923
1924/**
1925 * Memory mapped I/O Handler for read operations.
1926 *
1927 * @returns VBox status code.
1928 *
1929 * @param pDevIns The device instance.
1930 * @param pvUser User argument.
1931 * @param GCPhysAddr Physical address (in GC) where the read starts.
1932 * @param pv Where to store the result.
1933 * @param cb Number of bytes read.
1934 */
1935PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1936{
1937 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
1938 int rc = VINF_SUCCESS;
1939
1940 /* Break up 64 bits reads into two dword reads. */
1941 if (cb == 8)
1942 {
1943 rc = ahciMMIORead(pDevIns, pvUser, GCPhysAddr, pv, 4);
1944 if (RT_FAILURE(rc))
1945 return rc;
1946
1947 return ahciMMIORead(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
1948 }
1949
1950 Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
1951 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
1952
1953 /*
1954 * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
1955 * Otherwise it accesses the registers of a port.
1956 */
1957 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
1958 uint32_t iReg;
1959
1960 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
1961 {
1962 iReg = uOffset >> 2;
1963 Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
1964 if (iReg < RT_ELEMENTS(g_aOpRegs))
1965 {
1966 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
1967 rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
1968 }
1969 else
1970 {
1971 Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
1972 *(uint32_t *)pv = 0;
1973 }
1974 }
1975 else
1976 {
1977 uint32_t iRegOffset;
1978 uint32_t iPort;
1979
1980 /* Calculate accessed port. */
1981 uOffset -= AHCI_HBA_GLOBAL_SIZE;
1982 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
1983 iRegOffset = (uOffset % AHCI_PORT_REGISTER_SIZE);
1984 iReg = iRegOffset >> 2;
1985
1986 Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
1987
1988 if (RT_LIKELY( iPort < pAhci->cPortsImpl
1989 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
1990 {
1991 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
1992 rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
1993 }
1994 else
1995 {
1996 Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
1997 rc = VINF_IOM_MMIO_UNUSED_00;
1998 }
1999
2000 /*
2001 * Windows Vista tries to read one byte from some registers instead of four.
2002 * Correct the value according to the read size.
2003 */
2004 if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
2005 {
2006 switch (cb)
2007 {
2008 case 1:
2009 {
2010 uint8_t uNewValue;
2011 uint8_t *p = (uint8_t *)pv;
2012
2013 iRegOffset &= 3;
2014 Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
2015 uNewValue = p[iRegOffset];
2016 /* Clear old value */
2017 *(uint32_t *)pv = 0;
2018 *(uint8_t *)pv = uNewValue;
2019 break;
2020 }
2021 default:
2022 AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
2023 }
2024 }
2025 }
2026
2027 Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
2028 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
2029 return rc;
2030}
2031
2032
2033/**
2034 * Memory mapped I/O Handler for write operations.
2035 *
2036 * @returns VBox status code.
2037 *
2038 * @param pDevIns The device instance.
2039 * @param pvUser User argument.
2040 * @param GCPhysAddr Physical address (in GC) where the read starts.
2041 * @param pv Where to fetch the result.
2042 * @param cb Number of bytes to write.
2043 */
2044PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
2045{
2046 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2047 int rc = VINF_SUCCESS;
2048
2049 /* Break up 64 bits writes into two dword writes. */
2050 if (cb == 8)
2051 {
2052 /*
2053 * Only write the first 4 bytes if they weren't already.
2054 * It is possible that the last write to the register caused a world
2055 * switch and we entered this function again.
2056 * Writing the first 4 bytes again could cause indeterminate behavior
2057 * which can cause errors in the guest.
2058 */
2059 if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
2060 {
2061 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
2062 if (rc != VINF_SUCCESS)
2063 return rc;
2064
2065 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
2066 }
2067
2068 rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
2069 /*
2070 * Reset flag again so that the first 4 bytes are written again on the next
2071 * 8byte MMIO access.
2072 */
2073 if (rc == VINF_SUCCESS)
2074 pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
2075
2076 return rc;
2077 }
2078
2079 Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
2080 pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
2081
2082 /* Validate access. */
2083 if (cb != sizeof(uint32_t))
2084 {
2085 Log2(("%s: Bad write size!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2086 return VINF_SUCCESS;
2087 }
2088 if (GCPhysAddr & 0x3)
2089 {
2090 Log2(("%s: Unaligned write!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
2091 return VINF_SUCCESS;
2092 }
2093
2094 /*
2095 * If the access offset is smaller than 100h the guest accesses the global registers.
2096 * Otherwise it accesses the registers of a port.
2097 */
2098 uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
2099 uint32_t iReg;
2100 if (uOffset < AHCI_HBA_GLOBAL_SIZE)
2101 {
2102 Log3(("Write global HBA register\n"));
2103 iReg = uOffset >> 2;
2104 if (iReg < RT_ELEMENTS(g_aOpRegs))
2105 {
2106 const AHCIOPREG *pReg = &g_aOpRegs[iReg];
2107 rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
2108 }
2109 else
2110 {
2111 Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
2112 rc = VINF_SUCCESS;
2113 }
2114 }
2115 else
2116 {
2117 uint32_t iPort;
2118 Log3(("Write Port register\n"));
2119 /* Calculate accessed port. */
2120 uOffset -= AHCI_HBA_GLOBAL_SIZE;
2121 iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
2122 iReg = (uOffset % AHCI_PORT_REGISTER_SIZE) >> 2;
2123 Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
2124 if (RT_LIKELY( iPort < pAhci->cPortsImpl
2125 && iReg < RT_ELEMENTS(g_aPortOpRegs)))
2126 {
2127 const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
2128 rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
2129 }
2130 else
2131 {
2132 Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
2133 rc = VINF_SUCCESS;
2134 }
2135 }
2136
2137 return rc;
2138}
2139
2140PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2141{
2142 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2143 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2144 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2145
2146 Assert(iChannel < 2);
2147
2148 return ataControllerIOPortWrite1(pCtl, Port, u32, cb);
2149}
2150
2151PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2152{
2153 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2154 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2155 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2156
2157 Assert(iChannel < 2);
2158
2159 return ataControllerIOPortRead1(pCtl, Port, pu32, cb);
2160}
2161
2162PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2163{
2164 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2165 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2166 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2167
2168 Assert(iChannel < 2);
2169
2170 return ataControllerIOPortWrite2(pCtl, Port, u32, cb);
2171}
2172
2173PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2174{
2175 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2176 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2177 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2178
2179 Assert(iChannel < 2);
2180
2181 return ataControllerIOPortRead2(pCtl, Port, pu32, cb);
2182}
2183
2184PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2185{
2186 AssertMsgFailed(("Should not happen\n"));
2187 return VINF_SUCCESS;
2188}
2189
2190PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2191{
2192 AssertMsgFailed(("Should not happen\n"));
2193 return VINF_SUCCESS;
2194}
2195
2196#ifndef IN_RING0
2197/**
2198 * Port I/O Handler for primary port range IN string operations.
2199 * @see FNIOMIOPORTINSTRING for details.
2200 */
2201PDMBOTHCBDECL(int) ahciIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
2202{
2203 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2204 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2205 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2206
2207 Assert(iChannel < 2);
2208
2209 return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrDst, pcTransfer, cb);
2210}
2211
2212
2213/**
2214 * Port I/O Handler for primary port range OUT string operations.
2215 * @see FNIOMIOPORTOUTSTRING for details.
2216 */
2217PDMBOTHCBDECL(int) ahciIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
2218{
2219 uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
2220 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2221 PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
2222
2223 Assert(iChannel < 2);
2224
2225 return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrSrc, pcTransfer, cb);
2226}
2227#endif /* !IN_RING0 */
2228
2229#ifdef IN_RING3
2230
2231static DECLCALLBACK(int) ahciMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2232{
2233 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2234 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2235 int rc = VINF_SUCCESS;
2236
2237 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2238
2239 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
2240 Assert(cb >= 4352);
2241
2242 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2243 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
2244 ahciMMIOWrite, ahciMMIORead, NULL, "AHCI");
2245 if (RT_FAILURE(rc))
2246 return rc;
2247
2248 if (pThis->fR0Enabled)
2249 {
2250 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
2251 "ahciMMIOWrite", "ahciMMIORead", NULL);
2252 if (RT_FAILURE(rc))
2253 return rc;
2254 }
2255
2256 if (pThis->fGCEnabled)
2257 {
2258 rc = PDMDevHlpMMIORegisterGC(pDevIns, GCPhysAddress, cb, 0,
2259 "ahciMMIOWrite", "ahciMMIORead", NULL);
2260 if (RT_FAILURE(rc))
2261 return rc;
2262 }
2263
2264 pThis->MMIOBase = GCPhysAddress;
2265 return rc;
2266}
2267
2268/**
2269 * Map the legacy I/O port ranges to make Solaris work with the controller.
2270 */
2271static DECLCALLBACK(int) ahciLegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2272{
2273 PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
2274 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2275 int rc = VINF_SUCCESS;
2276
2277 Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
2278
2279 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2280
2281 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
2282 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
2283 ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
2284 if (RT_FAILURE(rc))
2285 return rc;
2286
2287 if (pThis->fR0Enabled)
2288 {
2289 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2290 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2291 if (RT_FAILURE(rc))
2292 return rc;
2293 }
2294
2295 if (pThis->fGCEnabled)
2296 {
2297 rc = PDMDevHlpIOPortRegisterGC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
2298 "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
2299 if (RT_FAILURE(rc))
2300 return rc;
2301 }
2302
2303 return rc;
2304}
2305
2306/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
2307
2308/**
2309 * Gets the pointer to the status LED of a unit.
2310 *
2311 * @returns VBox status code.
2312 * @param pInterface Pointer to the interface structure containing the called function pointer.
2313 * @param iLUN The unit which status LED we desire.
2314 * @param ppLed Where to store the LED pointer.
2315 */
2316static DECLCALLBACK(int) ahciStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2317{
2318 PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
2319 if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
2320 {
2321 *ppLed = &pAhci->ahciPort[iLUN].Led;
2322 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2323 return VINF_SUCCESS;
2324 }
2325 return VERR_PDM_LUN_NOT_FOUND;
2326}
2327
2328/**
2329 * Queries an interface to the driver.
2330 *
2331 * @returns Pointer to interface.
2332 * @returns NULL if the interface was not supported by the device.
2333 * @param pInterface Pointer to ATADevState::IBase.
2334 * @param enmInterface The requested interface identification.
2335 */
2336static DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2337{
2338 PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
2339 switch (enmInterface)
2340 {
2341 case PDMINTERFACE_BASE:
2342 return &pAhci->IBase;
2343 case PDMINTERFACE_LED_PORTS:
2344 return &pAhci->ILeds;
2345 default:
2346 return NULL;
2347 }
2348}
2349
2350/**
2351 * Query interface method for the AHCI port.
2352 */
2353static DECLCALLBACK(void *) ahciPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2354{
2355 PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2356 switch (enmInterface)
2357 {
2358 case PDMINTERFACE_BASE:
2359 return &pAhciPort->IBase;
2360 case PDMINTERFACE_BLOCK_PORT:
2361 return &pAhciPort->IPort;
2362 case PDMINTERFACE_BLOCK_ASYNC_PORT:
2363 return &pAhciPort->IPortAsync;
2364 case PDMINTERFACE_MOUNT_NOTIFY:
2365 return &pAhciPort->IMountNotify;
2366 default:
2367 return NULL;
2368 }
2369}
2370
2371static DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2372{
2373 uint32_t i;
2374 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
2375
2376 pAhci->pDevInsRC += offDelta;
2377 pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
2378 pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
2379
2380 /* Relocate every port. */
2381 for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
2382 {
2383 PAHCIPort pAhciPort = &pAhci->ahciPort[i];
2384 pAhciPort->pAhciRC += offDelta;
2385 pAhciPort->pDevInsRC += offDelta;
2386 }
2387
2388 /* Relocate emulated ATA controllers. */
2389 for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
2390 ataControllerRelocate(&pAhci->aCts[i], offDelta);
2391}
2392
2393#ifdef DEBUG
2394
2395/**
2396 * Dump info about the FIS
2397 *
2398 * @returns nothing
2399 * @param pAhciPort The port the command FIS was read from.
2400 * @param cmdFis The FIS to print info from.
2401 */
2402static void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
2403{
2404 ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
2405 /* Print FIS type. */
2406 switch (cmdFis[AHCI_CMDFIS_TYPE])
2407 {
2408 case AHCI_CMDFIS_TYPE_H2D:
2409 {
2410 ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
2411 ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
2412 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
2413 {
2414 ahciLog(("%s: Command register update\n", __FUNCTION__));
2415 }
2416 else
2417 {
2418 ahciLog(("%s: Control register update\n", __FUNCTION__));
2419 }
2420 ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
2421 ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
2422 ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
2423 ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
2424 ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
2425 ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
2426
2427 ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
2428 ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
2429 ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
2430 ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
2431
2432 ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
2433 ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
2434 ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
2435 if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
2436 {
2437 ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
2438 }
2439 }
2440 break;
2441 case AHCI_CMDFIS_TYPE_D2H:
2442 {
2443 ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
2444 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
2445 }
2446 break;
2447 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2448 {
2449 ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
2450 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
2451 }
2452 break;
2453 case AHCI_CMDFIS_TYPE_DMAACTD2H:
2454 {
2455 ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
2456 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
2457 }
2458 break;
2459 case AHCI_CMDFIS_TYPE_DMASETUP:
2460 {
2461 ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
2462 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
2463 }
2464 break;
2465 case AHCI_CMDFIS_TYPE_PIOSETUP:
2466 {
2467 ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
2468 ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
2469 }
2470 break;
2471 case AHCI_CMDFIS_TYPE_DATA:
2472 {
2473 ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
2474 }
2475 break;
2476 default:
2477 ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
2478 break;
2479 }
2480 ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
2481}
2482
2483/**
2484 * Dump info about the command header
2485 *
2486 * @returns nothing
2487 * @param pAhciPort Poitner to the port the command header was read from.
2488 * @param pCmdHdr The command header to print info from.
2489 */
2490static void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
2491{
2492 ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
2493 ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
2494 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
2495 ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
2496 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
2497 ahciLog(("%s: BIST Fis\n", __FUNCTION__));
2498 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
2499 ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
2500 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
2501 ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
2502 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
2503 ahciLog(("%s: Device write\n", __FUNCTION__));
2504 else
2505 ahciLog(("%s: Device read\n", __FUNCTION__));
2506 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
2507 ahciLog(("%s: ATAPI command\n", __FUNCTION__));
2508 else
2509 ahciLog(("%s: ATA command\n", __FUNCTION__));
2510
2511 ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
2512 ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
2513}
2514#endif /* DEBUG */
2515
2516/**
2517 * Post the first D2H FIS from the device into guest memory.
2518 *
2519 * @returns nothing
2520 * @param pAhciPort Pointer to the port which "receives" the FIS.
2521 */
2522static void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
2523{
2524 uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
2525
2526 pAhciPort->fFirstD2HFisSend = true;
2527
2528 ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
2529 memset(&d2hFis[0], 0, sizeof(d2hFis));
2530 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
2531 d2hFis[AHCI_CMDFIS_ERR] = 0x01;
2532
2533 d2hFis[AHCI_CMDFIS_STS] = 0x00;
2534
2535 /* Set the signature based on the device type. */
2536 if (pAhciPort->fATAPI)
2537 {
2538 d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
2539 d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
2540 }
2541 else
2542 {
2543 d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
2544 d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
2545 }
2546
2547 d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
2548 d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
2549 d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
2550
2551 pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
2552
2553 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
2554}
2555
2556/**
2557 * Post the FIS in the memory area allocated by the guest and set interrupt if neccessary.
2558 *
2559 * @returns VBox status code
2560 * @param pAhciPort The port which "receives" the FIS.
2561 * @param uFisType The type of the FIS.
2562 * @param pCmdFis Pointer to the FIS which is to be posted into memory.
2563 */
2564static int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
2565{
2566 int rc = VINF_SUCCESS;
2567 RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
2568 unsigned cbFis = 0;
2569
2570 ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
2571
2572 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
2573 {
2574 AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
2575
2576 /* Determine the offset and size of the FIS based on uFisType. */
2577 switch (uFisType)
2578 {
2579 case AHCI_CMDFIS_TYPE_D2H:
2580 {
2581 GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
2582 cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
2583 }
2584 break;
2585 case AHCI_CMDFIS_TYPE_SETDEVBITS:
2586 {
2587 GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
2588 cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
2589 }
2590 break;
2591 case AHCI_CMDFIS_TYPE_DMASETUP:
2592 {
2593 GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
2594 cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
2595 }
2596 break;
2597 case AHCI_CMDFIS_TYPE_PIOSETUP:
2598 {
2599 GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
2600 cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
2601 }
2602 break;
2603 default:
2604 /*
2605 * We should post the unknown FIS into memory too but this never happens because
2606 * we know which FIS types we generate. ;)
2607 */
2608 AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
2609 }
2610
2611 /* Post the FIS into memory. */
2612 ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
2613 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
2614 }
2615
2616 return rc;
2617}
2618
2619DECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
2620{
2621 pbBuf[0] = val >> 8;
2622 pbBuf[1] = val;
2623}
2624
2625
2626DECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
2627{
2628 pbBuf[0] = val >> 16;
2629 pbBuf[1] = val >> 8;
2630 pbBuf[2] = val;
2631}
2632
2633
2634DECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
2635{
2636 pbBuf[0] = val >> 24;
2637 pbBuf[1] = val >> 16;
2638 pbBuf[2] = val >> 8;
2639 pbBuf[3] = val;
2640}
2641
2642
2643DECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
2644{
2645 return (pbBuf[0] << 8) | pbBuf[1];
2646}
2647
2648
2649DECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
2650{
2651 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2652}
2653
2654
2655DECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
2656{
2657 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
2658}
2659
2660
2661DECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
2662{
2663 iATAPILBA += 150;
2664 pbBuf[0] = (iATAPILBA / 75) / 60;
2665 pbBuf[1] = (iATAPILBA / 75) % 60;
2666 pbBuf[2] = iATAPILBA % 75;
2667}
2668
2669
2670DECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
2671{
2672 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
2673}
2674
2675static void atapiCmdOK(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
2676{
2677 pAhciPortTaskState->uATARegError = 0;
2678 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
2679 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
2680 | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
2681 | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
2682 pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
2683 pAhciPort->uATAPIASC = SCSI_ASC_NONE;
2684}
2685
2686
2687static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
2688{
2689 pAhciPortTaskState->uATARegError = uATAPISenseKey << 4;
2690 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
2691 pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
2692 ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
2693 pAhciPort->uATAPISenseKey = uATAPISenseKey;
2694 pAhciPort->uATAPIASC = uATAPIASC;
2695}
2696
2697static void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2698{
2699 for (uint32_t i = 0; i < cbSize; i++)
2700 {
2701 if (*pbSrc)
2702 pbDst[i] = *pbSrc++;
2703 else
2704 pbDst[i] = ' ';
2705 }
2706}
2707
2708static void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2709{
2710 for (uint32_t i = 0; i < cbSize; i++)
2711 {
2712 if (*pbSrc)
2713 pbDst[i ^ 1] = *pbSrc++;
2714 else
2715 pbDst[i ^ 1] = ' ';
2716 }
2717}
2718
2719static int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
2720{
2721 uint16_t *p;
2722 int rc = VINF_SUCCESS;
2723
2724 p = (uint16_t *)pvBuf;
2725 memset(p, 0, 512);
2726 p[0] = RT_H2LE_U16(0x0040);
2727 p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2728 p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2729 /* Block size; obsolete, but required for the BIOS. */
2730 p[5] = RT_H2LE_U16(512);
2731 p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2732 ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
2733 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2734 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2735 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
2736 ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
2737 ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
2738#if ATA_MAX_MULT_SECTORS > 1
2739 p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
2740#endif
2741 p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
2742 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2743 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2744 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2745 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2746 p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
2747 p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
2748 p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
2749 p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
2750 p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
2751 p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
2752 if (pAhciPort->cMultSectors)
2753 p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
2754 if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
2755 {
2756 p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2757 p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2758 }
2759 else
2760 {
2761 /* Report maximum number of sectors possible with LBA28 */
2762 p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
2763 p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
2764 }
2765 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2766 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2767 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2768 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2769 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2770 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2771 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2772 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2773 p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
2774 p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2775 p[84] = RT_H2LE_U16(1 << 14);
2776 p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
2777 p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
2778 p[87] = RT_H2LE_U16(1 << 14);
2779 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2780 p[93] = RT_H2LE_U16(0x00);
2781 p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
2782 p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
2783 p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
2784 p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
2785
2786 /* The following are SATA specific */
2787 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2788 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2789
2790 return VINF_SUCCESS;
2791}
2792
2793typedef int (*PAtapiFunc)(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2794
2795static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2796static int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2797static int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2798static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2799static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2800static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2801static int atapiReadCapacitySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2802static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2803static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2804static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2805static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2806static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2807static int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2808//static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
2809
2810/**
2811 * Source/sink function indexes for g_apfnAtapiFuncs.
2812 */
2813typedef enum ATAPIFN
2814{
2815 ATAFN_SS_NULL = 0,
2816 ATAFN_SS_ATAPI_GET_CONFIGURATION,
2817 ATAFN_SS_ATAPI_IDENTIFY,
2818 ATAFN_SS_ATAPI_INQUIRY,
2819 ATAFN_SS_ATAPI_MECHANISM_STATUS,
2820 ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
2821 ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
2822 ATAFN_SS_ATAPI_READ_CAPACITY,
2823 ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
2824 ATAFN_SS_ATAPI_READ_TOC_NORMAL,
2825 ATAFN_SS_ATAPI_READ_TOC_MULTI,
2826 ATAFN_SS_ATAPI_READ_TOC_RAW,
2827 ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
2828 ATAFN_SS_ATAPI_REQUEST_SENSE,
2829 //ATAFN_SS_ATAPI_PASSTHROUGH,
2830 ATAFN_SS_MAX
2831} ATAPIFN;
2832
2833/**
2834 * Array of source/sink functions, the index is ATAFNSS.
2835 * Make sure ATAFNSS and this array match!
2836 */
2837static const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
2838{
2839 NULL,
2840 atapiGetConfigurationSS,
2841 atapiIdentifySS,
2842 atapiInquirySS,
2843 atapiMechanismStatusSS,
2844 atapiModeSenseErrorRecoverySS,
2845 atapiModeSenseCDStatusSS,
2846 atapiReadCapacitySS,
2847 atapiReadDiscInformationSS,
2848 atapiReadTOCNormalSS,
2849 atapiReadTOCMultiSS,
2850 atapiReadTOCRawSS,
2851 atapiReadTrackInformationSS,
2852 atapiRequestSenseSS
2853 //atapiPassthroughSS
2854};
2855
2856static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2857{
2858 uint16_t p[256];
2859 char aSerial[20];
2860 RTUUID Uuid;
2861 int rc;
2862
2863 rc = pAhciPort->pDrvBlock ? pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
2864 if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
2865 {
2866 /* Generate a predictable serial for drives which don't have a UUID. */
2867 RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-1a2b3c4d",
2868 pAhciPort->iLUN);
2869 }
2870 else
2871 RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
2872
2873 memset(p, 0, 512);
2874 /* Removable CDROM, 50us response, 12 byte packets */
2875 p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
2876 ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
2877 p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
2878 p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
2879 ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
2880 ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
2881 p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
2882 p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
2883 p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
2884 p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
2885 p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
2886 p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
2887 p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
2888 p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
2889 p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
2890 p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
2891 p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
2892 p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
2893 p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
2894 p[75] = RT_H2LE_U16(1); /* queue depth 1 */
2895 p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
2896 p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
2897 p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
2898 p[83] = RT_H2LE_U16(1 << 14);
2899 p[84] = RT_H2LE_U16(1 << 14);
2900 p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
2901 p[86] = RT_H2LE_U16(0);
2902 p[87] = RT_H2LE_U16(1 << 14);
2903 p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
2904 p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
2905
2906 /* The following are SATA specific */
2907 p[75] = RT_H2LE_U16(31); /* We support 32 commands */
2908 p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
2909
2910 /* Copy the buffer in to the scatter gather list. */
2911 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
2912 *pcbData = sizeof(p);
2913
2914 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2915 return VINF_SUCCESS;
2916}
2917
2918static int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2919{
2920 uint8_t aBuf[8];
2921
2922 ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
2923 ataH2BE_U32(aBuf + 4, 2048);
2924
2925 /* Copy the buffer in to the scatter gather list. */
2926 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2927 *pcbData = sizeof(aBuf);
2928
2929 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2930 return VINF_SUCCESS;
2931}
2932
2933
2934static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2935{
2936 uint8_t aBuf[34];
2937
2938 memset(aBuf, '\0', 34);
2939 ataH2BE_U16(aBuf, 32);
2940 aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
2941 aBuf[3] = 1; /* number of first track */
2942 aBuf[4] = 1; /* number of sessions (LSB) */
2943 aBuf[5] = 1; /* first track number in last session (LSB) */
2944 aBuf[6] = 1; /* last track number in last session (LSB) */
2945 aBuf[7] = (0 << 7) | (0 << 6) | (1 << 5) | (0 << 2) | (0 << 0); /* disc id not valid, disc bar code not valid, unrestricted use, not dirty, not RW medium */
2946 aBuf[8] = 0; /* disc type = CD-ROM */
2947 aBuf[9] = 0; /* number of sessions (MSB) */
2948 aBuf[10] = 0; /* number of sessions (MSB) */
2949 aBuf[11] = 0; /* number of sessions (MSB) */
2950 ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
2951 ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
2952
2953 /* Copy the buffer in to the scatter gather list. */
2954 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2955 *pcbData = sizeof(aBuf);
2956
2957 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2958 return VINF_SUCCESS;
2959}
2960
2961
2962static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2963{
2964 uint8_t aBuf[36];
2965
2966 /* Accept address/number type of 1 only, and only track 1 exists. */
2967 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
2968 {
2969 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2970 return VINF_SUCCESS;
2971 }
2972 memset(aBuf, '\0', 36);
2973 ataH2BE_U16(aBuf, 34);
2974 aBuf[2] = 1; /* track number (LSB) */
2975 aBuf[3] = 1; /* session number (LSB) */
2976 aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
2977 aBuf[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
2978 aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
2979 ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
2980 ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
2981 aBuf[32] = 0; /* track number (MSB) */
2982 aBuf[33] = 0; /* session number (MSB) */
2983
2984 /* Copy the buffer in to the scatter gather list. */
2985 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
2986 *pcbData = sizeof(aBuf);
2987
2988 atapiCmdOK(pAhciPort, pAhciPortTaskState);
2989 return VINF_SUCCESS;
2990}
2991
2992
2993static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
2994{
2995 uint8_t aBuf[32];
2996
2997 /* Accept valid request types only, and only starting feature 0. */
2998 if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
2999 {
3000 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3001 return VINF_SUCCESS;
3002 }
3003 memset(aBuf, '\0', 32);
3004 ataH2BE_U32(aBuf, 16);
3005 /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
3006 * way to differentiate them right now is based on the image size). Also
3007 * implement signalling "no current profile" if no medium is loaded. */
3008 ataH2BE_U16(aBuf + 6, 0x08); /* current profile: read-only CD */
3009
3010 ataH2BE_U16(aBuf + 8, 0); /* feature 0: list of profiles supported */
3011 aBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
3012 aBuf[11] = 8; /* additional bytes for profiles */
3013 /* The MMC-3 spec says that DVD-ROM read capability should be reported
3014 * before CD-ROM read capability. */
3015 ataH2BE_U16(aBuf + 12, 0x10); /* profile: read-only DVD */
3016 aBuf[14] = (0 << 0); /* NOT current profile */
3017 ataH2BE_U16(aBuf + 16, 0x08); /* profile: read only CD */
3018 aBuf[18] = (1 << 0); /* current profile */
3019
3020 /* Copy the buffer in to the scatter gather list. */
3021 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3022 *pcbData = sizeof(aBuf);
3023
3024 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3025 return VINF_SUCCESS;
3026}
3027
3028
3029static int atapiInquirySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3030{
3031 uint8_t aBuf[36];
3032
3033 aBuf[0] = 0x05; /* CD-ROM */
3034 aBuf[1] = 0x80; /* removable */
3035 aBuf[2] = 0x00; /* ISO */
3036 aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
3037 aBuf[4] = 31; /* additional length */
3038 aBuf[5] = 0; /* reserved */
3039 aBuf[6] = 0; /* reserved */
3040 aBuf[7] = 0; /* reserved */
3041 ataSCSIPadStr(aBuf + 8, "VBOX", 8);
3042 ataSCSIPadStr(aBuf + 16, "CD-ROM", 16);
3043 ataSCSIPadStr(aBuf + 32, "1.0", 4);
3044
3045 /* Copy the buffer in to the scatter gather list. */
3046 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3047 *pcbData = sizeof(aBuf);
3048
3049 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3050 return VINF_SUCCESS;
3051}
3052
3053
3054static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3055{
3056 uint8_t aBuf[16];
3057
3058 ataH2BE_U16(&aBuf[0], 16 + 6);
3059 aBuf[2] = 0x70;
3060 aBuf[3] = 0;
3061 aBuf[4] = 0;
3062 aBuf[5] = 0;
3063 aBuf[6] = 0;
3064 aBuf[7] = 0;
3065
3066 aBuf[8] = 0x01;
3067 aBuf[9] = 0x06;
3068 aBuf[10] = 0x00;
3069 aBuf[11] = 0x05;
3070 aBuf[12] = 0x00;
3071 aBuf[13] = 0x00;
3072 aBuf[14] = 0x00;
3073 aBuf[15] = 0x00;
3074
3075 /* Copy the buffer in to the scatter gather list. */
3076 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3077 *pcbData = sizeof(aBuf);
3078
3079 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3080 return VINF_SUCCESS;
3081}
3082
3083
3084static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3085{
3086 uint8_t aBuf[40];
3087
3088 ataH2BE_U16(&aBuf[0], 38);
3089 aBuf[2] = 0x70;
3090 aBuf[3] = 0;
3091 aBuf[4] = 0;
3092 aBuf[5] = 0;
3093 aBuf[6] = 0;
3094 aBuf[7] = 0;
3095
3096 aBuf[8] = 0x2a;
3097 aBuf[9] = 30; /* page length */
3098 aBuf[10] = 0x08; /* DVD-ROM read support */
3099 aBuf[11] = 0x00; /* no write support */
3100 /* The following claims we support audio play. This is obviously false,
3101 * but the Linux generic CDROM support makes many features depend on this
3102 * capability. If it's not set, this causes many things to be disabled. */
3103 aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3104 aBuf[13] = 0x00; /* no subchannel reads supported */
3105 aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3106 if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
3107 aBuf[14] |= 1 << 1; /* report lock state */
3108 aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3109 ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
3110 ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
3111 ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
3112 Just write the value DevATA is using. */
3113 ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
3114 aBuf[24] = 0; /* reserved */
3115 aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
3116 ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
3117 ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
3118 ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
3119 aBuf[32] = 0; /* reserved */
3120 aBuf[33] = 0; /* reserved */
3121 aBuf[34] = 0; /* reserved */
3122 aBuf[35] = 1; /* rotation control CAV */
3123 ataH2BE_U16(&aBuf[36], 0); /* current write speed */
3124 ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
3125
3126 /* Copy the buffer in to the scatter gather list. */
3127 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3128 *pcbData = sizeof(aBuf);
3129
3130 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3131 return VINF_SUCCESS;
3132}
3133
3134
3135static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3136{
3137 uint8_t aBuf[18];
3138
3139 memset(&aBuf[0], 0, 18);
3140 aBuf[0] = 0x70 | (1 << 7);
3141 aBuf[2] = pAhciPort->uATAPISenseKey;
3142 aBuf[7] = 10;
3143 aBuf[12] = pAhciPort->uATAPIASC;
3144
3145 /* Copy the buffer in to the scatter gather list. */
3146 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3147 *pcbData = sizeof(aBuf);
3148
3149 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3150 return VINF_SUCCESS;
3151}
3152
3153
3154static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3155{
3156 uint8_t aBuf[8];
3157
3158 ataH2BE_U16(&aBuf[0], 0);
3159 /* no current LBA */
3160 aBuf[2] = 0;
3161 aBuf[3] = 0;
3162 aBuf[4] = 0;
3163 aBuf[5] = 1;
3164 ataH2BE_U16(aBuf + 6, 0);
3165
3166 /* Copy the buffer in to the scatter gather list. */
3167 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3168 *pcbData = sizeof(aBuf);
3169
3170 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3171 return VINF_SUCCESS;
3172}
3173
3174
3175static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3176{
3177 uint8_t aBuf[20], *q, iStartTrack;
3178 bool fMSF;
3179 uint32_t cbSize;
3180
3181 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3182 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3183 if (iStartTrack > 1 && iStartTrack != 0xaa)
3184 {
3185 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3186 return VINF_SUCCESS;
3187 }
3188 q = aBuf + 2;
3189 *q++ = 1; /* first session */
3190 *q++ = 1; /* last session */
3191 if (iStartTrack <= 1)
3192 {
3193 *q++ = 0; /* reserved */
3194 *q++ = 0x14; /* ADR, control */
3195 *q++ = 1; /* track number */
3196 *q++ = 0; /* reserved */
3197 if (fMSF)
3198 {
3199 *q++ = 0; /* reserved */
3200 ataLBA2MSF(q, 0);
3201 q += 3;
3202 }
3203 else
3204 {
3205 /* sector 0 */
3206 ataH2BE_U32(q, 0);
3207 q += 4;
3208 }
3209 }
3210 /* lead out track */
3211 *q++ = 0; /* reserved */
3212 *q++ = 0x14; /* ADR, control */
3213 *q++ = 0xaa; /* track number */
3214 *q++ = 0; /* reserved */
3215 if (fMSF)
3216 {
3217 *q++ = 0; /* reserved */
3218 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3219 q += 3;
3220 }
3221 else
3222 {
3223 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3224 q += 4;
3225 }
3226 cbSize = q - aBuf;
3227 ataH2BE_U16(aBuf, cbSize - 2);
3228
3229 /* Copy the buffer in to the scatter gather list. */
3230 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3231 *pcbData = cbSize;
3232
3233 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3234 return VINF_SUCCESS;
3235}
3236
3237
3238static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3239{
3240 uint8_t aBuf[12];
3241 bool fMSF;
3242
3243 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3244 /* multi session: only a single session defined */
3245/** @todo double-check this stuff against what a real drive says for a CD-ROM (not a CD-R) with only a single data session. Maybe solve the problem with "cdrdao read-toc" not being able to figure out whether numbers are in BCD or hex. */
3246 memset(aBuf, 0, 12);
3247 aBuf[1] = 0x0a;
3248 aBuf[2] = 0x01;
3249 aBuf[3] = 0x01;
3250 aBuf[5] = 0x14; /* ADR, control */
3251 aBuf[6] = 1; /* first track in last complete session */
3252 if (fMSF)
3253 {
3254 aBuf[8] = 0; /* reserved */
3255 ataLBA2MSF(&aBuf[9], 0);
3256 }
3257 else
3258 {
3259 /* sector 0 */
3260 ataH2BE_U32(aBuf + 8, 0);
3261 }
3262
3263 /* Copy the buffer in to the scatter gather list. */
3264 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
3265 *pcbData = sizeof(aBuf);
3266
3267 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3268 return VINF_SUCCESS;
3269}
3270
3271
3272static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
3273{
3274 uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
3275 uint8_t *q, iStartTrack;
3276 bool fMSF;
3277 uint32_t cbSize;
3278
3279 fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
3280 iStartTrack = pAhciPortTaskState->aATAPICmd[6];
3281
3282 q = aBuf + 2;
3283 *q++ = 1; /* first session */
3284 *q++ = 1; /* last session */
3285
3286 *q++ = 1; /* session number */
3287 *q++ = 0x14; /* data track */
3288 *q++ = 0; /* track number */
3289 *q++ = 0xa0; /* first track in program area */
3290 *q++ = 0; /* min */
3291 *q++ = 0; /* sec */
3292 *q++ = 0; /* frame */
3293 *q++ = 0;
3294 *q++ = 1; /* first track */
3295 *q++ = 0x00; /* disk type CD-DA or CD data */
3296 *q++ = 0;
3297
3298 *q++ = 1; /* session number */
3299 *q++ = 0x14; /* data track */
3300 *q++ = 0; /* track number */
3301 *q++ = 0xa1; /* last track in program area */
3302 *q++ = 0; /* min */
3303 *q++ = 0; /* sec */
3304 *q++ = 0; /* frame */
3305 *q++ = 0;
3306 *q++ = 1; /* last track */
3307 *q++ = 0;
3308 *q++ = 0;
3309
3310 *q++ = 1; /* session number */
3311 *q++ = 0x14; /* data track */
3312 *q++ = 0; /* track number */
3313 *q++ = 0xa2; /* lead-out */
3314 *q++ = 0; /* min */
3315 *q++ = 0; /* sec */
3316 *q++ = 0; /* frame */
3317 if (fMSF)
3318 {
3319 *q++ = 0; /* reserved */
3320 ataLBA2MSF(q, pAhciPort->cTotalSectors);
3321 q += 3;
3322 }
3323 else
3324 {
3325 ataH2BE_U32(q, pAhciPort->cTotalSectors);
3326 q += 4;
3327 }
3328
3329 *q++ = 1; /* session number */
3330 *q++ = 0x14; /* ADR, control */
3331 *q++ = 0; /* track number */
3332 *q++ = 1; /* point */
3333 *q++ = 0; /* min */
3334 *q++ = 0; /* sec */
3335 *q++ = 0; /* frame */
3336 if (fMSF)
3337 {
3338 *q++ = 0; /* reserved */
3339 ataLBA2MSF(q, 0);
3340 q += 3;
3341 }
3342 else
3343 {
3344 /* sector 0 */
3345 ataH2BE_U32(q, 0);
3346 q += 4;
3347 }
3348
3349 cbSize = q - aBuf;
3350 ataH2BE_U16(aBuf, cbSize - 2);
3351
3352 /* Copy the buffer in to the scatter gather list. */
3353 ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
3354 *pcbData = cbSize;
3355
3356 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3357 return VINF_SUCCESS;
3358}
3359
3360static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
3361{
3362 int cbTransfered;
3363 int rc, rcSourceSink;
3364
3365 /* Create scatter gather list. */
3366 rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
3367 if (RT_FAILURE(rc))
3368 AssertMsgFailed(("Getting number of list elements failed rc=%Rrc\n", rc));
3369
3370 rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
3371
3372 pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
3373
3374 rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
3375 if (RT_FAILURE(rc))
3376 AssertMsgFailed(("Destroying list failed rc=%Rrc\n", rc));
3377
3378 /* Write updated command header into memory of the guest. */
3379 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
3380
3381 return rcSourceSink;
3382}
3383
3384static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
3385{
3386 Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
3387
3388 switch (cbSector)
3389 {
3390 case 2048:
3391 pAhciPortTaskState->uOffset = iATAPILBA * cbSector;
3392 pAhciPortTaskState->cbTransfer = cSectors * cbSector;
3393 break;
3394 case 2352:
3395 {
3396 AssertMsgFailed(("2352 read\n"));
3397 /* @todo: This is quite difficult as the data transfer is not handled here
3398 We need to add the sync bytes etc. here and modify the pointers
3399 and size of the sg entries. */
3400#if 0
3401 uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
3402
3403 for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
3404 {
3405 /* sync bytes */
3406 *pbBuf++ = 0x00;
3407 memset(pbBuf, 0xff, 11);
3408 pbBuf += 11;
3409 /* MSF */
3410 ataLBA2MSF(pbBuf, i);
3411 pbBuf += 3;
3412 *pbBuf++ = 0x01; /* mode 1 data */
3413 /* data */
3414 rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
3415 if (RT_FAILURE(rc))
3416 break;
3417 pbBuf += 2048;
3418 /* ECC */
3419 memset(pbBuf, 0, 288);
3420 pbBuf += 288;
3421 }
3422#endif
3423 pAhciPortTaskState->uOffset = iATAPILBA * 2048;
3424 pAhciPortTaskState->cbTransfer = cSectors * 2048;
3425 }
3426 break;
3427 default:
3428 AssertMsgFailed(("Unsupported sectors size\n"));
3429 break;
3430 }
3431
3432 return VINF_SUCCESS;
3433}
3434
3435static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3436{
3437 int rc = PDMBLOCKTXDIR_NONE;
3438 const uint8_t *pbPacket;
3439 uint32_t cbMax;
3440
3441 pbPacket = pAhciPortTaskState->aATAPICmd;
3442
3443 ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
3444
3445 switch (pbPacket[0])
3446 {
3447 case SCSI_TEST_UNIT_READY:
3448 if (pAhciPort->cNotifiedMediaChange > 0)
3449 {
3450 if (pAhciPort->cNotifiedMediaChange-- > 2)
3451 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3452 else
3453 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3454 }
3455 else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3456 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3457 else
3458 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3459 break;
3460 case SCSI_MODE_SENSE_10:
3461 {
3462 uint8_t uPageControl, uPageCode;
3463 cbMax = ataBE2H_U16(pbPacket + 7);
3464 uPageControl = pbPacket[2] >> 6;
3465 uPageCode = pbPacket[2] & 0x3f;
3466 switch (uPageControl)
3467 {
3468 case SCSI_PAGECONTROL_CURRENT:
3469 switch (uPageCode)
3470 {
3471 case SCSI_MODEPAGE_ERROR_RECOVERY:
3472 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
3473 break;
3474 case SCSI_MODEPAGE_CD_STATUS:
3475 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
3476 break;
3477 default:
3478 goto error_cmd;
3479 }
3480 break;
3481 case SCSI_PAGECONTROL_CHANGEABLE:
3482 goto error_cmd;
3483 case SCSI_PAGECONTROL_DEFAULT:
3484 goto error_cmd;
3485 default:
3486 case SCSI_PAGECONTROL_SAVED:
3487 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
3488 break;
3489 }
3490 }
3491 break;
3492 case SCSI_REQUEST_SENSE:
3493 cbMax = pbPacket[4];
3494 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_REQUEST_SENSE);
3495 break;
3496 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
3497 if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3498 {
3499 if (pbPacket[4] & 1)
3500 pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
3501 else
3502 pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
3503 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3504 }
3505 else
3506 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3507 break;
3508 case SCSI_READ_10:
3509 case SCSI_READ_12:
3510 {
3511 uint32_t cSectors, iATAPILBA;
3512
3513 if (pAhciPort->cNotifiedMediaChange > 0)
3514 {
3515 pAhciPort->cNotifiedMediaChange-- ;
3516 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3517 break;
3518 }
3519 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3520 {
3521 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3522 break;
3523 }
3524 if (pbPacket[0] == SCSI_READ_10)
3525 cSectors = ataBE2H_U16(pbPacket + 7);
3526 else
3527 cSectors = ataBE2H_U32(pbPacket + 6);
3528 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3529 if (cSectors == 0)
3530 {
3531 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3532 break;
3533 }
3534 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3535 {
3536 /* Rate limited logging, one log line per second. For
3537 * guests that insist on reading from places outside the
3538 * valid area this often generates too many release log
3539 * entries otherwise. */
3540 static uint64_t uLastLogTS = 0;
3541 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3542 {
3543 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3544 uLastLogTS = RTTimeMilliTS();
3545 }
3546 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3547 break;
3548 }
3549 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3550 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3551 }
3552 break;
3553 case SCSI_READ_CD:
3554 {
3555 uint32_t cSectors, iATAPILBA;
3556
3557 if (pAhciPort->cNotifiedMediaChange > 0)
3558 {
3559 pAhciPort->cNotifiedMediaChange-- ;
3560 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3561 break;
3562 }
3563 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3564 {
3565 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3566 break;
3567 }
3568 cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
3569 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3570 if (cSectors == 0)
3571 {
3572 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3573 break;
3574 }
3575 if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
3576 {
3577 /* Rate limited logging, one log line per second. For
3578 * guests that insist on reading from places outside the
3579 * valid area this often generates too many release log
3580 * entries otherwise. */
3581 static uint64_t uLastLogTS = 0;
3582 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3583 {
3584 LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
3585 uLastLogTS = RTTimeMilliTS();
3586 }
3587 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3588 break;
3589 }
3590 switch (pbPacket[9] & 0xf8)
3591 {
3592 case 0x00:
3593 /* nothing */
3594 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3595 break;
3596 case 0x10:
3597 /* normal read */
3598 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
3599 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3600 break;
3601 case 0xf8:
3602 /* read all data */
3603 atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
3604 rc = PDMBLOCKTXDIR_FROM_DEVICE;
3605 break;
3606 default:
3607 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
3608 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3609 break;
3610 }
3611 }
3612 break;
3613 case SCSI_SEEK_10:
3614 {
3615 uint32_t iATAPILBA;
3616 if (pAhciPort->cNotifiedMediaChange > 0)
3617 {
3618 pAhciPort->cNotifiedMediaChange-- ;
3619 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3620 break;
3621 }
3622 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3623 {
3624 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3625 break;
3626 }
3627 iATAPILBA = ataBE2H_U32(pbPacket + 2);
3628 if (iATAPILBA > pAhciPort->cTotalSectors)
3629 {
3630 /* Rate limited logging, one log line per second. For
3631 * guests that insist on seeking to places outside the
3632 * valid area this often generates too many release log
3633 * entries otherwise. */
3634 static uint64_t uLastLogTS = 0;
3635 if (RTTimeMilliTS() >= uLastLogTS + 1000)
3636 {
3637 LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
3638 uLastLogTS = RTTimeMilliTS();
3639 }
3640 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
3641 break;
3642 }
3643 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3644 pAhciPortTaskState->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
3645 }
3646 break;
3647 case SCSI_START_STOP_UNIT:
3648 {
3649 int rc = VINF_SUCCESS;
3650 switch (pbPacket[4] & 3)
3651 {
3652 case 0: /* 00 - Stop motor */
3653 case 1: /* 01 - Start motor */
3654 break;
3655 case 2: /* 10 - Eject media */
3656 /* This must be done from EMT. */
3657 {
3658 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3659 PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
3660 PVMREQ pReq;
3661
3662 rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
3663 (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
3664 AssertReleaseRC(rc);
3665 VMR3ReqFree(pReq);
3666 }
3667 break;
3668 case 3: /* 11 - Load media */
3669 /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
3670 break;
3671 }
3672 if (RT_SUCCESS(rc))
3673 atapiCmdOK(pAhciPort, pAhciPortTaskState);
3674 else
3675 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
3676 }
3677 break;
3678 case SCSI_MECHANISM_STATUS:
3679 {
3680 cbMax = ataBE2H_U16(pbPacket + 8);
3681 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MECHANISM_STATUS);
3682 }
3683 break;
3684 case SCSI_READ_TOC_PMA_ATIP:
3685 {
3686 uint8_t format;
3687
3688 if (pAhciPort->cNotifiedMediaChange > 0)
3689 {
3690 pAhciPort->cNotifiedMediaChange-- ;
3691 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3692 break;
3693 }
3694 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3695 {
3696 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3697 break;
3698 }
3699 cbMax = ataBE2H_U16(pbPacket + 7);
3700 /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
3701 * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
3702 * the other field is clear... */
3703 format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
3704 switch (format)
3705 {
3706 case 0:
3707 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
3708 break;
3709 case 1:
3710 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_MULTI);
3711 break;
3712 case 2:
3713 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_RAW);
3714 break;
3715 default:
3716 error_cmd:
3717 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
3718 break;
3719 }
3720 }
3721 break;
3722 case SCSI_READ_CAPACITY:
3723 if (pAhciPort->cNotifiedMediaChange > 0)
3724 {
3725 pAhciPort->cNotifiedMediaChange-- ;
3726 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3727 break;
3728 }
3729 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3730 {
3731 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3732 break;
3733 }
3734 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_CAPACITY);
3735 break;
3736 case SCSI_READ_DISC_INFORMATION:
3737 if (pAhciPort->cNotifiedMediaChange > 0)
3738 {
3739 pAhciPort->cNotifiedMediaChange-- ;
3740 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3741 break;
3742 }
3743 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3744 {
3745 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3746 break;
3747 }
3748 cbMax = ataBE2H_U16(pbPacket + 7);
3749 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
3750 break;
3751 case SCSI_READ_TRACK_INFORMATION:
3752 if (pAhciPort->cNotifiedMediaChange > 0)
3753 {
3754 pAhciPort->cNotifiedMediaChange-- ;
3755 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
3756 break;
3757 }
3758 else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
3759 {
3760 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
3761 break;
3762 }
3763 cbMax = ataBE2H_U16(pbPacket + 7);
3764 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
3765 break;
3766 case SCSI_GET_CONFIGURATION:
3767 /* No media change stuff here, it can confuse Linux guests. */
3768 cbMax = ataBE2H_U16(pbPacket + 7);
3769 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_CONFIGURATION);
3770 break;
3771 case SCSI_INQUIRY:
3772 cbMax = pbPacket[4];
3773 atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_INQUIRY);
3774 break;
3775 default:
3776 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
3777 break;
3778 }
3779
3780 return rc;
3781}
3782
3783/**
3784 * Reset all values after a reset of the attached storage device.
3785 *
3786 * @returns nothing
3787 * @param pAhciPort The port the device is attached to.
3788 * @param pAhciPortTaskState The state to get the tag number from.
3789 */
3790static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
3791{
3792 /* Send a status good D2H FIS. */
3793 pAhciPort->fResetDevice = false;
3794 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3795 ahciPostFirstD2HFisIntoMemory(pAhciPort);
3796
3797 /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
3798 pAhciPort->regSIG = 0x101;
3799 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3800
3801 ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
3802}
3803
3804/**
3805 * Build a D2H FIS and post into the memory area of the guest.
3806 *
3807 * @returns Nothing
3808 * @param pAhciPort The port of the SATA controller.
3809 * @param pAhciPortTaskState The state of the task.
3810 * @param pCmdFis Pointer to the command FIS from the guest.
3811 * @param fInterrupt If an interrupt should be send to the guest.
3812 */
3813static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis, bool fInterrupt)
3814{
3815 uint8_t d2hFis[20];
3816 bool fAssertIntr = false;
3817 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3818
3819 ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
3820
3821 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3822 {
3823 memset(&d2hFis[0], 0, sizeof(d2hFis));
3824 d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
3825 d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
3826 d2hFis[AHCI_CMDFIS_STS] = pAhciPortTaskState->uATARegStatus;
3827 d2hFis[AHCI_CMDFIS_ERR] = pAhciPortTaskState->uATARegError;
3828 d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
3829 d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
3830 d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
3831 d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
3832 d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
3833 d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
3834 d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
3835 d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
3836 d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
3837
3838 /* Update registers. */
3839 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3840
3841 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
3842
3843 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3844 {
3845 /* Error bit is set. */
3846 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3847 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3848 fAssertIntr = true;
3849 }
3850
3851 if (fInterrupt)
3852 {
3853 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
3854 /* Check if we should assert an interrupt */
3855 if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
3856 fAssertIntr = true;
3857 }
3858
3859 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
3860
3861 if (fAssertIntr)
3862 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3863 }
3864}
3865
3866/**
3867 * Build a SDB Fis and post it into the memory area of the guest.
3868 *
3869 * @returns Nothing
3870 * @param pAhciPort The port for which the SDB Fis is send.
3871 * @param uFinishedTasks Bitmask of finished tasks.
3872 * @param pAhciPortTaskState The state of the last task.
3873 * @param fInterrupt If an interrupt should be asserted.
3874 */
3875static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
3876{
3877 uint32_t sdbFis[2];
3878 bool fAssertIntr = false;
3879 PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3880
3881 ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3882
3883 if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
3884 {
3885 memset(&sdbFis[0], 0, sizeof(sdbFis));
3886 sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3887 sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3888 sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3889 sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3890 sdbFis[1] = uFinishedTasks;
3891
3892 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3893
3894 if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3895 {
3896 /* Error bit is set. */
3897 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
3898 if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
3899 fAssertIntr = true;
3900 }
3901
3902 if (fInterrupt)
3903 {
3904 ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
3905 /* Check if we should assert an interrupt */
3906 if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
3907 fAssertIntr = true;
3908 }
3909
3910 /* Update registers. */
3911 pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
3912
3913 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
3914
3915 if (fAssertIntr)
3916 ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
3917 }
3918}
3919
3920static uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
3921{
3922 /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
3923 if (fLBA48)
3924 {
3925 if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
3926 return 65536;
3927 else
3928 return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
3929 }
3930 else
3931 {
3932 if (!pCmdFis[AHCI_CMDFIS_SECTC])
3933 return 256;
3934 else
3935 return pCmdFis[AHCI_CMDFIS_SECTC];
3936 }
3937}
3938
3939static uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
3940{
3941 uint64_t iLBA;
3942 if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
3943 {
3944 /* any LBA variant */
3945 if (fLBA48)
3946 {
3947 /* LBA48 */
3948 iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3949 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3950 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3951 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3952 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3953 pCmdFis[AHCI_CMDFIS_SECTN];
3954 }
3955 else
3956 {
3957 /* LBA */
3958 iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3959 (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
3960 }
3961 }
3962 else
3963 {
3964 /* CHS */
3965 iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
3966 (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
3967 (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
3968 }
3969 return iLBA;
3970}
3971
3972static uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
3973{
3974 uint64_t uLBA;
3975
3976 uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
3977 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
3978 ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
3979 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
3980 ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
3981 pCmdFis[AHCI_CMDFIS_SECTN];
3982
3983 return uLBA;
3984}
3985
3986DECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
3987{
3988 if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
3989 return 65536;
3990 else
3991 return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
3992}
3993
3994DECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
3995{
3996 return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
3997}
3998
3999static int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
4000{
4001 if (pAhciPortTaskState->cSGListSize < cSGList)
4002 {
4003 /* The entries are not allocated yet or the number is too small. */
4004 if (pAhciPortTaskState->cSGListSize)
4005 {
4006 RTMemFree(pAhciPortTaskState->pSGListHead);
4007 RTMemFree(pAhciPortTaskState->paSGEntries);
4008 }
4009
4010 /* Allocate R3 scatter gather list. */
4011 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
4012 if (!pAhciPortTaskState->pSGListHead)
4013 return VERR_NO_MEMORY;
4014
4015 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
4016 if (!pAhciPortTaskState->paSGEntries)
4017 return VERR_NO_MEMORY;
4018
4019 /* Reset usage statistics. */
4020 pAhciPortTaskState->cSGListSize = cSGList;
4021 pAhciPortTaskState->cSGListTooBig = 0;
4022 }
4023 else if (pAhciPortTaskState->cSGListSize > cSGList)
4024 {
4025 /*
4026 * The list is too big. Increment counter.
4027 * So that the destroying function can free
4028 * the list if it is too big too many times
4029 * in a row.
4030 */
4031 pAhciPortTaskState->cSGListTooBig++;
4032 }
4033 else
4034 {
4035 /*
4036 * Needed entries matches current size.
4037 * Reset counter.
4038 */
4039 pAhciPortTaskState->cSGListTooBig = 0;
4040 }
4041
4042 pAhciPortTaskState->cSGEntries = cSGList;
4043
4044 if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4045 {
4046 if (pAhciPortTaskState->pvBufferUnaligned)
4047 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4048
4049 Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4050
4051 pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
4052 if (!pAhciPortTaskState->pvBufferUnaligned)
4053 return VERR_NO_MEMORY;
4054
4055 pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
4056 }
4057
4058 /* Make debugging easier. */
4059#ifdef DEBUG
4060 memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
4061 memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4062 if (pAhciPortTaskState->pvBufferUnaligned)
4063 memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4064#endif
4065
4066 return VINF_SUCCESS;
4067}
4068
4069/**
4070 * Fallback scatter gather list creator.
4071 * Used if the normal one fails in PDMDevHlpPhysGCPhys2CCPtr() or
4072 * PDMDevHlpPhysGCPhys2CCPtrReadonly()
4073 *
4074 * returns VBox status code.
4075 * @param pAhciPort The ahci port.
4076 * @param pAhciPortTaskState The task state which contains the S/G list entries.
4077 * @param fReadonly If the mappings should be readonly.
4078 * @param cSGEntriesProcessed Number of entries the normal creator procecssed
4079 * before an error occurred. Used to free
4080 * any ressources allocated before.
4081 * @thread EMT
4082 */
4083static int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
4084 bool fReadonly, unsigned cSGEntriesProcessed)
4085{
4086 CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4087 PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4088 PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
4089
4090 AssertPtr(pAhciPortTaskState->pSGListHead);
4091 AssertPtr(pAhciPortTaskState->paSGEntries);
4092
4093 for (unsigned cSGEntryCurr = 0; cSGEntryCurr < cSGEntriesProcessed; cSGEntryCurr++)
4094 {
4095 if (pSGInfoCurr->fGuestMemory)
4096 {
4097 /* Release the lock. */
4098 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
4099 }
4100
4101 /* Go to the next entry. */
4102 pSGInfoCurr++;
4103 }
4104
4105 if (pAhciPortTaskState->pvBufferUnaligned)
4106 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4107
4108 pAhciPortTaskState->cSGListTooBig = 0;
4109
4110 RTMemFree(pAhciPortTaskState->pSGListHead);
4111 RTMemFree(pAhciPortTaskState->paSGEntries);
4112 pAhciPortTaskState->cSGEntries = 1;
4113 pAhciPortTaskState->cSGListSize = 1;
4114 pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbTransfer;
4115
4116 /* Allocate new buffers and SG lists. */
4117 pAhciPortTaskState->pvBufferUnaligned = RTMemAlloc(pAhciPortTaskState->cbTransfer);
4118 if (!pAhciPortTaskState->pvBufferUnaligned)
4119 return VERR_NO_MEMORY;
4120
4121 pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(1 * sizeof(PDMDATASEG));
4122 if (!pAhciPortTaskState->pSGListHead)
4123 {
4124 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4125 return VERR_NO_MEMORY;
4126 }
4127
4128 pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
4129 if (!pAhciPortTaskState->paSGEntries)
4130 {
4131 RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4132 RTMemFree(pAhciPortTaskState->pSGListHead);
4133 return VERR_NO_MEMORY;
4134 }
4135
4136 /* Set pointers. */
4137 pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbTransfer;
4138 pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4139
4140 pAhciPortTaskState->paSGEntries[0].fGuestMemory = false;
4141 pAhciPortTaskState->paSGEntries[0].u.temp.cUnaligned = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4142 pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
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=%Rc\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=%Rc\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 uPhase The data phase.
5957 */
5958static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPhase)
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(uPhase == SSM_PHASE_FINAL); NOREF(uPhase);
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.

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